Merge changes I5059a1e3,I5a06a893
am: fff8ad2f35
Change-Id: If2bde9159092b2b2dfcb1cc03885781555875db0
This commit is contained in:
commit
7b38d380bd
|
@ -18,6 +18,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/blueprint"
|
"github.com/google/blueprint"
|
||||||
|
@ -380,6 +381,38 @@ func (p Paths) FilterOutByExt(ext string) Paths {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DirectorySortedPaths is a slice of paths that are sorted such that all files in a directory
|
||||||
|
// (including subdirectories) are in a contiguous subslice of the list, and can be found in
|
||||||
|
// O(log(N)) time using a binary search on the directory prefix.
|
||||||
|
type DirectorySortedPaths Paths
|
||||||
|
|
||||||
|
func PathsToDirectorySortedPaths(paths Paths) DirectorySortedPaths {
|
||||||
|
ret := append(DirectorySortedPaths(nil), paths...)
|
||||||
|
sort.Slice(ret, func(i, j int) bool {
|
||||||
|
return ret[i].String() < ret[j].String()
|
||||||
|
})
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathsInDirectory returns a subslice of the DirectorySortedPaths as a Paths that contains all entries
|
||||||
|
// that are in the specified directory and its subdirectories.
|
||||||
|
func (p DirectorySortedPaths) PathsInDirectory(dir string) Paths {
|
||||||
|
prefix := filepath.Clean(dir) + "/"
|
||||||
|
start := sort.Search(len(p), func(i int) bool {
|
||||||
|
return prefix < p[i].String()
|
||||||
|
})
|
||||||
|
|
||||||
|
ret := p[start:]
|
||||||
|
|
||||||
|
end := sort.Search(len(ret), func(i int) bool {
|
||||||
|
return !strings.HasPrefix(ret[i].String(), prefix)
|
||||||
|
})
|
||||||
|
|
||||||
|
ret = ret[:end]
|
||||||
|
|
||||||
|
return Paths(ret)
|
||||||
|
}
|
||||||
|
|
||||||
// WritablePaths is a slice of WritablePaths, used for multiple outputs.
|
// WritablePaths is a slice of WritablePaths, used for multiple outputs.
|
||||||
type WritablePaths []WritablePath
|
type WritablePaths []WritablePath
|
||||||
|
|
||||||
|
|
|
@ -340,3 +340,75 @@ func TestPathForModuleInstall(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDirectorySortedPaths(t *testing.T) {
|
||||||
|
makePaths := func() Paths {
|
||||||
|
return Paths{
|
||||||
|
PathForTesting("a.txt"),
|
||||||
|
PathForTesting("a/txt"),
|
||||||
|
PathForTesting("a/b/c"),
|
||||||
|
PathForTesting("a/b/d"),
|
||||||
|
PathForTesting("b"),
|
||||||
|
PathForTesting("b/b.txt"),
|
||||||
|
PathForTesting("a/a.txt"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []string{
|
||||||
|
"a.txt",
|
||||||
|
"a/a.txt",
|
||||||
|
"a/b/c",
|
||||||
|
"a/b/d",
|
||||||
|
"a/txt",
|
||||||
|
"b",
|
||||||
|
"b/b.txt",
|
||||||
|
}
|
||||||
|
|
||||||
|
paths := makePaths()
|
||||||
|
reversePaths := make(Paths, len(paths))
|
||||||
|
for i, v := range paths {
|
||||||
|
reversePaths[len(paths)-i-1] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
sortedPaths := PathsToDirectorySortedPaths(paths)
|
||||||
|
reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
|
||||||
|
t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
|
||||||
|
t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedA := []string{
|
||||||
|
"a/a.txt",
|
||||||
|
"a/b/c",
|
||||||
|
"a/b/d",
|
||||||
|
"a/txt",
|
||||||
|
}
|
||||||
|
|
||||||
|
inA := sortedPaths.PathsInDirectory("a")
|
||||||
|
if !reflect.DeepEqual(inA.Strings(), expectedA) {
|
||||||
|
t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedA_B := []string{
|
||||||
|
"a/b/c",
|
||||||
|
"a/b/d",
|
||||||
|
}
|
||||||
|
|
||||||
|
inA_B := sortedPaths.PathsInDirectory("a/b")
|
||||||
|
if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
|
||||||
|
t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedB := []string{
|
||||||
|
"b/b.txt",
|
||||||
|
}
|
||||||
|
|
||||||
|
inB := sortedPaths.PathsInDirectory("b")
|
||||||
|
if !reflect.DeepEqual(inB.Strings(), expectedB) {
|
||||||
|
t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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: [
|
||||||
|
|
|
@ -128,6 +128,7 @@ var (
|
||||||
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())
|
||||||
|
|
56
zip/zip.go
56
zip/zip.go
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue