|
16 | 16 | package tools
|
17 | 17 |
|
18 | 18 | import (
|
19 |
| - "archive/tar" |
20 |
| - "archive/zip" |
21 | 19 | "bytes"
|
22 |
| - "compress/bzip2" |
23 |
| - "compress/gzip" |
| 20 | + "context" |
24 | 21 | "crypto/sha256"
|
25 | 22 | "encoding/hex"
|
26 | 23 | "encoding/json"
|
27 | 24 | "errors"
|
28 |
| - "fmt" |
29 | 25 | "io"
|
30 | 26 | "net/http"
|
31 | 27 | "os"
|
32 | 28 | "os/exec"
|
33 |
| - "path" |
34 | 29 | "path/filepath"
|
35 | 30 | "runtime"
|
36 | 31 | "strings"
|
37 | 32 |
|
38 |
| - "github.com/arduino/arduino-create-agent/utilities" |
39 | 33 | "github.com/arduino/arduino-create-agent/v2/pkgs"
|
40 | 34 | "github.com/blang/semver"
|
| 35 | + "github.com/codeclysm/extract/v3" |
41 | 36 | )
|
42 | 37 |
|
43 | 38 | // public vars to allow override in the tests
|
|
46 | 41 | Arch = runtime.GOARCH
|
47 | 42 | )
|
48 | 43 |
|
49 |
| -func mimeType(data []byte) (string, error) { |
50 |
| - return http.DetectContentType(data[0:512]), nil |
51 |
| -} |
52 |
| - |
53 | 44 | func pathExists(path string) bool {
|
54 | 45 | _, err := os.Stat(path)
|
55 | 46 | if err == nil {
|
@@ -139,23 +130,22 @@ func (t *Tools) Download(pack, name, version, behaviour string) error {
|
139 | 130 | return err
|
140 | 131 | }
|
141 | 132 |
|
142 |
| - srcType, err := mimeType(body) |
| 133 | + ctx := context.Background() |
| 134 | + |
| 135 | + reader := bytes.NewReader(body) |
| 136 | + err = extract.Archive(ctx, reader, location, func(original string) string { |
| 137 | + // Split the original path into components |
| 138 | + components := strings.Split(original, string(os.PathSeparator)) |
| 139 | + // If there's a root directory, remove it |
| 140 | + if len(components) > 1 { |
| 141 | + return filepath.Join(components[1:]...) |
| 142 | + } |
| 143 | + return original |
| 144 | + }) |
143 | 145 | if err != nil {
|
144 | 146 | return err
|
145 | 147 | }
|
146 | 148 |
|
147 |
| - switch srcType { |
148 |
| - case "application/zip": |
149 |
| - location, err = extractZip(t.logger, body, location) |
150 |
| - case "application/x-bz2": |
151 |
| - case "application/octet-stream": |
152 |
| - location, err = extractBz2(t.logger, body, location) |
153 |
| - case "application/x-gzip": |
154 |
| - location, err = extractTarGz(t.logger, body, location) |
155 |
| - default: |
156 |
| - return errors.New("Unknown extension for file " + correctSystem.URL) |
157 |
| - } |
158 |
| - |
159 | 149 | if err != nil {
|
160 | 150 | t.logger("Error extracting the archive: " + err.Error())
|
161 | 151 | return err
|
@@ -207,258 +197,6 @@ func findTool(pack, name, version string, data pkgs.Index) (pkgs.Tool, pkgs.Syst
|
207 | 197 | return correctTool, correctSystem
|
208 | 198 | }
|
209 | 199 |
|
210 |
| -func commonPrefix(sep byte, paths []string) string { |
211 |
| - // Handle special cases. |
212 |
| - switch len(paths) { |
213 |
| - case 0: |
214 |
| - return "" |
215 |
| - case 1: |
216 |
| - return path.Clean(paths[0]) |
217 |
| - } |
218 |
| - |
219 |
| - c := []byte(path.Clean(paths[0])) |
220 |
| - |
221 |
| - // We add a trailing sep to handle: common prefix directory is included in the path list |
222 |
| - // (e.g. /home/user1, /home/user1/foo, /home/user1/bar). |
223 |
| - // path.Clean will have cleaned off trailing / separators with |
224 |
| - // the exception of the root directory, "/" making it "//" |
225 |
| - // but this will get fixed up to "/" below). |
226 |
| - c = append(c, sep) |
227 |
| - |
228 |
| - // Ignore the first path since it's already in c |
229 |
| - for _, v := range paths[1:] { |
230 |
| - // Clean up each path before testing it |
231 |
| - v = path.Clean(v) + string(sep) |
232 |
| - |
233 |
| - // Find the first non-common byte and truncate c |
234 |
| - if len(v) < len(c) { |
235 |
| - c = c[:len(v)] |
236 |
| - } |
237 |
| - for i := 0; i < len(c); i++ { |
238 |
| - if v[i] != c[i] { |
239 |
| - c = c[:i] |
240 |
| - break |
241 |
| - } |
242 |
| - } |
243 |
| - } |
244 |
| - |
245 |
| - // Remove trailing non-separator characters and the final separator |
246 |
| - for i := len(c) - 1; i >= 0; i-- { |
247 |
| - if c[i] == sep { |
248 |
| - c = c[:i] |
249 |
| - break |
250 |
| - } |
251 |
| - } |
252 |
| - |
253 |
| - return string(c) |
254 |
| -} |
255 |
| - |
256 |
| -func removeStringFromSlice(s []string, r string) []string { |
257 |
| - for i, v := range s { |
258 |
| - if v == r { |
259 |
| - return append(s[:i], s[i+1:]...) |
260 |
| - } |
261 |
| - } |
262 |
| - return s |
263 |
| -} |
264 |
| - |
265 |
| -func findBaseDir(dirList []string) string { |
266 |
| - if len(dirList) == 1 { |
267 |
| - return path.Dir(dirList[0]) + "/" |
268 |
| - } |
269 |
| - |
270 |
| - // https://github.com/backdrop-ops/contrib/issues/55#issuecomment-73814500 |
271 |
| - dontdiff := []string{"pax_global_header"} |
272 |
| - for _, v := range dontdiff { |
273 |
| - dirList = removeStringFromSlice(dirList, v) |
274 |
| - } |
275 |
| - |
276 |
| - commonBaseDir := commonPrefix('/', dirList) |
277 |
| - if commonBaseDir != "" { |
278 |
| - commonBaseDir = commonBaseDir + "/" |
279 |
| - } |
280 |
| - return commonBaseDir |
281 |
| -} |
282 |
| - |
283 |
| -func extractZip(log func(msg string), body []byte, location string) (string, error) { |
284 |
| - path, _ := utilities.SaveFileonTempDir("tooldownloaded.zip", bytes.NewReader(body)) |
285 |
| - r, err := zip.OpenReader(path) |
286 |
| - if err != nil { |
287 |
| - return location, err |
288 |
| - } |
289 |
| - |
290 |
| - var dirList []string |
291 |
| - |
292 |
| - for _, f := range r.File { |
293 |
| - dirList = append(dirList, f.Name) |
294 |
| - } |
295 |
| - |
296 |
| - basedir := findBaseDir(dirList) |
297 |
| - log(fmt.Sprintf("selected baseDir %s from Zip Archive Content: %v", basedir, dirList)) |
298 |
| - |
299 |
| - for _, f := range r.File { |
300 |
| - fullname := filepath.Join(location, strings.Replace(f.Name, basedir, "", -1)) |
301 |
| - log(fmt.Sprintf("generated fullname %s removing %s from %s", fullname, basedir, f.Name)) |
302 |
| - if f.FileInfo().IsDir() { |
303 |
| - os.MkdirAll(fullname, f.FileInfo().Mode().Perm()) |
304 |
| - } else { |
305 |
| - os.MkdirAll(filepath.Dir(fullname), 0755) |
306 |
| - perms := f.FileInfo().Mode().Perm() |
307 |
| - out, err := os.OpenFile(fullname, os.O_CREATE|os.O_RDWR, perms) |
308 |
| - if err != nil { |
309 |
| - return location, err |
310 |
| - } |
311 |
| - rc, err := f.Open() |
312 |
| - if err != nil { |
313 |
| - return location, err |
314 |
| - } |
315 |
| - _, err = io.CopyN(out, rc, f.FileInfo().Size()) |
316 |
| - if err != nil { |
317 |
| - return location, err |
318 |
| - } |
319 |
| - rc.Close() |
320 |
| - out.Close() |
321 |
| - |
322 |
| - mtime := f.FileInfo().ModTime() |
323 |
| - err = os.Chtimes(fullname, mtime, mtime) |
324 |
| - if err != nil { |
325 |
| - return location, err |
326 |
| - } |
327 |
| - } |
328 |
| - } |
329 |
| - return location, nil |
330 |
| -} |
331 |
| - |
332 |
| -func extractTarGz(log func(msg string), body []byte, location string) (string, error) { |
333 |
| - bodyCopy := make([]byte, len(body)) |
334 |
| - copy(bodyCopy, body) |
335 |
| - tarFile, _ := gzip.NewReader(bytes.NewReader(body)) |
336 |
| - tarReader := tar.NewReader(tarFile) |
337 |
| - |
338 |
| - var dirList []string |
339 |
| - |
340 |
| - for { |
341 |
| - header, err := tarReader.Next() |
342 |
| - if err == io.EOF { |
343 |
| - break |
344 |
| - } |
345 |
| - dirList = append(dirList, header.Name) |
346 |
| - } |
347 |
| - |
348 |
| - basedir := findBaseDir(dirList) |
349 |
| - log(fmt.Sprintf("selected baseDir %s from TarGz Archive Content: %v", basedir, dirList)) |
350 |
| - |
351 |
| - tarFile, _ = gzip.NewReader(bytes.NewReader(bodyCopy)) |
352 |
| - tarReader = tar.NewReader(tarFile) |
353 |
| - |
354 |
| - for { |
355 |
| - header, err := tarReader.Next() |
356 |
| - if err == io.EOF { |
357 |
| - break |
358 |
| - } else if err != nil { |
359 |
| - return location, err |
360 |
| - } |
361 |
| - |
362 |
| - path := filepath.Join(location, strings.Replace(header.Name, basedir, "", -1)) |
363 |
| - info := header.FileInfo() |
364 |
| - |
365 |
| - // Create parent folder |
366 |
| - dirmode := info.Mode() | os.ModeDir | 0700 |
367 |
| - if err = os.MkdirAll(filepath.Dir(path), dirmode); err != nil { |
368 |
| - return location, err |
369 |
| - } |
370 |
| - |
371 |
| - if info.IsDir() { |
372 |
| - if err = os.MkdirAll(path, info.Mode()); err != nil { |
373 |
| - return location, err |
374 |
| - } |
375 |
| - continue |
376 |
| - } |
377 |
| - |
378 |
| - if header.Typeflag == tar.TypeSymlink { |
379 |
| - _ = os.Symlink(header.Linkname, path) |
380 |
| - continue |
381 |
| - } |
382 |
| - |
383 |
| - file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()) |
384 |
| - if err != nil { |
385 |
| - continue |
386 |
| - } |
387 |
| - _, err = io.Copy(file, tarReader) |
388 |
| - if err != nil { |
389 |
| - return location, err |
390 |
| - } |
391 |
| - file.Close() |
392 |
| - } |
393 |
| - return location, nil |
394 |
| -} |
395 |
| - |
396 |
| -func extractBz2(log func(msg string), body []byte, location string) (string, error) { |
397 |
| - bodyCopy := make([]byte, len(body)) |
398 |
| - copy(bodyCopy, body) |
399 |
| - tarFile := bzip2.NewReader(bytes.NewReader(body)) |
400 |
| - tarReader := tar.NewReader(tarFile) |
401 |
| - |
402 |
| - var dirList []string |
403 |
| - |
404 |
| - for { |
405 |
| - header, err := tarReader.Next() |
406 |
| - if err == io.EOF { |
407 |
| - break |
408 |
| - } |
409 |
| - dirList = append(dirList, header.Name) |
410 |
| - } |
411 |
| - |
412 |
| - basedir := findBaseDir(dirList) |
413 |
| - log(fmt.Sprintf("selected baseDir %s from Bz2 Archive Content: %v", basedir, dirList)) |
414 |
| - |
415 |
| - tarFile = bzip2.NewReader(bytes.NewReader(bodyCopy)) |
416 |
| - tarReader = tar.NewReader(tarFile) |
417 |
| - |
418 |
| - for { |
419 |
| - header, err := tarReader.Next() |
420 |
| - if err == io.EOF { |
421 |
| - break |
422 |
| - } else if err != nil { |
423 |
| - continue |
424 |
| - //return location, err |
425 |
| - } |
426 |
| - |
427 |
| - path := filepath.Join(location, strings.Replace(header.Name, basedir, "", -1)) |
428 |
| - info := header.FileInfo() |
429 |
| - |
430 |
| - // Create parent folder |
431 |
| - dirmode := info.Mode() | os.ModeDir | 0700 |
432 |
| - if err = os.MkdirAll(filepath.Dir(path), dirmode); err != nil { |
433 |
| - return location, err |
434 |
| - } |
435 |
| - |
436 |
| - if info.IsDir() { |
437 |
| - if err = os.MkdirAll(path, info.Mode()); err != nil { |
438 |
| - return location, err |
439 |
| - } |
440 |
| - continue |
441 |
| - } |
442 |
| - |
443 |
| - if header.Typeflag == tar.TypeSymlink { |
444 |
| - _ = os.Symlink(header.Linkname, path) |
445 |
| - continue |
446 |
| - } |
447 |
| - |
448 |
| - file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()) |
449 |
| - if err != nil { |
450 |
| - continue |
451 |
| - //return location, err |
452 |
| - } |
453 |
| - _, err = io.Copy(file, tarReader) |
454 |
| - if err != nil { |
455 |
| - return location, err |
456 |
| - } |
457 |
| - file.Close() |
458 |
| - } |
459 |
| - return location, nil |
460 |
| -} |
461 |
| - |
462 | 200 | func (t *Tools) installDrivers(location string) error {
|
463 | 201 | OkPressed := 6
|
464 | 202 | extension := ".bat"
|
|
0 commit comments