Skip to content

Instantly share code, notes, and snippets.

@bkcsoft
Created April 16, 2016 22:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bkcsoft/b1c0c258a355510f5d304ff9754852e5 to your computer and use it in GitHub Desktop.
Save bkcsoft/b1c0c258a355510f5d304ff9754852e5 to your computer and use it in GitHub Desktop.
package main
import (
"errors"
"path/filepath"
"archive/zip"
"io"
"log"
"net/http"
"os"
"regexp"
"runtime"
"github.com/google/go-github/github"
)
var (
assetReleaseRegexp = regexp.MustCompile(`^(?P<os>[a-z0-9]+)_(?P<arch>[a-z0-9]+).(?P<ext>[a-z0-9\._-]+)`)
)
var (
ghOwner = "gogits"
ghRepo = "gogs"
extractDir = "./"
)
type Version struct {
URL string
Name string
Version string
}
func getVersion(owner, repo string) (*Version, error) {
client := github.NewClient(nil)
rel, resp, err := client.Repositories.GetLatestRelease(owner, repo)
if err != nil {
if _, ok := err.(*github.RateLimitError); ok {
log.Print("[ERROR] RateLimit Hit!")
}
return nil, err
}
log.Printf("[INFO] RateLimit %d/%d\n", resp.Remaining, resp.Limit)
if resp.Remaining-5 <= 0 {
log.Print("[WARN] Close to RateLimit!")
}
for _, v := range rel.Assets {
m := assetReleaseRegexp.FindStringSubmatch(*v.Name)
if len(m) > 0 && m[1] == runtime.GOOS && m[2] == runtime.GOARCH && m[3] == "zip" {
ver := &Version{URL: *v.BrowserDownloadURL, Name: *v.Name, Version: *rel.TagName}
return ver, nil
}
}
return nil, errors.New("No version found? o.O")
}
// Gracefully stolen from http://stackoverflow.com/a/33853856
func downloadFile(filepath string, url string) (err error) {
// Create the file
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
// Get the data
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
// Writer the body to file
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
return nil
}
// Gracefully stolen from http://stackoverflow.com/a/24792688
func unzipToDir(src, dest string) error {
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer func() {
if err := r.Close(); err != nil {
panic(err)
}
}()
os.MkdirAll(dest, 0755)
// Closure to address file descriptors issue with all the deferred .Close() methods
extractAndWriteFile := func(f *zip.File) error {
rc, err := f.Open()
if err != nil {
return err
}
defer func() {
if err := rc.Close(); err != nil {
panic(err)
}
}()
path := filepath.Join(dest, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(path, f.Mode())
} else {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
panic(err)
}
}()
_, err = io.Copy(f, rc)
if err != nil {
return err
}
}
return nil
}
for _, f := range r.File {
err := extractAndWriteFile(f)
if err != nil {
return err
}
}
return nil
}
func main() {
log.Printf("Fetching version-data for %s/%s\n", ghOwner, ghRepo)
version, err := getVersion(ghOwner, ghRepo)
if err != nil {
log.Fatal("[ERROR]", err.Error())
}
if version == nil {
log.Fatal("[ERROR] Pointer to Version is broken :/")
}
// Add check to determine new version!
// if version.Version != gogs.Version {
if _, err := os.Stat(version.Name); os.IsNotExist(err) {
log.Print("[INFO] Fetching new version", version.Version)
if err := downloadFile(version.Name, version.URL); err != nil {
log.Fatal("[ERROR]", err.Error())
}
}
log.Print("[INFO] Extracting new version to ", extractDir)
if err := unzipToDir(version.Name, extractDir); err != nil {
log.Fatal("[ERROR]", err.Error())
}
}
@bkcsoft
Copy link
Author

bkcsoft commented Apr 16, 2016

Outputs (on success):

[bkc@bkc-900] $ go run main.go 
2016/04/17 00:51:06 Fetching version-data for gogits/gogs
2016/04/17 00:51:07 [INFO] RateLimit 51/60
2016/04/17 00:51:07 [INFO] Fetching new versionv0.9.13
2016/04/17 00:51:17 [INFO] Extracting new version to ./

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment