Skip to content

Commit 5096eaa

Browse files
author
Drakirus
committed
Rename downloader
1 parent 29bccbd commit 5096eaa

File tree

1 file changed

+301
-0
lines changed

1 file changed

+301
-0
lines changed
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
package main
2+
3+
import (
4+
"archive/zip"
5+
"bufio"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"io/ioutil"
10+
"log"
11+
"net/http"
12+
"os"
13+
"os/exec"
14+
"path/filepath"
15+
"regexp"
16+
"runtime"
17+
"strconv"
18+
"strings"
19+
"time"
20+
)
21+
22+
// Unzip will decompress a zip archive, moving all files and folders
23+
// within the zip file (parameter 1) to an output directory (parameter 2).
24+
func unzip(src string, dest string) ([]string, error) {
25+
26+
var filenames []string
27+
28+
r, err := zip.OpenReader(src)
29+
if err != nil {
30+
return filenames, err
31+
}
32+
defer r.Close()
33+
34+
for _, f := range r.File {
35+
36+
rc, err := f.Open()
37+
if err != nil {
38+
return filenames, err
39+
}
40+
defer rc.Close()
41+
42+
// Store filename/path for returning and using later on
43+
fpath := filepath.Join(dest, f.Name)
44+
45+
// Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
46+
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
47+
return filenames, fmt.Errorf("%s: illegal file path", fpath)
48+
}
49+
50+
filenames = append(filenames, fpath)
51+
52+
if f.FileInfo().IsDir() {
53+
54+
// Make Folder
55+
os.MkdirAll(fpath, os.ModePerm)
56+
57+
} else {
58+
59+
// Make File
60+
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
61+
return filenames, err
62+
}
63+
64+
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
65+
if err != nil {
66+
return filenames, err
67+
}
68+
69+
_, err = io.Copy(outFile, rc)
70+
71+
// Close the file without defer to close before next iteration of loop
72+
outFile.Close()
73+
74+
if err != nil {
75+
return filenames, err
76+
}
77+
78+
}
79+
}
80+
return filenames, nil
81+
}
82+
83+
func askForConfirmation() bool {
84+
reader := bufio.NewReader(os.Stdin)
85+
86+
for {
87+
fmt.Printf("Would you like to overwrite the previously downloaded engine [Y/n] : ")
88+
89+
response, err := reader.ReadString('\n')
90+
if err != nil {
91+
log.Fatal(err)
92+
}
93+
94+
response = strings.ToLower(strings.TrimSpace(response))
95+
96+
if response == "y" || response == "yes" || response == "" {
97+
return true
98+
} else if response == "n" || response == "no" {
99+
return false
100+
}
101+
}
102+
}
103+
104+
// Function to prind download percent completion
105+
func printDownloadPercent(done chan int64, path string, total int64) {
106+
107+
var stop = false
108+
109+
for {
110+
select {
111+
case <-done:
112+
stop = true
113+
default:
114+
115+
file, err := os.Open(path)
116+
if err != nil {
117+
log.Fatal(err)
118+
}
119+
120+
fi, err := file.Stat()
121+
if err != nil {
122+
log.Fatal(err)
123+
}
124+
125+
size := fi.Size()
126+
127+
if size == 0 {
128+
size = 1
129+
}
130+
131+
var percent float64 = float64(size) / float64(total) * 100
132+
133+
// We use `\033[2K\r` to avoid carriage return, it will print above previous.
134+
fmt.Printf("\033[2K\r %.0f %% / 100 %%", percent)
135+
}
136+
137+
if stop {
138+
break
139+
}
140+
141+
time.Sleep(time.Second)
142+
}
143+
}
144+
145+
// Function to download file with given path and url.
146+
func downloadFile(filepath string, url string) error {
147+
148+
// Print download url in case user needs it.
149+
fmt.Printf("Downloading file from\n '%s'\n to '%s'\n\n", url, filepath)
150+
151+
if _, err := os.Stat(filepath); !os.IsNotExist(err) {
152+
if !askForConfirmation() {
153+
fmt.Printf("Leaving.\n")
154+
os.Exit(0)
155+
}
156+
}
157+
start := time.Now()
158+
159+
// Create the file
160+
out, err := os.Create(filepath)
161+
if err != nil {
162+
return err
163+
}
164+
defer out.Close()
165+
166+
// Get the data
167+
resp, err := http.Get(url)
168+
if err != nil {
169+
return err
170+
}
171+
defer resp.Body.Close()
172+
173+
size, err := strconv.Atoi(resp.Header.Get("Content-Length"))
174+
175+
done := make(chan int64)
176+
177+
go printDownloadPercent(done, filepath, int64(size))
178+
179+
// Write the body to file
180+
n, err := io.Copy(out, resp.Body)
181+
if err != nil {
182+
return err
183+
}
184+
185+
done <- n
186+
187+
elapsed := time.Since(start)
188+
log.Printf("\033[2K\rDownload completed in %s", elapsed)
189+
190+
return nil
191+
}
192+
193+
func main() {
194+
// Execute flutter command to retrieve the version
195+
out, err := exec.Command("flutter", "--version").Output()
196+
if err != nil {
197+
log.Fatal(err)
198+
}
199+
200+
// Get working directory
201+
dir, err := os.Getwd()
202+
if err != nil {
203+
log.Fatal(err)
204+
}
205+
206+
re := regexp.MustCompile(`Engine • revision (\w{10})`)
207+
shortRevision := re.FindStringSubmatch(string(out))[1]
208+
209+
url := fmt.Sprintf("https://api.github.com/search/commits?q=%s", shortRevision)
210+
211+
// This part is used to retrieve the full hash
212+
req, err := http.NewRequest("GET", os.ExpandEnv(url), nil)
213+
if err != nil {
214+
// handle err
215+
log.Fatal(err)
216+
}
217+
req.Header.Set("Accept", "application/vnd.github.cloak-preview")
218+
219+
resp, err := http.DefaultClient.Do(req)
220+
if err != nil {
221+
// handle err
222+
log.Fatal(err)
223+
}
224+
225+
body, err := ioutil.ReadAll(resp.Body)
226+
defer resp.Body.Close()
227+
if err != nil {
228+
log.Fatal(err)
229+
}
230+
231+
// We define a struct to build JSON object from the response
232+
hashResponse := struct {
233+
Items []struct {
234+
Sha string `json:"sha"`
235+
} `json:"items"`
236+
}{}
237+
238+
err2 := json.Unmarshal(body, &hashResponse)
239+
if err2 != nil {
240+
// handle err
241+
log.Fatal(err2)
242+
}
243+
244+
var platform = "undefined"
245+
var downloadURL = ""
246+
247+
// Retrieve the OS and set variable to retrieve correct flutter embedder
248+
switch runtime.GOOS {
249+
case "darwin":
250+
platform = "darwin-x64"
251+
downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/FlutterEmbedder.framework.zip", hashResponse.Items[0].Sha, platform)
252+
253+
case "linux":
254+
platform = "linux-x64"
255+
downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform)
256+
257+
case "windows":
258+
platform = "windows-x64"
259+
downloadURL = fmt.Sprintf("https://storage.googleapis.com/flutter_infra/flutter/%s/%s/%s-embedder", hashResponse.Items[0].Sha, platform, platform)
260+
261+
default:
262+
log.Fatal("OS not supported")
263+
}
264+
265+
err3 := downloadFile(dir+"/.build/temp.zip", downloadURL)
266+
if err3 != nil {
267+
log.Fatal(err3)
268+
} else {
269+
fmt.Printf("Downloaded embedder for %s platform, matching version : %s\n", platform, hashResponse.Items[0].Sha)
270+
}
271+
272+
_, err = unzip(".build/temp.zip", dir+"/.build/")
273+
if err != nil {
274+
log.Fatal(err)
275+
}
276+
277+
switch platform {
278+
case "darwin-x64":
279+
_, err = unzip(".build/FlutterEmbedder.framework.zip", dir+"/FlutterEmbedder.framework")
280+
if err != nil {
281+
log.Fatal(err)
282+
}
283+
284+
case "linux-x64":
285+
err := os.Rename(".build/libflutter_engine.so", dir+"/libflutter_engine.so")
286+
if err != nil {
287+
log.Fatal(err)
288+
}
289+
290+
case "windows-x64":
291+
err := os.Rename(".build/flutter_engine.dll", dir+"/flutter_engine.dll")
292+
if err != nil {
293+
log.Fatal(err)
294+
}
295+
296+
}
297+
fmt.Printf("Unzipped files and moved them to correct repository.\n")
298+
299+
fmt.Printf("Done.\n")
300+
301+
}

0 commit comments

Comments
 (0)