Add YAML as a config format option

@mustafa89 ;)
This commit is contained in:
2022-01-14 17:27:04 +01:00
parent e45de3b498
commit 9b64de7991
10 changed files with 394 additions and 295 deletions

34
Cargo.lock generated
View File

@@ -195,6 +195,7 @@ dependencies = [
"git2", "git2",
"regex", "regex",
"serde", "serde",
"serde_yaml",
"shellexpand", "shellexpand",
"tempdir", "tempdir",
"toml", "toml",
@@ -336,6 +337,12 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.5" version = "0.4.5"
@@ -592,6 +599,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "ryu"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@@ -618,6 +631,18 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "serde_yaml"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0"
dependencies = [
"indexmap",
"ryu",
"serde",
"yaml-rust",
]
[[package]] [[package]]
name = "shellexpand" name = "shellexpand"
version = "2.1.0" version = "2.1.0"
@@ -850,3 +875,12 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

View File

@@ -62,5 +62,8 @@ version = "=1.5.4"
[dependencies.comfy-table] [dependencies.comfy-table]
version = "=5.0.0" version = "=5.0.0"
[dependencies.serde_yaml]
version = "=0.8.23"
[dev-dependencies.tempdir] [dev-dependencies.tempdir]
version = "=0.3.7" version = "=0.3.7"

View File

@@ -5,7 +5,8 @@ Manager](https://github.com/hakoerber/git-repo-manager/) (GRM for short), a
tool that helps you manage git repositories. tool that helps you manage git repositories.
GRM helps you manage git repositories in a declarative way. Configure your GRM helps you manage git repositories in a declarative way. Configure your
repositories in a TOML file, GRM does the rest. Take a look at [the example repositories in a TOML or YAML file, GRM does the rest. Take a look at [the
example
configuration](https://github.com/hakoerber/git-repo-manager/blob/master/example.config.toml) configuration](https://github.com/hakoerber/git-repo-manager/blob/master/example.config.toml)
to get a feel for the way you configure your repositories. See the [repository to get a feel for the way you configure your repositories. See the [repository
tree chapter](./repos.md) for details. tree chapter](./repos.md) for details.

View File

@@ -74,3 +74,9 @@ $ grm repos status
╰──────────┴──────────┴────────┴──────────┴───────┴─────────╯ ╰──────────┴──────────┴────────┴──────────┴───────┴─────────╯
``` ```
## YAML
By default, the repo configuration uses TOML. If you prefer YAML, just give it
a YAML file instead (file ending does not matter, `grm` will figure out the format
itself). For generating a configuration, pass `--format yaml` to `grm repo find`
to generate YAML instead of TOML.

View File

@@ -3,6 +3,8 @@
import tempfile import tempfile
import toml import toml
import pytest
import yaml
from helpers import * from helpers import *
@@ -30,6 +32,16 @@ def test_repos_find_empty():
assert len(cmd.stderr) != 0 assert len(cmd.stderr) != 0
def test_repos_find_invalid_format():
with tempfile.TemporaryDirectory() as tmpdir:
cmd = grm(
["repos", "find", tmpdir, "--format", "invalidformat"], is_invalid=True
)
assert cmd.returncode != 0
assert len(cmd.stdout) == 0
assert "isn't a valid value" in cmd.stderr
def test_repos_find_non_git_repos(): def test_repos_find_non_git_repos():
with tempfile.TemporaryDirectory() as tmpdir: with tempfile.TemporaryDirectory() as tmpdir:
shell( shell(
@@ -50,7 +62,9 @@ def test_repos_find_non_git_repos():
assert len(cmd.stderr) != 0 assert len(cmd.stderr) != 0
def test_repos_find(): @pytest.mark.parametrize("default", [True, False])
@pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_find(configtype, default):
with tempfile.TemporaryDirectory() as tmpdir: with tempfile.TemporaryDirectory() as tmpdir:
shell( shell(
f""" f"""
@@ -83,11 +97,19 @@ def test_repos_find():
""" """
) )
cmd = grm(["repos", "find", tmpdir]) args = ["repos", "find", tmpdir]
if not default:
args += ["--format", configtype]
cmd = grm(args)
assert cmd.returncode == 0 assert cmd.returncode == 0
assert len(cmd.stderr) == 0 assert len(cmd.stderr) == 0
output = toml.loads(cmd.stdout) if default or configtype == "toml":
output = toml.loads(cmd.stdout)
elif configtype == "yaml":
output = yaml.safe_load(cmd.stdout)
else:
raise NotImplementedError()
assert isinstance(output, dict) assert isinstance(output, dict)
assert set(output.keys()) == {"trees"} assert set(output.keys()) == {"trees"}
@@ -125,14 +147,24 @@ def test_repos_find():
assert origin["url"] == "https://example.com/repo2.git" assert origin["url"] == "https://example.com/repo2.git"
def test_repos_find_in_root(): @pytest.mark.parametrize("default", [True, False])
@pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_find_in_root(configtype, default):
with TempGitRepository() as repo_dir: with TempGitRepository() as repo_dir:
cmd = grm(["repos", "find", repo_dir]) args = ["repos", "find", repo_dir]
if not default:
args += ["--format", configtype]
cmd = grm(args)
assert cmd.returncode == 0 assert cmd.returncode == 0
assert len(cmd.stderr) == 0 assert len(cmd.stderr) == 0
output = toml.loads(cmd.stdout) if default or configtype == "toml":
output = toml.loads(cmd.stdout)
elif configtype == "yaml":
output = yaml.safe_load(cmd.stdout)
else:
raise NotImplementedError()
assert isinstance(output, dict) assert isinstance(output, dict)
assert set(output.keys()) == {"trees"} assert set(output.keys()) == {"trees"}
@@ -160,7 +192,9 @@ def test_repos_find_in_root():
assert someremote["type"] == "file" assert someremote["type"] == "file"
def test_repos_find_with_invalid_repo(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
@pytest.mark.parametrize("default", [True, False])
def test_repos_find_with_invalid_repo(configtype, default):
with tempfile.TemporaryDirectory() as tmpdir: with tempfile.TemporaryDirectory() as tmpdir:
shell( shell(
f""" f"""
@@ -193,11 +227,19 @@ def test_repos_find_with_invalid_repo():
""" """
) )
cmd = grm(["repos", "find", tmpdir]) args = ["repos", "find", tmpdir]
if not default:
args += ["--format", configtype]
cmd = grm(args)
assert cmd.returncode == 0 assert cmd.returncode == 0
assert "broken" in cmd.stderr assert "broken" in cmd.stderr
output = toml.loads(cmd.stdout) if default or configtype == "toml":
output = toml.loads(cmd.stdout)
elif configtype == "yaml":
output = yaml.safe_load(cmd.stdout)
else:
raise NotImplementedError()
assert isinstance(output, dict) assert isinstance(output, dict)
assert set(output.keys()) == {"trees"} assert set(output.keys()) == {"trees"}

View File

@@ -2,6 +2,7 @@
import tempfile import tempfile
import re import re
import textwrap
import pytest import pytest
import toml import toml
@@ -9,8 +10,134 @@ import git
from helpers import * from helpers import *
templates = {
"repo_simple": {
"toml": """
[[trees]]
root = "{root}"
def test_repos_sync_config_is_valid_symlink(): [[trees.repos]]
name = "test"
""",
"yaml": """
trees:
- root: "{root}"
repos:
- name: "test"
""",
},
"repo_with_remote": {
"toml": """
[[trees]]
root = "{root}"
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "{remotename}"
url = "file://{remote}"
type = "file"
""",
"yaml": textwrap.dedent(
"""
trees:
- root: "{root}"
repos:
- name: test
remotes:
- name: "{remotename}"
url: "file://{remote}"
type: "file"
"""
),
},
"repo_with_two_remotes": {
"toml": """
[[trees]]
root = "{root}"
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
[[trees.repos.remotes]]
name = "origin2"
url = "file://{remote2}"
type = "file"
""",
"yaml": textwrap.dedent(
"""
trees:
- root: "{root}"
repos:
- name: "test"
remotes:
- name: "origin"
url: "file://{remote1}"
type: "file"
- name: "origin2"
url: "file://{remote2}"
type: "file"
"""
),
},
"worktree_repo_simple": {
"toml": """
[[trees]]
root = "{root}"
[[trees.repos]]
name = "test"
worktree_setup = true
""",
"yaml": textwrap.dedent(
"""
trees:
- root: "{root}"
repos:
- name: test
worktree_setup: true
"""
),
},
"worktree_repo_with_remote": {
"toml": """
[[trees]]
root = "{root}"
[[trees.repos]]
name = "test"
worktree_setup = true
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote}"
type = "file"
""",
"yaml": textwrap.dedent(
"""
trees:
- root: "{root}"
repos:
- name: test
worktree_setup: true
remotes:
- name: origin
url: "file://{remote}"
type: "file"
"""
),
},
}
@pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_config_is_valid_symlink(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with TempGitFileRemote() as (remote, head_commit_sha): with TempGitFileRemote() as (remote, head_commit_sha):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
@@ -20,20 +147,13 @@ def test_repos_sync_config_is_valid_symlink():
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote, remotename="origin"
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote}"
type = "file"
"""
) )
subprocess.run(["cat", config.name])
cmd = grm(["repos", "sync", "--config", config_symlink]) cmd = grm(["repos", "sync", "--config", config_symlink])
assert cmd.returncode == 0 assert cmd.returncode == 0
@@ -85,20 +205,13 @@ def test_repos_sync_config_is_unreadable():
assert "permission denied" in cmd.stderr.lower() assert "permission denied" in cmd.stderr.lower()
def test_repos_sync_unmanaged_repos(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_unmanaged_repos(configtype):
with tempfile.TemporaryDirectory() as root: with tempfile.TemporaryDirectory() as root:
with TempGitRepository(dir=root) as unmanaged_repo: with TempGitRepository(dir=root) as unmanaged_repo:
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(templates["repo_simple"][configtype].format(root=root))
f"""
[[trees]]
root = "{root}"
[[trees.repos]]
name = "test"
"""
)
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
assert cmd.returncode == 0 assert cmd.returncode == 0
@@ -112,19 +225,12 @@ def test_repos_sync_unmanaged_repos():
assert any([re.match(regex, l) for l in cmd.stderr.lower().split("\n")]) assert any([re.match(regex, l) for l in cmd.stderr.lower().split("\n")])
def test_repos_sync_root_is_file(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_root_is_file(configtype):
with tempfile.NamedTemporaryFile() as target: with tempfile.NamedTemporaryFile() as target:
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(templates["repo_simple"][configtype].format(root=target.name))
f"""
[[trees]]
root = "{target.name}"
[[trees.repos]]
name = "test"
"""
)
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
assert cmd.returncode != 0 assert cmd.returncode != 0
@@ -132,30 +238,17 @@ def test_repos_sync_root_is_file():
assert "not a directory" in cmd.stderr.lower() assert "not a directory" in cmd.stderr.lower()
def test_repos_sync_normal_clone(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_normal_clone(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with TempGitFileRemote() as (remote1, remote1_head_commit_sha): with TempGitFileRemote() as (remote1, remote1_head_commit_sha):
with TempGitFileRemote() as (remote2, remote2_head_commit_sha): with TempGitFileRemote() as (remote2, remote2_head_commit_sha):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_two_remotes"][configtype].format(
[[trees]] root=target, remote1=remote1, remote2=remote2
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
[[trees.repos.remotes]]
name = "origin2"
url = "file://{remote2}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -183,19 +276,12 @@ def test_repos_sync_normal_clone():
assert urls[0] == f"file://{remote2}" assert urls[0] == f"file://{remote2}"
def test_repos_sync_normal_init(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_normal_init(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(templates["repo_simple"][configtype].format(root=target))
f"""
[[trees]]
root = "{target}"
[[trees.repos]]
name = "test"
"""
)
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
assert cmd.returncode == 0 assert cmd.returncode == 0
@@ -210,25 +296,17 @@ def test_repos_sync_normal_init():
assert not repo.head.is_valid() assert not repo.head.is_valid()
def test_repos_sync_normal_add_remote(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_normal_add_remote(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with TempGitFileRemote() as (remote1, remote1_head_commit_sha): with TempGitFileRemote() as (remote1, remote1_head_commit_sha):
with TempGitFileRemote() as (remote2, remote2_head_commit_sha): with TempGitFileRemote() as (remote2, remote2_head_commit_sha):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote1, remotename="origin"
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -246,23 +324,9 @@ def test_repos_sync_normal_add_remote():
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_two_remotes"][configtype].format(
[[trees]] root=target, remote1=remote1, remote2=remote2
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
[[trees.repos.remotes]]
name = "origin2"
url = "file://{remote2}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -282,30 +346,17 @@ def test_repos_sync_normal_add_remote():
assert urls[0] == f"file://{remote2}" assert urls[0] == f"file://{remote2}"
def test_repos_sync_normal_remove_remote(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_normal_remove_remote(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with TempGitFileRemote() as (remote1, remote1_head_commit_sha): with TempGitFileRemote() as (remote1, remote1_head_commit_sha):
with TempGitFileRemote() as (remote2, remote2_head_commit_sha): with TempGitFileRemote() as (remote2, remote2_head_commit_sha):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_two_remotes"][configtype].format(
[[trees]] root=target, remote1=remote1, remote2=remote2
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
[[trees.repos.remotes]]
name = "origin2"
url = "file://{remote2}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -326,18 +377,9 @@ def test_repos_sync_normal_remove_remote():
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote2, remotename="origin2"
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin2"
url = "file://{remote2}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -369,25 +411,17 @@ def test_repos_sync_normal_remove_remote():
assert urls[0] == f"file://{remote2}" assert urls[0] == f"file://{remote2}"
def test_repos_sync_normal_change_remote_url(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_normal_change_remote_url(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with TempGitFileRemote() as (remote1, remote1_head_commit_sha): with TempGitFileRemote() as (remote1, remote1_head_commit_sha):
with TempGitFileRemote() as (remote2, remote2_head_commit_sha): with TempGitFileRemote() as (remote2, remote2_head_commit_sha):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote1, remotename="origin"
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -405,18 +439,9 @@ def test_repos_sync_normal_change_remote_url():
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote2, remotename="origin"
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote2}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -429,25 +454,17 @@ def test_repos_sync_normal_change_remote_url():
assert urls[0] == f"file://{remote2}" assert urls[0] == f"file://{remote2}"
def test_repos_sync_normal_change_remote_name(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_normal_change_remote_name(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with TempGitFileRemote() as (remote1, remote1_head_commit_sha): with TempGitFileRemote() as (remote1, remote1_head_commit_sha):
with TempGitFileRemote() as (remote2, remote2_head_commit_sha): with TempGitFileRemote() as (remote2, remote2_head_commit_sha):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote1, remotename="origin"
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -465,18 +482,9 @@ def test_repos_sync_normal_change_remote_name():
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote1, remotename="origin2"
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin2"
url = "file://{remote1}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -492,25 +500,16 @@ def test_repos_sync_normal_change_remote_name():
assert urls[0] == f"file://{remote1}" assert urls[0] == f"file://{remote1}"
def test_repos_sync_worktree_clone(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_worktree_clone(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with TempGitFileRemote() as (remote, head_commit_sha): with TempGitFileRemote() as (remote, head_commit_sha):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["worktree_repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote, remotename="origin"
root = "{target}" )
[[trees.repos]]
name = "test"
worktree_setup = true
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -530,19 +529,13 @@ def test_repos_sync_worktree_clone():
assert str(repo.head.commit) == head_commit_sha assert str(repo.head.commit) == head_commit_sha
def test_repos_sync_worktree_init(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_worktree_init(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["worktree_repo_simple"][configtype].format(root=target)
[[trees]]
root = "{target}"
[[trees.repos]]
name = "test"
worktree_setup = true
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -559,43 +552,42 @@ def test_repos_sync_worktree_init():
assert not repo.head.is_valid() assert not repo.head.is_valid()
def test_repos_sync_invalid_toml(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_invalid_syntax(configtype):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( if configtype == "toml":
f""" f.write(
[[trees]] f"""
root = invalid as there are no quotes ;) [[trees]]
""" root = invalid as there are no quotes ;)
) """
)
elif configtype == "yaml":
f.write(
f"""
trees:
wrong:
indentation:
"""
)
else:
raise NotImplementedError()
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
assert cmd.returncode != 0 assert cmd.returncode != 0
def test_repos_sync_unchanged(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_unchanged(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with TempGitFileRemote() as (remote1, remote1_head_commit_sha): with TempGitFileRemote() as (remote1, remote1_head_commit_sha):
with TempGitFileRemote() as (remote2, remote2_head_commit_sha): with TempGitFileRemote() as (remote2, remote2_head_commit_sha):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_two_remotes"][configtype].format(
[[trees]] root=target, remote1=remote1, remote2=remote2
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
[[trees.repos.remotes]]
name = "origin2"
url = "file://{remote2}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -609,25 +601,17 @@ def test_repos_sync_unchanged():
assert before == after assert before == after
def test_repos_sync_normal_change_to_worktree(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_normal_change_to_worktree(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with TempGitFileRemote() as (remote1, remote1_head_commit_sha): with TempGitFileRemote() as (remote1, remote1_head_commit_sha):
with TempGitFileRemote() as (remote2, remote2_head_commit_sha): with TempGitFileRemote() as (remote2, remote2_head_commit_sha):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote1, remotename="origin"
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -637,19 +621,9 @@ def test_repos_sync_normal_change_to_worktree():
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["worktree_repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote1, remotename="origin"
root = "{target}" )
[[trees.repos]]
name = "test"
worktree_setup = true
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -658,26 +632,17 @@ def test_repos_sync_normal_change_to_worktree():
assert "not using a worktree setup" in cmd.stderr assert "not using a worktree setup" in cmd.stderr
def test_repos_sync_worktree_change_to_normal(): @pytest.mark.parametrize("configtype", ["toml", "yaml"])
def test_repos_sync_worktree_change_to_normal(configtype):
with tempfile.TemporaryDirectory() as target: with tempfile.TemporaryDirectory() as target:
with TempGitFileRemote() as (remote1, remote1_head_commit_sha): with TempGitFileRemote() as (remote1, remote1_head_commit_sha):
with TempGitFileRemote() as (remote2, remote2_head_commit_sha): with TempGitFileRemote() as (remote2, remote2_head_commit_sha):
with tempfile.NamedTemporaryFile() as config: with tempfile.NamedTemporaryFile() as config:
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["worktree_repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote1, remotename="origin"
root = "{target}" )
[[trees.repos]]
name = "test"
worktree_setup = true
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])
@@ -687,18 +652,9 @@ def test_repos_sync_worktree_change_to_normal():
with open(config.name, "w") as f: with open(config.name, "w") as f:
f.write( f.write(
f""" templates["repo_with_remote"][configtype].format(
[[trees]] root=target, remote=remote1, remotename="origin"
root = "{target}" )
[[trees.repos]]
name = "test"
[[trees.repos.remotes]]
name = "origin"
url = "file://{remote1}"
type = "file"
"""
) )
cmd = grm(["repos", "sync", "--config", config.name]) cmd = grm(["repos", "sync", "--config", config.name])

16
example.config.yaml Normal file
View File

@@ -0,0 +1,16 @@
trees:
- root: "~/example-projects/"
repos:
- name: "git-repo-manager"
remotes:
- name: "origin"
url: "https://code.hkoerber.de/hannes/git-repo-manager.git"
type: "https"
- name: "github"
url: "https://github.com/hakoerber/git-repo-manager.git"
type: "https"
- name: "dotfiles"
remotes:
- name: "origin"
url: "https://github.com/hakoerber/dotfiles.git"
type: "https"

View File

@@ -36,6 +36,10 @@ impl Config {
Err(error) => Err(error.to_string()), Err(error) => Err(error.to_string()),
} }
} }
pub fn as_yaml(&self) -> Result<String, String> {
serde_yaml::to_string(self).map_err(|e| e.to_string())
}
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@@ -62,12 +66,15 @@ pub fn read_config(path: &str) -> Result<Config, String> {
let config: Config = match toml::from_str(&content) { let config: Config = match toml::from_str(&content) {
Ok(c) => c, Ok(c) => c,
Err(e) => { Err(_) => match serde_yaml::from_str(&content) {
return Err(format!( Ok(c) => c,
"Error parsing configuration file \"{}\": {}", Err(e) => {
path, e return Err(format!(
)) "Error parsing configuration file \"{}\": {}",
} path, e
))
}
},
}; };
Ok(config) Ok(config)

View File

@@ -61,10 +61,25 @@ pub struct OptionalConfig {
pub config: Option<String>, pub config: Option<String>,
} }
#[derive(clap::ArgEnum, Clone)]
pub enum ConfigFormat {
Yaml,
Toml,
}
#[derive(Parser)] #[derive(Parser)]
pub struct Find { pub struct Find {
#[clap(help = "The path to search through")] #[clap(help = "The path to search through")]
pub path: String, pub path: String,
#[clap(
arg_enum,
short,
long,
help = "Format to produce",
default_value_t = ConfigFormat::Toml,
)]
pub format: ConfigFormat,
} }
#[derive(Parser)] #[derive(Parser)]

View File

@@ -119,15 +119,34 @@ fn main() {
} else { } else {
let config = trees.to_config(); let config = trees.to_config();
let toml = match config.as_toml() { match find.format {
Ok(toml) => toml, cmd::ConfigFormat::Toml => {
Err(error) => { let toml = match config.as_toml() {
print_error(&format!("Failed converting config to TOML: {}", &error)); Ok(toml) => toml,
process::exit(1); Err(error) => {
print_error(&format!(
"Failed converting config to TOML: {}",
&error
));
process::exit(1);
}
};
print!("{}", toml);
} }
}; cmd::ConfigFormat::Yaml => {
let yaml = match config.as_yaml() {
print!("{}", toml); Ok(yaml) => yaml,
Err(error) => {
print_error(&format!(
"Failed converting config to YAML: {}",
&error
));
process::exit(1);
}
};
print!("{}", yaml);
}
}
} }
for warning in warnings { for warning in warnings {
print_warning(&warning); print_warning(&warning);