Browse Source

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
Colin Cross 6 years ago
parent
commit
f83c150269
3 changed files with 50 additions and 25 deletions
  1. 1 0
      zip/Android.bp
  2. 10 8
      zip/cmd/main.go
  3. 39 17
      zip/zip.go

+ 1 - 0
zip/Android.bp

@@ -19,6 +19,7 @@ bootstrap_go_package {
     pkgPath: "android/soong/zip",
     deps: [
         "android-archive-zip",
+        "blueprint-pathtools",
         "soong-jar",
     ],
     srcs: [

+ 10 - 8
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())

+ 39 - 17
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()