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
This commit is contained in:
Colin Cross 2020-07-03 11:56:24 -07:00
parent 9e44e21e91
commit c0efd1db13
5 changed files with 114 additions and 28 deletions

View File

@ -107,6 +107,25 @@ func (a *AndroidMkEntries) SetPath(name string, path Path) {
a.EntryMap[name] = []string{path.String()} 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) { func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) {
if flag { if flag {
if _, ok := a.EntryMap[name]; !ok { if _, ok := a.EntryMap[name]; !ok {

View File

@ -484,6 +484,10 @@ func (p Paths) Strings() []string {
return ret 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 // 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. // modifies the Paths slice contents in place, and returns a subslice of the original slice.
func FirstUniquePaths(list Paths) Paths { func FirstUniquePaths(list Paths) Paths {
@ -494,7 +498,8 @@ func FirstUniquePaths(list Paths) Paths {
return firstUniquePathsList(list) 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 { func SortedUniquePaths(list Paths) Paths {
unique := FirstUniquePaths(list) unique := FirstUniquePaths(list)
sort.Slice(unique, func(i, j int) bool { sort.Slice(unique, func(i, j int) bool {

View File

@ -131,6 +131,10 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary) entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary)
} }
entries.SetString("LOCAL_MODULE_STEM", library.Stem()) 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() install := app.onDeviceDir + "/" + extra.Base()
entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", extra.String()+":"+install) 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{ ExtraFooters: []android.AndroidMkExtraFootersFunc{

View File

@ -752,6 +752,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
a.linter.mergedManifest = a.aapt.mergedManifestFile a.linter.mergedManifest = a.aapt.mergedManifestFile
a.linter.manifest = a.aapt.manifestPath a.linter.manifest = a.aapt.manifestPath
a.linter.resources = a.aapt.resourceFiles a.linter.resources = a.aapt.resourceFiles
a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps()
dexJarFile := a.dexBuildActions(ctx) dexJarFile := a.dexBuildActions(ctx)

View File

@ -67,12 +67,32 @@ type linter struct {
kotlinLanguageLevel string kotlinLanguageLevel string
outputs lintOutputs outputs lintOutputs
properties LintProperties properties LintProperties
buildModuleReportZip bool
} }
type lintOutputs struct { type lintOutputs struct {
html android.ModuleOutPath html android.ModuleOutPath
text android.ModuleOutPath text android.ModuleOutPath
xml 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 { 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) projectXML, lintXML, cacheDir, homeDir, deps := l.writeLintProjectXML(ctx, rule)
l.outputs.html = android.PathForModuleOut(ctx, "lint-report.html") html := android.PathForModuleOut(ctx, "lint-report.html")
l.outputs.text = android.PathForModuleOut(ctx, "lint-report.txt") text := android.PathForModuleOut(ctx, "lint-report.txt")
l.outputs.xml = android.PathForModuleOut(ctx, "lint-report.xml") 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("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
rule.Command().Text("mkdir -p").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"). Flag("--quiet").
FlagWithInput("--project ", projectXML). FlagWithInput("--project ", projectXML).
FlagWithInput("--config ", lintXML). FlagWithInput("--config ", lintXML).
FlagWithOutput("--html ", l.outputs.html). FlagWithOutput("--html ", html).
FlagWithOutput("--text ", l.outputs.text). FlagWithOutput("--text ", text).
FlagWithOutput("--xml ", l.outputs.xml). FlagWithOutput("--xml ", xml).
FlagWithArg("--compile-sdk-version ", l.compileSdkVersion). FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
FlagWithArg("--java-language-level ", l.javaLanguageLevel). FlagWithArg("--java-language-level ", l.javaLanguageLevel).
FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel). FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
@ -250,23 +283,37 @@ func (l *linter) lint(ctx android.ModuleContext) {
Flag("--exitcode"). Flag("--exitcode").
Flags(l.properties.Lint.Flags). Flags(l.properties.Lint.Flags).
Implicits(deps). Implicits(deps).
Text("|| (").Text("cat").Input(l.outputs.text).Text("; exit 7)"). Text("|| (").Text("cat").Input(text).Text("; exit 7)").
Text(")") Text(")")
rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String()) rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
rule.Build(pctx, ctx, "lint", "lint") rule.Build(pctx, ctx, "lint", "lint")
}
func (l *linter) lintOutputs() *lintOutputs { l.outputs = lintOutputs{
return &l.outputs html: html,
} text: text,
xml: xml,
type lintOutputIntf interface { transitiveHTML: htmlDeps.Build(),
lintOutputs() *lintOutputs 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 { type lintSingleton struct {
htmlZip android.WritablePath htmlZip android.WritablePath
@ -356,18 +403,7 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
paths = append(paths, get(output)) paths = append(paths, get(output))
} }
sort.Slice(paths, func(i, j int) bool { lintZip(ctx, paths, outputPath)
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())
} }
l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip") l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
@ -394,3 +430,20 @@ func init() {
android.RegisterSingletonType("lint", android.RegisterSingletonType("lint",
func() android.Singleton { return &lintSingleton{} }) 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())
}