soong_zip: add --ignore_missing_files flag

soong_zip builds a list of files to zip early and then starts
zipping them all.  If a directory being zipped is concurrently
modified, a file that existed when soong_zip started may not
still exist.  Add a flag that continues when an expected file
does not exist.  Print a warning, since this should be rare
in normal usages but is a sign of a problem if it happens
regularly.

Test: zip_test.go
Test: m checkbuild
Test: m platform
Change-Id: I78426fe66fded8528ddd436c0f71a7442183cfeb
This commit is contained in:
Colin Cross 2018-09-28 15:16:48 -07:00
parent 09f11056f8
commit 4be8f9e2a3
3 changed files with 73 additions and 26 deletions

View File

@ -136,7 +136,7 @@ func main() {
compLevel := flags.Int("L", 5, "deflate compression level (0-9)") compLevel := flags.Int("L", 5, "deflate compression level (0-9)")
emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'") emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed") writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed")
ignoreMissingFiles := flags.Bool("ignore_missing_files", false, "continue if a requested file does not exist")
symlinks := flags.Bool("symlinks", true, "store symbolic links in zip instead of following them") symlinks := flags.Bool("symlinks", true, "store symbolic links in zip instead of following them")
parallelJobs := flags.Int("parallel", runtime.NumCPU(), "number of parallel threads to use") parallelJobs := flags.Int("parallel", runtime.NumCPU(), "number of parallel threads to use")
@ -200,6 +200,7 @@ func main() {
NonDeflatedFiles: nonDeflatedFiles, NonDeflatedFiles: nonDeflatedFiles,
WriteIfChanged: *writeIfChanged, WriteIfChanged: *writeIfChanged,
StoreSymlinks: *symlinks, StoreSymlinks: *symlinks,
IgnoreMissingFiles: *ignoreMissingFiles,
}) })
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "error:", err.Error()) fmt.Fprintln(os.Stderr, "error:", err.Error())

View File

@ -189,7 +189,9 @@ type ZipWriter struct {
compLevel int compLevel int
followSymlinks pathtools.ShouldFollowSymlinks followSymlinks pathtools.ShouldFollowSymlinks
ignoreMissingFiles bool
stderr io.Writer
fs pathtools.FileSystem fs pathtools.FileSystem
} }
@ -215,7 +217,9 @@ type ZipArgs struct {
NonDeflatedFiles map[string]bool NonDeflatedFiles map[string]bool
WriteIfChanged bool WriteIfChanged bool
StoreSymlinks bool StoreSymlinks bool
IgnoreMissingFiles bool
Stderr io.Writer
Filesystem pathtools.FileSystem Filesystem pathtools.FileSystem
} }
@ -277,6 +281,8 @@ func ZipTo(args ZipArgs, w io.Writer) error {
directories: args.AddDirectoryEntriesToZip, directories: args.AddDirectoryEntriesToZip,
compLevel: args.CompressionLevel, compLevel: args.CompressionLevel,
followSymlinks: followSymlinks, followSymlinks: followSymlinks,
ignoreMissingFiles: args.IgnoreMissingFiles,
stderr: args.Stderr,
fs: args.Filesystem, fs: args.Filesystem,
} }
@ -284,6 +290,10 @@ func ZipTo(args ZipArgs, w io.Writer) error {
z.fs = pathtools.OsFs z.fs = pathtools.OsFs
} }
if z.stderr == nil {
z.stderr = os.Stderr
}
pathMappings := []pathMapping{} pathMappings := []pathMapping{}
noCompression := args.CompressionLevel == 0 noCompression := args.CompressionLevel == 0
@ -301,29 +311,44 @@ func ZipTo(args ZipArgs, w io.Writer) error {
return err return err
} }
if len(globbed) == 0 { if len(globbed) == 0 {
return &os.PathError{ err := &os.PathError{
Op: "stat", Op: "lstat",
Path: s, Path: s,
Err: os.ErrNotExist, Err: os.ErrNotExist,
} }
if args.IgnoreMissingFiles {
fmt.Fprintln(args.Stderr, "warning:", err)
} else {
return err
}
} }
srcs = append(srcs, globbed...) srcs = append(srcs, globbed...)
} }
if fa.GlobDir != "" { if fa.GlobDir != "" {
if exists, isDir, err := z.fs.Exists(fa.GlobDir); err != nil { if exists, isDir, err := z.fs.Exists(fa.GlobDir); err != nil {
return err return err
} else if !exists { } else if !exists && !args.IgnoreMissingFiles {
return &os.PathError{ err := &os.PathError{
Op: "stat", Op: "lstat",
Path: fa.GlobDir, Path: fa.GlobDir,
Err: os.ErrNotExist, Err: os.ErrNotExist,
} }
} else if !isDir { if args.IgnoreMissingFiles {
return &os.PathError{ fmt.Fprintln(args.Stderr, "warning:", err)
Op: "stat", } else {
return err
}
} else if !isDir && !args.IgnoreMissingFiles {
err := &os.PathError{
Op: "lstat",
Path: fa.GlobDir, Path: fa.GlobDir,
Err: syscall.ENOTDIR, Err: syscall.ENOTDIR,
} }
if args.IgnoreMissingFiles {
fmt.Fprintln(args.Stderr, "warning:", err)
} else {
return err
}
} }
globbed, _, err := z.fs.Glob(filepath.Join(fa.GlobDir, "**/*"), nil, followSymlinks) globbed, _, err := z.fs.Glob(filepath.Join(fa.GlobDir, "**/*"), nil, followSymlinks)
if err != nil { if err != nil {
@ -576,6 +601,10 @@ func (z *ZipWriter) addFile(dest, src string, method uint16, emulateJar bool) er
} }
if err != nil { if err != nil {
if os.IsNotExist(err) && z.ignoreMissingFiles {
fmt.Fprintln(z.stderr, "warning:", err)
return nil
}
return err return err
} else if s.IsDir() { } else if s.IsDir() {
if z.directories { if z.directories {

View File

@ -106,6 +106,7 @@ func TestZip(t *testing.T) {
dirEntries bool dirEntries bool
manifest string manifest string
storeSymlinks bool storeSymlinks bool
ignoreMissingFiles bool
files []zip.FileHeader files []zip.FileHeader
err error err error
@ -338,6 +339,20 @@ func TestZip(t *testing.T) {
fh("a/a/b", fileB, zip.Deflate), fh("a/a/b", fileB, zip.Deflate),
}, },
}, },
{
name: "ignore missing files",
args: fileArgsBuilder().
File("a/a/a").
File("a/a/b").
File("missing"),
compressionLevel: 9,
ignoreMissingFiles: true,
files: []zip.FileHeader{
fh("a/a/a", fileA, zip.Deflate),
fh("a/a/b", fileB, zip.Deflate),
},
},
// errors // errors
{ {
@ -381,7 +396,9 @@ func TestZip(t *testing.T) {
args.NonDeflatedFiles = test.nonDeflatedFiles args.NonDeflatedFiles = test.nonDeflatedFiles
args.ManifestSourcePath = test.manifest args.ManifestSourcePath = test.manifest
args.StoreSymlinks = test.storeSymlinks args.StoreSymlinks = test.storeSymlinks
args.IgnoreMissingFiles = test.ignoreMissingFiles
args.Filesystem = mockFs args.Filesystem = mockFs
args.Stderr = &bytes.Buffer{}
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
err := ZipTo(args, buf) err := ZipTo(args, buf)