From bfc6ca6686ee11b2d87fa5c4d4b571dc3be86095 Mon Sep 17 00:00:00 2001 From: Quentin Cuvillier Date: Tue, 2 Jun 2015 00:04:48 -0700 Subject: [PATCH 1/2] updater --- deploy.go | 14 +++++ updater.go | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 updater.go diff --git a/deploy.go b/deploy.go index 724554a..27b46e1 100644 --- a/deploy.go +++ b/deploy.go @@ -69,6 +69,10 @@ var flags = []cli.Flag{ Name: "quiet, q", Usage: "Silence any output to STDOUT.", }, + cli.BoolFlag{ + Name: "update, u", + Usage: "Update the binary", + }, } var ProtectedEnvironments = map[string]bool{ @@ -83,6 +87,16 @@ func NewApp() *cli.App { app.Usage = Usage app.Flags = flags app.Action = func(c *cli.Context) { + if c.Bool("update") { + updater := NewUpdater() + if err := updater.Update(); err != nil { + fmt.Println(err) + os.Exit(-1) + } else { + os.Exit(0) + } + } + if err := RunDeploy(c); err != nil { msg := err.Error() if err, ok := err.(*github.ErrorResponse); ok { diff --git a/updater.go b/updater.go new file mode 100644 index 0000000..53cb43f --- /dev/null +++ b/updater.go @@ -0,0 +1,182 @@ +package deploy + +import ( + "archive/zip" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/remind101/deploy/Godeps/_workspace/src/github.com/inconshreveable/go-update" + "github.com/remind101/deploy/Godeps/_workspace/src/github.com/octokit/go-octokit/octokit" +) + +const GitHubHost = "github.com" + +type Updater struct { + Host string + CurrentVersion string +} + +func NewUpdater() *Updater { + version := Version + return &Updater{ + Host: GitHubHost, + CurrentVersion: version, + } +} + +func (updater *Updater) Update() (err error) { + releaseName, version := updater.latestReleaseNameAndVersion() + + if version == "" { + fmt.Println("There is no newer version of Deploy available.") + return + } + + if version == updater.CurrentVersion { + fmt.Printf("You're already on the latest version: %s\n", version) + } else { + err = updater.updateTo(releaseName, version) + } + + return +} + +func (updater *Updater) updateTo(releaseName, version string) (err error) { + downloadURL := fmt.Sprintf("https://%s/remind101/deploy/releases/download/%s/deploy_%s_%s_%s.zip", updater.Host, releaseName, version, runtime.GOOS, runtime.GOARCH) + + fmt.Printf("Downloading %s...", version) + path, err := downloadFile(downloadURL) + if err != nil { + return + } + + exec, err := unzipExecutable(path) + if err != nil { + return + } + + err, _ = update.New().FromFile(exec) + if err != nil { + fmt.Printf("Update failed: %v\n", err) + } + + return +} + +func unzipExecutable(path string) (exec string, err error) { + rc, err := zip.OpenReader(path) + if err != nil { + err = fmt.Errorf("Can't open zip file %s: %s", path, err) + return + } + defer rc.Close() + + for _, file := range rc.File { + if !strings.HasPrefix(file.Name, "deploy") { + continue + } + + dir := filepath.Dir(path) + exec, err = unzipFile(file, dir) + break + } + + if exec == "" && err == nil { + err = fmt.Errorf("No Deploy executable is found in %s", path) + } + + return +} + +func unzipFile(file *zip.File, to string) (exec string, err error) { + frc, err := file.Open() + if err != nil { + err = fmt.Errorf("Can't open zip entry %s when reading: %s", file.Name, err) + return + } + defer frc.Close() + + dest := filepath.Join(to, filepath.Base(file.Name)) + f, err := os.Create(dest) + if err != nil { + return + } + defer f.Close() + + copied, err := io.Copy(f, frc) + if err != nil { + return + } + + if uint32(copied) != file.UncompressedSize { + err = fmt.Errorf("Zip entry %s is corrupted", file.Name) + return + } + + exec = f.Name() + + return +} + +func downloadFile(url string) (path string, err error) { + dir, err := ioutil.TempDir("", "deploy-update") + if err != nil { + return + } + + resp, err := http.Get(url) + if err != nil { + return + } + defer resp.Body.Close() + + if resp.StatusCode >= 300 || resp.StatusCode < 200 { + err = fmt.Errorf("Can't download %s: %d", url, resp.StatusCode) + return + } + + file, err := os.Create(filepath.Join(dir, filepath.Base(url))) + if err != nil { + return + } + defer file.Close() + + _, err = io.Copy(file, resp.Body) + if err != nil { + return + } + + path = file.Name() + + return +} + +func (updater *Updater) latestReleaseNameAndVersion() (name, version string) { + client := octokit.NewClient(nil) + + url, err := octokit.ReleasesURL.Expand(octokit.M{"owner": "remind101", "repo": "deploy"}) + if err != nil { + return + } + + releases, result := client.Releases(url).All() + if result.HasError() { + err = fmt.Errorf("Error getting Deploy release: %s", result.Err) + return + } + + if len(releases) == 0 { + err = fmt.Errorf("No Deploy release is available") + return + } + + name = releases[0].TagName + version = strings.TrimPrefix(name, "v") + return +} From 3d3f8b7e4df19d208237805a06d81f5e784dab19 Mon Sep 17 00:00:00 2001 From: Quentin Cuvillier Date: Wed, 3 Jun 2015 00:11:07 -0700 Subject: [PATCH 2/2] stop packaging release binaries & update url to accomodate new url --- Makefile | 2 +- scripts/release | 11 +++++ updater.go | 108 +----------------------------------------------- 3 files changed, 14 insertions(+), 107 deletions(-) create mode 100755 scripts/release diff --git a/Makefile b/Makefile index 4051ca4..add7e34 100644 --- a/Makefile +++ b/Makefile @@ -4,4 +4,4 @@ cmd: godep go build -o build/deploy ./cmd/deploy release: - goxc -bc="linux,darwin" -d build -pv="0.0.3" + ./scripts/release $(VERSION) diff --git a/scripts/release b/scripts/release new file mode 100755 index 0000000..2bb4939 --- /dev/null +++ b/scripts/release @@ -0,0 +1,11 @@ +#!/bin/bash + +if [ -z "$1" ]; then + echo "need version number. make release VERSION=0.0.3" + exit +fi + +goxc -bc="linux,darwin" -d build -pv="$1" -tasks-=package + +find $(dirname $0)/../build/$1/* -type d -exec mv -n -- {}/deploy {}_deploy \; +rm -R -- $(dirname $0)/../build/$1/*/ diff --git a/updater.go b/updater.go index 53cb43f..5ed92ab 100644 --- a/updater.go +++ b/updater.go @@ -1,13 +1,7 @@ package deploy import ( - "archive/zip" "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" "runtime" "strings" @@ -48,20 +42,10 @@ func (updater *Updater) Update() (err error) { } func (updater *Updater) updateTo(releaseName, version string) (err error) { - downloadURL := fmt.Sprintf("https://%s/remind101/deploy/releases/download/%s/deploy_%s_%s_%s.zip", updater.Host, releaseName, version, runtime.GOOS, runtime.GOARCH) + downloadURL := fmt.Sprintf("https://%s/remind101/deploy/releases/download/%s/%s_%s_deploy", updater.Host, releaseName, runtime.GOOS, runtime.GOARCH) fmt.Printf("Downloading %s...", version) - path, err := downloadFile(downloadURL) - if err != nil { - return - } - - exec, err := unzipExecutable(path) - if err != nil { - return - } - - err, _ = update.New().FromFile(exec) + err, _ = update.New().FromUrl(downloadURL) if err != nil { fmt.Printf("Update failed: %v\n", err) } @@ -69,94 +53,6 @@ func (updater *Updater) updateTo(releaseName, version string) (err error) { return } -func unzipExecutable(path string) (exec string, err error) { - rc, err := zip.OpenReader(path) - if err != nil { - err = fmt.Errorf("Can't open zip file %s: %s", path, err) - return - } - defer rc.Close() - - for _, file := range rc.File { - if !strings.HasPrefix(file.Name, "deploy") { - continue - } - - dir := filepath.Dir(path) - exec, err = unzipFile(file, dir) - break - } - - if exec == "" && err == nil { - err = fmt.Errorf("No Deploy executable is found in %s", path) - } - - return -} - -func unzipFile(file *zip.File, to string) (exec string, err error) { - frc, err := file.Open() - if err != nil { - err = fmt.Errorf("Can't open zip entry %s when reading: %s", file.Name, err) - return - } - defer frc.Close() - - dest := filepath.Join(to, filepath.Base(file.Name)) - f, err := os.Create(dest) - if err != nil { - return - } - defer f.Close() - - copied, err := io.Copy(f, frc) - if err != nil { - return - } - - if uint32(copied) != file.UncompressedSize { - err = fmt.Errorf("Zip entry %s is corrupted", file.Name) - return - } - - exec = f.Name() - - return -} - -func downloadFile(url string) (path string, err error) { - dir, err := ioutil.TempDir("", "deploy-update") - if err != nil { - return - } - - resp, err := http.Get(url) - if err != nil { - return - } - defer resp.Body.Close() - - if resp.StatusCode >= 300 || resp.StatusCode < 200 { - err = fmt.Errorf("Can't download %s: %d", url, resp.StatusCode) - return - } - - file, err := os.Create(filepath.Join(dir, filepath.Base(url))) - if err != nil { - return - } - defer file.Close() - - _, err = io.Copy(file, resp.Body) - if err != nil { - return - } - - path = file.Name() - - return -} - func (updater *Updater) latestReleaseNameAndVersion() (name, version string) { client := octokit.NewClient(nil)