1 Commits

Author SHA1 Message Date
cuddle-please
1904af4413 chore(release): 0.3.5
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-02-20 06:02:16 +00:00
8 changed files with 703 additions and 853 deletions

View File

@@ -6,10 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.3.5] - 2025-03-04 ## [0.3.5] - 2025-02-20
### Added
- allow clone all
### Fixed ### Fixed
- *(deps)* update rust crate serde to v1.0.218 - *(deps)* update rust crate serde to v1.0.218
@@ -26,8 +23,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- *(deps)* update rust crate uuid to v1.11.1 - *(deps)* update rust crate uuid to v1.11.1
### Other ### Other
- *(deps)* update all dependencies
- *(deps)* update all dependencies
- *(deps)* update rust crate clap to v4.5.29 - *(deps)* update rust crate clap to v4.5.29
- *(deps)* update rust crate clap to v4.5.27 - *(deps)* update rust crate clap to v4.5.27
- *(deps)* update rust crate clap to v4.5.26 - *(deps)* update rust crate clap to v4.5.26

1440
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,5 @@
# Git Now # Git Now
> https://gitnow.kjuulh.io/
Git Now is a utility for easily navigating git projects from common upstream providers. Search, Download, and Enter projects as quickly as you can type. Git Now is a utility for easily navigating git projects from common upstream providers. Search, Download, and Enter projects as quickly as you can type.
![example gif](./assets/gifs/example.gif) ![example gif](./assets/gifs/example.gif)

View File

@@ -1,7 +1,7 @@
[package] [package]
name = "gitnow" name = "gitnow"
description = "Git Now is a utility for easily navigating git projects from common upstream providers. Search, Download, and Enter projects as quickly as you can type." description = "Git Now is a utility for easily navigating git projects from common upstream providers. Search, Download, and Enter projects as quickly as you can type."
edition = "2024" edition = "2021"
readme = "../../README.md" readme = "../../README.md"
repository = "https://github.com/kjuulh/gitnow" repository = "https://github.com/kjuulh/gitnow"
homepage = "https://gitnow-client.prod.kjuulh.app" homepage = "https://gitnow-client.prod.kjuulh.app"
@@ -36,7 +36,6 @@ ratatui = { version = "0.29.0", features = ["termwiz"] }
crossterm = { version = "0.28.0", features = ["event-stream"] } crossterm = { version = "0.28.0", features = ["event-stream"] }
futures = "0.3.30" futures = "0.3.30"
termwiz = "0.23.0" termwiz = "0.23.0"
regex = "1.11.1"
[dev-dependencies] [dev-dependencies]
pretty_assertions = "1.4.0" pretty_assertions = "1.4.0"

View File

@@ -1,83 +1,3 @@
pub mod root; pub mod root;
pub mod shell; pub mod shell;
pub mod update; pub mod update;
pub mod clone {
use std::sync::Arc;
use futures::future::join_all;
use regex::Regex;
use crate::{
app::App, cache::CacheApp, custom_command::CustomCommandApp, git_clone::GitCloneApp,
};
#[derive(clap::Parser)]
pub struct CloneCommand {
#[arg(long = "search")]
search: String,
}
impl CloneCommand {
pub async fn execute(&mut self, app: &'static App) -> anyhow::Result<()> {
let repos = app.cache().get().await?.ok_or(anyhow::anyhow!(
"failed to get cache, do a gitnow update first"
))?;
let search = Regex::new(&self.search)?;
let filtered_repos = repos
.iter()
.filter(|r| search.is_match(&r.to_rel_path().display().to_string()))
.collect::<Vec<_>>();
let concurrency_limit = Arc::new(tokio::sync::Semaphore::new(5));
let mut handles = Vec::default();
for repo in filtered_repos {
let config = app.config.clone();
let custom_command = app.custom_command();
let git_clone = app.git_clone();
let repo = repo.clone();
let concurrency = Arc::clone(&concurrency_limit);
let handle = tokio::spawn(async move {
let permit = concurrency.acquire().await?;
let project_path = config.settings.projects.directory.join(repo.to_rel_path());
if !project_path.exists() {
eprintln!("cloning repository: {}", repo.to_rel_path().display());
git_clone.clone_repo(&repo, false).await?;
custom_command
.execute_post_clone_command(&project_path)
.await?;
}
drop(permit);
Ok::<(), anyhow::Error>(())
});
handles.push(handle);
}
let res = join_all(handles).await;
for res in res {
match res {
Ok(Ok(())) => {}
Ok(Err(e)) => {
tracing::error!("failed to clone repo: {}", e);
anyhow::bail!(e)
}
Err(e) => {
tracing::error!("failed to clone repo: {}", e);
anyhow::bail!(e)
}
}
}
Ok(())
}
}
}

