delayed-rm 2.9.3__tar.gz → 2.11.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.
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/PKG-INFO +3 -2
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/delayed_rm/delayed_rm.py +33 -14
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/delayed_rm.egg-info/PKG-INFO +3 -2
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/LICENSE +0 -0
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/README.md +0 -0
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/delayed_rm/__init__.py +0 -0
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/delayed_rm/py.typed +0 -0
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/delayed_rm.egg-info/SOURCES.txt +0 -0
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/delayed_rm.egg-info/dependency_links.txt +0 -0
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/delayed_rm.egg-info/entry_points.txt +0 -0
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/delayed_rm.egg-info/top_level.txt +0 -0
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/pyproject.toml +0 -0
- {delayed_rm-2.9.3 → delayed_rm-2.11.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: delayed_rm
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.11.0
|
|
4
4
|
Summary: Ever wish you had a few minutes to undo an rm? Now you do!
|
|
5
5
|
License: GPLv3
|
|
6
6
|
Project-URL: Homepage, https://github.com/zwimer/delayed_rm
|
|
@@ -12,6 +12,7 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
|
12
12
|
Requires-Python: >=3.10
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
+
Dynamic: license-file
|
|
15
16
|
|
|
16
17
|
# delayed\_rm
|
|
17
18
|
Ever wish you had a few minutes to undo an rm? Now you do!
|
|
@@ -8,11 +8,12 @@ import subprocess
|
|
|
8
8
|
import argparse
|
|
9
9
|
import tempfile
|
|
10
10
|
import shutil
|
|
11
|
+
import math
|
|
11
12
|
import time
|
|
12
13
|
import sys
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
__version__ = "2.
|
|
16
|
+
__version__ = "2.11.0"
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
#
|
|
@@ -51,6 +52,17 @@ class _Secret:
|
|
|
51
52
|
#
|
|
52
53
|
|
|
53
54
|
|
|
55
|
+
def _size(p: Path) -> str:
|
|
56
|
+
"""
|
|
57
|
+
Get file size as a human readable string
|
|
58
|
+
This does follow symlinks
|
|
59
|
+
"""
|
|
60
|
+
s = p.stat().st_size
|
|
61
|
+
lg = int(math.log(s, 1000))
|
|
62
|
+
si = " KMGT"[lg].replace(" ", "")
|
|
63
|
+
return f"{round(s/(1000**lg))} {si}B"
|
|
64
|
+
|
|
65
|
+
|
|
54
66
|
def _eprint(e: str | BaseException) -> None:
|
|
55
67
|
"""
|
|
56
68
|
Print e to stderr
|
|
@@ -88,7 +100,7 @@ def _prep(paths: list[Path], rf: bool) -> list[Path]:
|
|
|
88
100
|
except (FileNotFoundError, RuntimeError) as e:
|
|
89
101
|
raise RMError(e) from e
|
|
90
102
|
for i in paths:
|
|
91
|
-
if not rf and
|
|
103
|
+
if not rf and i.is_dir() and not i.is_symlink():
|
|
92
104
|
raise RMError(f"{i} is a directory. -rf required!")
|
|
93
105
|
if tmp_d == i:
|
|
94
106
|
raise RMError(f"Will not delete {tmp_d}")
|
|
@@ -107,7 +119,7 @@ def _prep(paths: list[Path], rf: bool) -> list[Path]:
|
|
|
107
119
|
|
|
108
120
|
def delayed_rm(paths: list[Path], delay: int, rf: bool) -> bool:
|
|
109
121
|
"""
|
|
110
|
-
Move paths to a
|
|
122
|
+
Move paths to a temporary directory, delete them after delay seconds
|
|
111
123
|
Log's this action to the log
|
|
112
124
|
If rf, acts like rm -rf
|
|
113
125
|
May raise an RMError if something goes wrong
|
|
@@ -147,7 +159,7 @@ def delayed_rm(paths: list[Path], delay: int, rf: bool) -> bool:
|
|
|
147
159
|
edited = True
|
|
148
160
|
except OSError:
|
|
149
161
|
copyf = lambda src, dst: shutil.copy2(src, dst, follow_symlinks=False)
|
|
150
|
-
if p.is_dir():
|
|
162
|
+
if p.is_dir() and not p.is_symlink():
|
|
151
163
|
shutil.copytree(p, new, copy_function=copyf, symlinks=False)
|
|
152
164
|
edited = True
|
|
153
165
|
shutil.rmtree(p)
|
|
@@ -213,7 +225,7 @@ def delayed_rm_raw(delay: int, log: bool, r: bool, f: bool, paths: list[Path]) -
|
|
|
213
225
|
if r or f or paths:
|
|
214
226
|
_eprint("--log may not be used with other arguments")
|
|
215
227
|
return False
|
|
216
|
-
print(f"{log_f.read_text()}Log file: {log_f}" if log_f.exists() else "Log is empty")
|
|
228
|
+
print(f"{log_f.read_text()}Log file ({_size(log_f)}): {log_f}" if log_f.exists() else "Log is empty")
|
|
217
229
|
return True
|
|
218
230
|
if not paths:
|
|
219
231
|
_eprint("nothing to remove")
|
|
@@ -250,21 +262,28 @@ def cli() -> None:
|
|
|
250
262
|
#
|
|
251
263
|
|
|
252
264
|
|
|
253
|
-
def _secret_cli():
|
|
265
|
+
def _secret_cli() -> None:
|
|
254
266
|
"""
|
|
255
267
|
This CLI is invoked on import and not will do nothing by default
|
|
256
268
|
This CLI will only activate if argv was intentionally configured to do so
|
|
257
269
|
This entrypoint is for the spawned process to act
|
|
258
270
|
"""
|
|
271
|
+
if len(sys.argv) > 1 and sys.argv[1] == "--force-cli":
|
|
272
|
+
del sys.argv[1]
|
|
273
|
+
cli()
|
|
259
274
|
try:
|
|
260
|
-
if len(sys.argv)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
275
|
+
if len(sys.argv) != 4 or sys.argv[1] != _Secret.value or environ.get(_Secret.key, None) != _Secret.value:
|
|
276
|
+
print(
|
|
277
|
+
"This script should be run by invoking the cli() function.\n"
|
|
278
|
+
"Pass --force-cli as the first argument to bypass this restriction.",
|
|
279
|
+
file=sys.stderr,
|
|
280
|
+
)
|
|
281
|
+
sys.exit(1)
|
|
282
|
+
d = Path(sys.argv[3]).resolve()
|
|
283
|
+
time.sleep(int(sys.argv[2]))
|
|
284
|
+
shutil.rmtree(d)
|
|
285
|
+
with log_f.open("a") as f:
|
|
286
|
+
f.write(f"Removing: {d}" + "\n\n")
|
|
268
287
|
except Exception:
|
|
269
288
|
sys.stderr = log_f.open("a")
|
|
270
289
|
sys.stdout = sys.stderr
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: delayed_rm
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.11.0
|
|
4
4
|
Summary: Ever wish you had a few minutes to undo an rm? Now you do!
|
|
5
5
|
License: GPLv3
|
|
6
6
|
Project-URL: Homepage, https://github.com/zwimer/delayed_rm
|
|
@@ -12,6 +12,7 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
|
12
12
|
Requires-Python: >=3.10
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
+
Dynamic: license-file
|
|
15
16
|
|
|
16
17
|
# delayed\_rm
|
|
17
18
|
Ever wish you had a few minutes to undo an rm? Now you do!
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|