From d6b50c8ca042c232066cc03a5aa593cf851c3f1a Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Sat, 24 Nov 2018 17:12:27 +0100 Subject: [PATCH 01/17] Enhanced version management --- example/simpleDemo/embedderDownloader.go | 122 +++++++++++++++++++++++ example/simpleDemo/main.go | 5 + 2 files changed, 127 insertions(+) create mode 100644 example/simpleDemo/embedderDownloader.go diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go new file mode 100644 index 00000000..ed487c2e --- /dev/null +++ b/example/simpleDemo/embedderDownloader.go @@ -0,0 +1,122 @@ +package main + +import ( + "io" + "fmt" + "log" + "os/exec" + "runtime" + "regexp" + "net/http" + "os" + "io/ioutil" + "encoding/json" +) + +// Function to download file with given path and url. +func DownloadFile(filepath string, url string) 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() + + // Write the body to file + _, err = io.Copy(out, resp.Body) + if err != nil { + return err + } + + return nil +} + +func main() { + // Execute flutter command to retrieve the version + out, err := exec.Command("flutter","--version").Output() + if err != nil { + log.Fatal(err) + } + + // DEBUG + // fmt.Printf("The os is %s\n",platform) + + re := regexp.MustCompile(`Engine • revision (\w{10})`) + shortRevision := re.FindStringSubmatch(string(out))[1] + + url := fmt.Sprintf("https://api.github.com/search/commits?q=%s", shortRevision) + + // DEBUG + //fmt.Printf("The url is %s\n",url) + + // This part is used to retrieve the full hash + + req, err := http.NewRequest("GET", os.ExpandEnv(url), nil) + if err != nil { + // handle err + log.Fatal(err) + } + req.Header.Set("Accept", "application/vnd.github.cloak-preview") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + // handle err + log.Fatal(err) + } + body, err := ioutil.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + log.Fatal(err) + } + + // We define a struct to build JSON object from the response + myStruct := struct { + IncompleteResults bool `json:"incomplete_results"` + Items []struct { + Sha string `json:"sha"` + URL string `json:"url"` + } `json:"items"` + TotalCount int `json:"total_count"` + }{} + + err2 := json.Unmarshal(body, &myStruct) + if err2 != nil { + // handle err + log.Fatal(err2) + } + + var platform = "undefined" + var downloadUrl = "" + + // Retrieve the OS and set variable to retrieve correct flutter embedder + switch runtime.GOOS { + case "darwin": + platform = "darwin-x64" + downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", myStruct.Items[0].Sha, platform) + case "linux": + platform = "linux-x64" + downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", myStruct.Items[0].Sha, platform, platform) + + case "windows": + platform = "windows-x64" + downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", myStruct.Items[0].Sha, platform, platform) + + default: + log.Fatal("OS not supported") + } + + err3 := DownloadFile(".build/temp.zip", downloadUrl) + if err3 != nil { + log.Fatal(err3) + } else{ + fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, myStruct.Items[0].Sha) + } +} \ No newline at end of file diff --git a/example/simpleDemo/main.go b/example/simpleDemo/main.go index 07b54f68..8e13976a 100644 --- a/example/simpleDemo/main.go +++ b/example/simpleDemo/main.go @@ -25,6 +25,11 @@ func main() { options := []gutter.Option{ gutter.OptionAssetPath(dir + "/flutter_project/demo/build/flutter_assets"), + /* Depending on your architecture you need to change the enginer + * Mac OS X : flutter/bin/cache/artifacts/engine/darwin-x64/icudtl.dat + * Linux : flutter/bin/cache/artifacts/engine/linux-x64/icudtl.dat + * Windows : flutter/bin/cache/artifacts/engine/windows-x64/icudtl.dat + */ gutter.OptionICUDataPath("/opt/flutter/bin/cache/artifacts/engine/linux-x64/icudtl.dat"), gutter.OptionWindowInitializer(setIcon), gutter.OptionWindowDimension(800, 600), From 53be955e77cf4421d6df1a9284c48c1f1446d015 Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Sun, 25 Nov 2018 13:01:21 +0100 Subject: [PATCH 02/17] Added downloader tracker --- example/simpleDemo/embedderDownloader.go | 81 +++++++++++++++++++++--- 1 file changed, 73 insertions(+), 8 deletions(-) diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go index ed487c2e..3e404f05 100644 --- a/example/simpleDemo/embedderDownloader.go +++ b/example/simpleDemo/embedderDownloader.go @@ -11,11 +11,68 @@ import ( "os" "io/ioutil" "encoding/json" + "time" + "path" + "bytes" + "strconv" ) +// Function to prind download percent completion +func PrintDownloadPercent(done chan int64, path string, total int64) { + + var stop bool = false + + for { + select { + case <-done: + stop = true + default: + + file, err := os.Open(path) + if err != nil { + log.Fatal(err) + } + + fi, err := file.Stat() + if err != nil { + log.Fatal(err) + } + + size := fi.Size() + + if size == 0 { + size = 1 + } + + var percent float64 = float64(size) / float64(total) * 100 + + // We use `\033[2K\r` to avoid carriage return, it will print above previous. + fmt.Printf("\033[2K\r %.0f %% / 100 %%", percent) + } + + if stop { + break + } + + time.Sleep(time.Second) + } +} + // Function to download file with given path and url. func DownloadFile(filepath string, url string) error { + file := path.Base(url) + + // Print download url in case user needs it. + fmt.Printf("Downloading file from %s\n", url) + + var path bytes.Buffer + path.WriteString(filepath) + path.WriteString("/") + path.WriteString(file) + + start := time.Now() + // Create the file out, err := os.Create(filepath) if err != nil { @@ -30,12 +87,25 @@ func DownloadFile(filepath string, url string) error { } defer resp.Body.Close() + + size, err := strconv.Atoi(resp.Header.Get("Content-Length")) + + done := make(chan int64) + + go PrintDownloadPercent(done, filepath, int64(size)) + + // Write the body to file - _, err = io.Copy(out, resp.Body) + n, err := io.Copy(out, resp.Body) if err != nil { return err } + done <- n + + elapsed := time.Since(start) + log.Printf("\033[2K\rDownload completed in %s", elapsed) + return nil } @@ -45,20 +115,14 @@ func main() { if err != nil { log.Fatal(err) } - - // DEBUG - // fmt.Printf("The os is %s\n",platform) + re := regexp.MustCompile(`Engine • revision (\w{10})`) shortRevision := re.FindStringSubmatch(string(out))[1] url := fmt.Sprintf("https://api.github.com/search/commits?q=%s", shortRevision) - - // DEBUG - //fmt.Printf("The url is %s\n",url) // This part is used to retrieve the full hash - req, err := http.NewRequest("GET", os.ExpandEnv(url), nil) if err != nil { // handle err @@ -71,6 +135,7 @@ func main() { // handle err log.Fatal(err) } + body, err := ioutil.ReadAll(resp.Body) defer resp.Body.Close() if err != nil { From 1947a5fda45b5dfadc5f114eb341bcecdc221538 Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Sun, 25 Nov 2018 13:14:50 +0100 Subject: [PATCH 03/17] Func to unexported --- example/simpleDemo/embedderDownloader.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go index 3e404f05..945ec181 100644 --- a/example/simpleDemo/embedderDownloader.go +++ b/example/simpleDemo/embedderDownloader.go @@ -18,7 +18,7 @@ import ( ) // Function to prind download percent completion -func PrintDownloadPercent(done chan int64, path string, total int64) { +func printDownloadPercent(done chan int64, path string, total int64) { var stop bool = false @@ -59,7 +59,7 @@ func PrintDownloadPercent(done chan int64, path string, total int64) { } // Function to download file with given path and url. -func DownloadFile(filepath string, url string) error { +func downloadFile(filepath string, url string) error { file := path.Base(url) @@ -92,7 +92,7 @@ func DownloadFile(filepath string, url string) error { done := make(chan int64) - go PrintDownloadPercent(done, filepath, int64(size)) + go printDownloadPercent(done, filepath, int64(size)) // Write the body to file @@ -178,7 +178,7 @@ func main() { log.Fatal("OS not supported") } - err3 := DownloadFile(".build/temp.zip", downloadUrl) + err3 := downloadFile(".build/temp.zip", downloadUrl) if err3 != nil { log.Fatal(err3) } else{ From c6ec92d125d17fc36c087262f5948ad7bc87534c Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Mon, 26 Nov 2018 23:35:48 +0100 Subject: [PATCH 04/17] Added confirmation message to overwrite and unzip support (partially) --- example/simpleDemo/embedderDownloader.go | 146 +++++++++++++++++++---- 1 file changed, 125 insertions(+), 21 deletions(-) diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go index 945ec181..d65fb542 100644 --- a/example/simpleDemo/embedderDownloader.go +++ b/example/simpleDemo/embedderDownloader.go @@ -1,7 +1,6 @@ package main import ( - "io" "fmt" "log" "os/exec" @@ -9,14 +8,100 @@ import ( "regexp" "net/http" "os" + "bufio" + "io" "io/ioutil" "encoding/json" "time" - "path" - "bytes" + "path/filepath" "strconv" + "archive/zip" + "strings" ) +// Unzip will decompress a zip archive, moving all files and folders +// within the zip file (parameter 1) to an output directory (parameter 2). +func unzip(src string, dest string) ([]string, error) { + + var filenames []string + + r, err := zip.OpenReader(src) + if err != nil { + return filenames, err + } + defer r.Close() + + for _, f := range r.File { + + rc, err := f.Open() + if err != nil { + return filenames, err + } + defer rc.Close() + + // Store filename/path for returning and using later on + fpath := filepath.Join(dest, f.Name) + + // Check for ZipSlip. More Info: http://bit.ly/2MsjAWE + if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { + return filenames, fmt.Errorf("%s: illegal file path", fpath) + } + + filenames = append(filenames, fpath) + + if f.FileInfo().IsDir() { + + // Make Folder + os.MkdirAll(fpath, os.ModePerm) + + } else { + + // Make File + if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { + return filenames, err + } + + outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return filenames, err + } + + _, err = io.Copy(outFile, rc) + + // Close the file without defer to close before next iteration of loop + outFile.Close() + + if err != nil { + return filenames, err + } + + } + } + return filenames, nil +} + + +func askForConfirmation() bool { + reader := bufio.NewReader(os.Stdin) + + for { + fmt.Printf("Would you like to overwrite the previously downloaded engine [Y/n] : ") + + response, err := reader.ReadString('\n') + if err != nil { + log.Fatal(err) + } + + response = strings.ToLower(strings.TrimSpace(response)) + + if response == "y" || response == "yes" { + return true + } else if response == "n" || response == "no" { + return false + } + } +} + // Function to prind download percent completion func printDownloadPercent(done chan int64, path string, total int64) { @@ -61,16 +146,15 @@ func printDownloadPercent(done chan int64, path string, total int64) { // Function to download file with given path and url. func downloadFile(filepath string, url string) error { - file := path.Base(url) - // Print download url in case user needs it. fmt.Printf("Downloading file from %s\n", url) - var path bytes.Buffer - path.WriteString(filepath) - path.WriteString("/") - path.WriteString(file) - + if _, err := os.Stat(filepath); !os.IsNotExist(err) { + if !askForConfirmation(){ + fmt.Printf("Leaving.\n") + os.Exit(0) + } + } start := time.Now() // Create the file @@ -87,7 +171,6 @@ func downloadFile(filepath string, url string) error { } defer resp.Body.Close() - size, err := strconv.Atoi(resp.Header.Get("Content-Length")) done := make(chan int64) @@ -116,6 +199,11 @@ func main() { log.Fatal(err) } + // Get working directory + dir, err := os.Getwd() + if err != nil { + log.Fatal(err) + } re := regexp.MustCompile(`Engine • revision (\w{10})`) shortRevision := re.FindStringSubmatch(string(out))[1] @@ -143,16 +231,13 @@ func main() { } // We define a struct to build JSON object from the response - myStruct := struct { - IncompleteResults bool `json:"incomplete_results"` + hashResponse := struct { Items []struct { Sha string `json:"sha"` - URL string `json:"url"` } `json:"items"` - TotalCount int `json:"total_count"` }{} - err2 := json.Unmarshal(body, &myStruct) + err2 := json.Unmarshal(body, &hashResponse) if err2 != nil { // handle err log.Fatal(err2) @@ -165,23 +250,42 @@ func main() { switch runtime.GOOS { case "darwin": platform = "darwin-x64" - downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", myStruct.Items[0].Sha, platform) + downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) case "linux": platform = "linux-x64" - downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", myStruct.Items[0].Sha, platform, platform) + downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) case "windows": platform = "windows-x64" - downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", myStruct.Items[0].Sha, platform, platform) + downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) default: log.Fatal("OS not supported") } - err3 := downloadFile(".build/temp.zip", downloadUrl) + err3 := downloadFile(dir + "/.build/temp.zip", downloadUrl) if err3 != nil { log.Fatal(err3) } else{ - fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, myStruct.Items[0].Sha) + fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha) + } + + switch platform{ + case "darwin-x64": + _, err = unzip(".build/temp.zip", dir + "/.build/") + if err != nil { + log.Fatal(err) + } + + _, err = unzip(".build/FlutterEmbedder.framework.zip", dir) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Unzipped:\n") + + case "linux-x64": + + case "windows-x64": } } \ No newline at end of file From cc551fe1cc0b89b48e7c27dfe9f381419adca2f4 Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Tue, 27 Nov 2018 00:01:41 +0100 Subject: [PATCH 05/17] Updated Readme --- README.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6078876b..31aa9050 100755 --- a/README.md +++ b/README.md @@ -58,11 +58,9 @@ cd flutter_project/demo/ flutter build bundle cd ../.. -# Download the share library (CORRESPONDING to the Flutter's version shown above) -wget https://storage.googleapis.com/flutter_infra/flutter/af42b6dc95bd9f719e43c4e9f29a00640f0f0bba/linux-x64/linux-x64-embedder -O .build/temp.zip - -# Extract the share library -unzip .build/temp.zip -x flutter_embedder.h +# Run script that will download share library, unzip it and move it. +# Downloaded version is the one corresponding to your flutter version +go run embedderDownloader.go # REQUIRED before every `go build`. The CGO compiler need to know where to look for the share library export CGO_LDFLAGS="-L${PWD}" @@ -101,11 +99,9 @@ cd flutter_project/demo/ flutter build bundle cd ../.. -# Download the share library (CORRESPONDING to the Flutter's version shown above) -# => https://storage.googleapis.com/flutter_infra/flutter/af42b6dc95bd9f719e43c4e9f29a00640f0f0bba/windows-x64/windows-x64-embedder.zip - -# Move the share library -# => "flutter_engine.dll" must be in the flutter example project (where the main.go is) +# Run script that will download share library, unzip it and move it. +# Downloaded version is the one corresponding to your flutter version +go run embedderDownloader.go # REQUIRED before every `go build`. The CGO compiler need to know where to look for the share library set CGO_LDFLAGS=-L%cd% @@ -144,8 +140,9 @@ cd flutter_project/demo/ flutter build bundle cd ../.. -# Download the share library (CORRESPONDING to the Flutter's version shown above) -wget https://storage.googleapis.com/flutter_infra/flutter/af42b6dc95bd9f719e43c4e9f29a00640f0f0bba/darwin-x64/FlutterEmbedder.framework.zip -O .build/temp.zip +# Run script that will download share library, unzip it and move it. +# Downloaded version is the one corresponding to your flutter version +go run embedderDownloader.go # Move the share library unzip .build/temp.zip -d .build && unzip .build/FlutterEmbedder.framework.zip -d .build/FlutterEmbedder.framework From 583a3e27bad4e2d3eb2f24ee19e53a6a056eb415 Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Tue, 27 Nov 2018 00:02:34 +0100 Subject: [PATCH 06/17] Finished zip implementation depending on OS. And move files unzipped to their needed location --- example/simpleDemo/embedderDownloader.go | 38 ++++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go index d65fb542..ba8c9ef8 100644 --- a/example/simpleDemo/embedderDownloader.go +++ b/example/simpleDemo/embedderDownloader.go @@ -251,6 +251,7 @@ func main() { case "darwin": platform = "darwin-x64" downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) + case "linux": platform = "linux-x64" downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) @@ -270,22 +271,33 @@ func main() { fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha) } + _, err = unzip(".build/temp.zip", dir + "/.build/") + if err != nil { + log.Fatal(err) + } + switch platform{ - case "darwin-x64": - _, err = unzip(".build/temp.zip", dir + "/.build/") - if err != nil { - log.Fatal(err) - } - - _, err = unzip(".build/FlutterEmbedder.framework.zip", dir) - if err != nil { - log.Fatal(err) - } + case "darwin-x64": + _, err = unzip(".build/FlutterEmbedder.framework.zip", dir + "/FlutterEmbedder.framework") + if err != nil { + log.Fatal(err) + } - fmt.Println("Unzipped:\n") + case "linux-x64": + err := os.Rename("libflutter_engine.so", dir + "/libflutter_engine.so") + if err != nil { + log.Fatal(err) + } - case "linux-x64": + case "windows-x64": + err := os.Rename("flutter_engine.dll", dir + "/flutter_engine.dll") + if err != nil { + log.Fatal(err) + } - case "windows-x64": } + fmt.Printf("Unzipped files and moved them to correct repository.\n") + + fmt.Printf("Done.\n") + } \ No newline at end of file From 35f1f2bd9b108e27341e1d544b32e479e226fa5f Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Tue, 27 Nov 2018 09:38:07 +0100 Subject: [PATCH 07/17] Updated README --- README.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 31aa9050..116f4f17 100755 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ go get -u -v github.com/Drakirus/go-flutter-desktop-embedder # Make sure the path in "main.go" to the `icudtl.dat` is correct. # Build the example project -go build +go run main.go # `go run main.go` is not working ATM. ``` @@ -112,7 +112,7 @@ go get -u -v github.com/Drakirus/go-flutter-desktop-embedder # Make sure the path in "main.go" to the `icudtl.dat` is correct. # Build the example project -go build +go run main.go # `go run main.go` is not working ATM. ``` @@ -144,10 +144,6 @@ cd ../.. # Downloaded version is the one corresponding to your flutter version go run embedderDownloader.go -# Move the share library -unzip .build/temp.zip -d .build && unzip .build/FlutterEmbedder.framework.zip -d .build/FlutterEmbedder.framework -mv .build/FlutterEmbedder.framework . - # REQUIRED before every `go build`. The CGO compiler need to know where to look for the share library export CGO_LDFLAGS="-F${PWD} -Wl,-rpath,@executable_path" # The share library must stay next to the generated binary. @@ -157,7 +153,7 @@ go get -u -v github.com/Drakirus/go-flutter-desktop-embedder # Make sure the path in "main.go" to the `icudtl.dat` is correct. # Build the example project -go build +go run main.go # `go run main.go` is not working ATM. ``` From cab7108aa2dca64394855de96ebd0625ad63a2a2 Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Tue, 27 Nov 2018 09:47:01 +0100 Subject: [PATCH 08/17] omit type (inferred) --- example/simpleDemo/embedderDownloader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go index ba8c9ef8..f5213cea 100644 --- a/example/simpleDemo/embedderDownloader.go +++ b/example/simpleDemo/embedderDownloader.go @@ -105,7 +105,7 @@ func askForConfirmation() bool { // Function to prind download percent completion func printDownloadPercent(done chan int64, path string, total int64) { - var stop bool = false + var stop = false for { select { From aa8ed97ed215c743bc99ec1be8cdc315c35d845c Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Tue, 27 Nov 2018 09:47:23 +0100 Subject: [PATCH 09/17] Fixed var name & fixe path --- example/simpleDemo/embedderDownloader.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go index f5213cea..5de38199 100644 --- a/example/simpleDemo/embedderDownloader.go +++ b/example/simpleDemo/embedderDownloader.go @@ -244,27 +244,27 @@ func main() { } var platform = "undefined" - var downloadUrl = "" + var downloadURL = "" // Retrieve the OS and set variable to retrieve correct flutter embedder switch runtime.GOOS { case "darwin": platform = "darwin-x64" - downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) + downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) case "linux": platform = "linux-x64" - downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) + downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) case "windows": platform = "windows-x64" - downloadUrl = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) + downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) default: log.Fatal("OS not supported") } - err3 := downloadFile(dir + "/.build/temp.zip", downloadUrl) + err3 := downloadFile(dir + "/.build/temp.zip", downloadURL) if err3 != nil { log.Fatal(err3) } else{ @@ -284,13 +284,13 @@ func main() { } case "linux-x64": - err := os.Rename("libflutter_engine.so", dir + "/libflutter_engine.so") + err := os.Rename(".build/libflutter_engine.so", dir + "/libflutter_engine.so") if err != nil { log.Fatal(err) } case "windows-x64": - err := os.Rename("flutter_engine.dll", dir + "/flutter_engine.dll") + err := os.Rename(".build/flutter_engine.dll", dir + "/flutter_engine.dll") if err != nil { log.Fatal(err) } From 9b150378f70bbef6fb7cdbccde446a4c0c1fef71 Mon Sep 17 00:00:00 2001 From: Drakirus Date: Tue, 27 Nov 2018 09:51:29 +0100 Subject: [PATCH 10/17] [Prompt for overwrite] [Y/n] prompt default. The Y in [Y/n] is in Uppercase, pressing enter should act as a [Y] should --- example/simpleDemo/embedderDownloader.go | 384 +++++++++++------------ 1 file changed, 191 insertions(+), 193 deletions(-) diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go index 5de38199..92a9eb23 100644 --- a/example/simpleDemo/embedderDownloader.go +++ b/example/simpleDemo/embedderDownloader.go @@ -1,86 +1,85 @@ package main import ( - "fmt" - "log" - "os/exec" - "runtime" - "regexp" - "net/http" - "os" - "bufio" - "io" - "io/ioutil" - "encoding/json" - "time" - "path/filepath" - "strconv" - "archive/zip" - "strings" + "archive/zip" + "bufio" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "time" ) -// Unzip will decompress a zip archive, moving all files and folders +// Unzip will decompress a zip archive, moving all files and folders // within the zip file (parameter 1) to an output directory (parameter 2). func unzip(src string, dest string) ([]string, error) { - var filenames []string + var filenames []string - r, err := zip.OpenReader(src) - if err != nil { - return filenames, err - } - defer r.Close() + r, err := zip.OpenReader(src) + if err != nil { + return filenames, err + } + defer r.Close() - for _, f := range r.File { + for _, f := range r.File { - rc, err := f.Open() - if err != nil { - return filenames, err - } - defer rc.Close() + rc, err := f.Open() + if err != nil { + return filenames, err + } + defer rc.Close() - // Store filename/path for returning and using later on - fpath := filepath.Join(dest, f.Name) + // Store filename/path for returning and using later on + fpath := filepath.Join(dest, f.Name) - // Check for ZipSlip. More Info: http://bit.ly/2MsjAWE - if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { - return filenames, fmt.Errorf("%s: illegal file path", fpath) - } + // Check for ZipSlip. More Info: http://bit.ly/2MsjAWE + if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { + return filenames, fmt.Errorf("%s: illegal file path", fpath) + } - filenames = append(filenames, fpath) + filenames = append(filenames, fpath) - if f.FileInfo().IsDir() { + if f.FileInfo().IsDir() { - // Make Folder - os.MkdirAll(fpath, os.ModePerm) + // Make Folder + os.MkdirAll(fpath, os.ModePerm) - } else { + } else { - // Make File - if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { - return filenames, err - } + // Make File + if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { + return filenames, err + } - outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) - if err != nil { - return filenames, err - } + outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return filenames, err + } - _, err = io.Copy(outFile, rc) + _, err = io.Copy(outFile, rc) - // Close the file without defer to close before next iteration of loop - outFile.Close() + // Close the file without defer to close before next iteration of loop + outFile.Close() - if err != nil { - return filenames, err - } + if err != nil { + return filenames, err + } - } - } - return filenames, nil + } + } + return filenames, nil } - func askForConfirmation() bool { reader := bufio.NewReader(os.Stdin) @@ -94,7 +93,7 @@ func askForConfirmation() bool { response = strings.ToLower(strings.TrimSpace(response)) - if response == "y" || response == "yes" { + if response == "y" || response == "yes" || response == "" { return true } else if response == "n" || response == "no" { return false @@ -130,9 +129,9 @@ func printDownloadPercent(done chan int64, path string, total int64) { } var percent float64 = float64(size) / float64(total) * 100 - - // We use `\033[2K\r` to avoid carriage return, it will print above previous. - fmt.Printf("\033[2K\r %.0f %% / 100 %%", percent) + + // We use `\033[2K\r` to avoid carriage return, it will print above previous. + fmt.Printf("\033[2K\r %.0f %% / 100 %%", percent) } if stop { @@ -146,158 +145,157 @@ func printDownloadPercent(done chan int64, path string, total int64) { // Function to download file with given path and url. func downloadFile(filepath string, url string) error { - // Print download url in case user needs it. + // Print download url in case user needs it. fmt.Printf("Downloading file from %s\n", url) - if _, err := os.Stat(filepath); !os.IsNotExist(err) { - if !askForConfirmation(){ - fmt.Printf("Leaving.\n") - os.Exit(0) - } - } - start := time.Now() - - // 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() - - size, err := strconv.Atoi(resp.Header.Get("Content-Length")) - - done := make(chan int64) + if _, err := os.Stat(filepath); !os.IsNotExist(err) { + if !askForConfirmation() { + fmt.Printf("Leaving.\n") + os.Exit(0) + } + } + start := time.Now() - go printDownloadPercent(done, filepath, int64(size)) + // 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() - // Write the body to file - n, err := io.Copy(out, resp.Body) - if err != nil { - return err - } + size, err := strconv.Atoi(resp.Header.Get("Content-Length")) - done <- n + done := make(chan int64) + + go printDownloadPercent(done, filepath, int64(size)) + + // Write the body to file + n, err := io.Copy(out, resp.Body) + if err != nil { + return err + } + + done <- n elapsed := time.Since(start) log.Printf("\033[2K\rDownload completed in %s", elapsed) - return nil + return nil } func main() { - // Execute flutter command to retrieve the version - out, err := exec.Command("flutter","--version").Output() - if err != nil { - log.Fatal(err) - } - - // Get working directory - dir, err := os.Getwd() + // Execute flutter command to retrieve the version + out, err := exec.Command("flutter", "--version").Output() + if err != nil { + log.Fatal(err) + } + + // Get working directory + dir, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + + re := regexp.MustCompile(`Engine • revision (\w{10})`) + shortRevision := re.FindStringSubmatch(string(out))[1] + + url := fmt.Sprintf("https://api.github.com/search/commits?q=%s", shortRevision) + + // This part is used to retrieve the full hash + req, err := http.NewRequest("GET", os.ExpandEnv(url), nil) if err != nil { + // handle err log.Fatal(err) } + req.Header.Set("Accept", "application/vnd.github.cloak-preview") - re := regexp.MustCompile(`Engine • revision (\w{10})`) - shortRevision := re.FindStringSubmatch(string(out))[1] - - url := fmt.Sprintf("https://api.github.com/search/commits?q=%s", shortRevision) - - // This part is used to retrieve the full hash - req, err := http.NewRequest("GET", os.ExpandEnv(url), nil) - if err != nil { - // handle err - log.Fatal(err) - } - req.Header.Set("Accept", "application/vnd.github.cloak-preview") - - resp, err := http.DefaultClient.Do(req) - if err != nil { - // handle err - log.Fatal(err) - } - - body, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() - if err != nil { - log.Fatal(err) - } - - // We define a struct to build JSON object from the response - hashResponse := struct { - Items []struct { + resp, err := http.DefaultClient.Do(req) + if err != nil { + // handle err + log.Fatal(err) + } + + body, err := ioutil.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + log.Fatal(err) + } + + // We define a struct to build JSON object from the response + hashResponse := struct { + Items []struct { Sha string `json:"sha"` } `json:"items"` }{} err2 := json.Unmarshal(body, &hashResponse) - if err2 != nil { - // handle err - log.Fatal(err2) - } + if err2 != nil { + // handle err + log.Fatal(err2) + } var platform = "undefined" - var downloadURL = "" - - // Retrieve the OS and set variable to retrieve correct flutter embedder - switch runtime.GOOS { - case "darwin": - platform = "darwin-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) - - case "linux": - platform = "linux-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) - - case "windows": - platform = "windows-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) - - default: - log.Fatal("OS not supported") - } - - err3 := downloadFile(dir + "/.build/temp.zip", downloadURL) - if err3 != nil { - log.Fatal(err3) - } else{ - fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha) - } - - _, err = unzip(".build/temp.zip", dir + "/.build/") - if err != nil { - log.Fatal(err) - } - - switch platform{ - case "darwin-x64": - _, err = unzip(".build/FlutterEmbedder.framework.zip", dir + "/FlutterEmbedder.framework") - if err != nil { - log.Fatal(err) - } - - case "linux-x64": - err := os.Rename(".build/libflutter_engine.so", dir + "/libflutter_engine.so") - if err != nil { - log.Fatal(err) - } - - case "windows-x64": - err := os.Rename(".build/flutter_engine.dll", dir + "/flutter_engine.dll") - if err != nil { - log.Fatal(err) - } - - } - fmt.Printf("Unzipped files and moved them to correct repository.\n") - - fmt.Printf("Done.\n") - -} \ No newline at end of file + var downloadURL = "" + + // Retrieve the OS and set variable to retrieve correct flutter embedder + switch runtime.GOOS { + case "darwin": + platform = "darwin-x64" + downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) + + case "linux": + platform = "linux-x64" + downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) + + case "windows": + platform = "windows-x64" + downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) + + default: + log.Fatal("OS not supported") + } + + err3 := downloadFile(dir+"/.build/temp.zip", downloadURL) + if err3 != nil { + log.Fatal(err3) + } else { + fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha) + } + + _, err = unzip(".build/temp.zip", dir+"/.build/") + if err != nil { + log.Fatal(err) + } + + switch platform { + case "darwin-x64": + _, err = unzip(".build/FlutterEmbedder.framework.zip", dir+"/FlutterEmbedder.framework") + if err != nil { + log.Fatal(err) + } + + case "linux-x64": + err := os.Rename(".build/libflutter_engine.so", dir+"/libflutter_engine.so") + if err != nil { + log.Fatal(err) + } + + case "windows-x64": + err := os.Rename(".build/flutter_engine.dll", dir+"/flutter_engine.dll") + if err != nil { + log.Fatal(err) + } + + } + fmt.Printf("Unzipped files and moved them to correct repository.\n") + + fmt.Printf("Done.\n") + +} From 8fb88c0dc31e4328e947a6dc4d9ae7e706921dee Mon Sep 17 00:00:00 2001 From: Drakirus Date: Tue, 27 Nov 2018 09:58:07 +0100 Subject: [PATCH 11/17] Adds where the downloaded engine is stored --- example/simpleDemo/embedderDownloader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go index 92a9eb23..9a173f0c 100644 --- a/example/simpleDemo/embedderDownloader.go +++ b/example/simpleDemo/embedderDownloader.go @@ -146,7 +146,7 @@ func printDownloadPercent(done chan int64, path string, total int64) { func downloadFile(filepath string, url string) error { // Print download url in case user needs it. - fmt.Printf("Downloading file from %s\n", url) + fmt.Printf("Downloading file from\n '%s'\n to '%s'\n\n", url, filepath) if _, err := os.Stat(filepath); !os.IsNotExist(err) { if !askForConfirmation() { From 29bccbd0ba480743eaf73a1335d00f401060ddaa Mon Sep 17 00:00:00 2001 From: Drakirus Date: Tue, 27 Nov 2018 10:05:25 +0100 Subject: [PATCH 12/17] Update README.md --- README.md | 21 +- example/simpleDemo/embedderDownloader.go | 301 ----------------------- 2 files changed, 9 insertions(+), 313 deletions(-) delete mode 100644 example/simpleDemo/embedderDownloader.go diff --git a/README.md b/README.md index 116f4f17..ac6722b5 100755 --- a/README.md +++ b/README.md @@ -58,9 +58,8 @@ cd flutter_project/demo/ flutter build bundle cd ../.. -# Run script that will download share library, unzip it and move it. -# Downloaded version is the one corresponding to your flutter version -go run embedderDownloader.go +# Download the share library, the one corresponding to your flutter version. +go run engineDownloader.go # REQUIRED before every `go build`. The CGO compiler need to know where to look for the share library export CGO_LDFLAGS="-L${PWD}" @@ -71,7 +70,7 @@ go get -u -v github.com/Drakirus/go-flutter-desktop-embedder # Make sure the path in "main.go" to the `icudtl.dat` is correct. # Build the example project -go run main.go +go build main.go # `go run main.go` is not working ATM. ``` @@ -99,9 +98,8 @@ cd flutter_project/demo/ flutter build bundle cd ../.. -# Run script that will download share library, unzip it and move it. -# Downloaded version is the one corresponding to your flutter version -go run embedderDownloader.go +# Download the share library, the one corresponding to your flutter version. +go run engineDownloader.go # REQUIRED before every `go build`. The CGO compiler need to know where to look for the share library set CGO_LDFLAGS=-L%cd% @@ -112,7 +110,7 @@ go get -u -v github.com/Drakirus/go-flutter-desktop-embedder # Make sure the path in "main.go" to the `icudtl.dat` is correct. # Build the example project -go run main.go +go build main.go # `go run main.go` is not working ATM. ``` @@ -140,9 +138,8 @@ cd flutter_project/demo/ flutter build bundle cd ../.. -# Run script that will download share library, unzip it and move it. -# Downloaded version is the one corresponding to your flutter version -go run embedderDownloader.go +# Download the share library, the one corresponding to your flutter version. +go run engineDownloader.go # REQUIRED before every `go build`. The CGO compiler need to know where to look for the share library export CGO_LDFLAGS="-F${PWD} -Wl,-rpath,@executable_path" @@ -153,7 +150,7 @@ go get -u -v github.com/Drakirus/go-flutter-desktop-embedder # Make sure the path in "main.go" to the `icudtl.dat` is correct. # Build the example project -go run main.go +go build main.go # `go run main.go` is not working ATM. ``` diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go deleted file mode 100644 index 9a173f0c..00000000 --- a/example/simpleDemo/embedderDownloader.go +++ /dev/null @@ -1,301 +0,0 @@ -package main - -import ( - "archive/zip" - "bufio" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "log" - "net/http" - "os" - "os/exec" - "path/filepath" - "regexp" - "runtime" - "strconv" - "strings" - "time" -) - -// Unzip will decompress a zip archive, moving all files and folders -// within the zip file (parameter 1) to an output directory (parameter 2). -func unzip(src string, dest string) ([]string, error) { - - var filenames []string - - r, err := zip.OpenReader(src) - if err != nil { - return filenames, err - } - defer r.Close() - - for _, f := range r.File { - - rc, err := f.Open() - if err != nil { - return filenames, err - } - defer rc.Close() - - // Store filename/path for returning and using later on - fpath := filepath.Join(dest, f.Name) - - // Check for ZipSlip. More Info: http://bit.ly/2MsjAWE - if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { - return filenames, fmt.Errorf("%s: illegal file path", fpath) - } - - filenames = append(filenames, fpath) - - if f.FileInfo().IsDir() { - - // Make Folder - os.MkdirAll(fpath, os.ModePerm) - - } else { - - // Make File - if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { - return filenames, err - } - - outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) - if err != nil { - return filenames, err - } - - _, err = io.Copy(outFile, rc) - - // Close the file without defer to close before next iteration of loop - outFile.Close() - - if err != nil { - return filenames, err - } - - } - } - return filenames, nil -} - -func askForConfirmation() bool { - reader := bufio.NewReader(os.Stdin) - - for { - fmt.Printf("Would you like to overwrite the previously downloaded engine [Y/n] : ") - - response, err := reader.ReadString('\n') - if err != nil { - log.Fatal(err) - } - - response = strings.ToLower(strings.TrimSpace(response)) - - if response == "y" || response == "yes" || response == "" { - return true - } else if response == "n" || response == "no" { - return false - } - } -} - -// Function to prind download percent completion -func printDownloadPercent(done chan int64, path string, total int64) { - - var stop = false - - for { - select { - case <-done: - stop = true - default: - - file, err := os.Open(path) - if err != nil { - log.Fatal(err) - } - - fi, err := file.Stat() - if err != nil { - log.Fatal(err) - } - - size := fi.Size() - - if size == 0 { - size = 1 - } - - var percent float64 = float64(size) / float64(total) * 100 - - // We use `\033[2K\r` to avoid carriage return, it will print above previous. - fmt.Printf("\033[2K\r %.0f %% / 100 %%", percent) - } - - if stop { - break - } - - time.Sleep(time.Second) - } -} - -// Function to download file with given path and url. -func downloadFile(filepath string, url string) error { - - // Print download url in case user needs it. - fmt.Printf("Downloading file from\n '%s'\n to '%s'\n\n", url, filepath) - - if _, err := os.Stat(filepath); !os.IsNotExist(err) { - if !askForConfirmation() { - fmt.Printf("Leaving.\n") - os.Exit(0) - } - } - start := time.Now() - - // 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() - - size, err := strconv.Atoi(resp.Header.Get("Content-Length")) - - done := make(chan int64) - - go printDownloadPercent(done, filepath, int64(size)) - - // Write the body to file - n, err := io.Copy(out, resp.Body) - if err != nil { - return err - } - - done <- n - - elapsed := time.Since(start) - log.Printf("\033[2K\rDownload completed in %s", elapsed) - - return nil -} - -func main() { - // Execute flutter command to retrieve the version - out, err := exec.Command("flutter", "--version").Output() - if err != nil { - log.Fatal(err) - } - - // Get working directory - dir, err := os.Getwd() - if err != nil { - log.Fatal(err) - } - - re := regexp.MustCompile(`Engine • revision (\w{10})`) - shortRevision := re.FindStringSubmatch(string(out))[1] - - url := fmt.Sprintf("https://api.github.com/search/commits?q=%s", shortRevision) - - // This part is used to retrieve the full hash - req, err := http.NewRequest("GET", os.ExpandEnv(url), nil) - if err != nil { - // handle err - log.Fatal(err) - } - req.Header.Set("Accept", "application/vnd.github.cloak-preview") - - resp, err := http.DefaultClient.Do(req) - if err != nil { - // handle err - log.Fatal(err) - } - - body, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() - if err != nil { - log.Fatal(err) - } - - // We define a struct to build JSON object from the response - hashResponse := struct { - Items []struct { - Sha string `json:"sha"` - } `json:"items"` - }{} - - err2 := json.Unmarshal(body, &hashResponse) - if err2 != nil { - // handle err - log.Fatal(err2) - } - - var platform = "undefined" - var downloadURL = "" - - // Retrieve the OS and set variable to retrieve correct flutter embedder - switch runtime.GOOS { - case "darwin": - platform = "darwin-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) - - case "linux": - platform = "linux-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) - - case "windows": - platform = "windows-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) - - default: - log.Fatal("OS not supported") - } - - err3 := downloadFile(dir+"/.build/temp.zip", downloadURL) - if err3 != nil { - log.Fatal(err3) - } else { - fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha) - } - - _, err = unzip(".build/temp.zip", dir+"/.build/") - if err != nil { - log.Fatal(err) - } - - switch platform { - case "darwin-x64": - _, err = unzip(".build/FlutterEmbedder.framework.zip", dir+"/FlutterEmbedder.framework") - if err != nil { - log.Fatal(err) - } - - case "linux-x64": - err := os.Rename(".build/libflutter_engine.so", dir+"/libflutter_engine.so") - if err != nil { - log.Fatal(err) - } - - case "windows-x64": - err := os.Rename(".build/flutter_engine.dll", dir+"/flutter_engine.dll") - if err != nil { - log.Fatal(err) - } - - } - fmt.Printf("Unzipped files and moved them to correct repository.\n") - - fmt.Printf("Done.\n") - -} From 5096eaa5bf3d292e17a333116356c26d8fa6bb36 Mon Sep 17 00:00:00 2001 From: Drakirus Date: Tue, 27 Nov 2018 10:09:50 +0100 Subject: [PATCH 13/17] Rename downloader --- example/simpleDemo/engineDownloader.go | 301 +++++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 example/simpleDemo/engineDownloader.go diff --git a/example/simpleDemo/engineDownloader.go b/example/simpleDemo/engineDownloader.go new file mode 100644 index 00000000..9a173f0c --- /dev/null +++ b/example/simpleDemo/engineDownloader.go @@ -0,0 +1,301 @@ +package main + +import ( + "archive/zip" + "bufio" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "time" +) + +// Unzip will decompress a zip archive, moving all files and folders +// within the zip file (parameter 1) to an output directory (parameter 2). +func unzip(src string, dest string) ([]string, error) { + + var filenames []string + + r, err := zip.OpenReader(src) + if err != nil { + return filenames, err + } + defer r.Close() + + for _, f := range r.File { + + rc, err := f.Open() + if err != nil { + return filenames, err + } + defer rc.Close() + + // Store filename/path for returning and using later on + fpath := filepath.Join(dest, f.Name) + + // Check for ZipSlip. More Info: http://bit.ly/2MsjAWE + if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { + return filenames, fmt.Errorf("%s: illegal file path", fpath) + } + + filenames = append(filenames, fpath) + + if f.FileInfo().IsDir() { + + // Make Folder + os.MkdirAll(fpath, os.ModePerm) + + } else { + + // Make File + if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { + return filenames, err + } + + outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return filenames, err + } + + _, err = io.Copy(outFile, rc) + + // Close the file without defer to close before next iteration of loop + outFile.Close() + + if err != nil { + return filenames, err + } + + } + } + return filenames, nil +} + +func askForConfirmation() bool { + reader := bufio.NewReader(os.Stdin) + + for { + fmt.Printf("Would you like to overwrite the previously downloaded engine [Y/n] : ") + + response, err := reader.ReadString('\n') + if err != nil { + log.Fatal(err) + } + + response = strings.ToLower(strings.TrimSpace(response)) + + if response == "y" || response == "yes" || response == "" { + return true + } else if response == "n" || response == "no" { + return false + } + } +} + +// Function to prind download percent completion +func printDownloadPercent(done chan int64, path string, total int64) { + + var stop = false + + for { + select { + case <-done: + stop = true + default: + + file, err := os.Open(path) + if err != nil { + log.Fatal(err) + } + + fi, err := file.Stat() + if err != nil { + log.Fatal(err) + } + + size := fi.Size() + + if size == 0 { + size = 1 + } + + var percent float64 = float64(size) / float64(total) * 100 + + // We use `\033[2K\r` to avoid carriage return, it will print above previous. + fmt.Printf("\033[2K\r %.0f %% / 100 %%", percent) + } + + if stop { + break + } + + time.Sleep(time.Second) + } +} + +// Function to download file with given path and url. +func downloadFile(filepath string, url string) error { + + // Print download url in case user needs it. + fmt.Printf("Downloading file from\n '%s'\n to '%s'\n\n", url, filepath) + + if _, err := os.Stat(filepath); !os.IsNotExist(err) { + if !askForConfirmation() { + fmt.Printf("Leaving.\n") + os.Exit(0) + } + } + start := time.Now() + + // 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() + + size, err := strconv.Atoi(resp.Header.Get("Content-Length")) + + done := make(chan int64) + + go printDownloadPercent(done, filepath, int64(size)) + + // Write the body to file + n, err := io.Copy(out, resp.Body) + if err != nil { + return err + } + + done <- n + + elapsed := time.Since(start) + log.Printf("\033[2K\rDownload completed in %s", elapsed) + + return nil +} + +func main() { + // Execute flutter command to retrieve the version + out, err := exec.Command("flutter", "--version").Output() + if err != nil { + log.Fatal(err) + } + + // Get working directory + dir, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + + re := regexp.MustCompile(`Engine • revision (\w{10})`) + shortRevision := re.FindStringSubmatch(string(out))[1] + + url := fmt.Sprintf("https://api.github.com/search/commits?q=%s", shortRevision) + + // This part is used to retrieve the full hash + req, err := http.NewRequest("GET", os.ExpandEnv(url), nil) + if err != nil { + // handle err + log.Fatal(err) + } + req.Header.Set("Accept", "application/vnd.github.cloak-preview") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + // handle err + log.Fatal(err) + } + + body, err := ioutil.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + log.Fatal(err) + } + + // We define a struct to build JSON object from the response + hashResponse := struct { + Items []struct { + Sha string `json:"sha"` + } `json:"items"` + }{} + + err2 := json.Unmarshal(body, &hashResponse) + if err2 != nil { + // handle err + log.Fatal(err2) + } + + var platform = "undefined" + var downloadURL = "" + + // Retrieve the OS and set variable to retrieve correct flutter embedder + switch runtime.GOOS { + case "darwin": + platform = "darwin-x64" + downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) + + case "linux": + platform = "linux-x64" + downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) + + case "windows": + platform = "windows-x64" + downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) + + default: + log.Fatal("OS not supported") + } + + err3 := downloadFile(dir+"/.build/temp.zip", downloadURL) + if err3 != nil { + log.Fatal(err3) + } else { + fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha) + } + + _, err = unzip(".build/temp.zip", dir+"/.build/") + if err != nil { + log.Fatal(err) + } + + switch platform { + case "darwin-x64": + _, err = unzip(".build/FlutterEmbedder.framework.zip", dir+"/FlutterEmbedder.framework") + if err != nil { + log.Fatal(err) + } + + case "linux-x64": + err := os.Rename(".build/libflutter_engine.so", dir+"/libflutter_engine.so") + if err != nil { + log.Fatal(err) + } + + case "windows-x64": + err := os.Rename(".build/flutter_engine.dll", dir+"/flutter_engine.dll") + if err != nil { + log.Fatal(err) + } + + } + fmt.Printf("Unzipped files and moved them to correct repository.\n") + + fmt.Printf("Done.\n") + +} From 9e4473a42032725306dcd33c8465a06f20de169a Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Tue, 27 Nov 2018 13:59:33 +0100 Subject: [PATCH 14/17] Adding icudtl download --- example/simpleDemo/embedderDownloader.go | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/example/simpleDemo/embedderDownloader.go b/example/simpleDemo/embedderDownloader.go index 5de38199..161042f1 100644 --- a/example/simpleDemo/embedderDownloader.go +++ b/example/simpleDemo/embedderDownloader.go @@ -244,31 +244,38 @@ func main() { } var platform = "undefined" - var downloadURL = "" + var downloadShareLibraryURL = "" + downloadIcudtlURL := fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter//%s/artifacts.zip",platform) // Retrieve the OS and set variable to retrieve correct flutter embedder switch runtime.GOOS { case "darwin": platform = "darwin-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) - + downloadShareLibraryURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) case "linux": platform = "linux-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) + downloadShareLibraryURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) case "windows": platform = "windows-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) + downloadShareLibraryURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) default: log.Fatal("OS not supported") } - err3 := downloadFile(dir + "/.build/temp.zip", downloadURL) - if err3 != nil { + err3 := downloadFile(dir + "/.build/temp.zip", downloadShareLibraryURL) + if err != nil { log.Fatal(err3) } else{ - fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha) + fmt.Printf("Downloaded share library for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha) + } + + err4 := downloadFile(dir + "/.build/artifact.zip", downloadIcudtlURL) + if err != nil { + log.Fatal(err4) + } else{ + fmt.Printf("Downloaded artifact for %s platform.") } _, err = unzip(".build/temp.zip", dir + "/.build/") From 82405c7606fd1a6c043afa756bd956684303cf3a Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Tue, 27 Nov 2018 14:05:31 +0100 Subject: [PATCH 15/17] Download and unzip icudtl.dat --- example/simpleDemo/engineDownloader.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/example/simpleDemo/engineDownloader.go b/example/simpleDemo/engineDownloader.go index 9a173f0c..2ba6e23b 100644 --- a/example/simpleDemo/engineDownloader.go +++ b/example/simpleDemo/engineDownloader.go @@ -242,38 +242,51 @@ func main() { } var platform = "undefined" - var downloadURL = "" + var downloadShareLibraryURL = "" + downloadIcudtlURL := fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter//%s/artifacts.zip",platform) // Retrieve the OS and set variable to retrieve correct flutter embedder switch runtime.GOOS { case "darwin": platform = "darwin-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) + downloadShareLibraryURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform) case "linux": platform = "linux-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) + downloadShareLibraryURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) case "windows": platform = "windows-x64" - downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) + downloadShareLibraryURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform) default: log.Fatal("OS not supported") } - err3 := downloadFile(dir+"/.build/temp.zip", downloadURL) + err3 := downloadFile(dir+"/.build/temp.zip", downloadShareLibraryURL) if err3 != nil { log.Fatal(err3) } else { fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha) } + err4 := downloadFile(dir + "/.build/artifact.zip", downloadIcudtlURL) + if err != nil { + log.Fatal(err4) + } else{ + fmt.Printf("Downloaded artifact for %s platform.") + } + _, err = unzip(".build/temp.zip", dir+"/.build/") if err != nil { log.Fatal(err) } + _, err = unzip(".build/artifact.zip", dir+"/.build/") + if err != nil { + log.Fatal(err) + } + switch platform { case "darwin-x64": _, err = unzip(".build/FlutterEmbedder.framework.zip", dir+"/FlutterEmbedder.framework") From 92108c9611c21b60a8c592fa472f5ac7404dd0ee Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Tue, 27 Nov 2018 14:14:02 +0100 Subject: [PATCH 16/17] Download icudtl.dat depending on installed flutter version --- example/simpleDemo/engineDownloader.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/example/simpleDemo/engineDownloader.go b/example/simpleDemo/engineDownloader.go index 2ba6e23b..c55eeaad 100644 --- a/example/simpleDemo/engineDownloader.go +++ b/example/simpleDemo/engineDownloader.go @@ -243,7 +243,6 @@ func main() { var platform = "undefined" var downloadShareLibraryURL = "" - downloadIcudtlURL := fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter//%s/artifacts.zip",platform) // Retrieve the OS and set variable to retrieve correct flutter embedder switch runtime.GOOS { @@ -263,6 +262,8 @@ func main() { log.Fatal("OS not supported") } + downloadIcudtlURL := fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/artifacts.zip",hashResponse.Items[0].Sha, platform) + err3 := downloadFile(dir+"/.build/temp.zip", downloadShareLibraryURL) if err3 != nil { log.Fatal(err3) @@ -270,7 +271,7 @@ func main() { fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha) } - err4 := downloadFile(dir + "/.build/artifact.zip", downloadIcudtlURL) + err4 := downloadFile(dir + "/.build/artifacts.zip", downloadIcudtlURL) if err != nil { log.Fatal(err4) } else{ @@ -282,7 +283,7 @@ func main() { log.Fatal(err) } - _, err = unzip(".build/artifact.zip", dir+"/.build/") + _, err = unzip(".build/artifacts.zip", dir+"/.build/") if err != nil { log.Fatal(err) } From e2525189c043dfb370791e0f520e6e20c7206f7a Mon Sep 17 00:00:00 2001 From: Thibault Brocherieux Date: Tue, 27 Nov 2018 14:14:27 +0100 Subject: [PATCH 17/17] Use icudtl.dat downloaded from install script --- example/simpleDemo/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/example/simpleDemo/main.go b/example/simpleDemo/main.go index 8e13976a..f729c791 100644 --- a/example/simpleDemo/main.go +++ b/example/simpleDemo/main.go @@ -31,6 +31,7 @@ func main() { * Windows : flutter/bin/cache/artifacts/engine/windows-x64/icudtl.dat */ gutter.OptionICUDataPath("/opt/flutter/bin/cache/artifacts/engine/linux-x64/icudtl.dat"), + gutter.OptionICUDataPath(dir + ".build/artifacts/icudtl.dat") gutter.OptionWindowInitializer(setIcon), gutter.OptionWindowDimension(800, 600), gutter.OptionWindowInitializer(setIcon),