168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// found in the LICENSE file.
468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/build_settings.h"
668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/filesystem_utils.h"
768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/functions.h"
868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/parse_tree.h"
968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/scope.h"
1068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/settings.h"
1168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/source_dir.h"
1268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/source_file.h"
1368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/value.h"
1468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace functions {
1668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace {
1868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// We want the output to match the input in terms of ending in a slash or not.
2068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Through all the transformations, these can get added or removed in various
2168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// cases.
2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void MakeSlashEndingMatchInput(const std::string& input, std::string* output) {
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (EndsWithSlash(input)) {
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!EndsWithSlash(*output))  // Preserve same slash type as input.
2568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      output->push_back(input[input.size() - 1]);
2668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else {
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (EndsWithSlash(*output))
2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      output->resize(output->size() - 1);
2968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
3068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
3168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Returns true if the given value looks like a directory, otherwise we'll
3368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// assume it's a file.
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool ValueLooksLikeDir(const std::string& value) {
3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (value.empty())
3668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return true;
3768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t value_size = value.size();
3868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Count the number of dots at the end of the string.
4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t num_dots = 0;
4168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  while (num_dots < value_size && value[value_size - num_dots - 1] == '.')
4268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    num_dots++;
4368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
4468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (num_dots == value.size())
4568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return true;  // String is all dots.
4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (IsSlash(value[value_size - num_dots - 1]))
4868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return true;  // String is a [back]slash followed by 0 or more dots.
4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Anything else.
5168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return false;
5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
5368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)Value ConvertOnePath(const Scope* scope,
5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     const FunctionCallNode* function,
5668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     const Value& value,
5768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     const SourceDir& from_dir,
5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     const SourceDir& to_dir,
5968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     bool convert_to_system_absolute,
6068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     Err* err) {
6168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  Value result;  // Ensure return value optimization.
6268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!value.VerifyTypeIs(Value::STRING, err))
6468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return result;
6568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const std::string& string_value = value.string_value();
6668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool looks_like_dir = ValueLooksLikeDir(string_value);
6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // System-absolute output special case.
7068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (convert_to_system_absolute) {
7168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    base::FilePath system_path;
7268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (looks_like_dir) {
7368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      system_path = scope->settings()->build_settings()->GetFullPath(
7468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          from_dir.ResolveRelativeDir(string_value));
7568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    } else {
7668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      system_path = scope->settings()->build_settings()->GetFullPath(
7768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          from_dir.ResolveRelativeFile(string_value));
7868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
7968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    result = Value(function, FilePathToUTF8(system_path));
8068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (looks_like_dir)
8168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      MakeSlashEndingMatchInput(string_value, &result.string_value());
8268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return result;
8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
8468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
8568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (from_dir.is_system_absolute() || to_dir.is_system_absolute()) {
8668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    *err = Err(function, "System-absolute directories are not supported for "
8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        "the source or dest dir for rebase_path. It would be nice to add this "
8868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        "if you're so inclined!");
8968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return result;
9068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
9168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
9268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  result = Value(function, Value::STRING);
9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (looks_like_dir) {
9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    result.string_value() = RebaseSourceAbsolutePath(
9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        from_dir.ResolveRelativeDir(string_value).value(),
9668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        to_dir);
9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    MakeSlashEndingMatchInput(string_value, &result.string_value());
9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else {
9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    result.string_value() = RebaseSourceAbsolutePath(
10068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        from_dir.ResolveRelativeFile(string_value).value(),
10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        to_dir);
10268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return result;
10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
10668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}  // namespace
10868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
10968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kRebasePath[] = "rebase_path";
110e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst char kRebasePath_HelpShort[] =
111e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    "rebase_path: Rebase a file or directory to another location.";
11268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kRebasePath_Help[] =
11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "rebase_path: Rebase a file or directory to another location.\n"
11468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "  converted = rebase_path(input,\n"
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "                          new_base = \"\",\n"
117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "                          current_base = \".\")\n"
11868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
11968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  Takes a string argument representing a file name, or a list of such\n"
12068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  strings and converts it/them to be relative to a different base\n"
12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  directory.\n"
12268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
12368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  When invoking the compiler or scripts, GN will automatically convert\n"
12468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  sources and include directories to be relative to the build directory.\n"
12568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  However, if you're passing files directly in the \"args\" array or\n"
12668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  doing other manual manipulations where GN doesn't know something is\n"
12768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  a file name, you will need to convert paths to be relative to what\n"
12868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  your tool is expecting.\n"
12968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
13068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  The common case is to use this to convert paths relative to the\n"
13168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  current directory to be relative to the build directory (which will\n"
13268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  be the current directory when executing scripts).\n"
13368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
13446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "  If you want to convert a file path to be source-absolute (that is,\n"
13546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "  beginning with a double slash like \"//foo/bar\"), you should use\n"
13646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "  the get_path_info() function. This function won't work because it will\n"
13746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "  always make relative paths, and it needs to support making paths\n"
13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "  relative to the source root, so can't also generate source-absolute\n"
13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "  paths without more special-cases.\n"
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    "\n"
141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "Arguments:\n"
14268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
14368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  input\n"
14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "      A string or list of strings representing file or directory names\n"
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      These can be relative paths (\"foo/bar.txt\"), system absolute\n"
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      paths (\"/foo/bar.txt\"), or source absolute paths\n"
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      (\"//foo/bar.txt\").\n"
14868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
14968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  new_base\n"
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      The directory to convert the paths to be relative to. This can be\n"
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      an absolute path or a relative path (which will be treated\n"
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      as being relative to the current BUILD-file's directory).\n"
15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      As a special case, if new_base is the empty string (the default),\n"
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      all paths will be converted to system-absolute native style paths\n"
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      with system path separators. This is useful for invoking external\n"
15768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "      programs.\n"
15868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "  current_base\n"
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      Directory representing the base for relative paths in the input.\n"
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      If this is not an absolute path, it will be treated as being\n"
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      relative to the current build file. Use \".\" (the default) to\n"
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      convert paths from the current BUILD-file's directory.\n"
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "\n"
16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "      On Posix systems there are no path separator transformations\n"
16668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "      applied. If the new_base is empty (specifying absolute output)\n"
16768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "      this parameter should not be supplied since paths will always be\n"
16868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "      converted,\n"
16968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
17068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "Return value\n"
17168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
17268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  The return value will be the same type as the input value (either a\n"
17368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  string or a list of strings). All relative and source-absolute file\n"
17468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  names will be converted to be relative to the requested output\n"
17568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  System-absolute paths will be unchanged.\n"
17668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
17768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "Example\n"
17868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
17968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  # Convert a file in the current directory to be relative to the build\n"
18068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  # directory (the current dir when executing compilers and scripts).\n"
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "  foo = rebase_path(\"myfile.txt\", root_build_dir)\n"
18268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  # might produce \"../../project/myfile.txt\".\n"
18368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
18468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  # Convert a file to be system absolute:\n"
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "  foo = rebase_path(\"myfile.txt\")\n"
18668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  # Might produce \"D:\\source\\project\\myfile.txt\" on Windows or\n"
18768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  # \"/home/you/source/project/myfile.txt\" on Linux.\n"
18868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
18968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  # Convert a file's path separators from forward slashes to system\n"
19068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  # slashes.\n"
19168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  foo = rebase_path(\"source/myfile.txt\", \".\", \".\", \"to_system\")\n"
19268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
19368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  # Typical usage for converting to the build directory for a script.\n"
19423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    "  action(\"myscript\") {\n"
19568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "    # Don't convert sources, GN will automatically convert these to be\n"
19668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "    # relative to the build directory when it contructs the command\n"
19768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "    # line for your script.\n"
19868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "    sources = [ \"foo.txt\", \"bar.txt\" ]\n"
19968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "\n"
20068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "    # Extra file args passed manually need to be explicitly converted\n"
20168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "    # to be relative to the build directory:\n"
20268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "    args = [\n"
20368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "      \"--data\",\n"
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      rebase_path(\"//mything/data/input.dat\", root_build_dir),\n"
20568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "      \"--rel\",\n"
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "      rebase_path(\"relative_path.txt\", root_build_dir)\n"
20723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    "    ] + sources\n"
20868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    "  }\n";
20968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
21068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)Value RunRebasePath(Scope* scope,
21168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                    const FunctionCallNode* function,
21268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                    const std::vector<Value>& args,
21368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                    Err* err) {
21468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  Value result;
21568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Argument indices.
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const size_t kArgIndexInputs = 0;
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const size_t kArgIndexDest = 1;
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const size_t kArgIndexFrom = 2;
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
22168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Inputs.
222c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (args.size() < 1 || args.size() > 3) {
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *err = Err(function->function(), "Wrong # of arguments for rebase_path.");
22468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return result;
22568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Value& inputs = args[kArgIndexInputs];
22768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
22868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // To path.
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool convert_to_system_absolute = true;
23068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  SourceDir to_dir;
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const SourceDir& current_dir = scope->GetSourceDir();
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (args.size() > kArgIndexDest) {
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!args[kArgIndexDest].VerifyTypeIs(Value::STRING, err))
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return result;
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!args[kArgIndexDest].string_value().empty()) {
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      to_dir =
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          current_dir.ResolveRelativeDir(args[kArgIndexDest].string_value());
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      convert_to_system_absolute = false;
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // From path.
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SourceDir from_dir;
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (args.size() > kArgIndexFrom) {
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!args[kArgIndexFrom].VerifyTypeIs(Value::STRING, err))
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return result;
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    from_dir =
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        current_dir.ResolveRelativeDir(args[kArgIndexFrom].string_value());
24968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else {
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Default to current directory if unspecified.
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    from_dir = current_dir;
25268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
25368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
25468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Path conversion.
25568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (inputs.type() == Value::STRING) {
25668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return ConvertOnePath(scope, function, inputs,
257c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                          from_dir, to_dir, convert_to_system_absolute, err);
25868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
25968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else if (inputs.type() == Value::LIST) {
26068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    result = Value(function, Value::LIST);
26168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    result.list_value().reserve(inputs.list_value().size());
26268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
26368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    for (size_t i = 0; i < inputs.list_value().size(); i++) {
26468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      result.list_value().push_back(
26568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          ConvertOnePath(scope, function, inputs.list_value()[i],
266c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                         from_dir, to_dir, convert_to_system_absolute, err));
26768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      if (err->has_error()) {
26868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        result = Value();
26968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        return result;
27068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      }
27168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
27268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return result;
27368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
27468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
27568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  *err = Err(function->function(),
27668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)             "rebase_path requires a list or a string.");
27768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return result;
27868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
27968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
28068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}  // namespace functions
281