• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include <stddef.h>
6 
7 #include "gn/build_settings.h"
8 #include "gn/err.h"
9 #include "gn/functions.h"
10 #include "gn/label_pattern.h"
11 #include "gn/parse_tree.h"
12 #include "gn/scope.h"
13 #include "gn/settings.h"
14 #include "gn/value.h"
15 
16 namespace functions {
17 
18 enum FilterSelection {
19   kExcludeFilter,
20   kIncludeFilter,
21 };
22 
RunFilterLabels(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,FilterSelection selection,Err * err)23 Value RunFilterLabels(Scope* scope,
24                       const FunctionCallNode* function,
25                       const std::vector<Value>& args,
26                       FilterSelection selection,
27                       Err* err) {
28   if (args.size() != 2) {
29     *err = Err(function, "Expecting exactly two arguments.");
30     return Value();
31   }
32 
33   // Validate "labels" and "patterns" are both lists
34   if (args[0].type() != Value::LIST) {
35     *err = Err(args[0], "First argument must be a list of target labels.");
36     return Value();
37   }
38   if (args[1].type() != Value::LIST) {
39     *err = Err(args[1], "Second argument must be a list of label patterns.");
40     return Value();
41   }
42 
43   // Extract "patterns"
44   std::vector<LabelPattern> patterns;
45   patterns.reserve(args[1].list_value().size());
46 
47   for (const auto& value : args[1].list_value()) {
48     if (value.type() != Value::STRING) {
49       *err = Err(args[1], "Second argument must be a list of label patterns.");
50       return Value();
51     }
52     LabelPattern pattern = LabelPattern::GetPattern(
53         scope->GetSourceDir(),
54         scope->settings()->build_settings()->root_path_utf8(), value, err);
55     if (err->has_error()) {
56       return Value();
57     }
58     patterns.push_back(std::move(pattern));
59   }
60 
61   // Iterate over "labels", resolving and matching against the list of patterns.
62   Value result(function, Value::LIST);
63   for (const auto& value : args[0].list_value()) {
64     Label label =
65         Label::Resolve(scope->GetSourceDir(),
66                        scope->settings()->build_settings()->root_path_utf8(),
67                        ToolchainLabelForScope(scope), value, err);
68     if (err->has_error()) {
69       // Change the error message to be more applicable than what Resolve will
70       // produce.
71       *err = Err(value, "First argument must be a list of target labels.");
72       return Value();
73     }
74 
75     const bool matches_pattern = LabelPattern::VectorMatches(patterns, label);
76     switch (selection) {
77       case kIncludeFilter:
78         if (matches_pattern)
79           result.list_value().push_back(value);
80         break;
81 
82       case kExcludeFilter:
83         if (!matches_pattern)
84           result.list_value().push_back(value);
85         break;
86     }
87   }
88   return result;
89 }
90 
91 const char kFilterLabelsInclude[] = "filter_labels_include";
92 const char kFilterLabelsInclude_HelpShort[] =
93     "filter_labels_include: Remove labels that do not match a set of patterns.";
94 const char kFilterLabelsInclude_Help[] =
95     R"(filter_labels_include: Remove labels that do not match a set of patterns.
96 
97   filter_labels_include(labels, include_patterns)
98 
99   The argument labels must be a list of strings.
100 
101   The argument include_patterns must be a list of label patterns (see
102   "gn help label_pattern"). Only elements from labels matching at least
103   one of the patterns will be included.
104 
105 Examples
106   labels = [ "//foo:baz", "//foo/bar:baz", "//bar:baz" ]
107   result = filter_labels_include(labels, [ "//foo:*" ])
108   # result will be [ "//foo:baz" ]
109 )";
110 
RunFilterLabelsInclude(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,Err * err)111 Value RunFilterLabelsInclude(Scope* scope,
112                              const FunctionCallNode* function,
113                              const std::vector<Value>& args,
114                              Err* err) {
115   return RunFilterLabels(scope, function, args, kIncludeFilter, err);
116 }
117 
118 const char kFilterLabelsExclude[] = "filter_labels_exclude";
119 const char kFilterLabelsExclude_HelpShort[] =
120     "filter_labels_exclude: Remove labels that match a set of patterns.";
121 const char kFilterLabelsExclude_Help[] =
122     R"(filter_labels_exclude: Remove labels that match a set of patterns.
123 
124   filter_labels_exclude(labels, exclude_patterns)
125 
126   The argument labels must be a list of strings.
127 
128   The argument exclude_patterns must be a list of label patterns (see
129   "gn help label_pattern"). Only elements from labels matching at least
130   one of the patterns will be excluded.
131 
132 Examples
133   labels = [ "//foo:baz", "//foo/bar:baz", "//bar:baz" ]
134   result = filter_labels_exclude(labels, [ "//foo:*" ])
135   # result will be [ "//foo/bar:baz", "//bar:baz" ]
136 )";
137 
138 Value RunFilterLabelsExclude(Scope* scope,
139                              const FunctionCallNode* function,
140                              const std::vector<Value>& args,
141                              Err* err) {
142   return RunFilterLabels(scope, function, args, kExcludeFilter, err);
143 }
144 
145 }  // namespace functions
146