Support moving sources in srcjars in soong_zip

Add a -srcjar argument to soong_zip that causes it to read the
package statement of each .java file and use that to place the
source file at a path that matches the package.

Test: jar_test.go, zip_test.go
Change-Id: I36017e42445ba3b0a82a10a8d81e8ac0cca096f2
diff --git a/zip/zip_test.go b/zip/zip_test.go
index 93c5f3d..84317d1 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -40,14 +40,15 @@
 )
 
 var mockFs = pathtools.MockFs(map[string][]byte{
-	"a/a/a":            fileA,
-	"a/a/b":            fileB,
-	"a/a/c -> ../../c": nil,
-	"a/a/d -> b":       nil,
-	"c":                fileC,
-	"l":                []byte("a/a/a\na/a/b\nc\n"),
-	"l2":               []byte("missing\n"),
-	"manifest.txt":     fileCustomManifest,
+	"a/a/a":               fileA,
+	"a/a/b":               fileB,
+	"a/a/c -> ../../c":    nil,
+	"dangling -> missing": nil,
+	"a/a/d -> b":          nil,
+	"c":                   fileC,
+	"l":                   []byte("a/a/a\na/a/b\nc\n"),
+	"l2":                  []byte("missing\n"),
+	"manifest.txt":        fileCustomManifest,
 })
 
 func fh(name string, contents []byte, method uint16) zip.FileHeader {
@@ -210,6 +211,17 @@
 			},
 		},
 		{
+			name: "dangling symlinks",
+			args: fileArgsBuilder().
+				File("dangling"),
+			compressionLevel: 9,
+			storeSymlinks:    true,
+
+			files: []zip.FileHeader{
+				fhLink("dangling", "missing"),
+			},
+		},
+		{
 			name: "list",
 			args: fileArgsBuilder().
 				List("l"),
@@ -554,3 +566,70 @@
 		})
 	}
 }
+
+func TestSrcJar(t *testing.T) {
+	mockFs := pathtools.MockFs(map[string][]byte{
+		"wrong_package.java":       []byte("package foo;"),
+		"foo/correct_package.java": []byte("package foo;"),
+		"src/no_package.java":      nil,
+		"src2/parse_error.java":    []byte("error"),
+	})
+
+	want := []string{
+		"foo/",
+		"foo/wrong_package.java",
+		"foo/correct_package.java",
+		"no_package.java",
+		"src2/",
+		"src2/parse_error.java",
+	}
+
+	args := ZipArgs{}
+	args.FileArgs = NewFileArgsBuilder().File("**/*.java").FileArgs()
+
+	args.SrcJar = true
+	args.AddDirectoryEntriesToZip = true
+	args.Filesystem = mockFs
+	args.Stderr = &bytes.Buffer{}
+
+	buf := &bytes.Buffer{}
+	err := ZipTo(args, buf)
+	if err != nil {
+		t.Fatalf("got error %v", err)
+	}
+
+	br := bytes.NewReader(buf.Bytes())
+	zr, err := zip.NewReader(br, int64(br.Len()))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var got []string
+	for _, f := range zr.File {
+		r, err := f.Open()
+		if err != nil {
+			t.Fatalf("error when opening %s: %s", f.Name, err)
+		}
+
+		crc := crc32.NewIEEE()
+		len, err := io.Copy(crc, r)
+		r.Close()
+		if err != nil {
+			t.Fatalf("error when reading %s: %s", f.Name, err)
+		}
+
+		if uint64(len) != f.UncompressedSize64 {
+			t.Errorf("incorrect length for %s, want %d got %d", f.Name, f.UncompressedSize64, len)
+		}
+
+		if crc.Sum32() != f.CRC32 {
+			t.Errorf("incorrect crc for %s, want %x got %x", f.Name, f.CRC32, crc)
+		}
+
+		got = append(got, f.Name)
+	}
+
+	if !reflect.DeepEqual(want, got) {
+		t.Errorf("want files %q, got %q", want, got)
+	}
+}