Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions include/mrdocs/Config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ class MRDOCS_DECL

/** Full path to the config file directory

The working directory is the directory
of the mrdocs.yml file.
The reference directory for most MrDocs
options is the directory of the
mrdocs.yml file.

It is used to calculate full paths
from relative paths.
Expand All @@ -123,6 +124,29 @@ class MRDOCS_DECL
std::string
configDir() const;

/** Full path to the output directory

The reference directory for MrDocs
output and temporary files is the
output directory.

This is either the output option
(if already a directory) or
the parent directory of the output
option (if it is a file).

When the output option is a path
that does not exist, we determine
if it's a file or directory by
checking if the filename contains
a period.

This string will always be native style
and have a trailing directory separator.
*/
std::string
outputDir() const;

/** Full path to the mrdocs root directory

This is the directory containing the
Expand Down
3 changes: 2 additions & 1 deletion include/mrdocs/Support/Algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
#ifndef MRDOCS_API_SUPPORT_ALGORITHM_HPP
#define MRDOCS_API_SUPPORT_ALGORITHM_HPP

#include <cstdint>
#include <mrdocs/Support/Concepts.hpp>
#include <cstdint>
#include <algorithm>

namespace clang::mrdocs {

Expand Down
15 changes: 15 additions & 0 deletions include/mrdocs/Support/Path.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,21 @@ bool
isDirectory(
std::string_view pathName);

/** Determine lexically if a path is a directory.
This function determines if a path is a directory.
If the path does not exist, the function
determines lexically if the path represents
a directory. In this case, the function
returns true if the last path segment
contains a period, otherwise false.
*/
MRDOCS_DECL
bool
isLexicalDirectory(
std::string_view pathName);

/** Determine if a path is a directory.
*/
MRDOCS_DECL
Expand Down
40 changes: 36 additions & 4 deletions src/lib/Lib/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
// Official repository: https://github.com/cppalliance/mrdocs
//

#include "mrdocs/Config.hpp"
#include <mrdocs/Support/Report.hpp>
#include <mrdocs/Support/Path.hpp>
#include <llvm/Support/FileSystem.h>
#include <mrdocs/Config.hpp>
#include <mrdocs/Support/Algorithm.hpp>
#include <ranges>
#include <thread>
#include <llvm/Support/FileSystem.h>
#include <mrdocs/Support/Path.hpp>
#include <mrdocs/Support/Report.hpp>

namespace clang {
namespace mrdocs {
Expand Down Expand Up @@ -534,5 +535,36 @@ configDir() const
return files::getParentDir(config);
}

/** Full path to the output directory

The reference directory for MrDocs
output and temporary files is the
output directory.

This is either the output option
(if already a directory) or
the parent directory of the output
option (if it is a file).

When the output option is a path
that does not exist, we determine
if it's a file or directory by
checking if the filename contains
a period.

This string will always be native style
and have a trailing directory separator.
*/
std::string
Config::Settings::
outputDir() const
{
if (files::isLexicalDirectory(output))
{
return output;
}
return files::getParentDir(output);
}

} // mrdocs
} // clang
68 changes: 50 additions & 18 deletions src/lib/Support/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
//

#include "Path.hpp"
#include <mrdocs/Support/Algorithm.hpp>
#include <mrdocs/Support/Report.hpp>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Path.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/Path.h>
#include <fstream>

