miss-lemon 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.
- miss_lemon-0.2.0/LICENCE.txt +21 -0
- miss_lemon-0.2.0/MANIFEST.in +9 -0
- miss_lemon-0.2.0/PKG-INFO +76 -0
- miss_lemon-0.2.0/README.rst +33 -0
- miss_lemon-0.2.0/copy_tests/__init__.py +0 -0
- miss_lemon-0.2.0/copy_tests/conftest.py +97 -0
- miss_lemon-0.2.0/miss_lemon/__init__.py +6 -0
- miss_lemon-0.2.0/miss_lemon/cli/__init__.py +0 -0
- miss_lemon-0.2.0/miss_lemon/cli/check.py +126 -0
- miss_lemon-0.2.0/miss_lemon/cli/entrypoint.py +70 -0
- miss_lemon-0.2.0/miss_lemon/cli/rename.py +86 -0
- miss_lemon-0.2.0/miss_lemon/cli/version.py +15 -0
- miss_lemon-0.2.0/miss_lemon/diff.py +214 -0
- miss_lemon-0.2.0/miss_lemon/exceptions.py +20 -0
- miss_lemon-0.2.0/miss_lemon/logger.py +40 -0
- miss_lemon-0.2.0/miss_lemon/models/__init__.py +0 -0
- miss_lemon-0.2.0/miss_lemon/models/lists.py +38 -0
- miss_lemon-0.2.0/miss_lemon/models/mixins/__init__.py +0 -0
- miss_lemon-0.2.0/miss_lemon/models/mixins/export.py +92 -0
- miss_lemon-0.2.0/miss_lemon/models/resource.py +207 -0
- miss_lemon-0.2.0/miss_lemon/renamer.py +91 -0
- miss_lemon-0.2.0/miss_lemon/utils/__init__.py +0 -0
- miss_lemon-0.2.0/miss_lemon/utils/jsons.py +40 -0
- miss_lemon-0.2.0/miss_lemon/utils/tests.py +19 -0
- miss_lemon-0.2.0/miss_lemon/walker.py +224 -0
- miss_lemon-0.2.0/miss_lemon.egg-info/PKG-INFO +76 -0
- miss_lemon-0.2.0/miss_lemon.egg-info/SOURCES.txt +34 -0
- miss_lemon-0.2.0/miss_lemon.egg-info/dependency_links.txt +1 -0
- miss_lemon-0.2.0/miss_lemon.egg-info/entry_points.txt +2 -0
- miss_lemon-0.2.0/miss_lemon.egg-info/requires.txt +24 -0
- miss_lemon-0.2.0/miss_lemon.egg-info/top_level.txt +2 -0
- miss_lemon-0.2.0/miss_lemon.egg-info/zip-safe +1 -0
- miss_lemon-0.2.0/pyproject.toml +3 -0
- miss_lemon-0.2.0/setup.cfg +96 -0
- miss_lemon-0.2.0/setup.py +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, David Thenon
|
|
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,76 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: miss-lemon
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Rename a file structure with auto incremented prefix number
|
|
5
|
+
Home-page: https://github.com/sveetch/miss-lemon
|
|
6
|
+
Author: David Thenon
|
|
7
|
+
Author-email: sveetch@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Source Code, https://github.com/sveetch/miss-lemon
|
|
10
|
+
Project-URL: Issue Tracker, https://github.com/sveetch/miss-lemon/issues
|
|
11
|
+
Project-URL: Changelog, https://miss-lemon.readthedocs.io/en/latest/history.html
|
|
12
|
+
Project-URL: Documentation, https://miss-lemon.readthedocs.io/
|
|
13
|
+
Keywords: Python
|
|
14
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Natural Language :: English
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/x-rst
|
|
23
|
+
License-File: LICENCE.txt
|
|
24
|
+
Requires-Dist: click>=8.0
|
|
25
|
+
Requires-Dist: colorlog
|
|
26
|
+
Requires-Dist: bigtree>=1.5.3
|
|
27
|
+
Provides-Extra: rich
|
|
28
|
+
Requires-Dist: rich-click<2.0.0,>=1.9.9; extra == "rich"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
31
|
+
Provides-Extra: quality
|
|
32
|
+
Requires-Dist: flake8>=6.0.0; extra == "quality"
|
|
33
|
+
Requires-Dist: tox>=4.11.0; extra == "quality"
|
|
34
|
+
Provides-Extra: doc
|
|
35
|
+
Requires-Dist: sphinx>=8.0.2; extra == "doc"
|
|
36
|
+
Requires-Dist: furo>=2024.8.6; extra == "doc"
|
|
37
|
+
Requires-Dist: sphinx-copybutton>=0.5.2; extra == "doc"
|
|
38
|
+
Provides-Extra: doc-live
|
|
39
|
+
Requires-Dist: livereload>=2.6.0; extra == "doc-live"
|
|
40
|
+
Provides-Extra: release
|
|
41
|
+
Requires-Dist: twine>=5.0.0; extra == "release"
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
.. _Python: https://www.python.org/
|
|
45
|
+
.. _Click: https://click.palletsprojects.com
|
|
46
|
+
.. _Big Tree: https://bigtree.readthedocs.io/
|
|
47
|
+
.. _rich-click: https://ewels.github.io/rich-click/latest/
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
==========
|
|
51
|
+
Miss Lemon
|
|
52
|
+
==========
|
|
53
|
+
|
|
54
|
+
Miss Lemon is tool to rename resources (files and directories) with a prefix like
|
|
55
|
+
``0010_stuff/`` or ``0011_foo.py``.
|
|
56
|
+
|
|
57
|
+
The purpose of numbering resources is to organize them in order.
|
|
58
|
+
|
|
59
|
+
This tool helps to do it automatically without to rename them each time you introduce
|
|
60
|
+
a new resource or shift some ones.
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
Dependencies
|
|
64
|
+
************
|
|
65
|
+
|
|
66
|
+
* `Python`_>=3.8;
|
|
67
|
+
* `Click`_>=8.0;
|
|
68
|
+
* `Big Tree`_>=1.5.3;
|
|
69
|
+
* Optionnally `rich-click`_>=1.9.9, <2.0.0;
|
|
70
|
+
|
|
71
|
+
Links
|
|
72
|
+
*****
|
|
73
|
+
|
|
74
|
+
* Read the documentation on `Read the docs <https://miss-lemon.readthedocs.io/>`_;
|
|
75
|
+
* Download its `PyPi package <https://pypi.python.org/pypi/miss-lemon>`_;
|
|
76
|
+
* Clone it on its `Github repository <https://github.com/sveetch/miss-lemon>`_;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
.. _Python: https://www.python.org/
|
|
2
|
+
.. _Click: https://click.palletsprojects.com
|
|
3
|
+
.. _Big Tree: https://bigtree.readthedocs.io/
|
|
4
|
+
.. _rich-click: https://ewels.github.io/rich-click/latest/
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
==========
|
|
8
|
+
Miss Lemon
|
|
9
|
+
==========
|
|
10
|
+
|
|
11
|
+
Miss Lemon is tool to rename resources (files and directories) with a prefix like
|
|
12
|
+
``0010_stuff/`` or ``0011_foo.py``.
|
|
13
|
+
|
|
14
|
+
The purpose of numbering resources is to organize them in order.
|
|
15
|
+
|
|
16
|
+
This tool helps to do it automatically without to rename them each time you introduce
|
|
17
|
+
a new resource or shift some ones.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
Dependencies
|
|
21
|
+
************
|
|
22
|
+
|
|
23
|
+
* `Python`_>=3.8;
|
|
24
|
+
* `Click`_>=8.0;
|
|
25
|
+
* `Big Tree`_>=1.5.3;
|
|
26
|
+
* Optionnally `rich-click`_>=1.9.9, <2.0.0;
|
|
27
|
+
|
|
28
|
+
Links
|
|
29
|
+
*****
|
|
30
|
+
|
|
31
|
+
* Read the documentation on `Read the docs <https://miss-lemon.readthedocs.io/>`_;
|
|
32
|
+
* Download its `PyPi package <https://pypi.python.org/pypi/miss-lemon>`_;
|
|
33
|
+
* Clone it on its `Github repository <https://github.com/sveetch/miss-lemon>`_;
|
|
File without changes
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pytest fixtures
|
|
3
|
+
"""
|
|
4
|
+
import shutil
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
import miss_lemon
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class FixturesSettingsTestMixin(object):
|
|
13
|
+
"""
|
|
14
|
+
A mixin containing settings about application. This is almost only about useful
|
|
15
|
+
paths which may be used in tests.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
application_path (pathlib.Path): Absolute path to the application directory.
|
|
19
|
+
package_path (pathlib.Path): Absolute path to the package directory.
|
|
20
|
+
tests_dir (pathlib.Path): Directory name which include tests.
|
|
21
|
+
tests_path (pathlib.Path): Absolute path to the tests directory.
|
|
22
|
+
datas_dir (pathlib.Path): Directory name which include tests datas.
|
|
23
|
+
datas_path (pathlib.Path): Absolute path to the tests datas.
|
|
24
|
+
"""
|
|
25
|
+
def __init__(self):
|
|
26
|
+
self.application_path = Path(
|
|
27
|
+
miss_lemon.__file__
|
|
28
|
+
).parents[0].resolve()
|
|
29
|
+
|
|
30
|
+
self.package_path = self.application_path.parent
|
|
31
|
+
|
|
32
|
+
self.tests_dir = "tests"
|
|
33
|
+
self.tests_path = self.package_path / self.tests_dir
|
|
34
|
+
|
|
35
|
+
self.datas_dir = "data_fixtures"
|
|
36
|
+
self.datas_path = self.tests_path / self.datas_dir
|
|
37
|
+
|
|
38
|
+
def format(self, content):
|
|
39
|
+
"""
|
|
40
|
+
Format given string to include some values related to this application.
|
|
41
|
+
|
|
42
|
+
Arguments:
|
|
43
|
+
content (str): Content string to format with possible values.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
str: Given string formatted with possible values.
|
|
47
|
+
"""
|
|
48
|
+
return content.format(
|
|
49
|
+
HOMEDIR=Path.home(),
|
|
50
|
+
PACKAGE=str(self.package_path),
|
|
51
|
+
APPLICATION=str(self.application_path),
|
|
52
|
+
TESTS=str(self.tests_path),
|
|
53
|
+
FIXTURES=str(self.datas_path),
|
|
54
|
+
VERSION=miss_lemon.__version__,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@pytest.fixture(scope="function")
|
|
59
|
+
def temp_builds_dir(tmp_path):
|
|
60
|
+
"""
|
|
61
|
+
Prepare a temporary build directory.
|
|
62
|
+
|
|
63
|
+
NOTE: You should use directly the "tmp_path" fixture in your tests.
|
|
64
|
+
"""
|
|
65
|
+
return tmp_path
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@pytest.fixture(scope="module")
|
|
69
|
+
def settings():
|
|
70
|
+
"""
|
|
71
|
+
Initialize and return settings for tests.
|
|
72
|
+
|
|
73
|
+
Example:
|
|
74
|
+
You may use it like: ::
|
|
75
|
+
|
|
76
|
+
def test_foo(settings):
|
|
77
|
+
print(settings.package_path)
|
|
78
|
+
print(settings.format("Application version: {VERSION}"))
|
|
79
|
+
"""
|
|
80
|
+
return FixturesSettingsTestMixin()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@pytest.fixture(scope="function")
|
|
84
|
+
def basic_structure(tmp_path, settings):
|
|
85
|
+
"""
|
|
86
|
+
Copy the "basic_suite" structure into a temporary directory.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Path: The path to the copied structure in temp directory.
|
|
90
|
+
"""
|
|
91
|
+
dirname = "basic_structure"
|
|
92
|
+
basic_sample_path = settings.datas_path / dirname
|
|
93
|
+
destination = tmp_path / dirname
|
|
94
|
+
|
|
95
|
+
shutil.copytree(basic_sample_path, destination)
|
|
96
|
+
|
|
97
|
+
return destination
|
|
File without changes
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from ..walker import DirWalker
|
|
4
|
+
from ..diff import DiffTree
|
|
5
|
+
|
|
6
|
+
# On default rich is not present in outputs and may become available further
|
|
7
|
+
AVAILABLE_OUTPUTS = ["json", "tree"]
|
|
8
|
+
# On default Big tree output is prefered
|
|
9
|
+
DEFAULT_OUTPUT = "tree"
|
|
10
|
+
# First try to get Rich stack, fallback to basic Click and BigTree
|
|
11
|
+
try:
|
|
12
|
+
import rich_click as click
|
|
13
|
+
except ImportError:
|
|
14
|
+
import click
|
|
15
|
+
else:
|
|
16
|
+
from rich import print as RichPrint
|
|
17
|
+
# Append Rich to output and make it the default one
|
|
18
|
+
AVAILABLE_OUTPUTS.append("rich")
|
|
19
|
+
DEFAULT_OUTPUT = "rich"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@click.command()
|
|
23
|
+
@click.argument(
|
|
24
|
+
"source",
|
|
25
|
+
nargs=1,
|
|
26
|
+
type=click.Path(
|
|
27
|
+
exists=True,
|
|
28
|
+
file_okay=False,
|
|
29
|
+
dir_okay=True,
|
|
30
|
+
path_type=Path,
|
|
31
|
+
resolve_path=True,
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
@click.option(
|
|
35
|
+
"--step",
|
|
36
|
+
metavar="INTEGER",
|
|
37
|
+
show_default=True,
|
|
38
|
+
type=click.INT,
|
|
39
|
+
default=100,
|
|
40
|
+
help=(
|
|
41
|
+
"The lowest number slot step for the leaf resources."
|
|
42
|
+
),
|
|
43
|
+
)
|
|
44
|
+
@click.option(
|
|
45
|
+
"--output",
|
|
46
|
+
metavar="NAME",
|
|
47
|
+
show_default=True,
|
|
48
|
+
type=click.Choice(AVAILABLE_OUTPUTS),
|
|
49
|
+
help=(
|
|
50
|
+
"Report output format name. 'json' will print a dictionnary of computed "
|
|
51
|
+
"resources. 'tree' and 'rich' are similar but the latter one "
|
|
52
|
+
"is only allowed if the rich stack has been installed, it will provide colored "
|
|
53
|
+
"nodes (according to their status). Both will print a tree of differences "
|
|
54
|
+
"between original and renamed tree"
|
|
55
|
+
),
|
|
56
|
+
default=DEFAULT_OUTPUT,
|
|
57
|
+
)
|
|
58
|
+
@click.option(
|
|
59
|
+
"--unprefixed",
|
|
60
|
+
is_flag=True,
|
|
61
|
+
help=(
|
|
62
|
+
"Allows to collect all resource even if they don't match the regex for "
|
|
63
|
+
"\"filename with prefix\" (eg: '0001_foo'). Default behavior when this option "
|
|
64
|
+
"is not enabled, is to ignore those files without prefix, they won't be "
|
|
65
|
+
"renamed. This is commonly used with '--excludes' to prevent some resources to "
|
|
66
|
+
"be renamed."
|
|
67
|
+
),
|
|
68
|
+
)
|
|
69
|
+
@click.option(
|
|
70
|
+
"--excludes",
|
|
71
|
+
metavar="PATTERN",
|
|
72
|
+
show_default=True,
|
|
73
|
+
multiple=True,
|
|
74
|
+
help=(
|
|
75
|
+
"Define a 'Unix filename pattern'(compatible with Python module 'fnmatch') to "
|
|
76
|
+
"exclude resources from collect. This can be defined multiple times."
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
@click.option(
|
|
80
|
+
"--from-original",
|
|
81
|
+
is_flag=True,
|
|
82
|
+
help=(
|
|
83
|
+
"If enabled, the tree will display the original name first then the renamed "
|
|
84
|
+
"name. On default the renamed name is printed first."
|
|
85
|
+
),
|
|
86
|
+
)
|
|
87
|
+
@click.pass_context
|
|
88
|
+
def check_command(context, source, step, output, unprefixed, excludes, from_original):
|
|
89
|
+
"""
|
|
90
|
+
Proceed to analyze and prefix computation on a path then output a report.
|
|
91
|
+
|
|
92
|
+
This does not write or rename anything.
|
|
93
|
+
|
|
94
|
+
The preview report can be either a JSON payload or a tree of the original structure
|
|
95
|
+
including a preview of renaming that would occurs with the command 'rename'.
|
|
96
|
+
"""
|
|
97
|
+
logger = context.obj["logger"]
|
|
98
|
+
|
|
99
|
+
logger.debug("Working on: {}".format(source))
|
|
100
|
+
logger.debug("Select output: {}".format(output))
|
|
101
|
+
logger.debug("Collecting resource without prefix: {}".format(unprefixed))
|
|
102
|
+
if excludes:
|
|
103
|
+
logger.debug("Excludes: {}".format(", ".join(excludes)))
|
|
104
|
+
|
|
105
|
+
# Collect and compute with user options
|
|
106
|
+
new_walker = DirWalker(source, allow_unprefixed=unprefixed, excludes=excludes)
|
|
107
|
+
new_root = new_walker.compute(step=step)
|
|
108
|
+
|
|
109
|
+
# Just print output as simple JSON
|
|
110
|
+
if output == "json":
|
|
111
|
+
click.echo(new_root.as_json())
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
differ = DiffTree(source_first=from_original)
|
|
115
|
+
|
|
116
|
+
# Collect the full structure without any exclusions
|
|
117
|
+
original_walker = DirWalker(source, allow_unprefixed=True)
|
|
118
|
+
original_root = original_walker.collect()
|
|
119
|
+
|
|
120
|
+
# Print tree preview with differences report
|
|
121
|
+
if output == "tree":
|
|
122
|
+
click.echo("🎨 Big Tree preview")
|
|
123
|
+
click.echo(differ.build_bigtree(original_root, new_root).show(alias="label"))
|
|
124
|
+
elif output == "rich":
|
|
125
|
+
click.echo("🎨 Rich tree preview")
|
|
126
|
+
RichPrint(differ.build_richtree(original_root, new_root))
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main entrance to commandline actions
|
|
3
|
+
"""
|
|
4
|
+
try:
|
|
5
|
+
import rich_click as click
|
|
6
|
+
except ImportError:
|
|
7
|
+
import click
|
|
8
|
+
else:
|
|
9
|
+
# This is rich-click option only to show arguments in help
|
|
10
|
+
click.rich_click.SHOW_ARGUMENTS = True
|
|
11
|
+
|
|
12
|
+
from miss_lemon.logger import init_logger
|
|
13
|
+
|
|
14
|
+
from miss_lemon import __pkgname__
|
|
15
|
+
from miss_lemon.cli.version import version_command
|
|
16
|
+
from miss_lemon.cli.check import check_command
|
|
17
|
+
from miss_lemon.cli.rename import rename_command
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Help alias on "-h" argument
|
|
21
|
+
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Default logger conf
|
|
25
|
+
APP_LOGGER_CONF = ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", None)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@click.group(context_settings=CONTEXT_SETTINGS)
|
|
29
|
+
@click.option(
|
|
30
|
+
"-v", "--verbose",
|
|
31
|
+
type=click.IntRange(min=0, max=5),
|
|
32
|
+
default=4,
|
|
33
|
+
metavar="INTEGER",
|
|
34
|
+
help=(
|
|
35
|
+
"An integer between 0 and 5, where '0' make a totaly "
|
|
36
|
+
"silent output and '5' set level to DEBUG (the most verbose "
|
|
37
|
+
"level). Default to '4' (Info level)."
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
@click.pass_context
|
|
41
|
+
def cli_frontend(ctx, verbose):
|
|
42
|
+
"""
|
|
43
|
+
Script for application commandline entrypoint.
|
|
44
|
+
"""
|
|
45
|
+
printout = True
|
|
46
|
+
if verbose == 0:
|
|
47
|
+
verbose = 1
|
|
48
|
+
printout = False
|
|
49
|
+
|
|
50
|
+
# Verbosity is the inverse of logging levels
|
|
51
|
+
levels = [item for item in APP_LOGGER_CONF]
|
|
52
|
+
levels.reverse()
|
|
53
|
+
# Init the logger config
|
|
54
|
+
root_logger = init_logger(
|
|
55
|
+
__pkgname__,
|
|
56
|
+
levels[verbose],
|
|
57
|
+
printout=printout
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Init the default context that will be passed to commands
|
|
61
|
+
ctx.obj = {
|
|
62
|
+
"verbosity": verbose,
|
|
63
|
+
"logger": root_logger,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Attach commands methods to the main grouper
|
|
68
|
+
cli_frontend.add_command(version_command, name="version")
|
|
69
|
+
cli_frontend.add_command(check_command, name="check")
|
|
70
|
+
cli_frontend.add_command(rename_command, name="rename")
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from ..walker import DirWalker
|
|
4
|
+
from ..renamer import Renamer
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
import rich_click as click
|
|
8
|
+
except ImportError:
|
|
9
|
+
import click
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@click.command()
|
|
13
|
+
@click.argument(
|
|
14
|
+
"source",
|
|
15
|
+
nargs=1,
|
|
16
|
+
type=click.Path(
|
|
17
|
+
exists=True,
|
|
18
|
+
file_okay=False,
|
|
19
|
+
dir_okay=True,
|
|
20
|
+
path_type=Path,
|
|
21
|
+
resolve_path=True,
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
@click.option(
|
|
25
|
+
"--step",
|
|
26
|
+
metavar="INTEGER",
|
|
27
|
+
show_default=True,
|
|
28
|
+
type=click.INT,
|
|
29
|
+
default=100,
|
|
30
|
+
help=(
|
|
31
|
+
"The lowest number slot step for the leaf resources."
|
|
32
|
+
),
|
|
33
|
+
)
|
|
34
|
+
@click.option(
|
|
35
|
+
"--command",
|
|
36
|
+
metavar="NAME",
|
|
37
|
+
show_default=True,
|
|
38
|
+
type=click.Choice(["mv", "git-mv"]),
|
|
39
|
+
help="Command name. All resource renaming lines will use this command.",
|
|
40
|
+
default="mv",
|
|
41
|
+
)
|
|
42
|
+
@click.option(
|
|
43
|
+
"--unprefixed",
|
|
44
|
+
is_flag=True,
|
|
45
|
+
help=(
|
|
46
|
+
"Allows to collect all resource even if they don't match the regex for "
|
|
47
|
+
"\"filename with prefix\" (eg: '0001_foo'). Default behavior when this option "
|
|
48
|
+
"is not enabled, is to ignore those files without prefix, they won't be "
|
|
49
|
+
"renamed. This is commonly used with '--exclude' to prevent some resources to "
|
|
50
|
+
"be renamed."
|
|
51
|
+
),
|
|
52
|
+
)
|
|
53
|
+
@click.option(
|
|
54
|
+
"--excludes",
|
|
55
|
+
metavar="PATTERN",
|
|
56
|
+
multiple=True,
|
|
57
|
+
help=(
|
|
58
|
+
"Define a 'Unix filename pattern'(compatible with Python module 'fnmatch') to "
|
|
59
|
+
"exclude resources from collect. This can be defined multiple times."
|
|
60
|
+
),
|
|
61
|
+
)
|
|
62
|
+
@click.pass_context
|
|
63
|
+
def rename_command(context, source, step, command, unprefixed, excludes):
|
|
64
|
+
"""
|
|
65
|
+
Rename resources (directories and files) from a path with a computed number prefix.
|
|
66
|
+
"""
|
|
67
|
+
logger = context.obj["logger"]
|
|
68
|
+
|
|
69
|
+
logger.debug("Working on: {}".format(source))
|
|
70
|
+
logger.debug("Selected command: {}".format(command))
|
|
71
|
+
logger.debug("Collecting resource without prefix: {}".format(unprefixed))
|
|
72
|
+
if excludes:
|
|
73
|
+
logger.debug("Excludes: {}".format(", ".join(excludes)))
|
|
74
|
+
|
|
75
|
+
walker = DirWalker(source, allow_unprefixed=unprefixed, excludes=excludes)
|
|
76
|
+
|
|
77
|
+
root = walker.compute(step=step)
|
|
78
|
+
|
|
79
|
+
renamer = Renamer(root)
|
|
80
|
+
|
|
81
|
+
if command == "mv":
|
|
82
|
+
cmd_output = renamer.with_shell_mv()
|
|
83
|
+
elif command == "git-mv":
|
|
84
|
+
cmd_output = renamer.with_shell_gitmv()
|
|
85
|
+
|
|
86
|
+
click.echo(cmd_output)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
try:
|
|
2
|
+
import rich_click as click
|
|
3
|
+
except ImportError:
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from miss_lemon import __version__
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.command()
|
|
10
|
+
@click.pass_context
|
|
11
|
+
def version_command(context):
|
|
12
|
+
"""
|
|
13
|
+
Print out version information.
|
|
14
|
+
"""
|
|
15
|
+
click.echo("miss-lemon {}".format(__version__))
|