chore: bump v0.1.0, housekeeping #8

Merged
cafkafk merged 8 commits from dev into main 2023-07-03 11:49:50 +02:00
12 changed files with 129 additions and 73 deletions

View file

@ -2,6 +2,24 @@
All notable changes to this project will be documented in this file.
## [0.1.0] - 2023-07-03
### Documentation
- Changed roadmap
- Updated roadmap
### Features
- Implemented CoC flag
- Quiet flag
- Made SUCCESS/FAILURE emoji const
- Added flag no-emoji
### Refactor
- Made code more idiomatic
## [0.0.7] - 2023-07-02
### Bug Fixes

2
Cargo.lock generated
View file

@ -179,7 +179,7 @@ dependencies = [
[[package]]
name = "gg"
version = "0.0.6"
version = "0.1.0"
dependencies = [
"clap",
"clap_mangen",

View file

@ -1,6 +1,6 @@
[package]
name = "gg"
version = "0.0.7"
version = "0.1.0"
edition = "2021"
authors = ["Christina Sørensen"]
repository = "https://github.com/cafkafk/gg"

View file

@ -9,15 +9,17 @@ those that use declarative operating systems and package managers.
Although this isn't really a case where it matters *that* much for performance,
being written in rust instead of e.g. /janky/ scripting languages does also mean
it is snappy and reliable, and the /extensive/ testing helps ensure regressions
aren't introduced.
it is snappy and reliable, and the /extensive/ (hardly, but eventually) testing
helps ensure regressions aren't introduced.
That said, we're in 0.0.Z, *here be dragons* for now.
That said, we're in 0.Y.Z, *here be dragons* for now (although a little less each
commit).
** Installation
#+begin_src sh
$ git clone https://github.com/cafkafk/git
$ ./install
$ git clone https://github.com/cafkafk/gg
$ cd gg
$ cargo install --path .
#+end_src
** Configuration

View file

@ -1,3 +1,2 @@
#!/usr/bin/env bash
cargo rustc --release -- -C target-cpu=native
cargo install --path .

View file

@ -1,15 +1,27 @@
#+title: Roadmap
* 0.2.0 (maybe)
- [ ] Links in categories?
* 0.1.2
- [ ] Implement Quiet flag
* 0.1.1
- [ ] Implement no-emoji flag
* 0.1.0 [100%] [5/5]
- [X] No functionality regressions
- [X] commit works in quick, fast
- [X] commit with edit works
- [X] Repo Flags Finished
- [X] Optional Fields
- [X] Subcommands
- [X] Quiet flag (wont rn)
- [X] Do something about coc flag
- [X] UX
- [X] Change failure emotes
- [X] Flag for disabling emotes
* Roadmap [0%] [0/4]
- [ ] Custom operation sequences
- [ ] Generic repositories
- [ ] Version pinning
- [ ] libgit2 (maybe)
* 0.1.0 [60%] [3/5]
- [X] No functionality regressions
- [X] commit works in quick, fast
- [X] commit with edit works
- [X] Repo Flags Finished
- [ ] Category Flags Finished
- [X] Optional Fields
- [ ] Subcommands

View file

@ -59,10 +59,18 @@ pub struct Args {
#[arg(long)]
pub warranty: bool,
/// Print code-of-conduct information (not implemented)
/// Print code-of-conduct information
#[arg(long)]
pub code_of_conduct: bool,
/// Try to be as quiet as possible (unix philosophy) (not imlemented)
#[arg(short, long)]
pub quiet: bool,
/// No emoji (not imlemented)
#[arg(short, long)]
pub no_emoji: bool,
#[command(subcommand)]
pub command: Option<Commands>,
}

View file

@ -25,6 +25,8 @@ use std::os::unix::fs::symlink;
use std::path::Path;
use std::{fs, process::Command};
use crate::utils::strings::{FAILURE_EMOJI, SUCCESS_EMOJI};
/// An enum containing flags that change behaviour of repos and categories
#[derive(PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum RepoFlags {
@ -53,7 +55,7 @@ pub enum RepoFlags {
/// For diagrams of the underlying architecture, consult ARCHITECHTURE.md
///
///
#[derive(PartialEq, Debug, Serialize, Deserialize)]
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct Config {
/// map of all categories
///
@ -66,7 +68,7 @@ pub struct Config {
/// Represents a category of repositories
///
/// This allows you to organize your repositories into categories
#[derive(PartialEq, Debug, Serialize, Deserialize)]
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct Category {
#[serde(skip_serializing_if = "Option::is_none")]
pub flags: Option<Vec<RepoFlags>>, // FIXME: not implemented
@ -78,7 +80,7 @@ pub struct Category {
}
/// Contain fields for a single link.
#[derive(PartialEq, Debug, Serialize, Deserialize)]
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct Links {
/// The name of the link
pub name: String,
@ -87,7 +89,7 @@ pub struct Links {
}
/// Holds a single git repository and related fields.
#[derive(PartialEq, Debug, Serialize, Deserialize)]
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct GitRepo {
pub name: String,
pub path: String,
@ -101,7 +103,7 @@ pub struct GitRepo {
////////////////////////////////////
/// Represents a single operation on a repository
struct SeriesItem<'series> {
pub struct SeriesItem<'series> {
/// The string to be displayed to the user
operation: &'series str,
/// The closure representing the actual operation
@ -114,7 +116,10 @@ struct SeriesItem<'series> {
fn handle_file_exists(selff: &Links, tx_path: &Path, rx_path: &Path) {
match rx_path.read_link() {
Ok(file) if file.canonicalize().unwrap() == tx_path.canonicalize().unwrap() => {
Ok(file)
if file.canonicalize().expect("failed to canonicalize file")
== tx_path.canonicalize().expect("failed to canonicalize path") =>
{
debug!(
"Linking {} -> {} failed: file already linked",
&selff.tx, &selff.rx
@ -291,7 +296,7 @@ impl GitRepo {
/// Removes a repository (not implemented)
///
/// Kept here as a reminder that we probably shouldn't do this
fn remove(&self) -> Result<(), std::io::Error> {
fn remove() -> Result<(), std::io::Error> {
// https://doc.rust-lang.org/std/fs/fn.remove_dir_all.html
unimplemented!("This seems to easy to missuse/exploit");
// fs::remove_dir_all(format!("{}{}", &self.path, &self.name))
@ -327,7 +332,7 @@ impl Config {
where
F: Fn(&GitRepo),
{
for (_, category) in self.categories.iter() {
for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
f(repo);
}
@ -342,14 +347,13 @@ impl Config {
where
F: Fn(&GitRepo) -> bool,
{
for (_, category) in self.categories.iter() {
for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
let mut sp =
Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op).into());
let mut sp = Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op));
if f(repo) {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into());
sp.stop_and_persist(SUCCESS_EMOJI, format!("{}: {}", repo.name, op));
} else {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into());
sp.stop_and_persist(FAILURE_EMOJI, format!("{}: {}", repo.name, op));
}
}
}
@ -396,17 +400,16 @@ impl Config {
/// self.series_on_all(series);
/// ```
pub fn series_on_all(&self, closures: Vec<SeriesItem>) {
for (_, category) in self.categories.iter() {
for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
for instruction in closures.iter() {
for instruction in &closures {
let f = &instruction.closure;
let op = instruction.operation;
let mut sp =
Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op).into());
let mut sp = Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op));
if f(repo) {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into());
sp.stop_and_persist(SUCCESS_EMOJI, format!("{}: {}", repo.name, op));
} else {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into());
sp.stop_and_persist(FAILURE_EMOJI, format!("{}: {}", repo.name, op));
break;
}
}
@ -443,17 +446,16 @@ impl Config {
/// self.all_on_all(series);
/// ```
pub fn all_on_all(&self, closures: Vec<SeriesItem>) {
for (_, category) in self.categories.iter() {
for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
for instruction in closures.iter() {
for instruction in &closures {
let f = &instruction.closure;
let op = instruction.operation;
let mut sp =
Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op).into());
let mut sp = Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op));
if f(repo) {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into());
sp.stop_and_persist(SUCCESS_EMOJI, format!("{}: {}", repo.name, op));
} else {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into());
sp.stop_and_persist(FAILURE_EMOJI, format!("{}: {}", repo.name, op));
}
}
}
@ -465,22 +467,22 @@ impl Config {
/// Tries to pull all repositories, skips if fail.
pub fn pull_all(&self) {
debug!("exectuting pull_all");
self.on_all_spinner("pull", |repo| repo.pull());
self.on_all_spinner("pull", GitRepo::pull);
}
/// Tries to clone all repositories, skips if fail.
pub fn clone_all(&self) {
debug!("exectuting clone_all");
self.on_all_spinner("clone", |repo| repo.clone());
self.on_all_spinner("clone", GitRepo::clone);
}
/// Tries to add all work in all repositories, skips if fail.
pub fn add_all(&self) {
debug!("exectuting clone_all");
self.on_all_spinner("add", |repo| repo.add_all());
self.on_all_spinner("add", GitRepo::add_all);
}
/// Tries to commit all repositories one at a time, skips if fail.
pub fn commit_all(&self) {
debug!("exectuting clone_all");
self.on_all_spinner("commit", |repo| repo.commit());
self.on_all_spinner("commit", GitRepo::commit);
}
/// Tries to commit all repositories with msg, skips if fail.
pub fn commit_all_msg(&self, msg: &str) {
@ -494,11 +496,11 @@ impl Config {
let series: Vec<SeriesItem> = vec![
SeriesItem {
operation: "pull",
closure: Box::new(move |repo: &GitRepo| repo.pull()),
closure: Box::new(GitRepo::pull),
},
SeriesItem {
operation: "add",
closure: Box::new(move |repo: &GitRepo| repo.add_all()),
closure: Box::new(GitRepo::add_all),
},
SeriesItem {
operation: "commit",
@ -506,7 +508,7 @@ impl Config {
},
SeriesItem {
operation: "push",
closure: Box::new(move |repo: &GitRepo| repo.push()),
closure: Box::new(GitRepo::push),
},
];
self.all_on_all(series);
@ -518,19 +520,19 @@ impl Config {
let series: Vec<SeriesItem> = vec![
SeriesItem {
operation: "pull",
closure: Box::new(move |repo: &GitRepo| repo.pull()),
closure: Box::new(GitRepo::pull),
},
SeriesItem {
operation: "add",
closure: Box::new(move |repo: &GitRepo| repo.add_all()),
closure: Box::new(GitRepo::add_all),
},
SeriesItem {
operation: "commit",
closure: Box::new(move |repo: &GitRepo| repo.commit()),
closure: Box::new(move |repo: &GitRepo| repo.commit_with_msg(msg)),
},
SeriesItem {
operation: "push",
closure: Box::new(move |repo: &GitRepo| repo.push()),
closure: Box::new(GitRepo::push),
},
];
self.series_on_all(series);
@ -541,7 +543,7 @@ impl Config {
/// Tries to link all repositories, skips if fail.
pub fn link_all(&self) {
debug!("exectuting link_all");
for link in self.links.iter() {
for link in &self.links {
link.link();
}
}

View file

@ -61,7 +61,8 @@ fn main() {
match &args {
args if args.license => println!("{}", utils::strings::INTERACTIVE_LICENSE),
args if args.warranty => println!("{}", utils::strings::INTERACTIVE_WARRANTY),
args if args.code_of_conduct => unimplemented!(),
args if args.code_of_conduct => println!("{}", utils::strings::INTERACTIVE_COC),
args if args.quiet => todo!(),
_ => (),
}
match &mut args.command {
@ -99,7 +100,7 @@ fn main() {
config.commit_all();
}
Some(Commands::CommitMsg { msg }) => {
config.commit_all_msg(msg.as_ref().unwrap());
config.commit_all_msg(msg.as_ref().expect("failed to get message from input"));
}
None => (),
}
@ -154,8 +155,6 @@ mod config {
},
);
}
// let yaml = serde_yaml::to_string(&config).unwrap();
// println!("{}", yaml);
}
#[test]
fn read_config_populate() {
@ -163,13 +162,13 @@ mod config {
}
#[test]
fn write_config() {
let root = current_dir().unwrap();
let root = current_dir().expect("failed to get current dir");
let config = Config::new(
&RelativePath::new("./src/test/config.yaml")
.to_logical_path(&root)
.into_os_string()
.into_string()
.unwrap(),
.expect("failed to turn config into string"),
);
let mut test_file = File::create(
@ -177,11 +176,13 @@ mod config {
.to_logical_path(&root)
.into_os_string()
.into_string()
.unwrap(),
.expect("failed to turn config into string"),
)
.expect("failed to create test file");
let contents = serde_yaml::to_string(&config).unwrap();
test_file.write_all(contents.as_bytes()).unwrap();
let contents = serde_yaml::to_string(&config).expect("failed to turn config into string");
test_file
.write_all(contents.as_bytes())
.expect("failed to write contents of config into file");
let test_config = Config::new(&RelativePath::new("./src/test/test.yaml").to_string());
assert_eq!(config, test_config);
@ -205,13 +206,13 @@ mod config {
}
#[test]
fn is_config_readable() {
let root = current_dir().unwrap();
let root = current_dir().expect("failed to get current dir");
let config = Config::new(
&RelativePath::new("./src/test/config.yaml")
.to_logical_path(root)
.into_os_string()
.into_string()
.unwrap(),
.expect("failed to turnn config into string"),
);
let flags = vec![Clone, Push];

View file

@ -15,6 +15,7 @@ categories:
flags:
- Clone
- Push
empty: {}
stuff:
flags: []
repos:
@ -29,13 +30,6 @@ categories:
config:
flags: []
repos:
qmk_firmware:
name: qmk_firmware
path: /home/ces/org/src/git/
url: git@github.com:cafkafk/qmk_firmware.git
flags:
- Clone
- Push
starship:
name: starship
path: /home/ces/org/src/git/
@ -43,7 +37,13 @@ categories:
flags:
- Clone
- Push
empty: {}
qmk_firmware:
name: qmk_firmware
path: /home/ces/org/src/git/
url: git@github.com:cafkafk/qmk_firmware.git
flags:
- Clone
- Push
links:
- name: gg
rx: /home/ces/.config/gg

View file

@ -50,7 +50,7 @@ pub fn home_dir() -> String {
///
/// WARNING: NOT THREAD SAFE
fn change_dir_repo(path: &str, name: &str) {
let mut full_path: String = "".to_owned();
let mut full_path: String = String::new();
full_path.push_str(path);
full_path.push_str(name);
let root = Path::new(&full_path);

View file

@ -46,8 +46,22 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
";
pub const INTERACTIVE_COC: &str = "\
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of
experience, nationality, personal appearance, race, religion, or sexual identity
and orientation. For more, see http://contributor-covenant.org/version/1/4";
/// Contains the message for quick commit subcommand
pub const QUICK_COMMIT: &str = "git: quick commit";
/// Contains the message for fast commit subcommand
pub const FAST_COMMIT: &str = "git: fast commit";
/// Success emoji
pub const SUCCESS_EMOJI: &str = "";
/// Failure emoji
pub const FAILURE_EMOJI: &str = "";