notices.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright 2019 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package android
  15. import (
  16. "path/filepath"
  17. "github.com/google/blueprint"
  18. )
  19. func init() {
  20. pctx.SourcePathVariable("merge_notices", "build/soong/scripts/mergenotice.py")
  21. pctx.SourcePathVariable("generate_notice", "build/soong/scripts/generate-notice-files.py")
  22. pctx.HostBinToolVariable("minigzip", "minigzip")
  23. }
  24. type NoticeOutputs struct {
  25. Merged OptionalPath
  26. TxtOutput OptionalPath
  27. HtmlOutput OptionalPath
  28. HtmlGzOutput OptionalPath
  29. }
  30. var (
  31. mergeNoticesRule = pctx.AndroidStaticRule("mergeNoticesRule", blueprint.RuleParams{
  32. Command: `${merge_notices} --output $out $in`,
  33. CommandDeps: []string{"${merge_notices}"},
  34. Description: "merge notice files into $out",
  35. })
  36. generateNoticeRule = pctx.AndroidStaticRule("generateNoticeRule", blueprint.RuleParams{
  37. Command: `rm -rf $$(dirname $txtOut) $$(dirname $htmlOut) $$(dirname $out) && ` +
  38. `mkdir -p $$(dirname $txtOut) $$(dirname $htmlOut) $$(dirname $out) && ` +
  39. `${generate_notice} --text-output $txtOut --html-output $htmlOut -t "$title" -s $inputDir && ` +
  40. `${minigzip} -c $htmlOut > $out`,
  41. CommandDeps: []string{"${generate_notice}", "${minigzip}"},
  42. Description: "produce notice file $out",
  43. }, "txtOut", "htmlOut", "title", "inputDir")
  44. )
  45. func MergeNotices(ctx ModuleContext, mergedNotice WritablePath, noticePaths []Path) {
  46. ctx.Build(pctx, BuildParams{
  47. Rule: mergeNoticesRule,
  48. Description: "merge notices",
  49. Inputs: noticePaths,
  50. Output: mergedNotice,
  51. })
  52. }
  53. func BuildNoticeOutput(ctx ModuleContext, installPath InstallPath, installFilename string,
  54. noticePaths []Path) NoticeOutputs {
  55. // Merge all NOTICE files into one.
  56. // TODO(jungjw): We should just produce a well-formatted NOTICE.html file in a single pass.
  57. //
  58. // generate-notice-files.py, which processes the merged NOTICE file, has somewhat strict rules
  59. // about input NOTICE file paths.
  60. // 1. Their relative paths to the src root become their NOTICE index titles. We want to use
  61. // on-device paths as titles, and so output the merged NOTICE file the corresponding location.
  62. // 2. They must end with .txt extension. Otherwise, they're ignored.
  63. noticeRelPath := InstallPathToOnDevicePath(ctx, installPath.Join(ctx, installFilename+".txt"))
  64. mergedNotice := PathForModuleOut(ctx, filepath.Join("NOTICE_FILES/src", noticeRelPath))
  65. MergeNotices(ctx, mergedNotice, noticePaths)
  66. // Transform the merged NOTICE file into a gzipped HTML file.
  67. txtOuptut := PathForModuleOut(ctx, "NOTICE_txt", "NOTICE.txt")
  68. htmlOutput := PathForModuleOut(ctx, "NOTICE_html", "NOTICE.html")
  69. htmlGzOutput := PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
  70. title := "Notices for " + ctx.ModuleName()
  71. ctx.Build(pctx, BuildParams{
  72. Rule: generateNoticeRule,
  73. Description: "generate notice output",
  74. Input: mergedNotice,
  75. Output: htmlGzOutput,
  76. ImplicitOutputs: WritablePaths{txtOuptut, htmlOutput},
  77. Args: map[string]string{
  78. "txtOut": txtOuptut.String(),
  79. "htmlOut": htmlOutput.String(),
  80. "title": title,
  81. "inputDir": PathForModuleOut(ctx, "NOTICE_FILES/src").String(),
  82. },
  83. })
  84. return NoticeOutputs{
  85. Merged: OptionalPathForPath(mergedNotice),
  86. TxtOutput: OptionalPathForPath(txtOuptut),
  87. HtmlOutput: OptionalPathForPath(htmlOutput),
  88. HtmlGzOutput: OptionalPathForPath(htmlGzOutput),
  89. }
  90. }
  91. // BuildNotices merges the supplied NOTICE files into a single file that lists notices
  92. // for every key in noticeMap (which would normally be installed files).
  93. func BuildNotices(ctx ModuleContext, noticeMap map[string]Paths) NoticeOutputs {
  94. // TODO(jungjw): We should just produce a well-formatted NOTICE.html file in a single pass.
  95. //
  96. // generate-notice-files.py, which processes the merged NOTICE file, has somewhat strict rules
  97. // about input NOTICE file paths.
  98. // 1. Their relative paths to the src root become their NOTICE index titles. We want to use
  99. // on-device paths as titles, and so output the merged NOTICE file the corresponding location.
  100. // 2. They must end with .txt extension. Otherwise, they're ignored.
  101. mergeTool := PathForSource(ctx, "build/soong/scripts/mergenotice.py")
  102. generateNoticeTool := PathForSource(ctx, "build/soong/scripts/generate-notice-files.py")
  103. outputDir := PathForModuleOut(ctx, "notices")
  104. builder := NewRuleBuilder(pctx, ctx).
  105. Sbox(outputDir, PathForModuleOut(ctx, "notices.sbox.textproto"))
  106. for _, installPath := range SortedStringKeys(noticeMap) {
  107. noticePath := outputDir.Join(ctx, installPath+".txt")
  108. // It would be nice if sbox created directories for temporaries, but until then
  109. // this is simple enough.
  110. builder.Command().
  111. Text("(cd").OutputDir().Text("&&").
  112. Text("mkdir -p").Text(filepath.Dir(installPath)).Text(")")
  113. builder.Temporary(noticePath)
  114. builder.Command().
  115. Tool(mergeTool).
  116. Flag("--output").Output(noticePath).
  117. Inputs(noticeMap[installPath])
  118. }
  119. // Transform the merged NOTICE file into a gzipped HTML file.
  120. txtOutput := outputDir.Join(ctx, "NOTICE.txt")
  121. htmlOutput := outputDir.Join(ctx, "NOTICE.html")
  122. htmlGzOutput := outputDir.Join(ctx, "NOTICE.html.gz")
  123. title := "\"Notices for " + ctx.ModuleName() + "\""
  124. builder.Command().Tool(generateNoticeTool).
  125. FlagWithOutput("--text-output ", txtOutput).
  126. FlagWithOutput("--html-output ", htmlOutput).
  127. FlagWithArg("-t ", title).
  128. Flag("-s").OutputDir()
  129. builder.Command().BuiltTool("minigzip").
  130. FlagWithInput("-c ", htmlOutput).
  131. FlagWithOutput("> ", htmlGzOutput)
  132. builder.Build("build_notices", "generate notice output")
  133. return NoticeOutputs{
  134. TxtOutput: OptionalPathForPath(txtOutput),
  135. HtmlOutput: OptionalPathForPath(htmlOutput),
  136. HtmlGzOutput: OptionalPathForPath(htmlGzOutput),
  137. }
  138. }