root: init rust workspace (#20983)

This commit is contained in:
Marc 'risson' Schmitt
2026-03-19 14:12:00 +00:00
committed by GitHub
parent 25d3d5751e
commit 894f134893
24 changed files with 859 additions and 769 deletions

View File

@@ -1,474 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
[[package]]
name = "anstyle-parse"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
dependencies = [
"anstyle",
"windows-sys 0.52.0",
]
[[package]]
name = "anyhow"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "backtrace"
version = "0.3.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "cc"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
[[package]]
name = "colorchoice"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
[[package]]
name = "colored"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
]
[[package]]
name = "docsmg"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"colored",
"dotenv",
"regex",
"tokio",
]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "gimli"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "miniz_oxide"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
dependencies = [
"adler",
]
[[package]]
name = "object"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
dependencies = [
"memchr",
]
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tokio"
version = "1.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
dependencies = [
"backtrace",
"pin-project-lite",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@@ -1,14 +1,20 @@
[package]
name = "docsmg"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
version = "0.0.0"
authors.workspace = true
edition.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
license-file.workspace = true
publish = false
[dependencies]
anyhow = "1.0.86"
clap = { version = "4.5.9", features = ["derive", "env"] }
colored = "2.1.0"
dotenv = "0.15.0"
regex = "1.10.6"
tokio = "1.38.0"
eyre.workspace = true
clap.workspace = true
colored.workspace = true
dotenvy.workspace = true
regex.workspace = true
[lints]
workspace = true

View File

@@ -1,5 +1,5 @@
cargo install --git https://github.com/goauthentik/authentik
cargo install --git https://github.com/goauthentik/authentik docsmg
sudo wget https://raw.githubusercontent.com/goauthentik/authentik/main/website/scripts/docsmg/m.bash -O /bin/map
sudo wget https://raw.githubusercontent.com/goauthentik/authentik/main/website/scripts/docsmg/mcomplete.bash -O /bin/mapcomplete
sudo chmod 755 /bin/map
echo "source mapcomplete" >> ~/.zshrc
echo "source mapcomplete" >>~/.zshrc

View File

@@ -1,31 +1,24 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use crate::{migratefile::read_migrate_file_left_side, recurse_directory};
pub fn generate(migratefile: Option<PathBuf>, migrate_path: PathBuf) {
pub(crate) fn generate(migratefile: Option<&Path>, migrate_path: &Path) {
// if there is a migrate file, read it and get the paths from the left side
let paths: Vec<PathBuf> = match migratefile {
Some(i) => {
let contents = read_migrate_file_left_side(i);
if let Ok(contents) = contents {
contents
} else {
vec![]
}
}
Some(i) => read_migrate_file_left_side(i).unwrap_or_default(),
None => {
vec![]
}
};
// get rid of paths already in the specified migrate file
let paths: Vec<PathBuf> = recurse_directory(migrate_path.clone())
let paths: Vec<PathBuf> = recurse_directory(migrate_path)
.iter()
.filter_map(|x| x.strip_prefix(migrate_path.clone()).ok())
.filter_map(|x| x.strip_prefix(migrate_path).ok())
.filter(|x| !paths.contains(&x.to_path_buf()))
.map(|x| x.to_path_buf())
.collect();
for path in paths {
println!("{} ->", path.display());
eprintln!("{} ->", path.display());
}
}

View File

@@ -1,24 +1,30 @@
use std::{ffi::OsStr, fs::{read_to_string, write}, path::PathBuf};
use std::{
fs::{read_to_string, write},
path::Path,
};
use crate::recurse_directory;
pub fn add_extra_dot_dot_to_expression_mdx(migrate_path: PathBuf) {
pub(crate) fn add_extra_dot_dot_to_expression_mdx(migrate_path: &Path) {
let binding = recurse_directory(migrate_path);
let files = binding.iter().filter(|x| if let Some(i) = x.file_name() {
if Some("expression.mdx") == i.to_str() || Some("expressions.md") == i.to_str() {
true
let files = binding.iter().filter(|x| {
if let Some(i) = x.file_name() {
Some("expression.mdx") == i.to_str() || Some("expressions.md") == i.to_str()
} else {
false
}
} else {
false
});
for file in files {
let content = match read_to_string(file) {
Ok(i) => i,
_ => continue,
let Ok(content) = read_to_string(file) else {
continue;
};
let _ = write(file, content.replace("../expressions", "../../expressions"));
}
}
#[cfg(test)]
mod tests {
#[test]
fn noop() {}
}

View File

@@ -1,20 +1,22 @@
use std::{fs::read_to_string, path::PathBuf};
use std::{
fs::read_to_string,
path::{Path, PathBuf},
};
use regex::{Captures, Regex};
use crate::recurse_directory;
pub fn shorten_all_external_links(migrate_path: PathBuf) {
let files = recurse_directory(migrate_path.clone());
#[expect(unused)]
pub(crate) fn shorten_all_external_links(migrate_path: &Path) {
let files = recurse_directory(migrate_path);
let re = Regex::new(r"\[(?<name>.*)\]\((?<link>.*)\)").unwrap();
for file in files {
let file = migrate_path.join(file);
let absolute_file = file.clone().canonicalize().unwrap();
let contents = if let Ok(x) = read_to_string(file) {
x
} else {
let Ok(contents) = read_to_string(file) else {
continue;
};
let re = Regex::new(r"\[(?<name>.*)\]\((?<link>.*)\)").unwrap();
let captures: Vec<Captures> = re.captures_iter(&contents).collect();
for capture in captures {
let link = &capture["link"];
@@ -31,4 +33,4 @@ pub fn shorten_all_external_links(migrate_path: PathBuf) {
}
}
fn shorten_link_relative_to(link_to_shorten: PathBuf, relative_to: PathBuf) {}
fn shorten_link_relative_to(_link_to_shorten: PathBuf, _relative_to: PathBuf) {}

View File

@@ -1,13 +1,19 @@
use std::{fs, path::PathBuf};
#![expect(clippy::allow_attributes_without_reason)]
#![expect(clippy::unwrap_used)]
use std::{
fs,
path::{Path, PathBuf},
};
use clap::{Parser, Subcommand};
mod generate;
mod hackyfixes;
mod links;
mod migrate;
mod migratefile;
mod r#move;
mod hackyfixes;
#[derive(Parser)]
struct Cli {
@@ -45,41 +51,38 @@ enum Commands {
}
fn main() {
let _ = dotenv::from_filename("./docsmg.env");
let _ = dotenvy::from_filename("./docsmg.env");
let cli = Cli::parse();
match cli.command {
Commands::Move { old_path, new_path } => r#move::r#move(old_path, new_path),
Commands::Move { old_path, new_path } => r#move::r#move(&old_path, &new_path),
Commands::Migrate { migratefile, quiet } => {
migrate::migrate(quiet, migratefile, cli.migrate_path)
migrate::migrate(quiet, &migratefile, &cli.migrate_path);
}
Commands::Unmigrate { migratefile, quiet } => {
migrate::unmigrate(quiet, migratefile, cli.migrate_path)
migrate::unmigrate(quiet, &migratefile, &cli.migrate_path);
}
Commands::Generate { migratefile } => {
generate::generate(migratefile.as_deref(), &cli.migrate_path);
}
Commands::Generate { migratefile } => generate::generate(migratefile, cli.migrate_path),
}
}
fn recurse_directory(path: PathBuf) -> Vec<PathBuf> {
fn recurse_directory(path: &Path) -> Vec<PathBuf> {
let paths = fs::read_dir(path).expect("path to exist");
let mut final_paths = vec![];
for path in paths {
match path {
Ok(path) => {
if !path.path().is_file() && !path.path().is_dir() {
continue;
} // dont go any further if not a file or directory
let is_dir = path.path().is_dir();
let path = path.path();
for path in paths.flatten() {
if !path.path().is_file() && !path.path().is_dir() {
continue;
} // dont go any further if not a file or directory
let is_dir = path.path().is_dir();
let path = path.path();
if is_dir {
let mut paths = recurse_directory(path);
final_paths.append(&mut paths);
} else {
final_paths.push(path);
}
}
_ => {}
if is_dir {
let mut paths = recurse_directory(&path);
final_paths.append(&mut paths);
} else {
final_paths.push(path);
}
}
final_paths

View File

@@ -1,36 +1,41 @@
use std::{
collections::{HashMap, HashSet, VecDeque}, env::consts::OS, ffi::OsStr, fs::{create_dir_all, read_to_string, remove_file, write, File}, path::{Component, PathBuf}, process::Command
collections::{HashMap, VecDeque},
ffi::OsStr,
fmt::Write as _,
fs::{self, File},
iter::repeat_with,
path::{Component, Path, PathBuf},
process::Command,
};
use colored::Colorize;
use colored::Colorize as _;
use eyre::Result;
use regex::{Captures, Regex};
use crate::{hackyfixes::add_extra_dot_dot_to_expression_mdx, migratefile::read_migrate_file, recurse_directory, Cli};
use crate::{
hackyfixes::add_extra_dot_dot_to_expression_mdx, migratefile::read_migrate_file,
recurse_directory,
};
pub fn migrate(quiet: bool, migratefile: PathBuf, migrate_path: PathBuf) {
pub(crate) fn migrate(quiet: bool, migratefile: &Path, migrate_path: &Path) {
if !quiet {
println!("Reading migrate file");
eprintln!("Reading migrate file");
}
let files = read_migrate_file(migratefile);
let files = match files {
Ok(i) => {
if !quiet {
println!("{}", "Success".green());
}
i
}
Err(_) => {
println!("{}: Could not read migrate file", "Error".red());
return;
let files = if let Ok(files) = read_migrate_file(migratefile) {
if !quiet {
eprintln!("{}", "Success".green());
}
files
} else {
eprintln!("{}: Could not read migrate file", "Error".red());
return;
};
replace_links(migrate_path.clone(), files.clone());
let successful_moves = move_files(quiet, migrate_path.clone(), files);
add_redirects(successful_moves.clone(), migrate_path.clone());
//shorten_all_external_links(migrate_path);
add_extra_dot_dot_to_expression_mdx(migrate_path.clone());
replace_links(migrate_path, &files);
let successful_moves = move_files(quiet, migrate_path, &files);
add_redirects(&successful_moves, migrate_path);
// shorten_all_external_links(migrate_path);
add_extra_dot_dot_to_expression_mdx(migrate_path);
let _ = Command::new("sh")
.arg("-c")
.arg("find . -empty -type d -delete")
@@ -38,76 +43,71 @@ pub fn migrate(quiet: bool, migratefile: PathBuf, migrate_path: PathBuf) {
.output();
}
pub fn unmigrate(quiet: bool, migratefile: PathBuf, migrate_path: PathBuf) {
pub(crate) fn unmigrate(quiet: bool, migratefile: &Path, migrate_path: &Path) {
if !quiet {
println!("Reading migrate file");
eprintln!("Reading migrate file");
}
let files = read_migrate_file(migratefile);
let files = match files {
Ok(i) => {
if !quiet {
println!("{}", "Success".green());
}
i
}
Err(_) => {
println!("{}: Could not read migrate file", "Error".red());
return;
let files = if let Ok(files) = read_migrate_file(migratefile) {
if !quiet {
eprintln!("{}", "Success".green());
}
files
} else {
eprintln!("{}: Could not read migrate file", "Error".red());
return;
};
let files: Vec<(PathBuf, PathBuf)> = files.iter().map(|x| (x.1.clone(), x.0.clone())).collect(); //switch files to reverse a migration
replace_links(migrate_path.clone(), files.clone());
let successful_moves = move_files(quiet, migrate_path.clone(), files);
replace_links(migrate_path, &files);
let successful_moves = move_files(quiet, migrate_path, &files);
let successful_moves: Vec<(PathBuf, PathBuf)> = successful_moves
.iter()
.map(|x| (x.1.clone(), x.0.clone()))
.collect(); //switch files to reverse a migration
remove_redirects(successful_moves, migrate_path.clone());
//shorten_all_external_links(migrate_path);
remove_redirects(&successful_moves, migrate_path);
// shorten_all_external_links(migrate_path);
}
fn move_files(
quiet: bool,
migrate_path: PathBuf,
files: Vec<(PathBuf, PathBuf)>,
migrate_path: &Path,
files: &[(PathBuf, PathBuf)],
) -> Vec<(PathBuf, PathBuf)> {
let mut successful_moves = vec![];
for file in files {
if !quiet {
print!("{} -> {} : ", file.0.display(), file.1.display());
eprint!("{} -> {} : ", file.0.display(), file.1.display());
}
let rename: anyhow::Result<()> = (|| {
let rename: Result<()> = (|| {
let old_file = migrate_path.join(&file.0);
let new_file = migrate_path.join(&file.1);
std::fs::create_dir_all(&new_file.parent().expect("files to have a parent"))?;
std::fs::rename(&old_file, &new_file)?;
fs::create_dir_all(new_file.parent().expect("files to have a parent"))?;
fs::rename(&old_file, &new_file)?;
Ok(())
})();
match rename {
Ok(_) => {
Ok(()) => {
if !quiet {
println!("{}", "Success".green());
eprintln!("{}", "Success".green());
}
successful_moves.push(file);
successful_moves.push(file.to_owned());
}
Err(_) => println!(
Err(_) => eprintln!(
"{}: Could not move file {}",
"Error".red(),
file.0.display()
),
};
}
}
successful_moves
}
fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) {
let files = recurse_directory(migrate_path.clone());
let mut moved = HashSet::new();
fn replace_links(migrate_path: &Path, moves: &[(PathBuf, PathBuf)]) {
let files = recurse_directory(migrate_path);
let mut absolute_moves = vec![];
for r#move in &moves {
for r#move in moves {
let r#move = (
migrate_path.join(r#move.0.clone()),
migrate_path.join(r#move.1.clone()),
@@ -115,59 +115,55 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) {
let absolute_move_0 = r#move
.0
.canonicalize()
.expect(&format!("{}", r#move.0.display()));
.unwrap_or_else(|_| panic!("{}", r#move.0.display()));
let _ = create_dir_all(r#move.1.parent().unwrap());
let _ = fs::create_dir_all(r#move.1.parent().unwrap());
let tmp_file = File::create_new(&r#move.1);
let absolute_move_1 = r#move.1.clone().canonicalize().expect(&format!(
"{} {:?}",
r#move.1.display(),
tmp_file
));
let absolute_move_1 = r#move
.1
.clone()
.canonicalize()
.unwrap_or_else(|_| panic!("{} {:?}", r#move.1.display(), tmp_file));
// delete file if it didn't already exist
if let Ok(_) = tmp_file {
let _ = remove_file(&r#move.1);
};
if tmp_file.is_ok() {
let _ = fs::remove_file(&r#move.1);
}
absolute_moves.push((absolute_move_0, absolute_move_1));
}
let absolute_moves = absolute_moves
.iter()
.map(|x| x.clone())
.cloned()
.collect::<HashMap<PathBuf, PathBuf>>();
let re = Regex::new(r"\[(?<name>[\w \-\*'`]*)\]\((?<link>[\w\-\\/\\.#]*)\)").unwrap();
for file in files {
let absolute_file = file.canonicalize().unwrap();
println!("{}", absolute_file.display());
let mut contents = match read_to_string(file.clone()) {
Ok(i) => i,
Err(_) => continue,
eprintln!("{}", absolute_file.display());
let Ok(mut contents) = fs::read_to_string(file.clone()) else {
continue;
};
// replace old absolute file with the new absolute file
let old_absolute_file = absolute_file.clone();
let absolute_file = match absolute_moves.get(&absolute_file) {
Some(file) => {
println!(" new file: {}", file.display());
moved.insert(absolute_file);
eprintln!(" new file: {}", file.display());
file.clone()
}
None => absolute_file.clone(),
};
// get all links in file and remove web links and link to self
let re = Regex::new(r"\[(?<name>[\w \-\*'`]*)\]\((?<link>[\w\-\\/\\.#]*)\)").unwrap();
let tmp_contents = contents.clone();
let captures: Vec<Captures> = re
.captures_iter(&tmp_contents)
.filter(|x| {
let link = &x["link"];
!["http", "#", "/"]
.iter()
.fold(false, |acc, x| acc || link.starts_with(x))
!["http", "#", "/"].iter().any(|x| link.starts_with(x))
})
.collect();
println!(" captures: {}\n", captures.len());
eprintln!(" captures: {}\n", captures.len());
for capture in captures {
let mut capture_log = String::new();
@@ -176,37 +172,31 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) {
let link_postfix_index = link.find('#');
let link_postfix = match link_postfix_index {
Some(i) => {
let link_postfix = link[i..].to_owned();
link_path = link[..i].to_owned();
Some(link_postfix)
}
None => {
link_path = link.clone();
None
},
let link_postfix = if let Some(i) = link_postfix_index {
let link_postfix = link[i..].to_owned();
link_path = link[..i].to_owned();
Some(link_postfix)
} else {
link_path = link.clone();
None
};
let absolute_link = old_absolute_file.parent().unwrap().join(link_path.clone());
//let _ = create_dir_all(absolute_link.parent().unwrap());
//let tmp_file = File::create_new(&absolute_link);
// let _ = fs::create_dir_all(absolute_link.parent().unwrap());
// let tmp_file = File::create_new(&absolute_link);
let absolute_link = match absolute_link
let Ok(absolute_link) = absolute_link
.canonicalize()
.or(absolute_link.with_extension("md").canonicalize())
.or(absolute_link.with_extension("mdx").canonicalize())
{
Ok(link) => link,
_ => {
println!(
" {}: {} -> {}",
"failed".red(),
absolute_file.to_string_lossy().to_string().red(),
absolute_link.to_string_lossy().to_string().red()
);
continue;
}
.or_else(|_| absolute_link.with_extension("md").canonicalize())
.or_else(|_| absolute_link.with_extension("mdx").canonicalize())
else {
eprintln!(
" {}: {} -> {}",
"failed".red(),
absolute_file.to_string_lossy().to_string().red(),
absolute_link.to_string_lossy().to_string().red()
);
continue;
};
let absolute_link = if absolute_link.is_file() {
absolute_link
@@ -215,7 +205,7 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) {
} else if absolute_link.join("index.mdx").is_file() {
absolute_link.join("index.mdx")
} else {
println!(
eprintln!(
" {}: {} -> {}",
"failed".red(),
absolute_file.to_string_lossy().to_string().red(),
@@ -224,10 +214,10 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) {
continue;
};
// delete file if it didn't already exist
//if let Ok(_) = tmp_file {
// let _ = remove_file(&absolute_link);
// if tmp_file.is_ok() {
// let _ = fs::remove_file(&absolute_link);
//};
capture_log.push_str(&format!(" oldalink: {}\n", absolute_link.display()));
let _ = writeln!(capture_log, " oldalink: {}", absolute_link.display());
// replace old absolute link with the new absolute link
let absolute_link = match absolute_moves.get(&absolute_link) {
@@ -235,7 +225,7 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) {
None => absolute_link.clone(),
};
capture_log.push_str(&format!(" newalink: {}\n", absolute_link.display()));
let _ = writeln!(capture_log, " newalink: {}", absolute_link.display());
// create tmp absolutes and make them into components
let tmp_absolute_file = absolute_file.clone();
@@ -245,24 +235,26 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) {
// remove the shared path components
loop {
if tmp_absolute_file.front() != tmp_absolute_link.front()
|| tmp_absolute_file.front() == None
|| tmp_absolute_file.front().is_none()
{
break;
}
tmp_absolute_file.pop_front();
tmp_absolute_link.pop_front();
}
capture_log.push_str(&format!(
" shrtfile: {}\n",
let _ = writeln!(
capture_log,
" shrtfile: {}",
tmp_absolute_file.iter().collect::<PathBuf>().display()
));
capture_log.push_str(&format!(
" shrtlink: {}\n",
);
let _ = writeln!(
capture_log,
" shrtlink: {}",
tmp_absolute_link.iter().collect::<PathBuf>().display()
));
);
if tmp_absolute_file.len() <= 0 {
println!(
if tmp_absolute_file.is_empty() {
eprintln!(
" {}: {} -> {}",
"failed".red(),
absolute_file.to_string_lossy().to_string().red(),
@@ -270,8 +262,8 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) {
);
continue;
}
let escapes = (0..tmp_absolute_file.len() - 1)
.map(|_| Component::Normal("..".as_ref()))
let escapes = repeat_with(|| Component::Normal("..".as_ref()))
.take(tmp_absolute_file.len() - 1)
.collect::<PathBuf>();
let new_link = escapes.join(tmp_absolute_link.iter().collect::<PathBuf>());
@@ -284,69 +276,66 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) {
.collect::<PathBuf>()
.to_str()
{
Some(".") => new_link,
Some("..") => new_link,
Some("." | "..") => new_link,
_ => PathBuf::from(".").join(new_link),
};
let mut new_link = new_link.to_string_lossy().to_string();
match link_postfix {
Some(i) => new_link.push_str(&i),
None => {}
if let Some(i) = link_postfix {
new_link.push_str(&i);
}
capture_log.push_str(&format!(" old link: {}\n", link));
capture_log.push_str(&format!(" new link: {}\n", new_link));
print!("{}", capture_log);
//println!("{} {} {}", absolute_file.display(), absolute_link.display(), new_link.display());
let tmp_contents = contents.replace(&format!("({})", link), &format!("({})", new_link));
let _ = writeln!(capture_log, " old link: {link}");
let _ = writeln!(capture_log, " new link: {new_link}");
eprint!("{capture_log}");
// eprintln!("{} {} {}", absolute_file.display(), absolute_link.display(),
// new_link.display());
let tmp_contents = contents.replace(&format!("({link})"), &format!("({new_link})"));
if tmp_contents == contents {
println!("{}", " nothing replaced".yellow());
eprintln!("{}", " nothing replaced".yellow());
} else {
contents = tmp_contents;
};
println!("");
}
eprintln!();
}
write(file, contents).unwrap();
fs::write(file, contents).unwrap();
}
}
fn fix_internal_links_in_file(migrate_path: PathBuf, move_from: PathBuf, move_to: PathBuf) {
#[expect(unused)]
fn fix_internal_links_in_file(migrate_path: &Path, move_from: &Path, move_to: &Path) {
let move_from = migrate_path.join(move_from);
let move_to = migrate_path.join(move_to);
let contents = read_to_string(&move_from);
let mut contents = match contents {
Ok(ok) => ok,
Err(_) => return,
let Ok(mut contents) = fs::read_to_string(&move_from) else {
return;
};
let re = Regex::new(r"\[(?<name>.*)\]\((?<link>.*)\)").unwrap();
let captures: Vec<Captures> = re.captures_iter(&contents).collect();
let mut changes = vec![];
for capture in captures {
//let name = &capture["name"];
// let name = &capture["name"];
let link = &capture["link"];
if link.starts_with('#') || link.starts_with("http") {
continue;
}
let link = PathBuf::from(link);
//println!("{} {}", move_from.display(), link.display());
// println!("{} {}", move_from.display(), link.display());
let absolute_link = move_from
.parent()
.unwrap()
.canonicalize()
.unwrap()
.join(&link);
if move_to.components().collect::<Vec<_>>().len() > 1 {
let _ = create_dir_all(move_to.parent().unwrap());
if move_to.components().count() > 1 {
let _ = fs::create_dir_all(move_to.parent().unwrap());
}
let tmp_file = File::create_new(move_to.clone());
//println!("{} {} {} {}", name, link.display(), absolute_link.display(), make_path_relative(absolute_link.clone(), move_to.canonicalize().unwrap().clone()).display());
let new_link = make_path_relative(
absolute_link.clone(),
move_to.canonicalize().unwrap().clone(),
);
if let Ok(_) = tmp_file {
remove_file(move_to.clone()).unwrap()
};
// println!("{} {} {} {}", name, link.display(), absolute_link.display(),
// make_path_relative(absolute_link.clone(),
// move_to.canonicalize().unwrap().clone()).display());
let new_link = make_path_relative(&absolute_link, &move_to.canonicalize().unwrap());
if tmp_file.is_ok() {
fs::remove_file(move_to.clone()).unwrap();
}
changes.push((link.clone(), new_link.clone()));
}
for i in changes {
@@ -355,73 +344,64 @@ fn fix_internal_links_in_file(migrate_path: PathBuf, move_from: PathBuf, move_to
&format!("({})", i.1.display()),
);
}
write(move_from, contents).unwrap();
fs::write(move_from, contents).unwrap();
}
fn make_path_relative(path: PathBuf, relative_to: PathBuf) -> PathBuf {
fn make_path_relative(path: &Path, relative_to: &Path) -> PathBuf {
let mut subdirs = 0;
let path_components = path.components().collect::<Vec<_>>();
let relative_to_components = relative_to.components().collect::<Vec<_>>();
loop {
if path_components.len() <= subdirs {
break;
} else if path_components[subdirs] != relative_to_components[subdirs] {
if path_components.len() <= subdirs
|| path_components[subdirs] != relative_to_components[subdirs]
{
break;
}
subdirs += 1;
}
let new_path = &path_components[subdirs..].iter().collect::<PathBuf>();
let backouts = (0..relative_to_components.len() - subdirs - 1)
.map(|_| PathBuf::from(".."))
let backouts = repeat_with(|| PathBuf::from(".."))
.take(relative_to_components.len() - subdirs - 1)
.reduce(|acc, e| acc.join(e))
.unwrap_or(PathBuf::from(""));
//println!("{}, {}", relative_to_components.len() - subdirs - 1, backouts.display());
.unwrap_or_else(|| PathBuf::from(""));
// println!("{}, {}", relative_to_components.len() - subdirs - 1, backouts.display());
let new_path = backouts.join(new_path);
let new_path = if new_path
.to_string_lossy()
.to_string()
.chars()
.next()
.unwrap()
!= '.'
{
PathBuf::from(".").join(new_path)
} else {
let new_path = if new_path.to_string_lossy().to_string().starts_with('.') {
new_path
} else {
PathBuf::from(".").join(new_path)
};
let new_path = if new_path.file_name() == Some(OsStr::new("index.md"))
if new_path.file_name() == Some(OsStr::new("index.md"))
|| new_path.file_name() == Some(OsStr::new("index.mdx"))
{
new_path.parent().unwrap().to_path_buf()
} else {
new_path
};
new_path
}
}
fn add_redirects(successful_moves: Vec<(PathBuf, PathBuf)>, migrate_path: PathBuf) {
fn add_redirects(successful_moves: &[(PathBuf, PathBuf)], migrate_path: &Path) {
let redirects = generate_redirects(successful_moves);
let netlify_path = migrate_path.parent().unwrap().join("netlify.toml");
let mut netlify_contents = read_to_string(netlify_path.clone()).unwrap();
let mut netlify_contents = fs::read_to_string(netlify_path.clone()).unwrap();
for redirect in redirects {
netlify_contents.push_str(&redirect);
}
std::fs::write(netlify_path, netlify_contents).unwrap();
fs::write(netlify_path, netlify_contents).unwrap();
}
fn remove_redirects(successful_moves: Vec<(PathBuf, PathBuf)>, migrate_path: PathBuf) {
fn remove_redirects(successful_moves: &[(PathBuf, PathBuf)], migrate_path: &Path) {
let redirects = generate_redirects(successful_moves);
let netlify_path = migrate_path.parent().unwrap().join("netlify.toml");
let mut netlify_contents = read_to_string(netlify_path.clone()).unwrap();
let mut netlify_contents = fs::read_to_string(netlify_path.clone()).unwrap();
for redirect in redirects {
netlify_contents = netlify_contents.replace(&redirect, "");
}
std::fs::write(netlify_path, netlify_contents).unwrap();
fs::write(netlify_path, netlify_contents).unwrap();
}
fn generate_redirects(successful_moves: Vec<(PathBuf, PathBuf)>) -> Vec<String> {
fn generate_redirects(successful_moves: &[(PathBuf, PathBuf)]) -> Vec<String> {
successful_moves
.iter()
.map(|x| {

View File

@@ -1,16 +1,21 @@
use std::{fs::read_to_string, path::PathBuf};
use std::{
fs::read_to_string,
path::{Path, PathBuf},
};
pub fn read_migrate_file(file: PathBuf) -> anyhow::Result<Vec<(PathBuf, PathBuf)>> {
use eyre::Result;
pub(crate) fn read_migrate_file(file: &Path) -> Result<Vec<(PathBuf, PathBuf)>> {
let contents = read_to_string(file)?;
let lines: Vec<String> = contents
.split('\n')
.map(|x| x.to_owned())
.filter(|x| x != "")
.filter(|x| !x.is_empty())
.collect();
let migrations = lines
.iter()
.filter_map(|x| x.split_once(" -> "))
.filter(|x| !(x.0 == x.1))
.filter(|x| x.0 != x.1)
.map(|x| {
(
x.0.parse().expect("a valid path"),
@@ -21,16 +26,16 @@ pub fn read_migrate_file(file: PathBuf) -> anyhow::Result<Vec<(PathBuf, PathBuf)
Ok(migrations)
}
pub fn read_migrate_file_left_side(file: PathBuf) -> anyhow::Result<Vec<PathBuf>> {
pub(crate) fn read_migrate_file_left_side(file: &Path) -> Result<Vec<PathBuf>> {
let contents = read_to_string(file)?;
let lines: Vec<String> = contents
.split('\n')
.map(|x| x.to_owned())
.filter(|x| x != "")
.filter(|x| !x.is_empty())
.collect();
let migrations = lines
.iter()
.map(|x| x.split(" -> ").collect::<Vec<&str>>()[0].into())
.map(|x| x.split(" -> ").next().unwrap().into())
.collect::<Vec<_>>();
Ok(migrations)
}

View File

@@ -1,20 +1,20 @@
use std::path::PathBuf;
use std::path::Path;
use crate::recurse_directory;
pub fn r#move(old_path: PathBuf, new_path: PathBuf) {
pub(crate) fn r#move(old_path: &Path, new_path: &Path) {
let is_dir = old_path.is_dir();
if is_dir {
let paths = recurse_directory(old_path.clone());
let paths = recurse_directory(old_path);
for path in paths {
let raw_path = path
.strip_prefix(old_path.clone())
.strip_prefix(old_path)
.expect("path to be within old path");
let new_path = new_path.join(raw_path);
println!("{} -> {}", path.display(), new_path.display());
eprintln!("{} -> {}", path.display(), new_path.display());
}
} else {
println!(
eprintln!(
"{} -> {}",
old_path.to_string_lossy(),
new_path.to_string_lossy()