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_target_generator.h"
6
7 #include "gn/parse_tree.h"
8 #include "gn/scope.h"
9 #include "gn/substitution_type.h"
10 #include "gn/target.h"
11 #include "gn/value.h"
12 #include "gn/variables.h"
13
BundleDataTargetGenerator(Target * target,Scope * scope,const FunctionCallNode * function_call,Err * err)14 BundleDataTargetGenerator::BundleDataTargetGenerator(
15 Target* target,
16 Scope* scope,
17 const FunctionCallNode* function_call,
18 Err* err)
19 : TargetGenerator(target, scope, function_call, err) {}
20
21 BundleDataTargetGenerator::~BundleDataTargetGenerator() = default;
22
DoRun()23 void BundleDataTargetGenerator::DoRun() {
24 target_->set_output_type(Target::BUNDLE_DATA);
25
26 if (!FillSources())
27 return;
28 if (!FillOutputs())
29 return;
30
31 if (target_->sources().empty()) {
32 *err_ = Err(function_call_,
33 "Empty sources for bundle_data target."
34 "You have to specify at least one file in the \"sources\".");
35 return;
36 }
37 if (target_->action_values().outputs().list().size() != 1) {
38 *err_ = Err(
39 function_call_, "Target bundle_data must have exactly one output.",
40 "You must specify exactly one value in the \"output\" array for the"
41 "destination\ninto the generated bundle (see \"gn help bundle_data\"). "
42 "If there are multiple\nsources to copy, use source expansion (see "
43 "\"gn help source_expansion\").");
44 return;
45 }
46 }
47
FillOutputs()48 bool BundleDataTargetGenerator::FillOutputs() {
49 const Value* value = scope_->GetValue(variables::kOutputs, true);
50 if (!value)
51 return true;
52
53 SubstitutionList& outputs = target_->action_values().outputs();
54 if (!outputs.Parse(*value, err_))
55 return false;
56
57 // Check the substitutions used are valid for this purpose.
58 for (const Substitution* type : outputs.required_types()) {
59 if (!IsValidBundleDataSubstitution(type)) {
60 *err_ = Err(value->origin(), "Invalid substitution type.",
61 "The substitution " + std::string(type->name) +
62 " isn't valid for something\n"
63 "operating on a bundle_data file such as this.");
64 return false;
65 }
66 }
67
68 // Validate that outputs are in the bundle.
69 CHECK(outputs.list().size() == value->list_value().size());
70 for (size_t i = 0; i < outputs.list().size(); i++) {
71 if (!EnsureSubstitutionIsInBundleDir(outputs.list()[i],
72 value->list_value()[i]))
73 return false;
74 }
75
76 return true;
77 }
78
EnsureSubstitutionIsInBundleDir(const SubstitutionPattern & pattern,const Value & original_value)79 bool BundleDataTargetGenerator::EnsureSubstitutionIsInBundleDir(
80 const SubstitutionPattern& pattern,
81 const Value& original_value) {
82 if (pattern.ranges().empty()) {
83 // Pattern is empty, error out (this prevents weirdness below).
84 *err_ = Err(original_value, "This has an empty value in it.");
85 return false;
86 }
87
88 if (SubstitutionIsInBundleDir(pattern.ranges()[0].type))
89 return true;
90
91 *err_ = Err(original_value, "File is not inside bundle directory.",
92 "The given file should be in the output directory. Normally you\n"
93 "would specify {{bundle_resources_dir}} or such substitution.");
94 return false;
95 }
96