blob: 3c64d56f0fdcafff235825c2d3e38b920a6d3084 [file] [log] [blame]
Jiyong Park073ea552020-11-09 14:08:34 +09001// Copyright 2020 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
15package android
16
Jiyong Parkdda8f692020-11-09 18:38:48 +090017import (
18 "fmt"
19 "path/filepath"
Inseob Kim33f95a92024-07-11 15:44:49 +090020 "sort"
Jeongik Cha76e677f2023-12-21 16:39:15 +090021 "strings"
Jiyong Parkdda8f692020-11-09 18:38:48 +090022
23 "github.com/google/blueprint"
Jiyong Park105e11c2024-05-17 14:58:24 +090024 "github.com/google/blueprint/proptools"
Jiyong Parkdda8f692020-11-09 18:38:48 +090025)
26
Jiyong Parkcc1157c2020-11-25 11:31:13 +090027// PackagingSpec abstracts a request to place a built artifact at a certain path in a package. A
28// package can be the traditional <partition>.img, but isn't limited to those. Other examples could
29// be a new filesystem image that is a subset of system.img (e.g. for an Android-like mini OS
30// running on a VM), or a zip archive for some of the host tools.
Jiyong Park073ea552020-11-09 14:08:34 +090031type PackagingSpec struct {
32 // Path relative to the root of the package
33 relPathInPackage string
34
35 // The path to the built artifact
36 srcPath Path
37
38 // If this is not empty, then relPathInPackage should be a symlink to this target. (Then
39 // srcPath is of course ignored.)
40 symlinkTarget string
41
42 // Whether relPathInPackage should be marked as executable or not
43 executable bool
Dan Willemsen9fe14102021-07-13 21:52:04 -070044
45 effectiveLicenseFiles *Paths
Jooyung Han99c5fe62022-03-21 15:13:38 +090046
47 partition string
Jiyong Park4152b192024-04-30 21:24:21 +090048
49 // Whether this packaging spec represents an installation of the srcPath (i.e. this struct
50 // is created via InstallFile or InstallSymlink) or a simple packaging (i.e. created via
51 // PackageFile).
52 skipInstall bool
Justin Yun74f3f302024-05-07 14:32:14 +090053
54 // Paths of aconfig files for the built artifact
55 aconfigPaths *Paths
Jiyong Parkc6a773d2024-05-14 21:49:11 +090056
57 // ArchType of the module which produced this packaging spec
58 archType ArchType
Jiyong Parka574d532024-08-28 18:06:43 +090059
60 // List of module names that this packaging spec overrides
61 overrides *[]string
62
63 // Name of the module where this packaging spec is output of
64 owner string
Jiyong Park073ea552020-11-09 14:08:34 +090065}
Jiyong Parkdda8f692020-11-09 18:38:48 +090066
Yu Liu467d7c52024-09-18 21:54:44 +000067type packagingSpecGob struct {
68 RelPathInPackage string
69 SrcPath Path
70 SymlinkTarget string
71 Executable bool
72 Partition string
73 SkipInstall bool
74 AconfigPaths *Paths
75 ArchType ArchType
76 Overrides *[]string
77 Owner string
78}
Yu Liu26a716d2024-08-30 23:40:32 +000079
Yu Liu467d7c52024-09-18 21:54:44 +000080func (p *PackagingSpec) ToGob() *packagingSpecGob {
81 return &packagingSpecGob{
82 RelPathInPackage: p.relPathInPackage,
83 SrcPath: p.srcPath,
84 SymlinkTarget: p.symlinkTarget,
85 Executable: p.executable,
86 Partition: p.partition,
87 SkipInstall: p.skipInstall,
88 AconfigPaths: p.aconfigPaths,
89 ArchType: p.archType,
90 Overrides: p.overrides,
91 Owner: p.owner,
92 }
93}
94
95func (p *PackagingSpec) FromGob(data *packagingSpecGob) {
96 p.relPathInPackage = data.RelPathInPackage
97 p.srcPath = data.SrcPath
98 p.symlinkTarget = data.SymlinkTarget
99 p.executable = data.Executable
100 p.partition = data.Partition
101 p.skipInstall = data.SkipInstall
102 p.aconfigPaths = data.AconfigPaths
103 p.archType = data.ArchType
104 p.overrides = data.Overrides
105 p.owner = data.Owner
106}
107
108func (p *PackagingSpec) GobEncode() ([]byte, error) {
109 return blueprint.CustomGobEncode[packagingSpecGob](p)
Yu Liu26a716d2024-08-30 23:40:32 +0000110}
111
112func (p *PackagingSpec) GobDecode(data []byte) error {
Yu Liu467d7c52024-09-18 21:54:44 +0000113 return blueprint.CustomGobDecode[packagingSpecGob](data, p)
Yu Liu26a716d2024-08-30 23:40:32 +0000114}
115
Jiyong Park16ef7ac2024-05-01 12:36:10 +0000116func (p *PackagingSpec) Equals(other *PackagingSpec) bool {
117 if other == nil {
118 return false
119 }
120 if p.relPathInPackage != other.relPathInPackage {
121 return false
122 }
123 if p.srcPath != other.srcPath || p.symlinkTarget != other.symlinkTarget {
124 return false
125 }
126 if p.executable != other.executable {
127 return false
128 }
129 if p.partition != other.partition {
130 return false
131 }
132 return true
133}
134
Kiyoung Kim24dfc1f2020-11-16 10:48:44 +0900135// Get file name of installed package
136func (p *PackagingSpec) FileName() string {
137 if p.relPathInPackage != "" {
138 return filepath.Base(p.relPathInPackage)
139 }
140
141 return ""
142}
143
Jiyong Park6446b622021-02-01 20:08:28 +0900144// Path relative to the root of the package
145func (p *PackagingSpec) RelPathInPackage() string {
146 return p.relPathInPackage
147}
148
Dan Willemsen9fe14102021-07-13 21:52:04 -0700149func (p *PackagingSpec) SetRelPathInPackage(relPathInPackage string) {
150 p.relPathInPackage = relPathInPackage
151}
152
153func (p *PackagingSpec) EffectiveLicenseFiles() Paths {
154 if p.effectiveLicenseFiles == nil {
155 return Paths{}
156 }
157 return *p.effectiveLicenseFiles
158}
159
Jooyung Han99c5fe62022-03-21 15:13:38 +0900160func (p *PackagingSpec) Partition() string {
161 return p.partition
162}
163
Jiyong Park4152b192024-04-30 21:24:21 +0900164func (p *PackagingSpec) SkipInstall() bool {
165 return p.skipInstall
166}
167
Justin Yun74f3f302024-05-07 14:32:14 +0900168// Paths of aconfig files for the built artifact
169func (p *PackagingSpec) GetAconfigPaths() Paths {
170 return *p.aconfigPaths
171}
172
Jiyong Parkdda8f692020-11-09 18:38:48 +0900173type PackageModule interface {
174 Module
175 packagingBase() *PackagingBase
176
177 // AddDeps adds dependencies to the `deps` modules. This should be called in DepsMutator.
Jooyung Han092ef812021-03-10 15:40:34 +0900178 // When adding the dependencies, depTag is used as the tag. If `deps` modules are meant to
179 // be copied to a zip in CopyDepsToZip, `depTag` should implement PackagingItem marker interface.
Jiyong Park65b62242020-11-25 12:44:59 +0900180 AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900181
Jooyung Hana8834282022-03-25 11:40:12 +0900182 // GatherPackagingSpecs gathers PackagingSpecs of transitive dependencies.
183 GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec
Jeongik Cha54bf8752024-02-08 10:44:37 +0900184 GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec
Jooyung Hana8834282022-03-25 11:40:12 +0900185
Jiyong Parkdda8f692020-11-09 18:38:48 +0900186 // CopyDepsToZip zips the built artifacts of the dependencies into the given zip file and
Jiyong Parkcc1157c2020-11-25 11:31:13 +0900187 // returns zip entries in it. This is expected to be called in GenerateAndroidBuildActions,
Jiyong Parkdda8f692020-11-09 18:38:48 +0900188 // followed by a build rule that unzips it and creates the final output (img, zip, tar.gz,
189 // etc.) from the extracted files
Jooyung Hana8834282022-03-25 11:40:12 +0900190 CopyDepsToZip(ctx ModuleContext, specs map[string]PackagingSpec, zipOut WritablePath) []string
Jiyong Parkdda8f692020-11-09 18:38:48 +0900191}
192
193// PackagingBase provides basic functionality for packaging dependencies. A module is expected to
194// include this struct and call InitPackageModule.
195type PackagingBase struct {
196 properties PackagingProperties
197
Jiyong Parkcc1157c2020-11-25 11:31:13 +0900198 // Allows this module to skip missing dependencies. In most cases, this is not required, but
199 // for rare cases like when there's a dependency to a module which exists in certain repo
200 // checkouts, this is needed.
Jiyong Parkdda8f692020-11-09 18:38:48 +0900201 IgnoreMissingDependencies bool
Jiyong Park3ea9b652024-05-15 23:01:54 +0900202
203 // If this is set to true by a module type inheriting PackagingBase, the deps property
204 // collects the first target only even with compile_multilib: true.
205 DepsCollectFirstTargetOnly bool
Jiyong Parkdda8f692020-11-09 18:38:48 +0900206}
207
208type depsProperty struct {
209 // Modules to include in this package
Jiyong Park105e11c2024-05-17 14:58:24 +0900210 Deps proptools.Configurable[[]string] `android:"arch_variant"`
Jiyong Parkdda8f692020-11-09 18:38:48 +0900211}
212
213type packagingMultilibProperties struct {
Jiyong Parke6043782024-05-20 16:17:39 +0900214 First depsProperty `android:"arch_variant"`
215 Common depsProperty `android:"arch_variant"`
216 Lib32 depsProperty `android:"arch_variant"`
217 Lib64 depsProperty `android:"arch_variant"`
218 Both depsProperty `android:"arch_variant"`
219 Prefer32 depsProperty `android:"arch_variant"`
Jiyong Parkdda8f692020-11-09 18:38:48 +0900220}
221
Jiyong Park2136d152021-02-01 23:24:56 +0900222type packagingArchProperties struct {
223 Arm64 depsProperty
224 Arm depsProperty
225 X86_64 depsProperty
226 X86 depsProperty
227}
228
Jiyong Parkdda8f692020-11-09 18:38:48 +0900229type PackagingProperties struct {
Jiyong Park105e11c2024-05-17 14:58:24 +0900230 Deps proptools.Configurable[[]string] `android:"arch_variant"`
231 Multilib packagingMultilibProperties `android:"arch_variant"`
Jiyong Park2136d152021-02-01 23:24:56 +0900232 Arch packagingArchProperties
Jiyong Parkdda8f692020-11-09 18:38:48 +0900233}
234
Jiyong Parkdda8f692020-11-09 18:38:48 +0900235func InitPackageModule(p PackageModule) {
236 base := p.packagingBase()
237 p.AddProperties(&base.properties)
238}
239
240func (p *PackagingBase) packagingBase() *PackagingBase {
241 return p
242}
243
Jiyong Parkcc1157c2020-11-25 11:31:13 +0900244// From deps and multilib.*.deps, select the dependencies that are for the given arch deps is for
245// the current archicture when this module is not configured for multi target. When configured for
246// multi target, deps is selected for each of the targets and is NOT selected for the current
247// architecture which would be Common.
Jiyong Parkdda8f692020-11-09 18:38:48 +0900248func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) []string {
Jiyong Park105e11c2024-05-17 14:58:24 +0900249 get := func(prop proptools.Configurable[[]string]) []string {
250 return prop.GetOrDefault(ctx, nil)
251 }
252
Jiyong Parkdda8f692020-11-09 18:38:48 +0900253 var ret []string
254 if arch == ctx.Target().Arch.ArchType && len(ctx.MultiTargets()) == 0 {
Jiyong Park105e11c2024-05-17 14:58:24 +0900255 ret = append(ret, get(p.properties.Deps)...)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900256 } else if arch.Multilib == "lib32" {
Jiyong Park105e11c2024-05-17 14:58:24 +0900257 ret = append(ret, get(p.properties.Multilib.Lib32.Deps)...)
Jiyong Parke6043782024-05-20 16:17:39 +0900258 // multilib.prefer32.deps are added for lib32 only when they support 32-bit arch
259 for _, dep := range get(p.properties.Multilib.Prefer32.Deps) {
260 if checkIfOtherModuleSupportsLib32(ctx, dep) {
261 ret = append(ret, dep)
262 }
263 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900264 } else if arch.Multilib == "lib64" {
Jiyong Park105e11c2024-05-17 14:58:24 +0900265 ret = append(ret, get(p.properties.Multilib.Lib64.Deps)...)
Jiyong Parke6043782024-05-20 16:17:39 +0900266 // multilib.prefer32.deps are added for lib64 only when they don't support 32-bit arch
267 for _, dep := range get(p.properties.Multilib.Prefer32.Deps) {
268 if !checkIfOtherModuleSupportsLib32(ctx, dep) {
269 ret = append(ret, dep)
270 }
271 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900272 } else if arch == Common {
Jiyong Park105e11c2024-05-17 14:58:24 +0900273 ret = append(ret, get(p.properties.Multilib.Common.Deps)...)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900274 }
Jiyong Park2136d152021-02-01 23:24:56 +0900275
Jiyong Park3ea9b652024-05-15 23:01:54 +0900276 if p.DepsCollectFirstTargetOnly {
Jiyong Park105e11c2024-05-17 14:58:24 +0900277 if len(get(p.properties.Multilib.First.Deps)) > 0 {
Jiyong Park3ea9b652024-05-15 23:01:54 +0900278 ctx.PropertyErrorf("multilib.first.deps", "not supported. use \"deps\" instead")
279 }
280 for i, t := range ctx.MultiTargets() {
281 if t.Arch.ArchType == arch {
Jiyong Park105e11c2024-05-17 14:58:24 +0900282 ret = append(ret, get(p.properties.Multilib.Both.Deps)...)
Jiyong Park3ea9b652024-05-15 23:01:54 +0900283 if i == 0 {
Jiyong Park105e11c2024-05-17 14:58:24 +0900284 ret = append(ret, get(p.properties.Deps)...)
Jiyong Park3ea9b652024-05-15 23:01:54 +0900285 }
286 }
287 }
288 } else {
Jiyong Park105e11c2024-05-17 14:58:24 +0900289 if len(get(p.properties.Multilib.Both.Deps)) > 0 {
Jiyong Park3ea9b652024-05-15 23:01:54 +0900290 ctx.PropertyErrorf("multilib.both.deps", "not supported. use \"deps\" instead")
291 }
292 for i, t := range ctx.MultiTargets() {
293 if t.Arch.ArchType == arch {
Jiyong Park105e11c2024-05-17 14:58:24 +0900294 ret = append(ret, get(p.properties.Deps)...)
Jiyong Park3ea9b652024-05-15 23:01:54 +0900295 if i == 0 {
Jiyong Park105e11c2024-05-17 14:58:24 +0900296 ret = append(ret, get(p.properties.Multilib.First.Deps)...)
Jiyong Park3ea9b652024-05-15 23:01:54 +0900297 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900298 }
299 }
300 }
Jiyong Park2136d152021-02-01 23:24:56 +0900301
302 if ctx.Arch().ArchType == Common {
303 switch arch {
304 case Arm64:
Jiyong Park105e11c2024-05-17 14:58:24 +0900305 ret = append(ret, get(p.properties.Arch.Arm64.Deps)...)
Jiyong Park2136d152021-02-01 23:24:56 +0900306 case Arm:
Jiyong Park105e11c2024-05-17 14:58:24 +0900307 ret = append(ret, get(p.properties.Arch.Arm.Deps)...)
Jiyong Park2136d152021-02-01 23:24:56 +0900308 case X86_64:
Jiyong Park105e11c2024-05-17 14:58:24 +0900309 ret = append(ret, get(p.properties.Arch.X86_64.Deps)...)
Jiyong Park2136d152021-02-01 23:24:56 +0900310 case X86:
Jiyong Park105e11c2024-05-17 14:58:24 +0900311 ret = append(ret, get(p.properties.Arch.X86.Deps)...)
Jiyong Park2136d152021-02-01 23:24:56 +0900312 }
313 }
314
Jiyong Parkdda8f692020-11-09 18:38:48 +0900315 return FirstUniqueStrings(ret)
316}
317
Jiyong Parke6043782024-05-20 16:17:39 +0900318func getSupportedTargets(ctx BaseModuleContext) []Target {
Jiyong Parkdda8f692020-11-09 18:38:48 +0900319 var ret []Target
320 // The current and the common OS targets are always supported
321 ret = append(ret, ctx.Target())
322 if ctx.Arch().ArchType != Common {
323 ret = append(ret, Target{Os: ctx.Os(), Arch: Arch{ArchType: Common}})
324 }
325 // If this module is configured for multi targets, those should be supported as well
326 ret = append(ret, ctx.MultiTargets()...)
327 return ret
328}
329
Jiyong Parke6043782024-05-20 16:17:39 +0900330// getLib32Target returns the 32-bit target from the list of targets this module supports. If this
331// module doesn't support 32-bit target, nil is returned.
332func getLib32Target(ctx BaseModuleContext) *Target {
333 for _, t := range getSupportedTargets(ctx) {
334 if t.Arch.ArchType.Multilib == "lib32" {
335 return &t
336 }
337 }
338 return nil
339}
340
341// checkIfOtherModuleSUpportsLib32 returns true if 32-bit variant of dep exists.
342func checkIfOtherModuleSupportsLib32(ctx BaseModuleContext, dep string) bool {
343 t := getLib32Target(ctx)
344 if t == nil {
345 // This packaging module doesn't support 32bit. No point of checking if dep supports 32-bit
346 // or not.
347 return false
348 }
349 return ctx.OtherModuleFarDependencyVariantExists(t.Variations(), dep)
350}
351
Jooyung Han092ef812021-03-10 15:40:34 +0900352// PackagingItem is a marker interface for dependency tags.
353// Direct dependencies with a tag implementing PackagingItem are packaged in CopyDepsToZip().
354type PackagingItem interface {
355 // IsPackagingItem returns true if the dep is to be packaged
356 IsPackagingItem() bool
357}
358
359// DepTag provides default implementation of PackagingItem interface.
360// PackagingBase-derived modules can define their own dependency tag by embedding this, which
361// can be passed to AddDeps() or AddDependencies().
362type PackagingItemAlwaysDepTag struct {
363}
364
365// IsPackagingItem returns true if the dep is to be packaged
366func (PackagingItemAlwaysDepTag) IsPackagingItem() bool {
367 return true
368}
369
Jiyong Parkdda8f692020-11-09 18:38:48 +0900370// See PackageModule.AddDeps
Jiyong Park65b62242020-11-25 12:44:59 +0900371func (p *PackagingBase) AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag) {
Jiyong Parke6043782024-05-20 16:17:39 +0900372 for _, t := range getSupportedTargets(ctx) {
Jiyong Parkdda8f692020-11-09 18:38:48 +0900373 for _, dep := range p.getDepsForArch(ctx, t.Arch.ArchType) {
374 if p.IgnoreMissingDependencies && !ctx.OtherModuleExists(dep) {
375 continue
376 }
377 ctx.AddFarVariationDependencies(t.Variations(), depTag, dep)
378 }
379 }
380}
381
Jeongik Cha54bf8752024-02-08 10:44:37 +0900382func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
Jiyong Parka574d532024-08-28 18:06:43 +0900383 // all packaging specs gathered from the dep.
384 var all []PackagingSpec
385 // list of module names overridden
386 var overridden []string
Jiyong Parkc6a773d2024-05-14 21:49:11 +0900387
388 var arches []ArchType
Jiyong Parke6043782024-05-20 16:17:39 +0900389 for _, target := range getSupportedTargets(ctx) {
Jiyong Parkc6a773d2024-05-14 21:49:11 +0900390 arches = append(arches, target.Arch.ArchType)
391 }
392
393 // filter out packaging specs for unsupported architecture
394 filterArch := func(ps PackagingSpec) bool {
395 for _, arch := range arches {
396 if arch == ps.archType {
397 return true
398 }
399 }
400 return false
401 }
402
Jooyung Han092ef812021-03-10 15:40:34 +0900403 ctx.VisitDirectDeps(func(child Module) {
404 if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() {
405 return
Jiyong Parkdda8f692020-11-09 18:38:48 +0900406 }
Yu Liubad1eef2024-08-21 22:37:35 +0000407 for _, ps := range OtherModuleProviderOrDefault(
408 ctx, child, InstallFilesProvider).TransitivePackagingSpecs.ToList() {
Jiyong Parkc6a773d2024-05-14 21:49:11 +0900409 if !filterArch(ps) {
410 continue
411 }
412
Jeongik Cha54bf8752024-02-08 10:44:37 +0900413 if filter != nil {
414 if !filter(ps) {
415 continue
416 }
417 }
Jiyong Parka574d532024-08-28 18:06:43 +0900418 all = append(all, ps)
419 if ps.overrides != nil {
420 overridden = append(overridden, *ps.overrides...)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900421 }
422 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900423 })
Jiyong Parka574d532024-08-28 18:06:43 +0900424
425 // all minus packaging specs that are overridden
426 var filtered []PackagingSpec
427 for _, ps := range all {
428 if ps.owner != "" && InList(ps.owner, overridden) {
429 continue
430 }
431 filtered = append(filtered, ps)
432 }
433
434 m := make(map[string]PackagingSpec)
435 for _, ps := range filtered {
436 dstPath := ps.relPathInPackage
437 if existingPs, ok := m[dstPath]; ok {
438 if !existingPs.Equals(&ps) {
439 ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps)
440 }
441 continue
442 }
443 m[dstPath] = ps
444 }
Jooyung Handf09d172021-05-11 11:13:30 +0900445 return m
446}
Jiyong Parkdda8f692020-11-09 18:38:48 +0900447
Jeongik Cha54bf8752024-02-08 10:44:37 +0900448// See PackageModule.GatherPackagingSpecs
449func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec {
450 return p.GatherPackagingSpecsWithFilter(ctx, nil)
451}
452
Dan Willemsen9fe14102021-07-13 21:52:04 -0700453// CopySpecsToDir is a helper that will add commands to the rule builder to copy the PackagingSpec
454// entries into the specified directory.
Peter Collingbourneff56c012023-03-15 22:24:03 -0700455func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir WritablePath) (entries []string) {
Inseob Kim33f95a92024-07-11 15:44:49 +0900456 dirsToSpecs := make(map[WritablePath]map[string]PackagingSpec)
457 dirsToSpecs[dir] = specs
458 return p.CopySpecsToDirs(ctx, builder, dirsToSpecs)
459}
460
461// CopySpecsToDirs is a helper that will add commands to the rule builder to copy the PackagingSpec
462// entries into corresponding directories.
463func (p *PackagingBase) CopySpecsToDirs(ctx ModuleContext, builder *RuleBuilder, dirsToSpecs map[WritablePath]map[string]PackagingSpec) (entries []string) {
464 empty := true
465 for _, specs := range dirsToSpecs {
466 if len(specs) > 0 {
467 empty = false
468 break
469 }
470 }
471 if empty {
Cole Faust3b3a0112024-01-03 15:16:55 -0800472 return entries
473 }
Inseob Kim33f95a92024-07-11 15:44:49 +0900474
Jiyong Parkdda8f692020-11-09 18:38:48 +0900475 seenDir := make(map[string]bool)
Jeongik Cha76e677f2023-12-21 16:39:15 +0900476 preparerPath := PathForModuleOut(ctx, "preparer.sh")
477 cmd := builder.Command().Tool(preparerPath)
478 var sb strings.Builder
Cole Faust3b3a0112024-01-03 15:16:55 -0800479 sb.WriteString("set -e\n")
Inseob Kim33f95a92024-07-11 15:44:49 +0900480
481 dirs := make([]WritablePath, 0, len(dirsToSpecs))
482 for dir, _ := range dirsToSpecs {
483 dirs = append(dirs, dir)
484 }
485 sort.Slice(dirs, func(i, j int) bool {
486 return dirs[i].String() < dirs[j].String()
487 })
488
489 for _, dir := range dirs {
490 specs := dirsToSpecs[dir]
491 for _, k := range SortedKeys(specs) {
492 ps := specs[k]
493 destPath := filepath.Join(dir.String(), ps.relPathInPackage)
494 destDir := filepath.Dir(destPath)
495 entries = append(entries, ps.relPathInPackage)
496 if _, ok := seenDir[destDir]; !ok {
497 seenDir[destDir] = true
498 sb.WriteString(fmt.Sprintf("mkdir -p %s\n", destDir))
499 }
500 if ps.symlinkTarget == "" {
501 cmd.Implicit(ps.srcPath)
502 sb.WriteString(fmt.Sprintf("cp %s %s\n", ps.srcPath, destPath))
503 } else {
504 sb.WriteString(fmt.Sprintf("ln -sf %s %s\n", ps.symlinkTarget, destPath))
505 }
506 if ps.executable {
507 sb.WriteString(fmt.Sprintf("chmod a+x %s\n", destPath))
508 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900509 }
510 }
511
Jeongik Cha76e677f2023-12-21 16:39:15 +0900512 WriteExecutableFileRuleVerbatim(ctx, preparerPath, sb.String())
513
Dan Willemsen9fe14102021-07-13 21:52:04 -0700514 return entries
515}
516
517// See PackageModule.CopyDepsToZip
Jooyung Hana8834282022-03-25 11:40:12 +0900518func (p *PackagingBase) CopyDepsToZip(ctx ModuleContext, specs map[string]PackagingSpec, zipOut WritablePath) (entries []string) {
Dan Willemsen9fe14102021-07-13 21:52:04 -0700519 builder := NewRuleBuilder(pctx, ctx)
520
521 dir := PathForModuleOut(ctx, ".zip")
522 builder.Command().Text("rm").Flag("-rf").Text(dir.String())
523 builder.Command().Text("mkdir").Flag("-p").Text(dir.String())
Jooyung Hana8834282022-03-25 11:40:12 +0900524 entries = p.CopySpecsToDir(ctx, builder, specs, dir)
Dan Willemsen9fe14102021-07-13 21:52:04 -0700525
Jiyong Parkdda8f692020-11-09 18:38:48 +0900526 builder.Command().
Colin Crossf1a035e2020-11-16 17:32:30 -0800527 BuiltTool("soong_zip").
Jiyong Parkdda8f692020-11-09 18:38:48 +0900528 FlagWithOutput("-o ", zipOut).
529 FlagWithArg("-C ", dir.String()).
530 Flag("-L 0"). // no compression because this will be unzipped soon
531 FlagWithArg("-D ", dir.String())
532 builder.Command().Text("rm").Flag("-rf").Text(dir.String())
533
Colin Crossf1a035e2020-11-16 17:32:30 -0800534 builder.Build("zip_deps", fmt.Sprintf("Zipping deps for %s", ctx.ModuleName()))
Jiyong Parkdda8f692020-11-09 18:38:48 +0900535 return entries
536}