Skip to content

Commit 6a1c2a6

Browse files
authored
Port build_directory_md.py to Rust (#521)
1 parent 6cfb8ea commit 6a1c2a6

File tree

5 files changed

+150
-52
lines changed

5 files changed

+150
-52
lines changed

.github/workflows/directory_workflow.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
1616
- name: Update DIRECTORY.md
1717
run: |
18-
python .github/workflows/scripts/build_directory_md.py
18+
cargo run --manifest-path=.github/workflows/scripts/build_directory/Cargo.toml
1919
- name: Commit DIRECTORY.md
2020
run: |
2121
git add DIRECTORY.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "build_directory"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
use std::{
2+
error::Error,
3+
fs,
4+
path::{Path, PathBuf},
5+
};
6+
7+
static URL_BASE: &str = "https://github.com/TheAlgorithms/Rust/blob/master";
8+
9+
fn good_filepaths(top_dir: &Path) -> Result<Vec<String>, Box<dyn Error>> {
10+
let mut good_fs = Vec::new();
11+
if top_dir.is_dir() {
12+
for entry in fs::read_dir(top_dir)? {
13+
let entry = entry?;
14+
let path = entry.path();
15+
if entry.file_name().to_str().unwrap().starts_with('.')
16+
|| entry.file_name().to_str().unwrap().starts_with('_')
17+
{
18+
continue;
19+
}
20+
if path.is_dir() {
21+
let mut other = good_filepaths(&path)?;
22+
good_fs.append(&mut other);
23+
} else if entry.file_name().to_str().unwrap().ends_with(".rs")
24+
&& entry.file_name().to_str().unwrap() != "mod.rs"
25+
{
26+
good_fs.push(
27+
path.into_os_string()
28+
.into_string()
29+
.unwrap()
30+
.split_at(2)
31+
.1
32+
.to_string(),
33+
);
34+
}
35+
}
36+
}
37+
good_fs.sort();
38+
Ok(good_fs)
39+
}
40+
41+
fn md_prefix(indent_count: usize) -> String {
42+
if indent_count > 0 {
43+
format!("{}*", " ".repeat(indent_count))
44+
} else {
45+
"\n##".to_string()
46+
}
47+
}
48+
49+
fn print_path(old_path: String, new_path: String) -> (String, String) {
50+
let old_parts = old_path
51+
.split(std::path::MAIN_SEPARATOR)
52+
.collect::<Vec<&str>>();
53+
let mut result = String::new();
54+
for (count, new_part) in new_path.split(std::path::MAIN_SEPARATOR).enumerate() {
55+
if count + 1 > old_parts.len() || old_parts[count] != new_part {
56+
println!("{} {}", md_prefix(count), to_title(new_part));
57+
result.push_str(format!("{} {}\n", md_prefix(count), to_title(new_part)).as_str());
58+
}
59+
}
60+
(new_path, result)
61+
}
62+
63+
pub fn build_directory_md(top_dir: &Path) -> Result<String, Box<dyn Error>> {
64+
let mut old_path = String::from("");
65+
let mut result = String::new();
66+
for filepath in good_filepaths(top_dir)? {
67+
let mut filepath = PathBuf::from(filepath);
68+
let filename = filepath.file_name().unwrap().to_owned();
69+
filepath.pop();
70+
let filepath = filepath.into_os_string().into_string().unwrap();
71+
if filepath != old_path {
72+
let path_res = print_path(old_path, filepath);
73+
old_path = path_res.0;
74+
result.push_str(path_res.1.as_str());
75+
}
76+
let url = format!("{}/{}", old_path, filename.to_string_lossy());
77+
let url = get_addr(&url);
78+
let indent = old_path.matches(std::path::MAIN_SEPARATOR).count() + 1;
79+
let filename = to_title(filename.to_str().unwrap().split('.').collect::<Vec<&str>>()[0]);
80+
println!("{} [{}]({})", md_prefix(indent), filename, url);
81+
result.push_str(format!("{} [{}]({})\n", md_prefix(indent), filename, url).as_str());
82+
}
83+
Ok(result)
84+
}
85+
86+
fn to_title(name: &str) -> String {
87+
let mut change = true;
88+
name.chars()
89+
.map(move |letter| {
90+
if change && !letter.is_numeric() {
91+
change = false;
92+
letter.to_uppercase().next().unwrap()
93+
} else if letter == '_' {
94+
change = true;
95+
' '
96+
} else {
97+
if letter.is_numeric() || !letter.is_alphanumeric() {
98+
change = true;
99+
}
100+
letter
101+
}
102+
})
103+
.collect::<String>()
104+
}
105+
106+
fn get_addr(addr: &str) -> String {
107+
if cfg!(windows) {
108+
format!("{}/{}", URL_BASE, switch_backslash(addr))
109+
} else {
110+
format!("{}/{}", URL_BASE, addr)
111+
}
112+
}
113+
114+
// Function that changes '\' to '/' (for Windows builds only)
115+
fn switch_backslash(addr: &str) -> String {
116+
addr.chars()
117+
.map(|mut symbol| {
118+
if symbol == '\\' {
119+
symbol = '/';
120+
}
121+
symbol
122+
})
123+
.collect::<String>()
124+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use std::{fs::File, io::Write, path::Path};
2+
3+
use build_directory::build_directory_md;
4+
fn main() -> Result<(), std::io::Error> {
5+
let mut file = File::create("DIRECTORY.md").unwrap(); // unwrap for panic
6+
7+
match build_directory_md(Path::new(".")) {
8+
Ok(buf) => {
9+
file.write_all("# List of all files\n".as_bytes())?;
10+
file.write_all(buf.as_bytes())?;
11+
}
12+
Err(err) => {
13+
panic!("Error while creating string: {err}");
14+
}
15+
}
16+
Ok(())
17+
}

.github/workflows/scripts/build_directory_md.py

-51
This file was deleted.

0 commit comments

Comments
 (0)