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
This commit is contained in:
Colin Cross 2017-11-10 13:11:02 -08:00
parent 5e6cfbead9
commit f83c150269
3 changed files with 50 additions and 25 deletions

View file

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

View file

@ -120,14 +120,15 @@ func (d *dir) Set(s string) error {
} }
var ( var (
out = flag.String("o", "", "file to write zip file to") out = flag.String("o", "", "file to write zip file to")
manifest = flag.String("m", "", "input jar manifest file name") manifest = flag.String("m", "", "input jar manifest file name")
directories = flag.Bool("d", false, "include directories in zip") directories = flag.Bool("d", false, "include directories in zip")
rootPrefix = flag.String("P", "", "path prefix within the zip at which to place files") 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") 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") parallelJobs = flag.Int("j", runtime.NumCPU(), "number of parallel threads to use")
compLevel = flag.Int("L", 5, "deflate compression level (0-9)") 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'") 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 fArgs zip.FileArgs
nonDeflatedFiles = make(uniqueSet) nonDeflatedFiles = make(uniqueSet)
@ -163,6 +164,7 @@ func main() {
ManifestSourcePath: *manifest, ManifestSourcePath: *manifest,
NumParallelJobs: *parallelJobs, NumParallelJobs: *parallelJobs,
NonDeflatedFiles: nonDeflatedFiles, NonDeflatedFiles: nonDeflatedFiles,
WriteIfChanged: *writeIfChanged,
}) })
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err.Error()) fmt.Fprintln(os.Stderr, err.Error())

View file

@ -32,6 +32,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/google/blueprint/pathtools"
"android/soong/jar" "android/soong/jar"
"android/soong/third_party/zip" "android/soong/third_party/zip"
) )
@ -127,6 +129,7 @@ type ZipArgs struct {
ManifestSourcePath string ManifestSourcePath string
NumParallelJobs int NumParallelJobs int
NonDeflatedFiles map[string]bool NonDeflatedFiles map[string]bool
WriteIfChanged bool
} }
func Run(args ZipArgs) (err error) { 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 { func fillPathPairs(prefix, rel, src string, pathMappings *[]pathMapping, nonDeflatedFiles map[string]bool) error {
@ -226,19 +259,7 @@ type readerSeekerCloser interface {
io.Seeker io.Seeker
} }
func (z *ZipWriter) write(out string, pathMappings []pathMapping, manifest string, emulateJar bool, parallelJobs int) error { func (z *ZipWriter) write(f io.Writer, 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)
}
}()
z.errors = make(chan error) z.errors = make(chan error)
defer close(z.errors) defer close(z.errors)
@ -324,6 +345,7 @@ func (z *ZipWriter) write(out string, pathMappings []pathMapping, manifest strin
case op := <-writeOpChan: case op := <-writeOpChan:
currentWriteOpChan = nil currentWriteOpChan = nil
var err error
if op.fh.Method == zip.Deflate { if op.fh.Method == zip.Deflate {
currentWriter, err = zipw.CreateCompressedHeader(op.fh) currentWriter, err = zipw.CreateCompressedHeader(op.fh)
} else { } else {
@ -356,21 +378,21 @@ func (z *ZipWriter) write(out string, pathMappings []pathMapping, manifest strin
currentReader = futureReader currentReader = futureReader
case reader := <-currentReader: case reader := <-currentReader:
_, err = io.Copy(currentWriter, reader) _, err := io.Copy(currentWriter, reader)
if err != nil { if err != nil {
return err return err
} }
currentReader = nil currentReader = nil
case err = <-z.errors: case err := <-z.errors:
return err return err
} }
} }
// One last chance to catch an error // One last chance to catch an error
select { select {
case err = <-z.errors: case err := <-z.errors:
return err return err
default: default:
zipw.Close() zipw.Close()