From f83c150269c933ab6b384cf5e28cbf021a6ba9e1 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 10 Nov 2017 13:11:02 -0800 Subject: [PATCH] Add --write_if_changed argument to soong_zip Simplify making restat rules by adding a --write_if_changed argument to soong_zip that generates the output file into memory and then compares it to the version on disk before writing it out. Test: builds Change-Id: I5059a1e3a11e79b0ca538b3b829bc7479c126ce6 --- zip/Android.bp | 1 + zip/cmd/main.go | 18 +++++++++------- zip/zip.go | 56 ++++++++++++++++++++++++++++++++++--------------- 3 files changed, 50 insertions(+), 25 deletions(-) diff --git a/zip/Android.bp b/zip/Android.bp index d7080899b..3bb4f25d6 100644 --- a/zip/Android.bp +++ b/zip/Android.bp @@ -19,6 +19,7 @@ bootstrap_go_package { pkgPath: "android/soong/zip", deps: [ "android-archive-zip", + "blueprint-pathtools", "soong-jar", ], srcs: [ diff --git a/zip/cmd/main.go b/zip/cmd/main.go index 348728c25..c0418f7b5 100644 --- a/zip/cmd/main.go +++ b/zip/cmd/main.go @@ -120,14 +120,15 @@ func (d *dir) Set(s string) error { } var ( - out = flag.String("o", "", "file to write zip file to") - manifest = flag.String("m", "", "input jar manifest file name") - directories = flag.Bool("d", false, "include directories in zip") - rootPrefix = flag.String("P", "", "path prefix within the zip at which to place files") - relativeRoot = flag.String("C", "", "path to use as relative root of files in following -f, -l, or -D arguments") - parallelJobs = flag.Int("j", runtime.NumCPU(), "number of parallel threads to use") - compLevel = flag.Int("L", 5, "deflate compression level (0-9)") - emulateJar = flag.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'") + out = flag.String("o", "", "file to write zip file to") + manifest = flag.String("m", "", "input jar manifest file name") + directories = flag.Bool("d", false, "include directories in zip") + rootPrefix = flag.String("P", "", "path prefix within the zip at which to place files") + relativeRoot = flag.String("C", "", "path to use as relative root of files in following -f, -l, or -D arguments") + parallelJobs = flag.Int("j", runtime.NumCPU(), "number of parallel threads to use") + compLevel = flag.Int("L", 5, "deflate compression level (0-9)") + emulateJar = flag.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'") + writeIfChanged = flag.Bool("write_if_changed", false, "only update resultant .zip if it has changed") fArgs zip.FileArgs nonDeflatedFiles = make(uniqueSet) @@ -163,6 +164,7 @@ func main() { ManifestSourcePath: *manifest, NumParallelJobs: *parallelJobs, NonDeflatedFiles: nonDeflatedFiles, + WriteIfChanged: *writeIfChanged, }) if err != nil { fmt.Fprintln(os.Stderr, err.Error()) diff --git a/zip/zip.go b/zip/zip.go index 95520fe31..c878a0cce 100644 --- a/zip/zip.go +++ b/zip/zip.go @@ -32,6 +32,8 @@ import ( "sync" "time" + "github.com/google/blueprint/pathtools" + "android/soong/jar" "android/soong/third_party/zip" ) @@ -127,6 +129,7 @@ type ZipArgs struct { ManifestSourcePath string NumParallelJobs int NonDeflatedFiles map[string]bool + WriteIfChanged bool } func Run(args ZipArgs) (err error) { @@ -186,8 +189,38 @@ func Run(args ZipArgs) (err error) { } } - return w.write(args.OutputFilePath, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.NumParallelJobs) + buf := &bytes.Buffer{} + var out io.Writer = buf + if !args.WriteIfChanged { + f, err := os.Create(args.OutputFilePath) + if err != nil { + return err + } + + defer f.Close() + defer func() { + if err != nil { + os.Remove(args.OutputFilePath) + } + }() + + out = f + } + + err = w.write(out, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.NumParallelJobs) + if err != nil { + return err + } + + if args.WriteIfChanged { + err := pathtools.WriteFileIfChanged(args.OutputFilePath, buf.Bytes(), 0666) + if err != nil { + return err + } + } + + return nil } func fillPathPairs(prefix, rel, src string, pathMappings *[]pathMapping, nonDeflatedFiles map[string]bool) error { @@ -226,19 +259,7 @@ type readerSeekerCloser interface { io.Seeker } -func (z *ZipWriter) write(out string, pathMappings []pathMapping, manifest string, emulateJar bool, parallelJobs int) error { - f, err := os.Create(out) - if err != nil { - return err - } - - defer f.Close() - defer func() { - if err != nil { - os.Remove(out) - } - }() - +func (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest string, emulateJar bool, parallelJobs int) error { z.errors = make(chan error) defer close(z.errors) @@ -324,6 +345,7 @@ func (z *ZipWriter) write(out string, pathMappings []pathMapping, manifest strin case op := <-writeOpChan: currentWriteOpChan = nil + var err error if op.fh.Method == zip.Deflate { currentWriter, err = zipw.CreateCompressedHeader(op.fh) } else { @@ -356,21 +378,21 @@ func (z *ZipWriter) write(out string, pathMappings []pathMapping, manifest strin currentReader = futureReader case reader := <-currentReader: - _, err = io.Copy(currentWriter, reader) + _, err := io.Copy(currentWriter, reader) if err != nil { return err } currentReader = nil - case err = <-z.errors: + case err := <-z.errors: return err } } // One last chance to catch an error select { - case err = <-z.errors: + case err := <-z.errors: return err default: zipw.Close()