1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "gn/bundle_data.h"
6
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "gn/filesystem_utils.h"
10 #include "gn/label_pattern.h"
11 #include "gn/output_file.h"
12 #include "gn/settings.h"
13 #include "gn/substitution_writer.h"
14 #include "gn/target.h"
15
16 BundleData::BundleData() = default;
17
18 BundleData::~BundleData() = default;
19
GetAssetsCatalogDirectory(const SourceFile & source)20 SourceFile BundleData::GetAssetsCatalogDirectory(const SourceFile& source) {
21 SourceFile assets_catalog_dir;
22 std::string_view path = source.value();
23 while (!path.empty()) {
24 if (base::ends_with(path, ".xcassets")) {
25 assets_catalog_dir = SourceFile(path);
26 }
27
28 const auto sep = path.find_last_of("/\\");
29 if (sep == std::string_view::npos) {
30 break;
31 }
32
33 path = path.substr(0, sep);
34 }
35 return assets_catalog_dir;
36 }
37
AddBundleData(const Target * target,bool is_create_bundle)38 void BundleData::AddBundleData(const Target* target, bool is_create_bundle) {
39 DCHECK_EQ(target->output_type(), Target::BUNDLE_DATA);
40 for (const auto& pattern : bundle_deps_filter_) {
41 if (pattern.Matches(target->label()))
42 return;
43 }
44 if (transparent_) {
45 DCHECK(is_create_bundle);
46 if (target->bundle_data().product_type() == product_type_) {
47 bundle_deps_.push_back(target);
48 } else {
49 forwarded_bundle_deps_.push_back(target);
50 }
51 return;
52 }
53 if (is_create_bundle) {
54 bundle_deps_.push_back(target);
55 }
56 forwarded_bundle_deps_.push_back(target);
57 }
58
OnTargetResolved(Target * owning_target)59 void BundleData::OnTargetResolved(Target* owning_target) {
60 // Only initialize file_rules_ and assets_catalog_sources for "create_bundle"
61 // target (properties are only used by those targets).
62 if (owning_target->output_type() != Target::CREATE_BUNDLE)
63 return;
64
65 UniqueVector<const Target*> assets_catalog_deps;
66 UniqueVector<SourceFile> assets_catalog_sources;
67
68 for (const Target* target : bundle_deps_) {
69 SourceFiles file_rule_sources;
70 for (const SourceFile& source_file : target->sources()) {
71 SourceFile assets_catalog_dir = GetAssetsCatalogDirectory(source_file);
72 if (!assets_catalog_dir.is_null()) {
73 assets_catalog_sources.push_back(assets_catalog_dir);
74 assets_catalog_deps.push_back(target);
75 } else {
76 file_rule_sources.push_back(source_file);
77 }
78 }
79
80 if (!file_rule_sources.empty()) {
81 DCHECK_EQ(target->action_values().outputs().list().size(), 1u);
82 file_rules_.push_back(
83 BundleFileRule(target, file_rule_sources,
84 target->action_values().outputs().list()[0]));
85 }
86 }
87
88 assets_catalog_deps_.insert(assets_catalog_deps_.end(),
89 assets_catalog_deps.begin(),
90 assets_catalog_deps.end());
91 assets_catalog_sources_.insert(assets_catalog_sources_.end(),
92 assets_catalog_sources.begin(),
93 assets_catalog_sources.end());
94
95 GetSourceFiles(&owning_target->sources());
96 }
97
GetSourceFiles(SourceFiles * sources) const98 void BundleData::GetSourceFiles(SourceFiles* sources) const {
99 for (const BundleFileRule& file_rule : file_rules_) {
100 sources->insert(sources->end(), file_rule.sources().begin(),
101 file_rule.sources().end());
102 }
103 sources->insert(sources->end(), assets_catalog_sources_.begin(),
104 assets_catalog_sources_.end());
105 if (!post_processing_script_.is_null()) {
106 sources->insert(sources->end(), post_processing_sources_.begin(),
107 post_processing_sources_.end());
108 }
109 }
110
GetOutputFiles(const Settings * settings,const Target * target,OutputFiles * outputs,Err * err) const111 bool BundleData::GetOutputFiles(const Settings* settings,
112 const Target* target,
113 OutputFiles* outputs,
114 Err* err) const {
115 SourceFiles outputs_as_sources;
116 if (!GetOutputsAsSourceFiles(settings, target, &outputs_as_sources, err))
117 return false;
118 for (const SourceFile& source_file : outputs_as_sources)
119 outputs->push_back(OutputFile(settings->build_settings(), source_file));
120 return true;
121 }
122
GetOutputsAsSourceFiles(const Settings * settings,const Target * target,SourceFiles * outputs_as_source,Err * err) const123 bool BundleData::GetOutputsAsSourceFiles(const Settings* settings,
124 const Target* target,
125 SourceFiles* outputs_as_source,
126 Err* err) const {
127 for (const BundleFileRule& file_rule : file_rules_) {
128 for (const SourceFile& source : file_rule.sources()) {
129 SourceFile expanded_source_file;
130 if (!file_rule.ApplyPatternToSource(settings, target, *this, source,
131 &expanded_source_file, err))
132 return false;
133 outputs_as_source->push_back(expanded_source_file);
134 }
135 }
136
137 if (!assets_catalog_sources_.empty())
138 outputs_as_source->push_back(GetCompiledAssetCatalogPath());
139
140 if (!partial_info_plist_.is_null())
141 outputs_as_source->push_back(partial_info_plist_);
142
143 if (!post_processing_script_.is_null()) {
144 std::vector<SourceFile> post_processing_output_files;
145 SubstitutionWriter::GetListAsSourceFiles(post_processing_outputs_,
146 &post_processing_output_files);
147 outputs_as_source->insert(outputs_as_source->end(),
148 post_processing_output_files.begin(),
149 post_processing_output_files.end());
150 }
151
152 if (!root_dir_.is_null())
153 outputs_as_source->push_back(GetBundleRootDirOutput(settings));
154
155 return true;
156 }
157
GetCompiledAssetCatalogPath() const158 SourceFile BundleData::GetCompiledAssetCatalogPath() const {
159 DCHECK(!assets_catalog_sources_.empty());
160 std::string assets_car_path = resources_dir_.value() + "/Assets.car";
161 return SourceFile(std::move(assets_car_path));
162 }
163
GetBundleRootDirOutput(const Settings * settings) const164 SourceFile BundleData::GetBundleRootDirOutput(const Settings* settings) const {
165 std::string root_dir_value = root_dir().value();
166 size_t last_separator = root_dir_value.rfind('/');
167 if (last_separator != std::string::npos)
168 root_dir_value = root_dir_value.substr(0, last_separator);
169
170 return SourceFile(std::move(root_dir_value));
171 }
172
GetBundleRootDirOutputAsDir(const Settings * settings) const173 SourceDir BundleData::GetBundleRootDirOutputAsDir(
174 const Settings* settings) const {
175 return SourceDir(GetBundleRootDirOutput(settings).value());
176 }
177
GetBundleDir(const Settings * settings) const178 SourceDir BundleData::GetBundleDir(const Settings* settings) const {
179 return GetBundleRootDirOutput(settings).GetDir();
180 }
181