Commit 346a0811 authored by zauberstuhl's avatar zauberstuhl

Merge branch 'updater' into 'master'

Add and use bintray fetcher in updater agent

See merge request !70
parents 55fdbffa 476733b9
Pipeline #310 passed with stages
in 37 minutes and 48 seconds
......@@ -7,7 +7,7 @@ log/
# build
*.tar.gz
conf/app.conf
bindata.go
updater/bindata.go
# assets
app/assets/vendor
......
......@@ -51,7 +51,7 @@ endif
clean:
rm -r tmp vendor node_modules \
test-results bindata.go \
test-results updater/bindata.go \
updater.*.bin *.tar.gz || true
precompile:
......@@ -103,10 +103,10 @@ endif
mkdir -p $(srcdir)/tmp && cd $$_ && { \
tar -x -f "../ganggo.tar.gz" ;\
[ -f "ganggo.exe" ] && mv ganggo.exe ganggo ;\
go-bindata -ignore \
'src/$(package)/[vendor|node_modules|bindata.go|.*\.tar\.gz|tmp]' \
-o ../bindata.go ganggo src/... ;\
go-bindata -o ../updater/bindata.go ganggo \
src/github.com/revel/... \
src/$(package)/{app,conf,messages,public}/... ;\
}
cd $(srcdir) && go build \
cd $(srcdir)/updater && go build \
-ldflags "-X main.version=$(version)" \
-o updater.$$GOOS-$$GOARCH$$GOARM.bin updater.go bindata.go
-o ../updater.$$GOOS-$$GOARCH$$GOARM.bin updater.go bin*.go
package main
//
// GangGo Application Server
// Copyright (C) 2018 Lukas Matt <lukas@zauberstuhl.de>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
import (
"fmt"
"io"
"net/http"
"time"
"runtime"
"encoding/json"
)
const (
BINTRAY_API = "https://api.bintray.com/packages/%s/%s/%s/versions/_latest"
BINTRAY_DL = "https://dl.bintray.com/%s/%s/updater.%s-%s.%s.bin"
)
type Bintray struct {
User, Repo, Pkg string
Interval time.Duration
// internal
delay bool
last time.Time
}
type ApiResponse struct {
Name string
Created time.Time
}
// Init validates the provided config
func (h *Bintray) Init() error {
//apply defaults
if h.User == "" || h.Repo == "" || h.Pkg == "" {
return fmt.Errorf("User, Repo and Pkg required")
}
if h.Interval == 0 {
h.Interval = 5 * time.Minute
}
return nil
}
// Fetch the binary from the provided URL
func (h *Bintray) Fetch() (io.Reader, error) {
// delay fetches after first
if h.delay {
time.Sleep(h.Interval)
}
h.delay = true
// check version and return if no update is necessary
// https://api.bintray.com/packages/:user/:repo/:pkg/versions/_latest
resp, err := http.Get(fmt.Sprintf(BINTRAY_API, h.User, h.Repo, h.Pkg))
if err != nil {
return nil, fmt.Errorf("GET request failed (%s)", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("GET request failed (status code %d)", resp.StatusCode)
}
apiResp := ApiResponse{}
decoder := json.NewDecoder(resp.Body)
err = decoder.Decode(&apiResp)
if err != nil {
return nil, fmt.Errorf("DECODER failed (%s)", err)
}
if apiResp.Created.Before(h.last) {
return nil, nil
}
h.last = apiResp.Created
// binary fetch using GET
resp, err = http.Get(fmt.Sprintf(BINTRAY_DL, h.User, h.Repo,
runtime.GOOS, runtime.GOARCH, apiResp.Name))
if err != nil {
return nil, fmt.Errorf("GET request failed (%s)", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("GET request failed (status code %d)", resp.StatusCode)
}
return resp.Body, nil
}
package main
//
// GangGo Application Server
// Copyright (C) 2017 Lukas Matt <lukas@zauberstuhl.de>
// Copyright (C) 2018 Lukas Matt <lukas@zauberstuhl.de>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -18,18 +18,15 @@ package main
//
import (
"io/ioutil"
"time"
"fmt"
"strings"
"flag"
"github.com/jpillora/overseer"
"github.com/jpillora/overseer/fetcher"
"os"
"os/exec"
"github.com/revel/config"
"runtime"
"gopkg.in/AlecAivazis/survey.v1"
"github.com/getlantern/byteexec"
)
var (
......@@ -179,13 +176,22 @@ func main() {
interval = 1 * time.Hour
}
// Delete old files
// Restore assets and delete old files
os.RemoveAll("src")
// Extract assets and golang libraries
err := RestoreAssets("", "src")
if err != nil {
panic(err)
}
bin, err := ganggoBytes()
if err != nil {
panic(err)
}
// Restore ganggo binary file
bexec, err := byteexec.New(bin, fmt.Sprintf("ganggo.%s-%s.%s",
runtime.GOOS, runtime.GOARCH, version))
if err != nil {
panic(err)
}
// if app.conf is not in the current
// directory start the wizard and create it
......@@ -221,76 +227,39 @@ func main() {
}
overseer.Run(overseer.Config{
Program: prog,
Fetcher: &fetcher.Github{
Program: func(state overseer.State) {
// read config file from wizard and copy it to src folder
config, err := config.ReadDefault(userConfigPath)
if err != nil {
panic(err)
}
err = config.WriteFile(configPath, 0644, "AUTO-GENERATED BY GANGGO WIZARD")
if err != nil {
panic(err)
}
cmd := bexec.Command("-importPath", packageName,
"-srcPath", "src", "-runMode", mode)
if mode != "prod" {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
fmt.Printf("app#%s %s listening...\n", version, state.ID)
if err := cmd.Start(); err != nil {
panic(err)
}
// wait for overseer to restart or terminate
<-state.GracefulShutdown
fmt.Printf("app#%s %s exiting...\n", version, state.ID)
},
Fetcher: &Bintray{
User: "ganggo",
Repo: "ganggo",
Asset: AssetValidator,
Pkg: updateChannel,
Interval: interval,
},
Debug: true,
})
}
// Add the ability to use multiple update channel via Github-fetcher
func AssetValidator(filename string) bool {
defaultAsset := strings.Contains(filename, runtime.GOOS) && strings.Contains(filename, runtime.GOARCH)
if defaultAsset && updateChannel == "stable" {
return true
}
return defaultAsset && strings.Contains(filename, updateChannel)
}
func prog(state overseer.State) {
buildID := int32(time.Now().Unix())
binFile := fmt.Sprintf("./ganggo.%s.%d", version, buildID)
if runtime.GOOS == "windows" {
binFile = fmt.Sprintf("ganggo.%s.%d.exe", version, buildID)
}
// clean-up binaries
defer func() {
os.Remove(binFile)
}()
// restore app binary
asset, err := ganggoBytes()
if err != nil {
panic(err)
}
err = ioutil.WriteFile(binFile, asset, 0755)
if err != nil {
panic(err)
}
// read config file from wizard and copy it to src folder
config, err := config.ReadDefault(userConfigPath)
if err != nil {
panic(err)
}
err = config.WriteFile(configPath, 0644, "AUTO-GENERATED BY GANGGO WIZARD")
if err != nil {
panic(err)
}
cmd := exec.Command(binFile, "-importPath", packageName,
"-srcPath", "src", "-runMode", mode)
if mode != "prod" {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
fmt.Printf("app#%s %s listening...\n", version, state.ID)
if err := cmd.Start(); err != nil {
panic(err)
}
// wait for overseer to restart or terminate
<-state.GracefulShutdown
// send kill signal to old process
cmd.Process.Kill()
fmt.Printf("app#%s %s exiting...\n", version, state.ID)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment