From 322dbcf372d75f144b01a17b2a19195fe43b038a Mon Sep 17 00:00:00 2001 From: guol-fnst Date: Tue, 14 Jun 2022 19:01:57 +0800 Subject: [PATCH 1/7] add update feature --- weed/command/command.go | 4 +- weed/command/update.go | 386 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 weed/command/update.go diff --git a/weed/command/command.go b/weed/command/command.go index dbc18a053..b16de3eba 100644 --- a/weed/command/command.go +++ b/weed/command/command.go @@ -2,9 +2,10 @@ package command import ( "fmt" - flag "github.com/chrislusf/seaweedfs/weed/util/fla9" "os" "strings" + + flag "github.com/chrislusf/seaweedfs/weed/util/fla9" ) var Commands = []*Command{ @@ -37,6 +38,7 @@ var Commands = []*Command{ cmdServer, cmdShell, cmdUpload, + cmdUpdate, cmdVersion, cmdVolume, cmdWebDav, diff --git a/weed/command/update.go b/weed/command/update.go new file mode 100644 index 000000000..bda904a85 --- /dev/null +++ b/weed/command/update.go @@ -0,0 +1,386 @@ +package command + +import ( + "archive/tar" + "archive/zip" + "bytes" + "compress/gzip" + "context" + "crypto/md5" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "runtime" + "strings" + "time" + + "github.com/chrislusf/seaweedfs/weed/glog" + "github.com/chrislusf/seaweedfs/weed/util" + "golang.org/x/net/context/ctxhttp" +) + +// Release collects data about a single release on GitHub. +type Release struct { + Name string `json:"name"` + TagName string `json:"tag_name"` + Draft bool `json:"draft"` + PreRelease bool `json:"prerelease"` + PublishedAt time.Time `json:"published_at"` + Assets []Asset `json:"assets"` + + Version string `json:"-"` // set manually in the code +} + +// Asset is a file uploaded and attached to a release. +type Asset struct { + ID int `json:"id"` + Name string `json:"name"` + URL string `json:"url"` +} + +var ( + updateOpt UpdateOptions +) + +type UpdateOptions struct { + Output *string +} + +func init() { + updateOpt.Output = cmdUpdate.Flag.String("output", "weed", "Save the latest weed as `filename`") + cmdUpdate.Run = runUpdate +} + +var cmdUpdate = &Command{ + UsageLine: "update [-output=weed]", + Short: "get latest stable version from https://github.com/chrislusf/seaweedfs", + Long: `get latest stable version from https://github.com/chrislusf/seaweedfs`, +} + +func runUpdate(cmd *Command, args []string) bool { + weedPath := *updateOpt.Output + if weedPath == "" { + file, err := os.Executable() + if err != nil { + glog.Fatalf("unable to find executable:%s", err) + return false + } + + *updateOpt.Output = file + } + + fi, err := os.Lstat(*updateOpt.Output) + if err != nil { + dirname := filepath.Dir(*updateOpt.Output) + di, err := os.Lstat(dirname) + if err != nil { + glog.Fatalf("unable to find directory:%s", dirname) + return false + } + if !di.Mode().IsDir() { + glog.Fatalf("output parent path %v is not a directory, use --output to specify a different file path", dirname) + return false + } + } else { + if !fi.Mode().IsRegular() { + glog.Fatalf("output path %v is not a normal file, use --output to specify a different file path", updateOpt.Output) + return false + } + } + + glog.V(0).Infof("writing weed to %v\n", *updateOpt.Output) + + v, err := downloadLatestStableRelease(context.Background(), *updateOpt.Output) + if err != nil { + glog.Fatalf("unable to update weed: %v", err) + return false + } + + glog.V(0).Infof("successfully updated weed to version %v\n", v) + + return true +} + +func downloadLatestStableRelease(ctx context.Context, target string) (version string, err error) { + currentVersion := util.VERSION_NUMBER + largeDiskSuffix := "" + if util.VolumeSizeLimitGB == 8000 { + largeDiskSuffix = "_large_disk" + } + + rel, err := GitHubLatestRelease(ctx, "chrislusf", "seaweedfs") + if err != nil { + return "", err + } + + if rel.Version == currentVersion { + glog.V(0).Infof("weed is up to date\n") + return currentVersion, nil + } + + glog.V(0).Infof("latest version is %v\n", rel.Version) + + ext := "tar.gz" + if runtime.GOOS == "windows" { + ext = "zip" + } + + suffix := fmt.Sprintf("%s_%s%s.%s", runtime.GOOS, runtime.GOARCH, largeDiskSuffix, ext) + md5Filename := fmt.Sprintf("%s.md5", suffix) + _, md5Val, err := getGithubDataFile(ctx, rel.Assets, md5Filename) + if err != nil { + return "", err + } + + downloadFilename, buf, err := getGithubDataFile(ctx, rel.Assets, suffix) + if err != nil { + return "", err + } + + md5Ctx := md5.New() + md5Ctx.Write(buf) + binaryMd5 := md5Ctx.Sum(nil) + if hex.EncodeToString(binaryMd5) != string(md5Val[0:32]) { + glog.Errorf("md5:'%s' '%s'", hex.EncodeToString(binaryMd5), string(md5Val[0:32])) + err = errors.New("binary md5sum doesn't match") + return "", err + } + + err = extractToFile(buf, downloadFilename, target) + if err != nil { + return "", err + } + + return rel.Version, nil +} + +func (r Release) String() string { + return fmt.Sprintf("%v %v, %d assets", + r.TagName, + r.PublishedAt.Local().Format("2006-01-02 15:04:05"), + len(r.Assets)) +} + +const githubAPITimeout = 30 * time.Second + +// githubError is returned by the GitHub API, e.g. for rate-limiting. +type githubError struct { + Message string +} + +// GitHubLatestRelease uses the GitHub API to get information about the latest +// release of a repository. +func GitHubLatestRelease(ctx context.Context, owner, repo string) (Release, error) { + ctx, cancel := context.WithTimeout(ctx, githubAPITimeout) + defer cancel() + + url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", owner, repo) + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return Release{}, err + } + + // pin API version 3 + req.Header.Set("Accept", "application/vnd.github.v3+json") + + res, err := ctxhttp.Do(ctx, http.DefaultClient, req) + if err != nil { + return Release{}, err + } + + if res.StatusCode != http.StatusOK { + content := res.Header.Get("Content-Type") + if strings.Contains(content, "application/json") { + // try to decode error message + var msg githubError + jerr := json.NewDecoder(res.Body).Decode(&msg) + if jerr == nil { + return Release{}, fmt.Errorf("unexpected status %v (%v) returned, message:\n %v", res.StatusCode, res.Status, msg.Message) + } + } + + _ = res.Body.Close() + return Release{}, fmt.Errorf("unexpected status %v (%v) returned", res.StatusCode, res.Status) + } + + buf, err := ioutil.ReadAll(res.Body) + if err != nil { + _ = res.Body.Close() + return Release{}, err + } + + err = res.Body.Close() + if err != nil { + return Release{}, err + } + + var release Release + err = json.Unmarshal(buf, &release) + if err != nil { + return Release{}, err + } + + if release.TagName == "" { + return Release{}, errors.New("tag name for latest release is empty") + } + + release.Version = release.TagName + + return release, nil +} + +func getGithubData(ctx context.Context, url string) ([]byte, error) { + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return nil, err + } + + // request binary data + req.Header.Set("Accept", "application/octet-stream") + + res, err := ctxhttp.Do(ctx, http.DefaultClient, req) + if err != nil { + return nil, err + } + + if res.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status %v (%v) returned", res.StatusCode, res.Status) + } + + buf, err := ioutil.ReadAll(res.Body) + if err != nil { + _ = res.Body.Close() + return nil, err + } + + err = res.Body.Close() + if err != nil { + return nil, err + } + + return buf, nil +} + +func getGithubDataFile(ctx context.Context, assets []Asset, suffix string) (filename string, data []byte, err error) { + var url string + for _, a := range assets { + if strings.HasSuffix(a.Name, suffix) { + url = a.URL + filename = a.Name + break + } + } + + if url == "" { + return "", nil, fmt.Errorf("unable to find file with suffix %v", suffix) + } + + glog.V(0).Infof("download %v\n", filename) + data, err = getGithubData(ctx, url) + if err != nil { + return "", nil, err + } + + return filename, data, nil +} + +func extractToFile(buf []byte, filename, target string) error { + var rd io.Reader = bytes.NewReader(buf) + + switch filepath.Ext(filename) { + case ".gz": + gr, err := gzip.NewReader(rd) + if err != nil { + return err + } + defer gr.Close() + trd := tar.NewReader(gr) + hdr, terr := trd.Next() + if terr != nil { + glog.Errorf("uncompress file(%s) failed:%s", hdr.Name, terr) + return terr + } + rd = trd + case ".zip": + zrd, err := zip.NewReader(bytes.NewReader(buf), int64(len(buf))) + if err != nil { + return err + } + + if len(zrd.File) != 1 { + return errors.New("ZIP archive contains more than one file") + } + + file, err := zrd.File[0].Open() + if err != nil { + return err + } + + defer func() { + _ = file.Close() + }() + + rd = file + } + + // Write everything to a temp file + dir := filepath.Dir(target) + new, err := ioutil.TempFile(dir, "weed") + if err != nil { + return err + } + + n, err := io.Copy(new, rd) + if err != nil { + _ = new.Close() + _ = os.Remove(new.Name()) + return err + } + if err = new.Sync(); err != nil { + return err + } + if err = new.Close(); err != nil { + return err + } + + mode := os.FileMode(0755) + // attempt to find the original mode + if fi, err := os.Lstat(target); err == nil { + mode = fi.Mode() + } + + // Remove the original binary. + if err := removeWeedBinary(dir, target); err != nil { + return err + } + + // Rename the temp file to the final location atomically. + if err := os.Rename(new.Name(), target); err != nil { + return err + } + + glog.V(0).Infof("saved %d bytes in %v\n", n, target) + return os.Chmod(target, mode) +} + +// Rename (rather than remove) the running version. The running binary will be locked +// on Windows and cannot be removed while still executing. +func removeWeedBinary(dir, target string) error { + if runtime.GOOS == "linux" { + return nil + } + backup := filepath.Join(dir, filepath.Base(target)+".bak") + if _, err := os.Stat(backup); err == nil { + _ = os.Remove(backup) + } + if err := os.Rename(target, backup); err != nil { + return fmt.Errorf("unable to rename target file: %v", err) + } + return nil +} From 78fc9cdfa0cdd973d68be432cdcefb804ae5b723 Mon Sep 17 00:00:00 2001 From: guol-fnst Date: Tue, 14 Jun 2022 19:10:54 +0800 Subject: [PATCH 2/7] add "copied from https://github.com/restic/restic/tree/master/internal/selfupdate" --- weed/command/command.go | 2 +- weed/command/update.go | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/weed/command/command.go b/weed/command/command.go index b16de3eba..7635405dc 100644 --- a/weed/command/command.go +++ b/weed/command/command.go @@ -37,8 +37,8 @@ var Commands = []*Command{ cmdScaffold, cmdServer, cmdShell, - cmdUpload, cmdUpdate, + cmdUpload, cmdVersion, cmdVolume, cmdWebDav, diff --git a/weed/command/update.go b/weed/command/update.go index bda904a85..64a664923 100644 --- a/weed/command/update.go +++ b/weed/command/update.go @@ -25,6 +25,8 @@ import ( "golang.org/x/net/context/ctxhttp" ) +//copied from https://github.com/restic/restic/tree/master/internal/selfupdate + // Release collects data about a single release on GitHub. type Release struct { Name string `json:"name"` @@ -59,8 +61,8 @@ func init() { var cmdUpdate = &Command{ UsageLine: "update [-output=weed]", - Short: "get latest stable version from https://github.com/chrislusf/seaweedfs", - Long: `get latest stable version from https://github.com/chrislusf/seaweedfs`, + Short: "get latest version from https://github.com/chrislusf/seaweedfs", + Long: `get latest version from https://github.com/chrislusf/seaweedfs`, } func runUpdate(cmd *Command, args []string) bool { From 695e8c75551b7de9f47723b682f0cb0ab4b74002 Mon Sep 17 00:00:00 2001 From: guol-fnst Date: Wed, 15 Jun 2022 15:26:04 +0800 Subject: [PATCH 3/7] fix minor bug --- weed/command/update.go | 44 +++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/weed/command/update.go b/weed/command/update.go index 64a664923..945ecc293 100644 --- a/weed/command/update.go +++ b/weed/command/update.go @@ -9,7 +9,6 @@ import ( "crypto/md5" "encoding/hex" "encoding/json" - "errors" "fmt" "io" "io/ioutil" @@ -46,6 +45,13 @@ type Asset struct { URL string `json:"url"` } +const githubAPITimeout = 30 * time.Second + +// githubError is returned by the GitHub API, e.g. for rate-limiting. +type githubError struct { + Message string +} + var ( updateOpt UpdateOptions ) @@ -66,17 +72,6 @@ var cmdUpdate = &Command{ } func runUpdate(cmd *Command, args []string) bool { - weedPath := *updateOpt.Output - if weedPath == "" { - file, err := os.Executable() - if err != nil { - glog.Fatalf("unable to find executable:%s", err) - return false - } - - *updateOpt.Output = file - } - fi, err := os.Lstat(*updateOpt.Output) if err != nil { dirname := filepath.Dir(*updateOpt.Output) @@ -91,7 +86,7 @@ func runUpdate(cmd *Command, args []string) bool { } } else { if !fi.Mode().IsRegular() { - glog.Fatalf("output path %v is not a normal file, use --output to specify a different file path", updateOpt.Output) + glog.Fatalf("output path %v is not a normal file, use --output to specify a different file path", *updateOpt.Output) return false } } @@ -111,11 +106,6 @@ func runUpdate(cmd *Command, args []string) bool { func downloadLatestStableRelease(ctx context.Context, target string) (version string, err error) { currentVersion := util.VERSION_NUMBER - largeDiskSuffix := "" - if util.VolumeSizeLimitGB == 8000 { - largeDiskSuffix = "_large_disk" - } - rel, err := GitHubLatestRelease(ctx, "chrislusf", "seaweedfs") if err != nil { return "", err @@ -128,6 +118,11 @@ func downloadLatestStableRelease(ctx context.Context, target string) (version st glog.V(0).Infof("latest version is %v\n", rel.Version) + largeDiskSuffix := "" + if util.VolumeSizeLimitGB == 8000 { + largeDiskSuffix = "_large_disk" + } + ext := "tar.gz" if runtime.GOOS == "windows" { ext = "zip" @@ -150,7 +145,7 @@ func downloadLatestStableRelease(ctx context.Context, target string) (version st binaryMd5 := md5Ctx.Sum(nil) if hex.EncodeToString(binaryMd5) != string(md5Val[0:32]) { glog.Errorf("md5:'%s' '%s'", hex.EncodeToString(binaryMd5), string(md5Val[0:32])) - err = errors.New("binary md5sum doesn't match") + err = fmt.Errorf("binary md5sum doesn't match") return "", err } @@ -169,13 +164,6 @@ func (r Release) String() string { len(r.Assets)) } -const githubAPITimeout = 30 * time.Second - -// githubError is returned by the GitHub API, e.g. for rate-limiting. -type githubError struct { - Message string -} - // GitHubLatestRelease uses the GitHub API to get information about the latest // release of a repository. func GitHubLatestRelease(ctx context.Context, owner, repo string) (Release, error) { @@ -229,7 +217,7 @@ func GitHubLatestRelease(ctx context.Context, owner, repo string) (Release, erro } if release.TagName == "" { - return Release{}, errors.New("tag name for latest release is empty") + return Release{}, fmt.Errorf("tag name for latest release is empty") } release.Version = release.TagName @@ -316,7 +304,7 @@ func extractToFile(buf []byte, filename, target string) error { } if len(zrd.File) != 1 { - return errors.New("ZIP archive contains more than one file") + return fmt.Errorf("ZIP archive contains more than one file") } file, err := zrd.File[0].Open() From 1dbb925d298572afb09257ba3555374032799580 Mon Sep 17 00:00:00 2001 From: guol-fnst Date: Wed, 15 Jun 2022 15:51:37 +0800 Subject: [PATCH 4/7] remove unused function remove log when weed is up to date add check whether weed is full version --- weed/command/update.go | 26 ++++++++++++-------------- weed/command/update_full.go | 9 +++++++++ 2 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 weed/command/update_full.go diff --git a/weed/command/update.go b/weed/command/update.go index 945ecc293..3f575d513 100644 --- a/weed/command/update.go +++ b/weed/command/update.go @@ -52,6 +52,9 @@ type githubError struct { Message string } +//default version is not full version +var isFullVersion = false + var ( updateOpt UpdateOptions ) @@ -91,16 +94,11 @@ func runUpdate(cmd *Command, args []string) bool { } } - glog.V(0).Infof("writing weed to %v\n", *updateOpt.Output) - v, err := downloadLatestStableRelease(context.Background(), *updateOpt.Output) if err != nil { - glog.Fatalf("unable to update weed: %v", err) + glog.Fatalf("unable to update weed to version %s: %v", err, v) return false } - - glog.V(0).Infof("successfully updated weed to version %v\n", v) - return true } @@ -123,12 +121,17 @@ func downloadLatestStableRelease(ctx context.Context, target string) (version st largeDiskSuffix = "_large_disk" } + fullSuffix := "" + if isFullVersion { + fullSuffix = "_full" + } + ext := "tar.gz" if runtime.GOOS == "windows" { ext = "zip" } - suffix := fmt.Sprintf("%s_%s%s.%s", runtime.GOOS, runtime.GOARCH, largeDiskSuffix, ext) + suffix := fmt.Sprintf("%s_%s%s%s.%s", runtime.GOOS, runtime.GOARCH, fullSuffix, largeDiskSuffix, ext) md5Filename := fmt.Sprintf("%s.md5", suffix) _, md5Val, err := getGithubDataFile(ctx, rel.Assets, md5Filename) if err != nil { @@ -152,18 +155,13 @@ func downloadLatestStableRelease(ctx context.Context, target string) (version st err = extractToFile(buf, downloadFilename, target) if err != nil { return "", err + } else { + glog.V(0).Infof("successfully updated weed to version %v\n", rel.Version) } return rel.Version, nil } -func (r Release) String() string { - return fmt.Sprintf("%v %v, %d assets", - r.TagName, - r.PublishedAt.Local().Format("2006-01-02 15:04:05"), - len(r.Assets)) -} - // GitHubLatestRelease uses the GitHub API to get information about the latest // release of a repository. func GitHubLatestRelease(ctx context.Context, owner, repo string) (Release, error) { diff --git a/weed/command/update_full.go b/weed/command/update_full.go new file mode 100644 index 000000000..529f38219 --- /dev/null +++ b/weed/command/update_full.go @@ -0,0 +1,9 @@ +//go:build elastic && ydb && gocdk && hdfs +// +build elastic,ydb,gocdk,hdfs + +package command + +//set true if gtags are set +func init() { + isFullVersion = true +} From 4bc879264335ed0f96fc9604d261efe37554e470 Mon Sep 17 00:00:00 2001 From: guol-fnst Date: Thu, 16 Jun 2022 11:19:49 +0800 Subject: [PATCH 5/7] support specific version of weed --- weed/command/update.go | 55 +++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/weed/command/update.go b/weed/command/update.go index 3f575d513..2f25cbe32 100644 --- a/weed/command/update.go +++ b/weed/command/update.go @@ -60,18 +60,20 @@ var ( ) type UpdateOptions struct { - Output *string + Output *string + Version *string } func init() { - updateOpt.Output = cmdUpdate.Flag.String("output", "weed", "Save the latest weed as `filename`") + updateOpt.Output = cmdUpdate.Flag.String("output", "weed", "Save the weed as `filename` or /path/to/dir/filename.") + updateOpt.Version = cmdUpdate.Flag.String("version", "0", "The version of weed you want to download. If not specified, get the latest version.") cmdUpdate.Run = runUpdate } var cmdUpdate = &Command{ UsageLine: "update [-output=weed]", - Short: "get latest version from https://github.com/chrislusf/seaweedfs", - Long: `get latest version from https://github.com/chrislusf/seaweedfs`, + Short: "get latest or specific version from https://github.com/chrislusf/seaweedfs", + Long: `get latest or specific version from https://github.com/chrislusf/seaweedfs`, } func runUpdate(cmd *Command, args []string) bool { @@ -80,41 +82,45 @@ func runUpdate(cmd *Command, args []string) bool { dirname := filepath.Dir(*updateOpt.Output) di, err := os.Lstat(dirname) if err != nil { - glog.Fatalf("unable to find directory:%s", dirname) + glog.Errorf("unable to find directory:%s", dirname) return false } if !di.Mode().IsDir() { - glog.Fatalf("output parent path %v is not a directory, use --output to specify a different file path", dirname) + glog.Errorf("output parent path %v is not a directory, use --output to specify a different file path", dirname) return false } } else { if !fi.Mode().IsRegular() { - glog.Fatalf("output path %v is not a normal file, use --output to specify a different file path", *updateOpt.Output) + glog.Errorf("output path %v is not a normal file, use --output to specify a different file path", *updateOpt.Output) return false } } - v, err := downloadLatestStableRelease(context.Background(), *updateOpt.Output) + _, err = downloadRelease(context.Background(), *updateOpt.Output, *updateOpt.Version) if err != nil { - glog.Fatalf("unable to update weed to version %s: %v", err, v) + glog.Errorf("unable to download weed: %v", err) return false } return true } -func downloadLatestStableRelease(ctx context.Context, target string) (version string, err error) { +func downloadRelease(ctx context.Context, target string, ver string) (version string, err error) { currentVersion := util.VERSION_NUMBER - rel, err := GitHubLatestRelease(ctx, "chrislusf", "seaweedfs") + rel, err := GitHubLatestRelease(ctx, ver, "chrislusf", "seaweedfs") if err != nil { return "", err } if rel.Version == currentVersion { - glog.V(0).Infof("weed is up to date\n") + if ver == "0" { + glog.V(0).Infof("weed is up to date") + } else { + glog.V(0).Infof("no need to download the same version of weed ") + } return currentVersion, nil } - glog.V(0).Infof("latest version is %v\n", rel.Version) + glog.V(0).Infof("download version: %s", rel.Version) largeDiskSuffix := "" if util.VolumeSizeLimitGB == 8000 { @@ -162,13 +168,13 @@ func downloadLatestStableRelease(ctx context.Context, target string) (version st return rel.Version, nil } -// GitHubLatestRelease uses the GitHub API to get information about the latest +// GitHubLatestRelease uses the GitHub API to get information about the specific // release of a repository. -func GitHubLatestRelease(ctx context.Context, owner, repo string) (Release, error) { +func GitHubLatestRelease(ctx context.Context, ver string, owner, repo string) (Release, error) { ctx, cancel := context.WithTimeout(ctx, githubAPITimeout) defer cancel() - url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", owner, repo) + url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases", owner, repo) req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return Release{}, err @@ -209,17 +215,28 @@ func GitHubLatestRelease(ctx context.Context, owner, repo string) (Release, erro } var release Release - err = json.Unmarshal(buf, &release) + var releaseList []Release + err = json.Unmarshal(buf, &releaseList) if err != nil { return Release{}, err } + if ver == "0" { + release = releaseList[0] + glog.V(0).Infof("latest version is %v\n", release.TagName) + } else { + for _, r := range releaseList { + if r.TagName == ver { + release = r + break + } + } + } if release.TagName == "" { - return Release{}, fmt.Errorf("tag name for latest release is empty") + return Release{}, fmt.Errorf("can not find the specific version") } release.Version = release.TagName - return release, nil } From 995e221e97d2cd9982d07c699afec4815d45e557 Mon Sep 17 00:00:00 2001 From: guol-fnst Date: Thu, 16 Jun 2022 15:56:34 +0800 Subject: [PATCH 6/7] remove -output, add -dir,-name for more flexibility --- weed/command/update.go | 64 ++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/weed/command/update.go b/weed/command/update.go index 2f25cbe32..df5988b6e 100644 --- a/weed/command/update.go +++ b/weed/command/update.go @@ -60,13 +60,17 @@ var ( ) type UpdateOptions struct { - Output *string + dir *string + name *string Version *string } func init() { - updateOpt.Output = cmdUpdate.Flag.String("output", "weed", "Save the weed as `filename` or /path/to/dir/filename.") - updateOpt.Version = cmdUpdate.Flag.String("version", "0", "The version of weed you want to download. If not specified, get the latest version.") + path, _ := os.Executable() + _, name := filepath.Split(path) + updateOpt.dir = cmdUpdate.Flag.String("dir", filepath.Dir(path), "directory to save new weed.") + updateOpt.name = cmdUpdate.Flag.String("name", name, "name of new weed.On windows, name shouldn't be same to the orignial name.") + updateOpt.Version = cmdUpdate.Flag.String("version", "0", "specific version of weed you want to download. If not specified, get the latest version.") cmdUpdate.Run = runUpdate } @@ -77,26 +81,33 @@ var cmdUpdate = &Command{ } func runUpdate(cmd *Command, args []string) bool { - fi, err := os.Lstat(*updateOpt.Output) - if err != nil { - dirname := filepath.Dir(*updateOpt.Output) - di, err := os.Lstat(dirname) - if err != nil { - glog.Errorf("unable to find directory:%s", dirname) - return false - } - if !di.Mode().IsDir() { - glog.Errorf("output parent path %v is not a directory, use --output to specify a different file path", dirname) + path, _ := os.Executable() + _, name := filepath.Split(path) + + if *updateOpt.dir != "" { + if err := util.TestFolderWritable(util.ResolvePath(*updateOpt.dir)); err != nil { + glog.Fatalf("Check Folder(-dir) Writable %s : %s", *updateOpt.dir, err) return false } } else { - if !fi.Mode().IsRegular() { - glog.Errorf("output path %v is not a normal file, use --output to specify a different file path", *updateOpt.Output) + *updateOpt.dir = filepath.Dir(path) + } + + if *updateOpt.name == "" { + *updateOpt.name = name + } + + if runtime.GOOS == "windows" { + if *updateOpt.name == name || *updateOpt.name == "" { + glog.Fatalf("On windows, name of the new weed shouldn't be same to the orignial name.") return false } } - _, err = downloadRelease(context.Background(), *updateOpt.Output, *updateOpt.Version) + target := *updateOpt.dir + "/" + *updateOpt.name + glog.V(0).Infof("new weed will be saved to %s", target) + + _, err := downloadRelease(context.Background(), target, *updateOpt.Version) if err != nil { glog.Errorf("unable to download weed: %v", err) return false @@ -360,11 +371,6 @@ func extractToFile(buf []byte, filename, target string) error { mode = fi.Mode() } - // Remove the original binary. - if err := removeWeedBinary(dir, target); err != nil { - return err - } - // Rename the temp file to the final location atomically. if err := os.Rename(new.Name(), target); err != nil { return err @@ -373,19 +379,3 @@ func extractToFile(buf []byte, filename, target string) error { glog.V(0).Infof("saved %d bytes in %v\n", n, target) return os.Chmod(target, mode) } - -// Rename (rather than remove) the running version. The running binary will be locked -// on Windows and cannot be removed while still executing. -func removeWeedBinary(dir, target string) error { - if runtime.GOOS == "linux" { - return nil - } - backup := filepath.Join(dir, filepath.Base(target)+".bak") - if _, err := os.Stat(backup); err == nil { - _ = os.Remove(backup) - } - if err := os.Rename(target, backup); err != nil { - return fmt.Errorf("unable to rename target file: %v", err) - } - return nil -} From cd078471c4a3f588d452d1ae92b7489a5186957b Mon Sep 17 00:00:00 2001 From: guol-fnst Date: Thu, 16 Jun 2022 16:52:57 +0800 Subject: [PATCH 7/7] fix path bug on windows fix usage --- weed/command/update.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/weed/command/update.go b/weed/command/update.go index df5988b6e..8e0a76016 100644 --- a/weed/command/update.go +++ b/weed/command/update.go @@ -69,13 +69,13 @@ func init() { path, _ := os.Executable() _, name := filepath.Split(path) updateOpt.dir = cmdUpdate.Flag.String("dir", filepath.Dir(path), "directory to save new weed.") - updateOpt.name = cmdUpdate.Flag.String("name", name, "name of new weed.On windows, name shouldn't be same to the orignial name.") + updateOpt.name = cmdUpdate.Flag.String("name", name, "name of new weed. On windows, name shouldn't be same to the orignial name.") updateOpt.Version = cmdUpdate.Flag.String("version", "0", "specific version of weed you want to download. If not specified, get the latest version.") cmdUpdate.Run = runUpdate } var cmdUpdate = &Command{ - UsageLine: "update [-output=weed]", + UsageLine: "weed update -dir=/path/to/dir -name=name -version=x.xx", Short: "get latest or specific version from https://github.com/chrislusf/seaweedfs", Long: `get latest or specific version from https://github.com/chrislusf/seaweedfs`, } @@ -97,14 +97,15 @@ func runUpdate(cmd *Command, args []string) bool { *updateOpt.name = name } + target := filepath.Join(*updateOpt.dir, *updateOpt.name) + if runtime.GOOS == "windows" { - if *updateOpt.name == name || *updateOpt.name == "" { + if target == path { glog.Fatalf("On windows, name of the new weed shouldn't be same to the orignial name.") return false } } - target := *updateOpt.dir + "/" + *updateOpt.name glog.V(0).Infof("new weed will be saved to %s", target) _, err := downloadRelease(context.Background(), target, *updateOpt.Version)