diff --git a/src/lib/Lib/Config.cpp b/src/lib/Lib/Config.cpp index d5a37566e7..035aa649e4 100644 --- a/src/lib/Lib/Config.cpp +++ b/src/lib/Lib/Config.cpp @@ -150,7 +150,8 @@ struct PublicSettingsVisitor { std::string& value, ReferenceDirectories const& dirs, PublicSettings::OptionProperties const& opts, - bool const usingDefault) { + bool const usingDefault) + { // If the path is not absolute, we need to expand it if (!files::isAbsolute(value)) { @@ -256,39 +257,71 @@ struct PublicSettingsVisitor { PublicSettings::OptionProperties const& opts, bool const usingDefault) const { - for (auto& value : values) + // Move command line sink values to appropriate destinations + // Normalization happens later for each destination + if (opts.commandLineSink && opts.filenameMapping.has_value()) + { + MRDOCS_TRY(normalizeCmdLineSink(self, values, opts)); + } + else { - MRDOCS_DECL(normalizeStringPath(self, name, value, dirs, opts, usingDefault)); + // General case, normalize each path + for (auto& value : values) + { + MRDOCS_TRY(normalizeStringPath(self, name, value, dirs, opts, usingDefault)); + } } + return {}; + } + template + Expected + normalizeCmdLineSink( + PublicSettings& self, + T& values, + PublicSettings::OptionProperties const& opts) const + { // Move command line sink values to appropriate destinations - if (opts.commandLineSink && opts.filenameMapping.has_value()) + for (auto& value : values) { - for (auto& value : values) + std::string_view filename = files::getFileName(value); + auto it = opts.filenameMapping->find(std::string(filename)); + if (it == opts.filenameMapping->end()) + { + report::warn("command line input: unknown destination for filename \"{}\"", filename); + continue; + } + // Assign the value to the destination option of the map + std::string const& destOption = it->second; + bool foundOption = false; + bool setOption = false; + self.visit( + [&]( + std::string_view const optionName, U& optionValue) { - for (auto const& map = opts.filenameMapping.value(); - auto& [from, to] : map) + if constexpr (std::convertible_to) { - auto filename = files::getFileName(value); - if (filename == from) + if (optionName == destOption) { - self.visit( - [&]( - std::string_view const otherName, U& otherValue) + foundOption = true; + if (optionValue.empty()) { - if constexpr (std::convertible_to) - { - if (otherName == to) - { - otherValue = value; - } - } - }); + optionValue = value; + setOption = true; + } } } + }); + if (!foundOption) + { + report::warn("command line input: cannot find destination option \"{}\"", destOption); + } + else if (!setOption) + { + report::warn("command line input: destination option was \"{}\" already set", destOption); } } - + values.clear(); return {}; } diff --git a/src/lib/Lib/ConfigOptions.json b/src/lib/Lib/ConfigOptions.json index 233edfffc3..4842722b77 100644 --- a/src/lib/Lib/ConfigOptions.json +++ b/src/lib/Lib/ConfigOptions.json @@ -15,8 +15,8 @@ "command-line-sink": true, "filename-mapping": { "mrdocs.yml": "config", - "compile_commands.json": "compilationDatabase", - "CMakeLists.txt": "compilationDatabase" + "compile_commands.json": "compilation-database", + "CMakeLists.txt": "compilation-database" }, "relative-to": "", "must-exist": true, diff --git a/src/tool/ToolMain.cpp b/src/tool/ToolMain.cpp index 004691b6eb..828407e2c9 100644 --- a/src/tool/ToolMain.cpp +++ b/src/tool/ToolMain.cpp @@ -19,11 +19,11 @@ #include #include #include +#include extern int main(int argc, char const** argv); -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { extern int @@ -47,7 +47,7 @@ print_version(llvm::raw_ostream& os) << "\n"; } -Expected> +Expected getReferenceDirectories(std::string const& execPath) { ReferenceDirectories dirs; @@ -58,36 +58,37 @@ getReferenceDirectories(std::string const& execPath) return Unexpected(formatError("Unable to determine current working directory: {}", ec.message())); } dirs.cwd = std::string(cwd.data(), cwd.size()); + return dirs; +} + +Expected +getConfigPath(ReferenceDirectories const& dirs) +{ std::string configPath; - if (toolArgs.config.getValue() != "") + auto cmdLineFilenames = std::ranges::views::transform( + toolArgs.cmdLineInputs, files::getFileName); + if (!toolArgs.config.getValue().empty()) { + // From explicit --config argument configPath = toolArgs.config.getValue(); } - else + else if (auto const it = std::ranges::find(cmdLineFilenames, "mrdocs.yml"); + it != cmdLineFilenames.end()) { - llvm::cl::list& inputs = toolArgs.cmdLineInputs; - for (auto& input: inputs) - { - if (files::getFileName(input) == "mrdocs.yml") - { - configPath = input; - break; - } - } + // From implicit command line inputs + configPath = *(it.base()); } - if (configPath.empty()) + else if (files::exists("./mrdocs.yml")) { - if (files::exists("./mrdocs.yml")) - { - configPath = "./mrdocs.yml"; - } + // From current directory + configPath = "./mrdocs.yml"; } - if (configPath.empty()) + else { return Unexpected(formatError("The config path is missing")); } configPath = files::makeAbsolute(configPath, dirs.cwd); - return std::make_pair(configPath, dirs); + return configPath; } int @@ -129,7 +130,15 @@ mrdocs_main(int argc, char const** argv) report::fatal("Failed to determine reference directories: {}", res.error().message()); return EXIT_FAILURE; } - auto [configPath, dirs] = *res; + auto dirs = *std::move(res); + + auto expConfigPath = getConfigPath(dirs); + if (!expConfigPath) + { + report::fatal("Failed to determine config path: {}", expConfigPath.error().message()); + return EXIT_FAILURE; + } + auto configPath = *std::move(expConfigPath); // Generate auto exp = DoGenerateAction(configPath, dirs, argv); @@ -156,8 +165,7 @@ reportUnhandledException( sys::PrintStackTrace(llvm::errs()); } -} // mrdocs -} // clang +} // clang::mrdocs int main(int argc, char const** argv) diff --git a/util/generate-config-info.py b/util/generate-config-info.py index 0427723868..bc3122c2b2 100644 --- a/util/generate-config-info.py +++ b/util/generate-config-info.py @@ -839,11 +839,11 @@ def generate_toolargs_final_option_initializer(option, category_str, parents=Non if option['command-line-sink']: constructor_args.append('llvm::cl::Sink') if 'default' in option: - if option["type"] in ['string', 'enum']: - constructor_args.append(f'llvm::cl::init("{option["default"]}")') - elif option["type"] in ['path', 'file-path', 'dir-path']: - constructor_args.append(f'llvm::cl::init("{remove_reference_dir_from_path(option["default"])}")') - elif option['type'] in ['unsigned', 'int']: + # if option["type"] in ['string', 'enum']: + # constructor_args.append(f'llvm::cl::init("{option["default"]}")') + # elif option["type"] in ['path', 'file-path', 'dir-path']: + # constructor_args.append(f'llvm::cl::init("{remove_reference_dir_from_path(option["default"])}")') + if option['type'] in ['unsigned', 'int']: constructor_args.append(f'llvm::cl::init({option["default"]})') elif option['type'] == 'bool': bool_str = 'true' if option['default'] else 'false'