diff --git a/.gitignore b/.gitignore index ba077a4..1925e31 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -bin +tmp_hyperledger/ diff --git a/404.html b/404.html new file mode 100644 index 0000000..523fd97 --- /dev/null +++ b/404.html @@ -0,0 +1,12 @@ + + + 404 + + +

404

+

Page not found

+

你下载的链接不存在,可能是你拿到的链接是老版本的链接,请访问软件站点获得最新版本链接再下载 + 点击这里访问软件站点 +

+ + \ No newline at end of file diff --git a/README.md b/README.md index 43f4c96..16d0d8d 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ dget -arch linux/arm influxdb:1.8.3 ## 直接下载链接 -[windows x64版本](https://dget.oss-cn-beijing.aliyuncs.com/dget_windows_amd64_v_1_0_1.zip) -[linux amd64版本](https://dget.oss-cn-beijing.aliyuncs.com/dget_linux_amd64_v_1_0_1.zip) -[linux arm版本](https://dget.oss-cn-beijing.aliyuncs.com/dget_linux_arm_v_1_0_1.zip) +[windows x64版本](./bin/windows_amd64/dget.exe) +[linux amd64版本](./bin/linux_amd64/dget) +[linux arm版本](./bin/linux_arm/dget) [Mac 传统版本](https://dget.oss-cn-beijing.aliyuncs.com/dget_darwin_amd64_v1_0_1.zip) [Mac arm64版本](https://dget.oss-cn-beijing.aliyuncs.com/dget_darwin_arm64_v1_0_1.zip) diff --git a/bin/linux_amd64/dget b/bin/linux_amd64/dget new file mode 100644 index 0000000..4256929 Binary files /dev/null and b/bin/linux_amd64/dget differ diff --git a/bin/linux_arm/dget b/bin/linux_arm/dget new file mode 100644 index 0000000..21b5632 Binary files /dev/null and b/bin/linux_arm/dget differ diff --git a/bin/windows_amd64/dget.exe b/bin/windows_amd64/dget.exe new file mode 100644 index 0000000..58f0a96 Binary files /dev/null and b/bin/windows_amd64/dget.exe differ diff --git a/go.mod b/go.mod index 9400d66..53b8ca4 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.15 require ( github.com/boltdb/bolt v1.3.1 github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/sirupsen/logrus v1.8.1 diff --git a/go.sum b/go.sum index a957484..e3f4f1f 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= +github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= diff --git a/install.go b/install.go index 0a0c1d5..1dc6151 100644 --- a/install.go +++ b/install.go @@ -129,40 +129,48 @@ func Install(_registry, d, tag string, arch string, printInfo bool) (err error) os.Exit(1) } else { - var info manifestlist.ManifestList var bts []byte bts, err = io.ReadAll(resp.Body) if err == nil { + switch resp.Header.Get("Content-Type") { + case "application/vnd.docker.distribution.manifest.list.v2+json": + var info manifestlist.ManifestList + err = json.Unmarshal(bts, &info) - err = json.Unmarshal(bts, &info) + if err == nil { + resp.Body.Close() + + logrus.Infof("获得%d个架构信息:", len(info.Manifests)) + + var selectedManifest *manifestlist.ManifestDescriptor + for i := 0; i < len(info.Manifests); i++ { + var m = info.Manifests[i] + logrus.Infof("[%d]架构:%s,OS:%s", i+1, m.Platform.Architecture, m.Platform.OS) + if m.Platform.OS+"/"+m.Platform.Architecture == arch { + logrus.Infoln("找到匹配的架构,开始下载") + selectedManifest = &m + } + } + if printInfo { + fmt.Println(string(bts)) + os.Exit(0) + } + + if selectedManifest == nil { + return errors.New("未找到匹配的架构:" + arch) + } + + req.Header.Set("Accept", selectedManifest.MediaType) + } + case "application/vnd.docker.distribution.manifest.v1+prettyjws": + req.Header.Set("Accept", "application/vnd.docker.distribution.manifest.v2+json") + } + + resp, err = http.DefaultClient.Do(req) if err == nil { - resp.Body.Close() - logrus.Infof("获得%d个架构信息:", len(info.Manifests)) - - var selectedManifest *manifestlist.ManifestDescriptor - for i := 0; i < len(info.Manifests); i++ { - var m = info.Manifests[i] - logrus.Infof("[%d]架构:%s,OS:%s", i+1, m.Platform.Architecture, m.Platform.OS) - if m.Platform.OS+"/"+m.Platform.Architecture == arch { - logrus.Infoln("找到匹配的架构,开始下载") - selectedManifest = &m - } - } - if printInfo { - fmt.Println(string(bts)) - os.Exit(0) - } - - if selectedManifest == nil { - return errors.New("未找到匹配的架构:" + arch) - } - - req.Header.Set("Accept", selectedManifest.MediaType) - - resp, err = http.DefaultClient.Do(req) var info Info err = json.NewDecoder(resp.Body).Decode(&info) @@ -170,162 +178,9 @@ func Install(_registry, d, tag string, arch string, printInfo bool) (err error) resp.Body.Close() logrus.Infof("获得Manifest信息,共%d层需要下载", len(info.Layers)) - var tmpDir = fmt.Sprintf("tmp_%s_%s", d, tag) - err = os.MkdirAll(tmpDir, 0777) - if err == nil { - if _, e := os.Stat(filepath.Join(tmpDir, "repositories")); e == nil { - logrus.Info(tmpDir, "is downloaded,use dir as cache") - } else { - req, err = http.NewRequest("GET", fmt.Sprintf("https://%s/v2/%s/blobs/%s", _registry, d, info.Config.Digest), nil) - if err == nil { - req.Header = authHeader - resp, err = http.DefaultClient.Do(req) - if err == nil { - var dest *os.File - dest, err = os.OpenFile(filepath.Join(tmpDir, info.Config.Digest.Encoded()+".json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) - if err == nil { - var bts []byte - bts, err = ioutil.ReadAll(resp.Body) - var lastLayerInfo LayerInfo - err = json.Unmarshal(bts, &lastLayerInfo) - resp.Body.Close() - - var config []PackageConfig - config = append(config, PackageConfig{ - Config: info.Config.Digest.Encoded() + ".json", - RepoTags: []string{d + ":" + tag}, - }) - if err == nil { - _, err = io.Copy(dest, bytes.NewReader(bts)) - dest.Close() - if err == nil { - parentid := "" - var fakeLayerId string - for n, layer := range info.Layers { - namer := sha256.New() - namer.Write([]byte(parentid + "\n" + layer.Digest + "\n")) - fakeLayerId = hex.EncodeToString(namer.Sum(nil)) - logrus.Infoln("handle layer", n, fakeLayerId, layer.Urls) - layerDirName := filepath.Join(tmpDir, fakeLayerId) - err = os.Mkdir(layerDirName, 0777) - if _, er := os.Stat(filepath.Join(layerDirName, "layer.tar")); er == nil { - logrus.Infoln("layer", fakeLayerId, "is existed, continue") - config[0].Layers = append(config[0].Layers, fakeLayerId+"/layer.tar") - parentid = fakeLayerId - continue - } - if err == nil || os.IsExist(err) { - err = ioutil.WriteFile(filepath.Join(layerDirName, "VERSION"), []byte("1.0"), 0666) - if err == nil { - req, err = http.NewRequest("GET", fmt.Sprintf("https://%s/v2/%s/blobs/%s", _registry, d, layer.Digest), nil) - if err == nil { - req.Header = authHeader - req.Header.Set("Accept", "application/vnd.docker.distribution.manifest.v2+json") - resp, err = http.DefaultClient.Do(req) - if err == nil { - if resp.StatusCode != 200 { - defer resp.Body.Close() - if len(layer.Urls) > 0 { - req, err = http.NewRequest("GET", layer.Urls[0], nil) - if err == nil { - req.Header = authHeader - req.Header.Set("Accept", "application/vnd.docker.distribution.manifest.v2+json") - resp, err = http.DefaultClient.Do(req) - if err == nil { - if resp.StatusCode != 200 { - err = fmt.Errorf("download from customized url fail for layer[%d]", n) - goto response - } - } - } - } else { - bts, _ := ioutil.ReadAll(resp.Body) - logrus.Fatalln("下载失败", string(bts)) - } - } - } - if err != nil { - logrus.Errorf("请求第%d/%d层失败:%v", n+1, len(info.Layers), err) - } else { - logrus.Infof("请求第%d/%d层成功", n+1, len(info.Layers)) - } - var dst *os.File - dst, err = os.OpenFile(filepath.Join(layerDirName, "layer.tar.part"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) - if err == nil { - var greader *gzip.Reader - greader, err = gzip.NewReader(resp.Body) - if err == nil { - _, err = io.Copy(dst, greader) - if err == nil { - dst.Close() - var layerInfo LayerInfo - if n == len(info.Layers)-1 { - layerInfo = lastLayerInfo - } - layerInfo.Id = fakeLayerId - if parentid != "" { - layerInfo.Parent = parentid - } - parentid = fakeLayerId - var jsonFile *os.File - jsonFile, err = os.OpenFile(filepath.Join(layerDirName, "json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) - if err == nil { - err = json.NewEncoder(jsonFile).Encode(&layerInfo) - if err == nil { - jsonFile.Close() - err = os.Rename(filepath.Join(layerDirName, "layer.tar.part"), filepath.Join(layerDirName, "layer.tar")) - } - } - } - } - } - if err != nil { - logrus.Errorf("保存第%d/%d层失败,%v", n+1, len(info.Layers), err) - } else { - logrus.Infof("保存第%d/%d层成功", n+1, len(info.Layers)) - } - if err != nil { - goto response - } else { - config[0].Layers = append(config[0].Layers, fakeLayerId+"/layer.tar") - } - } - } - } - } - var manifest *os.File - manifest, err = os.OpenFile(filepath.Join(tmpDir, "manifest.json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) - if err == nil { - err = json.NewEncoder(manifest).Encode(&config) - if err == nil { - manifest.Close() - var repositories = make(map[string]interface{}) - repositories[d] = map[string]string{ - tag: fakeLayerId, - } - var rFile *os.File - rFile, err = os.OpenFile(filepath.Join(tmpDir, "repositories"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) - if err == nil { - err = json.NewEncoder(rFile).Encode(&repositories) - goto maketar - } - } - - } - } - } - } - } - } - - } - maketar: - if err == nil { - err = writeDirToTarGz(tmpDir, tmpDir+"-img.tar.gz") - if err == nil { - fmt.Println("write tar success", tmpDir+"-img.tar.gz") - } - } + err = download(_registry, d, tag, info.Config.Digest, authHeader, info.Layers) + if err != nil { + goto response } } } @@ -338,6 +193,169 @@ response: return } +func download(_registry, d, tag string, digest digest.Digest, authHeader http.Header, layers []Layer) (err error) { + var tmpDir = fmt.Sprintf("tmp_%s_%s", d, tag) + err = os.MkdirAll(tmpDir, 0777) + if err == nil { + if _, e := os.Stat(filepath.Join(tmpDir, "repositories")); e == nil { + logrus.Info(tmpDir, "is downloaded,use dir as cache") + } else { + var req *http.Request + req, err = http.NewRequest("GET", fmt.Sprintf("https://%s/v2/%s/blobs/%s", _registry, d, digest), nil) + if err == nil { + req.Header = authHeader + var resp *http.Response + resp, err = http.DefaultClient.Do(req) + if err == nil { + var dest *os.File + dest, err = os.OpenFile(filepath.Join(tmpDir, digest.Encoded()+".json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) + if err == nil { + var bts []byte + bts, err = ioutil.ReadAll(resp.Body) + var lastLayerInfo LayerInfo + err = json.Unmarshal(bts, &lastLayerInfo) + resp.Body.Close() + + var config []PackageConfig + config = append(config, PackageConfig{ + Config: digest.Encoded() + ".json", + RepoTags: []string{d + ":" + tag}, + }) + if err == nil { + _, err = io.Copy(dest, bytes.NewReader(bts)) + dest.Close() + if err == nil { + parentid := "" + var fakeLayerId string + for n, layer := range layers { + namer := sha256.New() + namer.Write([]byte(parentid + "\n" + layer.Digest + "\n")) + fakeLayerId = hex.EncodeToString(namer.Sum(nil)) + logrus.Infoln("handle layer", n, fakeLayerId, layer.Urls) + layerDirName := filepath.Join(tmpDir, fakeLayerId) + err = os.Mkdir(layerDirName, 0777) + if _, er := os.Stat(filepath.Join(layerDirName, "layer.tar")); er == nil { + logrus.Infoln("layer", fakeLayerId, "is existed, continue") + config[0].Layers = append(config[0].Layers, fakeLayerId+"/layer.tar") + parentid = fakeLayerId + continue + } + if err == nil || os.IsExist(err) { + err = ioutil.WriteFile(filepath.Join(layerDirName, "VERSION"), []byte("1.0"), 0666) + if err == nil { + req, err = http.NewRequest("GET", fmt.Sprintf("https://%s/v2/%s/blobs/%s", _registry, d, layer.Digest), nil) + if err == nil { + req.Header = authHeader + req.Header.Set("Accept", "application/vnd.docker.distribution.manifest.v2+json") + resp, err = http.DefaultClient.Do(req) + if err == nil { + if resp.StatusCode != 200 { + defer resp.Body.Close() + if len(layer.Urls) > 0 { + req, err = http.NewRequest("GET", layer.Urls[0], nil) + if err == nil { + req.Header = authHeader + req.Header.Set("Accept", "application/vnd.docker.distribution.manifest.v2+json") + resp, err = http.DefaultClient.Do(req) + if err == nil { + if resp.StatusCode != 200 { + err = fmt.Errorf("download from customized url fail for layer[%d]", n) + return err + } + } + } + } else { + bts, _ := ioutil.ReadAll(resp.Body) + logrus.Fatalln("下载失败", string(bts)) + } + } + } + if err != nil { + logrus.Errorf("请求第%d/%d层失败:%v", n+1, len(layers), err) + } else { + logrus.Infof("请求第%d/%d层成功", n+1, len(layers)) + } + var dst *os.File + dst, err = os.OpenFile(filepath.Join(layerDirName, "layer.tar.part"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) + if err == nil { + var greader *gzip.Reader + greader, err = gzip.NewReader(resp.Body) + if err == nil { + _, err = io.Copy(dst, greader) + if err == nil { + dst.Close() + var layerInfo LayerInfo + if n == len(layers)-1 { + layerInfo = lastLayerInfo + } + layerInfo.Id = fakeLayerId + if parentid != "" { + layerInfo.Parent = parentid + } + parentid = fakeLayerId + var jsonFile *os.File + jsonFile, err = os.OpenFile(filepath.Join(layerDirName, "json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) + if err == nil { + err = json.NewEncoder(jsonFile).Encode(&layerInfo) + if err == nil { + jsonFile.Close() + err = os.Rename(filepath.Join(layerDirName, "layer.tar.part"), filepath.Join(layerDirName, "layer.tar")) + } + } + } + } + } + if err != nil { + logrus.Errorf("保存第%d/%d层失败,%v", n+1, len(layers), err) + } else { + logrus.Infof("保存第%d/%d层成功", n+1, len(layers)) + } + if err != nil { + return err + } else { + config[0].Layers = append(config[0].Layers, fakeLayerId+"/layer.tar") + } + } + } + } + } + var manifest *os.File + manifest, err = os.OpenFile(filepath.Join(tmpDir, "manifest.json"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) + if err == nil { + err = json.NewEncoder(manifest).Encode(&config) + if err == nil { + manifest.Close() + var repositories = make(map[string]interface{}) + repositories[d] = map[string]string{ + tag: fakeLayerId, + } + var rFile *os.File + rFile, err = os.OpenFile(filepath.Join(tmpDir, "repositories"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) + if err == nil { + err = json.NewEncoder(rFile).Encode(&repositories) + goto maketar + } + } + + } + } + } + } + } + } + + } + maketar: + if err == nil { + err = writeDirToTarGz(tmpDir, tmpDir+"-img.tar.gz") + if err == nil { + fmt.Println("write tar success", tmpDir+"-img.tar.gz") + } + } + } + return +} + func getAuthHead(a, r, d string) (string, error) { resp, err := http.Get(fmt.Sprintf("%s?service=%s&scope=repository:%s:pull", a, r, d)) if err == nil {