dploy 0.1.1__tar.gz → 0.1.3__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.
- dploy-0.1.3/PKG-INFO +78 -0
- dploy-0.1.3/README.md +63 -0
- dploy-0.1.3/dploy/__init__.py +35 -0
- {dploy-0.1.1 → dploy-0.1.3}/dploy/__main__.py +17 -18
- {dploy-0.1.1 → dploy-0.1.3}/dploy/actions.py +98 -28
- dploy-0.1.3/dploy/cli.py +114 -0
- dploy-0.1.3/dploy/error.py +163 -0
- dploy-0.1.3/dploy/ignore.py +67 -0
- dploy-0.1.3/dploy/linkcmd.py +81 -0
- dploy-0.1.3/dploy/main.py +125 -0
- dploy-0.1.3/dploy/stowcmd.py +442 -0
- {dploy-0.1.1 → dploy-0.1.3}/dploy/utils.py +123 -98
- dploy-0.1.3/dploy/version.py +5 -0
- dploy-0.1.3/pyproject.toml +36 -0
- dploy-0.1.1/.pylintrc +0 -7
- dploy-0.1.1/CHANGELOG.md +0 -116
- dploy-0.1.1/MANIFEST.in +0 -12
- dploy-0.1.1/PKG-INFO +0 -36
- dploy-0.1.1/README.md +0 -15
- dploy-0.1.1/conftest.py +0 -0
- dploy-0.1.1/dploy/__init__.py +0 -30
- dploy-0.1.1/dploy/__init__.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/__init__.cpython-33.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/__init__.cpython-35.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/__main__.cpython-33.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/__main__.cpython-35.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/actions.cpython-33.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/actions.cpython-35.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/cli.cpython-33.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/cli.cpython-35.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/errors.cpython-33.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/errors.cpython-35.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/main.cpython-33.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/main.cpython-35.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/utils.cpython-33.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/utils.cpython-35.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/version.cpython-33.pyc +0 -0
- dploy-0.1.1/dploy/__pycache__/version.cpython-35.pyc +0 -0
- dploy-0.1.1/dploy/cli.py +0 -99
- dploy-0.1.1/dploy/errors.py +0 -86
- dploy-0.1.1/dploy/main.py +0 -579
- dploy-0.1.1/dploy/version.py +0 -18
- dploy-0.1.1/dploy.egg-info/PKG-INFO +0 -36
- dploy-0.1.1/dploy.egg-info/SOURCES.txt +0 -63
- dploy-0.1.1/dploy.egg-info/dependency_links.txt +0 -1
- dploy-0.1.1/dploy.egg-info/entry_points.txt +0 -3
- dploy-0.1.1/dploy.egg-info/top_level.txt +0 -1
- dploy-0.1.1/invoke.yaml +0 -2
- dploy-0.1.1/requirements.txt +0 -11
- dploy-0.1.1/setup.cfg +0 -8
- dploy-0.1.1/setup.py +0 -49
- dploy-0.1.1/tasks.py +0 -78
- dploy-0.1.1/tests/__pycache__/conftest.cpython-33-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/conftest.cpython-33.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/conftest.cpython-35.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/test_cli.cpython-33-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/test_cli.cpython-35-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/test_ignore.cpython-33-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/test_ignore.cpython-35-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/test_link.cpython-33-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/test_link.cpython-35-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/test_stow.cpython-33-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/test_stow.cpython-35-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/test_unstow.cpython-33-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/test_unstow.cpython-35-PYTEST.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/utils.cpython-33.pyc +0 -0
- dploy-0.1.1/tests/__pycache__/utils.cpython-35.pyc +0 -0
- dploy-0.1.1/tests/conftest.py +0 -173
- dploy-0.1.1/tests/test_cli.py +0 -78
- dploy-0.1.1/tests/test_ignore.py +0 -34
- dploy-0.1.1/tests/test_link.py +0 -63
- dploy-0.1.1/tests/test_stow.py +0 -216
- dploy-0.1.1/tests/test_unstow.py +0 -193
- dploy-0.1.1/tests/utils.py +0 -100
- {dploy-0.1.1 → dploy-0.1.3}/LICENSE.txt +0 -0
dploy-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dploy
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Provides functionality similar to GNU Stow as a cross platform CLI tool and Python 3 module
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE.txt
|
|
7
|
+
Author: Ryan Carney
|
|
8
|
+
Author-email: arecarn@gmail.com
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Topic :: Utilities
|
|
12
|
+
Project-URL: Homepage, https://github.com/arecarn/dploy
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# Dploy
|
|
16
|
+
|
|
17
|
+
Dploy is a tool for creating symbolic links similarly to [GNU
|
|
18
|
+
Stow](https://www.gnu.org/software/stow/). It is provided as a CLI tool and
|
|
19
|
+
Python 3.10+ module and supports Windows, Linux, and OSX.
|
|
20
|
+
|
|
21
|
+
Dploy's command `stow` creates symbolic links to the contents of source
|
|
22
|
+
directories or packages in a specified destination directory. Repeating the
|
|
23
|
+
`stow` command with the same arguments will confirm that the contents of the
|
|
24
|
+
package have been symbolically linked.
|
|
25
|
+
|
|
26
|
+
Dploy's command `unstow` removes symbolic links that resulted from `stow`
|
|
27
|
+
commands. Repeating the `unstow` command with the same arguments will confirm
|
|
28
|
+
that the links to stowed packages have been removed.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
* Latest Release: `pip install dploy`
|
|
33
|
+
* Development Version: `pip install git+https://github.com/arecarn/dploy.git`
|
|
34
|
+
|
|
35
|
+
## Basic CLI Usage
|
|
36
|
+
|
|
37
|
+
* `dploy stow <source-directory>... <destination-directory>`
|
|
38
|
+
* `dploy unstow <source-directory>... <destination-directory>`
|
|
39
|
+
* `dploy clean <source-directory>... <destination-directory>`
|
|
40
|
+
* `dploy --help`
|
|
41
|
+
|
|
42
|
+
## Rationale
|
|
43
|
+
|
|
44
|
+
Dploy started out as simple Python script to create symbolic links to my
|
|
45
|
+
dotfiles for Windows, Mac, and Linux. Over time I keep improving and tweaking my
|
|
46
|
+
script to suit my needs, but I was running into a problem. Keeping all the
|
|
47
|
+
files I wanted to link in a config file was becoming a real pain in the neck.
|
|
48
|
+
|
|
49
|
+
I started looking for another solution to solve my problem, and found many
|
|
50
|
+
alternatives but none of them seemed to be a good fit. The solution that seemed
|
|
51
|
+
the most promising was using GNU Stow. It seemed like the most simple elegant
|
|
52
|
+
solution to the problem. The only issue was that it didn't support Windows.
|
|
53
|
+
|
|
54
|
+
Then I thought to myself, why can't I just create my own version of Stow that
|
|
55
|
+
work on Windows, Linux and OSX. So after that my I started morphing
|
|
56
|
+
simple python script into what would become Dploy and learned a lot more about
|
|
57
|
+
python in the process.
|
|
58
|
+
|
|
59
|
+
## How does it compare with GNU Stow?
|
|
60
|
+
|
|
61
|
+
Below are just a few few major points of comparison between GNU stow and Dploy.
|
|
62
|
+
|
|
63
|
+
* Like GNU Stow Dploy runs in two passes. First by collecting the actions
|
|
64
|
+
required to complete the command and verifying that the command can
|
|
65
|
+
completed without any issues. If no issues are detected then the second
|
|
66
|
+
pass executes these actions are execute to complete the command. Otherwise
|
|
67
|
+
Dploy will exit and indicate why the command can not be completed. This way a
|
|
68
|
+
stow or unstow operation is atomic and never partially done.
|
|
69
|
+
|
|
70
|
+
* Like Stow, Dploy supports tree folding and tree unfolding.
|
|
71
|
+
|
|
72
|
+
* Unlike Stow, Dploy requires an explicit source(s) and a destination
|
|
73
|
+
directory.
|
|
74
|
+
|
|
75
|
+
* Unlike Stow, Dploy does not have any concept of ownership, but will only
|
|
76
|
+
operate on symbolic links and the creation or removal of directories for these
|
|
77
|
+
symbolic links.
|
|
78
|
+
|
dploy-0.1.3/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Dploy
|
|
2
|
+
|
|
3
|
+
Dploy is a tool for creating symbolic links similarly to [GNU
|
|
4
|
+
Stow](https://www.gnu.org/software/stow/). It is provided as a CLI tool and
|
|
5
|
+
Python 3.10+ module and supports Windows, Linux, and OSX.
|
|
6
|
+
|
|
7
|
+
Dploy's command `stow` creates symbolic links to the contents of source
|
|
8
|
+
directories or packages in a specified destination directory. Repeating the
|
|
9
|
+
`stow` command with the same arguments will confirm that the contents of the
|
|
10
|
+
package have been symbolically linked.
|
|
11
|
+
|
|
12
|
+
Dploy's command `unstow` removes symbolic links that resulted from `stow`
|
|
13
|
+
commands. Repeating the `unstow` command with the same arguments will confirm
|
|
14
|
+
that the links to stowed packages have been removed.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
* Latest Release: `pip install dploy`
|
|
19
|
+
* Development Version: `pip install git+https://github.com/arecarn/dploy.git`
|
|
20
|
+
|
|
21
|
+
## Basic CLI Usage
|
|
22
|
+
|
|
23
|
+
* `dploy stow <source-directory>... <destination-directory>`
|
|
24
|
+
* `dploy unstow <source-directory>... <destination-directory>`
|
|
25
|
+
* `dploy clean <source-directory>... <destination-directory>`
|
|
26
|
+
* `dploy --help`
|
|
27
|
+
|
|
28
|
+
## Rationale
|
|
29
|
+
|
|
30
|
+
Dploy started out as simple Python script to create symbolic links to my
|
|
31
|
+
dotfiles for Windows, Mac, and Linux. Over time I keep improving and tweaking my
|
|
32
|
+
script to suit my needs, but I was running into a problem. Keeping all the
|
|
33
|
+
files I wanted to link in a config file was becoming a real pain in the neck.
|
|
34
|
+
|
|
35
|
+
I started looking for another solution to solve my problem, and found many
|
|
36
|
+
alternatives but none of them seemed to be a good fit. The solution that seemed
|
|
37
|
+
the most promising was using GNU Stow. It seemed like the most simple elegant
|
|
38
|
+
solution to the problem. The only issue was that it didn't support Windows.
|
|
39
|
+
|
|
40
|
+
Then I thought to myself, why can't I just create my own version of Stow that
|
|
41
|
+
work on Windows, Linux and OSX. So after that my I started morphing
|
|
42
|
+
simple python script into what would become Dploy and learned a lot more about
|
|
43
|
+
python in the process.
|
|
44
|
+
|
|
45
|
+
## How does it compare with GNU Stow?
|
|
46
|
+
|
|
47
|
+
Below are just a few few major points of comparison between GNU stow and Dploy.
|
|
48
|
+
|
|
49
|
+
* Like GNU Stow Dploy runs in two passes. First by collecting the actions
|
|
50
|
+
required to complete the command and verifying that the command can
|
|
51
|
+
completed without any issues. If no issues are detected then the second
|
|
52
|
+
pass executes these actions are execute to complete the command. Otherwise
|
|
53
|
+
Dploy will exit and indicate why the command can not be completed. This way a
|
|
54
|
+
stow or unstow operation is atomic and never partially done.
|
|
55
|
+
|
|
56
|
+
* Like Stow, Dploy supports tree folding and tree unfolding.
|
|
57
|
+
|
|
58
|
+
* Unlike Stow, Dploy requires an explicit source(s) and a destination
|
|
59
|
+
directory.
|
|
60
|
+
|
|
61
|
+
* Unlike Stow, Dploy does not have any concept of ownership, but will only
|
|
62
|
+
operate on symbolic links and the creation or removal of directories for these
|
|
63
|
+
symbolic links.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
dploy script is an attempt at creating a clone of GNU stow that will work on
|
|
3
|
+
Windows as well as *nix
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from dploy import linkcmd
|
|
7
|
+
from dploy import stowcmd
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def stow(sources, dest, is_silent=True, is_dry_run=False, ignore_patterns=None):
|
|
11
|
+
"""
|
|
12
|
+
sub command stow
|
|
13
|
+
"""
|
|
14
|
+
stowcmd.Stow(sources, dest, is_silent, is_dry_run, ignore_patterns)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def unstow(sources, dest, is_silent=True, is_dry_run=False, ignore_patterns=None):
|
|
18
|
+
"""
|
|
19
|
+
sub command unstow
|
|
20
|
+
"""
|
|
21
|
+
stowcmd.UnStow(sources, dest, is_silent, is_dry_run, ignore_patterns)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def clean(sources, dest, is_silent=True, is_dry_run=False, ignore_patterns=None):
|
|
25
|
+
"""
|
|
26
|
+
sub command clean
|
|
27
|
+
"""
|
|
28
|
+
stowcmd.Clean(sources, dest, is_silent, is_dry_run, ignore_patterns)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def link(source, dest, is_silent=True, is_dry_run=False, ignore_patterns=None):
|
|
32
|
+
"""
|
|
33
|
+
sub command link
|
|
34
|
+
"""
|
|
35
|
+
linkcmd.Link(source, dest, is_silent, is_dry_run, ignore_patterns)
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
main()
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
The entry point when dploy is called as a module
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from dploy import cli
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main():
|
|
10
|
+
"""
|
|
11
|
+
main entry point when using dploy from the command line
|
|
12
|
+
"""
|
|
13
|
+
cli.run()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__":
|
|
17
|
+
main()
|
|
@@ -3,25 +3,86 @@ This module contains the actions that are combined to perform dploy's sub
|
|
|
3
3
|
commands
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
from collections import defaultdict
|
|
7
|
+
from dploy import utils
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
class
|
|
10
|
+
class Actions:
|
|
11
|
+
"""
|
|
12
|
+
A class that collects and executes action objects
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, is_silent, is_dry_run):
|
|
16
|
+
self.actions = []
|
|
17
|
+
self.is_silent = is_silent
|
|
18
|
+
self.is_dry_run = is_dry_run
|
|
19
|
+
|
|
20
|
+
def add(self, action):
|
|
21
|
+
"""
|
|
22
|
+
Adds an action
|
|
23
|
+
"""
|
|
24
|
+
self.actions.append(action)
|
|
25
|
+
|
|
26
|
+
def execute(self):
|
|
27
|
+
"""
|
|
28
|
+
Prints and executes actions
|
|
29
|
+
"""
|
|
30
|
+
for action in self.actions:
|
|
31
|
+
if not self.is_silent:
|
|
32
|
+
print(action)
|
|
33
|
+
if not self.is_dry_run:
|
|
34
|
+
action.execute()
|
|
35
|
+
|
|
36
|
+
def get_unlink_actions(self):
|
|
37
|
+
"""
|
|
38
|
+
get the current Unlink() actions from the self.actions
|
|
39
|
+
"""
|
|
40
|
+
return [a for a in self.actions if isinstance(a, UnLink)]
|
|
41
|
+
|
|
42
|
+
def get_unlink_target_parents(self):
|
|
43
|
+
"""
|
|
44
|
+
Get list of the parents for the current Unlink() actions from
|
|
45
|
+
self.actions
|
|
46
|
+
"""
|
|
47
|
+
unlink_actions = self.get_unlink_actions()
|
|
48
|
+
# sort for deterministic output
|
|
49
|
+
return sorted(set([a.target.parent for a in unlink_actions]))
|
|
50
|
+
|
|
51
|
+
def get_unlink_targets(self):
|
|
52
|
+
"""
|
|
53
|
+
Get list of the targets for the current Unlink() actions from
|
|
54
|
+
self.actions
|
|
55
|
+
"""
|
|
56
|
+
unlink_actions = self.get_unlink_actions()
|
|
57
|
+
return [a.target for a in unlink_actions]
|
|
58
|
+
|
|
59
|
+
def get_duplicates(self):
|
|
60
|
+
"""
|
|
61
|
+
return a tuple containing tuples with the following structure
|
|
62
|
+
(link destination, [indices of duplicates])
|
|
63
|
+
"""
|
|
64
|
+
tally = defaultdict(list)
|
|
65
|
+
for index, action in enumerate(self.actions):
|
|
66
|
+
if isinstance(action, SymbolicLink):
|
|
67
|
+
tally[action.dest].append(index)
|
|
68
|
+
# sort for deterministic output
|
|
69
|
+
return sorted([indices for _, indices in tally.items() if len(indices) > 1])
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class AbstractBaseAction:
|
|
10
73
|
# pylint: disable=too-few-public-methods
|
|
11
74
|
"""
|
|
12
75
|
An abstract base class that define the interface for actions
|
|
13
76
|
"""
|
|
14
|
-
def __init__(self):
|
|
15
|
-
pass
|
|
16
77
|
|
|
17
|
-
def
|
|
78
|
+
def __init__(self):
|
|
18
79
|
pass
|
|
19
80
|
|
|
20
81
|
def execute(self):
|
|
21
82
|
"""
|
|
22
|
-
function that executes
|
|
83
|
+
function that executes the logic of each concrete action
|
|
23
84
|
"""
|
|
24
|
-
|
|
85
|
+
pass
|
|
25
86
|
|
|
26
87
|
|
|
27
88
|
class SymbolicLink(AbstractBaseAction):
|
|
@@ -29,6 +90,7 @@ class SymbolicLink(AbstractBaseAction):
|
|
|
29
90
|
"""
|
|
30
91
|
Action to create a symbolic link relative to the source of the link
|
|
31
92
|
"""
|
|
93
|
+
|
|
32
94
|
def __init__(self, subcmd, source, dest):
|
|
33
95
|
super().__init__()
|
|
34
96
|
self.source = source
|
|
@@ -36,12 +98,13 @@ class SymbolicLink(AbstractBaseAction):
|
|
|
36
98
|
self.subcmd = subcmd
|
|
37
99
|
self.dest = dest
|
|
38
100
|
|
|
39
|
-
def
|
|
101
|
+
def execute(self):
|
|
40
102
|
self.dest.symlink_to(self.source_relative)
|
|
41
103
|
|
|
42
104
|
def __repr__(self):
|
|
43
105
|
return "dploy {subcmd}: link {dest} => {source}".format(
|
|
44
|
-
subcmd=self.subcmd, dest=self.dest, source=self.source_relative
|
|
106
|
+
subcmd=self.subcmd, dest=self.dest, source=self.source_relative
|
|
107
|
+
)
|
|
45
108
|
|
|
46
109
|
|
|
47
110
|
class AlreadyLinked(AbstractBaseAction):
|
|
@@ -49,6 +112,7 @@ class AlreadyLinked(AbstractBaseAction):
|
|
|
49
112
|
"""
|
|
50
113
|
Action to used to print an already linked message
|
|
51
114
|
"""
|
|
115
|
+
|
|
52
116
|
def __init__(self, subcmd, source, dest):
|
|
53
117
|
super().__init__()
|
|
54
118
|
self.source = source
|
|
@@ -56,14 +120,13 @@ class AlreadyLinked(AbstractBaseAction):
|
|
|
56
120
|
self.dest = dest
|
|
57
121
|
self.subcmd = subcmd
|
|
58
122
|
|
|
59
|
-
def
|
|
123
|
+
def execute(self):
|
|
60
124
|
pass
|
|
61
125
|
|
|
62
126
|
def __repr__(self):
|
|
63
127
|
return "dploy {subcmd}: already linked {dest} => {source}".format(
|
|
64
|
-
subcmd=self.subcmd,
|
|
65
|
-
|
|
66
|
-
dest=self.dest)
|
|
128
|
+
subcmd=self.subcmd, source=self.source_relative, dest=self.dest
|
|
129
|
+
)
|
|
67
130
|
|
|
68
131
|
|
|
69
132
|
class AlreadyUnlinked(AbstractBaseAction):
|
|
@@ -71,6 +134,7 @@ class AlreadyUnlinked(AbstractBaseAction):
|
|
|
71
134
|
"""
|
|
72
135
|
Action to used to print an already unlinked message
|
|
73
136
|
"""
|
|
137
|
+
|
|
74
138
|
def __init__(self, subcmd, source, dest):
|
|
75
139
|
super().__init__()
|
|
76
140
|
self.source = source
|
|
@@ -78,14 +142,13 @@ class AlreadyUnlinked(AbstractBaseAction):
|
|
|
78
142
|
self.dest = dest
|
|
79
143
|
self.subcmd = subcmd
|
|
80
144
|
|
|
81
|
-
def
|
|
145
|
+
def execute(self):
|
|
82
146
|
pass
|
|
83
147
|
|
|
84
148
|
def __repr__(self):
|
|
85
149
|
return "dploy {subcmd}: already unlinked {dest} => {source}".format(
|
|
86
|
-
subcmd=self.subcmd,
|
|
87
|
-
|
|
88
|
-
dest=self.dest)
|
|
150
|
+
subcmd=self.subcmd, source=self.source_relative, dest=self.dest
|
|
151
|
+
)
|
|
89
152
|
|
|
90
153
|
|
|
91
154
|
class UnLink(AbstractBaseAction):
|
|
@@ -93,53 +156,60 @@ class UnLink(AbstractBaseAction):
|
|
|
93
156
|
"""
|
|
94
157
|
Action to unlink a symbolic link
|
|
95
158
|
"""
|
|
159
|
+
|
|
96
160
|
def __init__(self, subcmd, target):
|
|
97
161
|
super().__init__()
|
|
98
162
|
self.target = target
|
|
99
163
|
self.subcmd = subcmd
|
|
100
164
|
|
|
101
|
-
def
|
|
165
|
+
def execute(self):
|
|
102
166
|
if not self.target.is_symlink():
|
|
103
|
-
#pylint: disable=line-too-long
|
|
104
|
-
raise RuntimeError(
|
|
167
|
+
# pylint: disable=line-too-long
|
|
168
|
+
raise RuntimeError(
|
|
169
|
+
"dploy detected and aborted an attempt to unlink a non-symlink {target} this is a bug and should be reported".format(
|
|
170
|
+
target=self.target
|
|
171
|
+
)
|
|
172
|
+
)
|
|
105
173
|
self.target.unlink()
|
|
106
174
|
|
|
107
175
|
def __repr__(self):
|
|
108
|
-
source_relative = utils.get_relative_path(self.target.resolve(), self.target.parent)
|
|
109
176
|
return "dploy {subcmd}: unlink {target} => {source}".format(
|
|
110
|
-
subcmd=self.subcmd,
|
|
111
|
-
|
|
112
|
-
|
|
177
|
+
subcmd=self.subcmd, target=self.target, source=utils.readlink(self.target)
|
|
178
|
+
)
|
|
179
|
+
|
|
113
180
|
|
|
114
181
|
class MakeDirectory(AbstractBaseAction):
|
|
115
182
|
# pylint: disable=too-few-public-methods
|
|
116
183
|
"""
|
|
117
184
|
Action to create a directory
|
|
118
185
|
"""
|
|
186
|
+
|
|
119
187
|
def __init__(self, subcmd, target):
|
|
120
188
|
super().__init__()
|
|
121
189
|
self.target = target
|
|
122
190
|
self.subcmd = subcmd
|
|
123
191
|
|
|
124
|
-
def
|
|
192
|
+
def execute(self):
|
|
125
193
|
self.target.mkdir()
|
|
126
194
|
|
|
127
195
|
def __repr__(self):
|
|
128
196
|
return "dploy {subcmd}: make directory {target}".format(
|
|
129
|
-
target=self.target,
|
|
130
|
-
|
|
197
|
+
target=self.target, subcmd=self.subcmd
|
|
198
|
+
)
|
|
199
|
+
|
|
131
200
|
|
|
132
201
|
class RemoveDirectory(AbstractBaseAction):
|
|
133
202
|
# pylint: disable=too-few-public-methods
|
|
134
203
|
"""
|
|
135
204
|
Action to remove a directory
|
|
136
205
|
"""
|
|
206
|
+
|
|
137
207
|
def __init__(self, subcmd, target):
|
|
138
208
|
super().__init__()
|
|
139
209
|
self.target = target
|
|
140
210
|
self.subcmd = subcmd
|
|
141
211
|
|
|
142
|
-
def
|
|
212
|
+
def execute(self):
|
|
143
213
|
self.target.rmdir()
|
|
144
214
|
|
|
145
215
|
def __repr__(self):
|
dploy-0.1.3/dploy/cli.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The command line interface
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import argparse
|
|
7
|
+
from dploy import linkcmd
|
|
8
|
+
from dploy import stowcmd
|
|
9
|
+
from dploy import version
|
|
10
|
+
from dploy.error import DployError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def add_ignore_argument(parser):
|
|
14
|
+
"""
|
|
15
|
+
adds the ignore argument to a subcmd parser
|
|
16
|
+
"""
|
|
17
|
+
parser.add_argument(
|
|
18
|
+
"--ignore",
|
|
19
|
+
dest="ignore_patterns",
|
|
20
|
+
action="append",
|
|
21
|
+
default=None,
|
|
22
|
+
help="glob pattern used to ignore directories",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def create_parser():
|
|
27
|
+
"""
|
|
28
|
+
create the CLI argument parser
|
|
29
|
+
"""
|
|
30
|
+
parser = argparse.ArgumentParser(prog="dploy")
|
|
31
|
+
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--version",
|
|
34
|
+
action="version",
|
|
35
|
+
version="%(prog)s {version}".format(version=version.__version__),
|
|
36
|
+
)
|
|
37
|
+
parser.add_argument(
|
|
38
|
+
"--silent", dest="is_silent", action="store_true", help="suppress all output"
|
|
39
|
+
)
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--dry-run",
|
|
42
|
+
dest="is_dry_run",
|
|
43
|
+
action="store_true",
|
|
44
|
+
help="show what would be done without doing it",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
sub_parsers = parser.add_subparsers(dest="subcmd")
|
|
48
|
+
|
|
49
|
+
stow_parser = sub_parsers.add_parser("stow")
|
|
50
|
+
stow_parser.add_argument("source", nargs="+", help="source directory to stow")
|
|
51
|
+
stow_parser.add_argument("dest", help="destination path to stow into")
|
|
52
|
+
add_ignore_argument(stow_parser)
|
|
53
|
+
|
|
54
|
+
unstow_parser = sub_parsers.add_parser("unstow")
|
|
55
|
+
unstow_parser.add_argument(
|
|
56
|
+
"source", nargs="+", help="source directory to unstow from"
|
|
57
|
+
)
|
|
58
|
+
unstow_parser.add_argument("dest", help="destination path to unstow")
|
|
59
|
+
add_ignore_argument(unstow_parser)
|
|
60
|
+
|
|
61
|
+
clean_parser = sub_parsers.add_parser("clean")
|
|
62
|
+
clean_parser.add_argument(
|
|
63
|
+
"source", nargs="+", help="source directory to clean from"
|
|
64
|
+
)
|
|
65
|
+
clean_parser.add_argument("dest", help="destination path to clean")
|
|
66
|
+
add_ignore_argument(clean_parser)
|
|
67
|
+
|
|
68
|
+
link_parser = sub_parsers.add_parser("link")
|
|
69
|
+
link_parser.add_argument("source", help="source file or directory to link")
|
|
70
|
+
link_parser.add_argument("dest", help="destination path to link")
|
|
71
|
+
add_ignore_argument(link_parser)
|
|
72
|
+
return parser
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def run(arguments=None):
|
|
76
|
+
"""
|
|
77
|
+
interpret the parser arguments and execute the corresponding commands
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
subcmd_map = {
|
|
81
|
+
"stow": stowcmd.Stow,
|
|
82
|
+
"unstow": stowcmd.UnStow,
|
|
83
|
+
"clean": stowcmd.Clean,
|
|
84
|
+
"link": linkcmd.Link,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
parser = create_parser()
|
|
89
|
+
|
|
90
|
+
if arguments is None:
|
|
91
|
+
args = parser.parse_args()
|
|
92
|
+
else:
|
|
93
|
+
args = parser.parse_args(arguments)
|
|
94
|
+
|
|
95
|
+
if args.subcmd in subcmd_map:
|
|
96
|
+
subcmd = subcmd_map[args.subcmd]
|
|
97
|
+
else:
|
|
98
|
+
parser.print_help()
|
|
99
|
+
sys.exit(0)
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
subcmd(
|
|
103
|
+
args.source,
|
|
104
|
+
args.dest,
|
|
105
|
+
is_silent=args.is_silent,
|
|
106
|
+
is_dry_run=args.is_dry_run,
|
|
107
|
+
ignore_patterns=args.ignore_patterns,
|
|
108
|
+
)
|
|
109
|
+
except DployError:
|
|
110
|
+
sys.exit(1)
|
|
111
|
+
|
|
112
|
+
except (KeyboardInterrupt) as error:
|
|
113
|
+
print(error, file=sys.stderr)
|
|
114
|
+
sys.exit(130)
|