From c0efd1db13e383a0b3ac96e3718a006dea0e1cfd Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 3 Jul 2020 11:56:24 -0700 Subject: [PATCH] Build a zip of transitive lint reports for apps Add a rule to build a zip containing the lint reports from transitive dependencies for apps, and pass it to Make. Bug: 153485543 Test: m TARGET_BUILD_APPS=Gallery2 lint-check Change-Id: I523c09016251377ff89d76084769be7401b95425 --- android/androidmk.go | 19 ++++++++ android/paths.go | 7 ++- java/androidmk.go | 8 ++++ java/app.go | 1 + java/lint.go | 107 ++++++++++++++++++++++++++++++++----------- 5 files changed, 114 insertions(+), 28 deletions(-) diff --git a/android/androidmk.go b/android/androidmk.go index 045cb59b3..dfc68c437 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -107,6 +107,25 @@ func (a *AndroidMkEntries) SetPath(name string, path Path) { a.EntryMap[name] = []string{path.String()} } +func (a *AndroidMkEntries) SetOptionalPath(name string, path OptionalPath) { + if path.Valid() { + a.SetPath(name, path.Path()) + } +} + +func (a *AndroidMkEntries) AddPath(name string, path Path) { + if _, ok := a.EntryMap[name]; !ok { + a.entryOrder = append(a.entryOrder, name) + } + a.EntryMap[name] = append(a.EntryMap[name], path.String()) +} + +func (a *AndroidMkEntries) AddOptionalPath(name string, path OptionalPath) { + if path.Valid() { + a.AddPath(name, path.Path()) + } +} + func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) { if flag { if _, ok := a.EntryMap[name]; !ok { diff --git a/android/paths.go b/android/paths.go index 066baf2d9..eef71b763 100644 --- a/android/paths.go +++ b/android/paths.go @@ -484,6 +484,10 @@ func (p Paths) Strings() []string { return ret } +func CopyOfPaths(paths Paths) Paths { + return append(Paths(nil), paths...) +} + // FirstUniquePaths returns all unique elements of a Paths, keeping the first copy of each. It // modifies the Paths slice contents in place, and returns a subslice of the original slice. func FirstUniquePaths(list Paths) Paths { @@ -494,7 +498,8 @@ func FirstUniquePaths(list Paths) Paths { return firstUniquePathsList(list) } -// SortedUniquePaths returns what its name says +// SortedUniquePaths returns all unique elements of a Paths in sorted order. It modifies the +// Paths slice contents in place, and returns a subslice of the original slice. func SortedUniquePaths(list Paths) Paths { unique := FirstUniquePaths(list) sort.Slice(unique, func(i, j int) bool { diff --git a/java/androidmk.go b/java/androidmk.go index 618e15d9a..99dd82304 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -131,6 +131,10 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary) } entries.SetString("LOCAL_MODULE_STEM", library.Stem()) + + entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", library.linter.outputs.transitiveHTMLZip) + entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", library.linter.outputs.transitiveTextZip) + entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", library.linter.outputs.transitiveXMLZip) }, }, } @@ -383,6 +387,10 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { install := app.onDeviceDir + "/" + extra.Base() entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", extra.String()+":"+install) } + + entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", app.linter.outputs.transitiveHTMLZip) + entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", app.linter.outputs.transitiveTextZip) + entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", app.linter.outputs.transitiveXMLZip) }, }, ExtraFooters: []android.AndroidMkExtraFootersFunc{ diff --git a/java/app.go b/java/app.go index 98bce9471..e6e0e1a8b 100755 --- a/java/app.go +++ b/java/app.go @@ -752,6 +752,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.linter.mergedManifest = a.aapt.mergedManifestFile a.linter.manifest = a.aapt.manifestPath a.linter.resources = a.aapt.resourceFiles + a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps() dexJarFile := a.dexBuildActions(ctx) diff --git a/java/lint.go b/java/lint.go index 6fbef18c7..20a7dc49f 100644 --- a/java/lint.go +++ b/java/lint.go @@ -67,12 +67,32 @@ type linter struct { kotlinLanguageLevel string outputs lintOutputs properties LintProperties + + buildModuleReportZip bool } type lintOutputs struct { html android.ModuleOutPath text android.ModuleOutPath xml android.ModuleOutPath + + transitiveHTML *android.DepSet + transitiveText *android.DepSet + transitiveXML *android.DepSet + + transitiveHTMLZip android.OptionalPath + transitiveTextZip android.OptionalPath + transitiveXMLZip android.OptionalPath +} + +type lintOutputIntf interface { + lintOutputs() *lintOutputs +} + +var _ lintOutputIntf = (*linter)(nil) + +func (l *linter) lintOutputs() *lintOutputs { + return &l.outputs } func (l *linter) enabled() bool { @@ -213,9 +233,22 @@ func (l *linter) lint(ctx android.ModuleContext) { projectXML, lintXML, cacheDir, homeDir, deps := l.writeLintProjectXML(ctx, rule) - l.outputs.html = android.PathForModuleOut(ctx, "lint-report.html") - l.outputs.text = android.PathForModuleOut(ctx, "lint-report.txt") - l.outputs.xml = android.PathForModuleOut(ctx, "lint-report.xml") + html := android.PathForModuleOut(ctx, "lint-report.html") + text := android.PathForModuleOut(ctx, "lint-report.txt") + xml := android.PathForModuleOut(ctx, "lint-report.xml") + + htmlDeps := android.NewDepSetBuilder(android.POSTORDER).Direct(html) + textDeps := android.NewDepSetBuilder(android.POSTORDER).Direct(text) + xmlDeps := android.NewDepSetBuilder(android.POSTORDER).Direct(xml) + + ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) { + if depLint, ok := dep.(lintOutputIntf); ok { + depLintOutputs := depLint.lintOutputs() + htmlDeps.Transitive(depLintOutputs.transitiveHTML) + textDeps.Transitive(depLintOutputs.transitiveText) + xmlDeps.Transitive(depLintOutputs.transitiveXML) + } + }) rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String()) rule.Command().Text("mkdir -p").Flag(cacheDir.String()).Flag(homeDir.String()) @@ -240,9 +273,9 @@ func (l *linter) lint(ctx android.ModuleContext) { Flag("--quiet"). FlagWithInput("--project ", projectXML). FlagWithInput("--config ", lintXML). - FlagWithOutput("--html ", l.outputs.html). - FlagWithOutput("--text ", l.outputs.text). - FlagWithOutput("--xml ", l.outputs.xml). + FlagWithOutput("--html ", html). + FlagWithOutput("--text ", text). + FlagWithOutput("--xml ", xml). FlagWithArg("--compile-sdk-version ", l.compileSdkVersion). FlagWithArg("--java-language-level ", l.javaLanguageLevel). FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel). @@ -250,23 +283,37 @@ func (l *linter) lint(ctx android.ModuleContext) { Flag("--exitcode"). Flags(l.properties.Lint.Flags). Implicits(deps). - Text("|| (").Text("cat").Input(l.outputs.text).Text("; exit 7)"). + Text("|| (").Text("cat").Input(text).Text("; exit 7)"). Text(")") rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String()) rule.Build(pctx, ctx, "lint", "lint") -} -func (l *linter) lintOutputs() *lintOutputs { - return &l.outputs -} + l.outputs = lintOutputs{ + html: html, + text: text, + xml: xml, -type lintOutputIntf interface { - lintOutputs() *lintOutputs -} + transitiveHTML: htmlDeps.Build(), + transitiveText: textDeps.Build(), + transitiveXML: xmlDeps.Build(), + } -var _ lintOutputIntf = (*linter)(nil) + if l.buildModuleReportZip { + htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip") + l.outputs.transitiveHTMLZip = android.OptionalPathForPath(htmlZip) + lintZip(ctx, l.outputs.transitiveHTML.ToSortedList(), htmlZip) + + textZip := android.PathForModuleOut(ctx, "lint-report-text.zip") + l.outputs.transitiveTextZip = android.OptionalPathForPath(textZip) + lintZip(ctx, l.outputs.transitiveText.ToSortedList(), textZip) + + xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip") + l.outputs.transitiveXMLZip = android.OptionalPathForPath(xmlZip) + lintZip(ctx, l.outputs.transitiveXML.ToSortedList(), xmlZip) + } +} type lintSingleton struct { htmlZip android.WritablePath @@ -356,18 +403,7 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { paths = append(paths, get(output)) } - sort.Slice(paths, func(i, j int) bool { - return paths[i].String() < paths[j].String() - }) - - rule := android.NewRuleBuilder() - - rule.Command().BuiltTool(ctx, "soong_zip"). - FlagWithOutput("-o ", outputPath). - FlagWithArg("-C ", android.PathForIntermediates(ctx).String()). - FlagWithRspFileInputList("-l ", paths) - - rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base()) + lintZip(ctx, paths, outputPath) } l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip") @@ -394,3 +430,20 @@ func init() { android.RegisterSingletonType("lint", func() android.Singleton { return &lintSingleton{} }) } + +func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) { + paths = android.SortedUniquePaths(android.CopyOfPaths(paths)) + + sort.Slice(paths, func(i, j int) bool { + return paths[i].String() < paths[j].String() + }) + + rule := android.NewRuleBuilder() + + rule.Command().BuiltTool(ctx, "soong_zip"). + FlagWithOutput("-o ", outputPath). + FlagWithArg("-C ", android.PathForIntermediates(ctx).String()). + FlagWithRspFileInputList("-l ", paths) + + rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base()) +}