devcleaner-cli 1.0.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.
- devcleaner_cli-1.0.0/.gitignore +223 -0
- devcleaner_cli-1.0.0/LICENSE +21 -0
- devcleaner_cli-1.0.0/PKG-INFO +468 -0
- devcleaner_cli-1.0.0/README.md +439 -0
- devcleaner_cli-1.0.0/pyproject.toml +75 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/__init__.py +1 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/__main__.py +6 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/cleaners/__init__.py +1 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/cleaners/base.py +8 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/cleaners/native.py +18 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/cleaners/wsl.py +37 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/cli/__init__.py +1 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/cli/interface.py +272 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/cli/parser.py +81 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/core/__init__.py +1 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/core/cleaner.py +171 -0
- devcleaner_cli-1.0.0/src/dev_cleaner/main.py +180 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
*.lcov
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
# Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# uv
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries.
|
|
102
|
+
# uv.lock
|
|
103
|
+
|
|
104
|
+
# poetry
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
106
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
107
|
+
# commonly ignored for libraries.
|
|
108
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
109
|
+
# poetry.lock
|
|
110
|
+
# poetry.toml
|
|
111
|
+
|
|
112
|
+
# pdm
|
|
113
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
114
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
115
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
116
|
+
# pdm.lock
|
|
117
|
+
# pdm.toml
|
|
118
|
+
.pdm-python
|
|
119
|
+
.pdm-build/
|
|
120
|
+
|
|
121
|
+
# pixi
|
|
122
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
123
|
+
# pixi.lock
|
|
124
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
125
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
126
|
+
.pixi/*
|
|
127
|
+
!.pixi/config.toml
|
|
128
|
+
|
|
129
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
130
|
+
__pypackages__/
|
|
131
|
+
|
|
132
|
+
# Celery stuff
|
|
133
|
+
celerybeat-schedule*
|
|
134
|
+
celerybeat.pid
|
|
135
|
+
|
|
136
|
+
# Redis
|
|
137
|
+
*.rdb
|
|
138
|
+
*.aof
|
|
139
|
+
*.pid
|
|
140
|
+
|
|
141
|
+
# RabbitMQ
|
|
142
|
+
mnesia/
|
|
143
|
+
rabbitmq/
|
|
144
|
+
rabbitmq-data/
|
|
145
|
+
|
|
146
|
+
# ActiveMQ
|
|
147
|
+
activemq-data/
|
|
148
|
+
|
|
149
|
+
# SageMath parsed files
|
|
150
|
+
*.sage.py
|
|
151
|
+
|
|
152
|
+
# Environments
|
|
153
|
+
.env
|
|
154
|
+
.envrc
|
|
155
|
+
.venv
|
|
156
|
+
env/
|
|
157
|
+
venv/
|
|
158
|
+
ENV/
|
|
159
|
+
env.bak/
|
|
160
|
+
venv.bak/
|
|
161
|
+
|
|
162
|
+
# Spyder project settings
|
|
163
|
+
.spyderproject
|
|
164
|
+
.spyproject
|
|
165
|
+
|
|
166
|
+
# Rope project settings
|
|
167
|
+
.ropeproject
|
|
168
|
+
|
|
169
|
+
# mkdocs/Zensical documentation
|
|
170
|
+
/site
|
|
171
|
+
|
|
172
|
+
# mypy
|
|
173
|
+
.mypy_cache/
|
|
174
|
+
.dmypy.json
|
|
175
|
+
dmypy.json
|
|
176
|
+
|
|
177
|
+
# Pyre type checker
|
|
178
|
+
.pyre/
|
|
179
|
+
|
|
180
|
+
# pytype static type analyzer
|
|
181
|
+
.pytype/
|
|
182
|
+
|
|
183
|
+
# Cython debug symbols
|
|
184
|
+
cython_debug/
|
|
185
|
+
|
|
186
|
+
# PyCharm
|
|
187
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
188
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
189
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
190
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
191
|
+
# .idea/
|
|
192
|
+
|
|
193
|
+
# Abstra
|
|
194
|
+
# Abstra is an AI-powered process automation framework.
|
|
195
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
196
|
+
# Learn more at https://abstra.io/docs
|
|
197
|
+
.abstra/
|
|
198
|
+
|
|
199
|
+
# Visual Studio Code
|
|
200
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that
|
|
201
|
+
# can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
202
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer, you
|
|
203
|
+
# could uncomment the following to ignore the entire vscode folder
|
|
204
|
+
# .vscode/
|
|
205
|
+
# Temporary file for partial code execution
|
|
206
|
+
tempCodeRunnerFile.py
|
|
207
|
+
|
|
208
|
+
# Ruff stuff:
|
|
209
|
+
.ruff_cache/
|
|
210
|
+
|
|
211
|
+
# PyPI configuration file
|
|
212
|
+
.pypirc
|
|
213
|
+
|
|
214
|
+
# Marimo
|
|
215
|
+
marimo/_static/
|
|
216
|
+
marimo/_lsp/
|
|
217
|
+
__marimo__/
|
|
218
|
+
|
|
219
|
+
# Streamlit
|
|
220
|
+
.streamlit/secrets.toml
|
|
221
|
+
|
|
222
|
+
# ide
|
|
223
|
+
.idea
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 adonesbalica
|
|
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,468 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: devcleaner-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Remove generated directories such as node_modules, .next, and dist from every project in a workspace.
|
|
5
|
+
Project-URL: Homepage, https://github.com/adonesbalica/dev-cleaner
|
|
6
|
+
Project-URL: Repository, https://github.com/adonesbalica/dev-cleaner
|
|
7
|
+
Project-URL: Issues, https://github.com/adonesbalica/dev-cleaner/issues
|
|
8
|
+
Author-email: Adones Balica <adonesbalica@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: cleanup,cli,developer-tools,disk-space,node-modules,wsl
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
21
|
+
Classifier: Topic :: System :: Filesystems
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.12
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.17; extra == 'dev'
|
|
27
|
+
Requires-Dist: twine>=5; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# dev-cleaner
|
|
31
|
+
|
|
32
|
+
A lightweight, cross-platform CLI tool to clean unnecessary directories from development projects.
|
|
33
|
+
|
|
34
|
+
`dev-cleaner` helps developers keep their workspaces clean by automatically detecting projects and removing generated or dependency directories such as `node_modules`, `.next`, and `dist`.
|
|
35
|
+
|
|
36
|
+
## Table of contents
|
|
37
|
+
|
|
38
|
+
- [Features](#features)
|
|
39
|
+
- [Supported environments](#supported-environments)
|
|
40
|
+
- [Requirements](#requirements)
|
|
41
|
+
- [Installation](#installation)
|
|
42
|
+
- [Tutorial](#tutorial)
|
|
43
|
+
- [Usage](#usage)
|
|
44
|
+
- [Development](#development)
|
|
45
|
+
- [Project structure](#project-structure)
|
|
46
|
+
- [Architecture](#architecture)
|
|
47
|
+
- [Safety](#safety)
|
|
48
|
+
- [Troubleshooting](#troubleshooting)
|
|
49
|
+
- [License](#license)
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- **Cross-platform:** runs natively on Windows, Linux, and inside WSL.
|
|
54
|
+
- **Automatic backend selection:** the right filesystem implementation is picked from the workspace path.
|
|
55
|
+
- **Windows → WSL support:** clean Linux filesystems from Windows without leaving the terminal.
|
|
56
|
+
- **Configurable targets:** defaults to `node_modules`, `.next`, and `dist`, and accepts custom targets.
|
|
57
|
+
- **Safe by default:** asks for confirmation, supports `--dry-run`, skips symlinks and junctions, and refuses to scan a filesystem root.
|
|
58
|
+
- **Per-operation reporting:** failures are reported per project instead of aborting the whole run.
|
|
59
|
+
- **Live progress:** a spinner and elapsed timer show that a long cleanup is still running.
|
|
60
|
+
- **Installable:** published on PyPI as `devcleaner-cli` and exposes the `dev-cleaner` command.
|
|
61
|
+
- **No dependencies:** the CLI uses only the Python standard library.
|
|
62
|
+
|
|
63
|
+
## Supported environments
|
|
64
|
+
|
|
65
|
+
| Where you run it | Workspace path | Backend |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| Windows | `C:\Users\me\workspace` | `native` (Windows filesystem) |
|
|
68
|
+
| Windows | `/home/me/workspace` | `wsl` (default distribution) |
|
|
69
|
+
| Windows | `//wsl.localhost/Ubuntu/home/me/workspace` | `wsl` (distribution taken from the path) |
|
|
70
|
+
| Linux | `/home/me/workspace` | `native` (Linux filesystem) |
|
|
71
|
+
| Inside WSL | `/home/me/workspace` or `/mnt/c/...` | `native` (Linux filesystem) |
|
|
72
|
+
|
|
73
|
+
The backend is detected automatically. Use `--backend` only to override the detection.
|
|
74
|
+
|
|
75
|
+
## Requirements
|
|
76
|
+
|
|
77
|
+
- Python 3.12 or higher.
|
|
78
|
+
- WSL 2 with a Linux distribution such as Ubuntu (only when cleaning a Linux filesystem from Windows).
|
|
79
|
+
|
|
80
|
+
No third-party packages are required.
|
|
81
|
+
|
|
82
|
+
## Installation
|
|
83
|
+
|
|
84
|
+
The package is published on PyPI as [`devcleaner-cli`](https://pypi.org/project/devcleaner-cli/) and installs the `dev-cleaner` command.
|
|
85
|
+
|
|
86
|
+
**pipx (recommended for CLI tools):**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pipx install devcleaner-cli
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**uv:**
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
uv tool install devcleaner-cli
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**pip:**
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
python -m pip install --user devcleaner-cli
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
On Windows, install pipx with `py -m pip install --user pipx` and run `py -m pipx ensurepath`, then reopen the terminal.
|
|
105
|
+
|
|
106
|
+
**From source:**
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone https://github.com/adonesbalica/dev-cleaner.git
|
|
110
|
+
cd dev-cleaner
|
|
111
|
+
pipx install .
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
After installing, `dev-cleaner` works from any directory:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
dev-cleaner --version
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
If the command is not found, reopen the terminal so the updated `PATH` is loaded, or run `python -m dev_cleaner`. The package has no runtime dependencies.
|
|
121
|
+
|
|
122
|
+
## Tutorial
|
|
123
|
+
|
|
124
|
+
This walkthrough creates a throwaway workspace, so nothing real is deleted. It takes about two minutes.
|
|
125
|
+
|
|
126
|
+
### 1. Create a practice workspace
|
|
127
|
+
|
|
128
|
+
**Windows (PowerShell):**
|
|
129
|
+
|
|
130
|
+
```powershell
|
|
131
|
+
$demo = Join-Path $env:TEMP "dev-cleaner-demo"
|
|
132
|
+
New-Item -ItemType Directory -Force "$demo\app-a\node_modules\react" | Out-Null
|
|
133
|
+
New-Item -ItemType Directory -Force "$demo\app-a\dist" | Out-Null
|
|
134
|
+
New-Item -ItemType Directory -Force "$demo\app-b\.next" | Out-Null
|
|
135
|
+
New-Item -ItemType Directory -Force "$demo\app-c\src" | Out-Null
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Linux or WSL:**
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
demo="$(mktemp -d)"
|
|
142
|
+
mkdir -p "$demo/app-a/node_modules/react" "$demo/app-a/dist"
|
|
143
|
+
mkdir -p "$demo/app-b/.next" "$demo/app-c/src"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
You now have three projects: `app-a` and `app-b` contain generated directories, while `app-c` contains only source code.
|
|
147
|
+
|
|
148
|
+
### 2. Preview the cleanup with a dry run
|
|
149
|
+
|
|
150
|
+
**Windows:**
|
|
151
|
+
|
|
152
|
+
```powershell
|
|
153
|
+
dev-cleaner -w $demo -n
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Linux or WSL:**
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
dev-cleaner -w "$demo" -n
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Expected output:
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
dev-cleaner 1.0.0 | native | <workspace>
|
|
166
|
+
|
|
167
|
+
would remove app-a/node_modules
|
|
168
|
+
would remove app-a/dist
|
|
169
|
+
would remove app-b/.next
|
|
170
|
+
|
|
171
|
+
3 matched (3 projects) [dry run]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The first line shows the tool version, the selected backend, and the workspace you passed. Nothing has been deleted; the `[dry run]` marker confirms it. The order of the lines depends on the filesystem; the counts are what matter.
|
|
175
|
+
|
|
176
|
+
### 3. Run the cleanup for real
|
|
177
|
+
|
|
178
|
+
Drop `-n` and add `-y` to skip the confirmation prompt:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
dev-cleaner -w "$demo" -y
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Expected output:
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
dev-cleaner 1.0.0 | native | <workspace>
|
|
188
|
+
|
|
189
|
+
removed app-a/node_modules
|
|
190
|
+
removed app-a/dist
|
|
191
|
+
removed app-b/.next
|
|
192
|
+
|
|
193
|
+
3 removed (3 projects)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
On a real terminal, a single-line spinner and timer appear while the directories are removed, so a slow cleanup never looks frozen:
|
|
197
|
+
|
|
198
|
+
```text
|
|
199
|
+
| cleaning app-a/node_modules (1/3) 0:04
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The line is erased when the run finishes, and the summary appends the total time when it took at least one second (for example `3 removed (3 projects) in 0:04`). When the output is piped or redirected, the spinner is skipped and only the final lines are written, which keeps the output easy to parse.
|
|
203
|
+
|
|
204
|
+
Without `-y`, the tool asks first:
|
|
205
|
+
|
|
206
|
+
```text
|
|
207
|
+
Remove node_modules, .next, dist from every project? [y/N]
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Press `y` and Enter to continue, or Enter to cancel. The default is always **No**.
|
|
211
|
+
|
|
212
|
+
### 4. Verify the result
|
|
213
|
+
|
|
214
|
+
**Windows:**
|
|
215
|
+
|
|
216
|
+
```powershell
|
|
217
|
+
Get-ChildItem -Directory -Recurse $demo | Select-Object -ExpandProperty FullName
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Linux or WSL:**
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
find "$demo" -type d
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Only `app-a`, `app-b`, and `app-c` (plus `app-c/src`) should remain. The generated directories are gone.
|
|
227
|
+
|
|
228
|
+
### 5. Remove the practice workspace
|
|
229
|
+
|
|
230
|
+
**Windows:**
|
|
231
|
+
|
|
232
|
+
```powershell
|
|
233
|
+
Remove-Item $demo -Recurse -Force
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Linux or WSL:**
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
rm -rf "$demo"
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Tutorial: clean a WSL workspace from Windows
|
|
243
|
+
|
|
244
|
+
Use the Linux path of the workspace. The tool detects that it is not a Windows path and switches to the WSL backend automatically.
|
|
245
|
+
|
|
246
|
+
```powershell
|
|
247
|
+
# See which distributions are available
|
|
248
|
+
wsl -l -q
|
|
249
|
+
|
|
250
|
+
# Preview the cleanup
|
|
251
|
+
dev-cleaner -w /home/me/workspace -n
|
|
252
|
+
|
|
253
|
+
# Use a specific distribution if the default is not the right one
|
|
254
|
+
dev-cleaner -w /home/me/workspace -d Ubuntu -n
|
|
255
|
+
|
|
256
|
+
# Run it
|
|
257
|
+
dev-cleaner -w /home/me/workspace -y
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The header shows which backend and distribution were selected:
|
|
261
|
+
|
|
262
|
+
```text
|
|
263
|
+
dev-cleaner 1.0.0 | wsl:Ubuntu | /home/me/workspace
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
You can also pass a Windows UNC path such as `//wsl.localhost/Ubuntu/home/me/workspace`; the distribution is read from the path.
|
|
267
|
+
|
|
268
|
+
### Tutorial: use custom targets
|
|
269
|
+
|
|
270
|
+
Passing `-t` **replaces** the default target list, so list every directory you want to remove:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
dev-cleaner -w /home/me/workspace -t node_modules -t .venv -t target -n
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
This removes only `node_modules`, `.venv`, and `target`; it does not also remove `.next` or `dist`.
|
|
277
|
+
|
|
278
|
+
### Tutorial: use it in a script
|
|
279
|
+
|
|
280
|
+
Use `-y` so the command never waits for input, and check the exit code:
|
|
281
|
+
|
|
282
|
+
**Bash:**
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
dev-cleaner -w /home/me/workspace -y
|
|
286
|
+
if [ $? -ne 0 ]; then
|
|
287
|
+
echo "cleanup failed" >&2
|
|
288
|
+
fi
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**PowerShell:**
|
|
292
|
+
|
|
293
|
+
```powershell
|
|
294
|
+
dev-cleaner -w C:/Users/me/workspace -y
|
|
295
|
+
if ($LASTEXITCODE -ne 0) {
|
|
296
|
+
Write-Error "cleanup failed"
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Usage
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
dev-cleaner -w <workspace> [options]
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Options
|
|
307
|
+
|
|
308
|
+
| Option | Description |
|
|
309
|
+
|---|---|
|
|
310
|
+
| `-w`, `--workspace` | Workspace directory to scan. Required. |
|
|
311
|
+
| `-t`, `--target` | Directory to remove. Repeatable; replaces the defaults. Defaults to `node_modules`, `.next`, `dist`. |
|
|
312
|
+
| `-b`, `--backend` | Force `native` or `wsl`. Auto-detected by default. |
|
|
313
|
+
| `-d`, `--distribution` | WSL distribution to use. Defaults to the WSL default distribution, or `Ubuntu`. |
|
|
314
|
+
| `-n`, `--dry-run` | Show what would be removed without deleting anything. |
|
|
315
|
+
| `-y`, `--yes` | Do not ask for confirmation. |
|
|
316
|
+
| `--version` | Show the version and exit. |
|
|
317
|
+
|
|
318
|
+
### Progress indicator
|
|
319
|
+
|
|
320
|
+
While scanning or deleting, the CLI shows one animated line with the directory being removed and an elapsed timer:
|
|
321
|
+
|
|
322
|
+
```text
|
|
323
|
+
/ cleaning app-a/node_modules (2/7) 0:12
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
- The spinner uses plain ASCII frames (`|`, `/`, `-`, `\`), so it works in any terminal.
|
|
327
|
+
- The status updates before **each directory** is removed, so the name changes even when a single project takes a long time.
|
|
328
|
+
- The timer uses `m:ss`, switching to `h:mm:ss` after one hour.
|
|
329
|
+
- The line is cleared before the per-directory results are printed.
|
|
330
|
+
- The summary appends `in m:ss` when the run took at least one second.
|
|
331
|
+
- The spinner is **TTY-only**. Piped or redirected output never contains the animation, so logs and scripts stay clean.
|
|
332
|
+
|
|
333
|
+
### Exit codes
|
|
334
|
+
|
|
335
|
+
| Code | Meaning |
|
|
336
|
+
|---|---|
|
|
337
|
+
| `0` | Success, including "nothing to remove" and a cancelled prompt. |
|
|
338
|
+
| `1` | Error: invalid workspace, invalid target, failed removal, or WSL unavailable. |
|
|
339
|
+
| `2` | Invalid command-line arguments. |
|
|
340
|
+
| `130` | Interrupted with Ctrl+C. |
|
|
341
|
+
|
|
342
|
+
### How it works
|
|
343
|
+
|
|
344
|
+
1. Detects the backend from the workspace path (unless `--backend` is given).
|
|
345
|
+
2. Maps the workspace to a scan path and, for WSL, to the equivalent Linux path.
|
|
346
|
+
3. Lists the direct children of the workspace as projects.
|
|
347
|
+
4. Checks each project for the configured target directories.
|
|
348
|
+
5. Removes matching directories using the selected backend, reporting every operation.
|
|
349
|
+
|
|
350
|
+
Only direct children of the workspace are treated as projects, and only direct children of each project are removed. Symlinked projects and targets, as well as Windows directory junctions, are skipped.
|
|
351
|
+
|
|
352
|
+
## Development
|
|
353
|
+
|
|
354
|
+
Clone the repository and create a virtual environment:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
git clone https://github.com/adonesbalica/dev-cleaner.git
|
|
358
|
+
cd dev-cleaner
|
|
359
|
+
python -m venv .venv
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Activate it:
|
|
363
|
+
|
|
364
|
+
**Windows (PowerShell):**
|
|
365
|
+
|
|
366
|
+
```powershell
|
|
367
|
+
.venv\Scripts\Activate.ps1
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Linux / WSL:**
|
|
371
|
+
|
|
372
|
+
```bash
|
|
373
|
+
source .venv/bin/activate
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Install the package in editable mode with the development tools:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
python -m pip install -e ".[dev]"
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Run the CLI without the console script:
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
python -m dev_cleaner --help
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Run the checks and build the distribution:
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
ruff check src
|
|
392
|
+
ruff format --check src
|
|
393
|
+
python -m build
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
The build writes `dist/devcleaner_cli-<version>-py3-none-any.whl` and a source archive. See [RELEASING.md](https://github.com/adonesbalica/dev-cleaner/blob/main/RELEASING.md) for the publish steps.
|
|
397
|
+
|
|
398
|
+
## Project structure
|
|
399
|
+
|
|
400
|
+
```text
|
|
401
|
+
dev-cleaner/
|
|
402
|
+
├── src/
|
|
403
|
+
│ └── dev_cleaner/
|
|
404
|
+
│ ├── __init__.py
|
|
405
|
+
│ ├── __main__.py
|
|
406
|
+
│ ├── main.py
|
|
407
|
+
│ ├── core/
|
|
408
|
+
│ │ ├── __init__.py
|
|
409
|
+
│ │ └── cleaner.py
|
|
410
|
+
│ ├── cleaners/
|
|
411
|
+
│ │ ├── __init__.py
|
|
412
|
+
│ │ ├── base.py
|
|
413
|
+
│ │ ├── native.py
|
|
414
|
+
│ │ └── wsl.py
|
|
415
|
+
│ └── cli/
|
|
416
|
+
│ ├── __init__.py
|
|
417
|
+
│ ├── interface.py
|
|
418
|
+
│ └── parser.py
|
|
419
|
+
├── pyproject.toml
|
|
420
|
+
├── README.md
|
|
421
|
+
├── RELEASING.md
|
|
422
|
+
├── LICENSE
|
|
423
|
+
└── .gitignore
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## Architecture
|
|
427
|
+
|
|
428
|
+
The project uses a strategy-based architecture to separate cleanup orchestration from filesystem operations.
|
|
429
|
+
|
|
430
|
+
- **`FileSystemCleaner`:** defines the contract for filesystem cleanup implementations.
|
|
431
|
+
- **`NativeCleaner`:** uses `shutil.rmtree` on the filesystem the application runs on (Windows or Linux), including retries for read-only files.
|
|
432
|
+
- **`WslCleaner`:** runs `wsl -d <distribution> -- rm -rf` to remove directories inside a Linux filesystem from Windows.
|
|
433
|
+
- **`Cleaner`:** handles workspace scanning, project detection, WSL path mapping, dry runs, and cleanup orchestration.
|
|
434
|
+
- **`main.py`:** detects the backend, resolves the workspace paths, and wires everything together.
|
|
435
|
+
- **`cli/`:** parses arguments, shows the TTY-only spinner and timer, and prints plain-text results, a summary, and the confirmation prompt. No third-party dependencies.
|
|
436
|
+
|
|
437
|
+
This design allows new filesystem cleanup implementations to be added without changing the core cleanup logic.
|
|
438
|
+
|
|
439
|
+
## Safety
|
|
440
|
+
|
|
441
|
+
Directory removal is permanent.
|
|
442
|
+
|
|
443
|
+
Before running the application, make sure that:
|
|
444
|
+
|
|
445
|
+
- The workspace path is correct.
|
|
446
|
+
- The target directories are the ones you intend to remove.
|
|
447
|
+
- The selected backend matches your environment.
|
|
448
|
+
|
|
449
|
+
Use `--dry-run` first to review what will be removed. Symlinked projects and targets are skipped, and the tool refuses to scan a filesystem root. Only direct children of the workspace are considered, so pointing `-w` at a folder that contains projects is safer than pointing it at a single project.
|
|
450
|
+
|
|
451
|
+
## Troubleshooting
|
|
452
|
+
|
|
453
|
+
| Problem | Cause and fix |
|
|
454
|
+
|---|---|
|
|
455
|
+
| `Error: Workspace not found: ...` | The path is wrong, or the WSL distribution is not running. Check the path and run `wsl -l -q` to see available distributions. |
|
|
456
|
+
| `Error: The wsl backend requires Windows with WSL installed.` | You forced `-b wsl` on Linux. Remove `-b wsl`; Linux paths already work with the native backend. |
|
|
457
|
+
| `Error: Refusing to scan a filesystem root: ...` | Pass the folder that contains your projects, not `/`, `C:\`, or a WSL distribution root. |
|
|
458
|
+
| `Error: Invalid target directory: ...` | Targets must be a single directory name. Do not use paths such as `src/dist` or `..`. |
|
|
459
|
+
| `failed ... [WinError 32]` or `Permission denied` | A file is open or read-only. Close editors, dev servers, and terminals using the directory, then retry. |
|
|
460
|
+
| Nothing is removed | Only direct children of the workspace are scanned. Point `-w` at the folder containing your project folders. |
|
|
461
|
+
| Paths with spaces do not work | Quote the path: `-w "C:/Users/me/My Projects"`. |
|
|
462
|
+
| Colors look wrong or appear as escape codes | Set `NO_COLOR=1`, or use a terminal with ANSI support. |
|
|
463
|
+
| No spinner or timer appears | The spinner is TTY-only. It is hidden when output is piped or redirected, and when `TERM=dumb`. Run the tool directly in a terminal to see it. |
|
|
464
|
+
| `dev-cleaner` is not recognized | Install it with `pipx install devcleaner-cli` or `uv tool install devcleaner-cli`, then reopen the terminal so `PATH` is updated. You can always run `python -m dev_cleaner` instead. |
|
|
465
|
+
|
|
466
|
+
## License
|
|
467
|
+
|
|
468
|
+
This project is licensed under the MIT License.
|