Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rewrite the library: simpler design and implementation, unit tests #26

Merged
merged 19 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 64 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,64 @@
# nu-git-manager
A collection of Nushell tools to manage `git` repositories.

## :bulb: what is `nu-git-manager`
# Table of content
- [*what is `nu-git-manager`*](#bulb-what-is-nu-git-manager-toc)
- [*requirements*](#link-requirements-toc)
- [*installation*](#recycle-installation-toc)
- [*usage*](#gear-usage-toc)
- [*getting help*](#pray-getting-help-toc)
- [*some ideas of advanced (?) usage*](#exclamation-some-ideas-of-advanced--usage-toc)

## :bulb: what is `nu-git-manager` [[toc](#table-of-content)]
like [`ghq`](https://github.com/x-motemen/ghq), `nu-git-manager` aims at being a fully-featured
repository manager, purely written in Nushell.

the public API of `nu-git-manager` is greatly inspired by `ghq` for now but this might very likely change
in the future!

regarding versions, as `nu-git-manager` is tied to the version of the main `nushell/nushell` repo,
its versioning cycle will be the same
- a new minor release every 3 weeks
- starting may 2023 tuesday the 16th

more information can be found in the [documentation](docs/)!
it provides two main modules:
- `nu-git-manager` itself which ships the main `gm` command
- `nu-git-manager sugar` which exports a bunch of Git-related tools, e.g. to help use the `gh` command or augment the capabilities of `git`

## :link: requirements
- Nushell 0.80.1+
- `git` 2.40.1
## :link: requirements [[toc](#table-of-content)]
- [Nushell] 0.85.1+
- with Cargo and `cargo install nu`
- `git` 2.34.1
- with Pacman and `pacman -S extra/git`
- with Nix and `nix run nixpkgs#git`
- `gh` (optional) 2.29.0 (used by `sugar gh`)
- with Pacman and `pacman -S community/github-cli`
- with Nix and `nix run nixpkgs#gh`
- `find` 4.9.0
- with Pacman and `pacman -S core/findutils`
- with Nix and `nix run nixpkgs#findutils`

## :recycle: installation [here](docs/installation/)
## :recycle: installation [[toc](#table-of-content)]
- install [Nupm] (**recommended**) by following the [Nupm instructions]
- download the `nu-git-manager` repository
```shell
git clone https://github.com/amtoine/nu-git-manager
```
- activate the `nupm` module with `use nupm`
- install the `nu-git-manager` package
```nushell
nupm install --path --force nu-git-manager
```

## :gear: usage
## :gear: usage [[toc](#table-of-content)]
in your `config.nu` you can add the following to load `nu-git-manager` modules:
```nu
# config.nu

# load the main `gm` module
use nu-git-manager gm
# load the main `gm` command
use nu-git-manager [gm, "gm clone", "gm list", "gm root", "gm remove"]

# the following are non-essential modules
use nu-git-manager sugar git # load `git` tool extensions
use nu-git-manager sugar git # augmnet Git with custom commands
use nu-git-manager sugar gh # load commands to interact with *GitHub*
use nu-git-manager sugar gist # load commands to interact with *GitHub* gists
use nu-git-manager sugar completions git * # load some `git` completion
use nu-git-manager sugar dotfiles # load tools to manage versionned dotfiles
```

then you have access to the whole `nu-git-manager` suite :partying_face:

### :pray: getting help
### :pray: getting help [[toc](#table-of-content)]
do not hesitate to run one of the following to have more information about what `nu-git-manager` has to offer :thumbsup:
```nu
help gm
Expand All @@ -59,42 +77,32 @@ help modules gist
gist
```

## :exclamation: some ideas of advanced (?) usage
one thing i like to do in my config to go ***BLAZZINGLY FAST*** is to use keybindings to call some `nu-git-manager` commands
in one key stroke :smirk:
## :exclamation: some ideas of advanced (?) usage [[toc](#table-of-content)]
everytime i open a terminal, i use [Tmux] to manage sessions, switch between them, detach and reattach, quite a ***BLAZZINGLY FAST*** workflow for my taste :smirk:

- with `gm` activated, i can jump to any repo from anywhere with `<c-g>`
```nu
{
name: open_repo
modifier: control
keycode: char_g
mode: [emacs, vi_insert, vi_normal]
event: {
send: executehostcommand
cmd: "gm goto"
}
}
```
- with `sugar dotfiles` activated, i can edit any configuration file from anywhere with `<c-v>`
```nu
{
name: edit_config
modifier: control
keycode: char_v
mode: [emacs, vi_insert, vi_normal]
event: {
send: executehostcommand
cmd: "dotfiles edit"
}
}
to achieve this, i use the [`tmux-sessionizer.nu` script][`tmux-sessionizer.nu`] from the [`nu-goat-scripts` package][`nu-goat-scripts`], again installed with [Nupm] :ok_hand:

then, in my Tmux config, i have a binding to
1. list all my Git repositories
2. fuzzy-pick one of them with the [`main` command of `tmux-sessionizer.nu`][`tmux-sessionizer.nu`]
3. create or reattach to the session associated with the repository
```bash
# ~/.config/tmux/tmux.conf

NUPM_HOME="~/.local/share/nupm"
TMUX_SESSIONIZER="$NUPM_HOME/scripts/tmux-sessionizer.nu"

bind-key -r t display-popup -E "nu --commands '
use $NUPM_HOME/modules/nu-git-manager *;\
$TMUX_SESSIONIZER (gm list --full-path) --short\
'"
```

## :calendar: the roadmap of `nu-git-manager`
- [ ] complete the main `gm` commands
- [ ] support more hosts, e.g. *GitLab*
- [ ] add more external completions, namely for `git` and `gh`, maybe `glab`
[Nushell]: https://github.com/nushell/nushell

[Nupm]: https://github.com/nushell/nupm
[Nupm instructions]: https://github.com/nushell/nupm#-installation

[nushell/nushell#9066]: https://github.com/nushell/nushell/pull/9066
[`a2a346e39`]: https://github.com/nushell/nushell/commit/a2a346e39c53e386b97d8d7f9a05ed58298e8789
[#21]: https://github.com/amtoine/nu-git-manager/pull/21
[Tmux]: https://github.com/tmux/tmux
[`tmux-sessionizer.nu`]: https://github.com/goatfiles/scripts/blob/main/nu_scripts/scripts/tmux-sessionizer.nu#L463
[`nu-goat-scripts`]: https://github.com/goatfiles/scripts/blob/main/nu_scripts/README.md#nu_scripts
3 changes: 0 additions & 3 deletions docs/README.md

This file was deleted.

7 changes: 0 additions & 7 deletions docs/installation/README.md

This file was deleted.

22 changes: 0 additions & 22 deletions docs/installation/manual.md

This file was deleted.

16 changes: 0 additions & 16 deletions docs/installation/nupm.md

This file was deleted.

10 changes: 10 additions & 0 deletions nu-git-manager/fs/dir.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Cross platform wrapper to open a directory, a file or a URL in the default application
export def open-item [file: path]: nothing -> nothing {
let cmd = match $nu.os-info.name {
"windows" => "explorer",
"macos" => "open",
"linux" => "xdg-open"
}

^$cmd $file
}
4 changes: 4 additions & 0 deletions nu-git-manager/fs/path.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# sanitize a Windows path
export def "path sanitize" []: path -> path {
str replace --all '\' '/'
}
22 changes: 22 additions & 0 deletions nu-git-manager/fs/store.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use path.nu "path sanitize"

export def get-repo-store-path []: nothing -> path {
$env.GIT_REPOS_HOME? | default (
$env.XDG_DATA_HOME? | default ($nu.home-path | path join ".local/share") | path join "repos"
) | path expand | path sanitize
}

export def list-repos-in-store []: nothing -> list<path> {
if not (get-repo-store-path | path exists) {
return []
}

if $nu.os-info.name == "windows" {
# FIXME: this is super slow on windows
glob **/*.git --not [**/*.venv **/node_modules/** **/target/** **/build/** */]
} else {
# FIXME: do not use external `find` command
^find (get-repo-store-path) -name ".git"
| lines
} | each { path split | range 0..(-2) | path join }
}
66 changes: 66 additions & 0 deletions nu-git-manager/git/url.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use ../fs/path.nu "path sanitize"

export def parse-git-url []: string -> record<host: string, owner: string, group: path, repo: string> {
str replace --regex '^git@(.*):' 'ssh://$1/'
| str replace --regex '\.git$' ''
| url parse
| select host path
| update path {
str trim --left --right --char '/'
| str replace --regex '\/tree\/.*' ''
| path split
| {
owner: ($in | first),
group: ($in | range 1..(-2) | if $in != null { path join | path sanitize }),
repo: ($in | last)
}
}
| flatten
| into record
}

export def get-fetch-push-urls [
repository: record<host: string, owner: string, group: path, repo: string>, # typically from `parse-git-url`
fetch: string, # one of 'https', 'ssh', or empty
push: string, # one of 'https', 'ssh', or empty
ssh: bool,
]: nothing -> record<fetch: string, push: string> {
let base_url = {
scheme: null,
host: $repository.host,
path: (
[$repository.owner $repository.group $repository.repo]
| compact
| path join
| path sanitize
)
}
let http_url = $base_url | update scheme "https" | url join
let ssh_url = $base_url | update scheme "ssh" | url join

let fetch_url = match $fetch {
"https" => $http_url,
"ssh" => $ssh_url,
_ => {
if $ssh {
$ssh_url
} else {
$http_url
}
},
}

let push_url = match $push {
"https" => $http_url,
"ssh" => $ssh_url,
_ => {
if $ssh {
$ssh_url
} else {
$http_url
}
},
}

{fetch: $fetch_url, push: $push_url}
}
Loading