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 |