| OLD | NEW |
| 1 // Copyright 2017 The LUCI Authors. | 1 // Copyright 2017 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, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 "strings" | 25 "strings" |
| 26 | 26 |
| 27 humanize "github.com/dustin/go-humanize" | 27 humanize "github.com/dustin/go-humanize" |
| 28 "github.com/luci/luci-go/common/isolated" | 28 "github.com/luci/luci-go/common/isolated" |
| 29 "github.com/luci/luci-go/common/isolatedclient" | 29 "github.com/luci/luci-go/common/isolatedclient" |
| 30 ) | 30 ) |
| 31 | 31 |
| 32 // limitedOS contains a subset of the functions from the os package. | 32 // limitedOS contains a subset of the functions from the os package. |
| 33 type limitedOS interface { | 33 type limitedOS interface { |
| 34 Readlink(string) (string, error) | 34 Readlink(string) (string, error) |
| 35 |
| 36 // Open is like os.Open, but returns an io.ReadCloser since |
| 37 // that's all we need and it's easier to implment with a fake. |
| 38 Open(string) (io.ReadCloser, error) |
| 39 |
| 35 openFiler | 40 openFiler |
| 36 } | 41 } |
| 37 | 42 |
| 38 type openFiler interface { | 43 type openFiler interface { |
| 39 // OpenFile is like os.OpenFile, but returns an io.WriteCloser since | 44 // OpenFile is like os.OpenFile, but returns an io.WriteCloser since |
| 40 // that's all we need and it's easier to implment with a fake. | 45 // that's all we need and it's easier to implment with a fake. |
| 41 OpenFile(string, int, os.FileMode) (io.WriteCloser, error) | 46 OpenFile(string, int, os.FileMode) (io.WriteCloser, error) |
| 42 } | 47 } |
| 43 | 48 |
| 44 // standardOS implements limitedOS by delegating to the standard library's os pa
ckage. | 49 // standardOS implements limitedOS by delegating to the standard library's os pa
ckage. |
| 45 type standardOS struct{} | 50 type standardOS struct{} |
| 46 | 51 |
| 47 func (sos standardOS) Readlink(name string) (string, error) { | 52 func (sos standardOS) Readlink(name string) (string, error) { |
| 48 return os.Readlink(name) | 53 return os.Readlink(name) |
| 49 } | 54 } |
| 50 | 55 |
| 56 func (sos standardOS) Open(name string) (io.ReadCloser, error) { |
| 57 return os.Open(name) |
| 58 } |
| 59 |
| 51 func (sos standardOS) OpenFile(name string, flag int, perm os.FileMode) (io.Writ
eCloser, error) { | 60 func (sos standardOS) OpenFile(name string, flag int, perm os.FileMode) (io.Writ
eCloser, error) { |
| 52 return os.OpenFile(name, flag, perm) | 61 return os.OpenFile(name, flag, perm) |
| 53 } | 62 } |
| 54 | 63 |
| 55 // UploadTracker uploads and keeps track of files. | 64 // UploadTracker uploads and keeps track of files. |
| 56 type UploadTracker struct { | 65 type UploadTracker struct { |
| 57 checker Checker | 66 checker Checker |
| 58 uploader Uploader | 67 uploader Uploader |
| 59 isol *isolated.Isolated | 68 isol *isolated.Isolated |
| 60 | 69 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 }) | 153 }) |
| 145 }) | 154 }) |
| 146 } | 155 } |
| 147 return nil | 156 return nil |
| 148 } | 157 } |
| 149 | 158 |
| 150 // uploadFiles uploads each file and adds it to files. | 159 // uploadFiles uploads each file and adds it to files. |
| 151 func (ut *UploadTracker) uploadFiles(files []*Item) error { | 160 func (ut *UploadTracker) uploadFiles(files []*Item) error { |
| 152 // Handle the large individually-uploaded files. | 161 // Handle the large individually-uploaded files. |
| 153 for _, item := range files { | 162 for _, item := range files { |
| 154 » » d, err := hashFile(item.Path) | 163 » » d, err := ut.hashFile(item.Path) |
| 155 if err != nil { | 164 if err != nil { |
| 156 return err | 165 return err |
| 157 } | 166 } |
| 158 item.Digest = d | 167 item.Digest = d |
| 159 ut.isol.Files[item.RelPath] = isolated.BasicFile(item.Digest, in
t(item.Mode), item.Size) | 168 ut.isol.Files[item.RelPath] = isolated.BasicFile(item.Digest, in
t(item.Mode), item.Size) |
| 160 ut.checker.AddItem(item, false, func(item *Item, ps *isolatedcli
ent.PushState) { | 169 ut.checker.AddItem(item, false, func(item *Item, ps *isolatedcli
ent.PushState) { |
| 161 if ps == nil { | 170 if ps == nil { |
| 162 return | 171 return |
| 163 } | 172 } |
| 164 log.Printf("QUEUED %q for upload", item.RelPath) | 173 log.Printf("QUEUED %q for upload", item.RelPath) |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 if err := isolFile.writeJSONFile(ut.lOS); err != nil { | 210 if err := isolFile.writeJSONFile(ut.lOS); err != nil { |
| 202 return IsolatedSummary{}, err | 211 return IsolatedSummary{}, err |
| 203 } | 212 } |
| 204 | 213 |
| 205 return IsolatedSummary{ | 214 return IsolatedSummary{ |
| 206 Name: isolFile.name(), | 215 Name: isolFile.name(), |
| 207 Digest: isolFile.item().Digest, | 216 Digest: isolFile.item().Digest, |
| 208 }, nil | 217 }, nil |
| 209 } | 218 } |
| 210 | 219 |
| 220 func (ut *UploadTracker) hashFile(path string) (isolated.HexDigest, error) { |
| 221 f, err := ut.lOS.Open(path) |
| 222 if err != nil { |
| 223 return "", err |
| 224 } |
| 225 defer f.Close() |
| 226 return isolated.Hash(f) |
| 227 } |
| 228 |
| 211 // isolatedFile is an isolated file which is stored in memory. | 229 // isolatedFile is an isolated file which is stored in memory. |
| 212 // It can produce a corresponding Item, for upload to the server, | 230 // It can produce a corresponding Item, for upload to the server, |
| 213 // and also write its contents to the filesystem. | 231 // and also write its contents to the filesystem. |
| 214 type isolatedFile struct { | 232 type isolatedFile struct { |
| 215 json []byte | 233 json []byte |
| 216 path string | 234 path string |
| 217 } | 235 } |
| 218 | 236 |
| 219 func newIsolatedFile(isol *isolated.Isolated, path string) (*isolatedFile, error
) { | 237 func newIsolatedFile(isol *isolated.Isolated, path string) (*isolatedFile, error
) { |
| 220 j, err := json.Marshal(isol) | 238 j, err := json.Marshal(isol) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 } | 271 } |
| 254 | 272 |
| 255 // name returns the base name of the isolated file, extension stripped. | 273 // name returns the base name of the isolated file, extension stripped. |
| 256 func (ij *isolatedFile) name() string { | 274 func (ij *isolatedFile) name() string { |
| 257 name := filepath.Base(ij.path) | 275 name := filepath.Base(ij.path) |
| 258 if i := strings.LastIndex(name, "."); i != -1 { | 276 if i := strings.LastIndex(name, "."); i != -1 { |
| 259 name = name[:i] | 277 name = name[:i] |
| 260 } | 278 } |
| 261 return name | 279 return name |
| 262 } | 280 } |
| OLD | NEW |