Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f7de5b1 authored by Bob Badour's avatar Bob Badour Committed by Automerger Merge Worker
Browse files

Build notice files from license metadata. am: 43c2dcae

parents 2774891c 43c2dcae
Loading
Loading
Loading
Loading
+14 −85
Original line number Diff line number Diff line
@@ -15,93 +15,9 @@
package android

import (
	"path/filepath"
	"strings"

	"github.com/google/blueprint"
)

func init() {
	pctx.SourcePathVariable("merge_notices", "build/soong/scripts/mergenotice.py")
	pctx.SourcePathVariable("generate_notice", "build/soong/scripts/generate-notice-files.py")

	pctx.HostBinToolVariable("minigzip", "minigzip")
}

type NoticeOutputs struct {
	Merged       OptionalPath
	TxtOutput    OptionalPath
	HtmlOutput   OptionalPath
	HtmlGzOutput OptionalPath
}

var (
	mergeNoticesRule = pctx.AndroidStaticRule("mergeNoticesRule", blueprint.RuleParams{
		Command:     `${merge_notices} --output $out $in`,
		CommandDeps: []string{"${merge_notices}"},
		Description: "merge notice files into $out",
	})

	generateNoticeRule = pctx.AndroidStaticRule("generateNoticeRule", blueprint.RuleParams{
		Command: `rm -rf $$(dirname $txtOut) $$(dirname $htmlOut) $$(dirname $out) && ` +
			`mkdir -p $$(dirname $txtOut) $$(dirname $htmlOut)  $$(dirname $out) && ` +
			`${generate_notice} --text-output $txtOut --html-output $htmlOut -t "$title" -s $inputDir && ` +
			`${minigzip} -c $htmlOut > $out`,
		CommandDeps: []string{"${generate_notice}", "${minigzip}"},
		Description: "produce notice file $out",
	}, "txtOut", "htmlOut", "title", "inputDir")
)

func MergeNotices(ctx ModuleContext, mergedNotice WritablePath, noticePaths []Path) {
	ctx.Build(pctx, BuildParams{
		Rule:        mergeNoticesRule,
		Description: "merge notices",
		Inputs:      noticePaths,
		Output:      mergedNotice,
	})
}

func BuildNoticeOutput(ctx ModuleContext, installPath InstallPath, installFilename string,
	noticePaths []Path) NoticeOutputs {
	// Merge all NOTICE files into one.
	// TODO(jungjw): We should just produce a well-formatted NOTICE.html file in a single pass.
	//
	// generate-notice-files.py, which processes the merged NOTICE file, has somewhat strict rules
	// about input NOTICE file paths.
	// 1. Their relative paths to the src root become their NOTICE index titles. We want to use
	// on-device paths as titles, and so output the merged NOTICE file the corresponding location.
	// 2. They must end with .txt extension. Otherwise, they're ignored.
	noticeRelPath := InstallPathToOnDevicePath(ctx, installPath.Join(ctx, installFilename+".txt"))
	mergedNotice := PathForModuleOut(ctx, filepath.Join("NOTICE_FILES/src", noticeRelPath))
	MergeNotices(ctx, mergedNotice, noticePaths)

	// Transform the merged NOTICE file into a gzipped HTML file.
	txtOuptut := PathForModuleOut(ctx, "NOTICE_txt", "NOTICE.txt")
	htmlOutput := PathForModuleOut(ctx, "NOTICE_html", "NOTICE.html")
	htmlGzOutput := PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
	title := "Notices for " + ctx.ModuleName()
	ctx.Build(pctx, BuildParams{
		Rule:            generateNoticeRule,
		Description:     "generate notice output",
		Input:           mergedNotice,
		Output:          htmlGzOutput,
		ImplicitOutputs: WritablePaths{txtOuptut, htmlOutput},
		Args: map[string]string{
			"txtOut":   txtOuptut.String(),
			"htmlOut":  htmlOutput.String(),
			"title":    title,
			"inputDir": PathForModuleOut(ctx, "NOTICE_FILES/src").String(),
		},
	})

	return NoticeOutputs{
		Merged:       OptionalPathForPath(mergedNotice),
		TxtOutput:    OptionalPathForPath(txtOuptut),
		HtmlOutput:   OptionalPathForPath(htmlOutput),
		HtmlGzOutput: OptionalPathForPath(htmlGzOutput),
	}
}

