Track dependencies when reading notice files

Track which files are read by the notice file indexer and add a flag
to textnotice and htmlnotice to support writing them out.

Bug: 207445310
Test: textnotice_test
Test: htmlnotice_test
Change-Id: Ib74706b8a87a5ed9268a0fe37982ecf89f4e227d
diff --git a/tools/compliance/Android.bp b/tools/compliance/Android.bp
index 7037670..3a12738 100644
--- a/tools/compliance/Android.bp
+++ b/tools/compliance/Android.bp
@@ -55,7 +55,10 @@
 blueprint_go_binary {
     name: "htmlnotice",
     srcs: ["cmd/htmlnotice/htmlnotice.go"],
-    deps: ["compliance-module"],
+    deps: [
+        "compliance-module",
+        "blueprint-deptools",
+    ],
     testSrcs: ["cmd/htmlnotice/htmlnotice_test.go"],
 }
 
@@ -69,7 +72,10 @@
 blueprint_go_binary {
     name: "textnotice",
     srcs: ["cmd/textnotice/textnotice.go"],
-    deps: ["compliance-module"],
+    deps: [
+        "compliance-module",
+        "blueprint-deptools",
+    ],
     testSrcs: ["cmd/textnotice/textnotice_test.go"],
 }
 
diff --git a/tools/compliance/cmd/htmlnotice/htmlnotice.go b/tools/compliance/cmd/htmlnotice/htmlnotice.go
index 2f59ee0..1f55546 100644
--- a/tools/compliance/cmd/htmlnotice/htmlnotice.go
+++ b/tools/compliance/cmd/htmlnotice/htmlnotice.go
@@ -26,10 +26,13 @@
 	"strings"
 
 	"android/soong/tools/compliance"
+
+	"github.com/google/blueprint/deptools"
 )
 
 var (
 	outputFile  = flag.String("o", "-", "Where to write the NOTICE text file. (default stdout)")
+	depsFile    = flag.String("d", "", "Where to write the deps file")
 	includeTOC  = flag.Bool("toc", true, "Whether to include a table of contents.")
 	stripPrefix = flag.String("strip_prefix", "", "Prefix to remove from paths. i.e. path to root")
 	title       = flag.String("title", "", "The title of the notice file.")
@@ -45,6 +48,7 @@
 	includeTOC  bool
 	stripPrefix string
 	title       string
+	deps        *[]string
 }
 
 func init() {
@@ -95,7 +99,9 @@
 		ofile = &bytes.Buffer{}
 	}
 
-	ctx := &context{ofile, os.Stderr, os.DirFS("."), *includeTOC, *stripPrefix, *title}
+	var deps []string
+
+	ctx := &context{ofile, os.Stderr, os.DirFS("."), *includeTOC, *stripPrefix, *title, &deps}
 
 	err := htmlNotice(ctx, flag.Args()...)
 	if err != nil {
@@ -112,6 +118,13 @@
 			os.Exit(1)
 		}
 	}
+	if *depsFile != "" {
+		err := deptools.WriteDepFile(*depsFile, *outputFile, deps)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "could not write deps to %q: %s\n", *depsFile, err)
+			os.Exit(1)
+		}
+	}
 	os.Exit(0)
 }
 
@@ -213,5 +226,7 @@
 	}
 	fmt.Fprintln(ctx.stdout, "</body></html>")
 
+	*ctx.deps = ni.InputNoticeFiles()
+
 	return nil
 }
diff --git a/tools/compliance/cmd/htmlnotice/htmlnotice_test.go b/tools/compliance/cmd/htmlnotice/htmlnotice_test.go
index fc935c1..4e9c43c 100644
--- a/tools/compliance/cmd/htmlnotice/htmlnotice_test.go
+++ b/tools/compliance/cmd/htmlnotice/htmlnotice_test.go
@@ -20,6 +20,7 @@
 	"fmt"
 	"html"
 	"os"
+	"reflect"
 	"regexp"
 	"strings"
 	"testing"
