|  | // Copyright 2018 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/generated_file_target_generator.h" | 
|  |  | 
|  | #include "tools/gn/err.h" | 
|  | #include "tools/gn/filesystem_utils.h" | 
|  | #include "tools/gn/parse_tree.h" | 
|  | #include "tools/gn/scope.h" | 
|  | #include "tools/gn/target.h" | 
|  | #include "tools/gn/variables.h" | 
|  |  | 
|  | GeneratedFileTargetGenerator::GeneratedFileTargetGenerator( | 
|  | Target* target, | 
|  | Scope* scope, | 
|  | const FunctionCallNode* function_call, | 
|  | Target::OutputType type, | 
|  | Err* err) | 
|  | : TargetGenerator(target, scope, function_call, err), output_type_(type) {} | 
|  |  | 
|  | GeneratedFileTargetGenerator::~GeneratedFileTargetGenerator() = default; | 
|  |  | 
|  | void GeneratedFileTargetGenerator::DoRun() { | 
|  | target_->set_output_type(output_type_); | 
|  |  | 
|  | if (!FillOutputs(false)) | 
|  | return; | 
|  | if (target_->action_values().outputs().list().size() != 1) { | 
|  | *err_ = Err( | 
|  | function_call_, "generated_file target must have exactly one output.", | 
|  | "You must specify exactly one value in the \"outputs\" array for the " | 
|  | "destination of the write\n(see \"gn help generated_file\")."); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!FillContents()) | 
|  | return; | 
|  | if (!FillDataKeys()) | 
|  | return; | 
|  |  | 
|  | // One of data and data_keys should be defined. | 
|  | if (!contents_defined_ && !data_keys_defined_) { | 
|  | *err_ = Err( | 
|  | function_call_, "Either contents or data_keys should be set.", | 
|  | "The generated_file target requires either the \"contents\" variable " | 
|  | "or the \"data_keys\" variable be set. See \"gn help " | 
|  | "generated_file\"."); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!FillRebase()) | 
|  | return; | 
|  | if (!FillWalkKeys()) | 
|  | return; | 
|  |  | 
|  | if (!FillOutputConversion()) | 
|  | return; | 
|  | } | 
|  |  | 
|  | bool GeneratedFileTargetGenerator::FillContents() { | 
|  | const Value* value = scope_->GetValue(variables::kWriteValueContents, true); | 
|  | if (!value) | 
|  | return true; | 
|  | target_->set_contents(*value); | 
|  | contents_defined_ = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool GeneratedFileTargetGenerator::IsMetadataCollectionTarget( | 
|  | const base::StringPiece& variable, | 
|  | const ParseNode* origin) { | 
|  | if (contents_defined_) { | 
|  | *err_ = | 
|  | Err(origin, variable.as_string() + " won't be used.", | 
|  | "\"contents\" is defined on this target, and so setting " + | 
|  | variable.as_string() + | 
|  | " will have no effect as no metdata collection will occur."); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool GeneratedFileTargetGenerator::FillOutputConversion() { | 
|  | const Value* value = | 
|  | scope_->GetValue(variables::kWriteOutputConversion, true); | 
|  | if (!value) { | 
|  | target_->set_output_conversion(Value(function_call_, "")); | 
|  | return true; | 
|  | } | 
|  | if (!value->VerifyTypeIs(Value::STRING, err_)) | 
|  | return false; | 
|  |  | 
|  | // Otherwise, the value itself will be checked when the conversion is done. | 
|  | target_->set_output_conversion(*value); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool GeneratedFileTargetGenerator::FillRebase() { | 
|  | const Value* value = scope_->GetValue(variables::kRebase, true); | 
|  | if (!value) | 
|  | return true; | 
|  | if (!IsMetadataCollectionTarget(variables::kRebase, value->origin())) | 
|  | return false; | 
|  | if (!value->VerifyTypeIs(Value::STRING, err_)) | 
|  | return false; | 
|  |  | 
|  | if (value->string_value().empty()) | 
|  | return true;  // Treat empty string as the default and do nothing. | 
|  |  | 
|  | const BuildSettings* build_settings = scope_->settings()->build_settings(); | 
|  | SourceDir dir = scope_->GetSourceDir().ResolveRelativeDir( | 
|  | *value, err_, build_settings->root_path_utf8()); | 
|  | if (err_->has_error()) | 
|  | return false; | 
|  |  | 
|  | target_->set_rebase(dir); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool GeneratedFileTargetGenerator::FillDataKeys() { | 
|  | const Value* value = scope_->GetValue(variables::kDataKeys, true); | 
|  | if (!value) | 
|  | return true; | 
|  | if (!IsMetadataCollectionTarget(variables::kDataKeys, value->origin())) | 
|  | return false; | 
|  | if (!value->VerifyTypeIs(Value::LIST, err_)) | 
|  | return false; | 
|  |  | 
|  | for (const Value& v : value->list_value()) { | 
|  | // Keys must be strings. | 
|  | if (!v.VerifyTypeIs(Value::STRING, err_)) | 
|  | return false; | 
|  | target_->data_keys().push_back(v.string_value()); | 
|  | } | 
|  |  | 
|  | data_keys_defined_ = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool GeneratedFileTargetGenerator::FillWalkKeys() { | 
|  | const Value* value = scope_->GetValue(variables::kWalkKeys, true); | 
|  | // If we define this and contents, that's an error. | 
|  | if (value && | 
|  | !IsMetadataCollectionTarget(variables::kWalkKeys, value->origin())) | 
|  | return false; | 
|  |  | 
|  | // If we don't define it, we want the default value which is a list | 
|  | // containing the empty string. | 
|  | if (!value) { | 
|  | target_->walk_keys().push_back(""); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Otherwise, pull and validate the specified value. | 
|  | if (!value->VerifyTypeIs(Value::LIST, err_)) | 
|  | return false; | 
|  | for (const Value& v : value->list_value()) { | 
|  | // Keys must be strings. | 
|  | if (!v.VerifyTypeIs(Value::STRING, err_)) | 
|  | return false; | 
|  | target_->walk_keys().push_back(v.string_value()); | 
|  | } | 
|  | return true; | 
|  | } |