...and std::filesystem::path::generic_string, which at least GCC 17 trunk
libstdc++ now flags for C++26 (--with-latest-c++) as
> In file included from engine/codemaker/source/netmaker/netproduce.cxx:19:
> engine/codemaker/source/netmaker/csharpfile.hxx:28:53: error: 'string' is deprecated: use 'display_string' or 'native_encoded_string' instead [-Werror,-Wdeprecated-declarations]
> 28 | std::string getPath() const { return m_filePath.string(); }
> | ^
> ~/gcc/inst/lib/gcc/x86_64-pc-linux-gnu/17.0.0/../../../../include/c++/17.0.0/bits/fs_path.h:465:5: note: 'string' has been explicitly marked deprecated here
> 465 | _GLIBCXX26_DEPRECATED_SUGGEST("display_string' or 'native_encoded_string")
> | ^
> ~/gcc/inst/lib/gcc/x86_64-pc-linux-gnu/17.0.0/../../../../include/c++/17.0.0/x86_64-pc-linux-gnu/bits/c++config.h:160:45: note: expanded from macro '_GLIBCXX26_DEPRECATED_SUGGEST'
> 160 | # define _GLIBCXX26_DEPRECATED_SUGGEST(ALT) _GLIBCXX_DEPRECATED_SUGGEST(ALT)
> | ^
> ~/gcc/inst/lib/gcc/x86_64-pc-linux-gnu/17.0.0/../../../../include/c++/17.0.0/x86_64-pc-linux-gnu/bits/c++config.h:112:19: note: expanded from macro '_GLIBCXX_DEPRECATED_SUGGEST'
> 112 | __attribute__ ((__deprecated__ ("use '" ALT "' instead")))
> | ^
since
<https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=341ad729c2c93b9f01854913b0404e4fc8958512>
"libstdc++: Add (generic_)display_string and (generic_)native_encoded_string to
filesystem::path".
Occurrences that are obviously meant for display purposes are #if-conditionally
replaced with the new display_string, while all other occurrences are left using
the (non-deprecated) [generic_]string<char> template instantiation, matching the
original code. (Where, for C++26, the latter could also be replaced with the
new [generic_]native_encoded_string, aka [generic_]system_encoded_string; see
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2319r5.html>
"Prevent path presentation problems" and
<https://cplusplus.github.io/LWG/issue4512> "The system_encoded_string() and
generic_system_encoded_string() member functions of std::filesystem::path are
misnamed" for details.)
Signed-off-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
Change-Id: I7c79c8522608550bb1e0f4cb8e4824480952446b
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/3987
Reviewed-by: Noel Grandin <noel.grandin@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit f320d95d89ecc9bea81182795969f83b05ec903c)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/206226
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
679 lines
20 KiB
C++
679 lines
20 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
// Implementation of Rust file generation and module management
|
|
|
|
#include "rustfile.hxx"
|
|
#include <algorithm>
|
|
#include <filesystem>
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <functional>
|
|
#include <codemaker/global.hxx>
|
|
|
|
RustFile::RustFile(std::string_view directory, std::string_view typeName)
|
|
: m_filePath(createFilePath(directory, typeName))
|
|
, m_indentLevel(0)
|
|
{
|
|
}
|
|
|
|
std::string RustFile::getPath() const
|
|
{
|
|
#if defined __cpp_lib_format_path
|
|
return m_filePath.display_string();
|
|
#else
|
|
return m_filePath.string<char>();
|
|
#endif
|
|
}
|
|
|
|
void RustFile::openFile()
|
|
{
|
|
std::filesystem::create_directories(m_filePath.parent_path());
|
|
createModFiles();
|
|
addFileToModDeclaration();
|
|
m_fileStream.open(m_filePath, std::fstream::out | std::fstream::trunc);
|
|
m_indentLevel = 0;
|
|
}
|
|
|
|
void RustFile::closeFile() { m_fileStream.close(); }
|
|
|
|
void RustFile::createLibFile(const std::filesystem::path& outputDir)
|
|
{
|
|
// Create generated/rustmaker directory first, then src directory inside it
|
|
std::filesystem::path generatedDir = outputDir / "generated";
|
|
std::filesystem::path rustmakerDir = generatedDir / "rustmaker";
|
|
std::filesystem::path srcDir = rustmakerDir / "src";
|
|
std::filesystem::create_directories(srcDir);
|
|
|
|
std::filesystem::path libFile = srcDir / "lib.rs";
|
|
if (!std::filesystem::exists(libFile))
|
|
{
|
|
std::ofstream libStream(libFile);
|
|
libStream << "//! Generated Rust bindings for LibreOffice UNO types\n";
|
|
libStream << "//! \n";
|
|
libStream << "//! This crate contains automatically generated Rust bindings\n";
|
|
libStream << "//! for LibreOffice UNO (Universal Network Objects) types.\n\n";
|
|
libStream.close();
|
|
}
|
|
}
|
|
|
|
void RustFile::createCargoFile(const std::filesystem::path& outputDir, const std::string& crateName)
|
|
{
|
|
// Create Cargo.toml in the generated/rustmaker directory
|
|
std::filesystem::path generatedDir = outputDir / "generated";
|
|
std::filesystem::path rustmakerDir = generatedDir / "rustmaker";
|
|
std::filesystem::path cargoFile = rustmakerDir / "Cargo.toml";
|
|
if (!std::filesystem::exists(cargoFile))
|
|
{
|
|
std::ofstream cargoStream(cargoFile);
|
|
cargoStream << "[package]\n";
|
|
cargoStream << "name = \"" << crateName << "\"\n";
|
|
cargoStream << "version = \"0.1.0\"\n";
|
|
cargoStream << "edition = \"2024\"\n";
|
|
cargoStream << "\n";
|
|
cargoStream << "[lib]\n";
|
|
cargoStream << "name = \"rustmaker\"\n";
|
|
// Support both dynamic and static linking
|
|
cargoStream << "crate-type = [\"cdylib\", \"rlib\"]\n";
|
|
cargoStream << "description = \"Generated Rust bindings for LibreOffice UNO types\"\n\n";
|
|
cargoStream << "[dependencies]\n";
|
|
cargoStream << "# UNO runtime dependencies\n";
|
|
cargoStream << "rust_uno = { path = \"../../../../rust_uno\" }\n";
|
|
cargoStream.close();
|
|
}
|
|
}
|
|
|
|
void RustFile::createGeneratedModFile(const std::filesystem::path& outputDir)
|
|
{
|
|
// Create generated directory and its mod.rs file
|
|
std::filesystem::path generatedDir = outputDir / "generated";
|
|
std::filesystem::create_directories(generatedDir);
|
|
|
|
std::filesystem::path modFile = generatedDir / "mod.rs";
|
|
if (!std::filesystem::exists(modFile))
|
|
{
|
|
std::ofstream modStream(modFile);
|
|
modStream << "//! Generated opaque bindings for LibreOffice UNO types\n";
|
|
modStream << "//!\n";
|
|
modStream << "//! This module contains both Rust and C++ opaque bindings\n";
|
|
modStream << "//! auto-generated by rustmaker\n\n";
|
|
modStream << "// Include the generated rustmaker bindings directly\n";
|
|
modStream << "// The rustmaker directory contains a complete Rust project structure\n";
|
|
modStream << "// We include its lib.rs as a module here\n";
|
|
modStream << "#[path = \"rustmaker/src/lib.rs\"]\n";
|
|
modStream << "pub mod rustmaker;\n\n";
|
|
modStream << "// Re-export the UNO namespace for easier access\n";
|
|
modStream << "pub use rustmaker::com;\n\n";
|
|
modStream << "// Note: cpp_rustmaker directory contains C++ bridge files\n";
|
|
modStream << "// These are compiled separately and linked via build.rs\n";
|
|
modStream.close();
|
|
}
|
|
}
|
|
|
|
void RustFile::finalizeModFiles(const std::filesystem::path& outputDir)
|
|
{
|
|
// Find all directories in the rustmaker source tree and update their mod.rs files
|
|
std::filesystem::path rustmakerSrc = outputDir / "generated" / "rustmaker" / "src";
|
|
|
|
if (!std::filesystem::exists(rustmakerSrc))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Start processing from the rustmaker src directory
|
|
processDirectoryRecursively(rustmakerSrc);
|
|
}
|
|
|
|
RustFile& RustFile::beginBlock()
|
|
{
|
|
beginLine();
|
|
append("{");
|
|
endLine();
|
|
++m_indentLevel;
|
|
return *this;
|
|
}
|
|
|
|
RustFile& RustFile::endBlock()
|
|
{
|
|
--m_indentLevel;
|
|
beginLine();
|
|
append("}");
|
|
endLine();
|
|
return *this;
|
|
}
|
|
|
|
// Text output methods
|
|
RustFile& RustFile::beginLine()
|
|
{
|
|
for (int i = 0; i < m_indentLevel; i++)
|
|
{
|
|
m_fileStream << " ";
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
RustFile& RustFile::extraIndent()
|
|
{
|
|
m_fileStream << " ";
|
|
return *this;
|
|
}
|
|
|
|
RustFile& RustFile::append(std::string_view item)
|
|
{
|
|
m_fileStream << item;
|
|
return *this;
|
|
}
|
|
|
|
RustFile& RustFile::append(std::u16string_view item)
|
|
{
|
|
m_fileStream << u2b(item);
|
|
return *this;
|
|
}
|
|
|
|
RustFile& RustFile::endLine()
|
|
{
|
|
m_fileStream << '\n';
|
|
return *this;
|
|
}
|
|
|
|
void RustFile::createModFiles()
|
|
{
|
|
std::filesystem::path outputRoot = findOutputRoot();
|
|
|
|
// Create lib and cargo files only once at the proper root level
|
|
// outputRoot should be the rustmaker directory, so we pass its parent to the create functions
|
|
// which will then create the rustmaker directory and put files inside it
|
|
createGeneratedModFile(
|
|
outputRoot.parent_path().parent_path()); // Create generated/mod.rs at top level
|
|
createLibFile(
|
|
outputRoot.parent_path().parent_path()); // Create in the directory containing generated/
|
|
createCargoFile(outputRoot.parent_path().parent_path(), "rustmaker");
|
|
|
|
// Build path hierarchy from file location up to project root
|
|
std::filesystem::path workingPath = m_filePath.parent_path();
|
|
std::vector<std::filesystem::path> pathsToProcess;
|
|
|
|
// Collect all directory paths from current file up to root
|
|
while (workingPath != outputRoot && workingPath.has_parent_path())
|
|
{
|
|
pathsToProcess.push_back(workingPath);
|
|
workingPath = workingPath.parent_path();
|
|
}
|
|
|
|
// Process paths from root down to ensure proper mod.rs structure
|
|
std::reverse(pathsToProcess.begin(), pathsToProcess.end());
|
|
for (const auto& path : pathsToProcess)
|
|
{
|
|
ensureModFileExists(path);
|
|
}
|
|
}
|
|
|
|
// Complex path resolution - walks up directory tree to find project root
|
|
std::filesystem::path RustFile::findOutputRoot()
|
|
{
|
|
std::filesystem::path currentPath = m_filePath.parent_path();
|
|
|
|
// Walk up until we find a directory structure indicating project root
|
|
while (currentPath.has_parent_path() && currentPath != currentPath.parent_path())
|
|
{
|
|
if (currentPath.filename() == "src")
|
|
{
|
|
return currentPath.parent_path(); // Return rustmaker directory
|
|
}
|
|
|
|
// Look for rustmaker directory as the project root
|
|
if (currentPath.filename() == "rustmaker")
|
|
{
|
|
return currentPath;
|
|
}
|
|
|
|
// Look for existing src/ subdirectory as root indicator
|
|
std::filesystem::path srcDir = currentPath / "src";
|
|
if (std::filesystem::exists(srcDir))
|
|
{
|
|
return currentPath;
|
|
}
|
|
|
|
currentPath = currentPath.parent_path();
|
|
}
|
|
|
|
// Fallback: find parent of src directory (which should be rustmaker)
|
|
std::filesystem::path result = m_filePath.parent_path();
|
|
while (result.has_parent_path() && result.filename() != "src")
|
|
{
|
|
result = result.parent_path();
|
|
}
|
|
|
|
if (result.filename() == "src")
|
|
{
|
|
return result.parent_path(); // Return rustmaker directory
|
|
}
|
|
|
|
return result; // Default case
|
|
}
|
|
|
|
void RustFile::addFileToModDeclaration()
|
|
{
|
|
std::filesystem::path parentDir = m_filePath.parent_path();
|
|
std::filesystem::path modFile = parentDir / "mod.rs";
|
|
std::string fileName = m_filePath.stem().string<char>(); // Get filename without extension
|
|
|
|
if (std::filesystem::exists(modFile))
|
|
{
|
|
addModuleDeclaration(modFile, fileName);
|
|
}
|
|
}
|
|
|
|
void RustFile::ensureModFileExists(const std::filesystem::path& dirPath)
|
|
{
|
|
// Skip mod.rs creation for the src directory itself
|
|
if (dirPath.filename() == "src")
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::filesystem::path modFile = dirPath / "mod.rs";
|
|
if (!std::filesystem::exists(modFile))
|
|
{
|
|
// Create mod.rs file with proper structure
|
|
std::ofstream modStream(modFile);
|
|
modStream << "// Generated mod.rs file\n\n";
|
|
modStream << "#[allow(non_snake_case)]\n";
|
|
modStream.close();
|
|
}
|
|
|
|
// After ensuring the mod.rs exists, collect all subdirectories and modules
|
|
// to automatically add pub use ::* patterns
|
|
std::vector<std::string> childModules;
|
|
|
|
// Scan directory for subdirectories (modules) and .rs files
|
|
if (std::filesystem::exists(dirPath))
|
|
{
|
|
try
|
|
{
|
|
for (const auto& entry : std::filesystem::directory_iterator(dirPath))
|
|
{
|
|
if (entry.is_directory())
|
|
{
|
|
std::string dirName = entry.path().filename().string<char>();
|
|
childModules.push_back(dirName);
|
|
}
|
|
else if (entry.is_regular_file() && entry.path().extension() == ".rs")
|
|
{
|
|
std::string fileName = entry.path().stem().string<char>();
|
|
if (fileName != "mod") // Don't include mod.rs itself
|
|
{
|
|
childModules.push_back(fileName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (const std::filesystem::filesystem_error&)
|
|
{
|
|
// Handle permission errors gracefully
|
|
}
|
|
}
|
|
|
|
// Add module declarations and pub use statements for all child modules
|
|
for (const std::string& moduleName : childModules)
|
|
{
|
|
addModuleDeclaration(modFile, moduleName);
|
|
}
|
|
|
|
// Recursively ensure parent modules are properly declared
|
|
if (dirPath.has_parent_path())
|
|
{
|
|
std::filesystem::path parentDir = dirPath.parent_path();
|
|
std::filesystem::path outputRoot = findOutputRoot();
|
|
|
|
if (parentDir >= outputRoot)
|
|
{
|
|
std::string moduleName = dirPath.filename().string<char>();
|
|
|
|
if (parentDir.filename() == "src")
|
|
{
|
|
std::filesystem::path libFile = parentDir / "lib.rs";
|
|
if (std::filesystem::exists(libFile))
|
|
{
|
|
addModuleDeclaration(libFile, moduleName);
|
|
}
|
|
}
|
|
else if (parentDir == outputRoot)
|
|
{
|
|
std::filesystem::path libFile = parentDir / "src" / "lib.rs";
|
|
if (std::filesystem::exists(libFile))
|
|
{
|
|
addModuleDeclaration(libFile, moduleName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ensureModFileExists(parentDir);
|
|
std::filesystem::path parentModFile = parentDir / "mod.rs";
|
|
if (std::filesystem::exists(parentModFile))
|
|
{
|
|
addModuleDeclaration(parentModFile, moduleName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RustFile::addModuleDeclaration(const std::filesystem::path& modFile,
|
|
const std::string& moduleName)
|
|
{
|
|
// Read existing content to check for duplicates and organize sections
|
|
std::ifstream inFile(modFile);
|
|
std::string line;
|
|
std::vector<std::string> pubModLines;
|
|
std::vector<std::string> otherLines;
|
|
bool foundModDeclaration = false;
|
|
|
|
while (std::getline(inFile, line))
|
|
{
|
|
if (line.find("pub mod " + moduleName + ";") != std::string::npos)
|
|
{
|
|
foundModDeclaration = true;
|
|
}
|
|
|
|
if (line.find("pub mod ") == 0)
|
|
{
|
|
pubModLines.push_back(line);
|
|
}
|
|
else if (!(line.find("pub use ") == 0 && line.find("::*;") != std::string::npos))
|
|
{
|
|
// Skip old pub use re-export lines, include everything else
|
|
otherLines.push_back(line);
|
|
}
|
|
}
|
|
inFile.close();
|
|
|
|
// If module declaration is already declared, return
|
|
if (foundModDeclaration)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Add new declarations if not found
|
|
if (!foundModDeclaration)
|
|
{
|
|
pubModLines.push_back("pub mod " + moduleName + ";");
|
|
}
|
|
// Re-export generation removed - causes unused import warnings
|
|
|
|
// Rewrite the file with organized structure
|
|
std::ofstream outFile(modFile, std::ios::trunc);
|
|
|
|
// Write other lines first (comments, etc.)
|
|
for (const auto& otherLine : otherLines)
|
|
{
|
|
// Skip re-export comment lines
|
|
if (otherLine.find("// Re-export all items from child modules") == std::string::npos)
|
|
{
|
|
outFile << otherLine << "\n";
|
|
}
|
|
}
|
|
|
|
// Write all pub mod declarations
|
|
for (const auto& modLine : pubModLines)
|
|
{
|
|
outFile << modLine << "\n";
|
|
}
|
|
|
|
// Re-export section removed - causes unused import warnings
|
|
|
|
outFile.close();
|
|
}
|
|
|
|
// Converts UNO type name to file path (dots become path separators)
|
|
std::filesystem::path RustFile::createFilePath(std::string_view dir, std::string_view type)
|
|
{
|
|
std::string subdir(type);
|
|
for (char& c : subdir)
|
|
if (c == '.')
|
|
c = '/';
|
|
|
|
std::filesystem::path path(dir);
|
|
path /= "rustmaker"; // Add rustmaker subdirectory for generated types
|
|
path /= "src";
|
|
path /= subdir + ".rs";
|
|
return path;
|
|
}
|
|
|
|
// CppFile implementation
|
|
CppFile::CppFile(std::string_view directory, std::string_view typeName)
|
|
: m_filePath(createCppFilePath(directory, typeName))
|
|
, m_indentLevel(0)
|
|
{
|
|
}
|
|
|
|
CppFile::CppFile(std::string_view directory, std::string_view typeName, std::string_view extension)
|
|
: m_filePath(createCppFilePath(directory, typeName, extension))
|
|
, m_indentLevel(0)
|
|
{
|
|
}
|
|
|
|
std::string CppFile::getPathString() const
|
|
{
|
|
#if defined __cpp_lib_format_path
|
|
return m_filePath.display_string();
|
|
#else
|
|
return m_filePath.string<char>();
|
|
#endif
|
|
}
|
|
std::filesystem::path CppFile::getPath() const { return m_filePath; }
|
|
std::string CppFile::getExtension() const { return m_filePath.extension().string<char>(); }
|
|
|
|
void CppFile::openFile()
|
|
{
|
|
std::filesystem::create_directories(m_filePath.parent_path());
|
|
m_fileStream.open(m_filePath, std::fstream::out | std::fstream::trunc);
|
|
m_indentLevel = 0;
|
|
}
|
|
|
|
void CppFile::openFileAppend()
|
|
{
|
|
std::filesystem::create_directories(m_filePath.parent_path());
|
|
m_fileStream.open(m_filePath, std::fstream::out | std::fstream::app);
|
|
m_indentLevel = 0;
|
|
}
|
|
|
|
void CppFile::closeFile() { m_fileStream.close(); }
|
|
|
|
CppFile& CppFile::beginBlock()
|
|
{
|
|
beginLine();
|
|
append("{");
|
|
endLine();
|
|
++m_indentLevel;
|
|
return *this;
|
|
}
|
|
|
|
CppFile& CppFile::endBlock()
|
|
{
|
|
--m_indentLevel;
|
|
beginLine();
|
|
append("}");
|
|
endLine();
|
|
return *this;
|
|
}
|
|
|
|
CppFile& CppFile::beginLine()
|
|
{
|
|
m_fileStream << std::string(4 * m_indentLevel, ' ');
|
|
return *this;
|
|
}
|
|
|
|
CppFile& CppFile::extraIndent()
|
|
{
|
|
m_fileStream << " ";
|
|
return *this;
|
|
}
|
|
|
|
CppFile& CppFile::append(std::string_view item)
|
|
{
|
|
m_fileStream << item;
|
|
return *this;
|
|
}
|
|
|
|
CppFile& CppFile::append(std::u16string_view item)
|
|
{
|
|
m_fileStream << u2b(item);
|
|
return *this;
|
|
}
|
|
|
|
CppFile& CppFile::endLine()
|
|
{
|
|
m_fileStream << std::endl;
|
|
return *this;
|
|
}
|
|
|
|
CppFile& CppFile::writeIncludes(const std::vector<std::string>& includes)
|
|
{
|
|
for (const auto& include : includes)
|
|
{
|
|
beginLine().append("#include ").append(include).endLine();
|
|
}
|
|
endLine();
|
|
return *this;
|
|
}
|
|
|
|
CppFile& CppFile::writeNamespaceBegin(const std::vector<std::string>& namespaces)
|
|
{
|
|
for (const auto& ns : namespaces)
|
|
{
|
|
beginLine().append("namespace ").append(ns).append(" {").endLine();
|
|
}
|
|
endLine();
|
|
return *this;
|
|
}
|
|
|
|
CppFile& CppFile::writeNamespaceEnd(const std::vector<std::string>& namespaces)
|
|
{
|
|
endLine();
|
|
for (auto it = namespaces.rbegin(); it != namespaces.rend(); ++it)
|
|
{
|
|
beginLine().append("} // namespace ").append(*it).endLine();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
std::filesystem::path CppFile::createCppFilePath(std::string_view dir, std::string_view type,
|
|
std::string_view extension)
|
|
{
|
|
std::filesystem::path outputDir(dir);
|
|
|
|
// For the special case of "rust_uno_bindings", create it directly in the output directory
|
|
if (type == "rust_uno_bindings")
|
|
{
|
|
return outputDir / (std::string(type) + std::string(extension));
|
|
}
|
|
|
|
std::filesystem::path basePath = outputDir;
|
|
|
|
std::string typeName(type);
|
|
|
|
// Extract interface name (part after last dot)
|
|
size_t lastDot = typeName.find_last_of('.');
|
|
std::string interfaceName
|
|
= (lastDot != std::string::npos) ? typeName.substr(lastDot + 1) : typeName;
|
|
|
|
// Create namespace directory path from the full type name
|
|
if (lastDot != std::string::npos)
|
|
{
|
|
// Convert namespace dots to path separators: com.sun.star.frame -> com/sun/star/frame/
|
|
std::string namespacePath = typeName.substr(0, lastDot);
|
|
|
|
// Replace dots with path separators
|
|
std::replace(namespacePath.begin(), namespacePath.end(), '.', '/');
|
|
|
|
// Build full path: cpp_rustmaker/com/sun/star/frame/XComponentLoader.hxx
|
|
return basePath / namespacePath / (interfaceName + std::string(extension));
|
|
}
|
|
else
|
|
{
|
|
// No namespace, put directly in cpp_rustmaker directory
|
|
return basePath / (interfaceName + std::string(extension));
|
|
}
|
|
}
|
|
|
|
void RustFile::processDirectoryRecursively(const std::filesystem::path& currentDir)
|
|
{
|
|
if (!std::filesystem::exists(currentDir) || !std::filesystem::is_directory(currentDir))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Skip the root src directory
|
|
if (currentDir.filename() == "src" && currentDir.parent_path().filename() == "rustmaker")
|
|
{
|
|
// Process subdirectories but don't create mod.rs for src itself
|
|
for (const auto& entry : std::filesystem::directory_iterator(currentDir))
|
|
{
|
|
if (entry.is_directory())
|
|
{
|
|
processDirectoryRecursively(entry.path());
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
std::vector<std::string> childModules;
|
|
|
|
try
|
|
{
|
|
// Collect all subdirectories and .rs files
|
|
for (const auto& entry : std::filesystem::directory_iterator(currentDir))
|
|
{
|
|
if (entry.is_directory())
|
|
{
|
|
std::string dirName = entry.path().filename().string<char>();
|
|
childModules.push_back(dirName);
|
|
// Recursively process subdirectory
|
|
processDirectoryRecursively(entry.path());
|
|
}
|
|
else if (entry.is_regular_file() && entry.path().extension() == ".rs")
|
|
{
|
|
std::string fileName = entry.path().stem().string<char>();
|
|
if (fileName != "mod" && fileName != "lib") // Don't include mod.rs or lib.rs
|
|
{
|
|
childModules.push_back(fileName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (const std::filesystem::filesystem_error&)
|
|
{
|
|
// Handle permission errors gracefully
|
|
return;
|
|
}
|
|
|
|
// Create/update mod.rs file if there are child modules
|
|
if (!childModules.empty())
|
|
{
|
|
std::filesystem::path modFile = currentDir / "mod.rs";
|
|
|
|
// Create the mod.rs file with all declarations
|
|
std::ofstream modStream(modFile, std::ios::trunc);
|
|
modStream << "// Generated mod.rs file\n\n";
|
|
modStream << "#[allow(non_snake_case)]\n";
|
|
|
|
for (const std::string& moduleName : childModules)
|
|
{
|
|
modStream << "pub mod " << moduleName << ";\n";
|
|
}
|
|
|
|
// Re-export section removed per request
|
|
|
|
modStream.close();
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|