1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #pragma once
18
19 #include <algorithm>
20 #include <memory>
21 #include <string>
22
23 #include "common/libs/utils/collect.h"
24 #include "common/libs/utils/contains.h"
25 #include "common/libs/utils/result.h"
26 #include "host/commands/cvd/selector/constant_reference.h"
27 #include "host/commands/cvd/selector/instance_database_types.h"
28
29 namespace cuttlefish {
30 namespace selector {
31
32 Result<std::string> GetCuttlefishConfigPath(const std::string& home);
33
34 std::string GenInternalGroupName();
35 std::string GenDefaultGroupName();
36 std::string LocalDeviceNameRule(const std::string& group_name,
37 const std::string& instance_name);
38
39 // [A-Za-z0-9_]+, e.g. 0, tv, my_phone07, etc
40 // Or, it can include "-" in the middle
41 // ([A-Za-z0-9_]+[-])*[A-Za-z0-9_]
42 bool IsValidInstanceName(const std::string& token);
43
44 // [A-Za-z_][A-Za-z0-9_]*, e.g. cool_group, cv0_d, cf, etc
45 // but can't start with [0-9]
46 bool IsValidGroupName(const std::string& token);
47
48 // <valid group name>-<valid instance name>
49 bool IsValidDeviceName(const std::string& token);
50
51 struct DeviceName {
52 std::string group_name;
53 std::string per_instance_name;
54 };
55 Result<DeviceName> BreakDeviceName(const std::string& device_name);
56
57 /**
58 * Runs simple tests to see if it could potentially be a host artifacts dir
59 *
60 */
61 bool PotentiallyHostArtifactsPath(const std::string& host_binaries_dir);
62
63 /**
64 * simply returns:
65 *
66 * "Only up to n must match" or
67 * "Only up to n must match by field " + FieldName
68 *
69 */
70 std::string GenerateTooManyInstancesErrorMsg(const int n,
71 const std::string& field_name);
72
73 /**
74 * return all the elements in container that satisfies predicate.
75 *
76 * Container has Wrappers, where each Wrapper is typically,
77 * std::unique/shared_ptr of T, or some wrapper of T, etc. Set is a set of T.
78 *
79 * This method returns the Set of T, as long as its corresponding Wrapper in
80 * Container meets the predicate.
81 */
82 template <typename T, typename Wrapper, typename Set, typename Container>
Collect(const Container & container,std::function<bool (const Wrapper &)> predicate,std::function<T (const Wrapper &)> convert)83 Set Collect(const Container& container,
84 std::function<bool(const Wrapper&)> predicate,
85 std::function<T(const Wrapper&)> convert) {
86 Set output;
87 for (const auto& t : container) {
88 if (!predicate(t)) {
89 continue;
90 }
91 output.insert(convert(t));
92 }
93 return output;
94 }
95
96 /*
97 * Returns a Set of ConstRef<T>, which essentially satisfies "predicate"
98 *
99 * Container has a list/set of std::unique_ptr<T>. We collect all the
100 * const references of each object owned by Container, which meets the
101 * condition defined by predicate.
102 *
103 */
104 template <typename T, typename Container>
CollectToSet(Container && container,std::function<bool (const std::unique_ptr<T> &)> predicate)105 Set<ConstRef<T>> CollectToSet(
106 Container&& container,
107 std::function<bool(const std::unique_ptr<T>&)> predicate) {
108 auto convert = [](const std::unique_ptr<T>& uniq_ptr) {
109 return Cref(*uniq_ptr);
110 };
111 return Collect<ConstRef<T>, std::unique_ptr<T>, Set<ConstRef<T>>>(
112 std::forward<Container>(container), std::move(predicate),
113 std::move(convert));
114 }
115
116 /**
117 * Given:
118 * Containers have a list of n `Container`s. Each Container may have
119 * m Element. Each is stored as a unique_ptr.
120 *
121 * Goal:
122 * To collect Elements from each Container with Container's APIs. The
123 * collected Elements meet the condition implicitly defined in collector.
124 *
125 * E.g. InstanceDatabase has InstanceGroups, each has Instances. We want
126 * all the Instances its build-target was TV. Then, collector will look
127 * like this:
128 * [&build_target](const std::unique_ptr<InstanceGroup>& group) {
129 * return group->FindByBuildTarget(build_target);
130 * }
131 *
132 * We take the union of all the returned subsets from each collector call.
133 */
134 template <typename Element, typename Container, typename Containers>
CollectAllElements(std::function<Result<Set<ConstRef<Element>>> (const std::unique_ptr<Container> &)> collector,const Containers & outermost_container)135 Result<Set<ConstRef<Element>>> CollectAllElements(
136 std::function<
137 Result<Set<ConstRef<Element>>>(const std::unique_ptr<Container>&)>
138 collector,
139 const Containers& outermost_container) {
140 Set<ConstRef<Element>> output;
141 for (const auto& container_ptr : outermost_container) {
142 auto subset = CF_EXPECT(collector(container_ptr));
143 output.insert(subset.cbegin(), subset.cend());
144 }
145 return {output};
146 }
147
148 template <typename S>
AtMostOne(S && s,const std::string & err_msg)149 Result<typename std::remove_reference<S>::type> AtMostOne(
150 S&& s, const std::string& err_msg) {
151 CF_EXPECT(AtMostN(std::forward<S>(s), 1), err_msg);
152 return {std::forward<S>(s)};
153 }
154
155 template <typename RetSet, typename AnyContainer>
Intersection(const RetSet & u,AnyContainer && v)156 RetSet Intersection(const RetSet& u, AnyContainer&& v) {
157 RetSet result;
158 if (u.empty() || v.empty()) {
159 return result;
160 }
161 for (auto const& e : v) {
162 if (Contains(u, e)) {
163 result.insert(e);
164 }
165 }
166 return result;
167 }
168
169 template <typename RetSet, typename AnyContainer, typename... Containers>
Intersection(const RetSet & u,AnyContainer && v,Containers &&...s)170 RetSet Intersection(const RetSet& u, AnyContainer&& v, Containers&&... s) {
171 RetSet first = Intersection(u, std::forward<AnyContainer>(v));
172 if (first.empty()) {
173 return first;
174 }
175 return Intersection(first, std::forward<Containers>(s)...);
176 }
177
178 } // namespace selector
179 } // namespace cuttlefish
180