Skip to content

Commit

Permalink
refactor(generate-config-info): normalization via visitor
Browse files Browse the repository at this point in the history
  • Loading branch information
alandefreitas committed Oct 24, 2024
1 parent 9ef4c38 commit a1fb8ec
Show file tree
Hide file tree
Showing 9 changed files with 411 additions and 400 deletions.
2 changes: 0 additions & 2 deletions include/mrdocs/Config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ class MRDOCS_DECL
*/
struct Settings : public PublicSettings
{
using ReferenceDirectories = PublicSettings::ReferenceDirectories;

/**
* @brief Loads the public configuration settings from the specified YAML file.
*
Expand Down
31 changes: 31 additions & 0 deletions include/mrdocs/Config/ReferenceDirectories.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// This is a derivative work. originally part of the LLVM Project.
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com)
//
// Official repository: https://github.com/cppalliance/mrdocs
//

#ifndef MRDOCS_API_CONFIG_REFERENCE_DIRECTORIES_HPP
#define MRDOCS_API_CONFIG_REFERENCE_DIRECTORIES_HPP

#include <string>

namespace clang {
namespace mrdocs {

/** Reference directories used to resolve paths
*/
struct ReferenceDirectories {
std::string configDir;
std::string cwd;
std::string mrdocsRoot;
};

} // mrdocs
} // clang

#endif
207 changes: 196 additions & 11 deletions src/lib/Lib/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <mrdocs/Support/Path.hpp>
#include <llvm/Support/FileSystem.h>
#include <ranges>
#include <thread>

