dploy 0.1.3__tar.gz → 0.2.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.
Files changed (52) hide show
  1. dploy-0.2.0/.gitattributes +5 -0
  2. dploy-0.2.0/.github/workflows/ci.yml +54 -0
  3. dploy-0.2.0/.github/workflows/release.yaml +50 -0
  4. dploy-0.2.0/.gitignore +16 -0
  5. dploy-0.2.0/AGENTS.md +21 -0
  6. dploy-0.2.0/CHANGELOG.md +233 -0
  7. dploy-0.2.0/CLAUDE.md +1 -0
  8. dploy-0.2.0/CONTEXT.md +105 -0
  9. dploy-0.2.0/PKG-INFO +121 -0
  10. dploy-0.1.3/PKG-INFO → dploy-0.2.0/README.md +44 -21
  11. dploy-0.2.0/docs/adr/0001-windows-permission-validation.md +67 -0
  12. dploy-0.2.0/docs/agents/domain.md +51 -0
  13. dploy-0.2.0/docs/agents/issue-tracker.md +45 -0
  14. dploy-0.2.0/docs/agents/triage-labels.md +13 -0
  15. dploy-0.2.0/dploy/__init__.py +94 -0
  16. {dploy-0.1.3 → dploy-0.2.0}/dploy/__main__.py +17 -17
  17. dploy-0.2.0/dploy/_winaccess.py +203 -0
  18. dploy-0.2.0/dploy/actions.py +207 -0
  19. dploy-0.2.0/dploy/cli.py +173 -0
  20. {dploy-0.1.3 → dploy-0.2.0}/dploy/error.py +49 -37
  21. dploy-0.2.0/dploy/ignore.py +96 -0
  22. dploy-0.2.0/dploy/linkcmd.py +119 -0
  23. dploy-0.2.0/dploy/main.py +138 -0
  24. dploy-0.2.0/dploy/py.typed +0 -0
  25. dploy-0.2.0/dploy/stowcmd.py +711 -0
  26. dploy-0.2.0/dploy/utils.py +225 -0
  27. {dploy-0.1.3 → dploy-0.2.0}/dploy/version.py +5 -5
  28. dploy-0.2.0/invoke.yaml +2 -0
  29. dploy-0.2.0/pyproject.toml +100 -0
  30. dploy-0.2.0/tasks.py +123 -0
  31. dploy-0.2.0/tests/__init__.py +0 -0
  32. dploy-0.2.0/tests/conftest.py +231 -0
  33. dploy-0.2.0/tests/test_clean.py +140 -0
  34. dploy-0.2.0/tests/test_cli.py +159 -0
  35. dploy-0.2.0/tests/test_ignore.py +228 -0
  36. dploy-0.2.0/tests/test_link.py +129 -0
  37. dploy-0.2.0/tests/test_stow.py +499 -0
  38. dploy-0.2.0/tests/test_unstow.py +517 -0
  39. dploy-0.2.0/tests/test_utils.py +271 -0
  40. dploy-0.2.0/tests/utils.py +249 -0
  41. dploy-0.2.0/uv.lock +476 -0
  42. dploy-0.1.3/README.md +0 -63
  43. dploy-0.1.3/dploy/__init__.py +0 -35
  44. dploy-0.1.3/dploy/actions.py +0 -217
  45. dploy-0.1.3/dploy/cli.py +0 -114
  46. dploy-0.1.3/dploy/ignore.py +0 -67
  47. dploy-0.1.3/dploy/linkcmd.py +0 -81
  48. dploy-0.1.3/dploy/main.py +0 -125
  49. dploy-0.1.3/dploy/stowcmd.py +0 -442
  50. dploy-0.1.3/dploy/utils.py +0 -123
  51. dploy-0.1.3/pyproject.toml +0 -36
  52. {dploy-0.1.3 → dploy-0.2.0}/LICENSE.txt +0 -0
