Skip to content

Commit

Permalink
Merge pull request #11 from mouuff/feature/gzip
Browse files Browse the repository at this point in the history
Feature/gzip
  • Loading branch information
mouuff authored Feb 25, 2021
2 parents d5e6d67 + e5f0799 commit 1e14674
Show file tree
Hide file tree
Showing 22 changed files with 354 additions and 62 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Here is an example using Github releases:
u := &updater.Updater{
Provider: &provider.Github{
RepositoryURL: "github.com/mouuff/go-rocket-update-example",
ZipName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
ArchiveName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
},
ExecutableName: fmt.Sprintf("go-rocket-update-example_%s_%s", runtime.GOOS, runtime.GOARCH),
Version: "v0.0.1",
Expand All @@ -53,10 +53,11 @@ Check this project for a complete example: https://github.com/mouuff/go-rocket-u
The updater uses a `Provider` as an input source for updates. It provides files and version for the updater.

Here is few examples of providers:
* `provider.Github`: It will check for the latest release on Github with a specific zip name
* `provider.Gitlab`: It will check for the latest release on Gitlab with a specific zip name
* `provider.Github`: It will check for the latest release on Github with a specific archive name (zip or tar.gz)
* `provider.Gitlab`: It will check for the latest release on Gitlab with a specific archive name (zip or tar.gz)
* `provider.Local`: It will use a local folder, version will be defined in the VERSION file (can be used for testing, or in a company with a shared folder for example)
* `provider.Zip`: Same as provider.Local but with a `Zip` file
* `provider.Zip`: It will use a `zip` file. The version is defined by the file name (Example: `binaries-v1.0.0.tar.gz`)
* `provider.Gzip`: Same as `provider.Zip` but with a `tar.gz` file.

*In the future there will be providers for FTP servers and Google cloud storage.*

Expand Down Expand Up @@ -86,6 +87,7 @@ This project is currently under construction, here is some of the things to come
- **Feb 7, 2021**: Minor: The `BinaryName` variable used in `Updater` have been renamed to `ExecutableName`.
- **Feb 12, 2021**: Minor: The method `Updater.Update()` now returns `(UpdateStatus, error)` instead of just `(error)`.
- **Feb 14, 2021**: Major: The `ExecutableName` variable used in `Updater` is no longer suffixed with `"_" + runtime.GOOS + "_" + runtime.GOARCH`.
- **Feb 21, 2021**: Minor: The `ZipName` variable used in `provider.Github` and `provider.Gitlab` have been renamed to `ArchiveName ` with the arrival of `tar.gz` support.


[tu]: https://twitter.com/tenntenn
Expand Down
2 changes: 1 addition & 1 deletion examples/github-background/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func main() {
u := &updater.Updater{
Provider: &provider.Github{
RepositoryURL: "github.com/mouuff/go-rocket-update-example",
ZipName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
ArchiveName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
},
ExecutableName: fmt.Sprintf("go-rocket-update-example_%s_%s", runtime.GOOS, runtime.GOARCH),
Version: "v0.0.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/github-rollback/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func main() {
u := &updater.Updater{
Provider: &provider.Github{
RepositoryURL: "github.com/mouuff/go-rocket-update-example",
ZipName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
ArchiveName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
},
ExecutableName: fmt.Sprintf("go-rocket-update-example_%s_%s", runtime.GOOS, runtime.GOARCH),
Version: "v0.0.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/github-simple/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func main() {
u := &updater.Updater{
Provider: &provider.Github{
RepositoryURL: "github.com/mouuff/go-rocket-update-example",
ZipName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
ArchiveName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
},
ExecutableName: fmt.Sprintf("go-rocket-update-example_%s_%s", runtime.GOOS, runtime.GOARCH),
Version: "v0.0.0",
Expand Down
4 changes: 2 additions & 2 deletions examples/gitlab-simple/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ func main() {
// Example project here: https://gitlab.com/arnaudalies.py/go-rocket-update-example
u := &updater.Updater{
Provider: &provider.Gitlab{
ProjectID: 24021648,
ZipName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
ProjectID: 24021648,
ArchiveName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
},
ExecutableName: fmt.Sprintf("go-rocket-update-example_%s_%s", runtime.GOOS, runtime.GOARCH),
Version: "v0.0.0",
Expand Down
44 changes: 44 additions & 0 deletions pkg/provider/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package provider

import (
"os"
"path/filepath"
"regexp"
"time"
)

// GetLatestVersionFromPath finds the latest version from a path
// This is used by provider zip and gzip
// Example: /example/binaries-v1.4.53.zip is going to match "v1.4.53"
func GetLatestVersionFromPath(path string) (string, error) {
// TODO unittest
versionRegex := regexp.MustCompile(`v[0-9]+\.[0-9]+\.[0-9]+`)
version := string(versionRegex.Find([]byte(filepath.Base(path))))
if version == "" {
return "", ErrProviderUnavaiable
}
return version, nil
}

// GlobNewestFile same as filepath.Glob but returns only one file with the latest modification time
func GlobNewestFile(pattern string) (string, error) {
matches, err := filepath.Glob(pattern)
if err != nil {
return "", err
}
var newestTime time.Time
var newestFile string
for _, match := range matches {
file, err := os.Stat(match)
if err == nil {
if newestFile == "" || newestTime.Before(file.ModTime()) {
newestFile = match
newestTime = file.ModTime()
}
}
}
if newestFile == "" {
return "", ErrFileNotFound
}
return newestFile, nil
}
47 changes: 47 additions & 0 deletions pkg/provider/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package provider_test

import (
"os"
"path/filepath"
"testing"
"time"

provider "github.com/mouuff/go-rocket-update/pkg/provider"
)

func TestGetLatestVersionFromPath(t *testing.T) {
version, err := provider.GetLatestVersionFromPath("binaries-v1.2.3.zip")
if err != nil {
t.Fatal(err)
}
if version != "v1.2.3" {
t.Error("version != 'v1.2.3'")
}

version, err = provider.GetLatestVersionFromPath("binaries-v.zip")
if err == nil {
t.Error("Should return an error")
}
}

func TestGlobNewestFile(t *testing.T) {
filename := "Allum1-v1.1.0.tar.gz"
currentTime := time.Now().Local().Add(time.Second)
err := os.Chtimes(filepath.Join("testdata", filename), currentTime, currentTime)
if err != nil {
t.Fatal(err)
}

match, err := provider.GlobNewestFile(filepath.Join("testdata", "Allum1-v*.tar.gz"))
if err != nil {
t.Fatal(err)
}
if filepath.Base(match) != filename {
t.Error("Expected " + filename)
}

match, err = provider.GlobNewestFile(filepath.Join("testdata", "doesntexists"))
if err == nil {
t.Error("Should return an error if file doesn't exists")
}
}
20 changes: 20 additions & 0 deletions pkg/provider/provider_decompress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package provider

import (
"errors"
"strings"
)

// Decompress gets a provider to decompress zip or tar.gz files
func Decompress(path string) (Provider, error) {
if strings.HasSuffix(path, ".zip") {
return &Zip{
Path: path,
}, nil
} else if strings.HasSuffix(path, ".tar.gz") {
return &Gzip{
Path: path,
}, nil
}
return nil, errors.New("provider.Decompress unknown file type for file: " + path)
}
40 changes: 40 additions & 0 deletions pkg/provider/provider_decompress_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package provider_test

import (
"path/filepath"
"testing"

provider "github.com/mouuff/go-rocket-update/pkg/provider"
)

func TestProviderDecompressZip(t *testing.T) {
p, err := provider.Decompress(filepath.Join("testdata", "Allum1-v1.0.0.zip"))
if err != nil {
t.Fatal(err)
}
if err := p.Open(); err != nil {
t.Fatal(err)
}
defer p.Close()

err = ProviderTestWalkAndRetrieve(p)
if err != nil {
t.Fatal(err)
}
}

func TestProviderDecompressGzip(t *testing.T) {
p, err := provider.Decompress(filepath.Join("testdata", "Allum1-v1.0.0.tar.gz"))
if err != nil {
t.Fatal(err)
}
if err := p.Open(); err != nil {
t.Fatal(err)
}
defer p.Close()

err = ProviderTestWalkAndRetrieve(p)
if err != nil {
t.Fatal(err)
}
}
47 changes: 25 additions & 22 deletions pkg/provider/provider_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import (
"github.com/mouuff/go-rocket-update/internal/fileio"
)

// Github provider finds a zip file in the repository's releases to provide files
// Github provider finds a archive file in the repository's releases to provide files
type Github struct {
RepositoryURL string // Repository URL, example github.com/mouuff/go-rocket-update
ZipName string // Zip name (the zip you upload for a release on github), example: binaries.zip
ArchiveName string // Archive name (the zip/tar.gz you upload for a release on github), example: binaries.zip

tmpDir string // temporary directory this is used internally
zipProvider *Zip // provider used to unzip the downloaded zip
zipPath string // path to the downloaded zip (should be in tmpDir)
tmpDir string // temporary directory this is used internally
decompressProvider Provider // provider used to decompress the downloaded archive
archivePath string // path to the downloaded archive (should be in tmpDir)
}

// githubTag struct used to unmarshal response from github
Expand Down Expand Up @@ -61,9 +61,9 @@ func (c *Github) getTagsURL() (string, error) {
), nil
}

// getZipURL get the zip URL for the github repository
// getArchiveURL get the archive URL for the github repository
// If no tag is provided then the latest version is selected
func (c *Github) getZipURL(tag string) (string, error) {
func (c *Github) getArchiveURL(tag string) (string, error) {
if len(tag) == 0 {
// Get latest version if no tag is provided
var err error
Expand All @@ -81,7 +81,7 @@ func (c *Github) getZipURL(tag string) (string, error) {
info.RepositoryOwner,
info.RepositoryName,
tag,
c.ZipName,
c.ArchiveName,
), nil
}

Expand All @@ -105,11 +105,11 @@ func (c *Github) getTags() (tags []githubTag, err error) {

// Open opens the provider
func (c *Github) Open() (err error) {
zipURL, err := c.getZipURL("") // get zip url for latest version
archiveURL, err := c.getArchiveURL("") // get archive url for latest version
if err != nil {
return
}
resp, err := http.Get(zipURL)
resp, err := http.Get(archiveURL)
if err != nil {
return
}
Expand All @@ -120,31 +120,34 @@ func (c *Github) Open() (err error) {
return
}

c.zipPath = filepath.Join(c.tmpDir, c.ZipName)
zipFile, err := os.Create(c.zipPath)
c.archivePath = filepath.Join(c.tmpDir, c.ArchiveName)
archiveFile, err := os.Create(c.archivePath)
if err != nil {
return
}
_, err = io.Copy(zipFile, resp.Body)
zipFile.Close()
_, err = io.Copy(archiveFile, resp.Body)
archiveFile.Close()
if err != nil {
return
}
c.zipProvider = &Zip{Path: c.zipPath}
return c.zipProvider.Open()
c.decompressProvider, err = Decompress(c.archivePath)
if err != nil {
return nil
}
return c.decompressProvider.Open()
}

// Close closes the provider
func (c *Github) Close() error {
if c.zipProvider != nil {
c.zipProvider.Close()
c.zipProvider = nil
if c.decompressProvider != nil {
c.decompressProvider.Close()
c.decompressProvider = nil
}

if len(c.tmpDir) > 0 {
os.RemoveAll(c.tmpDir)
c.tmpDir = ""
c.zipPath = ""
c.archivePath = ""
}
return nil
}
Expand All @@ -163,10 +166,10 @@ func (c *Github) GetLatestVersion() (string, error) {

// Walk walks all the files provided
func (c *Github) Walk(walkFn WalkFunc) error {
return c.zipProvider.Walk(walkFn)
return c.decompressProvider.Walk(walkFn)
}

// Retrieve file relative to "provider" to destination
func (c *Github) Retrieve(src string, dest string) error {
return c.zipProvider.Retrieve(src, dest)
return c.decompressProvider.Retrieve(src, dest)
}
2 changes: 1 addition & 1 deletion pkg/provider/provider_github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
func TestProviderGithub(t *testing.T) {
p := &provider.Github{
RepositoryURL: "github.com/mouuff/go-rocket-update-example",
ZipName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
ArchiveName: fmt.Sprintf("binaries_%s.zip", runtime.GOOS),
}
if err := p.Open(); err != nil {
t.Fatal(err)
Expand Down
Loading

0 comments on commit 1e14674

Please sign in to comment.