|  | // 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 "tools/gn/bundle_data_target_generator.h" | 
|  |  | 
|  | #include "tools/gn/parse_tree.h" | 
|  | #include "tools/gn/scope.h" | 
|  | #include "tools/gn/substitution_type.h" | 
|  | #include "tools/gn/target.h" | 
|  | #include "tools/gn/value.h" | 
|  | #include "tools/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 (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 ouput.", | 
|  | "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 (SubstitutionType type : outputs.required_types()) { | 
|  | if (!IsValidBundleDataSubstitution(type)) { | 
|  | *err_ = Err(value->origin(), "Invalid substitution type.", | 
|  | "The substitution " + std::string(kSubstitutionNames[type]) + | 
|  | " 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::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; | 
|  | } |