// BuildNoticeTextOutputFromLicenseMetadata writes out a notice text file based on the module's
// generated license metadata file.
func BuildNoticeTextOutputFromLicenseMetadata(ctx ModuleContext, outputFile WritablePath) {
@@ -112,5 +28,18 @@ func BuildNoticeTextOutputFromLicenseMetadata(ctx ModuleContext, outputFile Writ
		FlagWithOutput("-o ", outputFile).
		FlagWithDepFile("-d ", depsFile).
		Input(ctx.Module().base().licenseMetadataFile)
	rule.Build("container_notice", "container notice file")
	rule.Build("text_notice", "container notice file")
}

// BuildNoticeHtmlOutputFromLicenseMetadata writes out a notice text file based on the module's
// generated license metadata file.
func BuildNoticeHtmlOutputFromLicenseMetadata(ctx ModuleContext, outputFile WritablePath) {
	depsFile := outputFile.ReplaceExtension(ctx, strings.TrimPrefix(outputFile.Ext()+".d", "."))
	rule := NewRuleBuilder(pctx, ctx)
	rule.Command().
		BuiltTool("htmlnotice").
		FlagWithOutput("-o ", outputFile).
		FlagWithDepFile("-d ", depsFile).
		Input(ctx.Module().base().licenseMetadataFile)
	rule.Build("html_notice", "container notice file")
}
+0 −4
Original line number Diff line number Diff line
@@ -396,10 +396,6 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData {
				}
				a.writeRequiredModules(w, moduleNames)

				if a.mergedNotices.Merged.Valid() {
					fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNotices.Merged.Path().String())
				}

				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")

				if apexType == imageApex {
+6 −8
Original line number Diff line number Diff line
@@ -414,8 +414,8 @@ type apexBundle struct {
	// Processed file_contexts files
	fileContexts android.WritablePath

	// Struct holding the merged notice file paths in different formats
	mergedNotices android.NoticeOutputs
	// Path to notice file in html.gz format.
	htmlGzNotice android.WritablePath

	// The built APEX file. This is the main product.
	// Could be .apex or .capex
@@ -488,7 +488,6 @@ const (
type apexFile struct {
	// buildFile is put in the installDir inside the APEX.
	builtFile  android.Path
	noticeFiles android.Paths
	installDir string
	customStem string
	symlinks   []string // additional symlinks
@@ -528,7 +527,6 @@ func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidM
		module:              module,
	}
	if module != nil {
		ret.noticeFiles = module.NoticeFiles()
		ret.moduleDir = ctx.OtherModuleDir(module)
		ret.requiredModuleNames = module.RequiredModuleNames()
		ret.targetRequiredModuleNames = module.TargetRequiredModuleNames()
+0 −9
Original line number Diff line number Diff line
@@ -591,15 +591,6 @@ func TestBasicApex(t *testing.T) {
		t.Errorf("Could not find all expected symlinks! foo: %t, foo_link_64: %t. Command was %s", found_foo, found_foo_link_64, copyCmds)
	}

	mergeNoticesRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("mergeNoticesRule")
	noticeInputs := mergeNoticesRule.Inputs.Strings()
	if len(noticeInputs) != 3 {
		t.Errorf("number of input notice files: expected = 3, actual = %q", len(noticeInputs))
	}
	ensureListContains(t, noticeInputs, "NOTICE")
	ensureListContains(t, noticeInputs, "custom_notice")
	ensureListContains(t, noticeInputs, "custom_notice_for_static_lib")

	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
	ensureListContains(t, fullDepsInfo, "  myjar(minSdkVersion:(no version)) <- myapex")
	ensureListContains(t, fullDepsInfo, "  mylib2(minSdkVersion:(no version)) <- mylib")
+5 −32
Original line number Diff line number Diff line
@@ -305,32 +305,6 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Output
	return output.OutputPath
}

// buildNoticeFiles creates a buile rule for aggregating notice files from the modules that
// contributes to this APEX. The notice files are merged into a big notice file.
func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
	var noticeFiles android.Paths

	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
		if externalDep {
			// As soon as the dependency graph crosses the APEX boundary, don't go further.
			return false
		}
		noticeFiles = append(noticeFiles, to.NoticeFiles()...)
		return true
	})

	// TODO(jiyong): why do we need this? WalkPayloadDeps should have already covered this.
	for _, fi := range a.filesInfo {
		noticeFiles = append(noticeFiles, fi.noticeFiles...)
	}

	if len(noticeFiles) == 0 {
		return android.NoticeOutputs{}
	}

	return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.SortedUniquePaths(noticeFiles))
}

// buildInstalledFilesFile creates a build rule for the installed-files.txt file where the list of
// files included in this APEX is shown. The text file is dist'ed so that people can see what's
// included in the APEX without actually downloading and extracting it.
@@ -642,12 +616,11 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
			optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
		}

		a.mergedNotices = a.buildNoticeFiles(ctx, a.Name()+suffix)
		if a.mergedNotices.HtmlGzOutput.Valid() {
			// If there's a NOTICE file, embed it as an asset file in the APEX.
			implicitInputs = append(implicitInputs, a.mergedNotices.HtmlGzOutput.Path())
			optFlags = append(optFlags, "--assets_dir "+filepath.Dir(a.mergedNotices.HtmlGzOutput.String()))
		}
		// Create a NOTICE file, and embed it as an asset file in the APEX.
		a.htmlGzNotice = android.PathForModuleOut(ctx, "NOTICE/NOTICES.html.gz")
		android.BuildNoticeHtmlOutputFromLicenseMetadata(ctx, a.htmlGzNotice)
		implicitInputs = append(implicitInputs, a.htmlGzNotice)
		optFlags = append(optFlags, "--assets_dir "+filepath.Dir(a.htmlGzNotice.String()))

		if (moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) && !a.shouldGenerateHashtree()) && !compressionEnabled {
			// Apexes which are supposed to be installed in builtin dirs(/system, etc)
Loading