| // 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 std::string_view& variable, |
| const ParseNode* origin) { |
| if (contents_defined_) { |
| *err_ = |
| Err(origin, std::string(variable) + " won't be used.", |
| "\"contents\" is defined on this target, and so setting " + |
| std::string(variable) + |
| " 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; |
| } |