mud-git 1.1.8__tar.gz → 1.1.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mud_git-1.1.9/.github/requirements-binary.txt +2 -0
- mud_git-1.1.9/.github/workflows/publish-aur.yaml +169 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/AGENTS.md +17 -6
- {mud_git-1.1.8 → mud_git-1.1.9}/PKG-INFO +14 -12
- mud_git-1.1.9/PKGBUILD +21 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/README.md +13 -11
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud/app.py +0 -1
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud/runner.py +7 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud/settings.py +12 -8
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud/utils.py +0 -1
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud_git.egg-info/PKG-INFO +14 -12
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud_git.egg-info/SOURCES.txt +2 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud_git.egg-info/scm_file_list.json +2 -0
- mud_git-1.1.9/src/mud_git.egg-info/scm_version.json +8 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/tests/helpers.py +8 -2
- {mud_git-1.1.8 → mud_git-1.1.9}/tests/test_completion.py +26 -3
- {mud_git-1.1.8 → mud_git-1.1.9}/tests/test_run.py +19 -0
- mud_git-1.1.9/tests/test_settings.py +79 -0
- mud_git-1.1.8/.github/workflows/publish-aur.yaml +0 -60
- mud_git-1.1.8/PKGBUILD +0 -37
- mud_git-1.1.8/src/mud_git.egg-info/scm_version.json +0 -8
- {mud_git-1.1.8 → mud_git-1.1.9}/.editorconfig +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/.github/workflows/publish-pypi.yaml +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/.github/workflows/test.yaml +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/.gitignore +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/LICENSE +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/img.png +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/pyproject.toml +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/requirements.txt +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/setup.cfg +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud/__init__.py +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud/__main__.py +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud/commands.py +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud/completion.py +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud/config.py +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud/styles.py +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud_git.egg-info/dependency_links.txt +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud_git.egg-info/entry_points.txt +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud_git.egg-info/requires.txt +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/src/mud_git.egg-info/top_level.txt +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/tests/conftest.py +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/tests/test_config.py +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/tests/test_display.py +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/tests/test_filters.py +0 -0
- {mud_git-1.1.8 → mud_git-1.1.9}/tests/test_states.py +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
name: Publish mud binary to AUR
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
tag:
|
|
9
|
+
description: "Published stable release tag (vX.Y.Z)"
|
|
10
|
+
required: true
|
|
11
|
+
type: string
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: publish-aur
|
|
18
|
+
cancel-in-progress: false
|
|
19
|
+
|
|
20
|
+
env:
|
|
21
|
+
RELEASE_TAG: ${{ github.event.release.tag_name || inputs.tag }}
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
build:
|
|
25
|
+
if: github.event_name == 'workflow_dispatch' || !github.event.release.prerelease
|
|
26
|
+
runs-on: ubuntu-22.04
|
|
27
|
+
outputs:
|
|
28
|
+
version: ${{ steps.release.outputs.version }}
|
|
29
|
+
steps:
|
|
30
|
+
- name: Validate release
|
|
31
|
+
id: release
|
|
32
|
+
env:
|
|
33
|
+
GH_TOKEN: ${{ github.token }}
|
|
34
|
+
run: |
|
|
35
|
+
[[ "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]
|
|
36
|
+
stable=$(gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" \
|
|
37
|
+
--json isDraft,isPrerelease --jq '(.isDraft or .isPrerelease) | not')
|
|
38
|
+
[[ "$stable" == true ]]
|
|
39
|
+
echo "version=${RELEASE_TAG#v}" >> "$GITHUB_OUTPUT"
|
|
40
|
+
|
|
41
|
+
- name: Checkout release tag
|
|
42
|
+
uses: actions/checkout@v4
|
|
43
|
+
with:
|
|
44
|
+
ref: ${{ env.RELEASE_TAG }}
|
|
45
|
+
fetch-depth: 0
|
|
46
|
+
|
|
47
|
+
- name: Set up Python 3.13
|
|
48
|
+
uses: actions/setup-python@v5
|
|
49
|
+
with:
|
|
50
|
+
python-version: "3.13"
|
|
51
|
+
|
|
52
|
+
- name: Configure git
|
|
53
|
+
run: |
|
|
54
|
+
git config --global user.name "Test User"
|
|
55
|
+
git config --global user.email "test@example.com"
|
|
56
|
+
|
|
57
|
+
- name: Install dependencies and build wheel
|
|
58
|
+
run: |
|
|
59
|
+
python -m pip install build pytest -r .github/requirements-binary.txt
|
|
60
|
+
python -m build
|
|
61
|
+
python -m pip install dist/*.whl
|
|
62
|
+
|
|
63
|
+
- name: Test wheel
|
|
64
|
+
run: python -m pytest
|
|
65
|
+
|
|
66
|
+
- name: Build standalone executable
|
|
67
|
+
run: |
|
|
68
|
+
python -m PyInstaller --noconfirm --clean --onedir --name mud \
|
|
69
|
+
--distpath dist/binary --workpath build/pyinstaller --specpath build \
|
|
70
|
+
--collect-all pygit2 --hidden-import _cffi_backend \
|
|
71
|
+
--recursive-copy-metadata mud-git src/mud/__main__.py
|
|
72
|
+
|
|
73
|
+
- name: Test standalone executable
|
|
74
|
+
env:
|
|
75
|
+
MUD_EXECUTABLE: ${{ github.workspace }}/dist/binary/mud/mud
|
|
76
|
+
run: python -m pytest
|
|
77
|
+
|
|
78
|
+
- name: Prepare release archive and PKGBUILD
|
|
79
|
+
env:
|
|
80
|
+
VERSION: ${{ steps.release.outputs.version }}
|
|
81
|
+
run: |
|
|
82
|
+
mkdir -p dist/aur
|
|
83
|
+
install -m644 LICENSE dist/binary/LICENSE
|
|
84
|
+
archive="mud-${VERSION}-linux-x86_64.tar.gz"
|
|
85
|
+
tar -czf "dist/aur/$archive" -C dist/binary mud LICENSE
|
|
86
|
+
checksum=$(sha256sum "dist/aur/$archive" | cut -d ' ' -f 1)
|
|
87
|
+
sed -e "s/@VERSION@/$VERSION/" -e "s/@SHA256@/$checksum/" \
|
|
88
|
+
PKGBUILD > dist/aur/PKGBUILD
|
|
89
|
+
|
|
90
|
+
- uses: actions/upload-artifact@v4
|
|
91
|
+
with:
|
|
92
|
+
name: mud-aur
|
|
93
|
+
path: dist/aur/
|
|
94
|
+
if-no-files-found: error
|
|
95
|
+
|
|
96
|
+
test-package:
|
|
97
|
+
needs: build
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
container: archlinux:base-devel
|
|
100
|
+
steps:
|
|
101
|
+
- name: Install runtime dependencies
|
|
102
|
+
run: pacman -Syu --noconfirm git
|
|
103
|
+
|
|
104
|
+
- uses: actions/download-artifact@v4
|
|
105
|
+
with:
|
|
106
|
+
name: mud-aur
|
|
107
|
+
path: package
|
|
108
|
+
|
|
109
|
+
- name: Build and install Arch package
|
|
110
|
+
working-directory: package
|
|
111
|
+
run: |
|
|
112
|
+
useradd --create-home builder
|
|
113
|
+
chown -R builder:builder .
|
|
114
|
+
runuser -u builder -- makepkg --noconfirm
|
|
115
|
+
pacman -U --noconfirm mud-*.pkg.tar.zst
|
|
116
|
+
|
|
117
|
+
- name: Smoke test installed binary
|
|
118
|
+
shell: bash
|
|
119
|
+
run: |
|
|
120
|
+
HOME=$(mktemp -d)
|
|
121
|
+
export HOME
|
|
122
|
+
cd "$HOME"
|
|
123
|
+
mud completion carapace | grep -F 'mud'
|
|
124
|
+
test ! -e "$HOME/.config/mud/settings.ini"
|
|
125
|
+
mud --help
|
|
126
|
+
git init repo-a
|
|
127
|
+
git -C repo-a -c user.name=Test -c user.email=test@example.com \
|
|
128
|
+
commit --allow-empty -m Initial
|
|
129
|
+
mud init
|
|
130
|
+
mud status | grep -F 'repo-a'
|
|
131
|
+
mud -a -c='git rev-parse --is-inside-work-tree' | grep -F 'true'
|
|
132
|
+
|
|
133
|
+
publish:
|
|
134
|
+
needs: [build, test-package]
|
|
135
|
+
runs-on: ubuntu-latest
|
|
136
|
+
permissions:
|
|
137
|
+
contents: write
|
|
138
|
+
steps:
|
|
139
|
+
- uses: actions/download-artifact@v4
|
|
140
|
+
with:
|
|
141
|
+
name: mud-aur
|
|
142
|
+
path: package
|
|
143
|
+
|
|
144
|
+
- name: Upload binary to GitHub release
|
|
145
|
+
env:
|
|
146
|
+
GH_TOKEN: ${{ github.token }}
|
|
147
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
148
|
+
run: |
|
|
149
|
+
archive="mud-${VERSION}-linux-x86_64.tar.gz"
|
|
150
|
+
if gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" \
|
|
151
|
+
--json assets --jq '.assets[].name' | grep -Fxq "$archive"; then
|
|
152
|
+
gh release download "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" \
|
|
153
|
+
--pattern "$archive" --dir "$RUNNER_TEMP/published"
|
|
154
|
+
cmp "package/$archive" "$RUNNER_TEMP/published/$archive"
|
|
155
|
+
else
|
|
156
|
+
gh release upload "$RELEASE_TAG" "package/$archive" --repo "$GITHUB_REPOSITORY"
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
- name: Publish AUR package
|
|
160
|
+
uses: KSXGitHub/github-actions-deploy-aur@v4.1.2
|
|
161
|
+
with:
|
|
162
|
+
pkgname: mud
|
|
163
|
+
pkgbuild: ./package/PKGBUILD
|
|
164
|
+
test: true
|
|
165
|
+
commit_username: ${{ secrets.AUR_USERNAME }}
|
|
166
|
+
commit_email: ${{ secrets.AUR_EMAIL }}
|
|
167
|
+
ssh_private_key: ${{ secrets.AUR_SSH_KEY }}
|
|
168
|
+
commit_message: "Update mud to version ${{ needs.build.outputs.version }}"
|
|
169
|
+
ssh_keyscan_types: rsa,ecdsa,ed25519
|
|
@@ -15,6 +15,12 @@ pytest # run tests (verbose by default)
|
|
|
15
15
|
pytest tests/test_run.py # run a single file
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
## Binary releases and AUR
|
|
19
|
+
|
|
20
|
+
`.github/workflows/publish-aur.yaml` builds stable `vX.Y.Z` releases, with an explicit published tag required for manual runs. It checks out that exact tag, tests the wheel, freezes an x86_64 executable with PyInstaller on Ubuntu 22.04, and reruns the CLI tests against the executable. Build tools are pinned in `.github/requirements-binary.txt`.
|
|
21
|
+
|
|
22
|
+
The workflow fills `@VERSION@` and `@SHA256@` in the root `PKGBUILD` template, tests the package in Arch Linux, uploads `mud-X.Y.Z-linux-x86_64.tar.gz` to the release, then publishes `mud` and generated `.SRCINFO` to AUR using `AUR_USERNAME`, `AUR_EMAIL`, and `AUR_SSH_KEY`. Published assets are immutable; retry failed jobs with the original artifact. The package installs the bundled runtime under `/opt/mud` and links `/usr/bin/mud`, with no end-user Python build. `mud-git` is a provided/conflicting legacy AUR package; its listing is retired by requesting an AUR merge after `mud` is published. The PyPI distribution is still named `mud-git`.
|
|
23
|
+
|
|
18
24
|
## Entry point
|
|
19
25
|
|
|
20
26
|
`mud` CLI → `mud:run` in `src/mud/__init__.py` → `App` in `src/mud/app.py`; `mud completion` is dispatched to `completion.complete()` before writable settings are initialised.
|
|
@@ -28,15 +34,17 @@ pytest tests/test_run.py # run a single file
|
|
|
28
34
|
| `src/mud/completion.py` | Exports the Carapace spec and provides read-only dynamic completion via `C_ARG<n>` / `C_VALUE` |
|
|
29
35
|
| `src/mud/runner.py` | All display commands and execution modes |
|
|
30
36
|
| `src/mud/config.py` | `.mudconfig` TSV read/write; `init`, `add`, `remove`, `prune` |
|
|
31
|
-
| `src/mud/settings.py` | `~/.config/mud/settings.ini` read/write; read-only initialisation for completion |
|
|
37
|
+
| `src/mud/settings.py` | `~/.config/mud/settings.ini` read/write; legacy settings migration; read-only initialisation for completion |
|
|
32
38
|
| `src/mud/commands.py` | Constants for every command name and filter flag prefix |
|
|
33
39
|
| `src/mud/styles.py` | ANSI escape codes and Nerd Font glyphs |
|
|
34
|
-
| `src/mud/utils.py` | Shared helpers: table creation, error printing, configure wizard |
|
|
40
|
+
| `src/mud/utils.py` | Shared helpers: table creation, error printing, configure wizard, help banner (independent of source-file paths for frozen builds) |
|
|
35
41
|
|
|
36
42
|
## Architecture notes
|
|
37
43
|
|
|
38
44
|
**Global settings instance** — `utils.settings` is a single `Settings` object created in `__init__.run()` and accessed across all modules.
|
|
39
45
|
|
|
46
|
+
**Settings location** — All settings writes target `~/.config/mud/settings.ini`; mud never creates `~/.mudsettings`. An existing modern file takes precedence and leaves the legacy file untouched; otherwise normal startup moves the legacy file to the modern location, preserving its contents, or creates defaults at the modern location if neither file exists. The legacy file is removed only after a successful move. Completion can read legacy settings as a fallback but never migrates them. Ordinary package imports and builds do not initialise settings.
|
|
47
|
+
|
|
40
48
|
**Command dispatch** — `App.run()` routes to either a native `Runner` method (matched against constants in `commands.py`) or a shell pass-through. The `--` separator and `-c=<cmd>` flag both reach the shell path.
|
|
41
49
|
|
|
42
50
|
**Carapace completion** — `mud completion carapace` exports a shell-independent spec; its fixed `mud completion values` callback handles mud's equals-only flags without executing user input. Command/flag descriptions come from the argparse definitions, aliases from settings, and label/path/branch values from the discovered config. Local and remote branch names reuse `Runner._get_unique_branch_names()`. Nothing is completed after `--`, inside `-c=`, or in arbitrary shell/alias arguments. Filters remain available after a completed `-c=` token. Neither spec export nor completion creates settings files.
|
|
@@ -45,24 +53,27 @@ pytest tests/test_run.py # run a single file
|
|
|
45
53
|
|
|
46
54
|
**Execution modes** — three modes controlled by `run_async` + `run_table` settings (toggled by `-a` / `-t` flags): sequential, async streamed, async live-table.
|
|
47
55
|
|
|
56
|
+
**Frozen subprocesses** — `Runner` restores the original `LD_LIBRARY_PATH` (or removes it if originally unset) in the child-command environment when running under PyInstaller, so Git and arbitrary shell commands use system libraries rather than the bundled runtime.
|
|
57
|
+
|
|
48
58
|
**Filter chain** — `App._filter_with_arguments()` applies up to nine filters in sequence (ignore label, include/exclude label, include/exclude branch, include/exclude name substring, modified, diverged). Each step removes non-matching repos. Repeated `-N=` / `--not-name=` values exclude any matching path substring; empty exclusions are ignored.
|
|
49
59
|
|
|
50
60
|
**Nerd Fonts** — every glyph in `styles.GLYPHS` has an ASCII fallback. `utils.glyphs(key)` selects between them based on the `nerd_fonts` setting, so mud works with or without a patched font.
|
|
51
61
|
|
|
52
62
|
## Tests
|
|
53
63
|
|
|
54
|
-
Tests are black-box CLI tests — each runs `python -m mud` as a subprocess against real git repos in a temporary directory.
|
|
64
|
+
Tests are black-box CLI tests — each runs `python -m mud` as a subprocess against real git repos in a temporary directory. Set `MUD_EXECUTABLE` to an absolute executable path to run CLI and completion tests against a frozen binary instead; import-only checks still use the Python environment.
|
|
55
65
|
|
|
56
66
|
| File | Covers |
|
|
57
67
|
|---|---|
|
|
58
68
|
| `tests/test_config.py` | `init`, `add`, `remove`, `prune` |
|
|
69
|
+
| `tests/test_settings.py` | Import side effects, first-launch settings location, legacy moves and migration failures, modern-file precedence, and settings save destination |
|
|
59
70
|
| `tests/test_display.py` | `status`, `info`, `log`, `labels`, `branches`, `tags` |
|
|
60
|
-
| `tests/test_run.py` | Execution modes and
|
|
71
|
+
| `tests/test_run.py` | Execution modes, flags, and preservation of the external-command library path in frozen builds |
|
|
61
72
|
| `tests/test_filters.py` | `-l=`, `-L=`, `-b=`, `-B=`, `-n=`, `-N=` filter flags and native-command parsing regressions |
|
|
62
|
-
| `tests/test_completion.py` | Completion callback, dynamic values, command boundaries, read-only discovery, and optional real Carapace/Nushell integration |
|
|
73
|
+
| `tests/test_completion.py` | Completion callback, dynamic values, command boundaries, read-only settings precedence/discovery, and optional real Carapace/Nushell integration |
|
|
63
74
|
| `tests/test_states.py` | Edge-case repo states (unborn, detached, rebasing) |
|
|
64
75
|
|
|
65
|
-
Carapace integration tests run when `carapace` is on `PATH`; the Nushell round-trip test also requires `nu`. Tests isolate `HOME`, Carapace config/cache directories, and use the current Python environment's `mud` executable.
|
|
76
|
+
Carapace integration tests run when `carapace` is on `PATH`; the Nushell round-trip test also requires `nu`. Tests isolate `HOME`, Carapace config/cache directories, and use `MUD_EXECUTABLE` or the current Python environment's `mud` executable.
|
|
66
77
|
|
|
67
78
|
## Knowledge base update rule
|
|
68
79
|
After editing any file under `src/mud/`, update the affected sections of this file before finishing the task.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mud-git
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.9
|
|
4
4
|
Summary: Multi repository git utility. Manage multiple git-repositories simultaneously.
|
|
5
5
|
Author-email: Jasur Sadikov <jasur@sadikoff.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -18,7 +18,7 @@ Dynamic: license-file
|
|
|
18
18
|
# mud
|
|
19
19
|
|
|
20
20
|

|
|
21
|
-

|
|
22
22
|
[](https://github.com/jasursadikov/mud/actions/workflows/test.yaml)
|
|
23
23
|
[](https://github.com/jasursadikov/mud/actions/workflows/publish-pypi.yaml)
|
|
24
24
|
[](https://github.com/jasursadikov/mud/actions/workflows/publish-aur.yaml)
|
|
@@ -28,14 +28,16 @@ Dynamic: license-file
|
|
|
28
28
|
mud is CLI utility that allows you to run git commands in multiple repositories. It has multiple powerful filtering tools, native commands with an informative terminal output and support of aliasing. This tool is not limited to git commands only; you can run any commands you wish. However, this tool was primarily designed to be used with git, so each referenced directory should have a `.git` directory.
|
|
29
29
|
|
|
30
30
|
## Installing
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
pip install mud-git
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
| Distribution | Installation |
|
|
32
|
+
|--------------|--------------|
|
|
33
|
+
| PyPI | `pip install mud-git` |
|
|
34
|
+
| Arch Linux (x86_64) | `yay -S mud` installs the prebuilt release executable with its bundled Python runtime and libraries. |
|
|
35
|
+
| Migrate from AUR `mud-git` | Run `yay -S mud` and accept removal of the conflicting `mud-git` package. Existing mud settings and repository configurations are preserved. |
|
|
36
|
+
| Linux binary (x86_64) | Download `mud-X.Y.Z-linux-x86_64.tar.gz` from [GitHub Releases](https://github.com/jasursadikov/mud/releases), extract it, and run `mud/mud`; keep its `_internal` directory beside the executable. Requires Git, glibc 2.35 or newer, and zlib. |
|
|
37
|
+
| AUR release automation | Publish a stable `vX.Y.Z` GitHub release, or run **Publish mud binary to AUR** with its published release tag. CI tests the wheel and frozen executable, tests installation on Arch Linux, uploads the binary, and publishes `mud` with a SHA-256 checksum. |
|
|
38
|
+
| AUR credentials | Configure repository secrets `AUR_USERNAME`, `AUR_EMAIL`, and `AUR_SSH_KEY`; the key must belong to an AUR account allowed to publish `mud`. GitHub release uploads use the workflow's automatic token. |
|
|
39
|
+
| Retire the old AUR listing | After the first successful `mud` publication, request that AUR merge `mud-git` into `mud`. New releases publish only to `mud`. |
|
|
40
|
+
| Retry AUR publication | Re-run failed jobs to reuse the tested artifact. Existing release binaries are never overwritten; rebuilding a published binary requires a new release version. |
|
|
39
41
|
|
|
40
42
|
For requirements check [requirements.txt](requirements.txt).
|
|
41
43
|
|
|
@@ -66,9 +68,9 @@ mud --diverged git pull
|
|
|
66
68
|
| Command | Description |
|
|
67
69
|
|---------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
|
68
70
|
| `mud init` | creates `.mudconfig` and adds repositories beneath the current directory. |
|
|
69
|
-
| `mud configure`/`mud config` | runs the interactive settings wizard. |
|
|
71
|
+
| `mud configure`/`mud config` | runs the interactive settings wizard, saving only to `~/.config/mud/settings.ini`. If the modern file is missing, normal startup moves `~/.mudsettings` there or creates defaults if neither exists. An existing modern file takes precedence and leaves the legacy file untouched; mud never creates `~/.mudsettings`. |
|
|
70
72
|
| `mud help`/`mud --help`/`mud -h` | displays available commands and flags. |
|
|
71
|
-
| `mud set-global [path]` | sets the current `.mudconfig`, or the specified configuration path, as the fallback configuration to run from any directory. |
|
|
73
|
+
| `mud set-global [path]` | sets the current `.mudconfig`, or the specified configuration path, as the fallback configuration to run from any directory; saves to `~/.config/mud/settings.ini`. |
|
|
72
74
|
| `mud get-config` | prints the current `.mudconfig` location. |
|
|
73
75
|
| `mud prune` | removes all invalid repositories from the `.mudconfig`. |
|
|
74
76
|
| `mud info`/`mud i` | displays branch divergence and working directory changes. |
|
mud_git-1.1.9/PKGBUILD
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Maintainer: Jasur Sadikov <jasur@sadikoff.com>
|
|
2
|
+
pkgname=mud
|
|
3
|
+
pkgver=@VERSION@
|
|
4
|
+
pkgrel=1
|
|
5
|
+
pkgdesc="Multi repository git utility. Manage multiple git-repositories simultaneously."
|
|
6
|
+
arch=('x86_64')
|
|
7
|
+
url="https://github.com/jasursadikov/mud"
|
|
8
|
+
license=('MIT')
|
|
9
|
+
provides=("mud-git=$pkgver")
|
|
10
|
+
conflicts=('mud-git')
|
|
11
|
+
depends=('git' 'glibc' 'zlib')
|
|
12
|
+
options=('!strip')
|
|
13
|
+
source=("${url}/releases/download/v${pkgver}/mud-${pkgver}-linux-x86_64.tar.gz")
|
|
14
|
+
sha256sums=('@SHA256@')
|
|
15
|
+
|
|
16
|
+
package() {
|
|
17
|
+
install -d "$pkgdir/opt" "$pkgdir/usr/bin"
|
|
18
|
+
cp -a "$srcdir/mud" "$pkgdir/opt/mud"
|
|
19
|
+
ln -s /opt/mud/mud "$pkgdir/usr/bin/mud"
|
|
20
|
+
install -Dm644 "$srcdir/LICENSE" "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
|
21
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# mud
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
5
5
|
[](https://github.com/jasursadikov/mud/actions/workflows/test.yaml)
|
|
6
6
|
[](https://github.com/jasursadikov/mud/actions/workflows/publish-pypi.yaml)
|
|
7
7
|
[](https://github.com/jasursadikov/mud/actions/workflows/publish-aur.yaml)
|
|
@@ -11,14 +11,16 @@
|
|
|
11
11
|
mud is CLI utility that allows you to run git commands in multiple repositories. It has multiple powerful filtering tools, native commands with an informative terminal output and support of aliasing. This tool is not limited to git commands only; you can run any commands you wish. However, this tool was primarily designed to be used with git, so each referenced directory should have a `.git` directory.
|
|
12
12
|
|
|
13
13
|
## Installing
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
pip install mud-git
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
| Distribution | Installation |
|
|
15
|
+
|--------------|--------------|
|
|
16
|
+
| PyPI | `pip install mud-git` |
|
|
17
|
+
| Arch Linux (x86_64) | `yay -S mud` installs the prebuilt release executable with its bundled Python runtime and libraries. |
|
|
18
|
+
| Migrate from AUR `mud-git` | Run `yay -S mud` and accept removal of the conflicting `mud-git` package. Existing mud settings and repository configurations are preserved. |
|
|
19
|
+
| Linux binary (x86_64) | Download `mud-X.Y.Z-linux-x86_64.tar.gz` from [GitHub Releases](https://github.com/jasursadikov/mud/releases), extract it, and run `mud/mud`; keep its `_internal` directory beside the executable. Requires Git, glibc 2.35 or newer, and zlib. |
|
|
20
|
+
| AUR release automation | Publish a stable `vX.Y.Z` GitHub release, or run **Publish mud binary to AUR** with its published release tag. CI tests the wheel and frozen executable, tests installation on Arch Linux, uploads the binary, and publishes `mud` with a SHA-256 checksum. |
|
|
21
|
+
| AUR credentials | Configure repository secrets `AUR_USERNAME`, `AUR_EMAIL`, and `AUR_SSH_KEY`; the key must belong to an AUR account allowed to publish `mud`. GitHub release uploads use the workflow's automatic token. |
|
|
22
|
+
| Retire the old AUR listing | After the first successful `mud` publication, request that AUR merge `mud-git` into `mud`. New releases publish only to `mud`. |
|
|
23
|
+
| Retry AUR publication | Re-run failed jobs to reuse the tested artifact. Existing release binaries are never overwritten; rebuilding a published binary requires a new release version. |
|
|
22
24
|
|
|
23
25
|
For requirements check [requirements.txt](requirements.txt).
|
|
24
26
|
|
|
@@ -49,9 +51,9 @@ mud --diverged git pull
|
|
|
49
51
|
| Command | Description |
|
|
50
52
|
|---------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
|
51
53
|
| `mud init` | creates `.mudconfig` and adds repositories beneath the current directory. |
|
|
52
|
-
| `mud configure`/`mud config` | runs the interactive settings wizard. |
|
|
54
|
+
| `mud configure`/`mud config` | runs the interactive settings wizard, saving only to `~/.config/mud/settings.ini`. If the modern file is missing, normal startup moves `~/.mudsettings` there or creates defaults if neither exists. An existing modern file takes precedence and leaves the legacy file untouched; mud never creates `~/.mudsettings`. |
|
|
53
55
|
| `mud help`/`mud --help`/`mud -h` | displays available commands and flags. |
|
|
54
|
-
| `mud set-global [path]` | sets the current `.mudconfig`, or the specified configuration path, as the fallback configuration to run from any directory. |
|
|
56
|
+
| `mud set-global [path]` | sets the current `.mudconfig`, or the specified configuration path, as the fallback configuration to run from any directory; saves to `~/.config/mud/settings.ini`. |
|
|
55
57
|
| `mud get-config` | prints the current `.mudconfig` location. |
|
|
56
58
|
| `mud prune` | removes all invalid repositories from the `.mudconfig`. |
|
|
57
59
|
| `mud info`/`mud i` | displays branch divergence and working directory changes. |
|
|
@@ -22,6 +22,13 @@ class Runner:
|
|
|
22
22
|
|
|
23
23
|
def __init__(self, repos):
|
|
24
24
|
self._force_color_env = self._force_color_env | os.environ.copy()
|
|
25
|
+
if getattr(sys, 'frozen', False):
|
|
26
|
+
# PyInstaller's bundled libraries must not override system command libraries.
|
|
27
|
+
library_path = self._force_color_env.pop('LD_LIBRARY_PATH_ORIG', None)
|
|
28
|
+
if library_path is None:
|
|
29
|
+
self._force_color_env.pop('LD_LIBRARY_PATH', None)
|
|
30
|
+
else:
|
|
31
|
+
self._force_color_env['LD_LIBRARY_PATH'] = library_path
|
|
25
32
|
self._printed_lines_count = 0
|
|
26
33
|
self.repos = repos
|
|
27
34
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import shutil
|
|
2
3
|
import configparser
|
|
3
4
|
|
|
4
5
|
MAIN_SCOPE = 'mud'
|
|
@@ -7,14 +8,11 @@ ALIAS_SCOPE = 'alias'
|
|
|
7
8
|
|
|
8
9
|
class Settings:
|
|
9
10
|
def __init__(self, file_name: str, old_file_name: str, read_only: bool = False) -> None:
|
|
10
|
-
use_old = os.path.exists(os.path.join(os.path.expanduser('~'), old_file_name))
|
|
11
|
-
file_name = old_file_name if use_old else file_name
|
|
12
|
-
directory = os.path.expanduser('~' if use_old else '~/.config/mud')
|
|
13
|
-
|
|
14
11
|
self.mud_settings = None
|
|
15
12
|
self.alias_settings = None
|
|
16
13
|
self.config = configparser.ConfigParser()
|
|
17
|
-
self.settings_file = os.path.join(
|
|
14
|
+
self.settings_file = os.path.join(os.path.expanduser('~/.config/mud'), file_name)
|
|
15
|
+
self.old_settings_file = os.path.join(os.path.expanduser('~'), old_file_name)
|
|
18
16
|
self.read_only = read_only
|
|
19
17
|
self.defaults = {
|
|
20
18
|
'mud': {
|
|
@@ -38,9 +36,15 @@ class Settings:
|
|
|
38
36
|
|
|
39
37
|
def load_settings(self) -> None:
|
|
40
38
|
if not os.path.exists(self.settings_file):
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
self.
|
|
39
|
+
if os.path.exists(self.old_settings_file):
|
|
40
|
+
self.config.read(self.old_settings_file)
|
|
41
|
+
if not self.read_only:
|
|
42
|
+
os.makedirs(os.path.dirname(self.settings_file), exist_ok=True)
|
|
43
|
+
shutil.move(self.old_settings_file, self.settings_file)
|
|
44
|
+
else:
|
|
45
|
+
self.config.read_dict(self.defaults)
|
|
46
|
+
if not self.read_only:
|
|
47
|
+
self.save()
|
|
44
48
|
else:
|
|
45
49
|
self.config.read(self.settings_file)
|
|
46
50
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mud-git
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.9
|
|
4
4
|
Summary: Multi repository git utility. Manage multiple git-repositories simultaneously.
|
|
5
5
|
Author-email: Jasur Sadikov <jasur@sadikoff.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -18,7 +18,7 @@ Dynamic: license-file
|
|
|
18
18
|
# mud
|
|
19
19
|
|
|
20
20
|

|
|
21
|
-

|
|
22
22
|
[](https://github.com/jasursadikov/mud/actions/workflows/test.yaml)
|
|
23
23
|
[](https://github.com/jasursadikov/mud/actions/workflows/publish-pypi.yaml)
|
|
24
24
|
[](https://github.com/jasursadikov/mud/actions/workflows/publish-aur.yaml)
|
|
@@ -28,14 +28,16 @@ Dynamic: license-file
|
|
|
28
28
|
mud is CLI utility that allows you to run git commands in multiple repositories. It has multiple powerful filtering tools, native commands with an informative terminal output and support of aliasing. This tool is not limited to git commands only; you can run any commands you wish. However, this tool was primarily designed to be used with git, so each referenced directory should have a `.git` directory.
|
|
29
29
|
|
|
30
30
|
## Installing
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
pip install mud-git
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
| Distribution | Installation |
|
|
32
|
+
|--------------|--------------|
|
|
33
|
+
| PyPI | `pip install mud-git` |
|
|
34
|
+
| Arch Linux (x86_64) | `yay -S mud` installs the prebuilt release executable with its bundled Python runtime and libraries. |
|
|
35
|
+
| Migrate from AUR `mud-git` | Run `yay -S mud` and accept removal of the conflicting `mud-git` package. Existing mud settings and repository configurations are preserved. |
|
|
36
|
+
| Linux binary (x86_64) | Download `mud-X.Y.Z-linux-x86_64.tar.gz` from [GitHub Releases](https://github.com/jasursadikov/mud/releases), extract it, and run `mud/mud`; keep its `_internal` directory beside the executable. Requires Git, glibc 2.35 or newer, and zlib. |
|
|
37
|
+
| AUR release automation | Publish a stable `vX.Y.Z` GitHub release, or run **Publish mud binary to AUR** with its published release tag. CI tests the wheel and frozen executable, tests installation on Arch Linux, uploads the binary, and publishes `mud` with a SHA-256 checksum. |
|
|
38
|
+
| AUR credentials | Configure repository secrets `AUR_USERNAME`, `AUR_EMAIL`, and `AUR_SSH_KEY`; the key must belong to an AUR account allowed to publish `mud`. GitHub release uploads use the workflow's automatic token. |
|
|
39
|
+
| Retire the old AUR listing | After the first successful `mud` publication, request that AUR merge `mud-git` into `mud`. New releases publish only to `mud`. |
|
|
40
|
+
| Retry AUR publication | Re-run failed jobs to reuse the tested artifact. Existing release binaries are never overwritten; rebuilding a published binary requires a new release version. |
|
|
39
41
|
|
|
40
42
|
For requirements check [requirements.txt](requirements.txt).
|
|
41
43
|
|
|
@@ -66,9 +68,9 @@ mud --diverged git pull
|
|
|
66
68
|
| Command | Description |
|
|
67
69
|
|---------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
|
68
70
|
| `mud init` | creates `.mudconfig` and adds repositories beneath the current directory. |
|
|
69
|
-
| `mud configure`/`mud config` | runs the interactive settings wizard. |
|
|
71
|
+
| `mud configure`/`mud config` | runs the interactive settings wizard, saving only to `~/.config/mud/settings.ini`. If the modern file is missing, normal startup moves `~/.mudsettings` there or creates defaults if neither exists. An existing modern file takes precedence and leaves the legacy file untouched; mud never creates `~/.mudsettings`. |
|
|
70
72
|
| `mud help`/`mud --help`/`mud -h` | displays available commands and flags. |
|
|
71
|
-
| `mud set-global [path]` | sets the current `.mudconfig`, or the specified configuration path, as the fallback configuration to run from any directory. |
|
|
73
|
+
| `mud set-global [path]` | sets the current `.mudconfig`, or the specified configuration path, as the fallback configuration to run from any directory; saves to `~/.config/mud/settings.ini`. |
|
|
72
74
|
| `mud get-config` | prints the current `.mudconfig` location. |
|
|
73
75
|
| `mud prune` | removes all invalid repositories from the `.mudconfig`. |
|
|
74
76
|
| `mud info`/`mud i` | displays branch divergence and working directory changes. |
|
|
@@ -7,6 +7,7 @@ README.md
|
|
|
7
7
|
img.png
|
|
8
8
|
pyproject.toml
|
|
9
9
|
requirements.txt
|
|
10
|
+
.github/requirements-binary.txt
|
|
10
11
|
.github/workflows/publish-aur.yaml
|
|
11
12
|
.github/workflows/publish-pypi.yaml
|
|
12
13
|
.github/workflows/test.yaml
|
|
@@ -35,4 +36,5 @@ tests/test_config.py
|
|
|
35
36
|
tests/test_display.py
|
|
36
37
|
tests/test_filters.py
|
|
37
38
|
tests/test_run.py
|
|
39
|
+
tests/test_settings.py
|
|
38
40
|
tests/test_states.py
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": [
|
|
3
3
|
".editorconfig",
|
|
4
|
+
".github/requirements-binary.txt",
|
|
4
5
|
".github/workflows/publish-aur.yaml",
|
|
5
6
|
".github/workflows/publish-pypi.yaml",
|
|
6
7
|
".github/workflows/test.yaml",
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
"tests/test_display.py",
|
|
30
31
|
"tests/test_filters.py",
|
|
31
32
|
"tests/test_run.py",
|
|
33
|
+
"tests/test_settings.py",
|
|
32
34
|
"tests/test_states.py"
|
|
33
35
|
]
|
|
34
36
|
}
|
|
@@ -85,8 +85,14 @@ def make_rebasing_repo(path: Path) -> None:
|
|
|
85
85
|
# CLI runner
|
|
86
86
|
# ---------------------------------------------------------------------------
|
|
87
87
|
|
|
88
|
+
def mud_command(*args: str) -> list[str]:
|
|
89
|
+
executable = os.environ.get('MUD_EXECUTABLE')
|
|
90
|
+
command = [executable] if executable else [sys.executable, '-m', 'mud']
|
|
91
|
+
return [*command, *args]
|
|
92
|
+
|
|
93
|
+
|
|
88
94
|
def run_mud(*args: str, cwd: Path, home: Path) -> subprocess.CompletedProcess:
|
|
89
|
-
"""Run
|
|
95
|
+
"""Run mud inside *cwd*, using MUD_EXECUTABLE when set.
|
|
90
96
|
|
|
91
97
|
HOME is pointed at an empty temp directory so the subprocess gets
|
|
92
98
|
clean default mud settings, isolated from the developer's own machine.
|
|
@@ -94,7 +100,7 @@ def run_mud(*args: str, cwd: Path, home: Path) -> subprocess.CompletedProcess:
|
|
|
94
100
|
env = os.environ.copy()
|
|
95
101
|
env["HOME"] = str(home)
|
|
96
102
|
return subprocess.run(
|
|
97
|
-
|
|
103
|
+
mud_command(*args),
|
|
98
104
|
cwd=cwd,
|
|
99
105
|
capture_output=True,
|
|
100
106
|
text=True,
|
|
@@ -7,7 +7,7 @@ from pathlib import Path
|
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
9
|
|
|
10
|
-
from helpers import make_detached_repo, make_empty_repo, make_git_repo, run_mud
|
|
10
|
+
from helpers import make_detached_repo, make_empty_repo, make_git_repo, mud_command, run_mud
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
@pytest.fixture
|
|
@@ -18,7 +18,7 @@ def complete(repos_labeled: Path, home: Path):
|
|
|
18
18
|
env['C_VALUE'] = arguments[-1]
|
|
19
19
|
env.update({f'C_ARG{index}': argument for index, argument in enumerate(arguments[:-1])})
|
|
20
20
|
result = subprocess.run(
|
|
21
|
-
|
|
21
|
+
mud_command('completion', 'values'),
|
|
22
22
|
cwd=cwd, env=env, capture_output=True, text=True, check=True,
|
|
23
23
|
)
|
|
24
24
|
assert result.stderr == ''
|
|
@@ -101,6 +101,7 @@ def test_native_positionals(complete, repos_labeled: Path):
|
|
|
101
101
|
def test_read_only_discovery(complete, repos_labeled: Path, home: Path, tmp_path_factory):
|
|
102
102
|
assert complete('-l=', cwd=repos_labeled / 'repo_a') == ['-l=label_a', '-l=label_b']
|
|
103
103
|
assert not (home / '.config').exists()
|
|
104
|
+
assert not (home / '.mudsettings').exists()
|
|
104
105
|
settings = home / '.config' / 'mud' / 'settings.ini'
|
|
105
106
|
settings.parent.mkdir(parents=True)
|
|
106
107
|
settings.write_text(f'[mud]\nconfig_path = {repos_labeled / ".mudconfig"}\n[alias]\nto = git checkout\n')
|
|
@@ -108,6 +109,27 @@ def test_read_only_discovery(complete, repos_labeled: Path, home: Path, tmp_path
|
|
|
108
109
|
assert 'to' in complete('')
|
|
109
110
|
|
|
110
111
|
|
|
112
|
+
@pytest.mark.parametrize('modern_exists', [False, True])
|
|
113
|
+
def test_settings_precedence_without_migration(complete, home: Path, modern_exists):
|
|
114
|
+
legacy = home / '.mudsettings'
|
|
115
|
+
legacy_contents = '[mud]\n[alias]\nlegacy = git status\n'
|
|
116
|
+
legacy.write_text(legacy_contents)
|
|
117
|
+
modern = home / '.config' / 'mud' / 'settings.ini'
|
|
118
|
+
modern_contents = '[mud]\n[alias]\nmodern = git diff\n'
|
|
119
|
+
if modern_exists:
|
|
120
|
+
modern.parent.mkdir(parents=True)
|
|
121
|
+
modern.write_text(modern_contents)
|
|
122
|
+
|
|
123
|
+
values = complete('')
|
|
124
|
+
assert ('modern' in values) == modern_exists
|
|
125
|
+
assert ('legacy' in values) != modern_exists
|
|
126
|
+
assert legacy.read_text() == legacy_contents
|
|
127
|
+
if modern_exists:
|
|
128
|
+
assert modern.read_text() == modern_contents
|
|
129
|
+
else:
|
|
130
|
+
assert not (home / '.config').exists()
|
|
131
|
+
|
|
132
|
+
|
|
111
133
|
def test_invalid_and_empty_configs(complete, repos_labeled: Path, home: Path):
|
|
112
134
|
config = repos_labeled / '.mudconfig'
|
|
113
135
|
config.unlink()
|
|
@@ -135,6 +157,7 @@ def carapace(repos_labeled: Path, home: Path):
|
|
|
135
157
|
spec = run_mud('completion', 'carapace', cwd=home, home=home)
|
|
136
158
|
assert spec.returncode == 0, spec.stderr
|
|
137
159
|
assert not (home / '.config').exists()
|
|
160
|
+
assert not (home / '.mudsettings').exists()
|
|
138
161
|
spec_directory = home / '.config' / 'carapace' / 'specs'
|
|
139
162
|
spec_directory.mkdir(parents=True)
|
|
140
163
|
(spec_directory / 'mud.yaml').write_text(spec.stdout)
|
|
@@ -142,7 +165,7 @@ def carapace(repos_labeled: Path, home: Path):
|
|
|
142
165
|
env.update({
|
|
143
166
|
'HOME': str(home), 'XDG_CONFIG_HOME': str(home / '.config'),
|
|
144
167
|
'XDG_CACHE_HOME': str(home / '.cache'), 'CARAPACE_BRIDGES': '',
|
|
145
|
-
'PATH': str(Path(
|
|
168
|
+
'PATH': str(Path(mud_command()[0]).parent) + os.pathsep + env['PATH'],
|
|
146
169
|
})
|
|
147
170
|
|
|
148
171
|
def invoke(*arguments, shell='export'):
|
|
@@ -11,6 +11,9 @@ Default settings have both enabled, so:
|
|
|
11
11
|
We test that all modes exit 0 and that the command actually ran in each repo.
|
|
12
12
|
"""
|
|
13
13
|
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
import pytest
|
|
16
|
+
|
|
14
17
|
from helpers import run_mud
|
|
15
18
|
|
|
16
19
|
|
|
@@ -53,3 +56,19 @@ def test_run_command_runs_in_every_repo(repos: Path, home: Path):
|
|
|
53
56
|
result = run_mud("-a", "echo", "hello", cwd=repos, home=home)
|
|
54
57
|
# "hello" appears at least once per repo (the header also echoes the command name)
|
|
55
58
|
assert result.stdout.count("hello") >= 2
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@pytest.mark.parametrize('flags', [('-a',), ('-t',), ()])
|
|
62
|
+
@pytest.mark.parametrize('library_path', [None, '', '/external/libraries'])
|
|
63
|
+
def test_run_preserves_library_path(repos: Path, home: Path, monkeypatch, flags, library_path):
|
|
64
|
+
monkeypatch.delenv('LD_LIBRARY_PATH_ORIG', raising=False)
|
|
65
|
+
if library_path is None:
|
|
66
|
+
monkeypatch.delenv('LD_LIBRARY_PATH', raising=False)
|
|
67
|
+
else:
|
|
68
|
+
monkeypatch.setenv('LD_LIBRARY_PATH', library_path)
|
|
69
|
+
result = run_mud(
|
|
70
|
+
*flags, '-c=printf %s "${LD_LIBRARY_PATH-}" > library-path', cwd=repos, home=home,
|
|
71
|
+
)
|
|
72
|
+
assert result.returncode == 0, result.stderr
|
|
73
|
+
for name in ['repo_a', 'repo_b']:
|
|
74
|
+
assert (repos / name / 'library-path').read_text() == (library_path or '')
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import configparser
|
|
2
|
+
import os
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from helpers import run_mud
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_import_does_not_create_settings(home: Path):
|
|
11
|
+
result = subprocess.run(
|
|
12
|
+
[sys.executable, '-c', 'import mud'], cwd=home,
|
|
13
|
+
env={**os.environ, 'HOME': str(home)}, capture_output=True, text=True,
|
|
14
|
+
)
|
|
15
|
+
assert result.returncode == 0, result.stderr
|
|
16
|
+
assert list(home.iterdir()) == []
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_first_launch_creates_modern_settings(home: Path):
|
|
20
|
+
result = run_mud(cwd=home, home=home)
|
|
21
|
+
assert result.returncode == 0, result.stderr
|
|
22
|
+
settings = configparser.ConfigParser()
|
|
23
|
+
assert settings.read(home / '.config' / 'mud' / 'settings.ini')
|
|
24
|
+
assert settings.getboolean('mud', 'run_async') is True
|
|
25
|
+
assert settings['alias']['fetch'] == 'git fetch'
|
|
26
|
+
assert not (home / '.mudsettings').exists()
|
|
27
|
+
assert not (home / '.mudsetting').exists()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_legacy_settings_move_on_launch(home: Path, tmp_path: Path):
|
|
31
|
+
config = tmp_path / '.mudconfig'
|
|
32
|
+
config.write_text('')
|
|
33
|
+
legacy = home / '.mudsettings'
|
|
34
|
+
contents = f'# Personal settings\n[mud]\nconfig_path = {config}\nrun_async = False\n[alias]\ncustom = git status\n'
|
|
35
|
+
legacy.write_text(contents)
|
|
36
|
+
|
|
37
|
+
result = run_mud('get-config', cwd=home, home=home)
|
|
38
|
+
assert result.returncode == 0, result.stderr
|
|
39
|
+
assert result.stdout.strip() == str(config)
|
|
40
|
+
modern = home / '.config' / 'mud' / 'settings.ini'
|
|
41
|
+
assert modern.read_text() == contents
|
|
42
|
+
settings = configparser.ConfigParser()
|
|
43
|
+
assert settings.read(modern)
|
|
44
|
+
assert settings['mud']['config_path'] == str(config)
|
|
45
|
+
assert settings.getboolean('mud', 'run_async') is False
|
|
46
|
+
assert settings['alias']['custom'] == 'git status'
|
|
47
|
+
assert not legacy.exists()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_failed_migration_preserves_legacy_settings(home: Path):
|
|
51
|
+
legacy = home / '.mudsettings'
|
|
52
|
+
contents = '[mud]\nrun_async = False\n[alias]\ncustom = git status\n'
|
|
53
|
+
legacy.write_text(contents)
|
|
54
|
+
(home / '.config').write_text('not a directory\n')
|
|
55
|
+
|
|
56
|
+
result = run_mud('help', cwd=home, home=home)
|
|
57
|
+
assert result.returncode != 0
|
|
58
|
+
assert legacy.read_text() == contents
|
|
59
|
+
assert not (home / '.config' / 'mud' / 'settings.ini').exists()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_modern_settings_take_precedence_and_receive_updates(home: Path, tmp_path: Path):
|
|
63
|
+
config = tmp_path / '.mudconfig'
|
|
64
|
+
config.write_text('')
|
|
65
|
+
legacy = home / '.mudsettings'
|
|
66
|
+
contents = '[mud]\nrun_async = True\n[alias]\ncustom = git status\n'
|
|
67
|
+
legacy.write_text(contents)
|
|
68
|
+
modern = home / '.config' / 'mud' / 'settings.ini'
|
|
69
|
+
modern.parent.mkdir(parents=True)
|
|
70
|
+
modern.write_text('[mud]\nrun_async = False\n[alias]\ncustom = git diff\n')
|
|
71
|
+
|
|
72
|
+
result = run_mud('set-global', str(config), cwd=home, home=home)
|
|
73
|
+
assert result.returncode == 0, result.stderr
|
|
74
|
+
settings = configparser.ConfigParser()
|
|
75
|
+
settings.read(modern)
|
|
76
|
+
assert settings['mud']['config_path'] == str(config)
|
|
77
|
+
assert settings.getboolean('mud', 'run_async') is False
|
|
78
|
+
assert settings['alias']['custom'] == 'git diff'
|
|
79
|
+
assert legacy.read_text() == contents
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
name: Upload to Arch Linux (AUR)
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
test:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v4
|
|
13
|
-
|
|
14
|
-
- name: Set up Python 3.13
|
|
15
|
-
uses: actions/setup-python@v5
|
|
16
|
-
with:
|
|
17
|
-
python-version: "3.13"
|
|
18
|
-
|
|
19
|
-
- name: Configure git
|
|
20
|
-
run: |
|
|
21
|
-
git config --global user.name "Test User"
|
|
22
|
-
git config --global user.email "test@example.com"
|
|
23
|
-
|
|
24
|
-
- name: Install dependencies and build
|
|
25
|
-
run: |
|
|
26
|
-
pip install -r requirements.txt pytest build
|
|
27
|
-
python -m build
|
|
28
|
-
pip install dist/*.whl
|
|
29
|
-
|
|
30
|
-
- name: Run tests
|
|
31
|
-
run: pytest -v
|
|
32
|
-
|
|
33
|
-
aur-publish:
|
|
34
|
-
needs: [test]
|
|
35
|
-
runs-on: ubuntu-latest
|
|
36
|
-
steps:
|
|
37
|
-
- name: Checkout repository
|
|
38
|
-
uses: actions/checkout@v4
|
|
39
|
-
with:
|
|
40
|
-
fetch-depth: 0
|
|
41
|
-
|
|
42
|
-
- name: Update PKGBUILD with Tag Version
|
|
43
|
-
run: |
|
|
44
|
-
version=$(git describe --tags --abbrev=0 | sed 's/^v//')
|
|
45
|
-
echo "latest_version=$version" >> $GITHUB_ENV
|
|
46
|
-
sed -i "s/^pkgver=.*/pkgver=${version}/" PKGBUILD
|
|
47
|
-
cat PKGBUILD
|
|
48
|
-
|
|
49
|
-
- name: Publish AUR package
|
|
50
|
-
uses: KSXGitHub/github-actions-deploy-aur@v4.1.2
|
|
51
|
-
env:
|
|
52
|
-
latest_version: ${{ env.latest_version }}
|
|
53
|
-
with:
|
|
54
|
-
pkgname: mud-git
|
|
55
|
-
pkgbuild: ./PKGBUILD
|
|
56
|
-
commit_username: ${{ secrets.AUR_USERNAME }}
|
|
57
|
-
commit_email: ${{ secrets.AUR_EMAIL }}
|
|
58
|
-
ssh_private_key: ${{ secrets.AUR_SSH_KEY }}
|
|
59
|
-
commit_message: "Update AUR package to version ${{ env.latest_version }}"
|
|
60
|
-
ssh_keyscan_types: rsa,ecdsa
|
mud_git-1.1.8/PKGBUILD
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Maintainer: Jasur Sadikov <jasur@sadikoff.com>
|
|
2
|
-
pkgname=mud-git
|
|
3
|
-
_pkgname=mud
|
|
4
|
-
pkgver=1.0.0
|
|
5
|
-
pkgrel=1
|
|
6
|
-
pkgdesc="Multi repository git utility. Manage multiple git-repositories simultaneously."
|
|
7
|
-
arch=('any')
|
|
8
|
-
url="https://github.com/jasursadikov/mud"
|
|
9
|
-
license=('MIT')
|
|
10
|
-
provides=("${pkgname}")
|
|
11
|
-
conflicts=("${pkgname}")
|
|
12
|
-
depends=(
|
|
13
|
-
'python'
|
|
14
|
-
'python-prettytable'
|
|
15
|
-
'python-pygit2'
|
|
16
|
-
'git')
|
|
17
|
-
makedepends=(
|
|
18
|
-
'python-build'
|
|
19
|
-
'python-installer'
|
|
20
|
-
'python-wheel'
|
|
21
|
-
'python-hatchling'
|
|
22
|
-
'python-setuptools'
|
|
23
|
-
'python-setuptools-scm'
|
|
24
|
-
)
|
|
25
|
-
source=("${pkgname}::git+${url}#tag=v${pkgver}")
|
|
26
|
-
md5sums=('SKIP')
|
|
27
|
-
|
|
28
|
-
build() {
|
|
29
|
-
cd "$srcdir/$pkgname"
|
|
30
|
-
python -m build --wheel --no-isolation
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
package() {
|
|
34
|
-
cd "$srcdir/$pkgname"
|
|
35
|
-
python -m installer --destdir="$pkgdir" dist/*.whl
|
|
36
|
-
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
|
37
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|