Skip to content

Commit

Permalink
Merge pull request #139 from onflowser/flow_cli_module
Browse files Browse the repository at this point in the history
Flow CLI integration module
  • Loading branch information
sideninja authored Nov 21, 2022
2 parents a7aefeb + b13e622 commit 0917f3b
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 0 deletions.
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/onflowser/flowser

go 1.19

require github.com/google/go-github v17.0.0+incompatible

require github.com/google/go-querystring v1.1.0 // indirect
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
2 changes: 2 additions & 0 deletions pkg/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Temp installation dir used for testing
test-install
211 changes: 211 additions & 0 deletions pkg/flowser/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package flowser

import (
"context"
"errors"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"os/signal"
"path"
"runtime"
"strings"
"syscall"

"github.com/google/go-github/github"
)

const (
darwin = "darwin"
windows = "windows"
)

// New create new Flowser application.
func New() *App {
return &App{}
}

type App struct{}

var errorPlatformNotSupported = errors.New("OS not supported, only supporting Windows and Mac OS")

// Run starts the Flowser application with provided path to the flow project.
//
// Project path if exists should be set to the folder containing flow.json, if no such path exists pass empty value.
func (a *App) Run(installDir string, projectPath string) error {
exe, err := a.executable(installDir)
if err != nil {
return err
}

if projectPath != "" {
projectPath = fmt.Sprintf("--project-path=%s", projectPath)
}

cmd := exec.Command(exe, projectPath)

go func() {
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt)
signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
<-sig
_ = cmd.Process.Kill()
}()

return cmd.Run()
}

// Install Flowser application in the provided install directory.
func (a *App) Install(installDir string) error {
downloadDir, err := downloadLatestReleaseAsset()
if err != nil {
return err
}

defer os.Remove(downloadDir)
return a.unzip(downloadDir, installDir)
}

// Installed checks whether the flowser application is already installed on the system.
func (a *App) Installed(installDir string) bool {
executable, err := a.executable(installDir)
if err != nil {
return false
}

_, err = os.Stat(executable)
return err == nil
}

// Remove Flowser application from provide directory.
//
// Install directory is optional, if you don't provide a value default will be used.
func (a *App) Remove(installDir string) error {
dir, err := a.appDir(installDir)
if err != nil {
return err
}

return os.RemoveAll(dir)
}

// unzip content from source compressed file to a target directory.
func (a *App) unzip(source string, target string) error {
var cmd *exec.Cmd
switch runtime.GOOS {
case darwin:
// Use native unzip tool as it handles the creation of required symbolic links
cmd = exec.Command("unzip", source, "-d", target)
case windows:
appDir, err := a.appDir(target)
if err != nil {
return err
}

if err := os.MkdirAll(appDir, os.ModePerm); err != nil {
return err
}

// tar utility is available from Windows build 17063 consider using other command or a custom implementation
// https://learn.microsoft.com/en-us/virtualization/community/team-blog/2017/20171219-tar-and-curl-come-to-windows
cmd = exec.Command("tar", "-xf", source, "-C", appDir)
default:
return errorPlatformNotSupported
}

return cmd.Run()
}

// appDir returns the location of the executable application inside the installation dir.
func (a *App) appDir(installDir string) (string, error) {
return path.Join(installDir, "Flowser.app"), nil
}

// executable returns the location of application executable.
func (a *App) executable(installDir string) (string, error) {
files := map[string]string{
darwin: "Contents/MacOS/Flowser",
windows: "Flowser.exe",
}
file, ok := files[runtime.GOOS]
if !ok {
return "", errorPlatformNotSupported
}

appDir, err := a.appDir(installDir)
if err != nil {
return "", err
}

return path.Join(appDir, file), nil
}

func downloadLatestReleaseAsset() (string, error) {
release, err := getLatestRelease()

if err != nil {
return "", err
}

resp, err := http.Get(*release.asset.BrowserDownloadURL)

if err != nil {
return "", err
}

defer resp.Body.Close()

out, _ := os.Create(*release.asset.Name)
defer out.Close()

_, err = io.Copy(out, resp.Body)
if err != nil {
return "", err
}

return out.Name(), nil
}

type flowserRelease struct {
version string
asset github.ReleaseAsset
}

func getLatestRelease() (*flowserRelease, error) {
client := github.NewClient(nil)
release, _, err := client.Repositories.GetLatestRelease(context.Background(), "onflowser", "flowser")
if err != nil {
return nil, err
}
latestVersion := strings.Replace(*release.TagName, "v", "", 1)
targetAssetName, err := getAssetName(latestVersion)
if err != nil {
return nil, err
}
for _, asset := range release.Assets {
if *asset.Name == targetAssetName {
return &flowserRelease{
version: latestVersion,
asset: asset,
}, nil
}
}
return nil, errors.New("no asset found")
}

func getAssetName(version string) (string, error) {
isArm := strings.HasPrefix(runtime.GOARCH, "arm")
switch runtime.GOOS {
case darwin:
if isArm {
return fmt.Sprintf("Flowser-%s-arm64-mac.zip", version), nil
}
return fmt.Sprintf("Flowser-%s-mac.zip", version), nil
case windows:
return fmt.Sprintf("Flowser-%s-win.zip", version), nil
default:
return "", errorPlatformNotSupported
}
}
26 changes: 26 additions & 0 deletions pkg/main/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"fmt"
"github.com/onflowser/flowser/pkg/flowser"
"os"
"path"
)

func main() {
app := flowser.New()
installDir := path.Join("..", "test-install")

if !app.Installed(installDir) {
err := app.Install(installDir)
fmt.Println("Installing Flowser...")
if err != nil {
panic(err)
}

}

projectDir := os.Args[1]
fmt.Println("Running Flowser")
app.Run(installDir, projectDir)
}

0 comments on commit 0917f3b

Please sign in to comment.