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

Side by Side Diff: client/cmd/isolate/exp_archive.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, 4 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 unified diff | Download patch
« no previous file with comments | « client/cmd/isolate/checker.go ('k') | client/cmd/isolate/tarring_archiver.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The LUCI Authors. 1 // Copyright 2015 The LUCI Authors.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 package main 15 package main
16 16
17 import ( 17 import (
18 "encoding/json" 18 "encoding/json"
19 "errors" 19 "errors"
20 "fmt" 20 "fmt"
21 "io" 21 "io"
22 "log" 22 "log"
23 "os" 23 "os"
24 "path/filepath"
25 "time" 24 "time"
26 25
27 humanize "github.com/dustin/go-humanize"
28 "github.com/golang/protobuf/proto" 26 "github.com/golang/protobuf/proto"
29 "github.com/maruel/subcommands" 27 "github.com/maruel/subcommands"
30 "golang.org/x/net/context" 28 "golang.org/x/net/context"
31 29
32 "github.com/luci/luci-go/client/internal/common"
33 "github.com/luci/luci-go/client/isolate"
34 "github.com/luci/luci-go/common/auth" 30 "github.com/luci/luci-go/common/auth"
35 logpb "github.com/luci/luci-go/common/eventlog/proto" 31 logpb "github.com/luci/luci-go/common/eventlog/proto"
36 "github.com/luci/luci-go/common/isolated" 32 "github.com/luci/luci-go/common/isolated"
37 "github.com/luci/luci-go/common/isolatedclient" 33 "github.com/luci/luci-go/common/isolatedclient"
38 ) 34 )
39 35
40 const ( 36 const (
41 // archiveThreshold is the size (in bytes) used to determine whether to add 37 // archiveThreshold is the size (in bytes) used to determine whether to add
42 // files to a tar archive before uploading. Files smaller than this size will 38 // files to a tar archive before uploading. Files smaller than this size will
43 // be combined into archives before being uploaded to the server. 39 // be combined into archives before being uploaded to the server.
(...skipping 26 matching lines...) Expand all
70 66
71 // expArchiveRun contains the logic for the experimental archive subcommand. 67 // expArchiveRun contains the logic for the experimental archive subcommand.
72 // It implements subcommand.CommandRun 68 // It implements subcommand.CommandRun
73 type expArchiveRun struct { 69 type expArchiveRun struct {
74 commonServerFlags // Provides the GetFlags method. 70 commonServerFlags // Provides the GetFlags method.
75 isolateFlags isolateFlags 71 isolateFlags isolateFlags
76 loggingFlags loggingFlags 72 loggingFlags loggingFlags
77 dumpJSON string 73 dumpJSON string
78 } 74 }
79 75
80 // Item represents a file or symlink referenced by an isolate file.
81 type Item struct {
82 Path string
83 RelPath string
84 Size int64
85 Mode os.FileMode
86
87 Digest isolated.HexDigest
88 }
89
90 // itemGroup is a list of Items, plus a count of the aggregate size.
91 type itemGroup struct {
92 items []*Item
93 totalSize int64
94 }
95
96 func (ig *itemGroup) AddItem(item *Item) {
97 ig.items = append(ig.items, item)
98 ig.totalSize += item.Size
99 }
100
101 // partitioningWalker contains the state necessary to partition isolate deps by handling multiple os.WalkFunc invocations.
102 type partitioningWalker struct {
103 // fsView must be initialized before walkFn is called.
104 fsView common.FilesystemView
105
106 parts partitionedDeps
107 }
108
109 // partitionedDeps contains a list of items to be archived, partitioned into sym links and files categorized by size.
110 type partitionedDeps struct {
111 links itemGroup
112 filesToArchive itemGroup
113 indivFiles itemGroup
114 }
115
116 // walkFn implements filepath.WalkFunc, for use traversing a directory hierarchy to be isolated.
117 // It accumulates files in pw.parts, partitioned into symlinks and files categor ized by size.
118 func (pw *partitioningWalker) walkFn(path string, info os.FileInfo, err error) e rror {
119 if err != nil {
120 return err
121 }
122
123 relPath, err := pw.fsView.RelativePath(path)
124 if err != nil {
125 return err
126 }
127
128 if relPath == "" { // empty string indicates skip.
129 return common.WalkFuncSkipFile(info)
130 }
131
132 if info.IsDir() {
133 return nil
134 }
135
136 item := &Item{
137 Path: path,
138 RelPath: relPath,
139 Mode: info.Mode(),
140 Size: info.Size(),
141 }
142
143 switch {
144 case item.Mode&os.ModeSymlink == os.ModeSymlink:
145 pw.parts.links.AddItem(item)
146 case item.Size < archiveThreshold:
147 pw.parts.filesToArchive.AddItem(item)
148 default:
149 pw.parts.indivFiles.AddItem(item)
150 }
151 return nil
152 }
153
154 // partitionDeps walks each of the deps, partioning the results into symlinks an d files categorized by size.
155 func partitionDeps(deps []string, rootDir string, blacklist []string) (partition edDeps, error) {
156 fsView, err := common.NewFilesystemView(rootDir, blacklist)
157 if err != nil {
158 return partitionedDeps{}, err
159 }
160
161 walker := partitioningWalker{fsView: fsView}
162 for _, dep := range deps {
163 // Try to walk dep. If dep is a file (or symlink), the inner fun ction is called exactly once.
164 if err := filepath.Walk(filepath.Clean(dep), walker.walkFn); err != nil {
165 return partitionedDeps{}, err
166 }
167 }
168 return walker.parts, nil
169 }
170
171 // main contains the core logic for experimental archive. 76 // main contains the core logic for experimental archive.
172 func (c *expArchiveRun) main() error { 77 func (c *expArchiveRun) main() error {
173 // TODO(djd): This func is long and has a lot of internal complexity (li ke,
174 // such as, archiveCallback). Refactor.
175
176 start := time.Now() 78 start := time.Now()
177 archiveOpts := &c.isolateFlags.ArchiveOptions 79 archiveOpts := &c.isolateFlags.ArchiveOptions
178 // Parse the incoming isolate file.
179 deps, rootDir, isol, err := isolate.ProcessIsolate(archiveOpts)
180 if err != nil {
181 return fmt.Errorf("failed to process isolate: %v", err)
182 }
183 log.Printf("Isolate referenced %d deps", len(deps))
184 80
185 // Set up a background context which is cancelled when this function ret urns. 81 // Set up a background context which is cancelled when this function ret urns.
186 ctx, cancel := context.WithCancel(context.Background()) 82 ctx, cancel := context.WithCancel(context.Background())
187 defer cancel() 83 defer cancel()
188 84
189 // Create the isolated client which connects to the isolate server. 85 // Create the isolated client which connects to the isolate server.
190 authCl, err := c.createAuthClient() 86 authCl, err := c.createAuthClient()
191 if err != nil { 87 if err != nil {
192 return err 88 return err
193 } 89 }
194 client := isolatedclient.New(nil, authCl, c.isolatedFlags.ServerURL, c.i solatedFlags.Namespace, nil, nil) 90 client := isolatedclient.New(nil, authCl, c.isolatedFlags.ServerURL, c.i solatedFlags.Namespace, nil, nil)
195 91
196 // Set up a checker and uploader. We limit the uploader to one concurren t 92 // Set up a checker and uploader. We limit the uploader to one concurren t
197 // upload, since the uploads are all coming from disk (with the exceptio n of 93 // upload, since the uploads are all coming from disk (with the exceptio n of
198 // the isolated JSON itself) and we only want a single goroutine reading from 94 // the isolated JSON itself) and we only want a single goroutine reading from
199 // disk at once. 95 // disk at once.
200 checker := NewChecker(ctx, client) 96 checker := NewChecker(ctx, client)
201 uploader := NewUploader(ctx, client, 1) 97 uploader := NewUploader(ctx, client, 1)
98 archiver := NewTarringArchiver(checker, uploader)
202 99
203 » parts, err := partitionDeps(deps, rootDir, c.isolateFlags.ArchiveOptions .Blacklist) 100 » isolSummary, err := archiver.Archive(archiveOpts)
204 » if err != nil {
205 » » return fmt.Errorf("partitioning deps: %v", err)
206 » }
207
208 » numFiles := len(parts.filesToArchive.items) + len(parts.indivFiles.items )
209 » filesSize := uint64(parts.filesToArchive.totalSize + parts.indivFiles.to talSize)
210 » log.Printf("Isolate expanded to %d files (total size %s) and %d symlinks ", numFiles, humanize.Bytes(filesSize), len(parts.links.items))
211 » log.Printf("\t%d files (%s) to be isolated individually", len(parts.indi vFiles.items), humanize.Bytes(uint64(parts.indivFiles.totalSize)))
212 » log.Printf("\t%d files (%s) to be isolated in archives", len(parts.files ToArchive.items), humanize.Bytes(uint64(parts.filesToArchive.totalSize)))
213
214 » tracker := NewUploadTracker(checker, uploader, isol)
215 » if err := tracker.UploadDeps(parts); err != nil {
216 » » return err
217 » }
218 » isolSummary, err := tracker.Finalize(archiveOpts.Isolated)
219 » if err != nil {
220 » » return err
221 » }
222
223 printSummary(isolSummary) 101 printSummary(isolSummary)
224 if c.dumpJSON != "" { 102 if c.dumpJSON != "" {
225 f, err := os.OpenFile(c.dumpJSON, os.O_RDWR|os.O_CREATE|os.O_TRU NC, 0644) 103 f, err := os.OpenFile(c.dumpJSON, os.O_RDWR|os.O_CREATE|os.O_TRU NC, 0644)
226 if err != nil { 104 if err != nil {
227 return err 105 return err
228 } 106 }
229 writeSummaryJSON(f, isolSummary) 107 writeSummaryJSON(f, isolSummary)
230 f.Close() 108 f.Close()
231 } 109 }
232 110
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 } 170 }
293 171
294 func hashFile(path string) (isolated.HexDigest, error) { 172 func hashFile(path string) (isolated.HexDigest, error) {
295 f, err := os.Open(path) 173 f, err := os.Open(path)
296 if err != nil { 174 if err != nil {
297 return "", err 175 return "", err
298 } 176 }
299 defer f.Close() 177 defer f.Close()
300 return isolated.Hash(f) 178 return isolated.Hash(f)
301 } 179 }
OLDNEW
« no previous file with comments | « client/cmd/isolate/checker.go ('k') | client/cmd/isolate/tarring_archiver.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698