16d528ed9Sopenharmony_ci// Copyright 2018 The Chromium Authors. All rights reserved.
26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
36d528ed9Sopenharmony_ci// found in the LICENSE file.
46d528ed9Sopenharmony_ci
56d528ed9Sopenharmony_ci#include "gn/generated_file_target_generator.h"
66d528ed9Sopenharmony_ci
76d528ed9Sopenharmony_ci#include "gn/err.h"
86d528ed9Sopenharmony_ci#include "gn/filesystem_utils.h"
96d528ed9Sopenharmony_ci#include "gn/parse_tree.h"
106d528ed9Sopenharmony_ci#include "gn/scope.h"
116d528ed9Sopenharmony_ci#include "gn/target.h"
126d528ed9Sopenharmony_ci#include "gn/variables.h"
136d528ed9Sopenharmony_ci
146d528ed9Sopenharmony_ciGeneratedFileTargetGenerator::GeneratedFileTargetGenerator(
156d528ed9Sopenharmony_ci    Target* target,
166d528ed9Sopenharmony_ci    Scope* scope,
176d528ed9Sopenharmony_ci    const FunctionCallNode* function_call,
186d528ed9Sopenharmony_ci    Target::OutputType type,
196d528ed9Sopenharmony_ci    Err* err)
206d528ed9Sopenharmony_ci    : TargetGenerator(target, scope, function_call, err), output_type_(type) {}
216d528ed9Sopenharmony_ci
226d528ed9Sopenharmony_ciGeneratedFileTargetGenerator::~GeneratedFileTargetGenerator() = default;
236d528ed9Sopenharmony_ci
246d528ed9Sopenharmony_civoid GeneratedFileTargetGenerator::DoRun() {
256d528ed9Sopenharmony_ci  target_->set_output_type(output_type_);
266d528ed9Sopenharmony_ci
276d528ed9Sopenharmony_ci  if (!FillOutputs(false))
286d528ed9Sopenharmony_ci    return;
296d528ed9Sopenharmony_ci  if (target_->action_values().outputs().list().size() != 1) {
306d528ed9Sopenharmony_ci    *err_ = Err(
316d528ed9Sopenharmony_ci        function_call_, "generated_file target must have exactly one output.",
326d528ed9Sopenharmony_ci        "You must specify exactly one value in the \"outputs\" array for the "
336d528ed9Sopenharmony_ci        "destination of the write\n(see \"gn help generated_file\").");
346d528ed9Sopenharmony_ci    return;
356d528ed9Sopenharmony_ci  }
366d528ed9Sopenharmony_ci
376d528ed9Sopenharmony_ci  if (!FillContents())
386d528ed9Sopenharmony_ci    return;
396d528ed9Sopenharmony_ci  if (!FillDataKeys())
406d528ed9Sopenharmony_ci    return;
416d528ed9Sopenharmony_ci
426d528ed9Sopenharmony_ci  // One of data and data_keys should be defined.
436d528ed9Sopenharmony_ci  if (!contents_defined_ && !data_keys_defined_) {
446d528ed9Sopenharmony_ci    *err_ = Err(
456d528ed9Sopenharmony_ci        function_call_, "Either contents or data_keys should be set.",
466d528ed9Sopenharmony_ci        "The generated_file target requires either the \"contents\" variable "
476d528ed9Sopenharmony_ci        "or the \"data_keys\" variable be set. See \"gn help "
486d528ed9Sopenharmony_ci        "generated_file\".");
496d528ed9Sopenharmony_ci    return;
506d528ed9Sopenharmony_ci  }
516d528ed9Sopenharmony_ci
526d528ed9Sopenharmony_ci  if (!FillRebase())
536d528ed9Sopenharmony_ci    return;
546d528ed9Sopenharmony_ci  if (!FillWalkKeys())
556d528ed9Sopenharmony_ci    return;
566d528ed9Sopenharmony_ci
576d528ed9Sopenharmony_ci  if (!FillOutputConversion())
586d528ed9Sopenharmony_ci    return;
596d528ed9Sopenharmony_ci}
606d528ed9Sopenharmony_ci
616d528ed9Sopenharmony_cibool GeneratedFileTargetGenerator::FillContents() {
626d528ed9Sopenharmony_ci  const Value* value = scope_->GetValue(variables::kWriteValueContents, true);
636d528ed9Sopenharmony_ci  if (!value)
646d528ed9Sopenharmony_ci    return true;
656d528ed9Sopenharmony_ci  target_->set_contents(*value);
666d528ed9Sopenharmony_ci  contents_defined_ = true;
676d528ed9Sopenharmony_ci  return true;
686d528ed9Sopenharmony_ci}
696d528ed9Sopenharmony_ci
706d528ed9Sopenharmony_cibool GeneratedFileTargetGenerator::IsMetadataCollectionTarget(
716d528ed9Sopenharmony_ci    std::string_view variable,
726d528ed9Sopenharmony_ci    const ParseNode* origin) {
736d528ed9Sopenharmony_ci  if (contents_defined_) {
746d528ed9Sopenharmony_ci    *err_ =
756d528ed9Sopenharmony_ci        Err(origin, std::string(variable) + " won't be used.",
766d528ed9Sopenharmony_ci            "\"contents\" is defined on this target, and so setting " +
776d528ed9Sopenharmony_ci                std::string(variable) +
786d528ed9Sopenharmony_ci                " will have no effect as no metadata collection will occur.");
796d528ed9Sopenharmony_ci    return false;
806d528ed9Sopenharmony_ci  }
816d528ed9Sopenharmony_ci  return true;
826d528ed9Sopenharmony_ci}
836d528ed9Sopenharmony_ci
846d528ed9Sopenharmony_cibool GeneratedFileTargetGenerator::FillOutputConversion() {
856d528ed9Sopenharmony_ci  const Value* value =
866d528ed9Sopenharmony_ci      scope_->GetValue(variables::kWriteOutputConversion, true);
876d528ed9Sopenharmony_ci  if (!value) {
886d528ed9Sopenharmony_ci    target_->set_output_conversion(Value(function_call_, ""));
896d528ed9Sopenharmony_ci    return true;
906d528ed9Sopenharmony_ci  }
916d528ed9Sopenharmony_ci  if (!value->VerifyTypeIs(Value::STRING, err_))
926d528ed9Sopenharmony_ci    return false;
936d528ed9Sopenharmony_ci
946d528ed9Sopenharmony_ci  // Otherwise, the value itself will be checked when the conversion is done.
956d528ed9Sopenharmony_ci  target_->set_output_conversion(*value);
966d528ed9Sopenharmony_ci  return true;
976d528ed9Sopenharmony_ci}
986d528ed9Sopenharmony_ci
996d528ed9Sopenharmony_cibool GeneratedFileTargetGenerator::FillRebase() {
1006d528ed9Sopenharmony_ci  const Value* value = scope_->GetValue(variables::kRebase, true);
1016d528ed9Sopenharmony_ci  if (!value)
1026d528ed9Sopenharmony_ci    return true;
1036d528ed9Sopenharmony_ci  if (!IsMetadataCollectionTarget(variables::kRebase, value->origin()))
1046d528ed9Sopenharmony_ci    return false;
1056d528ed9Sopenharmony_ci  if (!value->VerifyTypeIs(Value::STRING, err_))
1066d528ed9Sopenharmony_ci    return false;
1076d528ed9Sopenharmony_ci
1086d528ed9Sopenharmony_ci  if (value->string_value().empty())
1096d528ed9Sopenharmony_ci    return true;  // Treat empty string as the default and do nothing.
1106d528ed9Sopenharmony_ci
1116d528ed9Sopenharmony_ci  const BuildSettings* build_settings = scope_->settings()->build_settings();
1126d528ed9Sopenharmony_ci  SourceDir dir = scope_->GetSourceDir().ResolveRelativeDir(
1136d528ed9Sopenharmony_ci      *value, err_, build_settings->root_path_utf8());
1146d528ed9Sopenharmony_ci  if (err_->has_error())
1156d528ed9Sopenharmony_ci    return false;
1166d528ed9Sopenharmony_ci
1176d528ed9Sopenharmony_ci  target_->set_rebase(dir);
1186d528ed9Sopenharmony_ci  return true;
1196d528ed9Sopenharmony_ci}
1206d528ed9Sopenharmony_ci
1216d528ed9Sopenharmony_cibool GeneratedFileTargetGenerator::FillDataKeys() {
1226d528ed9Sopenharmony_ci  const Value* value = scope_->GetValue(variables::kDataKeys, true);
1236d528ed9Sopenharmony_ci  if (!value)
1246d528ed9Sopenharmony_ci    return true;
1256d528ed9Sopenharmony_ci  if (!IsMetadataCollectionTarget(variables::kDataKeys, value->origin()))
1266d528ed9Sopenharmony_ci    return false;
1276d528ed9Sopenharmony_ci  if (!value->VerifyTypeIs(Value::LIST, err_))
1286d528ed9Sopenharmony_ci    return false;
1296d528ed9Sopenharmony_ci
1306d528ed9Sopenharmony_ci  for (const Value& v : value->list_value()) {
1316d528ed9Sopenharmony_ci    // Keys must be strings.
1326d528ed9Sopenharmony_ci    if (!v.VerifyTypeIs(Value::STRING, err_))
1336d528ed9Sopenharmony_ci      return false;
1346d528ed9Sopenharmony_ci    target_->data_keys().push_back(v.string_value());
1356d528ed9Sopenharmony_ci  }
1366d528ed9Sopenharmony_ci
1376d528ed9Sopenharmony_ci  data_keys_defined_ = true;
1386d528ed9Sopenharmony_ci  return true;
1396d528ed9Sopenharmony_ci}
1406d528ed9Sopenharmony_ci
1416d528ed9Sopenharmony_cibool GeneratedFileTargetGenerator::FillWalkKeys() {
1426d528ed9Sopenharmony_ci  const Value* value = scope_->GetValue(variables::kWalkKeys, true);
1436d528ed9Sopenharmony_ci  // If we define this and contents, that's an error.
1446d528ed9Sopenharmony_ci  if (value &&
1456d528ed9Sopenharmony_ci      !IsMetadataCollectionTarget(variables::kWalkKeys, value->origin()))
1466d528ed9Sopenharmony_ci    return false;
1476d528ed9Sopenharmony_ci
1486d528ed9Sopenharmony_ci  // If we don't define it, we want the default value which is a list
1496d528ed9Sopenharmony_ci  // containing the empty string.
1506d528ed9Sopenharmony_ci  if (!value) {
1516d528ed9Sopenharmony_ci    target_->walk_keys().push_back("");
1526d528ed9Sopenharmony_ci    return true;
1536d528ed9Sopenharmony_ci  }
1546d528ed9Sopenharmony_ci
1556d528ed9Sopenharmony_ci  // Otherwise, pull and validate the specified value.
1566d528ed9Sopenharmony_ci  if (!value->VerifyTypeIs(Value::LIST, err_))
1576d528ed9Sopenharmony_ci    return false;
1586d528ed9Sopenharmony_ci  for (const Value& v : value->list_value()) {
1596d528ed9Sopenharmony_ci    // Keys must be strings.
1606d528ed9Sopenharmony_ci    if (!v.VerifyTypeIs(Value::STRING, err_))
1616d528ed9Sopenharmony_ci      return false;
1626d528ed9Sopenharmony_ci    target_->walk_keys().push_back(v.string_value());
1636d528ed9Sopenharmony_ci  }
1646d528ed9Sopenharmony_ci  return true;
1656d528ed9Sopenharmony_ci}
166