Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Unified Diff: client/cmd/isolate/tarring_archiver.go

Issue 2991083002: isolate: Move partitioning code out of exparchive main. (Closed)
Patch Set: refer to isolate rather than isolated path when logging Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « client/cmd/isolate/exp_archive.go ('k') | client/cmd/isolate/upload_tracker.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: client/cmd/isolate/tarring_archiver.go
diff --git a/client/cmd/isolate/tarring_archiver.go b/client/cmd/isolate/tarring_archiver.go
new file mode 100644
index 0000000000000000000000000000000000000000..2f91d119ef37aa4719f2e93ee9e533416763d4ac
--- /dev/null
+++ b/client/cmd/isolate/tarring_archiver.go
@@ -0,0 +1,160 @@
+// Copyright 2017 The LUCI Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+
+ humanize "github.com/dustin/go-humanize"
+ "github.com/luci/luci-go/client/internal/common"
+ "github.com/luci/luci-go/client/isolate"
+ "github.com/luci/luci-go/common/isolated"
+)
+
+// TarringArchiver archives the files specified by an isolate file to the server,
+// Small files are combining into tar archives before uploading.
+type TarringArchiver struct {
+ checker Checker
+ uploader Uploader
+}
+
+// NewTarringArchiver constructs a TarringArchiver.
+func NewTarringArchiver(checker Checker, uploader Uploader) *TarringArchiver {
+ return &TarringArchiver{checker: checker, uploader: uploader}
+}
+
+// Archive uploads a single isolate.
+func (ta *TarringArchiver) Archive(archiveOpts *isolate.ArchiveOptions) (IsolatedSummary, error) {
+ // Parse the incoming isolate file.
+ deps, rootDir, isol, err := isolate.ProcessIsolate(archiveOpts)
+ if err != nil {
+ return IsolatedSummary{}, fmt.Errorf("failed to process isolate: %v", err)
+ }
+ log.Printf("Isolate %s referenced %d deps", archiveOpts.Isolate, len(deps))
+
+ parts, err := partitionDeps(deps, rootDir, archiveOpts.Blacklist)
+ if err != nil {
+ return IsolatedSummary{}, fmt.Errorf("partitioning deps: %v", err)
+ }
+
+ log.Printf("Isolate %s expanded to the following items to be isolated:\n%s", archiveOpts.Isolate, parts)
+
+ tracker := NewUploadTracker(ta.checker, ta.uploader, isol)
+ if err := tracker.UploadDeps(parts); err != nil {
+ return IsolatedSummary{}, err
+ }
+ return tracker.Finalize(archiveOpts.Isolated)
+}
+
+// Item represents a file or symlink referenced by an isolate file.
+type Item struct {
+ Path string
+ RelPath string
+ Size int64
+ Mode os.FileMode
+
+ Digest isolated.HexDigest
+}
+
+// itemGroup is a list of Items, plus a count of the aggregate size.
+type itemGroup struct {
+ items []*Item
+ totalSize int64
+}
+
+func (ig *itemGroup) AddItem(item *Item) {
+ ig.items = append(ig.items, item)
+ ig.totalSize += item.Size
+}
+
+// partitioningWalker contains the state necessary to partition isolate deps by handling multiple os.WalkFunc invocations.
+type partitioningWalker struct {
+ // fsView must be initialized before walkFn is called.
+ fsView common.FilesystemView
+
+ parts partitionedDeps
+}
+
+// partitionedDeps contains a list of items to be archived, partitioned into symlinks and files categorized by size.
+type partitionedDeps struct {
+ links itemGroup
+ filesToArchive itemGroup
+ indivFiles itemGroup
+}
+
+func (parts partitionedDeps) String() string {
+ str := fmt.Sprintf(" %d symlinks\n", len(parts.links.items))
+ str += fmt.Sprintf(" %d individual files (total size: %s)\n", len(parts.indivFiles.items), humanize.Bytes(uint64(parts.indivFiles.totalSize)))
+ str += fmt.Sprintf(" %d files in archives (total size %s)", len(parts.filesToArchive.items), humanize.Bytes(uint64(parts.filesToArchive.totalSize)))
+ return str
+}
+
+// walkFn implements filepath.WalkFunc, for use traversing a directory hierarchy to be isolated.
+// It accumulates files in pw.parts, partitioned into symlinks and files categorized by size.
+func (pw *partitioningWalker) walkFn(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ relPath, err := pw.fsView.RelativePath(path)
+ if err != nil {
+ return err
+ }
+
+ if relPath == "" { // empty string indicates skip.
+ return common.WalkFuncSkipFile(info)
+ }
+
+ if info.IsDir() {
+ return nil
+ }
+
+ item := &Item{
+ Path: path,
+ RelPath: relPath,
+ Mode: info.Mode(),
+ Size: info.Size(),
+ }
+
+ switch {
+ case item.Mode&os.ModeSymlink == os.ModeSymlink:
+ pw.parts.links.AddItem(item)
+ case item.Size < archiveThreshold:
+ pw.parts.filesToArchive.AddItem(item)
+ default:
+ pw.parts.indivFiles.AddItem(item)
+ }
+ return nil
+}
+
+// partitionDeps walks each of the deps, partioning the results into symlinks and files categorized by size.
+func partitionDeps(deps []string, rootDir string, blacklist []string) (partitionedDeps, error) {
+ fsView, err := common.NewFilesystemView(rootDir, blacklist)
+ if err != nil {
+ return partitionedDeps{}, err
+ }
+
+ walker := partitioningWalker{fsView: fsView}
+ for _, dep := range deps {
+ // Try to walk dep. If dep is a file (or symlink), the inner function is called exactly once.
+ if err := filepath.Walk(filepath.Clean(dep), walker.walkFn); err != nil {
+ return partitionedDeps{}, err
+ }
+ }
+ return walker.parts, nil
+}
« no previous file with comments | « client/cmd/isolate/exp_archive.go ('k') | client/cmd/isolate/upload_tracker.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698