blob: 18af1ab4fe98d6a4e6f2a2a8bdfa8e7c761ce138 [file] [log] [blame]
// 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 "gn/bundle_data_target_generator.h"
#include "gn/parse_tree.h"
#include "gn/scope.h"
#include "gn/substitution_type.h"
#include "gn/target.h"
#include "gn/value.h"
#include "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 (!FillProductType())
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 output.",
"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 (const Substitution* type : outputs.required_types()) {
if (!IsValidBundleDataSubstitution(type)) {
*err_ = Err(value->origin(), "Invalid substitution type.",
"The substitution " + std::string(type->name) +
" 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::FillProductType() {
const Value* value = scope_->GetValue(variables::kProductType, true);
if (!value)
return true;
if (!value->VerifyTypeIs(Value::STRING, err_))
return false;
target_->bundle_data().product_type().assign(value->string_value());
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;
}