Skip to content

Commit a1fb8ec

Browse files
committed
refactor(generate-config-info): normalization via visitor
1 parent 9ef4c38 commit a1fb8ec

File tree

9 files changed

+411
-400
lines changed

9 files changed

+411
-400
lines changed

include/mrdocs/Config.hpp

-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ class MRDOCS_DECL
6262
*/
6363
struct Settings : public PublicSettings
6464
{
65-
using ReferenceDirectories = PublicSettings::ReferenceDirectories;
66-
6765
/**
6866
* @brief Loads the public configuration settings from the specified YAML file.
6967
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// This is a derivative work. originally part of the LLVM Project.
3+
// Licensed under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
// Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com)
8+
//
9+
// Official repository: https://github.com/cppalliance/mrdocs
10+
//
11+
12+
#ifndef MRDOCS_API_CONFIG_REFERENCE_DIRECTORIES_HPP
13+
#define MRDOCS_API_CONFIG_REFERENCE_DIRECTORIES_HPP
14+
15+
#include <string>
16+
17+
namespace clang {
18+
namespace mrdocs {
19+
20+
/** Reference directories used to resolve paths
21+
*/
22+
struct ReferenceDirectories {
23+
std::string configDir;
24+
std::string cwd;
25+
std::string mrdocsRoot;
26+
};
27+
28+
} // mrdocs
29+
} // clang
30+
31+
#endif

src/lib/Lib/Config.cpp

+196-11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <mrdocs/Support/Path.hpp>
1515
#include <llvm/Support/FileSystem.h>
1616
#include <ranges>
17+
#include <thread>
1718

1819
namespace clang {
1920
namespace mrdocs {
@@ -70,23 +71,207 @@ load_file(
7071
return {};
7172
}
7273

73-
Expected<void>
74-
Config::Settings::
75-
normalize(ReferenceDirectories const& dirs)
76-
{
77-
auto exp = PublicSettings::normalize(*this, dirs);
78-
if (!exp)
74+
struct PublicSettingsVisitor {
75+
template <class T>
76+
Expected<void>
77+
operator()(
78+
PublicSettings& self,
79+
std::string_view name,
80+
T& value,
81+
ReferenceDirectories const& dirs,
82+
PublicSettings::OptionProperties const& opts)
83+
{
84+
using DT = std::decay_t<T>;
85+
if constexpr (std::ranges::range<T>)
86+
{
87+
bool const useDefault = value.empty() && std::holds_alternative<DT>(opts.defaultValue);
88+
if (useDefault) {
89+
value = std::get<DT>(opts.defaultValue);
90+
}
91+
if (value.empty() && opts.required) {
92+
return formatError("`{}` option is required", name);
93+
}
94+
if constexpr (std::same_as<DT, std::string>) {
95+
if (!value.empty() &&
96+
(opts.type == PublicSettings::OptionType::Path ||
97+
opts.type == PublicSettings::OptionType::DirPath ||
98+
opts.type == PublicSettings::OptionType::FilePath))
99+
{
100+
// If the path is not absolute, we need to expand it
101+
if (!files::isAbsolute(value)) {
102+
auto exp = getBaseDir(value, dirs, useDefault, opts);
103+
if (!exp)
104+
{
105+
MRDOCS_TRY(value, files::makeAbsolute(value));
106+
}
107+
else
108+
{
109+
std::string_view baseDir = *exp;
110+
value = files::makeAbsolute(value, baseDir);
111+
}
112+
}
113+
if (opts.mustExist &&
114+
!files::exists(value))
115+
{
116+
return Unexpected(formatError("`{}` option: path does not exist: {}", name, value));
117+
}
118+
if (opts.type == PublicSettings::OptionType::DirPath &&
119+
!files::isDirectory(value))
120+
{
121+
return Unexpected(formatError("`{}` option: path should be a directory: {}", name, value));
122+
}
123+
if (opts.type == PublicSettings::OptionType::FilePath &&
124+
files::isDirectory(value))
125+
{
126+
return Unexpected(formatError("`{}` option: path should be a regular file: {}", name, value));
127+
}
128+
}
129+
else if (opts.type == PublicSettings::OptionType::String) {
130+
if (name == "base-url")
131+
{
132+
if (!value.empty() && value.back() != '/') {
133+
value.push_back('/');
134+
}
135+
}
136+
}
137+
}
138+
else if constexpr (std::same_as<DT, std::vector<std::string>>) {
139+
if (opts.type == PublicSettings::OptionType::ListPath) {
140+
for (auto& v : value) {
141+
if (!files::isAbsolute(v))
142+
{
143+
auto exp = getBaseDir(v, dirs, useDefault, opts);
144+
if (!exp)
145+
{
146+
MRDOCS_TRY(v, files::makeAbsolute(v));
147+
}
148+
else
149+
{
150+
std::string_view baseDir = *exp;
151+
v = files::makeAbsolute(v, baseDir);
152+
}
153+
}
154+
if (opts.mustExist && !files::exists(v))
155+
{
156+
return Unexpected(formatError("`{}` option: path does not exist: {}", name, v));
157+
}
158+
if (opts.commandLineSink && opts.filenameMapping.has_value())
159+
{
160+
auto const& map = opts.filenameMapping.value();
161+
for (auto& [from, to] : map) {
162+
auto f = files::getFileName(v);
163+
if (f == from)
164+
{
165+
auto* dest = fileMapDest(self, to);
166+
if (dest) {
167+
*dest = v;
168+
}
169+
}
170+
}
171+
}
172+
}
173+
}
174+
}
175+
}
176+
else if constexpr (std::same_as<DT, int> || std::same_as<DT, unsigned>) {
177+
if (name == "concurrency" && std::cmp_equal(value, 0))
178+
{
179+
value = std::thread::hardware_concurrency();
180+
}
181+
if (opts.minValue && std::cmp_less(value, *opts.minValue))
182+
{
183+
return Unexpected(formatError("`{}` option: value {} is less than minimum: {}", name, value, *opts.minValue));
184+
}
185+
if (opts.maxValue && std::cmp_greater(value, *opts.maxValue))
186+
{
187+
return Unexpected(formatError("`{}` option: value {} is greater than maximum: {}", name, value, *opts.maxValue));
188+
}
189+
}
190+
191+
// Booleans should already be validated because the struct
192+
// already has their default values
193+
return {};
194+
}
195+
196+
static
197+
std::string*
198+
fileMapDest(PublicSettings& self, std::string_view mapDest)
79199
{
80-
return exp.error();
200+
if (mapDest == "config") {
201+
return &self.config;
202+
}
203+
if (mapDest == "compilationDatabase") {
204+
return &self.compilationDatabase;
205+
}
206+
return nullptr;
81207
}
82208

83-
// Base-URL has to be dirsy with forward slash style
84-
if (!baseUrl.empty() && baseUrl.back() != '/')
209+
Expected<std::string_view>
210+
getBaseDir(
211+
std::string_view referenceDirKey,
212+
ReferenceDirectories const& dirs)
85213
{
86-
baseUrl.push_back('/');
214+
if (referenceDirKey == "config-dir") {
215+
return dirs.configDir;
216+
}
217+
else if (referenceDirKey == "cwd") {
218+
return dirs.cwd;
219+
}
220+
else if (referenceDirKey == "mrdocs-root") {
221+
return dirs.mrdocsRoot;
222+
}
223+
return Unexpected(formatError("unknown relative-to value: \"{}\"", referenceDirKey));
87224
}
88225

89-
return {};
226+
static
227+
std::string_view
228+
trimBaseDirReference(std::string_view s)
229+
{
230+
if (s.size() > 2 &&
231+
s.front() == '<' &&
232+
s.back() == '>') {
233+
s.remove_prefix(1);
234+
s.remove_suffix(1);
235+
}
236+
return s;
237+
};
238+
239+
Expected<std::string_view>
240+
getBaseDir(
241+
std::string& value,
242+
ReferenceDirectories const& dirs,
243+
bool useDefault,
244+
PublicSettings::OptionProperties const& opts)
245+
{
246+
if (!useDefault) {
247+
// If we did not use the default value, we use "relativeto"
248+
// as the base path
249+
std::string_view relativeTo = opts.relativeto;
250+
relativeTo = trimBaseDirReference(relativeTo);
251+
return getBaseDir(relativeTo, dirs);
252+
}
253+
254+
// If we used the default value, the base dir comes from
255+
// the first path segment of the value
256+
std::string_view referenceDirKey = value;
257+
auto pos = referenceDirKey.find('/');
258+
if (pos != std::string::npos) {
259+
referenceDirKey = referenceDirKey.substr(0, pos);
260+
}
261+
referenceDirKey = trimBaseDirReference(referenceDirKey);
262+
MRDOCS_TRY(std::string_view baseDir, getBaseDir(referenceDirKey, dirs));
263+
if (pos != std::string::npos) {
264+
value = value.substr(pos + 1);
265+
}
266+
return baseDir;
267+
}
268+
};
269+
270+
Expected<void>
271+
Config::Settings::
272+
normalize(ReferenceDirectories const& dirs)
273+
{
274+
return PublicSettings::normalize(dirs, PublicSettingsVisitor{});
90275
}
91276

92277
} // mrdocs

src/lib/Lib/ConfigImpl.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ Expected<std::shared_ptr<ConfigImpl const>>
133133
ConfigImpl::
134134
load(
135135
Config::Settings const& publicSettings,
136-
Config::Settings::ReferenceDirectories const& dirs,
136+
ReferenceDirectories const& dirs,
137137
ThreadPool& threadPool)
138138
{
139139
std::shared_ptr<ConfigImpl> c =

src/lib/Lib/ConfigImpl.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class ConfigImpl
119119
Expected<std::shared_ptr<ConfigImpl const>>
120120
load(
121121
Config::Settings const& publicSettings,
122-
Config::Settings::ReferenceDirectories const& dirs,
122+
ReferenceDirectories const& dirs,
123123
ThreadPool& threadPool);
124124

125125
ThreadPool&

src/test/TestRunner.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class TestRunner
5353
ThreadPool threadPool_;
5454
llvm::ErrorOr<std::string> diffCmdPath_;
5555
Generator const* gen_;
56-
Config::Settings::ReferenceDirectories dirs_;
56+
ReferenceDirectories dirs_;
5757

5858
Error writeFile(
5959
llvm::StringRef filePath,

src/tool/GenerateAction.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ generateCompileCommandsFile(llvm::StringRef inputPath, llvm::StringRef cmakeArgs
8888
Expected<void>
8989
DoGenerateAction(
9090
std::string const& configPath,
91-
Config::Settings::ReferenceDirectories const& dirs,
91+
ReferenceDirectories const& dirs,
9292
char const** argv)
9393
{
9494
// --------------------------------------------------------------

src/tool/ToolMain.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ namespace mrdocs {
2727

2828
extern
2929
int
30-
DoTestAction();
30+
DoTestAction(char const** argv);
3131

3232
extern
3333
Expected<void>
3434
DoGenerateAction(
3535
std::string const& configPath,
36-
Config::Settings::ReferenceDirectories const& dirs,
36+
ReferenceDirectories const& dirs,
3737
char const** argv);
3838

3939
void
@@ -47,10 +47,10 @@ print_version(llvm::raw_ostream& os)
4747
<< "\n";
4848
}
4949

50-
Expected<std::pair<std::string, Config::Settings::ReferenceDirectories>>
50+
Expected<std::pair<std::string, ReferenceDirectories>>
5151
getReferenceDirectories(std::string const& execPath)
5252
{
53-
Config::Settings::ReferenceDirectories dirs;
53+
ReferenceDirectories dirs;
5454
dirs.mrdocsRoot = files::getParentDir(execPath, 2);
5555
llvm::SmallVector<char, 256> cwd;
5656
if (auto ec = llvm::sys::fs::current_path(cwd); ec)

0 commit comments

Comments
 (0)