Merge "Allow duplicate files inputs in soong_zip"
diff --git a/zip/zip.go b/zip/zip.go
index ae379f5..955fe68 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -201,6 +201,16 @@
 	return fmt.Sprintf("path %q is outside relative root %q", x.Path, x.RelativeRoot)
 }
 
+type ConflictingFileError struct {
+	Dest string
+	Prev string
+	Src  string
+}
+
+func (x ConflictingFileError) Error() string {
+	return fmt.Sprintf("destination %q has two files %q and %q", x.Dest, x.Prev, x.Src)
+}
+
 type ZipWriter struct {
 	time         time.Time
 	createdFiles map[string]string
@@ -605,13 +615,24 @@
 		if prev, exists := z.createdDirs[dest]; exists {
 			return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
 		}
+
+		return nil
+	}
+
+	checkDuplicateFiles := func(dest, src string) (bool, error) {
 		if prev, exists := z.createdFiles[dest]; exists {
-			return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
+			if prev != src {
+				return true, ConflictingFileError{
+					Dest: dest,
+					Prev: prev,
+					Src:  src,
+				}
+			}
+			return true, nil
 		}
 
 		z.createdFiles[dest] = src
-
-		return nil
+		return false, nil
 	}
 
 	if s.IsDir() {
@@ -625,6 +646,14 @@
 			return err
 		}
 
+		duplicate, err := checkDuplicateFiles(dest, src)
+		if err != nil {
+			return err
+		}
+		if duplicate {
+			return nil
+		}
+
 		return z.writeSymlink(dest, src)
 	} else if s.Mode().IsRegular() {
 		r, err := z.fs.Open(src)
@@ -667,6 +696,14 @@
 			return err
 		}
 
+		duplicate, err := checkDuplicateFiles(dest, src)
+		if err != nil {
+			return err
+		}
+		if duplicate {
+			return nil
+		}
+
 		return z.writeFileContents(header, r)
 	} else {
 		return fmt.Errorf("%s is not a file, directory, or symlink", src)
@@ -678,7 +715,14 @@
 		return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
 	}
 	if prev, exists := z.createdFiles[dest]; exists {
-		return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
+		if prev != src {
+			return ConflictingFileError{
+				Dest: dest,
+				Prev: prev,
+				Src:  src,
+			}
+		}
+		return nil
 	}
 
 	if err := z.writeDirectory(filepath.Dir(dest), src, true); err != nil {
diff --git a/zip/zip_test.go b/zip/zip_test.go
index 79cc0b4..c4832dc 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -46,6 +46,7 @@
 	"dangling -> missing": nil,
 	"a/a/d -> b":          nil,
 	"c":                   fileC,
+	"d/a/a":               nil,
 	"l_nl":                []byte("a/a/a\na/a/b\nc\n\\[\n"),
 	"l_sp":                []byte("a/a/a a/a/b c \\["),
 	"l2":                  []byte("missing\n"),
@@ -400,6 +401,17 @@
 				fh("a/a/b", fileB, zip.Deflate),
 			},
 		},
+		{
+			name: "duplicate sources",
+			args: fileArgsBuilder().
+				File("a/a/a").
+				File("a/a/a"),
+			compressionLevel: 9,
+
+			files: []zip.FileHeader{
+				fh("a/a/a", fileA, zip.Deflate),
+			},
+		},
 
 		// errors
 		{
@@ -427,6 +439,15 @@
 				File("a/a/a"),
 			err: IncorrectRelativeRootError{},
 		},
+		{
+			name: "error conflicting file",
+			args: fileArgsBuilder().
+				SourcePrefixToStrip("a").
+				File("a/a/a").
+				SourcePrefixToStrip("d").
+				File("d/a/a"),
+			err: ConflictingFileError{},
+		},
 	}
 
 	for _, test := range testCases {
@@ -454,13 +475,17 @@
 				t.Fatalf("want error %v, got %v", test.err, err)
 			} else if test.err != nil {
 				if os.IsNotExist(test.err) {
-					if !os.IsNotExist(test.err) {
+					if !os.IsNotExist(err) {
 						t.Fatalf("want error %v, got %v", test.err, err)
 					}
 				} else if _, wantRelativeRootErr := test.err.(IncorrectRelativeRootError); wantRelativeRootErr {
 					if _, gotRelativeRootErr := err.(IncorrectRelativeRootError); !gotRelativeRootErr {
 						t.Fatalf("want error %v, got %v", test.err, err)
 					}
+				} else if _, wantConflictingFileError := test.err.(ConflictingFileError); wantConflictingFileError {
+					if _, gotConflictingFileError := err.(ConflictingFileError); !gotConflictingFileError {
+						t.Fatalf("want error %v, got %v", test.err, err)
+					}
 				} else {
 					t.Fatalf("want error %v, got %v", test.err, err)
 				}