#include "gn/generated_file_target_generator.h"
#include "gn/err.h"
#include "gn/filesystem_utils.h"
#include "gn/parse_tree.h"
#include "gn/scope.h"
#include "gn/target.h"
#include "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;
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(
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 metadata 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;
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;
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()) {
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 (value &&
!IsMetadataCollectionTarget(variables::kWalkKeys, value->origin()))
return false;
if (!value) {
target_->walk_keys().push_back("");
return true;
}
if (!value->VerifyTypeIs(Value::LIST, err_))
return false;
for (const Value& v : value->list_value()) {
if (!v.VerifyTypeIs(Value::STRING, err_))
return false;
target_->walk_keys().push_back(v.string_value());
}
return true;
}