• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020-2021 Huawei Technologies Co., Ltd
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 "tools/common/flag_parser.h"
18 #include "src/common/log_adapter.h"
19 #include "tools/converter/converter_context.h"
20 #include "src/common/file_utils.h"
21 
22 namespace mindspore {
23 namespace lite {
24 constexpr auto kConverterLite = "converter_lite";
25 // parse flags read from command line
ParseFlags(int argc,const char * const * argv,bool supportUnknown,bool supportDuplicate)26 Option<std::string> FlagParser::ParseFlags(int argc, const char *const *argv, bool supportUnknown,
27                                            bool supportDuplicate) {
28   MS_ASSERT(argv != nullptr);
29   const int FLAG_PREFIX_LEN = 2;
30   if (argc <= 0) {
31     MS_LOG(ERROR) << "The arguments number is out of range";
32     return Option<std::string>("Failed: flags is not valid");
33   }
34   binName = GetFileName(argv[0]);
35   if (binName == kConverterLite) {
36     std::map<std::string, std::string> flag_argv_maps;
37     auto real_path = RealPath(argv[0]);
38     if (real_path.empty()) {
39       MS_LOG(WARNING) << kConverterLite << " path is not exist.";
40     }
41     flag_argv_maps["converter_lite_path"] = real_path;
42     ConverterInnerContext::GetInstance()->SetExternalUsedConfigInfos(mindspore::converter::KConverterParam,
43                                                                      flag_argv_maps);
44   }
45 
46   std::multimap<std::string, Option<std::string>> keyValues{};
47   for (int i = 1; i < argc; i++) {
48     std::string tmp = argv[i];
49     Trim(&tmp);
50     const std::string flagItem(tmp);
51 
52     if (flagItem == "--") {
53       break;
54     }
55 
56     if (flagItem.find("--") == std::string::npos) {
57       return Option<std::string>("Failed: flag " + flagItem + " is not valid.");
58     }
59 
60     std::string key;
61     Option<std::string> value = Option<std::string>(None());
62 
63     size_t pos = flagItem.find_first_of('=');
64     if (pos == std::string::npos) {
65       key = flagItem.substr(FLAG_PREFIX_LEN);
66     } else {
67       key = flagItem.substr(FLAG_PREFIX_LEN, pos - FLAG_PREFIX_LEN);
68       value = Option<std::string>(flagItem.substr(pos + 1));
69     }
70 
71     keyValues.insert(std::pair<std::string, Option<std::string>>(key, value));
72   }
73 
74   Option<std::string> ret = Option<std::string>(InnerParseFlags(&keyValues));
75   if (ret.IsSome()) {
76     return Option<std::string>(ret.Get());
77   }
78 
79   return Option<std::string>(None());
80 }
81 
GetRealFlagName(std::string * flagName,const std::string & oriFlagName)82 bool FlagParser::GetRealFlagName(std::string *flagName, const std::string &oriFlagName) {
83   MS_ASSERT(flagName != nullptr);
84   const int BOOL_TYPE_FLAG_PREFIX_LEN = 3;
85   bool opaque = false;
86   if (StartsWithPrefix(oriFlagName, "no-")) {
87     *flagName = oriFlagName.substr(BOOL_TYPE_FLAG_PREFIX_LEN);
88     opaque = true;
89   } else {
90     *flagName = oriFlagName;
91   }
92   return opaque;
93 }
94 
95 // Inner parse function
InnerParseFlags(std::multimap<std::string,Option<std::string>> * keyValues)96 Option<std::string> FlagParser::InnerParseFlags(std::multimap<std::string, Option<std::string>> *keyValues) {
97   MS_ASSERT(keyValues != nullptr);
98   for (auto &keyValue : *keyValues) {
99     std::string flagName;
100     bool opaque = GetRealFlagName(&flagName, keyValue.first);
101     Option<std::string> flagValue = keyValue.second;
102 
103     auto item = flags.find(flagName);
104     if (item == flags.end()) {
105       return Option<std::string>(std::string(flagName + " is not a valid flag"));
106     }
107     FlagInfo *flag = &(item->second);
108     if (flag == nullptr) {
109       return Option<std::string>("Failed: flag is nullptr");
110     }
111     if (flag->isParsed) {
112       return Option<std::string>("Failed: already parsed flag: " + flagName);
113     }
114     std::string tmpValue;
115     if (!flag->isBoolean) {
116       if (opaque) {
117         return Option<std::string>(flagName + " is not a boolean type");
118       }
119       if (flagValue.IsNone()) {
120         return Option<std::string>("No value provided for non-boolean type: " + flagName);
121       }
122       tmpValue = flagValue.Get();
123     } else {
124       if (flagValue.IsNone() || flagValue.Get().empty()) {
125         tmpValue = !opaque ? "true" : "false";
126       } else if (!opaque) {
127         tmpValue = flagValue.Get();
128       } else {
129         return Option<std::string>(std::string("Boolean flag can not have non-empty value"));
130       }
131     }
132     // begin to parse value
133     Option<Nothing> ret = flag->parse(this, tmpValue);
134     if (ret.IsNone()) {
135       return Option<std::string>("Failed to parse value for: " + flag->flagName);
136     }
137     flag->isParsed = true;
138   }
139 
140   // to check flags not given in command line but added as in constructor
141   for (auto &flag : flags) {
142     if (flag.second.isRequired && !flag.second.isParsed) {
143       return Option<std::string>("Error, value of '" + flag.first + "' not provided");
144     }
145   }
146 
147   return Option<std::string>(None());
148 }
149 
ReplaceAll(std::string * str,const std::string & oldValue,const std::string & newValue)150 void ReplaceAll(std::string *str, const std::string &oldValue, const std::string &newValue) {
151   if (str == nullptr) {
152     MS_LOG(ERROR) << "Input str is nullptr";
153     return;
154   }
155   while (true) {
156     std::string::size_type pos(0);
157     if ((pos = str->find(oldValue)) != std::string::npos) {
158       str->replace(pos, oldValue.length(), newValue);
159     } else {
160       break;
161     }
162   }
163 }
164 
Usage(const Option<std::string> & usgMsg) const165 std::string FlagParser::Usage(const Option<std::string> &usgMsg) const {
166   // first line, brief of the usage
167   std::string usageString = usgMsg.IsSome() ? usgMsg.Get() + "\n" : "";
168   // usage of bin name
169   usageString += usageMsg.IsNone() ? "\nusage: " + binName + " [options]\n" : usageMsg.Get() + "\n";
170   // help line of help message, usageLine:message of parameters
171   std::string helpLine;
172   std::string usageLine;
173   uint32_t i = 0;
174   for (auto flag = flags.begin(); flag != flags.end(); flag++) {
175     std::string flagName = flag->second.flagName;
176     std::string helpInfo = flag->second.helpInfo;
177     // parameter line
178     std::string thisLine = flagName == "help" ? " --" + flagName : " --" + flagName + "=VALUE";
179     if (++i <= flags.size()) {
180       // add parameter help message of each line
181       thisLine += " " + helpInfo;
182       ReplaceAll(&helpInfo, "\n\r", "\n");
183       usageLine += thisLine + "\n";
184     } else {
185       // brief help message
186       helpLine = thisLine + " " + helpInfo + "\n";
187     }
188   }
189   // total usage is brief of usage+ brief of bin + help message + brief of
190   // parameters
191   return usageString + helpLine + usageLine;
192 }
193 }  // namespace lite
194 }  // namespace mindspore
195