|
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