OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/err.h" | 5 #include "tools/gn/err.h" |
6 #include "tools/gn/functions.h" | 6 #include "tools/gn/functions.h" |
7 #include "tools/gn/parse_tree.h" | 7 #include "tools/gn/parse_tree.h" |
8 #include "tools/gn/scope.h" | 8 #include "tools/gn/scope.h" |
9 | 9 |
10 namespace functions { | 10 namespace functions { |
11 | 11 |
12 namespace { | 12 namespace { |
13 | 13 |
14 void ForwardAllValues(const FunctionCallNode* function, | 14 void ForwardAllValues(const FunctionCallNode* function, |
15 Scope* source, | 15 Scope* source, |
16 Scope* dest, | 16 Scope* dest, |
| 17 const std::set<std::string>& exclusion_set, |
17 Err* err) { | 18 Err* err) { |
18 Scope::MergeOptions options; | 19 Scope::MergeOptions options; |
19 // This function needs to clobber existing for it to be useful. It will be | 20 // This function needs to clobber existing for it to be useful. It will be |
20 // called in a template to forward all values, but there will be some | 21 // called in a template to forward all values, but there will be some |
21 // default stuff like configs set up in both scopes, so it would always | 22 // default stuff like configs set up in both scopes, so it would always |
22 // fail if it didn't clobber. | 23 // fail if it didn't clobber. |
23 options.clobber_existing = true; | 24 options.clobber_existing = true; |
24 options.skip_private_vars = true; | 25 options.skip_private_vars = true; |
25 options.mark_dest_used = false; | 26 options.mark_dest_used = false; |
| 27 options.excluded_values = exclusion_set; |
26 source->NonRecursiveMergeTo(dest, options, function, | 28 source->NonRecursiveMergeTo(dest, options, function, |
27 "source scope", err); | 29 "source scope", err); |
28 source->MarkAllUsed(); | 30 source->MarkAllUsed(); |
29 } | 31 } |
30 | 32 |
31 void ForwardValuesFromList(Scope* source, | 33 void ForwardValuesFromList(Scope* source, |
32 Scope* dest, | 34 Scope* dest, |
33 const std::vector<Value>& list, | 35 const std::vector<Value>& list, |
| 36 const std::set<std::string>& exclusion_set, |
34 Err* err) { | 37 Err* err) { |
35 for (const Value& cur : list) { | 38 for (const Value& cur : list) { |
36 if (!cur.VerifyTypeIs(Value::STRING, err)) | 39 if (!cur.VerifyTypeIs(Value::STRING, err)) |
37 return; | 40 return; |
| 41 if (exclusion_set.find(cur.string_value()) != exclusion_set.end()) |
| 42 continue; |
38 const Value* value = source->GetValue(cur.string_value(), true); | 43 const Value* value = source->GetValue(cur.string_value(), true); |
39 if (value) { | 44 if (value) { |
40 // Use the storage key for the original value rather than the string in | 45 // Use the storage key for the original value rather than the string in |
41 // "cur" because "cur" is a temporary that will be deleted, and Scopes | 46 // "cur" because "cur" is a temporary that will be deleted, and Scopes |
42 // expect a persistent StringPiece (it won't copy). Not doing this will | 47 // expect a persistent StringPiece (it won't copy). Not doing this will |
43 // lead the scope's key to point to invalid memory after this returns. | 48 // lead the scope's key to point to invalid memory after this returns. |
44 base::StringPiece storage_key = source->GetStorageKey(cur.string_value()); | 49 base::StringPiece storage_key = source->GetStorageKey(cur.string_value()); |
45 if (storage_key.empty()) { | 50 if (storage_key.empty()) { |
46 // Programmatic value, don't allow copying. | 51 // Programmatic value, don't allow copying. |
47 *err = Err(cur, "This value can't be forwarded.", | 52 *err = Err(cur, "This value can't be forwarded.", |
(...skipping 11 matching lines...) Expand all Loading... |
59 } | 64 } |
60 | 65 |
61 } // namespace | 66 } // namespace |
62 | 67 |
63 const char kForwardVariablesFrom[] = "forward_variables_from"; | 68 const char kForwardVariablesFrom[] = "forward_variables_from"; |
64 const char kForwardVariablesFrom_HelpShort[] = | 69 const char kForwardVariablesFrom_HelpShort[] = |
65 "forward_variables_from: Copies variables from a different scope."; | 70 "forward_variables_from: Copies variables from a different scope."; |
66 const char kForwardVariablesFrom_Help[] = | 71 const char kForwardVariablesFrom_Help[] = |
67 "forward_variables_from: Copies variables from a different scope.\n" | 72 "forward_variables_from: Copies variables from a different scope.\n" |
68 "\n" | 73 "\n" |
69 " forward_variables_from(from_scope, variable_list_or_star)\n" | 74 " forward_variables_from(from_scope, variable_list_or_star,\n" |
| 75 " variable_to_not_forward_list = [])\n" |
70 "\n" | 76 "\n" |
71 " Copies the given variables from the given scope to the local scope\n" | 77 " Copies the given variables from the given scope to the local scope\n" |
72 " if they exist. This is normally used in the context of templates to\n" | 78 " if they exist. This is normally used in the context of templates to\n" |
73 " use the values of variables defined in the template invocation to\n" | 79 " use the values of variables defined in the template invocation to\n" |
74 " a template-defined target.\n" | 80 " a template-defined target.\n" |
75 "\n" | 81 "\n" |
76 " The variables in the given variable_list will be copied if they exist\n" | 82 " The variables in the given variable_list will be copied if they exist\n" |
77 " in the given scope or any enclosing scope. If they do not exist,\n" | 83 " in the given scope or any enclosing scope. If they do not exist,\n" |
78 " nothing will happen and they be left undefined in the current scope.\n" | 84 " nothing will happen and they be left undefined in the current scope.\n" |
79 "\n" | 85 "\n" |
80 " As a special case, if the variable_list is a string with the value of\n" | 86 " As a special case, if the variable_list is a string with the value of\n" |
81 " \"*\", all variables from the given scope will be copied. \"*\" only\n" | 87 " \"*\", all variables from the given scope will be copied. \"*\" only\n" |
82 " copies variables set directly on the from_scope, not enclosing ones.\n" | 88 " copies variables set directly on the from_scope, not enclosing ones.\n" |
83 " Otherwise it would duplicate all global variables.\n" | 89 " Otherwise it would duplicate all global variables.\n" |
84 "\n" | 90 "\n" |
85 " When an explicit list of variables is supplied, if the variable exists\n" | 91 " When an explicit list of variables is supplied, if the variable exists\n" |
86 " in the current (destination) scope already, an error will be thrown.\n" | 92 " in the current (destination) scope already, an error will be thrown.\n" |
87 " If \"*\" is specified, variables in the current scope will be\n" | 93 " If \"*\" is specified, variables in the current scope will be\n" |
88 " clobbered (the latter is important because most targets have an\n" | 94 " clobbered (the latter is important because most targets have an\n" |
89 " implicit configs list, which means it wouldn't work at all if it\n" | 95 " implicit configs list, which means it wouldn't work at all if it\n" |
90 " didn't clobber).\n" | 96 " didn't clobber).\n" |
91 "\n" | 97 "\n" |
92 " The sources assignment filter (see \"gn help " | 98 " The sources assignment filter (see \"gn help " |
93 "set_sources_assignment_filter\")\n" | 99 "set_sources_assignment_filter\")\n" |
94 " is never applied by this function. It's assumed than any desired\n" | 100 " is never applied by this function. It's assumed than any desired\n" |
95 " filtering was already done when sources was set on the from_scope.\n" | 101 " filtering was already done when sources was set on the from_scope.\n" |
96 "\n" | 102 "\n" |
| 103 " If variables_to_not_forward_list is non-empty, then it must contains\n" |
| 104 " a list of variable names that will not be forwarded. This is mostly\n" |
| 105 " useful when variable_list_or_star has a value of \"*\".\n" |
| 106 "\n" |
97 "Examples\n" | 107 "Examples\n" |
98 "\n" | 108 "\n" |
99 " # This is a common action template. It would invoke a script with\n" | 109 " # This is a common action template. It would invoke a script with\n" |
100 " # some given parameters, and wants to use the various types of deps\n" | 110 " # some given parameters, and wants to use the various types of deps\n" |
101 " # and the visibility from the invoker if it's defined. It also injects\n" | 111 " # and the visibility from the invoker if it's defined. It also injects\n" |
102 " # an additional dependency to all targets.\n" | 112 " # an additional dependency to all targets.\n" |
103 " template(\"my_test\") {\n" | 113 " template(\"my_test\") {\n" |
104 " action(target_name) {\n" | 114 " action(target_name) {\n" |
105 " forward_variables_from(invoker, [ \"data_deps\", \"deps\",\n" | 115 " forward_variables_from(invoker, [ \"data_deps\", \"deps\",\n" |
106 " \"public_deps\", \"visibility\" " | 116 " \"public_deps\", \"visibility\" " |
107 "])\n" | 117 "])\n" |
108 " # Add our test code to the dependencies.\n" | 118 " # Add our test code to the dependencies.\n" |
109 " # \"deps\" may or may not be defined at this point.\n" | 119 " # \"deps\" may or may not be defined at this point.\n" |
110 " if (defined(deps)) {\n" | 120 " if (defined(deps)) {\n" |
111 " deps += [ \"//tools/doom_melon\" ]\n" | 121 " deps += [ \"//tools/doom_melon\" ]\n" |
112 " } else {\n" | 122 " } else {\n" |
113 " deps = [ \"//tools/doom_melon\" ]\n" | 123 " deps = [ \"//tools/doom_melon\" ]\n" |
114 " }\n" | 124 " }\n" |
115 " }\n" | 125 " }\n" |
116 " }\n" | 126 " }\n" |
117 "\n" | 127 "\n" |
118 " # This is a template around either a target whose type depends on a\n" | 128 " # This is a template around either a target whose type depends on a\n" |
119 " # global variable. It forwards all values from the invoker.\n" | 129 " # global variable. It forwards all values from the invoker.\n" |
120 " template(\"my_wrapper\") {\n" | 130 " template(\"my_wrapper\") {\n" |
121 " target(my_wrapper_target_type, target_name) {\n" | 131 " target(my_wrapper_target_type, target_name) {\n" |
122 " forward_variables_from(invoker, \"*\")\n" | 132 " forward_variables_from(invoker, \"*\")\n" |
123 " }\n" | 133 " }\n" |
124 " }\n"; | 134 " }\n" |
| 135 "\n" |
| 136 " # A template that wraps another. It adds behavior based on one \n" |
| 137 " # variable, and forwards all others to the nested target.\n" |
| 138 " template(\"my_ios_test_app\") {\n" |
| 139 " ios_test_app(target_name) {\n" |
| 140 " forward_variables_from(invoker, \"*\", [\"test_bundle_name\"])\n" |
| 141 " if (!defined(extra_substitutions)) {\n" |
| 142 " extra_substitutions = []\n" |
| 143 " }\n" |
| 144 " extra_substitutions += [ \"BUNDLE_ID_TEST_NAME=$test_bundle_name\" " |
| 145 "]\n" |
| 146 " }\n" |
| 147 " }\n"; |
125 | 148 |
126 // This function takes a ListNode rather than a resolved vector of values | 149 // This function takes a ListNode rather than a resolved vector of values |
127 // both avoid copying the potentially-large source scope, and so the variables | 150 // both avoid copying the potentially-large source scope, and so the variables |
128 // in the source scope can be marked as used. | 151 // in the source scope can be marked as used. |
129 Value RunForwardVariablesFrom(Scope* scope, | 152 Value RunForwardVariablesFrom(Scope* scope, |
130 const FunctionCallNode* function, | 153 const FunctionCallNode* function, |
131 const ListNode* args_list, | 154 const ListNode* args_list, |
132 Err* err) { | 155 Err* err) { |
133 const std::vector<const ParseNode*>& args_vector = args_list->contents(); | 156 const std::vector<const ParseNode*>& args_vector = args_list->contents(); |
134 if (args_vector.size() != 2) { | 157 if (args_vector.size() != 2 && args_vector.size() != 3) { |
135 *err = Err(function, "Wrong number of arguments.", | 158 *err = Err(function, "Wrong number of arguments.", |
136 "Expecting exactly two."); | 159 "Expecting two or three arguments."); |
137 return Value(); | 160 return Value(); |
138 } | 161 } |
139 | 162 |
140 // Extract the scope identifier. This assumes the first parameter is an | 163 // Extract the scope identifier. This assumes the first parameter is an |
141 // identifier. It is difficult to write code where this is not the case, and | 164 // identifier. It is difficult to write code where this is not the case, and |
142 // this saves an expensive scope copy. If necessary, this could be expanded | 165 // this saves an expensive scope copy. If necessary, this could be expanded |
143 // to execute the ParseNode and get the value out if it's not an identifer. | 166 // to execute the ParseNode and get the value out if it's not an identifer. |
144 const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); | 167 const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); |
145 if (!identifier) { | 168 if (!identifier) { |
146 *err = Err(args_vector[0], "Expected an identifier for the scope."); | 169 *err = Err(args_vector[0], "Expected an identifier for the scope."); |
147 return Value(); | 170 return Value(); |
148 } | 171 } |
149 | 172 |
150 // Extract the source scope. | 173 // Extract the source scope. |
151 Value* value = scope->GetMutableValue(identifier->value().value(), true); | 174 Value* value = scope->GetMutableValue(identifier->value().value(), true); |
152 if (!value) { | 175 if (!value) { |
153 *err = Err(identifier, "Undefined identifier."); | 176 *err = Err(identifier, "Undefined identifier."); |
154 return Value(); | 177 return Value(); |
155 } | 178 } |
156 if (!value->VerifyTypeIs(Value::SCOPE, err)) | 179 if (!value->VerifyTypeIs(Value::SCOPE, err)) |
157 return Value(); | 180 return Value(); |
158 Scope* source = value->scope_value(); | 181 Scope* source = value->scope_value(); |
159 | 182 |
| 183 // Extract the exclusion list if defined. |
| 184 std::set<std::string> exclusion_set; |
| 185 if (args_vector.size() == 3) { |
| 186 Value exclusion_value = args_vector[2]->Execute(scope, err); |
| 187 if (err->has_error()) |
| 188 return Value(); |
| 189 |
| 190 if (exclusion_value.type() != Value::LIST) { |
| 191 *err = Err(exclusion_value, "Not a valid list of variables to exclude.", |
| 192 "Expecting a list of strings."); |
| 193 return Value(); |
| 194 } |
| 195 |
| 196 for (const Value& cur : exclusion_value.list_value()) { |
| 197 if (!cur.VerifyTypeIs(Value::STRING, err)) |
| 198 return Value(); |
| 199 |
| 200 exclusion_set.insert(cur.string_value()); |
| 201 } |
| 202 } |
| 203 |
160 // Extract the list. If all_values is not set, the what_value will be a list. | 204 // Extract the list. If all_values is not set, the what_value will be a list. |
161 Value what_value = args_vector[1]->Execute(scope, err); | 205 Value what_value = args_vector[1]->Execute(scope, err); |
162 if (err->has_error()) | 206 if (err->has_error()) |
163 return Value(); | 207 return Value(); |
164 if (what_value.type() == Value::STRING) { | 208 if (what_value.type() == Value::STRING) { |
165 if (what_value.string_value() == "*") { | 209 if (what_value.string_value() == "*") { |
166 ForwardAllValues(function, source, scope, err); | 210 ForwardAllValues(function, source, scope, exclusion_set, err); |
167 return Value(); | 211 return Value(); |
168 } | 212 } |
169 } else { | 213 } else { |
170 if (what_value.type() == Value::LIST) { | 214 if (what_value.type() == Value::LIST) { |
171 ForwardValuesFromList(source, scope, what_value.list_value(), err); | 215 ForwardValuesFromList(source, scope, what_value.list_value(), |
| 216 exclusion_set, err); |
172 return Value(); | 217 return Value(); |
173 } | 218 } |
174 } | 219 } |
175 | 220 |
176 // Not the right type of argument. | 221 // Not the right type of argument. |
177 *err = Err(what_value, "Not a valid list of variables to copy.", | 222 *err = Err(what_value, "Not a valid list of variables to copy.", |
178 "Expecting either the string \"*\" or a list of strings."); | 223 "Expecting either the string \"*\" or a list of strings."); |
179 return Value(); | 224 return Value(); |
180 } | 225 } |
181 | 226 |
182 } // namespace functions | 227 } // namespace functions |
OLD | NEW |