| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "tools/gn/build_settings.h" | 5 #include "tools/gn/build_settings.h" |
| 6 #include "tools/gn/filesystem_utils.h" | 6 #include "tools/gn/filesystem_utils.h" |
| 7 #include "tools/gn/functions.h" | 7 #include "tools/gn/functions.h" |
| 8 #include "tools/gn/parse_tree.h" | 8 #include "tools/gn/parse_tree.h" |
| 9 #include "tools/gn/scope.h" | 9 #include "tools/gn/scope.h" |
| 10 #include "tools/gn/settings.h" | 10 #include "tools/gn/settings.h" |
| 11 #include "tools/gn/source_dir.h" | 11 #include "tools/gn/source_dir.h" |
| 12 #include "tools/gn/source_file.h" | 12 #include "tools/gn/source_file.h" |
| 13 #include "tools/gn/value.h" | 13 #include "tools/gn/value.h" |
| 14 | 14 |
| 15 namespace functions { | 15 namespace functions { |
| 16 | 16 |
| 17 namespace { | 17 namespace { |
| 18 | 18 |
| 19 enum SeparatorConversion { | |
| 20 SEP_TO_SLASH, // All slashes to forward. | |
| 21 SEP_TO_SYSTEM, // Slashes to system ones. | |
| 22 }; | |
| 23 | |
| 24 // Does the specified path separator conversion in-place. | |
| 25 void ConvertSlashes(std::string* str, SeparatorConversion mode) { | |
| 26 #if defined(OS_WIN) | |
| 27 if (mode == SEP_TO_SYSTEM) | |
| 28 std::replace(str->begin(), str->end(), '/', '\\'); | |
| 29 else | |
| 30 #endif | |
| 31 if (mode == SEP_TO_SLASH) | |
| 32 std::replace(str->begin(), str->end(), '\\', '/'); | |
| 33 } | |
| 34 | |
| 35 // We want the output to match the input in terms of ending in a slash or not. | 19 // We want the output to match the input in terms of ending in a slash or not. |
| 36 // Through all the transformations, these can get added or removed in various | 20 // Through all the transformations, these can get added or removed in various |
| 37 // cases. | 21 // cases. |
| 38 void MakeSlashEndingMatchInput(const std::string& input, std::string* output) { | 22 void MakeSlashEndingMatchInput(const std::string& input, std::string* output) { |
| 39 if (EndsWithSlash(input)) { | 23 if (EndsWithSlash(input)) { |
| 40 if (!EndsWithSlash(*output)) // Preserve same slash type as input. | 24 if (!EndsWithSlash(*output)) // Preserve same slash type as input. |
| 41 output->push_back(input[input.size() - 1]); | 25 output->push_back(input[input.size() - 1]); |
| 42 } else { | 26 } else { |
| 43 if (EndsWithSlash(*output)) | 27 if (EndsWithSlash(*output)) |
| 44 output->resize(output->size() - 1); | 28 output->resize(output->size() - 1); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 66 // Anything else. | 50 // Anything else. |
| 67 return false; | 51 return false; |
| 68 } | 52 } |
| 69 | 53 |
| 70 Value ConvertOnePath(const Scope* scope, | 54 Value ConvertOnePath(const Scope* scope, |
| 71 const FunctionCallNode* function, | 55 const FunctionCallNode* function, |
| 72 const Value& value, | 56 const Value& value, |
| 73 const SourceDir& from_dir, | 57 const SourceDir& from_dir, |
| 74 const SourceDir& to_dir, | 58 const SourceDir& to_dir, |
| 75 bool convert_to_system_absolute, | 59 bool convert_to_system_absolute, |
| 76 SeparatorConversion separator_conversion, | |
| 77 Err* err) { | 60 Err* err) { |
| 78 Value result; // Ensure return value optimization. | 61 Value result; // Ensure return value optimization. |
| 79 | 62 |
| 80 if (!value.VerifyTypeIs(Value::STRING, err)) | 63 if (!value.VerifyTypeIs(Value::STRING, err)) |
| 81 return result; | 64 return result; |
| 82 const std::string& string_value = value.string_value(); | 65 const std::string& string_value = value.string_value(); |
| 83 | 66 |
| 84 bool looks_like_dir = ValueLooksLikeDir(string_value); | 67 bool looks_like_dir = ValueLooksLikeDir(string_value); |
| 85 | 68 |
| 86 // System-absolute output special case. | 69 // System-absolute output special case. |
| 87 if (convert_to_system_absolute) { | 70 if (convert_to_system_absolute) { |
| 88 base::FilePath system_path; | 71 base::FilePath system_path; |
| 89 if (looks_like_dir) { | 72 if (looks_like_dir) { |
| 90 system_path = scope->settings()->build_settings()->GetFullPath( | 73 system_path = scope->settings()->build_settings()->GetFullPath( |
| 91 from_dir.ResolveRelativeDir(string_value)); | 74 from_dir.ResolveRelativeDir(string_value)); |
| 92 } else { | 75 } else { |
| 93 system_path = scope->settings()->build_settings()->GetFullPath( | 76 system_path = scope->settings()->build_settings()->GetFullPath( |
| 94 from_dir.ResolveRelativeFile(string_value)); | 77 from_dir.ResolveRelativeFile(string_value)); |
| 95 } | 78 } |
| 96 result = Value(function, FilePathToUTF8(system_path)); | 79 result = Value(function, FilePathToUTF8(system_path)); |
| 97 if (looks_like_dir) | 80 if (looks_like_dir) |
| 98 MakeSlashEndingMatchInput(string_value, &result.string_value()); | 81 MakeSlashEndingMatchInput(string_value, &result.string_value()); |
| 99 ConvertPathToSystem(&result.string_value()); | |
| 100 return result; | 82 return result; |
| 101 } | 83 } |
| 102 | 84 |
| 103 if (from_dir.is_system_absolute() || to_dir.is_system_absolute()) { | 85 if (from_dir.is_system_absolute() || to_dir.is_system_absolute()) { |
| 104 *err = Err(function, "System-absolute directories are not supported for " | 86 *err = Err(function, "System-absolute directories are not supported for " |
| 105 "the source or dest dir for rebase_path. It would be nice to add this " | 87 "the source or dest dir for rebase_path. It would be nice to add this " |
| 106 "if you're so inclined!"); | 88 "if you're so inclined!"); |
| 107 return result; | 89 return result; |
| 108 } | 90 } |
| 109 | 91 |
| 110 result = Value(function, Value::STRING); | 92 result = Value(function, Value::STRING); |
| 111 if (looks_like_dir) { | 93 if (looks_like_dir) { |
| 112 result.string_value() = RebaseSourceAbsolutePath( | 94 result.string_value() = RebaseSourceAbsolutePath( |
| 113 from_dir.ResolveRelativeDir(string_value).value(), | 95 from_dir.ResolveRelativeDir(string_value).value(), |
| 114 to_dir); | 96 to_dir); |
| 115 MakeSlashEndingMatchInput(string_value, &result.string_value()); | 97 MakeSlashEndingMatchInput(string_value, &result.string_value()); |
| 116 } else { | 98 } else { |
| 117 result.string_value() = RebaseSourceAbsolutePath( | 99 result.string_value() = RebaseSourceAbsolutePath( |
| 118 from_dir.ResolveRelativeFile(string_value).value(), | 100 from_dir.ResolveRelativeFile(string_value).value(), |
| 119 to_dir); | 101 to_dir); |
| 120 } | 102 } |
| 121 | 103 |
| 122 ConvertSlashes(&result.string_value(), separator_conversion); | |
| 123 return result; | 104 return result; |
| 124 } | 105 } |
| 125 | 106 |
| 126 } // namespace | 107 } // namespace |
| 127 | 108 |
| 128 const char kRebasePath[] = "rebase_path"; | 109 const char kRebasePath[] = "rebase_path"; |
| 129 const char kRebasePath_HelpShort[] = | 110 const char kRebasePath_HelpShort[] = |
| 130 "rebase_path: Rebase a file or directory to another location."; | 111 "rebase_path: Rebase a file or directory to another location."; |
| 131 const char kRebasePath_Help[] = | 112 const char kRebasePath_Help[] = |
| 132 "rebase_path: Rebase a file or directory to another location.\n" | 113 "rebase_path: Rebase a file or directory to another location.\n" |
| 133 "\n" | 114 "\n" |
| 134 " converted = rebase_path(input,\n" | 115 " converted = rebase_path(input,\n" |
| 135 " new_base = \"\",\n" | 116 " new_base = \"\",\n" |
| 136 " current_base = \".\",\n" | 117 " current_base = \".\")\n" |
| 137 " path_separators = \"to_slash\")\n" | |
| 138 "\n" | 118 "\n" |
| 139 " Takes a string argument representing a file name, or a list of such\n" | 119 " Takes a string argument representing a file name, or a list of such\n" |
| 140 " strings and converts it/them to be relative to a different base\n" | 120 " strings and converts it/them to be relative to a different base\n" |
| 141 " directory.\n" | 121 " directory.\n" |
| 142 "\n" | 122 "\n" |
| 143 " When invoking the compiler or scripts, GN will automatically convert\n" | 123 " When invoking the compiler or scripts, GN will automatically convert\n" |
| 144 " sources and include directories to be relative to the build directory.\n" | 124 " sources and include directories to be relative to the build directory.\n" |
| 145 " However, if you're passing files directly in the \"args\" array or\n" | 125 " However, if you're passing files directly in the \"args\" array or\n" |
| 146 " doing other manual manipulations where GN doesn't know something is\n" | 126 " doing other manual manipulations where GN doesn't know something is\n" |
| 147 " a file name, you will need to convert paths to be relative to what\n" | 127 " a file name, you will need to convert paths to be relative to what\n" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 168 " all paths will be converted to system-absolute native style paths\n" | 148 " all paths will be converted to system-absolute native style paths\n" |
| 169 " with system path separators. This is useful for invoking external\n" | 149 " with system path separators. This is useful for invoking external\n" |
| 170 " programs.\n" | 150 " programs.\n" |
| 171 "\n" | 151 "\n" |
| 172 " current_base\n" | 152 " current_base\n" |
| 173 " Directory representing the base for relative paths in the input.\n" | 153 " Directory representing the base for relative paths in the input.\n" |
| 174 " If this is not an absolute path, it will be treated as being\n" | 154 " If this is not an absolute path, it will be treated as being\n" |
| 175 " relative to the current build file. Use \".\" (the default) to\n" | 155 " relative to the current build file. Use \".\" (the default) to\n" |
| 176 " convert paths from the current BUILD-file's directory.\n" | 156 " convert paths from the current BUILD-file's directory.\n" |
| 177 "\n" | 157 "\n" |
| 178 " path_separators\n" | |
| 179 " On Windows systems, indicates whether and how path separators\n" | |
| 180 " should be converted as part of the transformation. It can be one\n" | |
| 181 " of the following strings:\n" | |
| 182 " - \"to_slash\" Normalize all types of slashes to forward slashes.\n" | |
| 183 " This is the default if this argument is unspecified.\n" | |
| 184 " - \"to_system\" Convert to the system path separators\n" | |
| 185 " (backslashes on Windows).\n" | |
| 186 "\n" | |
| 187 " On Posix systems there are no path separator transformations\n" | 158 " On Posix systems there are no path separator transformations\n" |
| 188 " applied. If the new_base is empty (specifying absolute output)\n" | 159 " applied. If the new_base is empty (specifying absolute output)\n" |
| 189 " this parameter should not be supplied since paths will always be\n" | 160 " this parameter should not be supplied since paths will always be\n" |
| 190 " converted,\n" | 161 " converted,\n" |
| 191 "\n" | 162 "\n" |
| 192 "Return value\n" | 163 "Return value\n" |
| 193 "\n" | 164 "\n" |
| 194 " The return value will be the same type as the input value (either a\n" | 165 " The return value will be the same type as the input value (either a\n" |
| 195 " string or a list of strings). All relative and source-absolute file\n" | 166 " string or a list of strings). All relative and source-absolute file\n" |
| 196 " names will be converted to be relative to the requested output\n" | 167 " names will be converted to be relative to the requested output\n" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 Value RunRebasePath(Scope* scope, | 203 Value RunRebasePath(Scope* scope, |
| 233 const FunctionCallNode* function, | 204 const FunctionCallNode* function, |
| 234 const std::vector<Value>& args, | 205 const std::vector<Value>& args, |
| 235 Err* err) { | 206 Err* err) { |
| 236 Value result; | 207 Value result; |
| 237 | 208 |
| 238 // Argument indices. | 209 // Argument indices. |
| 239 static const size_t kArgIndexInputs = 0; | 210 static const size_t kArgIndexInputs = 0; |
| 240 static const size_t kArgIndexDest = 1; | 211 static const size_t kArgIndexDest = 1; |
| 241 static const size_t kArgIndexFrom = 2; | 212 static const size_t kArgIndexFrom = 2; |
| 242 static const size_t kArgIndexPathConversion = 3; | |
| 243 | 213 |
| 244 // Inputs. | 214 // Inputs. |
| 245 if (args.size() < 1 || args.size() > 4) { | 215 if (args.size() < 1 || args.size() > 3) { |
| 246 *err = Err(function->function(), "Wrong # of arguments for rebase_path."); | 216 *err = Err(function->function(), "Wrong # of arguments for rebase_path."); |
| 247 return result; | 217 return result; |
| 248 } | 218 } |
| 249 const Value& inputs = args[kArgIndexInputs]; | 219 const Value& inputs = args[kArgIndexInputs]; |
| 250 | 220 |
| 251 // To path. | 221 // To path. |
| 252 bool convert_to_system_absolute = true; | 222 bool convert_to_system_absolute = true; |
| 253 SourceDir to_dir; | 223 SourceDir to_dir; |
| 254 const SourceDir& current_dir = scope->GetSourceDir(); | 224 const SourceDir& current_dir = scope->GetSourceDir(); |
| 255 if (args.size() > kArgIndexDest) { | 225 if (args.size() > kArgIndexDest) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 268 if (!args[kArgIndexFrom].VerifyTypeIs(Value::STRING, err)) | 238 if (!args[kArgIndexFrom].VerifyTypeIs(Value::STRING, err)) |
| 269 return result; | 239 return result; |
| 270 from_dir = | 240 from_dir = |
| 271 current_dir.ResolveRelativeDir(args[kArgIndexFrom].string_value()); | 241 current_dir.ResolveRelativeDir(args[kArgIndexFrom].string_value()); |
| 272 } else { | 242 } else { |
| 273 // Default to current directory if unspecified. | 243 // Default to current directory if unspecified. |
| 274 from_dir = current_dir; | 244 from_dir = current_dir; |
| 275 } | 245 } |
| 276 | 246 |
| 277 // Path conversion. | 247 // Path conversion. |
| 278 SeparatorConversion sep_conversion = SEP_TO_SLASH; | |
| 279 if (args.size() > kArgIndexPathConversion) { | |
| 280 if (convert_to_system_absolute) { | |
| 281 *err = Err(function, "Can't specify slash conversion.", | |
| 282 "You specified absolute system path output by using an empty string " | |
| 283 "for the destination directory on rebase_path(). In this case, you " | |
| 284 "can't specify slash conversion."); | |
| 285 return result; | |
| 286 } | |
| 287 | |
| 288 if (!args[kArgIndexPathConversion].VerifyTypeIs(Value::STRING, err)) | |
| 289 return result; | |
| 290 const std::string& sep_string = | |
| 291 args[kArgIndexPathConversion].string_value(); | |
| 292 if (sep_string == "to_slash") { | |
| 293 sep_conversion = SEP_TO_SLASH; | |
| 294 } else if (sep_string == "to_system") { | |
| 295 sep_conversion = SEP_TO_SYSTEM; | |
| 296 } else { | |
| 297 *err = Err(args[kArgIndexPathConversion], | |
| 298 "Invalid path separator conversion mode.", | |
| 299 "I was expecting \"to_slash\" or \"to_system\" and\n" | |
| 300 "you gave me \"" + args[kArgIndexPathConversion].string_value() + | |
| 301 "\"."); | |
| 302 return result; | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 if (inputs.type() == Value::STRING) { | 248 if (inputs.type() == Value::STRING) { |
| 307 return ConvertOnePath(scope, function, inputs, | 249 return ConvertOnePath(scope, function, inputs, |
| 308 from_dir, to_dir, convert_to_system_absolute, | 250 from_dir, to_dir, convert_to_system_absolute, err); |
| 309 sep_conversion, err); | |
| 310 | 251 |
| 311 } else if (inputs.type() == Value::LIST) { | 252 } else if (inputs.type() == Value::LIST) { |
| 312 result = Value(function, Value::LIST); | 253 result = Value(function, Value::LIST); |
| 313 result.list_value().reserve(inputs.list_value().size()); | 254 result.list_value().reserve(inputs.list_value().size()); |
| 314 | 255 |
| 315 for (size_t i = 0; i < inputs.list_value().size(); i++) { | 256 for (size_t i = 0; i < inputs.list_value().size(); i++) { |
| 316 result.list_value().push_back( | 257 result.list_value().push_back( |
| 317 ConvertOnePath(scope, function, inputs.list_value()[i], | 258 ConvertOnePath(scope, function, inputs.list_value()[i], |
| 318 from_dir, to_dir, convert_to_system_absolute, | 259 from_dir, to_dir, convert_to_system_absolute, err)); |
| 319 sep_conversion, err)); | |
| 320 if (err->has_error()) { | 260 if (err->has_error()) { |
| 321 result = Value(); | 261 result = Value(); |
| 322 return result; | 262 return result; |
| 323 } | 263 } |
| 324 } | 264 } |
| 325 return result; | 265 return result; |
| 326 } | 266 } |
| 327 | 267 |
| 328 *err = Err(function->function(), | 268 *err = Err(function->function(), |
| 329 "rebase_path requires a list or a string."); | 269 "rebase_path requires a list or a string."); |
| 330 return result; | 270 return result; |
| 331 } | 271 } |
| 332 | 272 |
| 333 } // namespace functions | 273 } // namespace functions |
| OLD | NEW |