@@ -0,0 +1,5 @@
1
+ # This checkout is shared between Windows and Linux (via Dropbox), so the same
2
+ # physical files are opened by both. Normalize to LF everywhere -- including in
3
+ # the working tree on Windows -- so that editing from one side does not rewrite
4
+ # every file from the other side's point of view.
5
+ * text=auto eol=lf
@@ -0,0 +1,54 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test:
12
+ name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
13
+ runs-on: ${{ matrix.os }}
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ os: [ubuntu-latest, macos-latest, windows-latest]
18
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ with:
23
+ # hatch-vcs reads the version from tags, so it needs the full history.
24
+ fetch-depth: 0
25
+
26
+ - name: Enable symlinks on Windows
27
+ if: runner.os == 'Windows'
28
+ run: |
29
+ reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /v "AllowDevelopmentWithoutDevLicense" /d 1 /f
30
+ git config --global core.symlinks true
31
+
32
+ - name: Install uv
33
+ uses: astral-sh/setup-uv@v5
34
+ with:
35
+ enable-cache: true
36
+ cache-dependency-glob: "uv.lock"
37
+
38
+ - name: Set up Python ${{ matrix.python-version }}
39
+ run: uv python install ${{ matrix.python-version }}
40
+
41
+ - name: Install dependencies
42
+ run: uv sync --all-groups
43
+
44
+ - name: Lint (pylint, ruff, ty)
45
+ run: uv run invoke lint
46
+
47
+ - name: Reformat Check (ruff)
48
+ run: uv run invoke reformat-check
49
+
50
+ - name: Metrics (radon)
51
+ run: uv run invoke metrics
52
+
53
+ - name: Test (pytest)
54
+ run: uv run invoke test
@@ -0,0 +1,50 @@
1
+ name: Release
2
+
3
+ # Publishes to PyPI when a version tag is pushed, for example:
4
+ # git tag 0.2.0 && git push origin 0.2.0
5
+ # The package version comes from the tag (hatch-vcs), so there is no version
6
+ # to edit by hand. Before tagging, set the date in CHANGELOG.md.
7
+ #
8
+ # One-time setup on PyPI: add this repository and workflow (release.yaml) as a
9
+ # trusted publisher for the project, with the environment name "pypi".
10
+
11
+ on:
12
+ push:
13
+ tags:
14
+ - "[0-9]+.[0-9]+.[0-9]+*"
15
+
16
+ jobs:
17
+ build:
18
+ name: Build distributions
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ with:
23
+ # hatch-vcs reads the version from tags, so it needs the full history.
24
+ fetch-depth: 0
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@v5
28
+
29
+ - name: Build
30
+ run: uv build
31
+
32
+ - uses: actions/upload-artifact@v4
33
+ with:
34
+ name: dist
35
+ path: dist/
36
+
37
+ publish:
38
+ name: Publish to PyPI
39
+ needs: build
40
+ runs-on: ubuntu-latest
41
+ environment: pypi
42
+ permissions:
43
+ id-token: write # required for PyPI trusted publishing
44
+ steps:
45
+ - uses: actions/download-artifact@v4
46
+ with:
47
+ name: dist
48
+ path: dist/
49
+
50
+ - uses: pypa/gh-action-pypi-publish@release/v1
dploy-0.2.0/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ # python files
2
+ __pycache__/
3
+ *.pyc
4
+ .venv/
5
+
6
+ # pyinstaller files
7
+ dist/
8
+ build/
9
+ *.spec
10
+
11
+ # pytest-cov files
12
+ .coverage
13
+ .pytest_cache/
14
+
15
+ # git worktrees
16
+ .worktree/
dploy-0.2.0/AGENTS.md ADDED
@@ -0,0 +1,21 @@
1
+ # dploy
2
+
3
+ A command-line stow/link/unstow utility for managing dotfiles and other
4
+ symlinked file trees.
5
+
6
+ ## Agent skills
7
+
8
+ ### Issue tracker
9
+
10
+ Issues live as GitHub issues in `arecarn/dploy`, managed with the `gh` CLI. See
11
+ `docs/agents/issue-tracker.md`.
12
+
13
+ ### Triage labels
14
+
15
+ Default canonical role names (`needs-triage`, `needs-info`, `ready-for-agent`,
16
+ `ready-for-human`, `wontfix`). See `docs/agents/triage-labels.md`.
17
+
18
+ ### Domain docs
19
+
20
+ Single-context: `CONTEXT.md` and `docs/adr/` at the repo root (created lazily,
21
+ absence is not an error). See `docs/agents/domain.md`.
@@ -0,0 +1,233 @@
1
+ # Change Log
2
+
3
+ The format of this change log is based on [Keep a Changelog](http://keepachangelog.com/)
4
+
5
+ All changes documented here should be written with the goal give the end-user
6
+ (not other developers) a summarized view of the changes since the last release,
7
+ organized by order of importance.
8
+
9
+ ## [0.2.0] - 2026-11-14
10
+
11
+ ### Added
12
+
13
+ - Added a `--skip-conflicts` flag to `stow` that links everything that
14
+ doesn't conflict with an existing, unmanaged file instead of aborting the
15
+ whole command. Dploy exits with status `2` when some files were skipped.
16
+ - Added a `--no-folding` flag to `stow` and `unstow`, matching GNU Stow's
17
+ flag of the same name, that keeps each file as its own individual link
18
+ instead of folding a destination directory into one link.
19
+ - Added a `--dotfiles` flag to `stow` and `unstow`, matching GNU Stow's flag
20
+ of the same name: a package entry named `dot-foo` is linked as `.foo`.
21
+ `unstow` removes links by what they point at, so it does not need the flag.
22
+
23
+ ### Changed
24
+
25
+ - **Breaking:** Renamed `source`/`sources`/`dest` to `package`/`packages`/
26
+ `destination` across the public API and the CLI, to match the terms
27
+ `CONTEXT.md` defines. This affects the `stow`, `unstow`, and `clean`
28
+ function parameters and CLI arguments. The `link` command's argument stays
29
+ `source`, since it takes a single file or directory, not a package.
30
+ - Switch to uv for dependency management instead of Poetry.
31
+ - Use hatchling as the build system.
32
+ - Switch CI from Travis CI and AppVeyor to GitHub Actions.
33
+ - Move Pylint configuration to pyproject.toml and remove in-code suppressions.
34
+
35
+ ### Fixed
36
+
37
+ - On Windows, a link to a directory is now created as a directory symlink
38
+ instead of a file symlink, which did not work.
39
+ - On Windows, existing links are now recognized as pointing at their
40
+ package. Windows reports link targets with a `\\?\` prefix, which made
41
+ every comparison with the package path fail.
42
+ - On Windows, dploy now decides whether two paths are the same file by asking
43
+ the file system instead of comparing path text, so a different spelling of
44
+ one path (letter case, short names) no longer counts as a different file.
45
+ - An ignore pattern the file system rejects, which Windows does for some
46
+ patterns POSIX accepts, is now skipped instead of crashing stow, unstow
47
+ and clean.
48
+ - On Windows, permission checks now read the file's ACL instead of only the
49
+ read-only flag, so an unreadable or unwritable path is reported before
50
+ anything changes rather than raising `PermissionError` part way through.
51
+ - Blank lines in `.dploystowignore`, or an empty `--ignore` pattern, no
52
+ longer crash stow/unstow/clean.
53
+ - Stowing a second package that shares a directory two or more levels deep
54
+ with an already-stowed package no longer writes into the first package's
55
+ source tree.
56
+ - Recursive ignore patterns, like `**/*.swp`, no longer cause dploy to skip
57
+ the whole folder a matching file lives in, including when that folder is
58
+ shared with another package being stowed.
59
+ - `unstow` no longer leaves behind an empty directory when all of its
60
+ contents are removed within the same run, for example a subdirectory
61
+ cleared while its parent directory only contained that one entry.
62
+ - `clean` now removes dangling links. It previously removed nothing, because
63
+ it could not match a link to its package unless the package sat directly in
64
+ the working directory and the link's target had no `..` in it. An unreadable
65
+ directory is now reported as an error instead of crashing.
66
+ - `link` now reports a clean error when the destination's parent is a file
67
+ instead of a directory. It previously crashed with a traceback.
68
+
69
+ ## [0.1.3] - 2026-02-13
70
+
71
+ ### Added
72
+
73
+ - Added a `dploy clean` subcommand.
74
+
75
+ ### Changed
76
+
77
+ - Switch to Poetry for packaging instead of setuptools.
78
+ - Require at least Python >= 3.10.
79
+ - Use black for auto formatting instead of yapf.
80
+ - Use custom *DployError* exceptions.
81
+ - Version is now sourced from pyproject.toml via importlib.metadata.
82
+
83
+ ### Fixed
84
+
85
+ - Print syntax help if no valid subcommand was provided.
86
+ - Fixed pytest.
87
+ - Fixed invoke tasks to work with Poetry and Python 3.13.
88
+
89
+ ### Removed
90
+
91
+ - Removed requirements.txt in favor of pyproject.toml dependency groups.
92
+
93
+ ## [0.1.2] - 2017-10-26
94
+
95
+ ### Changed
96
+
97
+ - Renamed the CLI --quiet option to --silent because it better reflects the
98
+ effect of the option
99
+
100
+ ### Fixed
101
+
102
+ - Fix bug causing unstow to delete dest directory when unfolding.
103
+ When unstowing and nearly all actions have been collected additional checking
104
+ to find candidates for folding i.e. when a directory contains symlinks to
105
+ files that all share the same parent directory. It just so happens that the
106
+ dest directory passed into unstow could also meet this same criteria and would
107
+ be deleted in error.
108
+
109
+ - Produce a helpful error when stowing or unstowing with duplicate sources.
110
+ Before stow would fail, when conflicts were found, and unstow would succeed in
111
+ unstowing a duplicate source the first time, but fail after trying to unstow
112
+ nothing. By catching the bug before hand the error message is much clearer.
113
+
114
+ - Fix bug stowing or linking paths that cannot be relative to each other and
115
+ caused a silent failure.
116
+ e.g. with windows paths: `dploy stow C:\some\path D:\other\Path`
117
+ Since the symbolic links can't use a relative path fallback to the absolute
118
+ version of the path passed in.
119
+
120
+ ## [0.1.1] - 2016-12-29
121
+
122
+ ### Fix
123
+
124
+ - Added a MANIFEST.in to fix installation via PyPi
125
+
126
+ ## [0.1.0] - 2016-12-29
127
+
128
+ ### Changed
129
+
130
+ - Added Dates to Change log releases
131
+
132
+ ### Fixed
133
+
134
+ - Fixed change log formatting
135
+ - Fix PyPi Package so it can be installed
136
+
137
+ ## [0.0.5] - 2016-12-28
138
+
139
+ ### Added
140
+
141
+ - Added --ignore argument to stow and unstow commands, to specify patterns file
142
+ to ignore.
143
+ - Added reading of .dploystowignore files in the directories of sources for
144
+ ignore patterns that are additional to those specified via --ignore
145
+ - Added optional is_silent & is_dry_run arguments to dploy.stow() dploy.unstow()
146
+ and dploy.link(), This is analogous to the --dry-run and --quiet command line
147
+ arguments. These function arguments default to is_silent=True and
148
+ is_dry_run=False.
149
+ - Added redundant check to make sure dploy never deletes anything other than a
150
+ symbolic link
151
+ - Check for source and dest new consideration was taken for sources
152
+ and dests directories that have invalid execute permissions.
153
+
154
+ ### Changed
155
+
156
+ - Check for additional issues with sub commands that are similar to the initial
157
+ checks done on the input of stow and unstow
158
+ - Prevent redundant errors when the src or dest are not directories
159
+ - Clarify some error messages
160
+ - Display the user inputted source and dest paths instead of absolute paths in
161
+ the output
162
+ - Clarify error messages for file and symbolic link conflicts
163
+ - Make the output of dploy stow and unstow deterministic across file systems
164
+ - Changed the output of failing dploy sub commands so they print as many
165
+ detected issues as possible before aborting
166
+ - Print all conflicts while stowing instead of just the first conflict, and
167
+ print what exactly the conflict is
168
+
169
+ ### Fixed
170
+
171
+ - Fixed issue when unstowing where some stowed packages directories created
172
+ during the stowing process via unfolding would not be deleted.
173
+ - Fix issue unstowing a folded dir with a stray link
174
+ - This fixed the following scenario: Given a dest directory with stowed
175
+ packages that share a folded directory, that also contains a stray link
176
+ along with the links created by stowing. When the stowed packages are
177
+ unstowed Then the folded directory was re-folded using the parent
178
+ directory of the single stray link and possibly linking new files that
179
+ were never intended to be linked there. When what was desired was the
180
+ directory to just remain with the single stray symlink.
181
+ - Fix an improperly handled expetion that occurred when unstowing a package that
182
+ had it's destination directories execute permission unset.
183
+
184
+ ## [0.0.4] - 2016-09-13
185
+
186
+ ### Added
187
+
188
+ - Add folding of the remaining links that would be around after calling unstow
189
+ - Add Checks for conflicts between multiple sources for stow
190
+ - Add checking to see if args are directories for stow and unstow
191
+ - Add check the permissions for source and dest before running a command
192
+ - Add error handling for source permissions errors for stow and unstow
193
+ - CLI: Add a --dry-run flag to show what would be done
194
+ - CLI: Add a --quiet option to suppress normal output
195
+ - CLI: Add handling for canceling the program with CTRL-C
196
+ - CLI: Add a message for case when a source is already unlinked
197
+
198
+ ### Changed
199
+
200
+ - Relicense under MIT
201
+ - Make dploy module usage silent
202
+ - Clarify message when a source argument is the same the dest argument
203
+ - Have the dploy module throw exceptions that the CLI module would handle
204
+ instead of just printing to stdout
205
+
206
+ ### Fixed
207
+
208
+ - CLI: Fix link to take only take one source
209
+ - Fix link source arg so it takes a string not a list
210
+ - Fix console output to print the correct command name e.g. stow, link, and
211
+ unstow
212
+ - Fix issue where files could be deleted during unstow folding
213
+ - Fix bug that would cause an unexpected and unhanded exception when there was
214
+ link in the destination directory that pointed to a non existing location in
215
+ the source.
216
+ - Fix issue in stow and unstow where source and dest could be the same. This
217
+ issue made it possible to delete files when unstow had the same
218
+ parameters for both source and dest. It also didn't make sense to try to stow
219
+ a directory into itself, since there will always be conflicts.
220
+
221
+ ## [0.0.3] - 2016-04-11
222
+
223
+ ### Added
224
+
225
+ - Adds support for python 3.3
226
+ - Add an unstow command to undo stowing
227
+
228
+ ### Changed
229
+
230
+ - Stow command is run in two passes and check for conflicts first before making
231
+ any changes
232
+
233
+ - General bug fixes and improvements.
dploy-0.2.0/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ AGENTS.md
dploy-0.2.0/CONTEXT.md ADDED
@@ -0,0 +1,105 @@
1
+ # dploy
2
+
3
+ dploy creates and removes symbolic links so that the contents of one directory
4
+ appear inside another, in the manner of GNU Stow, on Windows, Linux, and macOS.
5
+
6
+ ## Language
7
+
8
+ ### What gets linked
9
+
10
+ **Package**:
11
+ A directory whose contents are linked into a destination as a unit. Packages are
12
+ always named explicitly on the command line; dploy has no directory it searches
13
+ for them.
14
+ _Avoid_: source, source directory, stow package
15
+
16
+ **Destination**:
17
+ The directory a package's contents are linked into.
18
+ _Avoid_: target, target directory, dest
19
+
20
+ **Target**:
21
+ The path a symbolic link points at. A link's target is what it refers to, never
22
+ where it lives.
23
+ _Avoid_: referent, linked-to path
24
+
25
+ **Dangling link**:
26
+ A symbolic link whose target no longer exists.
27
+ _Avoid_: broken link, orphaned link, stale link
28
+
29
+ ### Dot-file names
30
+
31
+ **Dotfile translation**:
32
+ With `--dotfiles`, linking a package entry named `dot-foo` under the destination
33
+ name `.foo`. A name where `dot-` is followed by nothing or by a dot is never
34
+ translated.
35
+ _Avoid_: dot renaming, dot expansion
36
+
37
+ **Literal name**:
38
+ A package entry's own name, such as `dot-foo`.
39
+ _Avoid_: original name, source name
40
+
41
+ **Translated name**:
42
+ The name dotfile translation gives an entry, such as `.foo`. For an entry that is
43
+ not translated, it is the same as the literal name.
44
+ _Avoid_: dot name, renamed name
45
+
46
+ **Matching by target**:
47
+ How unstow finds the links to remove: a link is removed because its target is
48
+ inside the package, whichever of the entry's two names it carries. A file or link
49
+ that does not point into the package is never touched.
50
+ _Avoid_: name matching, flag matching
51
+
52
+ ### Operations
53
+
54
+ **Stow**:
55
+ Linking the contents of a package into a destination. Stowing is idempotent:
56
+ stowing an already-stowed package reports the links as already in place.
57
+ _Avoid_: install, deploy, apply
58
+
59
+ **Unstow**:
60
+ Removing the links a stow produced, recognised by their target rather than by
61
+ their name. Also idempotent.
62
+ _Avoid_: uninstall, remove, undeploy
63
+
64
+ **Clean**:
65
+ Removing dangling links in a destination that point into a given package. Unlike
66
+ unstow, it acts on links whose targets are already gone.
67
+ _Avoid_: prune, sweep, garbage collect
68
+
69
+ **Link**:
70
+ Creating a single symbolic link at an exact path, rather than linking a whole
71
+ package's contents. Where the distinction matters, say "the link command" for
72
+ the operation and "a symbolic link" for the thing.
73
+ _Avoid_: symlink (as the name of the operation)
74
+
75
+ **Folding**:
76
+ Replacing a destination directory whose links all point into one package
77
+ directory with a single link to that directory.
78
+ _Avoid_: collapsing, compacting
79
+
80
+ **Unfolding**:
81
+ Replacing a link to a directory with a real directory containing links to that
82
+ directory's contents, so a second package can contribute entries alongside the
83
+ first.
84
+ _Avoid_: expanding, exploding
85
+
86
+ ### How work is described
87
+
88
+ **Action**:
89
+ A single filesystem change dploy intends to make: creating a link, removing a
90
+ link, creating a directory, removing a directory. Actions are collected and
91
+ validated as a set before any of them run, so a command either applies fully or
92
+ not at all.
93
+ _Avoid_: operation, step, task, change
94
+
95
+ **Conflict**:
96
+ A reason a collected set of actions cannot be applied, such as a destination
97
+ entry that is not a link dploy created, or two packages claiming the same
98
+ destination path. Conflicts are reported together and abort the command before
99
+ any action runs.
100
+ _Avoid_: error, clash, collision
101
+
102
+ **Ignore pattern**:
103
+ A glob that excludes matching entries of a package from being linked. Patterns
104
+ come from the command line or from a `.dploystowignore` file beside the package.
105
+ _Avoid_: exclude pattern, skip pattern, filter
dploy-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.5
2
+ Name: dploy
3
+ Version: 0.2.0
4
+ Summary: Provides functionality similar to GNU Stow as a cross platform CLI tool and Python 3 module
5
+ Project-URL: Homepage, https://github.com/arecarn/dploy
6
+ Author-email: Ryan Carney <arecarn@gmail.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE.txt
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Utilities
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+
21
+ # Dploy
22
+
23
+ Dploy is a tool for creating symbolic links similarly to [GNU
24
+ Stow](https://www.gnu.org/software/stow/). It is provided as a CLI tool and
25
+ Python 3.10+ module and supports Windows, Linux, and OSX.
26
+
27
+ Dploy's command `stow` creates symbolic links to the contents of packages in a
28
+ specified destination directory. Repeating the
29
+ `stow` command with the same arguments will confirm that the contents of the
30
+ package have been symbolically linked.
31
+
32
+ Dploy's command `unstow` removes symbolic links that resulted from `stow`
33
+ commands. Repeating the `unstow` command with the same arguments will confirm
34
+ that the links to stowed packages have been removed.
35
+
36
+ ## Installation
37
+
38
+ * Latest Release: `pip install dploy`
39
+ * Development Version: `pip install git+https://github.com/arecarn/dploy.git`
40
+
41
+ ## Basic CLI Usage
42
+
43
+ * `dploy stow <package-directory>... <destination-directory>`
44
+ * `dploy unstow <package-directory>... <destination-directory>`
45
+ * `dploy clean <package-directory>... <destination-directory>`
46
+ * `dploy --help`
47
+
48
+ ### Dot-file names
49
+
50
+ `stow --dotfiles` stows a package entry named `dot-something` as a destination
51
+ entry named `.something`:
52
+
53
+ ```
54
+ dploy stow --dotfiles ~/dotfiles/bash ~
55
+ # ~/dotfiles/bash/dot-bashrc -> ~/.bashrc
56
+ ```
57
+
58
+ This keeps the files visible in the package directory while they land as
59
+ dot-files in the destination.
60
+
61
+ `unstow` does not need `--dotfiles`. It finds links by what they point at, so it
62
+ removes them whether they are named `dot-something` or `.something`. It still
63
+ accepts the flag, for symmetry with `stow`; with it, an unrelated file already
64
+ named `.something` is reported as a conflict. `clean` is unaffected for the
65
+ same reason.
66
+
67
+ An entry whose name is `dot-` followed by nothing or by a dot (`dot-`,
68
+ `dot-.`, `dot-..`, `dot-.hidden`) is left untranslated, as GNU Stow does; the
69
+ first two would otherwise resolve to the destination directory or its parent.
70
+
71
+ ## Rationale
72
+
73
+ Dploy started out as simple Python script to create symbolic links to my
74
+ dotfiles for Windows, Mac, and Linux. Over time I keep improving and tweaking my
75
+ script to suit my needs, but I was running into a problem. Keeping all the
76
+ files I wanted to link in a config file was becoming a real pain in the neck.
77
+
78
+ I started looking for another solution to solve my problem, and found many
79
+ alternatives but none of them seemed to be a good fit. The solution that seemed
80
+ the most promising was using GNU Stow. It seemed like the most simple elegant
81
+ solution to the problem. The only issue was that it didn't support Windows.
82
+
83
+ Then I thought to myself, why can't I just create my own version of Stow that
84
+ work on Windows, Linux and OSX. So after that my I started morphing
85
+ simple python script into what would become Dploy and learned a lot more about
86
+ python in the process.
87
+
88
+ ## How does it compare with GNU Stow?
89
+
90
+ Below are just a few few major points of comparison between GNU stow and Dploy.
91
+
92
+ * Like GNU Stow Dploy runs in two passes. First by collecting the actions
93
+ required to complete the command and verifying that the command can
94
+ completed without any issues. If no issues are detected then the second
95
+ pass executes these actions are execute to complete the command. Otherwise
96
+ Dploy will exit and indicate why the command can not be completed. This way a
97
+ stow or unstow operation is atomic and never partially done.
98
+
99
+ * Like Stow, Dploy supports tree folding and tree unfolding. Like Stow's
100
+ `--no-folding`, passing `--no-folding` to `stow` or `unstow` disables
101
+ folding, so each file gets its own link inside a real directory.
102
+
103
+ * Unlike Stow, Dploy requires an explicit package(s) and a destination
104
+ directory.
105
+
106
+ * Unlike Stow, Dploy does not have any concept of ownership, but will only
107
+ operate on symbolic links and the creation or removal of directories for these
108
+ symbolic links.
109
+
110
+ * Unlike Stow, Dploy's `unstow` removes a destination directory that becomes
111
+ empty as a result of removing its symbolic links, even if that directory
112
+ existed before `stow` created any links inside it. Dploy keeps no state
113
+ across invocations, so it cannot distinguish a directory it created from
114
+ one that already existed.
115
+
116
+ * `stow`'s `--skip-conflicts` flag is the one opt-in exception to the
117
+ atomicity described above: files that conflict with an existing,
118
+ unmanaged destination entry are skipped and reported, while every other
119
+ file in the package is still linked. `dploy` exits with status `2` when
120
+ this happens, so a script can tell a partial stow apart from a full
121
+ success (status `0`) or a fatal error (status `1`).