blob: e8c4ae93015a48b7980c808339867361891df8d1 [file] [log] [blame]
// Copyright (c) 2013 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/source_dir.h"
#include <string>
#include "base/logging.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/source_file.h"
#include "util/build_config.h"
namespace {
void AssertValueSourceDirString(const std::string& s) {
if (!s.empty()) {
#if defined(OS_WIN)
DCHECK(s[0] == '/' ||
(s.size() > 2 && s[0] != '/' && s[1] == ':' && IsSlash(s[2])));
#else
DCHECK(s[0] == '/');
#endif
DCHECK(EndsWithSlash(s)) << s;
}
}
// Validates input value (input_value) and sets proper error message.
// Note: Parameter blame_input is used only for generating error message.
template <typename StringType>
bool ValidateResolveInput(bool as_file,
const Value& blame_input_value,
const StringType& input_value,
Err* err) {
if (as_file) {
// It's an error to resolve an empty string or one that is a directory
// (indicated by a trailing slash) because this is the function that expects
// to return a file.
if (input_value.empty()) {
*err = Err(blame_input_value, "Empty file path.",
"You can't use empty strings as file paths.");
return false;
} else if (input_value[input_value.size() - 1] == '/') {
std::string help = "You specified the path\n ";
help.append(std::string(input_value));
help.append(
"\nand it ends in a slash, indicating you think it's a directory."
"\nBut here you're supposed to be listing a file.");
*err = Err(blame_input_value, "File path ends in a slash.", help);
return false;
}
} else if (input_value.empty()) {
*err = Err(blame_input_value, "Empty directory path.",
"You can't use empty strings as directories.");
return false;
}
return true;
}
} // namespace
SourceDir::SourceDir(const std::string& s) : value_(s) {
if (!EndsWithSlash(value_))
value_.push_back('/');
AssertValueSourceDirString(value_);
}
SourceDir::SourceDir(std::string&& s) : value_(std::move(s)) {
if (!EndsWithSlash(value_))
value_.push_back('/');
AssertValueSourceDirString(value_);
}
template <typename StringType>
std::string SourceDir::ResolveRelativeAs(
bool as_file,
const Value& blame_input_value,
const StringType& input_value,
Err* err,
const std::string_view& source_root) const {
if (!ValidateResolveInput<StringType>(as_file, blame_input_value, input_value,
err)) {
return std::string();
}
return ResolveRelative(input_value, value_, as_file, source_root);
}
SourceFile SourceDir::ResolveRelativeFile(
const Value& p,
Err* err,
const std::string_view& source_root) const {
SourceFile ret;
if (!p.VerifyTypeIs(Value::STRING, err))
return ret;
const std::string& input_string = p.string_value();
if (!ValidateResolveInput<std::string>(true, p, input_string, err))
return ret;
ret.SetValue(ResolveRelative(input_string, value_, true, source_root));
return ret;
}
std::string SourceDir::ResolveRelativeAs(bool as_file,
const Value& v,
Err* err,
const std::string_view& source_root,
const std::string* v_value) const {
if (!v.VerifyTypeIs(Value::STRING, err))
return std::string();
if (!v_value) {
v_value = &v.string_value();
}
std::string result =
ResolveRelativeAs(as_file, v, *v_value, err, source_root);
if (!as_file)
AssertValueSourceDirString(result);
return result;
}
SourceDir SourceDir::ResolveRelativeDir(
const Value& v,
Err* err,
const std::string_view& source_root) const {
if (!v.VerifyTypeIs(Value::STRING, err))
return SourceDir();
return ResolveRelativeDir<std::string>(v, v.string_value(), err, source_root);
}
base::FilePath SourceDir::Resolve(const base::FilePath& source_root) const {
return ResolvePath(value_, false, source_root);
}
// Explicit template instantiation
template std::string SourceDir::ResolveRelativeAs(
bool as_file,
const Value& blame_input_value,
const std::string& input_value,
Err* err,
const std::string_view& source_root) const;
template std::string SourceDir::ResolveRelativeAs(
bool as_file,
const Value& blame_input_value,
const std::string_view& input_value,
Err* err,
const std::string_view& source_root) const;