func getInstalledVersions(pattern string) []dockerversion.Version { searchPath := filepath.Join(getVersionsDir(), pattern) versions, _ := filepath.Glob(searchPath) var results []dockerversion.Version for _, versionDir := range versions { version := dockerversion.Parse(filepath.Base(versionDir)) if version.IsExperimental() { experimentalDockerPath := filepath.Join(versionDir, getBinaryName()) experimentalVersion, err := getDockerVersion(experimentalDockerPath, true) if err != nil { writeDebug("Unable to get version of installed experimental version at %s.\n%s", versionDir, err) continue } version.SemVer = experimentalVersion.SemVer } results = append(results, version) } if glob.Glob(pattern, dockerversion.SystemAlias) { systemVersion, err := getSystemDockerVersion() if err == nil { results = append(results, systemVersion) } } dockerversion.Sort(results) return results }
func getDockerVersion(dockerPath string, includeBuild bool) (dockerversion.Version, error) { rawVersion, _ := exec.Command(dockerPath, "-v").Output() writeDebug("%s -v output: %s", dockerPath, rawVersion) versionRegex := regexp.MustCompile(`^Docker version (.+), build ([^,]+),?`) match := versionRegex.FindSubmatch(rawVersion) if len(match) < 2 { return dockerversion.Version{}, errors.New("Could not detect docker version.") } version := string(match[1][:]) build := string(match[2][:]) if includeBuild { version = fmt.Sprintf("%s+%s", version, build) } return dockerversion.Parse(version), nil }
func getAvailableVersions(pattern string) []dockerversion.Version { gh := buildGithubClient() options := &github.ListOptions{PerPage: 100} var allReleases []github.RepositoryRelease for { releases, response, err := gh.Repositories.ListReleases("docker", "docker", options) if err != nil { warnWhenRateLimitExceeded(err, response) die("Unable to retrieve list of Docker releases from GitHub", err, retCodeRuntimeError) } allReleases = append(allReleases, releases...) if response.StatusCode != 200 { die("Unable to retrieve list of Docker releases from GitHub (Status %s).", nil, retCodeRuntimeError, response.StatusCode) } if response.NextPage == 0 { break } options.Page = response.NextPage } versionRegex := regexp.MustCompile(`^v([1-9]+\.\d+\.\d+)$`) patternRegex, err := regexp.Compile(pattern) if err != nil { die("Invalid pattern.", err, retCodeInvalidOperation) } var results []dockerversion.Version for _, release := range allReleases { version := *release.Name match := versionRegex.FindStringSubmatch(version) if len(match) > 1 && patternRegex.MatchString(version) { results = append(results, dockerversion.Parse(match[1])) } } dockerversion.Sort(results) return results }
func main() { app := cli.NewApp() app.Name = "Docker Version Manager" app.Usage = "Manage multiple versions of the Docker client" app.Version = fmt.Sprintf("%s (%s)", dvmVersion, dvmCommit) app.EnableBashCompletion = true app.Flags = []cli.Flag{ cli.StringFlag{Name: "github-token", EnvVar: "GITHUB_TOKEN", Usage: "Increase the github api rate limit by specifying your github personal access token."}, cli.StringFlag{Name: "dvm-dir", EnvVar: "DVM_DIR", Usage: "Specify an alternate DVM home directory, defaults to ~/.dvm."}, cli.StringFlag{Name: "shell", EnvVar: "SHELL", Usage: "Specify the shell format in which environment variables should be output, e.g. powershell, cmd or sh/bash. Defaults to sh/bash."}, cli.BoolFlag{Name: "debug", Usage: "Print additional debug information."}, cli.BoolFlag{Name: "silent", EnvVar: "DVM_SILENT", Usage: "Suppress output. Errors will still be displayed."}, } app.Commands = []cli.Command{ { Name: "install", Aliases: []string{"i"}, Usage: "dvm install [<version>], dvm install experimental\n\tInstall a Docker version, using $DOCKER_VERSION if the version is not specified.", Flags: []cli.Flag{ cli.StringFlag{Name: "mirror-url", EnvVar: "DVM_MIRROR_URL", Usage: "Specify an alternate URL from which to download the Docker client. Defaults to https://get.docker.com/builds"}, cli.BoolFlag{Name: "nocheck", EnvVar: "DVM_NOCHECK", Usage: "Do not check if version exists (use with caution)."}, }, Action: func(c *cli.Context) error { setGlobalVars(c) versionName := c.Args().First() if versionName == "" { versionName = getDockerVersionVar() } version := dockerversion.Parse(versionName) install(version) return nil }, }, { Name: "uninstall", Usage: "dvm uninstall <version>\n\tUninstall a Docker version.", Action: func(c *cli.Context) error { setGlobalVars(c) version := dockerversion.Parse(c.Args().First()) uninstall(version) return nil }, }, { Name: "use", Usage: "dvm use [<version>], dvm use system, dvm use experimental\n\tUse a Docker version, using $DOCKER_VERSION if the version is not specified.", Flags: []cli.Flag{ cli.StringFlag{Name: "mirror-url", EnvVar: "DVM_MIRROR_URL", Usage: "Specify an alternate URL from which to download the Docker client. Defaults to https://get.docker.com/builds"}, cli.BoolFlag{Name: "nocheck", EnvVar: "DVM_NOCHECK", Usage: "Do not check if version exists (use with caution)."}, }, Action: func(c *cli.Context) error { setGlobalVars(c) versionName := c.Args().First() if versionName == "" { versionName = getDockerVersionVar() } version := dockerversion.Parse(versionName) use(version) return nil }, }, { Name: "deactivate", Usage: "dvm deactivate\n\tUndo the effects of `dvm` on current shell.", Action: func(c *cli.Context) error { setGlobalVars(c) deactivate() return nil }, }, { Name: "current", Usage: "dvm current\n\tPrint the current Docker version.", Action: func(c *cli.Context) error { setGlobalVars(c) current() return nil }, }, { Name: "which", Usage: "dvm which\n\tPrint the path to the current Docker version.", Action: func(c *cli.Context) error { setGlobalVars(c) which() return nil }, }, { Name: "alias", Usage: "dvm alias <alias> <version>\n\tCreate an alias to a Docker version.", Action: func(c *cli.Context) error { setGlobalVars(c) name := c.Args().Get(0) version := dockerversion.Parse(c.Args().Get(1)) alias(name, version) return nil }, }, { Name: "unalias", Usage: "dvm unalias <alias>\n\tRemove a Docker version alias.", Action: func(c *cli.Context) error { setGlobalVars(c) name := c.Args().First() unalias(name) return nil }, }, { Name: "list", Aliases: []string{"ls"}, Usage: "dvm list [<pattern>]\n\tList installed Docker versions.", Action: func(c *cli.Context) error { setGlobalVars(c) list(c.Args().First()) return nil }, }, { Name: "list-remote", Aliases: []string{"ls-remote"}, Usage: "dvm list-remote [<pattern>]\n\tList available Docker versions.", Action: func(c *cli.Context) error { setGlobalVars(c) listRemote(c.Args().First()) return nil }, }, { Name: "list-alias", Aliases: []string{"ls-alias"}, Usage: "dvm list-alias\n\tList Docker version aliases.", Action: func(c *cli.Context) error { setGlobalVars(c) listAlias() return nil }, }, } if upgradeDisabled != "true" { app.Commands = append(app.Commands, cli.Command{ Name: "upgrade", Usage: "dvm upgrade\n\tUpgrade dvm to the latest release.", Flags: []cli.Flag{ cli.BoolFlag{Name: "check", Usage: "Checks if an newer version of dvm is available, but does not perform the upgrade."}, cli.StringFlag{Name: "version", Usage: "Upgrade to the specified version."}, }, Action: func(c *cli.Context) error { setGlobalVars(c) upgrade(c.Bool("check"), c.String("version")) return nil }, }) } app.Run(os.Args) }