Compare commits

..

5 Commits

Author SHA1 Message Date
Falko Victor Habel 048c275b55 updated tests
Gitea Actions For prodir / Explore-Gitea-Actions (push) Failing after 0s Details
2025-04-22 17:07:52 +02:00
Falko Victor Habel eec232ae53 updated the verbose handling for new version 2025-04-22 17:07:46 +02:00
Falko Victor Habel 2a034e9c0e updated folder printing with better loooking ui and removed debu prints 2025-04-22 17:07:30 +02:00
Falko Victor Habel e230128be0 added missing requirements 2025-04-22 17:06:24 +02:00
Falko Victor Habel 64596eaf46 fixed display for tree_structurer 2025-04-22 15:51:32 +02:00
4 changed files with 84 additions and 151 deletions

View File

@ -70,6 +70,8 @@
"xutility": "cpp",
"fstream": "cpp",
"iostream": "cpp",
"codecvt": "cpp"
"codecvt": "cpp",
"map": "cpp",
"xtree": "cpp"
}
}

View File

@ -69,10 +69,9 @@ def main():
create_tree_structurer()
if args.command == 'display':
if args.verbose:
print(f"Analyzing directory: {args.path}")
try:
structure = get_structure(args.path)
print(f"Analyzing directory: {args.path}")
for line in structure:
print(line)
except FileNotFoundError:

View File

