sidestepper: yeah its done lol
this language is kinda nice actually
This commit is contained in:
parent
fa05392348
commit
5f60a5fad2
1 changed files with 180 additions and 8 deletions
188
src/main.rs
188
src/main.rs
|
@ -14,15 +14,19 @@
|
|||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs::metadata;
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::{env, fs, io};
|
||||
|
||||
const SOTA_SIDESTEP_CHUNK_SIZE: u16 = 16;
|
||||
const SOTA_SIDESTEP_MAX_WORKERS: u16 = 4;
|
||||
use ignore;
|
||||
|
||||
// const SOTA_SIDESTEP_CHUNK_SIZE: u16 = 16;
|
||||
// const SOTA_SIDESTEP_MAX_WORKERS: u16 = 4;
|
||||
const SOTA_SIDESTEP_LARGE_FILE_SIZE: u64 = 100000000; // 100mb
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Behaviour {
|
||||
repo_dir_path: PathBuf,
|
||||
repo_sotaignore_path: PathBuf,
|
||||
|
@ -30,7 +34,6 @@ struct Behaviour {
|
|||
// chunk_size: u16,
|
||||
// max_workers: u16,
|
||||
large_file_size: u64,
|
||||
search_here: bool,
|
||||
plumbing: bool,
|
||||
}
|
||||
|
||||
|
@ -83,7 +86,6 @@ fn cli_get_behaviour() -> Result<Behaviour, Box<dyn Error>> {
|
|||
repo_dir_path: PathBuf::from(¤t_dir),
|
||||
repo_sotaignore_path: PathBuf::from(current_dir.join(".sotaignore")),
|
||||
large_file_size,
|
||||
search_here,
|
||||
plumbing,
|
||||
});
|
||||
}
|
||||
|
@ -114,13 +116,137 @@ fn cli_get_behaviour() -> Result<Behaviour, Box<dyn Error>> {
|
|||
repo_dir_path: PathBuf::from(repo_dir_path),
|
||||
repo_sotaignore_path: PathBuf::from(repo_dir_path.join(".sotaignore")),
|
||||
large_file_size,
|
||||
search_here,
|
||||
plumbing,
|
||||
})
|
||||
}
|
||||
|
||||
fn ss_scan_for_unignored_files(behaviour: &Behaviour) -> Vec<PathBuf> {
|
||||
// for file in ignore::WalkBuilder::new(&behaviour.repo_dir_path)
|
||||
// .hidden(false)
|
||||
// .build()
|
||||
// .into_iter()
|
||||
// .filter_map(|e| e.ok())
|
||||
// {
|
||||
// if file
|
||||
// .path()
|
||||
// .starts_with(Path::new(&behaviour.repo_dir_path).join(".git/"))
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// if file.path().is_file() {
|
||||
// files.push(file.into_path());
|
||||
// }
|
||||
// }
|
||||
ignore::WalkBuilder::new(&behaviour.repo_dir_path)
|
||||
.hidden(false)
|
||||
.build()
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|file| {
|
||||
!file
|
||||
.path()
|
||||
.starts_with(Path::new(&behaviour.repo_dir_path).join(".git/"))
|
||||
&& file.path().is_file()
|
||||
})
|
||||
.map(|file| file.into_path())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn ss_check_for_large_files(behaviour: &Behaviour, files: &Vec<PathBuf>) -> Vec<PathBuf> {
|
||||
// let mut large_files: Vec<PathBuf> = Vec::new();
|
||||
// for file in files {
|
||||
// let result = metadata(file);
|
||||
// if let Err(_) = result {
|
||||
// continue;
|
||||
// }
|
||||
// let metadata = result.unwrap();
|
||||
// if metadata.len() >= behaviour.large_file_size {
|
||||
// large_files.push(file.into());
|
||||
// }
|
||||
// }
|
||||
files
|
||||
.iter()
|
||||
.filter_map(|file| {
|
||||
metadata(file)
|
||||
.ok()
|
||||
.filter(|meta| meta.len() >= behaviour.large_file_size)
|
||||
.map(|_| file.into())
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn ss_write_sotaignore(behaviour: &Behaviour, large_files: &Vec<PathBuf>) -> io::Result<bool> {
|
||||
if large_files.is_empty() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// are we outputting to stdout for other programs?
|
||||
// do so and return true, we did write something
|
||||
if behaviour.plumbing {
|
||||
eprintln!();
|
||||
for file in large_files {
|
||||
println!("{}", file.to_str().unwrap());
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let old_sotaignore = if behaviour.repo_sotaignore_path.try_exists().ok() == Some(true) {
|
||||
fs::read_to_string(&behaviour.repo_sotaignore_path)?
|
||||
.lines()
|
||||
.map(String::from)
|
||||
.collect::<Vec<String>>()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let mut new_sotaignore = old_sotaignore.clone();
|
||||
for file in large_files {
|
||||
if let Ok(file_relative) = file.strip_prefix(&behaviour.repo_dir_path) {
|
||||
let relative_path_str = file_relative.to_string_lossy();
|
||||
if !old_sotaignore.contains(&relative_path_str.to_string()) {
|
||||
new_sotaignore.push(relative_path_str.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no new changes? return, nothing has been written
|
||||
if new_sotaignore == old_sotaignore {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// check if the sotaignore file starts with a comment
|
||||
if !new_sotaignore.is_empty() & !new_sotaignore[0].starts_with("#") {
|
||||
let header = vec![
|
||||
"# .sotaignore file generated by sota staircase ReStepper/SideStepper",
|
||||
"# anything here either can't or shouldn't be uploaded to GitHub",
|
||||
"# unless you know what you're doing, don't edit this file! >:(",
|
||||
];
|
||||
new_sotaignore.splice(0..0, header.iter().map(|&line| line.to_string()));
|
||||
}
|
||||
|
||||
let mut sotaignore_file = fs::File::create(&behaviour.repo_sotaignore_path)?;
|
||||
sotaignore_file.write_all(new_sotaignore.join("\n").as_bytes())?;
|
||||
sotaignore_file.write_all(b"\n")?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn format_elapsed_time(secs: f64) -> String {
|
||||
let hours = (secs / 3600.0).floor() as i64;
|
||||
let minutes = ((secs % 3600.0) / 60.0).floor() as i64;
|
||||
let seconds = (secs % 60.0).round() as f64;
|
||||
let secs_string: String;
|
||||
if secs > 3600.0 {
|
||||
secs_string = format!("{}h {}′ {:.1}″", hours, minutes, seconds);
|
||||
} else if secs > 60.0 {
|
||||
secs_string = format!("{}′ {:.2}″", minutes, seconds);
|
||||
} else {
|
||||
secs_string = format!("{:.3}″", secs);
|
||||
}
|
||||
secs_string
|
||||
}
|
||||
|
||||
fn main() {
|
||||
eprintln!("\nsota staircase SideStepper v5 (i3/a4)");
|
||||
eprintln!("\nsota staircase SideStepper v5 (i3/a5)");
|
||||
let behaviour = {
|
||||
let behaviour = cli_get_behaviour();
|
||||
// huh. pattern matching consumes the variable, so we ref (&) it. damn.
|
||||
|
@ -151,4 +277,50 @@ fn main() {
|
|||
}
|
||||
},
|
||||
);
|
||||
|
||||
let zero_duration = Duration::new(0, 0);
|
||||
let all = SystemTime::now();
|
||||
|
||||
eprint!("1/3 scanning repository... ");
|
||||
let now = SystemTime::now();
|
||||
let files = ss_scan_for_unignored_files(&behaviour);
|
||||
eprintln!(
|
||||
"done in {} (found {})",
|
||||
format_elapsed_time(now.elapsed().unwrap_or(zero_duration).as_secs_f64()),
|
||||
files.len()
|
||||
);
|
||||
|
||||
eprint!("2/3 finding large files... ");
|
||||
let now = SystemTime::now();
|
||||
let large_files = ss_check_for_large_files(&behaviour, &files);
|
||||
eprintln!(
|
||||
"done in {} (found {})",
|
||||
format_elapsed_time(now.elapsed().unwrap_or(zero_duration).as_secs_f64()),
|
||||
large_files.len()
|
||||
);
|
||||
|
||||
eprint!("3/3 writing .sotaignore file... ");
|
||||
match ss_write_sotaignore(&behaviour, &large_files) {
|
||||
Ok(true) => {
|
||||
eprintln!(
|
||||
"{}",
|
||||
if behaviour.plumbing {
|
||||
"done (to stdout)"
|
||||
} else {
|
||||
"done"
|
||||
}
|
||||
);
|
||||
}
|
||||
Ok(false) => {
|
||||
eprintln!("skipped")
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("error ({})", e)
|
||||
}
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
"\n--- done! took {} ″~ ☆*: .。. o(≧▽≦)o .。.:*☆ ---\n",
|
||||
format_elapsed_time(all.elapsed().unwrap_or(zero_duration).as_secs_f64())
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue