1 /*
2 * Copyright (C) 2021 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 #pragma once
17
18 #include <ostream>
19 #include <string>
20 #include <unordered_map>
21 #include <unordered_set>
22 #include <vector>
23
24 #include <android-base/logging.h>
25
26 #include "common/libs/utils/result.h"
27
28 namespace cuttlefish {
29
30 template <typename Subclass>
31 class Feature {
32 public:
33 virtual ~Feature() = default;
34
35 virtual std::string Name() const = 0;
36
37 static Result<void> TopologicalVisit(
38 const std::unordered_set<Subclass*>& features,
39 const std::function<bool(Subclass*)>& callback);
40
41 private:
42 virtual std::unordered_set<Subclass*> Dependencies() const = 0;
43 };
44
45 class SetupFeature : public virtual Feature<SetupFeature> {
46 public:
47 virtual ~SetupFeature();
48
49 static Result<void> RunSetup(const std::vector<SetupFeature*>& features);
50
51 virtual bool Enabled() const = 0;
52
53 private:
54 virtual Result<void> ResultSetup();
55 virtual bool Setup();
56 };
57
58 class FlagFeature : public Feature<FlagFeature> {
59 public:
60 static Result<void> ProcessFlags(const std::vector<FlagFeature*>& features,
61 std::vector<std::string>& flags);
62 static bool WriteGflagsHelpXml(const std::vector<FlagFeature*>& features,
63 std::ostream& out);
64
65 private:
66 // Must be executed in dependency order following Dependencies(). Expected to
67 // mutate the `flags` argument to remove handled flags, and possibly introduce
68 // new flag values (e.g. from a file).
69 virtual bool Process(std::vector<std::string>& flags) = 0;
70
71 // TODO(schuffelen): Migrate the xml help to human-readable help output after
72 // the gflags migration is done.
73
74 // Write an xml fragment that is compatible with gflags' `--helpxml` format.
75 virtual bool WriteGflagsCompatHelpXml(std::ostream& out) const = 0;
76 };
77
78 template <typename Subclass>
TopologicalVisit(const std::unordered_set<Subclass * > & features,const std::function<bool (Subclass *)> & callback)79 Result<void> Feature<Subclass>::TopologicalVisit(
80 const std::unordered_set<Subclass*>& features,
81 const std::function<bool(Subclass*)>& callback) {
82 enum class Status { UNVISITED, VISITING, VISITED };
83 std::unordered_map<Subclass*, Status> features_status;
84 for (const auto& feature : features) {
85 features_status[feature] = Status::UNVISITED;
86 }
87 std::function<Result<void>(Subclass*)> visit;
88 visit = [&callback, &features_status,
89 &visit](Subclass* feature) -> Result<void> {
90 CF_EXPECT(features_status.count(feature) > 0,
91 "Dependency edge to "
92 << feature->Name() << " but it is not part of the feature "
93 << "graph. This feature is either disabled or not correctly "
94 << "registered.");
95 if (features_status[feature] == Status::VISITED) {
96 return {};
97 }
98 CF_EXPECT(features_status[feature] != Status::VISITING,
99 "Cycle detected while visiting " << feature->Name());
100 features_status[feature] = Status::VISITING;
101 for (const auto& dependency : feature->Dependencies()) {
102 CF_EXPECT(dependency != nullptr,
103 "SetupFeature " << feature->Name() << " has a null dependency.");
104 CF_EXPECT(visit(dependency),
105 "Error detected while visiting " << feature->Name());
106 }
107 features_status[feature] = Status::VISITED;
108 CF_EXPECT(callback(feature), "Callback error on " << feature->Name());
109 return {};
110 };
111 for (const auto& feature : features) {
112 CF_EXPECT(visit(feature)); // `visit` will log the error chain.
113 }
114 return {};
115 }
116
117 } // namespace cuttlefish
118