@ -123,7 +123,6 @@ std::vector<fs::path> TreeStructurer::get_filtered_paths(const fs::path& start)
std::vector<std::string> TreeStructurer::get_directory_structure(const std::string& startpath) {
std::vector<std::string> result;
// Normalize the input path by removing ./ or .\ prefix if present
std::string normalized_path = startpath;
if (normalized_path.size() >= 2 &&
(normalized_path.substr(0, 2) == ".\\" || normalized_path.substr(0, 2) == "./")) {
@ -140,145 +139,51 @@ std::vector<std::string> TreeStructurer::get_directory_structure(const std::stri
throw std::runtime_error("Path is not a directory: " + start.string());
}
// Start with the root node
std::string root_name = start.filename().string();
result.push_back(root_name + "/");
std::vector<fs::path> paths = get_filtered_paths(start);
std::vector<bool> is_last_per_level;
// First, collect all paths and organize them by their parent directories
std::map<std::string, std::vector<fs::path>> dir_contents;
std::vector<std::string> dir_paths; // To maintain order of directories
// Add root directory
dir_contents["/"] = {};
dir_paths.push_back("/");
// Collect files and directories
for (const auto& entry : fs::recursive_directory_iterator(start)) {
const auto& path = entry.path();
std::string rel_path = get_relative_path(path, start);
// Replace backslashes with forward slashes
std::replace(rel_path.begin(), rel_path.end(), '\\', '/');
// Skip if it should be ignored
bool should_skip = false;
for (const auto& component : path) {
if (should_ignore_dir(component.string())) {
should_skip = true;
break;
}
}
if (should_skip) continue;
if (entry.is_directory()) {
if (should_ignore_dir(path.filename().string())) {
continue;
// Skip the first path as it's the root
for (size_t i = 1; i < paths.size(); ++i) {
fs::path relative = fs::relative(paths[i], start);
std::vector<std::string> components;
for (const auto& comp : relative) {
components.push_back(comp.string());
}
// Add directory to its parent
std::string parent_path = "/";
size_t last_slash = rel_path.find_last_of('/');
if (last_slash != std::string::npos) {
parent_path = rel_path.substr(0, last_slash);
if (parent_path.empty()) {
parent_path = "/";
}
// Calculate the current level
size_t level = components.size() - 1;
// Adjust is_last_per_level vector size
while (is_last_per_level.size() <= level) {
is_last_per_level.push_back(false);
}
// Create parent directory entry if it doesn't exist
if (dir_contents.find(parent_path) == dir_contents.end()) {
dir_contents[parent_path] = {};
dir_paths.push_back(parent_path);
}
// Determine if this is the last item at its level
bool is_last = (i == paths.size() - 1) ||
(i + 1 < paths.size() &&
fs::relative(paths[i + 1], start).begin()->string() != components[0]);
// Create directory entry
dir_contents[parent_path].push_back(path);
// Create entry for this directory's contents
dir_contents[rel_path] = {};
dir_paths.push_back(rel_path);
} else {
if (should_ignore_file(path.filename().string())) {
continue;
}
// Add file to its parent
std::string parent_path = "/";
size_t last_slash = rel_path.find_last_of('/');
if (last_slash != std::string::npos) {
parent_path = rel_path.substr(0, last_slash);
if (parent_path.empty()) {
parent_path = "/";
}
}
// Create parent directory entry if it doesn't exist
if (dir_contents.find(parent_path) == dir_contents.end()) {
dir_contents[parent_path] = {};
dir_paths.push_back(parent_path);
}
dir_contents[parent_path].push_back(path);
}
}
// Now create the tree structure
std::function<void(const std::string&, const std::string&, std::vector<bool>&)>
build_tree = [&](const std::string& dir_path, const std::string& prefix, std::vector<bool>& is_last_stack) {
// Sort paths - directories first, then files
std::vector<fs::path>& paths = dir_contents[dir_path];
std::sort(paths.begin(), paths.end(), [](const fs::path& a, const fs::path& b) {
bool a_is_dir = fs::is_directory(a);
bool b_is_dir = fs::is_directory(b);
if (a_is_dir != b_is_dir) {
return a_is_dir > b_is_dir; // Directories before files
}
return a.filename() < b.filename(); // Alphabetical order
});
// Add entries for this directory
for (size_t i = 0; i < paths.size(); ++i) {
const auto& path = paths[i];
bool is_last = (i == paths.size() - 1);
is_last_per_level[level] = is_last;
// Build the line prefix
std::string line_prefix = prefix;
if (!prefix.empty()) {
line_prefix += is_last ? "└── " : "├── ";
std::string line;
for (size_t j = 0; j < level; ++j) {
if (j == level - 1) {
line += is_last ? "└── " : "├── ";
} else {
line += is_last_per_level[j] ? " " : "";
}
}
// Add the file/directory name
std::string name = path.filename().string();
std::string line = line_prefix + name;
if (fs::is_directory(path)) {
line += components.back();
if (fs::is_directory(paths[i])) {
line += "/";
}
result.push_back(line);
// If it's a directory, process its contents with updated prefix
if (fs::is_directory(path)) {
std::string rel_path = get_relative_path(path, start);
std::replace(rel_path.begin(), rel_path.end(), '\\', '/');
std::string next_prefix = prefix;
if (!prefix.empty()) {
next_prefix += is_last ? " " : "";
}
std::vector<bool> next_is_last_stack = is_last_stack;
next_is_last_stack.push_back(is_last);
build_tree(rel_path, next_prefix, next_is_last_stack);
}
}
};
// Start building the tree from the root
std::vector<bool> is_last_stack;
build_tree("/", "", is_last_stack);
} catch (const fs::filesystem_error& e) {
throw std::runtime_error("Failed to access directory: " + std::string(e.what()));
}
@ -527,8 +432,6 @@ std::vector<std::string> TreeStructurer::read_structure_file(const std::string&
line.pop_back();
}
std::cout << "Processing line: " << line << std::endl;
size_t hash_pos = line.find('#');
size_t single_line_comment_pos = line.find("//");
size_t multi_line_comment_start_pos = line.find("/*");
@ -536,15 +439,12 @@ std::vector<std::string> TreeStructurer::read_structure_file(const std::string&
if (hash_pos != std::string::npos) {
// Trim the line at the hash comment
line = line.substr(0, hash_pos);
std::cout << "Trimmed line at hash comment position: " << hash_pos << std::endl;
} else if (single_line_comment_pos != std::string::npos) {
// Trim the line at the single-line comment
line = line.substr(0, single_line_comment_pos);
std::cout << "Trimmed line at single-line comment position: " << single_line_comment_pos << std::endl;
} else if (multi_line_comment_start_pos != std::string::npos) {
// Trim the line at the multi-line comment start
line = line.substr(0, multi_line_comment_start_pos);
std::cout << "Trimmed line at multi-line comment start position: " << multi_line_comment_start_pos << std::endl;
}
// Remove leading and trailing whitespace
@ -553,9 +453,7 @@ std::vector<std::string> TreeStructurer::read_structure_file(const std::string&
if (!line.empty()) {
lines.push_back(line);
std::cout << "Added non-empty line: " << line << std::endl;
} else {
std::cout << "Skipped empty or commented-out line." << std::endl;
}
}

View File

@ -67,16 +67,50 @@ def test_display_verbose(tmp_path):
# Only check if we got any output, ignoring encoding errors
assert stdout != "" or stderr != ""
# ... rest of code here ...
# ... rest of code here ...
def test_create_directory_from_file(tmp_path):
structure_file = tmp_path / 'structure.txt'
structure_content = "dir1/\n file1.txt"
structure_file.write_text(structure_content)
# Define the desired directory structure in a string with proper indentation
structure_content = """data/
sample_data.csv
docs/
README.md
requirements.txt
setup.py
src/
__init__.py
main.py
utils.py
tests/
__init__.py
test_main.py
test_utils.py"""
output_dir = tmp_path / 'output'
output_dir.mkdir()
stdout, stderr = run_prodir(['create', str(structure_file), '-o', str(output_dir)])
assert os.path.exists(output_dir / 'dir1' / 'file1.txt')
stdout, stderr = run_prodir(['create', "example.md" '-o'])
# Print the stdout and stderr for debugging
print("stdout:", stdout)
print("stderr:", stderr)
assert os.path.exists('my_project/data/sample_data.csv')
assert os.path.exists('my_project/docs/README.md')
assert os.path.exists('my_project/requirements.txt')
assert os.path.exists('my_project/setup.py')
assert os.path.exists('my_project/src/__init__.py')
assert os.path.exists('my_project/src/main.py')
assert os.path.exists('my_project/src/utils.py')
assert os.path.exists('my_project/tests/__init__.py')
assert os.path.exists('my_project/tests/test_main.py')
assert os.path.exists('my_project/tests/test_utils.py')
def test_create_verbose(tmp_path):
structure_file = tmp_path / 'structure.txt'
@ -86,9 +120,9 @@ def test_create_verbose(tmp_path):
output_dir = tmp_path / 'output'
output_dir.mkdir()
stdout, stderr = run_prodir(['create', str(structure_file), '-o', str(output_dir), '-v'])
stdout, stderr = run_prodir(['create', "example.md" '-v'])
# Only check if we got any output and the directory was created
assert os.path.exists(output_dir / 'dir1' / 'file1.txt')
assert os.path.exists( 'my_project/requirements.txt')
def test_display_invalid_path():
# Use an absolute path with some random UUID to ensure it doesn't exist