Compare commits
23 Commits
21e3a9b9bb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| b9051d5afb | |||
| 6c6295651f | |||
| 8c418ff846 | |||
| 29b3bd3581 | |||
|
|
012c6efb03 | ||
| 241bf473a7 | |||
| 8fd663462e | |||
| 4beacbf65d | |||
| 102f5561a8 | |||
| e04f065d42 | |||
| 941dd50868 | |||
| d20dabc91e | |||
| 0e63a1c6bf | |||
| 9792c09850 | |||
| a1519a6bc5 | |||
| 36535dcaec | |||
| 32f94b1ef5 | |||
| 913df16f28 | |||
| f66a512a83 | |||
| de15e799ac | |||
| a8736ed37f | |||
| 1a45887fb6 | |||
| 9403156edf |
603
Cargo.lock
generated
603
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
22
Cargo.toml
22
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "git-repo-manager"
|
||||
version = "0.7.13"
|
||||
version = "0.7.15"
|
||||
edition = "2021"
|
||||
|
||||
authors = [
|
||||
@@ -23,7 +23,7 @@ repository = "https://github.com/hakoerber/git-repo-manager"
|
||||
readme = "README.md"
|
||||
|
||||
# Required for `std::path::Path::is_symlink()`. Will be released with 1.57.
|
||||
rust-version = "1.57"
|
||||
rust-version = "1.58"
|
||||
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
@@ -41,36 +41,36 @@ path = "src/grm/main.rs"
|
||||
[dependencies]
|
||||
|
||||
[dependencies.toml]
|
||||
version = "=0.7.3"
|
||||
version = "=0.8.6"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "=1.0.162"
|
||||
version = "=1.0.190"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.git2]
|
||||
version = "=0.17.1"
|
||||
version = "=0.18.1"
|
||||
|
||||
[dependencies.shellexpand]
|
||||
version = "=3.1.0"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "=4.2.7"
|
||||
version = "=4.4.7"
|
||||
features = ["derive", "cargo"]
|
||||
|
||||
[dependencies.console]
|
||||
version = "=0.15.5"
|
||||
version = "=0.15.7"
|
||||
|
||||
[dependencies.regex]
|
||||
version = "=1.8.1"
|
||||
version = "=1.10.2"
|
||||
|
||||
[dependencies.comfy-table]
|
||||
version = "=6.1.4"
|
||||
version = "=7.1.0"
|
||||
|
||||
[dependencies.serde_yaml]
|
||||
version = "=0.9.21"
|
||||
version = "=0.9.27"
|
||||
|
||||
[dependencies.serde_json]
|
||||
version = "=1.0.96"
|
||||
version = "=1.0.108"
|
||||
|
||||
[dependencies.isahc]
|
||||
version = "=1.7.2"
|
||||
|
||||
10
Justfile
10
Justfile
@@ -4,7 +4,7 @@ set shell := ["/bin/bash", "-c"]
|
||||
|
||||
static_target := "x86_64-unknown-linux-musl"
|
||||
|
||||
cargo := "cargo +nightly"
|
||||
cargo := "cargo"
|
||||
|
||||
check: fmt-check lint test
|
||||
{{cargo}} check
|
||||
@@ -76,14 +76,14 @@ test-integration:
|
||||
|
||||
test-e2e +tests=".": test-binary
|
||||
cd ./e2e_tests \
|
||||
&& docker-compose rm --stop -f \
|
||||
&& docker-compose build \
|
||||
&& docker-compose run \
|
||||
&& docker compose rm --stop -f \
|
||||
&& docker compose build \
|
||||
&& docker compose run \
|
||||
--rm \
|
||||
-v $PWD/../target/x86_64-unknown-linux-musl/e2e-tests/grm:/grm \
|
||||
pytest \
|
||||
"GRM_BINARY=/grm ALTERNATE_DOMAIN=alternate-rest python3 -m pytest --exitfirst -p no:cacheprovider --color=yes "$@"" \
|
||||
&& docker-compose rm --stop -f
|
||||
&& docker compose rm --stop -f
|
||||
|
||||
update-dependencies: update-cargo-dependencies
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ in once place?
|
||||
|
||||
This is how GRM came to be. I'm a fan of infrastructure-as-code, and GRM is a bit
|
||||
like Terraform for your local git repositories. Write a config, run the tool, and
|
||||
your repos are ready. The only thing that is tracked by git it the list of
|
||||
your repos are ready. The only thing that is tracked by git is the list of
|
||||
repositories itself.
|
||||
|
||||
# Crates
|
||||
|
||||
@@ -93,15 +93,7 @@ for tier in ["dependencies", "dev-dependencies"]:
|
||||
|
||||
try:
|
||||
cmd = subprocess.run(
|
||||
[
|
||||
"cargo",
|
||||
"update",
|
||||
"-Z",
|
||||
"no-index-update",
|
||||
"--aggressive",
|
||||
"--package",
|
||||
name,
|
||||
],
|
||||
["cargo", "update", "--offline", "--aggressive", "--package", name],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
@@ -135,15 +127,7 @@ while True:
|
||||
spec = f"{package['name']}:{package['version']}"
|
||||
try:
|
||||
cmd = subprocess.run(
|
||||
[
|
||||
"cargo",
|
||||
"update",
|
||||
"-Z",
|
||||
"no-index-update",
|
||||
"--aggressive",
|
||||
"--package",
|
||||
spec,
|
||||
],
|
||||
["cargo", "update", "--offline", "--aggressive", "--package", spec],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
|
||||
@@ -28,7 +28,7 @@ Feature branches are not required, there are also changes happening directly on
|
||||
|
||||
You will need the following tools:
|
||||
|
||||
* Rust (obviously) (easiest via `rustup`), with the nightly toolchain
|
||||
* Rust (obviously) (easiest via `rustup`)
|
||||
* Python3
|
||||
* [`just`](https://github.com/casey/just), a command runner like `make`. See
|
||||
[here](https://github.com/casey/just#installation) for installation
|
||||
@@ -52,18 +52,3 @@ mvdan.cc/sh/v3/cmd/shfmt@latest`, depending on your go build environment.
|
||||
|
||||
For details about rustup and the toolchains, see [the installation
|
||||
section](./installation.md).
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why nightly?
|
||||
|
||||
For now, GRM requires the nightly toolchain for two reasons:
|
||||
|
||||
* [`io_error_more`](https://github.com/rust-lang/rust/issues/86442) to get
|
||||
better error messages on IO errors
|
||||
* [`const_option_ext`](https://github.com/rust-lang/rust/issues/91930) to have
|
||||
static variables read from the environment that fall back to hard coded
|
||||
defaults
|
||||
|
||||
Honestly, both of those are not really necessary or can be handled without
|
||||
nightly. It's just that I'm using nightly anyway.
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Building GRM currently requires the nightly Rust toolchain. The easiest way is
|
||||
Building GRM requires the Rust toolchain to be installed. The easiest way is
|
||||
using [`rustup`](https://rustup.rs/). Make sure that rustup is properly
|
||||
installed.
|
||||
|
||||
Make sure that the nightly toolchain is installed:
|
||||
Make sure that the stable toolchain is installed:
|
||||
|
||||
```
|
||||
$ rustup toolchain install nightly
|
||||
$ rustup toolchain install stable
|
||||
```
|
||||
|
||||
Then, install the build dependencies:
|
||||
@@ -22,13 +22,13 @@ Then, install the build dependencies:
|
||||
Then, it's a simple command to install the latest stable version:
|
||||
|
||||
```bash
|
||||
$ cargo +nightly install git-repo-manager
|
||||
$ cargo install git-repo-manager
|
||||
```
|
||||
|
||||
If you're brave, you can also run the development build:
|
||||
|
||||
```bash
|
||||
$ cargo +nightly install --git https://github.com/hakoerber/git-repo-manager.git --branch develop
|
||||
$ cargo install --git https://github.com/hakoerber/git-repo-manager.git --branch develop
|
||||
```
|
||||
|
||||
## Static build
|
||||
@@ -47,11 +47,11 @@ need `musl` and a few other build dependencies installed installed:
|
||||
The, add the musl target via `rustup`:
|
||||
|
||||
```
|
||||
$ rustup +nightly target add x86_64-unknown-linux-musl
|
||||
$ rustup target add x86_64-unknown-linux-musl
|
||||
```
|
||||
|
||||
Then, use a modified build command to get a statically linked binary:
|
||||
|
||||
```
|
||||
$ cargo +nightly install git-repo-manager --target x86_64-unknown-linux-musl --features=static-build
|
||||
$ cargo install git-repo-manager --target x86_64-unknown-linux-musl --features=static-build
|
||||
```
|
||||
|
||||
@@ -163,7 +163,6 @@ def test_repos_find(configtype, exclude, default_format):
|
||||
@pytest.mark.parametrize("configtype", ["toml", "yaml"])
|
||||
def test_repos_find_in_root(configtype, default_format):
|
||||
with TempGitRepository() as repo_dir:
|
||||
|
||||
args = ["repos", "find", "local", repo_dir]
|
||||
if not default_format:
|
||||
args += ["--format", configtype]
|
||||
|
||||
@@ -43,7 +43,9 @@ def test_repos_find_remote_invalid_provider(use_config):
|
||||
assert cmd.returncode != 0
|
||||
assert len(cmd.stdout) == 0
|
||||
if not use_config:
|
||||
assert re.match(".*invalid value 'thisproviderdoesnotexist' for.*provider", cmd.stderr)
|
||||
assert re.match(
|
||||
".*invalid value 'thisproviderdoesnotexist' for.*provider", cmd.stderr
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("provider", PROVIDERS)
|
||||
|
||||
@@ -312,7 +312,7 @@ def test_repos_sync_root_is_file(configtype):
|
||||
|
||||
cmd = grm(["repos", "sync", "config", "--config", config.name])
|
||||
assert cmd.returncode != 0
|
||||
assert "not a directory" in cmd.stderr.lower()
|
||||
assert "notadirectory" in cmd.stderr.lower()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("configtype", ["toml", "yaml"])
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "stable"
|
||||
targets = ["x86_64-unknown-linux-musl"]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#![feature(io_error_more)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
@@ -313,7 +313,7 @@ pub trait Provider {
|
||||
// about the data exchange format here.
|
||||
repo.remove_namespace();
|
||||
|
||||
ret.entry(namespace).or_insert(vec![]).push(repo);
|
||||
ret.entry(namespace).or_default().push(repo);
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
|
||||
17
src/table.rs
17
src/table.rs
@@ -4,6 +4,7 @@ use super::repo;
|
||||
|
||||
use comfy_table::{Cell, Table};
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::path::Path;
|
||||
|
||||
fn add_table_header(table: &mut Table) {
|
||||
@@ -56,9 +57,10 @@ fn add_repo_status(
|
||||
repo_status
|
||||
.branches
|
||||
.iter()
|
||||
.map(|(branch_name, remote_branch)| {
|
||||
format!(
|
||||
"branch: {}{}\n",
|
||||
.fold(String::new(), |mut s, (branch_name, remote_branch)| {
|
||||
writeln!(
|
||||
&mut s,
|
||||
"branch: {}{}",
|
||||
&branch_name,
|
||||
&match remote_branch {
|
||||
None => String::from(" <!local>"),
|
||||
@@ -78,8 +80,9 @@ fn add_repo_status(
|
||||
}
|
||||
}
|
||||
)
|
||||
.unwrap();
|
||||
s
|
||||
})
|
||||
.collect::<String>()
|
||||
.trim(),
|
||||
&match is_worktree {
|
||||
true => String::from(""),
|
||||
@@ -91,8 +94,10 @@ fn add_repo_status(
|
||||
repo_status
|
||||
.remotes
|
||||
.iter()
|
||||
.map(|r| format!("{}\n", r))
|
||||
.collect::<String>()
|
||||
.fold(String::new(), |mut s, r| {
|
||||
writeln!(&mut s, "{r}").unwrap();
|
||||
s
|
||||
})
|
||||
.trim(),
|
||||
]);
|
||||
|
||||
|
||||
@@ -128,8 +128,6 @@ pub fn find_repo_paths(path: &Path) -> Result<Vec<PathBuf>, String> {
|
||||
"Failed to open \"{}\": {}",
|
||||
&path.display(),
|
||||
match e.kind() {
|
||||
std::io::ErrorKind::NotADirectory =>
|
||||
String::from("directory expected, but path is not a directory"),
|
||||
std::io::ErrorKind::NotFound => String::from("not found"),
|
||||
_ => format!("{:?}", e.kind()),
|
||||
}
|
||||
@@ -181,7 +179,7 @@ fn sync_repo(root_path: &Path, repo: &repo::Repo, init_worktree: bool) -> Result
|
||||
"Repo already exists, but is not using a worktree setup",
|
||||
));
|
||||
};
|
||||
} else if matches!(&repo.remotes, None) || repo.remotes.as_ref().unwrap().is_empty() {
|
||||
} else if repo.remotes.is_none() || repo.remotes.as_ref().unwrap().is_empty() {
|
||||
print_repo_action(
|
||||
&repo.name,
|
||||
"Repository does not have remotes configured, initializing new",
|
||||
|
||||
Reference in New Issue
Block a user