namespace clang {
namespace mrdocs {
Expand Down Expand Up @@ -70,23 +71,207 @@ load_file(
return {};
}

Expected<void>
Config::Settings::
normalize(ReferenceDirectories const& dirs)
{
auto exp = PublicSettings::normalize(*this, dirs);
if (!exp)
struct PublicSettingsVisitor {
template <class T>
Expected<void>
operator()(
PublicSettings& self,
std::string_view name,
T& value,
ReferenceDirectories const& dirs,
PublicSettings::OptionProperties const& opts)
{
using DT = std::decay_t<T>;
if constexpr (std::ranges::range<T>)
{
bool const useDefault = value.empty() && std::holds_alternative<DT>(opts.defaultValue);
if (useDefault) {
value = std::get<DT>(opts.defaultValue);
}
if (value.empty() && opts.required) {
return formatError("`{}` option is required", name);
}
if constexpr (std::same_as<DT, std::string>) {
if (!value.empty() &&
(opts.type == PublicSettings::OptionType::Path ||
opts.type == PublicSettings::OptionType::DirPath ||
opts.type == PublicSettings::OptionType::FilePath))
{
// If the path is not absolute, we need to expand it
if (!files::isAbsolute(value)) {
auto exp = getBaseDir(value, dirs, useDefault, opts);
if (!exp)
{
MRDOCS_TRY(value, files::makeAbsolute(value));
}
else
{
std::string_view baseDir = *exp;
value = files::makeAbsolute(value, baseDir);
}
}
if (opts.mustExist &&
!files::exists(value))
{
return Unexpected(formatError("`{}` option: path does not exist: {}", name, value));
}
if (opts.type == PublicSettings::OptionType::DirPath &&
!files::isDirectory(value))
{
return Unexpected(formatError("`{}` option: path should be a directory: {}", name, value));
}
if (opts.type == PublicSettings::OptionType::FilePath &&
files::isDirectory(value))
{
return Unexpected(formatError("`{}` option: path should be a regular file: {}", name, value));
}
}
else if (opts.type == PublicSettings::OptionType::String) {
if (name == "base-url")
{
if (!value.empty() && value.back() != '/') {
value.push_back('/');
}
}
}
}
else if constexpr (std::same_as<DT, std::vector<std::string>>) {
if (opts.type == PublicSettings::OptionType::ListPath) {
for (auto& v : value) {
if (!files::isAbsolute(v))
{
auto exp = getBaseDir(v, dirs, useDefault, opts);
if (!exp)
{
MRDOCS_TRY(v, files::makeAbsolute(v));
}
else
{
std::string_view baseDir = *exp;
v = files::makeAbsolute(v, baseDir);
}
}
if (opts.mustExist && !files::exists(v))
{
return Unexpected(formatError("`{}` option: path does not exist: {}", name, v));
}
if (opts.commandLineSink && opts.filenameMapping.has_value())
{
auto const& map = opts.filenameMapping.value();
for (auto& [from, to] : map) {
auto f = files::getFileName(v);
if (f == from)
{
auto* dest = fileMapDest(self, to);
if (dest) {
*dest = v;
}
}
}
}
}
}
}
}
else if constexpr (std::same_as<DT, int> || std::same_as<DT, unsigned>) {
if (name == "concurrency" && std::cmp_equal(value, 0))
{
value = std::thread::hardware_concurrency();
}
if (opts.minValue && std::cmp_less(value, *opts.minValue))
{
return Unexpected(formatError("`{}` option: value {} is less than minimum: {}", name, value, *opts.minValue));
}
if (opts.maxValue && std::cmp_greater(value, *opts.maxValue))
{
return Unexpected(formatError("`{}` option: value {} is greater than maximum: {}", name, value, *opts.maxValue));
}
}

// Booleans should already be validated because the struct
// already has their default values
return {};
}

static
std::string*
fileMapDest(PublicSettings& self, std::string_view mapDest)
{
return exp.error();
if (mapDest == "config") {
return &self.config;
}
if (mapDest == "compilationDatabase") {
return &self.compilationDatabase;
}
return nullptr;
}

// Base-URL has to be dirsy with forward slash style
if (!baseUrl.empty() && baseUrl.back() != '/')
Expected<std::string_view>
getBaseDir(
std::string_view referenceDirKey,
ReferenceDirectories const& dirs)
{
baseUrl.push_back('/');
if (referenceDirKey == "config-dir") {
return dirs.configDir;
}
else if (referenceDirKey == "cwd") {
return dirs.cwd;
}
else if (referenceDirKey == "mrdocs-root") {
return dirs.mrdocsRoot;
}
return Unexpected(formatError("unknown relative-to value: \"{}\"", referenceDirKey));
}

return {};
static
std::string_view
trimBaseDirReference(std::string_view s)
{
if (s.size() > 2 &&
s.front() == '<' &&
s.back() == '>') {
s.remove_prefix(1);
s.remove_suffix(1);
}
return s;
};

Expected<std::string_view>
getBaseDir(
std::string& value,
ReferenceDirectories const& dirs,
bool useDefault,
PublicSettings::OptionProperties const& opts)
{
if (!useDefault) {
// If we did not use the default value, we use "relativeto"
// as the base path
std::string_view relativeTo = opts.relativeto;
relativeTo = trimBaseDirReference(relativeTo);
return getBaseDir(relativeTo, dirs);
}

// If we used the default value, the base dir comes from
// the first path segment of the value
std::string_view referenceDirKey = value;
auto pos = referenceDirKey.find('/');
if (pos != std::string::npos) {
referenceDirKey = referenceDirKey.substr(0, pos);
}
referenceDirKey = trimBaseDirReference(referenceDirKey);
MRDOCS_TRY(std::string_view baseDir, getBaseDir(referenceDirKey, dirs));
if (pos != std::string::npos) {
value = value.substr(pos + 1);
}
return baseDir;
}
};

Expected<void>
Config::Settings::
normalize(ReferenceDirectories const& dirs)
{
return PublicSettings::normalize(dirs, PublicSettingsVisitor{});
}

} // mrdocs
Expand Down
2 changes: 1 addition & 1 deletion src/lib/Lib/ConfigImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ Expected<std::shared_ptr<ConfigImpl const>>
ConfigImpl::
load(
Config::Settings const& publicSettings,
Config::Settings::ReferenceDirectories const& dirs,
ReferenceDirectories const& dirs,
ThreadPool& threadPool)
{
std::shared_ptr<ConfigImpl> c =
Expand Down
2 changes: 1 addition & 1 deletion src/lib/Lib/ConfigImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class ConfigImpl
Expected<std::shared_ptr<ConfigImpl const>>
load(
Config::Settings const& publicSettings,
Config::Settings::ReferenceDirectories const& dirs,
ReferenceDirectories const& dirs,
ThreadPool& threadPool);

ThreadPool&
Expand Down
2 changes: 1 addition & 1 deletion src/test/TestRunner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class TestRunner
ThreadPool threadPool_;
llvm::ErrorOr<std::string> diffCmdPath_;
Generator const* gen_;
Config::Settings::ReferenceDirectories dirs_;
ReferenceDirectories dirs_;

Error writeFile(
llvm::StringRef filePath,
Expand Down
2 changes: 1 addition & 1 deletion src/tool/GenerateAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ generateCompileCommandsFile(llvm::StringRef inputPath, llvm::StringRef cmakeArgs
Expected<void>
DoGenerateAction(
std::string const& configPath,
Config::Settings::ReferenceDirectories const& dirs,
ReferenceDirectories const& dirs,
char const** argv)
{
// --------------------------------------------------------------
Expand Down
8 changes: 4 additions & 4 deletions src/tool/ToolMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ namespace mrdocs {

extern
int
DoTestAction();
DoTestAction(char const** argv);

extern
Expected<void>
DoGenerateAction(
std::string const& configPath,
Config::Settings::ReferenceDirectories const& dirs,
ReferenceDirectories const& dirs,
char const** argv);

void
Expand All @@ -47,10 +47,10 @@ print_version(llvm::raw_ostream& os)
<< "\n";
}

Expected<std::pair<std::string, Config::Settings::ReferenceDirectories>>
Expected<std::pair<std::string, ReferenceDirectories>>
getReferenceDirectories(std::string const& execPath)
{
Config::Settings::ReferenceDirectories dirs;
ReferenceDirectories dirs;
dirs.mrdocsRoot = files::getParentDir(execPath, 2);
llvm::SmallVector<char, 256> cwd;
if (auto ec = llvm::sys::fs::current_path(cwd); ec)
Expand Down
Loading

0 comments on commit a1fb8ec

Please sign in to comment.