Changeset 319b736 in gignore


Ignore:
Timestamp:
7 Dec 2025, 16:25:36 (5 months ago)
Author:
Asher Mullaney <asher.mullaney@…>
Branches:
error_handling, file_locations, help, json_tlib, logging, man, multi_arg, trunk, visibility
Children:
b6c2333
Parents:
48d7b95
Message:

First commit! Fully functional.

Files:
1 added
1 deleted
3 edited

Legend:

Unmodified
Added
Removed
  • .gitignore

    r48d7b95 r319b736  
    11target/
    2 *.swp
    3 */*.swp
    42Cargo.lock
     3**.swp
     4test.txt
     5python.txt
     6rust.txt
     7mutants.out
     8vi.txt
     9html.txt
  • Cargo.toml

    r48d7b95 r319b736  
    66[dependencies]
    77clap = { version = "4.5.53", features = ["derive"] }
     8home = "0.5.12"
  • src/lib.rs

    r48d7b95 r319b736  
    11#![warn(clippy::unwrap_used)]
     2
     3mod template;
    24
    35use clap::{Subcommand, Parser};
     
    911    process::exit,
    1012    io,
     13    path::Path,
    1114};
     15
     16trait HandleErr {
     17    type OkType;
     18
     19    fn handle_err(self, _: &str) -> Self::OkType;
     20}
     21
     22impl<T, E: std::fmt::Display> HandleErr for Result<T, E> {
     23    type OkType = T;
     24
     25    fn handle_err(self, operation: &str) -> Self::OkType {
     26        match self {
     27            Ok(val) => val,
     28            Err(e) => {
     29                eprintln!("Error {operation}: {e}");
     30                exit(1);
     31            },
     32        }
     33    }
     34}
     35impl<T> HandleErr for Option<T> {
     36    type OkType = T;
     37
     38    fn handle_err(self, none_message: &str) -> Self::OkType {
     39        match self {
     40            Some(val) => val,
     41            None => {
     42                eprintln!("{none_message}");
     43                exit(1);
     44            },
     45        }
     46    }
     47}
     48
    1249#[derive(Parser)]
    1350#[command(about = ".gitignore manipulator tool.", long_about = None, version)]
     
    3370    /// Lists items within .gitignore
    3471    List {
     72        /// Print contents on one line, separated by whitespace.
    3573        #[arg(long)]
    3674        oneline: bool,
    3775    },
     76
     77    /// Add, remove, or use templates.
     78    Template {
     79        #[command(subcommand)]
     80        operation: TemplateCommand,
     81    },
     82}
     83
     84#[derive(Subcommand)]
     85pub enum TemplateCommand {
     86    /// Add template names and source files to the library
     87    Add {
     88        /// Name to add to library
     89        name: String,
     90        /// Source file to add to library
     91        source_file: String,
     92
     93        #[arg(long, short)]
     94        /// Append template to .gitignore when using (rather than truncating)
     95        append: bool,
     96    },
     97
     98    /// Remove templates from the library
     99    Remove {
     100        /// Name to remove from library
     101        name: String,
     102    },
     103
     104    /// Use templates
     105    Use {
     106        /// Name to write to gitignore
     107        name: String,
     108    },
     109
     110    /// List entries in library
     111    List {
     112        #[arg(long)]
     113        /// Print entries on one line
     114        oneline: bool
     115    },
     116   
     117    /// Clear template library
     118    Clear,
    38119}
    39120
     
    45126        } => {
    46127            let Some(path) = path else {
    47                 File::create("test_gitignore").unwrap_or_else(|e| {
    48                     println!("Error creating file: {e}");
    49                     exit(1);
    50                 });
     128                File::create(".gitignore").handle_err("creating file");
    51129
    52130                std::process::exit(0);
    53131            };
    54132
    55             let mut append_handle = open_append("test_gitignore").unwrap_or_else(|e| {
    56                 println!("Error opening file for append: {e}");
    57                 exit(1);
    58             });
    59 
    60             append_handle.write_all(format!("{}\n", path.trim()).as_bytes()).unwrap_or_else(|e| {
    61                 println!("Error writing to file: {e}");
    62                 exit(1);
    63             });
     133            if fs::read_to_string(".gitignore")
     134                .handle_err("reading file")
     135                    .lines()
     136                    .collect::<Vec<&str>>()
     137                    .contains(&&path[..]) {
     138                        println!("That path already exists in .gitignore!");
     139                        exit(1);
     140            }
     141
     142            let mut append_handle = open_append(".gitignore".as_ref()).handle_err("opening file for append");
     143
     144            append_handle.write_all(format!("{}\n", path.trim()).as_bytes()).handle_err("writing to file");
    64145        },
    65146        OperCommand::Remove {
     
    67148        } => {
    68149            let Some(path) = path else {
    69                 println!("This will permanently remove .gitignore!");
    70 
    71                 loop {
    72                     println!("Do you really want to do this? y/N");
    73                     let mut s = String::new();
    74                     io::stdin()
    75                         .read_line(&mut s)
    76                         .unwrap_or_else(|e| {
    77                             println!("Error reading from stdin: {e}");
    78                             exit(1);
    79                         });
    80 
    81                     match &s.trim().to_lowercase()[..] {
    82                         "" | "n" => break,
    83                         "y" => {
    84                             println!("Removing .gitignore...");
    85 
    86                             fs::remove_file("test_gitignore").unwrap_or_else(|e| {
    87                                 eprintln!("Error while removing the file: {e}");
    88                                 exit(1);
    89                             });
    90 
    91                             exit(0);
     150                if fs::exists(".gitignore").handle_err("searching for file") {
     151                    loop {
     152                        println!("This will permanently remove .gitignore!");
     153                        println!("Do you really want to do this? y/N");
     154                        let mut s = String::new();
     155                        io::stdin()
     156                            .read_line(&mut s)
     157                            .handle_err("reading stdin");
     158
     159                        match &s.trim().to_lowercase()[..] {
     160                            "" | "n" => break,
     161                            "y" => {
     162                                println!("Removing .gitignore...");
     163
     164                                fs::remove_file(".gitignore").handle_err("removing file");
     165
     166                                exit(0);
     167                            }
     168                            _ => continue,
    92169                        }
    93                         _ => continue,
    94170                    }
     171                    exit(0);
     172                } else {
     173                    println!("File is already removed.");
     174                    exit(1);
    95175                }
    96                 exit(0);
    97176            };
    98177
    99             let contents = fs::read_to_string("test_gitignore").unwrap_or_else(|e| {
    100                 eprintln!("Error reading contents of file: {e}");
    101                 exit(1);
    102             });
     178            let contents = fs::read_to_string(".gitignore").handle_err("reading file");
    103179
    104180            let mut lines: Vec<&str> =  contents.lines().collect();
     
    113189            drop(extracted);
    114190
     191            open_truncate(".gitignore".as_ref()).handle_err("opening file for truncate").write_all(b"").handle_err("writing to file");
     192
    115193            // Re-add lines to file, without [PATH].
    116194            for line in lines {
    117                 File::create("test_gitignore").unwrap_or_else(|e| {
    118                     eprintln!("{e}");
    119                     exit(1);
    120                 })
    121                 .write_all(format!("{}\n", line).as_bytes())
    122                 .unwrap_or_else(|e| {
    123                     eprintln!("{e}");
    124                     exit(1);
    125                 });
     195                open_append(".gitignore".as_ref()).handle_err("opening file for append")
     196                    .write_all(
     197                        format!("{line}\n").as_bytes()
     198                    ).handle_err("writing to file");
    126199            }
    127200        },
     
    130203            oneline
    131204        } => {
    132             let result = fs::read_to_string("test_gitignore");
     205            let result = fs::read_to_string(".gitignore");
    133206
    134207            if let Err(e) = result {
     
    151224
    152225            println!("{}", result.trim());
     226        },
     227
     228        OperCommand::Template {
     229            operation: TemplateCommand::Add {
     230                name,
     231                source_file,
     232                append,
     233            }
     234        } => {
     235            template::add(template::Template::new(source_file.as_ref(), name, *append));
     236        }
     237
     238        OperCommand::Template {
     239            operation: TemplateCommand::Remove {
     240                name,
     241            }
     242        } => {
     243            template::remove(name);
     244        },
     245
     246        OperCommand::Template {
     247            operation: TemplateCommand::List {
     248                oneline,
     249            }
     250        } => {
     251            template::list(*oneline);
     252        },
     253
     254        OperCommand::Template {
     255            operation: TemplateCommand::Use {
     256                name,
     257            }
     258        } => {
     259            template::gitignore_write(name);
     260        },
     261
     262        OperCommand::Template {
     263            operation: TemplateCommand::Clear
     264        } => {
     265            template::clear();
    153266        }
    154267    };
    155268}
    156269
    157 fn open_append(path: &str) -> Result<File, Box<dyn Error>> {
     270fn open_append(path: &Path) -> Result<File, Box<dyn Error>> {
    158271    Ok(
    159272        OpenOptions::new()
     
    163276    )
    164277}
     278fn open_truncate(path: &Path) -> Result<File, Box<dyn Error>> {
     279    Ok(
     280        OpenOptions::new()
     281        .create(true)
     282        .write(true)
     283        .truncate(true)
     284        .open(path)?
     285    )
     286}
Note: See TracChangeset for help on using the changeset viewer.