namespace clang {
Expand Down Expand Up @@ -378,11 +379,27 @@ isDirectory(
{
namespace fs = llvm::sys::fs;
fs::file_status fileStatus;
if(auto ec = fs::status(pathName, fileStatus))
return false;
if(fileStatus.type() != fs::file_type::directory_file)
if (auto ec = fs::status(pathName, fileStatus))
{
return false;
return true;
}
return fileStatus.type() == fs::file_type::directory_file;
}

bool
isLexicalDirectory(
std::string_view pathName)
{
namespace fs = llvm::sys::fs;
fs::file_status fileStatus;
if (auto const ec = fs::status(pathName, fileStatus);
ec ||
fileStatus.type() == fs::file_type::file_not_found)
{
auto const filename = getFileName(pathName);
return !contains(filename, '.');
}
return fileStatus.type() == fs::file_type::directory_file;
}

bool
Expand Down Expand Up @@ -487,7 +504,7 @@ ScopedTempFile(

ScopedTempDirectory::
~ScopedTempDirectory() {
if (ok_)
if (*this)
{
llvm::sys::fs::remove_directories(path_);
}
Expand All @@ -498,11 +515,12 @@ ScopedTempDirectory(
llvm::StringRef prefix)
{
llvm::SmallString<128> tempPath;
ok_ = !llvm::sys::fs::createUniqueDirectory(prefix, tempPath);
if (ok_)
if (llvm::sys::fs::createUniqueDirectory(prefix, tempPath))
{
path_ = tempPath;
status_ = ErrorStatus::CannotCreateDirectories;
return;
}
path_ = tempPath;
}

ScopedTempDirectory::
Expand All @@ -513,19 +531,33 @@ ScopedTempDirectory(
llvm::SmallString<128> tempPath(root);
llvm::sys::path::append(tempPath, dir);
bool const exists = llvm::sys::fs::exists(tempPath);
if (exists)
if (exists &&
llvm::sys::fs::remove_directories(tempPath))
{
ok_ = !llvm::sys::fs::remove_directories(tempPath);
if (!ok_)
{
return;
}
status_ = ErrorStatus::CannotDeleteExisting;
return;
}
ok_ = !llvm::sys::fs::create_directory(tempPath);
if (ok_)
if (llvm::sys::fs::create_directories(tempPath))
{
path_ = tempPath;
status_ = ErrorStatus::CannotCreateDirectories;
return;
}
path_ = tempPath;
}

Error
ScopedTempDirectory::
error() const
{
if (status_ == ErrorStatus::CannotDeleteExisting)
{
return Error("Failed to delete existing directory");
}
if (status_ == ErrorStatus::CannotCreateDirectories)
{
return Error("Failed to create directories");
}
return Error();
}

} // mrdocs
Expand Down
27 changes: 25 additions & 2 deletions src/lib/Support/Path.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,16 @@ class ScopedTempFile
*/
class ScopedTempDirectory
{
// Status of the directory
enum class ErrorStatus
{
None,
CannotDeleteExisting,
CannotCreateDirectories
};

clang::mrdocs::SmallPathString path_;
bool ok_ = false;
ErrorStatus status_ = ErrorStatus::None;
public:
/** Destructor

Expand Down Expand Up @@ -129,12 +137,27 @@ class ScopedTempDirectory

/** Returns `true` if the directory was created successfully.
*/
operator bool() const { return ok_; }
operator bool() const
{
return status_ == ErrorStatus::None;
}

/** Returns `true` if the directory was not created successfully.
*/
bool
failed() const
{
return status_ != ErrorStatus::None;
}

/** Returns the path to the temporary directory.
*/
std::string_view path() const { return static_cast<llvm::StringRef>(path_); }

/** Returns the error status of the directory.
*/
Error error() const;

/** Convert temp directory to a std::string_view
*/
operator std::string_view() const { return path(); }
Expand Down
9 changes: 8 additions & 1 deletion src/tool/GenerateAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,14 @@ DoGenerateAction(
MRDOCS_CHECK(
compilationDatabasePath,
"The compilation database path argument is missing");
ScopedTempDirectory tempDir(config->settings().output, ".temp");
ScopedTempDirectory tempDir(
config->settings().outputDir(),
".temp");
if (tempDir.failed())
{
report::error("Failed to create temporary directory: {}", tempDir.error());
return Unexpected(tempDir.error());
}
std::string buildPath = files::appendPath(tempDir, "build");
Expected<std::string> const compileCommandsPathExp =
generateCompileCommandsFile(
Expand Down
Loading