• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "host/commands/cvd/selector/instance_database_utils.h"
18 
19 #include <regex>
20 #include <set>
21 #include <sstream>
22 #include <string_view>
23 #include <vector>
24 
25 #include <android-base/file.h>
26 #include <android-base/strings.h>
27 
28 #include "common/libs/utils/files.h"
29 #include "host/libs/config/cuttlefish_config.h"
30 
31 namespace cuttlefish {
32 namespace selector {
33 
GetCuttlefishConfigPath(const std::string & home)34 Result<std::string> GetCuttlefishConfigPath(const std::string& home) {
35   std::string home_realpath;
36   CF_EXPECT(DirectoryExists(home), "Invalid Home Directory");
37   CF_EXPECT(android::base::Realpath(home, &home_realpath));
38   static const char kSuffix[] = "/cuttlefish_assembly/cuttlefish_config.json";
39   std::string config_path = AbsolutePath(home_realpath + kSuffix);
40   CF_EXPECT(FileExists(config_path), "No config file exists");
41   return {config_path};
42 }
43 
GenInternalGroupName()44 std::string GenInternalGroupName() {
45   std::string_view internal_name{kCvdNamePrefix};  // "cvd-"
46   internal_name.remove_suffix(1);                  // "cvd"
47   return std::string(internal_name);
48 }
49 
GenDefaultGroupName()50 std::string GenDefaultGroupName() { return GenInternalGroupName(); }
51 
LocalDeviceNameRule(const std::string & group_name,const std::string & instance_name)52 std::string LocalDeviceNameRule(const std::string& group_name,
53                                 const std::string& instance_name) {
54   return group_name + "-" + instance_name;
55 }
56 
IsValidGroupName(const std::string & token)57 bool IsValidGroupName(const std::string& token) {
58   std::regex regular_expr("[A-Za-z_][A-Za-z_0-9]*");
59   return std::regex_match(token, regular_expr);
60 }
61 
IsValidInstanceName(const std::string & token)62 bool IsValidInstanceName(const std::string& token) {
63   if (token.empty()) {
64     return false;
65   }
66   std::regex base_regular_expr("[A-Za-z_0-9]+");
67   auto pieces = android::base::Split(token, "-");
68   for (const auto& piece : pieces) {
69     if (!std::regex_match(piece, base_regular_expr)) {
70       return false;
71     }
72   }
73   return true;
74 }
75 
BreakDeviceName(const std::string & device_name)76 Result<DeviceName> BreakDeviceName(const std::string& device_name) {
77   CF_EXPECT(!device_name.empty());
78   CF_EXPECT(Contains(device_name, '-'));
79   auto dash_pos = device_name.find_first_of('-');
80   // - must be neither the first nor the last character
81   CF_EXPECT(dash_pos != 0 && dash_pos != (device_name.size() - 1));
82   const auto group_name = device_name.substr(0, dash_pos);
83   const auto instance_name = device_name.substr(dash_pos + 1);
84   return DeviceName{.group_name = group_name,
85                     .per_instance_name = instance_name};
86 }
87 
IsValidDeviceName(const std::string & token)88 bool IsValidDeviceName(const std::string& token) {
89   if (token.empty()) {
90     return false;
91   }
92   auto result = BreakDeviceName(token);
93   if (!result.ok()) {
94     return false;
95   }
96   const auto [group_name, instance_name] = *result;
97   return IsValidGroupName(group_name) && IsValidInstanceName(instance_name);
98 }
99 
PotentiallyHostArtifactsPath(const std::string & host_artifacts_path)100 bool PotentiallyHostArtifactsPath(const std::string& host_artifacts_path) {
101   if (host_artifacts_path.empty() || !DirectoryExists(host_artifacts_path)) {
102     return false;
103   }
104   const auto host_bin_path = host_artifacts_path + "/bin";
105   auto contents_result = DirectoryContents(host_bin_path);
106   if (!contents_result.ok()) {
107     return false;
108   }
109   std::vector<std::string> contents = std::move(*contents_result);
110   std::set<std::string> contents_set{std::move_iterator(contents.begin()),
111                                      std::move_iterator(contents.end())};
112   std::set<std::string> launchers = {"cvd", "launch_cvd"};
113   std::vector<std::string> result;
114   std::set_intersection(launchers.cbegin(), launchers.cend(),
115                         contents_set.cbegin(), contents_set.cend(),
116                         std::back_inserter(result));
117   return !result.empty();
118 }
119 
GenerateTooManyInstancesErrorMsg(const int n,const std::string & field_name)120 std::string GenerateTooManyInstancesErrorMsg(const int n,
121                                              const std::string& field_name) {
122   std::stringstream s;
123   s << "Only up to " << n << " must match";
124   if (!field_name.empty()) {
125     s << " by the field " << field_name;
126   }
127   return s.str();
128 }
129 
130 }  // namespace selector
131 }  // namespace cuttlefish
132