Compare commits
1 Commits
51971d0202
...
4ebfb08d2e
Author | SHA1 | Date | |
---|---|---|---|
|
4ebfb08d2e |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
target/
|
target/
|
||||||
.cuddle/
|
.cuddle/
|
||||||
.DS_Store
|
|
||||||
|
@ -9,7 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## [0.2.1] - 2024-09-22
|
## [0.2.1] - 2024-09-22
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- include vhs demo
|
|
||||||
- add interactive search
|
- add interactive search
|
||||||
- implement naive fuzzy matcher
|
- implement naive fuzzy matcher
|
||||||
|
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
How many steps do you normally do to download a project?
|
How many steps do you normally do to download a project?
|
||||||
|
|
||||||
1. Navigate to github.com
|
1. Navigate to github.com
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 643 KiB |
@ -29,6 +29,3 @@ ratatui = "0.28.1"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
example = []
|
|
||||||
|
@ -19,27 +19,19 @@ impl RootCommand {
|
|||||||
Self { app }
|
Self { app }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(
|
pub async fn execute(&mut self, search: Option<impl Into<String>>) -> anyhow::Result<()> {
|
||||||
&mut self,
|
|
||||||
search: Option<impl Into<String>>,
|
|
||||||
cache: bool,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
tracing::debug!("executing");
|
tracing::debug!("executing");
|
||||||
|
|
||||||
let repositories = if cache {
|
let repositories = match self.app.cache().get().await? {
|
||||||
match self.app.cache().get().await? {
|
Some(repos) => repos,
|
||||||
Some(repos) => repos,
|
None => {
|
||||||
None => {
|
tracing::info!("finding repositories...");
|
||||||
tracing::info!("finding repositories...");
|
let repositories = self.app.projects_list().get_projects().await?;
|
||||||
let repositories = self.app.projects_list().get_projects().await?;
|
|
||||||
|
|
||||||
self.app.cache().update(&repositories).await?;
|
self.app.cache().update(&repositories).await?;
|
||||||
|
|
||||||
repositories
|
repositories
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.app.projects_list().get_projects().await?
|
|
||||||
};
|
};
|
||||||
match search {
|
match search {
|
||||||
Some(needle) => {
|
Some(needle) => {
|
||||||
|
@ -25,9 +25,6 @@ struct Command {
|
|||||||
|
|
||||||
#[arg()]
|
#[arg()]
|
||||||
search: Option<String>,
|
search: Option<String>,
|
||||||
|
|
||||||
#[arg(long = "no-cache", default_value = "false")]
|
|
||||||
no_cache: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
@ -59,9 +56,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
match cli.command {
|
match cli.command {
|
||||||
Some(_) => todo!(),
|
Some(_) => todo!(),
|
||||||
None => {
|
None => {
|
||||||
RootCommand::new(app)
|
RootCommand::new(app).execute(cli.search.as_ref()).await?;
|
||||||
.execute(cli.search.as_ref(), !cli.no_cache)
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,112 @@
|
|||||||
#[cfg(not(feature = "example"))]
|
use crate::{
|
||||||
pub use implementation::*;
|
app::App,
|
||||||
|
git_provider::{
|
||||||
|
gitea::GiteaProviderApp, github::GitHubProviderApp, Repository, VecRepositoryExt,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "example")]
|
pub struct ProjectsList {
|
||||||
pub use example_projects::*;
|
app: &'static App,
|
||||||
|
}
|
||||||
|
|
||||||
use crate::app::App;
|
impl ProjectsList {
|
||||||
|
pub fn new(app: &'static App) -> Self {
|
||||||
|
Self { app }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_projects(&self) -> anyhow::Result<Vec<Repository>> {
|
||||||
|
let mut repositories = Vec::new();
|
||||||
|
|
||||||
|
repositories.extend(self.get_gitea_projects().await?);
|
||||||
|
repositories.extend(self.get_github_projects().await?);
|
||||||
|
|
||||||
|
repositories.collect_unique();
|
||||||
|
|
||||||
|
Ok(repositories)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_gitea_projects(&self) -> anyhow::Result<Vec<Repository>> {
|
||||||
|
let gitea_provider = self.app.gitea_provider();
|
||||||
|
|
||||||
|
let mut repositories = Vec::new();
|
||||||
|
for gitea in self.app.config.providers.gitea.iter() {
|
||||||
|
if let Some(_user) = &gitea.current_user {
|
||||||
|
let mut repos = gitea_provider
|
||||||
|
.list_repositories_for_current_user(&gitea.url, gitea.access_token.as_ref())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
repositories.append(&mut repos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for gitea_user in gitea.users.iter() {
|
||||||
|
let mut repos = gitea_provider
|
||||||
|
.list_repositories_for_user(
|
||||||
|
gitea_user.into(),
|
||||||
|
&gitea.url,
|
||||||
|
gitea.access_token.as_ref(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
repositories.append(&mut repos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for gitea_org in gitea.organisations.iter() {
|
||||||
|
let mut repos = gitea_provider
|
||||||
|
.list_repositories_for_organisation(
|
||||||
|
gitea_org.into(),
|
||||||
|
&gitea.url,
|
||||||
|
gitea.access_token.as_ref(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
repositories.append(&mut repos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(repositories)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_github_projects(&self) -> anyhow::Result<Vec<Repository>> {
|
||||||
|
let github_provider = self.app.github_provider();
|
||||||
|
|
||||||
|
let mut repositories = Vec::new();
|
||||||
|
for github in self.app.config.providers.github.iter() {
|
||||||
|
if let Some(_user) = &github.current_user {
|
||||||
|
let mut repos = github_provider
|
||||||
|
.list_repositories_for_current_user(github.url.as_ref(), &github.access_token)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
repositories.append(&mut repos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for github_user in github.users.iter() {
|
||||||
|
let mut repos = github_provider
|
||||||
|
.list_repositories_for_user(
|
||||||
|
github_user.into(),
|
||||||
|
github.url.as_ref(),
|
||||||
|
&github.access_token,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
repositories.append(&mut repos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for github_org in github.organisations.iter() {
|
||||||
|
let mut repos = github_provider
|
||||||
|
.list_repositories_for_organisation(
|
||||||
|
github_org.into(),
|
||||||
|
github.url.as_ref(),
|
||||||
|
&github.access_token,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
repositories.append(&mut repos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(repositories)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ProjectsListApp {
|
pub trait ProjectsListApp {
|
||||||
fn projects_list(&self) -> ProjectsList;
|
fn projects_list(&self) -> ProjectsList;
|
||||||
@ -15,121 +117,3 @@ impl ProjectsListApp for &'static App {
|
|||||||
ProjectsList::new(self)
|
ProjectsList::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod implementation {
|
|
||||||
use crate::{
|
|
||||||
app::App,
|
|
||||||
git_provider::{
|
|
||||||
gitea::GiteaProviderApp, github::GitHubProviderApp, Repository, VecRepositoryExt,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct ProjectsList {
|
|
||||||
app: &'static App,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProjectsList {
|
|
||||||
pub fn new(app: &'static App) -> Self {
|
|
||||||
Self { app }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_projects(&self) -> anyhow::Result<Vec<Repository>> {
|
|
||||||
let mut repositories = Vec::new();
|
|
||||||
|
|
||||||
repositories.extend(self.get_gitea_projects().await?);
|
|
||||||
repositories.extend(self.get_github_projects().await?);
|
|
||||||
|
|
||||||
repositories.collect_unique();
|
|
||||||
|
|
||||||
Ok(repositories)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_gitea_projects(&self) -> anyhow::Result<Vec<Repository>> {
|
|
||||||
let gitea_provider = self.app.gitea_provider();
|
|
||||||
|
|
||||||
let mut repositories = Vec::new();
|
|
||||||
for gitea in self.app.config.providers.gitea.iter() {
|
|
||||||
if let Some(_user) = &gitea.current_user {
|
|
||||||
let mut repos = gitea_provider
|
|
||||||
.list_repositories_for_current_user(&gitea.url, gitea.access_token.as_ref())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
repositories.append(&mut repos);
|
|
||||||
}
|
|
||||||
|
|
||||||
for gitea_user in gitea.users.iter() {
|
|
||||||
let mut repos = gitea_provider
|
|
||||||
.list_repositories_for_user(
|
|
||||||
gitea_user.into(),
|
|
||||||
&gitea.url,
|
|
||||||
gitea.access_token.as_ref(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
repositories.append(&mut repos);
|
|
||||||
}
|
|
||||||
|
|
||||||
for gitea_org in gitea.organisations.iter() {
|
|
||||||
let mut repos = gitea_provider
|
|
||||||
.list_repositories_for_organisation(
|
|
||||||
gitea_org.into(),
|
|
||||||
&gitea.url,
|
|
||||||
gitea.access_token.as_ref(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
repositories.append(&mut repos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(repositories)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_github_projects(&self) -> anyhow::Result<Vec<Repository>> {
|
|
||||||
let github_provider = self.app.github_provider();
|
|
||||||
|
|
||||||
let mut repositories = Vec::new();
|
|
||||||
for github in self.app.config.providers.github.iter() {
|
|
||||||
if let Some(_user) = &github.current_user {
|
|
||||||
let mut repos = github_provider
|
|
||||||
.list_repositories_for_current_user(
|
|
||||||
github.url.as_ref(),
|
|
||||||
&github.access_token,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
repositories.append(&mut repos);
|
|
||||||
}
|
|
||||||
|
|
||||||
for github_user in github.users.iter() {
|
|
||||||
let mut repos = github_provider
|
|
||||||
.list_repositories_for_user(
|
|
||||||
github_user.into(),
|
|
||||||
github.url.as_ref(),
|
|
||||||
&github.access_token,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
repositories.append(&mut repos);
|
|
||||||
}
|
|
||||||
|
|
||||||
for github_org in github.organisations.iter() {
|
|
||||||
let mut repos = github_provider
|
|
||||||
.list_repositories_for_organisation(
|
|
||||||
github_org.into(),
|
|
||||||
github.url.as_ref(),
|
|
||||||
&github.access_token,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
repositories.append(&mut repos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(repositories)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "example")]
|
|
||||||
mod example_projects;
|
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
use crate::{app::App, git_provider::Repository};
|
|
||||||
|
|
||||||
pub struct ProjectsList {}
|
|
||||||
|
|
||||||
impl ProjectsList {
|
|
||||||
pub fn new(_app: &'static App) -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_projects(&self) -> anyhow::Result<Vec<Repository>> {
|
|
||||||
Ok(self.from_strings([
|
|
||||||
"github.com/kjuulh/gitnow",
|
|
||||||
"github.com/kjuulh/gitnow-client",
|
|
||||||
"github.com/kjuulh/crunch",
|
|
||||||
"git.front.kjuulh.io/kjuulh/gitnow",
|
|
||||||
"git.front.kjuulh.io/kjuulh/gitnow-client",
|
|
||||||
"git.front.kjuulh.io/kjuulh/cuddle",
|
|
||||||
"git.front.kjuulh.io/kjuulh/buckle",
|
|
||||||
"git.front.kjuulh.io/kjuulh/books",
|
|
||||||
"git.front.kjuulh.io/kjuulh/blog-deployment",
|
|
||||||
"git.front.kjuulh.io/kjuulh/blog",
|
|
||||||
"git.front.kjuulh.io/kjuulh/bitfield",
|
|
||||||
"git.front.kjuulh.io/kjuulh/bitebuds-deployment",
|
|
||||||
"git.front.kjuulh.io/kjuulh/bitebuds",
|
|
||||||
"git.front.kjuulh.io/kjuulh/beerday",
|
|
||||||
"git.front.kjuulh.io/kjuulh/bearing",
|
|
||||||
"git.front.kjuulh.io/kjuulh/basic-webserver",
|
|
||||||
"git.front.kjuulh.io/kjuulh/backup",
|
|
||||||
"git.front.kjuulh.io/kjuulh/backstage",
|
|
||||||
"git.front.kjuulh.io/kjuulh/autom8-calendar-integration",
|
|
||||||
"git.front.kjuulh.io/kjuulh/astronvim",
|
|
||||||
"git.front.kjuulh.io/kjuulh/artifacts",
|
|
||||||
"git.front.kjuulh.io/kjuulh/articles",
|
|
||||||
"git.front.kjuulh.io/kjuulh/acc-server",
|
|
||||||
"git.front.kjuulh.io/kjuulh/_cargo-index",
|
|
||||||
"git.front.kjuulh.io/keep-up/keep-up-example",
|
|
||||||
"git.front.kjuulh.io/keep-up/keep-up",
|
|
||||||
"git.front.kjuulh.io/experiments/wasm-bin",
|
|
||||||
"git.front.kjuulh.io/dotfiles/doom",
|
|
||||||
"git.front.kjuulh.io/danskebank/testssl.sh",
|
|
||||||
"git.front.kjuulh.io/clank/kubernetes-state",
|
|
||||||
"git.front.kjuulh.io/clank/kubernetes-init",
|
|
||||||
"git.front.kjuulh.io/clank/blog",
|
|
||||||
"git.front.kjuulh.io/cibus/deployments",
|
|
||||||
"git.front.kjuulh.io/butikkaerlighilsen/client",
|
|
||||||
"git.front.kjuulh.io/bevy/bevy",
|
|
||||||
"git.front.kjuulh.io/OpenFood/openfood",
|
|
||||||
]))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_strings(
|
|
||||||
&self,
|
|
||||||
repos_into: impl IntoIterator<Item = impl Into<Repository>>,
|
|
||||||
) -> Vec<Repository> {
|
|
||||||
let repos = repos_into
|
|
||||||
.into_iter()
|
|
||||||
.map(|item| item.into())
|
|
||||||
.collect::<Vec<Repository>>();
|
|
||||||
|
|
||||||
repos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&str> for Repository {
|
|
||||||
fn from(value: &str) -> Self {
|
|
||||||
let values = value.split("/").collect::<Vec<_>>();
|
|
||||||
if values.len() != 3 {
|
|
||||||
panic!("value: '{value}' isn't a valid provider/owner/repository")
|
|
||||||
}
|
|
||||||
|
|
||||||
let (provider, owner, name) = (
|
|
||||||
values.get(0).unwrap(),
|
|
||||||
values.get(1).unwrap(),
|
|
||||||
values.get(2).unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
provider: provider.to_string(),
|
|
||||||
owner: owner.to_string(),
|
|
||||||
repo_name: name.to_string(),
|
|
||||||
ssh_url: format!("ssh://git@{provider}/{owner}/{name}.git"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,9 +15,3 @@ please:
|
|||||||
api_url: "https://git.front.kjuulh.io"
|
api_url: "https://git.front.kjuulh.io"
|
||||||
actions:
|
actions:
|
||||||
rust:
|
rust:
|
||||||
|
|
||||||
scripts:
|
|
||||||
record:
|
|
||||||
type: shell
|
|
||||||
update-gifs:
|
|
||||||
type: shell
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
#!/usr/bin/env zsh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Loop through each file in the folder
|
|
||||||
for file in "vhs"/*; do
|
|
||||||
# Check if it is a file (not a directory)
|
|
||||||
if [[ -f "$file" ]]; then
|
|
||||||
echo "Recording: $file"
|
|
||||||
|
|
||||||
vhs "./$file"
|
|
||||||
fi
|
|
||||||
done
|
|
@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/env zsh
|
|
||||||
|
|
||||||
rm -r assets/gifs
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
cuddle x record
|
|
||||||
mkdir -p assets/gifs
|
|
||||||
mv target/vhs/* assets/gifs
|
|
@ -1,14 +0,0 @@
|
|||||||
Output "target/vhs/example.gif"
|
|
||||||
Set Theme "Aardvark Blue"
|
|
||||||
Set Width 1200
|
|
||||||
Set Height 1000
|
|
||||||
Hide
|
|
||||||
Type "cargo run --features example -- --no-cache"
|
|
||||||
Enter
|
|
||||||
Sleep 1s
|
|
||||||
Show
|
|
||||||
Sleep 2s
|
|
||||||
Type@500ms "bevy"
|
|
||||||
Sleep 3s
|
|
||||||
Enter
|
|
||||||
Sleep 3s
|
|
Loading…
Reference in New Issue
Block a user