| /* |
| * Copyright (C) 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #pragma once |
| |
| #include <ostream> |
| #include <string> |
| #include <unordered_map> |
| #include <unordered_set> |
| #include <vector> |
| |
| #include <android-base/logging.h> |
| |
| #include "common/libs/utils/result.h" |
| |
| namespace cuttlefish { |
| |
| template <typename Subclass> |
| class Feature { |
| public: |
| virtual ~Feature() = default; |
| |
| virtual std::string Name() const = 0; |
| |
| static Result<void> TopologicalVisit( |
| const std::unordered_set<Subclass*>& features, |
| const std::function<bool(Subclass*)>& callback); |
| |
| private: |
| virtual std::unordered_set<Subclass*> Dependencies() const = 0; |
| }; |
| |
| class SetupFeature : public virtual Feature<SetupFeature> { |
| public: |
| virtual ~SetupFeature(); |
| |
| static Result<void> RunSetup(const std::vector<SetupFeature*>& features); |
| |
| virtual bool Enabled() const = 0; |
| |
| private: |
| virtual Result<void> ResultSetup(); |
| virtual bool Setup(); |
| }; |
| |
| class FlagFeature : public Feature<FlagFeature> { |
| public: |
| static Result<void> ProcessFlags(const std::vector<FlagFeature*>& features, |
| std::vector<std::string>& flags); |
| static bool WriteGflagsHelpXml(const std::vector<FlagFeature*>& features, |
| std::ostream& out); |
| |
| private: |
| // Must be executed in dependency order following Dependencies(). Expected to |
| // mutate the `flags` argument to remove handled flags, and possibly introduce |
| // new flag values (e.g. from a file). |
| virtual bool Process(std::vector<std::string>& flags) = 0; |
| |
| // TODO(schuffelen): Migrate the xml help to human-readable help output after |
| // the gflags migration is done. |
| |
| // Write an xml fragment that is compatible with gflags' `--helpxml` format. |
| virtual bool WriteGflagsCompatHelpXml(std::ostream& out) const = 0; |
| }; |
| |
| template <typename Subclass> |
| Result<void> Feature<Subclass>::TopologicalVisit( |
| const std::unordered_set<Subclass*>& features, |
| const std::function<bool(Subclass*)>& callback) { |
| enum class Status { UNVISITED, VISITING, VISITED }; |
| std::unordered_map<Subclass*, Status> features_status; |
| for (const auto& feature : features) { |
| features_status[feature] = Status::UNVISITED; |
| } |
| std::function<Result<void>(Subclass*)> visit; |
| visit = [&callback, &features_status, |
| &visit](Subclass* feature) -> Result<void> { |
| CF_EXPECT(features_status.count(feature) > 0, |
| "Dependency edge to " |
| << feature->Name() << " but it is not part of the feature " |
| << "graph. This feature is either disabled or not correctly " |
| << "registered."); |
| if (features_status[feature] == Status::VISITED) { |
| return {}; |
| } |
| CF_EXPECT(features_status[feature] != Status::VISITING, |
| "Cycle detected while visiting " << feature->Name()); |
| features_status[feature] = Status::VISITING; |
| for (const auto& dependency : feature->Dependencies()) { |
| CF_EXPECT(dependency != nullptr, |
| "SetupFeature " << feature->Name() << " has a null dependency."); |
| CF_EXPECT(visit(dependency), |
| "Error detected while visiting " << feature->Name()); |
| } |
| features_status[feature] = Status::VISITED; |
| CF_EXPECT(callback(feature), "Callback error on " << feature->Name()); |
| return {}; |
| }; |
| for (const auto& feature : features) { |
| CF_EXPECT(visit(feature)); // `visit` will log the error chain. |
| } |
| return {}; |
| } |
| |
| } // namespace cuttlefish |