Compare commits
3 Commits
e990bfd452
...
4418427caf
Author | SHA1 | Date | |
---|---|---|---|
4418427caf | |||
4d44b447d5 | |||
56d8b7f6d4 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
something/
|
||||
target/
|
||||
|
419
Cargo.lock
generated
419
Cargo.lock
generated
@ -2,6 +2,425 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[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.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06badb543e734a2d6568e19a40af66ed5364360b9226184926f89d229b4b4267"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"unicase",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"terminal_size",
|
||||
"unicode-width",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
|
||||
dependencies = [
|
||||
"indenter",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gitignore"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"console",
|
||||
"eyre",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indenter"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.135"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"libc",
|
||||
"num_threads",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"time",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
16
README.md
Normal file
16
README.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Git ignore
|
||||
|
||||
Is an extension for easily adding ignored files to `.gitignore files`, when
|
||||
added it will by default also try to remove any files matching the pattern added
|
||||
to .gitignore, this is by default also run in interactive mode, giving you the
|
||||
option to confirm or deny
|
||||
|
||||
```bash
|
||||
$ git ignore 'node_modules/'
|
||||
Added node_modules/ to .gitignore
|
||||
Searching env for pattern...
|
||||
|
||||
found:
|
||||
<gitroot>/client/node_modules
|
||||
? Remove from git state? (Y)es/(N)o/(C)ontinue/(A)bort
|
||||
```
|
1
crates/gitignore/.gitignore
vendored
1
crates/gitignore/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/target
|
@ -6,3 +6,8 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.0.17", features = ["env", "unicode", "string"] }
|
||||
console = "0.15.2"
|
||||
eyre = "0.6.8"
|
||||
tracing = { version = "0.1.37", features = ["log"] }
|
||||
tracing-subscriber = { version = "0.3.16", features = ["local-time", "env-filter"] }
|
||||
|
191
crates/gitignore/src/.main.rs.rustfmt
Normal file
191
crates/gitignore/src/.main.rs.rustfmt
Normal file
@ -0,0 +1,191 @@
|
||||
use clap::{Arg, Command};
|
||||
use eyre::{Context, ContextCompat};
|
||||
use std::io::prelude::*;
|
||||
use std::{env::current_dir, io::Read, path::PathBuf};
|
||||
|
||||
fn main() -> eyre::Result<()> {
|
||||
let matches = Command::new("gitignore")
|
||||
.version("0.1")
|
||||
.author("Kasper J. Hermansen <contact@kjuulh.io>")
|
||||
.about("Easily ignore items and remove from git state")
|
||||
.long_about("git ignore is a utility tool for easily adding patterns to your .gitignore file.
|
||||
Easily add patterns using `git ignore <pattern>` this will by default also help you remove committed code violating these patterns
|
||||
")
|
||||
.propagate_version(true)
|
||||
.arg(
|
||||
Arg::new("pattern")
|
||||
.help("the pattern you want to ignore")
|
||||
.long_help("the pattern you want to ignore in the nearest .gitignore file")
|
||||
.required(true),
|
||||
).arg(
|
||||
Arg::new("log-level").long("log-level").help("choose a log level and get more messages").long_help("Choose a log level and get more message, defaults to [INFO]"))
|
||||
.get_matches();
|
||||
|
||||
let pattern = matches
|
||||
.get_one::<String>("pattern")
|
||||
.context("missing [pattern]")?;
|
||||
|
||||
add_gitignore_pattern(pattern)
|
||||
}
|
||||
|
||||
enum GitActions {
|
||||
AddPattern {
|
||||
git_path: PathBuf,
|
||||
gitignore_path: PathBuf,
|
||||
},
|
||||
CreateIgnoreAndAddPattern {
|
||||
git_path: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
fn add_gitignore_pattern(pattern: &String) -> eyre::Result<()> {
|
||||
let curdir = current_dir().context(
|
||||
"could not find current_dir, you may not have permission to access that directory",
|
||||
)?;
|
||||
let actions = match search_for_dotgitignore(&curdir)? {
|
||||
// If we have an ignore path, make sure it is in a git repo as well
|
||||
GitSearchResult::GitIgnore(ignorepath) => match search_for_git_root(&curdir)? {
|
||||
GitSearchResult::Git(gitpath) => GitActions::AddPattern {
|
||||
git_path: gitpath,
|
||||
gitignore_path: ignorepath,
|
||||
},
|
||||
_ => return Err(eyre::anyhow!("could not find parent git directory")),
|
||||
},
|
||||
// Find the nearest git repo
|
||||
GitSearchResult::Git(gitpath) => {
|
||||
GitActions::CreateIgnoreAndAddPattern { git_path: gitpath }
|
||||
} // We will always have either above, or an error so we have no default arm
|
||||
};
|
||||
|
||||
match actions {
|
||||
GitActions::AddPattern {
|
||||
git_path,
|
||||
gitignore_path,
|
||||
} => {
|
||||
let mut gitignore_file = open_gitignore_file(&gitignore_path)?;
|
||||
// TODO: search for pattern in file
|
||||
let mut gitignore_content = String::new();
|
||||
gitignore_file
|
||||
.read_to_string(&mut gitignore_content)
|
||||
.context(format!(
|
||||
"could not read file: {}",
|
||||
gitignore_path.to_string_lossy()
|
||||
))?;
|
||||
if gitignore_content.contains(pattern) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
writeln!(gitignore_file, "{}", pattern).context("could not write contents to file")?;
|
||||
gitignore_file
|
||||
.sync_all()
|
||||
.context("failed to write data to disk")?;
|
||||
}
|
||||
GitActions::CreateIgnoreAndAddPattern { git_path } => {
|
||||
// TODO: Create gitignore file in root
|
||||
let mut gitignore_file = create_gitignore_file(&git_path)?;
|
||||
// TODO: do same as above
|
||||
writeln!(gitignore_file, "{}", pattern).context("could not write contents to file")?;
|
||||
gitignore_file
|
||||
.sync_all()
|
||||
.context("failed to write data to disk")?;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Run git rm -r --cached on the .git root
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_gitignore_file(gitroot: &PathBuf) -> eyre::Result<std::fs::File> {
|
||||
let mut ignore_path = gitroot.clone();
|
||||
if !ignore_path.pop() {
|
||||
return Err(eyre::anyhow!("could not open parent dir"));
|
||||
}
|
||||
ignore_path.push(".gitignore");
|
||||
let file = std::fs::File::create(ignore_path.clone()).context(format!(
|
||||
"could not create file at path: {}",
|
||||
ignore_path.to_string_lossy()
|
||||
))?;
|
||||
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
fn open_gitignore_file(gitignore: &PathBuf) -> eyre::Result<std::fs::File> {
|
||||
let file = std::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(gitignore)
|
||||
.context(format!(
|
||||
"could not create file at path: {}",
|
||||
gitignore.to_string_lossy()
|
||||
))?;
|
||||
|
||||
return Ok(file);
|
||||
}
|
||||
|
||||
enum GitSearchResult {
|
||||
GitIgnore(PathBuf),
|
||||
Git(PathBuf),
|
||||
}
|
||||
|
||||
fn search_for_git_root(path: &PathBuf) -> eyre::Result<GitSearchResult> {
|
||||
if !path.is_dir() {
|
||||
return Err(eyre::anyhow!(
|
||||
"path is not a dir: {}",
|
||||
path.to_string_lossy()
|
||||
));
|
||||
}
|
||||
|
||||
let direntries = std::fs::read_dir(path)
|
||||
.context(format!("could not open dir: {}", path.to_string_lossy()))?;
|
||||
for direntry in direntries {
|
||||
let entry = direntry.context("could not access file")?;
|
||||
|
||||
let file_name = entry.file_name().to_os_string();
|
||||
match file_name.to_str().context("could not convert to str")? {
|
||||
".git" => return Ok(GitSearchResult::Git(entry.path())),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut upwards_par = path.clone();
|
||||
if !upwards_par.pop() {
|
||||
return Err(eyre::anyhow!(
|
||||
"no parent exists, cannot check further, you may not be in a git repository"
|
||||
));
|
||||
}
|
||||
|
||||
search_for_git_root(&upwards_par)
|
||||
}
|
||||
|
||||
fn search_for_dotgitignore(path: &PathBuf) -> eyre::Result<GitSearchResult> {
|
||||
if !path.is_dir() {
|
||||
return Err(eyre::anyhow!(
|
||||
"path is not a dir: {}",
|
||||
path.to_string_lossy()
|
||||
));
|
||||
}
|
||||
|
||||
let direntries = std::fs::read_dir(path)
|
||||
.context(format!("could not open dir: {}", path.to_string_lossy()))?;
|
||||
for direntry in direntries {
|
||||
let entry = direntry.context("could not access file")?;
|
||||
|
||||
let file_name = entry.file_name().to_os_string();
|
||||
|
||||
match file_name.to_str().context("could not convert to str")? {
|
||||
".gitignore" => return Ok(GitSearchResult::GitIgnore(entry.path())),
|
||||
".git" => return Ok(GitSearchResult::Git(entry.path())),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut upwards_par = path.clone();
|
||||
if !upwards_par.pop() {
|
||||
return Err(eyre::anyhow!(
|
||||
"no parent exists, cannot check further, you may not be in a git repository"
|
||||
));
|
||||
}
|
||||
|
||||
search_for_dotgitignore(&upwards_par)
|
||||
}
|
@ -1,3 +1,217 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use clap::{Arg, Command};
|
||||
use eyre::{Context, ContextCompat};
|
||||
use std::io::prelude::*;
|
||||
use std::{env::current_dir, io::Read, path::PathBuf};
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
|
||||
fn main() -> eyre::Result<()> {
|
||||
let matches = Command::new("gitignore")
|
||||
.version("0.1")
|
||||
.author("Kasper J. Hermansen <contact@kjuulh.io>")
|
||||
.about("Easily ignore items and remove from git state")
|
||||
.long_about("git ignore is a utility tool for easily adding patterns to your .gitignore file.
|
||||
Easily add patterns using `git ignore <pattern>` this will by default also help you remove committed code violating these patterns
|
||||
")
|
||||
.propagate_version(true)
|
||||
.arg(
|
||||
Arg::new("pattern")
|
||||
.help("the pattern you want to ignore")
|
||||
.long_help("the pattern you want to ignore in the nearest .gitignore file")
|
||||
.required(true),
|
||||
).arg(
|
||||
Arg::new("log-level").long("log-level").help("choose a log level and get more messages").long_help("Choose a log level and get more message, defaults to [fatal]"))
|
||||
.get_matches();
|
||||
|
||||
let log_level = match matches.get_one::<String>("log-level").map(|f| f.as_str()) {
|
||||
Some("off") => "off",
|
||||
Some("info") => "info",
|
||||
Some("debug") => "debug",
|
||||
Some("warn") => "warn",
|
||||
Some("error") => "error",
|
||||
_ => "error",
|
||||
};
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(tracing_subscriber::EnvFilter::new(format!(
|
||||
"gitignore={}",
|
||||
log_level
|
||||
)))
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
|
||||
let term = console::Term::stdout();
|
||||
|
||||
let pattern = matches
|
||||
.get_one::<String>("pattern")
|
||||
.context("missing [pattern]")?;
|
||||
|
||||
add_gitignore_pattern(term, pattern)
|
||||
}
|
||||
|
||||
enum GitActions {
|
||||
AddPattern {
|
||||
git_path: PathBuf,
|
||||
gitignore_path: PathBuf,
|
||||
},
|
||||
CreateIgnoreAndAddPattern {
|
||||
git_path: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
fn add_gitignore_pattern(term: console::Term, pattern: &String) -> eyre::Result<()> {
|
||||
term.write_line("git ignore: Add pattern")?;
|
||||
let curdir = current_dir().context(
|
||||
"could not find current_dir, you may not have permission to access that directory",
|
||||
)?;
|
||||
let actions = match search_for_dotgitignore(&curdir)? {
|
||||
// If we have an ignore path, make sure it is in a git repo as well
|
||||
GitSearchResult::GitIgnore(ignorepath) => match search_for_git_root(&curdir)? {
|
||||
GitSearchResult::Git(gitpath) => GitActions::AddPattern {
|
||||
git_path: gitpath,
|
||||
gitignore_path: ignorepath,
|
||||
},
|
||||
_ => return Err(eyre::anyhow!("could not find parent git directory")),
|
||||
},
|
||||
// Find the nearest git repo
|
||||
GitSearchResult::Git(gitpath) => {
|
||||
GitActions::CreateIgnoreAndAddPattern { git_path: gitpath }
|
||||
} // We will always have either above, or an error so we have no default arm
|
||||
};
|
||||
|
||||
match actions {
|
||||
GitActions::AddPattern {
|
||||
git_path,
|
||||
gitignore_path,
|
||||
} => {
|
||||
term.write_line("Found existing .gitignore")?;
|
||||
let mut gitignore_file = open_gitignore_file(&gitignore_path)?;
|
||||
let mut gitignore_content = String::new();
|
||||
gitignore_file
|
||||
.read_to_string(&mut gitignore_content)
|
||||
.context(format!(
|
||||
"could not read file: {}",
|
||||
gitignore_path.to_string_lossy()
|
||||
))?;
|
||||
if gitignore_content.contains(pattern) {
|
||||
term.write_line(".gitignore already contains pattern, skipping")?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
term.write_line("adding pattern to file")?;
|
||||
writeln!(gitignore_file, "{}", pattern).context("could not write contents to file")?;
|
||||
gitignore_file
|
||||
.sync_all()
|
||||
.context("failed to write data to disk")?;
|
||||
}
|
||||
GitActions::CreateIgnoreAndAddPattern { git_path } => {
|
||||
term.write_line(
|
||||
"could not find .gitignore file, creating one in the root of the git repository",
|
||||
)?;
|
||||
let mut gitignore_file = create_gitignore_file(&git_path)?;
|
||||
term.write_line("adding pattern to file")?;
|
||||
writeln!(gitignore_file, "{}", pattern).context("could not write contents to file")?;
|
||||
gitignore_file
|
||||
.sync_all()
|
||||
.context("failed to write data to disk")?;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Run git rm -r --cached on the .git root
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_gitignore_file(gitroot: &PathBuf) -> eyre::Result<std::fs::File> {
|
||||
let mut ignore_path = gitroot.clone();
|
||||
if !ignore_path.pop() {
|
||||
return Err(eyre::anyhow!("could not open parent dir"));
|
||||
}
|
||||
ignore_path.push(".gitignore");
|
||||
let file = std::fs::File::create(ignore_path.clone()).context(format!(
|
||||
"could not create file at path: {}",
|
||||
ignore_path.to_string_lossy()
|
||||
))?;
|
||||
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
fn open_gitignore_file(gitignore: &PathBuf) -> eyre::Result<std::fs::File> {
|
||||
let file = std::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(gitignore)
|
||||
.context(format!(
|
||||
"could not create file at path: {}",
|
||||
gitignore.to_string_lossy()
|
||||
))?;
|
||||
|
||||
return Ok(file);
|
||||
}
|
||||
|
||||
enum GitSearchResult {
|
||||
GitIgnore(PathBuf),
|
||||
Git(PathBuf),
|
||||
}
|
||||
|
||||
fn search_for_git_root(path: &PathBuf) -> eyre::Result<GitSearchResult> {
|
||||
if !path.is_dir() {
|
||||
return Err(eyre::anyhow!(
|
||||
"path is not a dir: {}",
|
||||
path.to_string_lossy()
|
||||
));
|
||||
}
|
||||
|
||||
let direntries = std::fs::read_dir(path)
|
||||
.context(format!("could not open dir: {}", path.to_string_lossy()))?;
|
||||
for direntry in direntries {
|
||||
let entry = direntry.context("could not access file")?;
|
||||
|
||||
let file_name = entry.file_name().to_os_string();
|
||||
match file_name.to_str().context("could not convert to str")? {
|
||||
".git" => return Ok(GitSearchResult::Git(entry.path())),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut upwards_par = path.clone();
|
||||
if !upwards_par.pop() {
|
||||
return Err(eyre::anyhow!(
|
||||
"no parent exists, cannot check further, you may not be in a git repository"
|
||||
));
|
||||
}
|
||||
|
||||
search_for_git_root(&upwards_par)
|
||||
}
|
||||
|
||||
fn search_for_dotgitignore(path: &PathBuf) -> eyre::Result<GitSearchResult> {
|
||||
if !path.is_dir() {
|
||||
return Err(eyre::anyhow!(
|
||||
"path is not a dir: {}",
|
||||
path.to_string_lossy()
|
||||
));
|
||||
}
|
||||
|
||||
let direntries = std::fs::read_dir(path)
|
||||
.context(format!("could not open dir: {}", path.to_string_lossy()))?;
|
||||
for direntry in direntries {
|
||||
let entry = direntry.context("could not access file")?;
|
||||
|
||||
let file_name = entry.file_name().to_os_string();
|
||||
|
||||
match file_name.to_str().context("could not convert to str")? {
|
||||
".gitignore" => return Ok(GitSearchResult::GitIgnore(entry.path())),
|
||||
".git" => return Ok(GitSearchResult::Git(entry.path())),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut upwards_par = path.clone();
|
||||
if !upwards_par.pop() {
|
||||
return Err(eyre::anyhow!(
|
||||
"no parent exists, cannot check further, you may not be in a git repository"
|
||||
));
|
||||
}
|
||||
|
||||
search_for_dotgitignore(&upwards_par)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user