| // 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; | |
| } |