// Archive processes a .isolate, generates a .isolated and archive it. // Returns a Future to the .isolated. func Archive(arch archiver.Archiver, opts *ArchiveOptions) archiver.Future { displayName := filepath.Base(opts.Isolated) defer tracer.Span(arch, strings.SplitN(displayName, ".", 2)[0]+":archive", nil)(nil) f, err := archive(arch, opts, displayName) if err != nil { arch.Cancel(err) s := archiver.NewSimpleFuture(displayName) s.Finalize("", err) return s } return f }
func archive(arch archiver.Archiver, opts *ArchiveOptions, displayName string) (archiver.Future, error) { end := tracer.Span(arch, strings.SplitN(displayName, ".", 2)[0]+":loading", nil) filesCount, dirsCount, deps, rootDir, i, err := processing(opts) end(tracer.Args{"err": err}) if err != nil { return nil, err } // Handle each dependency, either a file or a directory.. fileFutures := make([]archiver.Future, 0, filesCount) dirFutures := make([]archiver.Future, 0, dirsCount) for _, dep := range deps { relPath, err := filepath.Rel(rootDir, dep) if err != nil { return nil, err } if dep[len(dep)-1] == os.PathSeparator { relPath, err := filepath.Rel(rootDir, dep) if err != nil { return nil, err } dirFutures = append(dirFutures, archiver.PushDirectory(arch, dep, relPath, opts.Blacklist)) } else { // Grab the stats right away. info, err := os.Lstat(dep) if err != nil { return nil, err } mode := info.Mode() if mode&os.ModeSymlink == os.ModeSymlink { l, err := os.Readlink(dep) if err != nil { return nil, err } i.Files[relPath] = isolated.File{Link: newString(l)} } else { i.Files[relPath] = isolated.File{Mode: newInt(int(mode.Perm())), Size: newInt64(info.Size())} fileFutures = append(fileFutures, arch.PushFile(relPath, dep, -info.Size())) } } } for _, future := range fileFutures { future.WaitForHashed() if err = future.Error(); err != nil { return nil, err } f := i.Files[future.DisplayName()] f.Digest = future.Digest() i.Files[future.DisplayName()] = f } // Avoid duplicated entries in includes. // TODO(tandrii): add test to reproduce the problem. includesSet := map[isolated.HexDigest]bool{} for _, future := range dirFutures { future.WaitForHashed() if err = future.Error(); err != nil { return nil, err } includesSet[future.Digest()] = true } for digest := range includesSet { i.Includes = append(i.Includes, digest) } raw := &bytes.Buffer{} if err = json.NewEncoder(raw).Encode(i); err != nil { return nil, err } if err := ioutil.WriteFile(opts.Isolated, raw.Bytes(), 0644); err != nil { return nil, err } return arch.Push(displayName, bytes.NewReader(raw.Bytes()), 0), nil }