256 lines
8.5 KiB
C++
256 lines
8.5 KiB
C++
|
|
//
|
||
|
|
// Copyright (C) 2022 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.
|
||
|
|
|
||
|
|
#include "host/libs/config/instance_nums.h"
|
||
|
|
|
||
|
|
#include <android-base/parseint.h>
|
||
|
|
#include <android-base/strings.h>
|
||
|
|
#include <gflags/gflags.h>
|
||
|
|
|
||
|
|
#include "common/libs/utils/contains.h"
|
||
|
|
#include "common/libs/utils/flag_parser.h"
|
||
|
|
#include "host/libs/config/cuttlefish_config.h"
|
||
|
|
|
||
|
|
namespace cuttlefish {
|
||
|
|
|
||
|
|
// Failed result: The flag was specified in an invalid way
|
||
|
|
// Empty optional: The flag was not specified
|
||
|
|
// Present optional: The flag was specified with a valid value
|
||
|
|
static Result<std::optional<std::int32_t>> ParseBaseInstanceFlag(
|
||
|
|
std::vector<std::string>& flags) {
|
||
|
|
int value = -1;
|
||
|
|
auto flag = GflagsCompatFlag("base_instance_num", value);
|
||
|
|
CF_EXPECT(flag.Parse(flags), "Flag parsing error");
|
||
|
|
return value > 0 ? value : std::optional<std::int32_t>();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Failed result: The flag was specified in an invalid way
|
||
|
|
// Empty optional: The flag was not specified
|
||
|
|
// Present optional: The flag was specified with a valid value
|
||
|
|
static Result<std::optional<std::int32_t>> ParseNumInstancesFlag(
|
||
|
|
std::vector<std::string>& flags) {
|
||
|
|
int value = -1;
|
||
|
|
auto flag = GflagsCompatFlag("num_instances", value);
|
||
|
|
CF_EXPECT(flag.Parse(flags), "Flag parsing error");
|
||
|
|
return value > 0 ? value : std::optional<std::int32_t>();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Failed result: The flag was specified in an invalid way
|
||
|
|
// Empty set: The flag was not specified
|
||
|
|
// Set with members: The flag was specified with a valid value
|
||
|
|
static Result<std::vector<std::int32_t>> ParseInstanceNums(
|
||
|
|
const std::string& instance_nums_str) {
|
||
|
|
if (instance_nums_str == "") {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
std::vector<std::int32_t> instance_nums;
|
||
|
|
std::vector<std::string> split_str =
|
||
|
|
android::base::Split(instance_nums_str, ",");
|
||
|
|
std::set<std::int32_t> duplication_check_set;
|
||
|
|
for (const auto& instance_num_str : split_str) {
|
||
|
|
std::int32_t instance_num;
|
||
|
|
CF_EXPECT(android::base::ParseInt(instance_num_str.c_str(), &instance_num),
|
||
|
|
"Unable to parse \"" << instance_num_str << "\" in "
|
||
|
|
<< "`--instance_nums=\"" << instance_nums_str
|
||
|
|
<< "\"`");
|
||
|
|
CF_EXPECT(!Contains(duplication_check_set, instance_num),
|
||
|
|
instance_num << " is duplicated in -instance_nums flag.");
|
||
|
|
duplication_check_set.insert(instance_num);
|
||
|
|
instance_nums.push_back(instance_num);
|
||
|
|
}
|
||
|
|
return instance_nums;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Failed result: The flag was specified in an invalid way
|
||
|
|
// Empty set: The flag was not specified
|
||
|
|
// Set with members: The flag was specified with a valid value
|
||
|
|
static Result<std::vector<std::int32_t>> ParseInstanceNumsFlag(
|
||
|
|
std::vector<std::string>& flags) {
|
||
|
|
std::string value;
|
||
|
|
auto flag = GflagsCompatFlag("instance_nums", value);
|
||
|
|
CF_EXPECT(flag.Parse(flags), "Flag parsing error");
|
||
|
|
if (!value.empty()) {
|
||
|
|
return CF_EXPECT(ParseInstanceNums(value));
|
||
|
|
} else {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
InstanceNumsCalculator& InstanceNumsCalculator::FromFlags(
|
||
|
|
const std::vector<std::string>& flags) & {
|
||
|
|
std::vector<std::string> flags_copy = flags;
|
||
|
|
TrySet(base_instance_num_, ParseBaseInstanceFlag(flags_copy));
|
||
|
|
TrySet(num_instances_, ParseNumInstancesFlag(flags_copy));
|
||
|
|
TrySet(instance_nums_, ParseInstanceNumsFlag(flags_copy));
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
InstanceNumsCalculator InstanceNumsCalculator::FromFlags(
|
||
|
|
const std::vector<std::string>& flags) && {
|
||
|
|
return FromFlags(flags);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Failed result: The flag was specified in an invalid way
|
||
|
|
// Empty optional: The flag was not specified
|
||
|
|
// Present optional: The flag was specified with a valid value
|
||
|
|
static Result<std::optional<std::int32_t>> GflagsBaseInstanceFlag() {
|
||
|
|
gflags::CommandLineFlagInfo info;
|
||
|
|
if (!gflags::GetCommandLineFlagInfo("base_instance_num", &info)) {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
if (info.is_default) {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
CF_EXPECT(info.type == "int32");
|
||
|
|
return *reinterpret_cast<const std::int32_t*>(info.flag_ptr);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Failed result: The flag was specified in an invalid way
|
||
|
|
// Empty optional: The flag was not specified
|
||
|
|
// Present optional: The flag was specified with a valid value
|
||
|
|
static Result<std::optional<std::int32_t>> GflagsNumInstancesFlag() {
|
||
|
|
gflags::CommandLineFlagInfo info;
|
||
|
|
if (!gflags::GetCommandLineFlagInfo("num_instances", &info)) {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
if (info.is_default) {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
CF_EXPECT(info.type == "int32");
|
||
|
|
return *reinterpret_cast<const std::int32_t*>(info.flag_ptr);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Failed result: The flag was specified in an invalid way
|
||
|
|
// Empty set: The flag was not specified
|
||
|
|
// Set with members: The flag was specified with a valid value
|
||
|
|
static Result<std::vector<std::int32_t>> GflagsInstanceNumsFlag() {
|
||
|
|
gflags::CommandLineFlagInfo info;
|
||
|
|
if (!gflags::GetCommandLineFlagInfo("instance_nums", &info)) {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
if (info.is_default) {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
CF_EXPECT(info.type == "string");
|
||
|
|
auto contents = *reinterpret_cast<const std::string*>(info.flag_ptr);
|
||
|
|
return CF_EXPECT(ParseInstanceNums(contents));
|
||
|
|
}
|
||
|
|
|
||
|
|
InstanceNumsCalculator& InstanceNumsCalculator::FromGlobalGflags() & {
|
||
|
|
TrySet(base_instance_num_, GflagsBaseInstanceFlag());
|
||
|
|
TrySet(num_instances_, GflagsNumInstancesFlag());
|
||
|
|
TrySet(instance_nums_, GflagsInstanceNumsFlag());
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
InstanceNumsCalculator InstanceNumsCalculator::FromGlobalGflags() && {
|
||
|
|
return FromGlobalGflags();
|
||
|
|
}
|
||
|
|
|
||
|
|
InstanceNumsCalculator& InstanceNumsCalculator::BaseInstanceNum(
|
||
|
|
std::int32_t num) & {
|
||
|
|
base_instance_num_ = num;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
InstanceNumsCalculator InstanceNumsCalculator::BaseInstanceNum(
|
||
|
|
std::int32_t num) && {
|
||
|
|
return BaseInstanceNum(num);
|
||
|
|
}
|
||
|
|
|
||
|
|
InstanceNumsCalculator& InstanceNumsCalculator::NumInstances(
|
||
|
|
std::int32_t num) & {
|
||
|
|
num_instances_ = num;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
InstanceNumsCalculator InstanceNumsCalculator::NumInstances(
|
||
|
|
std::int32_t num) && {
|
||
|
|
return NumInstances(num);
|
||
|
|
}
|
||
|
|
|
||
|
|
InstanceNumsCalculator& InstanceNumsCalculator::InstanceNums(
|
||
|
|
const std::string& nums) & {
|
||
|
|
TrySet(instance_nums_, ParseInstanceNums(nums));
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
InstanceNumsCalculator InstanceNumsCalculator::InstanceNums(
|
||
|
|
const std::string& nums) && {
|
||
|
|
return InstanceNums(nums);
|
||
|
|
}
|
||
|
|
|
||
|
|
InstanceNumsCalculator& InstanceNumsCalculator::InstanceNums(
|
||
|
|
std::vector<std::int32_t> set) & {
|
||
|
|
instance_nums_ = std::move(set);
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
InstanceNumsCalculator InstanceNumsCalculator::InstanceNums(
|
||
|
|
std::vector<std::int32_t> set) && {
|
||
|
|
return InstanceNums(std::move(set));
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T>
|
||
|
|
void InstanceNumsCalculator::TrySet(T& field, Result<T> result) {
|
||
|
|
if (result.ok()) {
|
||
|
|
field = std::move(*result);
|
||
|
|
} else {
|
||
|
|
// TODO(schuffelen): Combine both errors into one
|
||
|
|
setter_result_.error() = result.error();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Result<std::vector<std::int32_t>> InstanceNumsCalculator::CalculateFromFlags() {
|
||
|
|
CF_EXPECT(Result<void>(setter_result_));
|
||
|
|
std::optional<std::vector<std::int32_t>> instance_nums_opt;
|
||
|
|
if (!instance_nums_.empty()) {
|
||
|
|
instance_nums_opt = instance_nums_;
|
||
|
|
}
|
||
|
|
// exactly one of these two should be given
|
||
|
|
CF_EXPECT(!instance_nums_opt || !base_instance_num_,
|
||
|
|
"At least one of --instance_nums or --base_instance_num"
|
||
|
|
<< "should be given to call CalculateFromFlags()");
|
||
|
|
CF_EXPECT(instance_nums_opt || base_instance_num_,
|
||
|
|
"InstanceNums and BaseInstanceNum are mutually exclusive");
|
||
|
|
|
||
|
|
if (instance_nums_opt) {
|
||
|
|
if (num_instances_) {
|
||
|
|
CF_EXPECT(instance_nums_.size() == *num_instances_);
|
||
|
|
}
|
||
|
|
CF_EXPECT(instance_nums_.size() > 0, "no instance nums");
|
||
|
|
return instance_nums_;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<std::int32_t> instance_nums;
|
||
|
|
for (int i = 0; i < num_instances_.value_or(1); i++) {
|
||
|
|
instance_nums.push_back(i + *base_instance_num_);
|
||
|
|
}
|
||
|
|
return instance_nums;
|
||
|
|
}
|
||
|
|
|
||
|
|
Result<std::vector<std::int32_t>> InstanceNumsCalculator::Calculate() {
|
||
|
|
CF_EXPECT(Result<void>(setter_result_));
|
||
|
|
|
||
|
|
if (!instance_nums_.empty() || base_instance_num_) {
|
||
|
|
return CalculateFromFlags();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<std::int32_t> instance_nums;
|
||
|
|
for (int i = 0; i < num_instances_.value_or(1); i++) {
|
||
|
|
instance_nums.push_back(i + GetInstance());
|
||
|
|
}
|
||
|
|
CF_EXPECT(instance_nums.size() > 0, "no instance nums");
|
||
|
|
return instance_nums;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace cuttlefish
|