cdf-shell 0.1.0__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.
@@ -0,0 +1,75 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: release-${{ github.ref }}
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ test:
17
+ uses: ./.github/workflows/test.yml
18
+
19
+ build:
20
+ needs: test
21
+ runs-on: ubuntu-24.04
22
+ timeout-minutes: 10
23
+ steps:
24
+ - name: Checkout
25
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26
+ with:
27
+ persist-credentials: false
28
+
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
31
+ with:
32
+ version: "0.12.7"
33
+ python-version: "3.14.7"
34
+
35
+ - name: Verify tag matches package version
36
+ run: |
37
+ tag_version="${GITHUB_REF_NAME#v}"
38
+ # --no-project: reading pyproject.toml needs no environment, so don't
39
+ # sync one (which could also rewrite a stale uv.lock instead of failing).
40
+ pkg_version="$(uv run --no-project python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
41
+ if [ "$tag_version" != "$pkg_version" ]; then
42
+ echo "::error::tag $GITHUB_REF_NAME does not match pyproject.toml version $pkg_version"
43
+ exit 1
44
+ fi
45
+
46
+ # Build backend pinned by version and hash (build-constraints.txt), so the
47
+ # published artifacts don't depend on whatever hatchling is newest today.
48
+ - name: Build distributions
49
+ run: make build
50
+
51
+ - name: Upload distributions
52
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
53
+ with:
54
+ name: dist
55
+ path: dist/
56
+ retention-days: 7
57
+
58
+ publish:
59
+ needs: build
60
+ runs-on: ubuntu-24.04
61
+ timeout-minutes: 10
62
+ environment:
63
+ name: pypi
64
+ url: https://pypi.org/project/cdf-shell/
65
+ permissions:
66
+ id-token: write
67
+ steps:
68
+ - name: Download distributions
69
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
70
+ with:
71
+ name: dist
72
+ path: dist/
73
+
74
+ - name: Publish to PyPI
75
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
@@ -0,0 +1,87 @@
1
+ name: test
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ # release.yml runs this same job before building, so the two can't drift.
8
+ workflow_call:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: test-${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ test:
19
+ runs-on: ubuntu-24.04
20
+ timeout-minutes: 10
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ # Oldest supported (requires-python) through newest, exact patch releases.
25
+ python: ["3.11.16", "3.12.14", "3.13.15", "3.14.7"]
26
+ # Latest fzf everywhere, plus the oldest supported one (Ubuntu 24.04's)
27
+ # once; the real-fzf picker tests skip if fzf is missing, so it's pinned.
28
+ fzf: ["0.74.4"]
29
+ include:
30
+ - python: "3.11.16"
31
+ fzf: "0.44.1"
32
+ steps:
33
+ - name: Checkout
34
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
35
+ with:
36
+ persist-credentials: false
37
+
38
+ - name: Install uv
39
+ uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
40
+ with:
41
+ version: "0.12.7"
42
+ python-version: ${{ matrix.python }}
43
+
44
+ - name: Install dependencies
45
+ run: uv sync --locked
46
+
47
+ # Pinned to the versions the shell wrapper tests were verified with;
48
+ # the tests skip a shell that is missing, so this must not silently drift.
49
+ - name: Install zsh 5.9 and fish 4.9.3
50
+ env:
51
+ FISH_VERSION: 4.9.3
52
+ FISH_SHA256: 8f643d10ad1abb0ef7072764c01ceb5cf61b2d373fda400cf60f0bad69b7e095
53
+ run: |
54
+ sudo apt-get update
55
+ sudo apt-get install -y --no-install-recommends zsh
56
+ if ! zsh --version | grep -q '^zsh 5\.9 '; then
57
+ echo "::error::expected zsh 5.9, got: $(zsh --version)"
58
+ exit 1
59
+ fi
60
+ curl -fsSL -o "$RUNNER_TEMP/fish.tar.xz" \
61
+ "https://github.com/fish-shell/fish-shell/releases/download/${FISH_VERSION}/fish-${FISH_VERSION}-linux-x86_64.tar.xz"
62
+ echo "${FISH_SHA256} $RUNNER_TEMP/fish.tar.xz" | sha256sum -c -
63
+ mkdir -p "$HOME/.local/bin"
64
+ tar -xf "$RUNNER_TEMP/fish.tar.xz" -C "$HOME/.local/bin"
65
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
66
+ "$HOME/.local/bin/fish" --version
67
+
68
+ - name: Install fzf ${{ matrix.fzf }}
69
+ env:
70
+ FZF_VERSION: ${{ matrix.fzf }}
71
+ run: |
72
+ # Release tags changed from "X.Y.Z" to "vX.Y.Z" along the way.
73
+ case "$FZF_VERSION" in
74
+ 0.44.1) tag=0.44.1; sha=73d7946f08dae8a330f4233e3eeb71c4ffc411412e3fe8488d608dde3f7a74bd ;;
75
+ 0.74.4) tag=v0.74.4; sha=05e6813a337cc722c3ed07e54a764b75cc5d671e2e60459db0ba696ee5fa7504 ;;
76
+ *) echo "::error::no pinned checksum for fzf $FZF_VERSION"; exit 1 ;;
77
+ esac
78
+ curl -fsSL -o "$RUNNER_TEMP/fzf.tar.gz" \
79
+ "https://github.com/junegunn/fzf/releases/download/${tag}/fzf-${FZF_VERSION}-linux_amd64.tar.gz"
80
+ echo "${sha} $RUNNER_TEMP/fzf.tar.gz" | sha256sum -c -
81
+ mkdir -p "$HOME/.local/bin"
82
+ tar -xzf "$RUNNER_TEMP/fzf.tar.gz" -C "$HOME/.local/bin"
83
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
84
+ "$HOME/.local/bin/fzf" --version | grep -q "^${FZF_VERSION} "
85
+
86
+ - name: Run test suite
87
+ run: make test
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .mypy_cache/
5
+ .ruff_cache/
6
+ .pytest_cache/
7
+ .coverage
8
+ .coverage.*
9
+ htmlcov/
10
+ dist/
11
+ CLAUDE.md
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Felipe Ruhland
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,19 @@
1
+ .PHONY: run test lint build build-constraints
2
+
3
+ run:
4
+ uv run python -m cdf
5
+
6
+ test:
7
+ PYTHONDONTWRITEBYTECODE=1 uv run pytest
8
+
9
+ lint:
10
+ uv run ruff check .
11
+
12
+ # Build with the hash-pinned backend from build-constraints.txt (same as CI).
13
+ build:
14
+ uv build --build-constraints build-constraints.txt --require-hashes
15
+
16
+ # Re-lock build-constraints.txt after changing build-constraints.in.
17
+ build-constraints:
18
+ uv pip compile build-constraints.in --generate-hashes --universal \
19
+ --python-version 3.11 --no-header -o build-constraints.txt
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.5
2
+ Name: cdf-shell
3
+ Version: 0.1.0
4
+ Summary: Interactive git-project cd/find
5
+ Author-email: Felipe Ruhland <pypi@feliperuhland.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+
11
+ # cdf
12
+
13
+ `cdf` ("cd" + "find") interactively searches the directory tree below your
14
+ current working directory for a term, and `cd`s into the directory you
15
+ select.
16
+
17
+ - Search scope is always the current working directory downward — never the
18
+ whole filesystem, never a cached/global index.
19
+ - By default it only matches git repository roots and stops descending once
20
+ it finds one (pass `--no-git` to walk every directory instead).
21
+ - Symlinked directories are listed (in git mode, only if they point at a
22
+ repository) but never descended into, so symlink loops can't hang the walk.
23
+ - Selection is powered by [`fzf`](https://github.com/junegunn/fzf) 0.44 or
24
+ newer, which must be on `PATH`. Your `FZF_DEFAULT_OPTS` (theme, layout,
25
+ `--print-query`, `--accept-nth`, ...) are respected.
26
+ - Results are shown (and fuzzy-matched) relative to the search root, so the
27
+ root's own path doesn't match every query.
28
+ - Directory names are shown with terminal control characters (escape
29
+ sequences, newlines, tabs) replaced by `?`, so a hostile name in a cloned
30
+ repo can't mess with your terminal; the directory you pick is still the
31
+ exact one on disk.
32
+
33
+ ## Install
34
+
35
+ ### From source
36
+
37
+ ```sh
38
+ uv sync
39
+ ```
40
+
41
+ This installs the `cdf` console script into `.venv/bin/`.
42
+
43
+ ### Arch Linux
44
+
45
+ A `PKGBUILD` is provided at the repo root, sourcing the tarball from this
46
+ repo's own `v*.*.*` git tags:
47
+
48
+ ```sh
49
+ makepkg -si
50
+ ```
51
+
52
+ `cdf` (the binary) only *resolves* a path and prints it to stdout — a Python
53
+ process can't change its parent shell's working directory. Load the shell
54
+ integration so the `cdf` command actually `cd`s for you:
55
+
56
+ ```sh
57
+ # ~/.bashrc
58
+ eval "$(command cdf --init bash)"
59
+ # ~/.zshrc
60
+ eval "$(command cdf --init zsh)"
61
+ ```
62
+
63
+ ```fish
64
+ # ~/.config/fish/config.fish
65
+ command cdf --init fish | source
66
+ ```
67
+
68
+ This defines a shell function also named `cdf`, which takes priority over
69
+ the binary in your shell and calls it internally via `command cdf`. Make
70
+ sure the `cdf` binary itself is on `PATH` (e.g. via `uv tool install .`, or
71
+ by adding `.venv/bin` to `PATH`).
72
+
73
+ ## Usage
74
+
75
+ ```sh
76
+ cdf [term ...] [-p/--path ROOT] [--git/--no-git] [-a/--all|--no-all] [-d/--max-depth N]
77
+ [-x/--one-file-system|--no-one-file-system] [-c/--config FILE]
78
+ cdf --init {bash,zsh,fish}
79
+ ```
80
+
81
+ | Flag | Default | Meaning |
82
+ |---|---|---|
83
+ | `term ...` | `""` | initial fuzzy filter text passed to `fzf` (several words are joined with spaces) |
84
+ | `-p, --path` | cwd | root to search from |
85
+ | `--git` / `--no-git` | `--git` | only match git repository roots |
86
+ | `-a, --all` / `--no-all` | `--no-all` | include hidden/dot directories |
87
+ | `-d, --max-depth N` | no limit | only look `N` levels below the root (`0` = no limit, to lift a limit set in the config file) |
88
+ | `-x, --one-file-system` / `--no-one-file-system` | off | list mount points but don't descend into them, like `find -xdev` |
89
+ | `-c, --config` | `$CDF_CONFIG_PATH`, else first existing default | config file path |
90
+ | `--init SHELL` | | print the shell integration for `bash`, `zsh` or `fish` and exit |
91
+
92
+ Run `cdf --help` for the full reference, or `cdf --version` (the shell
93
+ function special-cases `--help`/`-h`/`--version`/`--init` to pass them straight
94
+ through instead of attempting to `cd` into their output).
95
+
96
+ ### Exit codes
97
+
98
+ - `0` — a directory was selected
99
+ - `1` — nothing was selected (cancelled in `fzf`, or no candidates found, in
100
+ which case a hint is printed on stderr)
101
+ - `2` — an error occurred (message on stderr) — e.g. `fzf` missing, an
102
+ unreadable search root, or a bad config file
103
+ - `130` — interrupted with Ctrl-C
104
+
105
+ ## Config file
106
+
107
+ The config file path is resolved in this order:
108
+
109
+ 1. `-c/--config FILE` — must exist, or it's an error.
110
+ 2. `$CDF_CONFIG_PATH` — must exist, or it's an error.
111
+ 3. Otherwise, the first of these that exists (silently skipped if none do):
112
+ `$XDG_CONFIG_HOME/cdf/cdf.conf` (default `~/.config/cdf/cdf.conf`), then
113
+ `~/cdf.conf`.
114
+
115
+ All keys are optional (TOML syntax, despite the `.conf` extension):
116
+
117
+ ```toml
118
+ path = "~/projects" # string, expanded with ~; relative paths are relative to this file
119
+ git = true # boolean
120
+ hidden = false # boolean
121
+ ignore = ["node_modules", "__pycache__", ".venv"] # glob patterns of directory names to skip
122
+ max_depth = 0 # non-negative integer, 0 = no limit
123
+ one_file_system = false # boolean
124
+ ```
125
+
126
+ `ignore` replaces the default list shown above (set `ignore = []` to skip
127
+ nothing). Patterns match one directory name at a time, so they can't contain
128
+ `/`. `.git` directories are never descended into regardless.
129
+
130
+ `one_file_system` is off by default because btrfs subvolumes (and some other
131
+ setups) report their own device IDs, so turning it on would hide those
132
+ directories. Turn it on if you run `cdf --no-git` from places like `/` or `~`
133
+ that have network or FUSE mounts below them, which can be slow or hang.
134
+
135
+ Unknown keys, and values of the wrong type (e.g. `git = "false"` instead of
136
+ `git = false`), are rejected with an error, to catch typos early.
137
+
138
+ ## Development
139
+
140
+ ```sh
141
+ make run # uv run python -m cdf
142
+ make test # pytest + ruff + ruff-format + mypy (strict) + coverage, gated at 100%
143
+ make lint # uv run ruff check .
144
+ make build # sdist + wheel, with the build backend pinned by hash (build-constraints.txt)
145
+ make build-constraints # re-lock build-constraints.txt after editing build-constraints.in
146
+ ```
147
+
148
+ Supported Python: 3.11 through 3.14; CI runs the full `make test` gate on
149
+ each, with the bash/zsh/fish wrapper tests running against pinned zsh 5.9
150
+ and fish 4.9.3.
@@ -0,0 +1,39 @@
1
+ # Maintainer: Felipe Ruhland <archlinux@feliperuhland.com>
2
+
3
+ pkgname=cdf-shell
4
+ pkgver=0.1.0
5
+ pkgrel=1
6
+ pkgdesc="Interactively search the directory tree below the cwd and cd into the result"
7
+ arch=('any')
8
+ url="https://github.com/feliperuhland/cdf-shell"
9
+ license=('MIT')
10
+ depends=('python' 'fzf>=0.44')
11
+ makedepends=('python-build' 'python-hatchling' 'python-installer')
12
+ checkdepends=('python-pytest')
13
+ _pkgsrc="${pkgname}-${pkgver}"
14
+ source=("${pkgname}-${pkgver}.tar.gz::${url}/archive/v${pkgver}.tar.gz")
15
+ # Placeholder — v${pkgver} isn't tagged upstream yet, so this can't be computed
16
+ # for real. Run `updpkgsums` once it is; this deliberately fails checksum
17
+ # verification (rather than using SKIP) so makepkg refuses to build silently
18
+ # unverified.
19
+ sha256sums=('0000000000000000000000000000000000000000000000000000000000000000')
20
+
21
+ build() {
22
+ cd "${_pkgsrc}"
23
+ python -m build --wheel --no-isolation
24
+ }
25
+
26
+ check() {
27
+ cd "${_pkgsrc}"
28
+ python -m venv --system-site-packages test-env
29
+ test-env/bin/python -m installer dist/*.whl
30
+ test-env/bin/python -m pytest -o addopts="" tests/
31
+ }
32
+
33
+ package() {
34
+ cd "${_pkgsrc}"
35
+ python -m installer --destdir="${pkgdir}" dist/*.whl
36
+
37
+ install -vDm644 README.md "${pkgdir}/usr/share/doc/${pkgname}/README.md"
38
+ install -vDm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
39
+ }
@@ -0,0 +1,140 @@
1
+ # cdf
2
+
3
+ `cdf` ("cd" + "find") interactively searches the directory tree below your
4
+ current working directory for a term, and `cd`s into the directory you
5
+ select.
6
+
7
+ - Search scope is always the current working directory downward — never the
8
+ whole filesystem, never a cached/global index.
9
+ - By default it only matches git repository roots and stops descending once
10
+ it finds one (pass `--no-git` to walk every directory instead).
11
+ - Symlinked directories are listed (in git mode, only if they point at a
12
+ repository) but never descended into, so symlink loops can't hang the walk.
13
+ - Selection is powered by [`fzf`](https://github.com/junegunn/fzf) 0.44 or
14
+ newer, which must be on `PATH`. Your `FZF_DEFAULT_OPTS` (theme, layout,
15
+ `--print-query`, `--accept-nth`, ...) are respected.
16
+ - Results are shown (and fuzzy-matched) relative to the search root, so the
17
+ root's own path doesn't match every query.
18
+ - Directory names are shown with terminal control characters (escape
19
+ sequences, newlines, tabs) replaced by `?`, so a hostile name in a cloned
20
+ repo can't mess with your terminal; the directory you pick is still the
21
+ exact one on disk.
22
+
23
+ ## Install
24
+
25
+ ### From source
26
+
27
+ ```sh
28
+ uv sync
29
+ ```
30
+
31
+ This installs the `cdf` console script into `.venv/bin/`.
32
+
33
+ ### Arch Linux
34
+
35
+ A `PKGBUILD` is provided at the repo root, sourcing the tarball from this
36
+ repo's own `v*.*.*` git tags:
37
+
38
+ ```sh
39
+ makepkg -si
40
+ ```
41
+
42
+ `cdf` (the binary) only *resolves* a path and prints it to stdout — a Python
43
+ process can't change its parent shell's working directory. Load the shell
44
+ integration so the `cdf` command actually `cd`s for you:
45
+
46
+ ```sh
47
+ # ~/.bashrc
48
+ eval "$(command cdf --init bash)"
49
+ # ~/.zshrc
50
+ eval "$(command cdf --init zsh)"
51
+ ```
52
+
53
+ ```fish
54
+ # ~/.config/fish/config.fish
55
+ command cdf --init fish | source
56
+ ```
57
+
58
+ This defines a shell function also named `cdf`, which takes priority over
59
+ the binary in your shell and calls it internally via `command cdf`. Make
60
+ sure the `cdf` binary itself is on `PATH` (e.g. via `uv tool install .`, or
61
+ by adding `.venv/bin` to `PATH`).
62
+
63
+ ## Usage
64
+
65
+ ```sh
66
+ cdf [term ...] [-p/--path ROOT] [--git/--no-git] [-a/--all|--no-all] [-d/--max-depth N]
67
+ [-x/--one-file-system|--no-one-file-system] [-c/--config FILE]
68
+ cdf --init {bash,zsh,fish}
69
+ ```
70
+
71
+ | Flag | Default | Meaning |
72
+ |---|---|---|
73
+ | `term ...` | `""` | initial fuzzy filter text passed to `fzf` (several words are joined with spaces) |
74
+ | `-p, --path` | cwd | root to search from |
75
+ | `--git` / `--no-git` | `--git` | only match git repository roots |
76
+ | `-a, --all` / `--no-all` | `--no-all` | include hidden/dot directories |
77
+ | `-d, --max-depth N` | no limit | only look `N` levels below the root (`0` = no limit, to lift a limit set in the config file) |
78
+ | `-x, --one-file-system` / `--no-one-file-system` | off | list mount points but don't descend into them, like `find -xdev` |
79
+ | `-c, --config` | `$CDF_CONFIG_PATH`, else first existing default | config file path |
80
+ | `--init SHELL` | | print the shell integration for `bash`, `zsh` or `fish` and exit |
81
+
82
+ Run `cdf --help` for the full reference, or `cdf --version` (the shell
83
+ function special-cases `--help`/`-h`/`--version`/`--init` to pass them straight
84
+ through instead of attempting to `cd` into their output).
85
+
86
+ ### Exit codes
87
+
88
+ - `0` — a directory was selected
89
+ - `1` — nothing was selected (cancelled in `fzf`, or no candidates found, in
90
+ which case a hint is printed on stderr)
91
+ - `2` — an error occurred (message on stderr) — e.g. `fzf` missing, an
92
+ unreadable search root, or a bad config file
93
+ - `130` — interrupted with Ctrl-C
94
+
95
+ ## Config file
96
+
97
+ The config file path is resolved in this order:
98
+
99
+ 1. `-c/--config FILE` — must exist, or it's an error.
100
+ 2. `$CDF_CONFIG_PATH` — must exist, or it's an error.
101
+ 3. Otherwise, the first of these that exists (silently skipped if none do):
102
+ `$XDG_CONFIG_HOME/cdf/cdf.conf` (default `~/.config/cdf/cdf.conf`), then
103
+ `~/cdf.conf`.
104
+
105
+ All keys are optional (TOML syntax, despite the `.conf` extension):
106
+
107
+ ```toml
108
+ path = "~/projects" # string, expanded with ~; relative paths are relative to this file
109
+ git = true # boolean
110
+ hidden = false # boolean
111
+ ignore = ["node_modules", "__pycache__", ".venv"] # glob patterns of directory names to skip
112
+ max_depth = 0 # non-negative integer, 0 = no limit
113
+ one_file_system = false # boolean
114
+ ```
115
+
116
+ `ignore` replaces the default list shown above (set `ignore = []` to skip
117
+ nothing). Patterns match one directory name at a time, so they can't contain
118
+ `/`. `.git` directories are never descended into regardless.
119
+
120
+ `one_file_system` is off by default because btrfs subvolumes (and some other
121
+ setups) report their own device IDs, so turning it on would hide those
122
+ directories. Turn it on if you run `cdf --no-git` from places like `/` or `~`
123
+ that have network or FUSE mounts below them, which can be slow or hang.
124
+
125
+ Unknown keys, and values of the wrong type (e.g. `git = "false"` instead of
126
+ `git = false`), are rejected with an error, to catch typos early.
127
+
128
+ ## Development
129
+
130
+ ```sh
131
+ make run # uv run python -m cdf
132
+ make test # pytest + ruff + ruff-format + mypy (strict) + coverage, gated at 100%
133
+ make lint # uv run ruff check .
134
+ make build # sdist + wheel, with the build backend pinned by hash (build-constraints.txt)
135
+ make build-constraints # re-lock build-constraints.txt after editing build-constraints.in
136
+ ```
137
+
138
+ Supported Python: 3.11 through 3.14; CI runs the full `make test` gate on
139
+ each, with the bash/zsh/fish wrapper tests running against pinned zsh 5.9
140
+ and fish 4.9.3.
@@ -0,0 +1 @@
1
+ hatchling==1.32.4
@@ -0,0 +1,24 @@
1
+ hatchling==1.32.4 \
2
+ --hash=sha256:08ecf7548fb48205e7f213d70c71e67b8271b7242093dc3f1da578b42c734a2c \
3
+ --hash=sha256:c4468f73144c054d2aab4ef0f0378c43b9878bf07f8ffd6b79690e970d375f07
4
+ # via -r build-constraints.in
5
+ packaging==26.3 \
6
+ --hash=sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79 \
7
+ --hash=sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c
8
+ # via hatchling
9
+ pathspec==1.1.1 \
10
+ --hash=sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a \
11
+ --hash=sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189
12
+ # via hatchling
13
+ pluggy==1.6.0 \
14
+ --hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \
15
+ --hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746
16
+ # via hatchling
17
+ tomlkit==0.15.1 \
18
+ --hash=sha256:177a05aece5a8ca5266fd3c448abb47b8d352f09d477d3ca8332db4d89b24304 \
19
+ --hash=sha256:e25bbf38843005246210a12982776f27f99cb9be67160e14434d0c0d21ee1e97
20
+ # via hatchling
21
+ trove-classifiers==2026.9.21.13 \
22
+ --hash=sha256:0a9ebc8d4e2f3e8a22848c5258033035bec17a3012ac3fea16dbaa764489eb71 \
23
+ --hash=sha256:8b1ff4f9c191b1040b71c37f1e445ab99732911e3cd91de52838453a854d7a17
24
+ # via hatchling
@@ -0,0 +1,58 @@
1
+ [project]
2
+ name = "cdf-shell"
3
+ version = "0.1.0"
4
+ description = "Interactive git-project cd/find"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "Felipe Ruhland", email = "pypi@feliperuhland.com" }]
9
+ requires-python = ">=3.11"
10
+ dependencies = []
11
+
12
+ [project.scripts]
13
+ cdf = "cdf.cli:main"
14
+
15
+ [dependency-groups]
16
+ dev = [
17
+ "pytest>=8.0",
18
+ "pytest-cov>=5.0",
19
+ "pytest-ruff>=0.4",
20
+ "pytest-mypy>=0.10",
21
+ "ruff>=0.6",
22
+ "mypy>=1.11",
23
+ ]
24
+
25
+ [tool.pytest.ini_options]
26
+ addopts = "--ruff --ruff-format --mypy --cov=cdf --cov-report=term-missing --cov-fail-under=100"
27
+ testpaths = ["src", "tests"]
28
+
29
+ [tool.coverage.run]
30
+ source = ["src/cdf"]
31
+ omit = ["src/cdf/__main__.py"]
32
+
33
+ [tool.coverage.report]
34
+ exclude_also = [
35
+ "if __name__ == .__main__.:",
36
+ ]
37
+
38
+ [tool.ruff]
39
+ line-length = 100
40
+ target-version = "py311"
41
+
42
+ [tool.ruff.lint]
43
+ select = ["E", "F", "I", "UP", "B"]
44
+
45
+ [tool.mypy]
46
+ strict = true
47
+ # Check against the oldest supported Python, not whichever one runs mypy.
48
+ python_version = "3.11"
49
+ files = ["src", "tests"]
50
+
51
+ [build-system]
52
+ # Lower bound only (PEP 639 license fields need 1.27+) so distro builds can use
53
+ # their own hatchling; CI and `make build` pin it exactly via build-constraints.txt.
54
+ requires = ["hatchling>=1.27"]
55
+ build-backend = "hatchling.build"
56
+
57
+ [tool.hatch.build.targets.wheel]
58
+ packages = ["src/cdf"]
File without changes
@@ -0,0 +1,8 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+
5
+ from cdf.cli import main
6
+
7
+ if __name__ == "__main__":
8
+ sys.exit(main())