| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "gn/bundle_data_target_generator.h" |
| |
| #include "gn/parse_tree.h" |
| #include "gn/scope.h" |
| #include "gn/substitution_type.h" |
| #include "gn/target.h" |
| #include "gn/value.h" |
| #include "gn/variables.h" |
| |
| BundleDataTargetGenerator::BundleDataTargetGenerator( |
| Target* target, |
| Scope* scope, |
| const FunctionCallNode* function_call, |
| Err* err) |
| : TargetGenerator(target, scope, function_call, err) {} |
| |
| BundleDataTargetGenerator::~BundleDataTargetGenerator() = default; |
| |
| void BundleDataTargetGenerator::DoRun() { |
| target_->set_output_type(Target::BUNDLE_DATA); |
| |
| if (!FillSources()) |
| return; |
| if (!FillOutputs()) |
| return; |
| if (!FillProductType()) |
| return; |
| |
| if (target_->sources().empty()) { |
| *err_ = Err(function_call_, |
| "Empty sources for bundle_data target." |
| "You have to specify at least one file in the \"sources\"."); |
| return; |
| } |
| if (target_->action_values().outputs().list().size() != 1) { |
| *err_ = Err( |
| function_call_, "Target bundle_data must have exactly one output.", |
| "You must specify exactly one value in the \"output\" array for the" |
| "destination\ninto the generated bundle (see \"gn help bundle_data\"). " |
| "If there are multiple\nsources to copy, use source expansion (see " |
| "\"gn help source_expansion\")."); |
| return; |
| } |
| } |
| |
| bool BundleDataTargetGenerator::FillOutputs() { |
| const Value* value = scope_->GetValue(variables::kOutputs, true); |
| if (!value) |
| return true; |
| |
| SubstitutionList& outputs = target_->action_values().outputs(); |
| if (!outputs.Parse(*value, err_)) |
| return false; |
| |
| // Check the substitutions used are valid for this purpose. |
| for (const Substitution* type : outputs.required_types()) { |
| if (!IsValidBundleDataSubstitution(type)) { |
| *err_ = Err(value->origin(), "Invalid substitution type.", |
| "The substitution " + std::string(type->name) + |
| " isn't valid for something\n" |
| "operating on a bundle_data file such as this."); |
| return false; |
| } |
| } |
| |
| // Validate that outputs are in the bundle. |
| CHECK(outputs.list().size() == value->list_value().size()); |
| for (size_t i = 0; i < outputs.list().size(); i++) { |
| if (!EnsureSubstitutionIsInBundleDir(outputs.list()[i], |
| value->list_value()[i])) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool BundleDataTargetGenerator::FillProductType() { |
| const Value* value = scope_->GetValue(variables::kProductType, true); |
| if (!value) |
| return true; |
| |
| if (!value->VerifyTypeIs(Value::STRING, err_)) |
| return false; |
| |
| target_->bundle_data().product_type().assign(value->string_value()); |
| return true; |
| } |
| |
| bool BundleDataTargetGenerator::EnsureSubstitutionIsInBundleDir( |
| const SubstitutionPattern& pattern, |
| const Value& original_value) { |
| if (pattern.ranges().empty()) { |
| // Pattern is empty, error out (this prevents weirdness below). |
| *err_ = Err(original_value, "This has an empty value in it."); |
| return false; |
| } |
| |
| if (SubstitutionIsInBundleDir(pattern.ranges()[0].type)) |
| return true; |
| |
| *err_ = Err(original_value, "File is not inside bundle directory.", |
| "The given file should be in the output directory. Normally you\n" |
| "would specify {{bundle_resources_dir}} or such substitution."); |
| return false; |
| } |