View File

@@ -3,16 +3,18 @@ use std::time::Duration;
use crossterm::event::{EventStream, KeyCode}; use crossterm::event::{EventStream, KeyCode};
use futures::{FutureExt, StreamExt}; use futures::{FutureExt, StreamExt};
use ratatui::{ use ratatui::{
TerminalOptions, Viewport, crossterm, crossterm,
prelude::*, prelude::*,
widgets::{Block, Padding}, widgets::{Block, Padding},
TerminalOptions, Viewport,
}; };
use crate::components::BatchCommand; use crate::components::BatchCommand;
use super::{ use super::{
Dispatch, IntoCommand, Msg, Receiver, create_dispatch, create_dispatch,
spinner::{Spinner, SpinnerState}, spinner::{Spinner, SpinnerState},
Dispatch, IntoCommand, Msg, Receiver,
}; };
pub struct InlineCommand { pub struct InlineCommand {
@@ -118,7 +120,7 @@ impl InlineCommand {
return Ok(true); return Ok(true);
} }
let mut cmd = self.update_state(msg); let mut cmd = self.update_state(&msg);
loop { loop {
let msg = cmd.into_command().execute(dispatch); let msg = cmd.into_command().execute(dispatch);
@@ -126,7 +128,7 @@ impl InlineCommand {
match msg { match msg {
Some(Msg::Quit) => return Ok(true), Some(Msg::Quit) => return Ok(true),
Some(msg) => { Some(msg) => {
cmd = self.update_state(msg); cmd = self.update_state(&msg);
} }
None => break, None => break,
} }
@@ -161,7 +163,7 @@ impl InlineCommand {
None None
} }
fn update_state(&mut self, msg: Msg) -> impl IntoCommand { fn update_state(&mut self, msg: &Msg) -> impl IntoCommand {
tracing::debug!("handling message: {:?}", msg); tracing::debug!("handling message: {:?}", msg);
let mut batch = BatchCommand::default(); let mut batch = BatchCommand::default();
@@ -176,7 +178,7 @@ impl InlineCommand {
} }
} }
batch.with(self.spinner.update(&msg)); batch.with(self.spinner.update(msg));
batch.into_command() batch.into_command()
} }

View File

@@ -148,7 +148,7 @@ impl CacheDuration {
hours, hours,
minutes, minutes,
} => Some( } => Some(
std::time::Duration::from_hours(*days * 24) std::time::Duration::from_days(*days)
+ std::time::Duration::from_hours(*hours) + std::time::Duration::from_hours(*hours)
+ std::time::Duration::from_mins(*minutes), + std::time::Duration::from_mins(*minutes),
), ),

View File

@@ -1,8 +1,10 @@
#![feature(duration_constructors)]
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::Context; use anyhow::Context;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use commands::{clone::CloneCommand, root::RootCommand, shell::Shell, update::Update}; use commands::{root::RootCommand, shell::Shell, update::Update};
use config::Config; use config::Config;
use tracing::level_filters::LevelFilter; use tracing::level_filters::LevelFilter;
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
@@ -50,7 +52,6 @@ struct Command {
enum Commands { enum Commands {
Init(Shell), Init(Shell),
Update(Update), Update(Update),
Clone(CloneCommand),
} }
const DEFAULT_CONFIG_PATH: &str = ".config/gitnow/gitnow.toml"; const DEFAULT_CONFIG_PATH: &str = ".config/gitnow/gitnow.toml";
@@ -88,9 +89,6 @@ async fn main() -> anyhow::Result<()> {
Commands::Update(mut update) => { Commands::Update(mut update) => {
update.execute(app).await?; update.execute(app).await?;
} }
Commands::Clone(mut clone) => {
clone.execute(app).await?;
}
}, },
None => { None => {
RootCommand::new(app) RootCommand::new(app)