@@ -51,13 +52,14 @@
 
 func Test(t *testing.T) {
 	tests := []struct {
-		condition   string
-		name        string
-		roots       []string
-		includeTOC  bool
-		stripPrefix string
-		title       string
-		expectedOut []matcher
+		condition    string
+		name         string
+		roots        []string
+		includeTOC   bool
+		stripPrefix  string
+		title        string
+		expectedOut  []matcher
+		expectedDeps []string
 	}{
 		{
 			condition: "firstparty",
@@ -73,6 +75,7 @@
 				usedBy{"highest.apex/lib/libb.so"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition:  "firstparty",
@@ -100,6 +103,7 @@
 				usedBy{"highest.apex/lib/libb.so"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "firstparty",
@@ -117,6 +121,7 @@
 				usedBy{"highest.apex/lib/libb.so"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition:  "firstparty",
@@ -146,6 +151,7 @@
 				usedBy{"highest.apex/lib/libb.so"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "firstparty",
@@ -161,6 +167,7 @@
 				usedBy{"container.zip/libb.so"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "firstparty",
@@ -172,6 +179,7 @@
 				usedBy{"application"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "firstparty",
@@ -183,6 +191,7 @@
 				usedBy{"bin/bin1"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "firstparty",
@@ -194,6 +203,7 @@
 				usedBy{"lib/libd.so"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "notice",
@@ -215,6 +225,10 @@
 				usedBy{"highest.apex/bin/bin1"},
 				notice{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/notice/NOTICE_LICENSE",
+			},
 		},
 		{
 			condition: "notice",
@@ -236,6 +250,10 @@
 				usedBy{"container.zip/bin1"},
 				notice{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/notice/NOTICE_LICENSE",
+			},
 		},
 		{
 			condition: "notice",
@@ -251,6 +269,10 @@
 				usedBy{"application"},
 				notice{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/notice/NOTICE_LICENSE",
+			},
 		},
 		{
 			condition: "notice",
@@ -268,6 +290,10 @@
 				usedBy{"bin/bin1"},
 				notice{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/notice/NOTICE_LICENSE",
+			},
 		},
 		{
 			condition: "notice",
@@ -279,6 +305,7 @@
 				usedBy{"lib/libd.so"},
 				notice{},
 			},
+			expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
 		},
 		{
 			condition: "reciprocal",
@@ -300,6 +327,10 @@
 				usedBy{"highest.apex/bin/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+			},
 		},
 		{
 			condition: "reciprocal",
@@ -321,6 +352,10 @@
 				usedBy{"container.zip/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+			},
 		},
 		{
 			condition: "reciprocal",
@@ -336,6 +371,10 @@
 				usedBy{"application"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+			},
 		},
 		{
 			condition: "reciprocal",
@@ -353,6 +392,10 @@
 				usedBy{"bin/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+			},
 		},
 		{
 			condition: "reciprocal",
@@ -364,6 +407,7 @@
 				usedBy{"lib/libd.so"},
 				notice{},
 			},
+			expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
 		},
 		{
 			condition: "restricted",
@@ -389,6 +433,11 @@
 				usedBy{"highest.apex/bin/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "restricted",
@@ -414,6 +463,11 @@
 				usedBy{"container.zip/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "restricted",
@@ -429,6 +483,10 @@
 				usedBy{"application"},
 				restricted{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "restricted",
@@ -448,6 +506,11 @@
 				usedBy{"bin/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "restricted",
@@ -459,6 +522,7 @@
 				usedBy{"lib/libd.so"},
 				notice{},
 			},
+			expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
 		},
 		{
 			condition: "proprietary",
@@ -485,6 +549,11 @@
 				usedBy{"highest.apex/bin/bin1"},
 				proprietary{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/proprietary/PROPRIETARY_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "proprietary",
@@ -511,6 +580,11 @@
 				usedBy{"container.zip/bin1"},
 				proprietary{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/proprietary/PROPRIETARY_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "proprietary",
@@ -526,6 +600,10 @@
 				usedBy{"application"},
 				proprietary{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/proprietary/PROPRIETARY_LICENSE",
+			},
 		},
 		{
 			condition: "proprietary",
@@ -543,6 +621,10 @@
 				usedBy{"bin/bin1"},
 				proprietary{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/proprietary/PROPRIETARY_LICENSE",
+			},
 		},
 		{
 			condition: "proprietary",
@@ -554,6 +636,7 @@
 				usedBy{"lib/libd.so"},
 				notice{},
 			},
+			expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
 		},
 	}
 	for _, tt := range tests {
@@ -566,7 +649,9 @@
 				rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
 			}
 
-			ctx := context{stdout, stderr, os.DirFS("."), tt.includeTOC, tt.stripPrefix, tt.title}
+			var deps []string
+
+			ctx := context{stdout, stderr, os.DirFS("."), tt.includeTOC, tt.stripPrefix, tt.title, &deps}
 
 			err := htmlNotice(&ctx, rootFiles...)
 			if err != nil {
@@ -625,6 +710,15 @@
 			for ; lineno < len(tt.expectedOut); lineno++ {
 				t.Errorf("htmlnotice: missing output line %d: ended early, want %q", lineno+1, tt.expectedOut[lineno].String())
 			}
+
+			t.Logf("got deps: %q", deps)
+
+			t.Logf("want deps: %q", tt.expectedDeps)
+
+			if g, w := deps, tt.expectedDeps; !reflect.DeepEqual(g, w) {
+				t.Errorf("unexpected deps, wanted:\n%s\ngot:\n%s\n",
+					strings.Join(w, "\n"), strings.Join(g, "\n"))
+			}
 		})
 	}
 }
diff --git a/tools/compliance/cmd/textnotice/textnotice.go b/tools/compliance/cmd/textnotice/textnotice.go
index b89aff1..eebb13d 100644
--- a/tools/compliance/cmd/textnotice/textnotice.go
+++ b/tools/compliance/cmd/textnotice/textnotice.go
@@ -25,10 +25,13 @@
 	"strings"
 
 	"android/soong/tools/compliance"
+
+	"github.com/google/blueprint/deptools"
 )
 
 var (
 	outputFile  = flag.String("o", "-", "Where to write the NOTICE text file. (default stdout)")
+	depsFile    = flag.String("d", "", "Where to write the deps file")
 	stripPrefix = flag.String("strip_prefix", "", "Prefix to remove from paths. i.e. path to root")
 
 	failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
@@ -40,6 +43,7 @@
 	stderr      io.Writer
 	rootFS      fs.FS
 	stripPrefix string
+	deps        *[]string
 }
 
 func init() {
@@ -90,7 +94,9 @@
 		ofile = &bytes.Buffer{}
 	}
 
-	ctx := &context{ofile, os.Stderr, os.DirFS("."), *stripPrefix}
+	var deps []string
+
+	ctx := &context{ofile, os.Stderr, os.DirFS("."), *stripPrefix, &deps}
 
 	err := textNotice(ctx, flag.Args()...)
 	if err != nil {
@@ -107,6 +113,13 @@
 			os.Exit(1)
 		}
 	}
+	if *depsFile != "" {
+		err := deptools.WriteDepFile(*depsFile, *outputFile, deps)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "could not write deps to %q: %s\n", *depsFile, err)
+			os.Exit(1)
+		}
+	}
 	os.Exit(0)
 }
 
@@ -150,5 +163,8 @@
 		ctx.stdout.Write(ni.HashText(h))
 		fmt.Fprintln(ctx.stdout)
 	}
+
+	*ctx.deps = ni.InputNoticeFiles()
+
 	return nil
 }
diff --git a/tools/compliance/cmd/textnotice/textnotice_test.go b/tools/compliance/cmd/textnotice/textnotice_test.go
index 7993532..39f711d 100644
--- a/tools/compliance/cmd/textnotice/textnotice_test.go
+++ b/tools/compliance/cmd/textnotice/textnotice_test.go
@@ -19,6 +19,7 @@
 	"bytes"
 	"fmt"
 	"os"
+	"reflect"
 	"regexp"
 	"strings"
 	"testing"
@@ -40,11 +41,12 @@
 
 func Test(t *testing.T) {
 	tests := []struct {
-		condition   string
-		name        string
-		roots       []string
-		stripPrefix string
-		expectedOut []matcher
+		condition    string
+		name         string
+		roots        []string
+		stripPrefix  string
+		expectedOut  []matcher
+		expectedDeps []string
 	}{
 		{
 			condition: "firstparty",
@@ -60,6 +62,7 @@
 				usedBy{"highest.apex/lib/libb.so"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "firstparty",
@@ -75,6 +78,7 @@
 				usedBy{"container.zip/libb.so"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "firstparty",
@@ -86,6 +90,7 @@
 				usedBy{"application"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "firstparty",
@@ -97,6 +102,7 @@
 				usedBy{"bin/bin1"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "firstparty",
@@ -108,6 +114,7 @@
 				usedBy{"lib/libd.so"},
 				firstParty{},
 			},
+			expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
 		},
 		{
 			condition: "notice",
@@ -129,6 +136,10 @@
 				usedBy{"highest.apex/bin/bin1"},
 				notice{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/notice/NOTICE_LICENSE",
+			},
 		},
 		{
 			condition: "notice",
@@ -150,6 +161,10 @@
 				usedBy{"container.zip/bin1"},
 				notice{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/notice/NOTICE_LICENSE",
+			},
 		},
 		{
 			condition: "notice",
@@ -165,6 +180,10 @@
 				usedBy{"application"},
 				notice{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/notice/NOTICE_LICENSE",
+			},
 		},
 		{
 			condition: "notice",
@@ -182,6 +201,10 @@
 				usedBy{"bin/bin1"},
 				notice{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/notice/NOTICE_LICENSE",
+			},
 		},
 		{
 			condition: "notice",
@@ -193,6 +216,7 @@
 				usedBy{"lib/libd.so"},
 				notice{},
 			},
+			expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
 		},
 		{
 			condition: "reciprocal",
@@ -214,6 +238,10 @@
 				usedBy{"highest.apex/bin/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+			},
 		},
 		{
 			condition: "reciprocal",
@@ -235,6 +263,10 @@
 				usedBy{"container.zip/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+			},
 		},
 		{
 			condition: "reciprocal",
@@ -250,6 +282,10 @@
 				usedBy{"application"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+			},
 		},
 		{
 			condition: "reciprocal",
@@ -267,6 +303,10 @@
 				usedBy{"bin/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+			},
 		},
 		{
 			condition: "reciprocal",
@@ -278,6 +318,9 @@
 				usedBy{"lib/libd.so"},
 				notice{},
 			},
+			expectedDeps: []string{
+				"testdata/notice/NOTICE_LICENSE",
+			},
 		},
 		{
 			condition: "restricted",
@@ -303,6 +346,11 @@
 				usedBy{"highest.apex/bin/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "restricted",
@@ -328,6 +376,11 @@
 				usedBy{"container.zip/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "restricted",
@@ -343,6 +396,10 @@
 				usedBy{"application"},
 				restricted{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "restricted",
@@ -362,6 +419,11 @@
 				usedBy{"bin/bin1"},
 				reciprocal{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/reciprocal/RECIPROCAL_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "restricted",
@@ -373,6 +435,7 @@
 				usedBy{"lib/libd.so"},
 				notice{},
 			},
+			expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
 		},
 		{
 			condition: "proprietary",
@@ -399,6 +462,11 @@
 				usedBy{"highest.apex/bin/bin1"},
 				proprietary{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/proprietary/PROPRIETARY_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "proprietary",
@@ -425,6 +493,11 @@
 				usedBy{"container.zip/bin1"},
 				proprietary{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/proprietary/PROPRIETARY_LICENSE",
+				"testdata/restricted/RESTRICTED_LICENSE",
+			},
 		},
 		{
 			condition: "proprietary",
@@ -440,6 +513,10 @@
 				usedBy{"application"},
 				proprietary{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/proprietary/PROPRIETARY_LICENSE",
+			},
 		},
 		{
 			condition: "proprietary",
@@ -457,6 +534,10 @@
 				usedBy{"bin/bin1"},
 				proprietary{},
 			},
+			expectedDeps: []string{
+				"testdata/firstparty/FIRST_PARTY_LICENSE",
+				"testdata/proprietary/PROPRIETARY_LICENSE",
+			},
 		},
 		{
 			condition: "proprietary",
@@ -468,6 +549,7 @@
 				usedBy{"lib/libd.so"},
 				notice{},
 			},
+			expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
 		},
 	}
 	for _, tt := range tests {
@@ -480,7 +562,9 @@
 				rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
 			}
 
-			ctx := context{stdout, stderr, os.DirFS("."), tt.stripPrefix}
+			var deps []string
+
+			ctx := context{stdout, stderr, os.DirFS("."), tt.stripPrefix, &deps}
 
 			err := textNotice(&ctx, rootFiles...)
 			if err != nil {
@@ -512,6 +596,15 @@
 			for ; lineno < len(tt.expectedOut); lineno++ {
 				t.Errorf("textnotice: missing output line %d: ended early, want %q", lineno+1, tt.expectedOut[lineno].String())
 			}
+
+			t.Logf("got deps: %q", deps)
+
+			t.Logf("want deps: %q", tt.expectedDeps)
+
+			if g, w := deps, tt.expectedDeps; !reflect.DeepEqual(g, w) {
+				t.Errorf("unexpected deps, wanted:\n%s\ngot:\n%s\n",
+					strings.Join(w, "\n"), strings.Join(g, "\n"))
+			}
 		})
 	}
 }
diff --git a/tools/compliance/noticeindex.go b/tools/compliance/noticeindex.go
index 58b1c3b..7bebe3d 100644
--- a/tools/compliance/noticeindex.go
+++ b/tools/compliance/noticeindex.go
@@ -62,6 +62,8 @@
 	targetHashes map[*TargetNode]map[hash]struct{}
 	// projectName maps project directory names to project name text.
 	projectName map[string]string
+	// files lists all the files accessed during indexing
+	files []string
 }
 
 // IndexLicenseTexts creates a hashed index of license texts for `lg` and `rs`
@@ -71,14 +73,17 @@
 		rs = ResolveNotices(lg)
 	}
 	ni := &NoticeIndex{
-		lg, rs, ShippedNodes(lg), rootFS,
-		make(map[string]hash),
-		make(map[hash][]byte),
-		make(map[hash]map[string]map[string]struct{}),
-		make(map[string]map[hash]map[string]struct{}),
-		make(map[string]map[hash]struct{}),
-		make(map[*TargetNode]map[hash]struct{}),
-		make(map[string]string),
+		lg:             lg,
+		rs:             rs,
+		shipped:        ShippedNodes(lg),
+		rootFS:         rootFS,
+		hash:           make(map[string]hash),
+		text:           make(map[hash][]byte),
+		hashLibInstall: make(map[hash]map[string]map[string]struct{}),
+		installHashLib: make(map[string]map[hash]map[string]struct{}),
+		libHash:        make(map[string]map[hash]struct{}),
+		targetHashes:   make(map[*TargetNode]map[hash]struct{}),
+		projectName:    make(map[string]string),
 	}
 
 	// index adds all license texts for `tn` to the index.
@@ -208,6 +213,13 @@
 	return c
 }
 
+// InputNoticeFiles returns the list of files that were hashed during IndexLicenseTexts.
+func (ni *NoticeIndex) InputNoticeFiles() []string {
+	files := append([]string(nil), ni.files...)
+	sort.Strings(files)
+	return files
+}
+
 // HashLibs returns the ordered array of library names using the license text
 // hashed as `h`.
 func (ni *NoticeIndex) HashLibs(h hash) []string {
@@ -449,6 +461,8 @@
 		ni.text[hash] = text
 	}
 
+	ni.files = append(ni.files, file)
+
 	return nil
 }