| Hash | Commit message | Author | Date | Files | + | - |
1 | commit 1b80b36aa234b1be35ba6513c0e2ece734791476 |
2 | Author: Connor Etherington <[email protected]> |
3 | Date: Tue Sep 19 23:12:10 2023 +0200 |
4 | |
5 | Auto-Commit Update - 20230919 |
6 | --- |
7 | PKGBUILD | 4 +- |
8 | README.md | 2 +- |
9 | build/lib/ptrack/__init__.py | 16 +++ |
10 | build/lib/ptrack/main.py | 215 +++++++++++++++++++++++++++++++++++ |
11 | build/lib/ptrack/methods.py | 147 ++++++++++++++++++++++++ |
12 | dist/ptrack-1.0.0-py3-none-any.whl | Bin 0 -> 6744 bytes |
13 | dist/ptrack-1.0.0.tar.gz | Bin 0 -> 6921 bytes |
14 | ptrack.egg-info/PKG-INFO | 13 +++ |
15 | ptrack.egg-info/SOURCES.txt | 12 ++ |
16 | ptrack.egg-info/dependency_links.txt | 1 + |
17 | ptrack.egg-info/entry_points.txt | 5 + |
18 | ptrack.egg-info/requires.txt | 6 + |
19 | ptrack.egg-info/top_level.txt | 1 + |
20 | ptrack/__init__.py | 2 +- |
21 | ptrack/main.py | 5 + |
22 | ptrack/methods.py | 9 +- |
23 | recipe/meta.yaml | 2 +- |
24 | setup.py | 2 +- |
25 | 18 files changed, 435 insertions(+), 7 deletions(-) |
26 | |
27 | diff --git a/PKGBUILD b/PKGBUILD |
28 | index 49eabb5..41df404 100644 |
29 | --- a/PKGBUILD |
30 | +++ b/PKGBUILD |
31 | @@ -1,7 +1,7 @@ |
32 | # Maintainer: Connor Etherington <[email protected]> |
33 | # --- |
34 | pkgname=ptrack |
35 | -pkgver=0.2.5 |
36 | +pkgver=1.0.0 |
37 | pkgrel=1 |
38 | pkgdesc="A simple CLI utility for asthetically tracking progress when copying, moving or downloading files." |
39 | arch=(x86_64) |
40 | @@ -32,7 +32,7 @@ package() { |
41 | cd "$srcdir/${pkgname}-${pkgver}-${pkgrel}-${arch}" || |
42 | cd "$srcdir/${pkgname}" |
43 | |
44 | - python3 ./setup.py install --root="$pkgdir" --prefix=/usr --optimize=1 |
45 | + pip3 install --root="${pkgdir}" --no-deps --ignore-installed ${pkgname} |
46 | |
47 | install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" |
48 | install -Dm644 README.md "${pkgdir}/usr/share/doc/${pkgname}/README.md" |
49 | diff --git a/README.md b/README.md |
50 | index 7943082..dd55b8b 100644 |
51 | --- a/README.md |
52 | +++ b/README.md |
53 | @@ -3,7 +3,7 @@ |
54 | ### Welcome to ptrack, a powerful and user-friendly CLI utility for tracking the progress of your file operations. |
55 | ### Designed to be as concise, efficient and performance-optimized, ptrack works swiftly and accurately, while providing insight into the progress of the task at hand. |
56 | |
57 | -*Version: 0.2.5* |
58 | +*Version: 1.0.0* |
59 | |
60 | *** |
61 | |
62 | diff --git a/build/lib/ptrack/__init__.py b/build/lib/ptrack/__init__.py |
63 | new file mode 100644 |
64 | index 0000000..bf11915 |
65 | --- /dev/null |
66 | +++ b/build/lib/ptrack/__init__.py |
67 | @@ -0,0 +1,16 @@ |
68 | +import argparse |
69 | +version="1.0.0" |
70 | + |
71 | +parser = argparse.ArgumentParser(description='A simple CLI utility for asthetically tracking progress when copying or moving files.') |
72 | +parser.add_argument('-v', '--verbose', action='store_true', help='verbose output') |
73 | +parser.add_argument('-c', '--copy', action='store_true', help='copy files (You can use `ptc` instead of `ptrack -c`)') |
74 | +parser.add_argument('-m', '--move', action='store_true', help='move files (You can use `ptm` instead of `ptrack -m`)') |
75 | +parser.add_argument('-d', '--download', action='store_true', help='download files (You can use `ptd` instead of `ptrack -d`)') |
76 | +parser.add_argument('-V', '--version', action='version', version='%(prog)s' + version) |
77 | + |
78 | +args, unknown = parser.parse_known_args() |
79 | + |
80 | +verbose = args.verbose |
81 | +copy = args.copy |
82 | +move = args.move |
83 | +download = args.download |
84 | diff --git a/build/lib/ptrack/main.py b/build/lib/ptrack/main.py |
85 | new file mode 100644 |
86 | index 0000000..44e9aa6 |
87 | --- /dev/null |
88 | +++ b/build/lib/ptrack/main.py |
89 | @@ -0,0 +1,215 @@ |
90 | +import os |
91 | +import re |
92 | +import sys |
93 | +import ptrack |
94 | +from ptrack.methods import format_file_size, regular_copy, verbose_copy, hlp, getTotalSize, CustomFileSizeColumn |
95 | +from rich.progress import Progress, BarColumn, TextColumn, TimeRemainingColumn, FileSizeColumn |
96 | +from rich.console import Console |
97 | +from datetime import timedelta |
98 | +import shutil |
99 | +import requests |
100 | +import validators |
101 | + |
102 | +verbose = ptrack.verbose |
103 | +argCopy = ptrack.copy |
104 | +argMove = ptrack.move |
105 | +argDownload = ptrack.download |
106 | + |
107 | + |
108 | +def run(process): |
109 | + console = Console() |
110 | + |
111 | + if len(sys.argv) < 3: |
112 | + hlp() |
113 | + if process == "Copying": |
114 | + console.print("[bold cyan]Usage: ptc [OPTIONS] SOURCE... DESTINATION[/bold cyan]") |
115 | + elif process == "Moving": |
116 | + console.print("[bold cyan]Usage: ptm [OPTIONS] SOURCE... DESTINATION[/bold cyan]") |
117 | + sys.exit(1) |
118 | + |
119 | + src_paths = sys.argv[1:-1] |
120 | + dst = sys.argv[-1] |
121 | + srcPaths = [] |
122 | + |
123 | + for path in src_paths: |
124 | + if path.endswith('/'): |
125 | + path = path[:-1] |
126 | + srcPaths.append(path) |
127 | + |
128 | + if os.path.isdir(dst): |
129 | + dst_dir = dst |
130 | + new_name = None |
131 | + else: |
132 | + dst_dir = os.path.dirname(dst) |
133 | + new_name = os.path.basename(dst) |
134 | + |
135 | + total_files = sum(len(files) for path in srcPaths for r, d, files in os.walk(path) if os.path.isdir(path)) + sum(1 for path in srcPaths if os.path.isfile(path)) |
136 | + total_size = getTotalSize(srcPaths) |
137 | + destination_path = os.path.join(dst_dir, os.path.basename(srcPaths[0]) if not new_name else new_name) |
138 | + |
139 | + current_file = 1 |
140 | + |
141 | + if total_files > 1: |
142 | + console.print(f"\n[#ea2a6f]{process}:[/#ea2a6f] [bold cyan]{total_files} files[/bold cyan]\n") |
143 | + else: |
144 | + for src_path in srcPaths: |
145 | + if os.path.isfile(src_path): |
146 | + console.print(f"\n[#ea2a6f]{process}:[/#ea2a6f] [bold cyan] {os.path.basename(src_path)} [/bold cyan]\n") |
147 | + |
148 | + if verbose: |
149 | + for src_path in srcPaths: |
150 | + if os.path.isfile(src_path): |
151 | + dst_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name) |
152 | + terminate = verbose_copy(src_path, dst_path, console, current_file, total_files, file_name=os.path.basename(src_path)) |
153 | + current_file += 1 |
154 | + if terminate == 'c': |
155 | + console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
156 | + sys.exit(1) |
157 | + else: |
158 | + for root, dirs, files in os.walk(src_path): |
159 | + for file in files: |
160 | + src_file_path = os.path.join(root, file) |
161 | + relative_path = os.path.relpath(src_file_path, start=src_path) |
162 | + dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name, relative_path) |
163 | + os.makedirs(os.path.dirname(src_file_path), exist_ok=True) |
164 | + terminate = verbose_copy(src_file_path, dst_file_path, console, current_file, total_files, file_name=file) |
165 | + current_file += 1 |
166 | + if terminate == 'c': |
167 | + console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
168 | + sys.exit(1) |
169 | + else: |
170 | + with Progress( |
171 | + BarColumn(bar_width=50), |
172 | + "[progress.percentage]{task.percentage:>3.0f}%", |
173 | + TimeRemainingColumn(), |
174 | + "[#ea2a6f][[/#ea2a6f]", |
175 | + FileSizeColumn(), |
176 | + "[#ea2a6f]/[/#ea2a6f]", |
177 | + TextColumn("[bold cyan]{task.fields[total_size]}[/bold cyan]"), |
178 | + "[#ea2a6f]][/#ea2a6f]", |
179 | + TextColumn("-[bold yellow] {task.fields[current_file_name]}[/bold yellow]"), |
180 | + console=console, |
181 | + auto_refresh=False |
182 | + ) as progress: |
183 | + task = progress.add_task("", total=total_size, total_size=format_file_size(total_size), current_file_name="Initializing...") |
184 | + |
185 | + try: |
186 | + for src_path in srcPaths: |
187 | + if os.path.isfile(src_path): |
188 | + src_file_path = src_path |
189 | + dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name) |
190 | + file_premissions = os.stat(src_file_path).st_mode |
191 | + progress.update(task, current_file_name=os.path.basename(src_path), refresh=True) # Force refresh |
192 | + terminate = regular_copy(src_path, dst_file_path, console, task, progress, file_name=os.path.basename(src_path)) |
193 | + if terminate == 'c': |
194 | + console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
195 | + sys.exit(1) |
196 | + else: |
197 | + os.chmod(dst_file_path, file_premissions) |
198 | + |
199 | + else: |
200 | + for root, dirs, files in os.walk(src_path): |
201 | + for file in files: |
202 | + src_file_path = os.path.join(root, file) |
203 | + relative_path = os.path.relpath(src_file_path, start=src_path) |
204 | + dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name, relative_path) |
205 | + os.makedirs(os.path.dirname(dst_file_path), exist_ok=True) |
206 | + progress.update(task, current_file_name=file, refresh=True) # Force refresh |
207 | + regular_copy(src_file_path, dst_file_path, console, task, progress, file_name=file) |
208 | + |
209 | + except KeyboardInterrupt: |
210 | + console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
211 | + sys.exit(1) |
212 | + |
213 | + return srcPaths |
214 | + |
215 | + |
216 | +def download(): |
217 | + console = Console() |
218 | + urls = sys.argv[1:] |
219 | + |
220 | + if len(urls) == 0: |
221 | + console.print("\n[bold red][-][/bold red] No URL provided.\n") |
222 | + sys.exit() |
223 | + |
224 | + num_urls = len(urls) |
225 | + for url in urls: |
226 | + if url.startswith('-'): |
227 | + num_urls -= 1 |
228 | + elif not validators.url(url): |
229 | + console.print(f"\n[bold red][-][/bold red] Invalid URL: [bold yellow]{url}[/bold yellow]\n") |
230 | + sys.exit() |
231 | + |
232 | + console.print(f"\n[#ea2a6f]Downloading:[/#ea2a6f] [bold yellow]{num_urls}[/bold yellow] [bold cyan]files[/bold cyan]\n") |
233 | + |
234 | + errors = [] |
235 | + for url in urls: |
236 | + try: |
237 | + if url.startswith('-'): |
238 | + continue |
239 | + |
240 | + response = requests.get(url, stream=True, allow_redirects=True) |
241 | + total_size_in_bytes = int(response.headers.get('content-length', 0)) |
242 | + content_disposition = response.headers.get('content-disposition') |
243 | + destination_path = re.findall('filename="(.+)"', content_disposition)[0] if content_disposition and re.findall('filename="(.+)"', content_disposition) else os.path.basename(url) |
244 | + |
245 | + with Progress( |
246 | + BarColumn(bar_width=50), |
247 | + "[progress.percentage]{task.percentage:>3.0f}%", |
248 | + TimeRemainingColumn(), |
249 | + "[#ea2a6f][[/#ea2a6f]", |
250 | + CustomFileSizeColumn(), |
251 | + "[#ea2a6f]][/#ea2a6f]", |
252 | + f" {destination_path}", # This line will print the filename at the end |
253 | + console=console, |
254 | + auto_refresh=True |
255 | + ) as progress: |
256 | + task_id = progress.add_task("Downloading", total=total_size_in_bytes) |
257 | + block_size = 1024 # 1 Kibibyte |
258 | + with open(destination_path, 'wb') as file: |
259 | + for data in response.iter_content(block_size): |
260 | + file.write(data) |
261 | + progress.update(task_id, advance=block_size) |
262 | + except KeyboardInterrupt: |
263 | + console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
264 | + sys.exit(1) |
265 | + |
266 | + except Exception as e: |
267 | + console.print(f"\n[bold red]\[-][/bold red][bold white] Could not download file: [bold yellow]{url}[/bold yellow]\n") |
268 | + print(e) |
269 | + errors.append(url) |
270 | + |
271 | + if len(errors) == 0: |
272 | + console.print("\n[bold green]Download completed![/bold green]\n") |
273 | + else: |
274 | + console.print("[bold red]The following files could not be downloaded:[/bold red]\n") |
275 | + for error in errors: |
276 | + console.print(f"[bold red] -[/bold red][bold yellow]{error}[/bold yellow]\n") |
277 | + |
278 | + |
279 | +def copy(): |
280 | + run('Copying') |
281 | + |
282 | + |
283 | +def move(): |
284 | + src_paths = run('Moving') |
285 | + for src_path in src_paths: |
286 | + if os.path.isfile(src_path): |
287 | + os.remove(src_path) |
288 | + else: |
289 | + shutil.rmtree(src_path) |
290 | + |
291 | + |
292 | +def main(): |
293 | + if argMove: |
294 | + move() |
295 | + elif argCopy: |
296 | + copy() |
297 | + elif argDownload: |
298 | + download() |
299 | + else: |
300 | + hlp() |
301 | + |
302 | + |
303 | +if __name__ == "__main__": |
304 | + main() |
305 | diff --git a/build/lib/ptrack/methods.py b/build/lib/ptrack/methods.py |
306 | new file mode 100644 |
307 | index 0000000..01a2d63 |
308 | --- /dev/null |
309 | +++ b/build/lib/ptrack/methods.py |
310 | @@ -0,0 +1,147 @@ |
311 | +import os |
312 | +import sys |
313 | +import requests |
314 | +from rich.console import Console |
315 | +from rich.progress import Progress, TextColumn, BarColumn, TimeRemainingColumn, FileSizeColumn, Task, DownloadColumn, TimeElapsedColumn |
316 | +from rich.text import Text |
317 | +from datetime import timedelta |
318 | +from humanize import naturalsize |
319 | +import shutil |
320 | + |
321 | +console = Console() |
322 | +operation_cancelled = False |
323 | + |
324 | + |
325 | +def getTotalSize(srcPaths): |
326 | + total_size = 0 |
327 | + for path in srcPaths: |
328 | + if os.path.isfile(path): |
329 | + total_size += os.path.getsize(path) |
330 | + else: |
331 | + for r, d, files in os.walk(path): |
332 | + for f in files: |
333 | + fp = os.path.join(r, f) |
334 | + total_size += os.path.getsize(fp) |
335 | + return total_size |
336 | + |
337 | + |
338 | +def format_file_size(file_size): |
339 | + if file_size >= 1000 ** 4: # Terabyte |
340 | + return f"{round(file_size / (1000 ** 4))} TB" |
341 | + elif file_size >= 1000 ** 3: # Gigabyte |
342 | + return f"{round(file_size / (1000 ** 3))} GB" |
343 | + elif file_size >= 1000 ** 2: # Megabyte |
344 | + return f"{round(file_size / (1000 ** 2))} MB" |
345 | + elif file_size >= 1000: # Kilobyte |
346 | + return f"{round(file_size / 1000)} kB" |
347 | + else: # Byte |
348 | + return f"{file_size} bytes" |
349 | + |
350 | + |
351 | + |
352 | +def regular_copy(src, dst, console, task, progress, file_name): |
353 | + |
354 | + global operation_cancelled |
355 | + |
356 | + try: |
357 | + with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst: |
358 | + while True: |
359 | + buf = fsrc.read(1024*1024) |
360 | + if not buf or operation_cancelled: |
361 | + break |
362 | + filePremissions = os.stat(src).st_mode |
363 | + fdst.write(buf) |
364 | + progress.update(task, advance=len(buf)) |
365 | + progress.refresh() |
366 | + |
367 | + os.chmod(dst, filePremissions) |
368 | + |
369 | + except KeyboardInterrupt: |
370 | + operation_cancelled = True |
371 | + progress.stop() |
372 | + return "c" |
373 | + |
374 | + |
375 | +def verbose_copy(src, dst, console, current, total_files, file_name): |
376 | + operation_cancelled = False |
377 | + file_size = os.path.getsize(src) |
378 | + |
379 | + with Progress( |
380 | + BarColumn(bar_width=50), |
381 | + "[progress.percentage]{task.percentage:>3.0f}%", |
382 | + TimeRemainingColumn(), |
383 | + "[#ea2a6f][[/#ea2a6f]", |
384 | + FileSizeColumn(), |
385 | + "[#ea2a6f]/[/#ea2a6f]", |
386 | + TextColumn(f"[bold cyan]{format_file_size(file_size)}[/bold cyan]"), |
387 | + "[#ea2a6f]][/#ea2a6f]", |
388 | + f"({current} of {total_files}) - {file_name}", |
389 | + console=console, |
390 | + auto_refresh=False |
391 | + ) as progress: |
392 | + task = progress.add_task("", total=file_size, file_size=format_file_size(file_size)) |
393 | + |
394 | + try: |
395 | + with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst: |
396 | + while not progress.finished: |
397 | + buf = fsrc.read(1024*1024) |
398 | + if not buf or operation_cancelled: |
399 | + break |
400 | + fdst.write(buf) |
401 | + progress.update(task, advance=len(buf)) |
402 | + progress.refresh() |
403 | + |
404 | + shutil.copystat(src, dst) |
405 | + |
406 | + except KeyboardInterrupt: |
407 | + operation_cancelled = True |
408 | + progress.stop() |
409 | + return "c" |
410 | + |
411 | + |
412 | +def hlp(): |
413 | + print(""" |
414 | +usage: ptrack [-h] [-v] [-c] [-m] [-d] [-V] |
415 | + |
416 | +A simple CLI utility for asthetically tracking progress when copying or moving files. |
417 | + |
418 | +options: |
419 | + -h, --help show this help message and exit |
420 | + -v, --verbose verbose output |
421 | + -c, --copy copy files (You can use `ptc` instead of `ptrack -c`) |
422 | + -m, --move move files (You can use `ptm` instead of `ptrack -m`) |
423 | + -d, --download download files (You can use `ptd` instead of `ptrack -d`) |
424 | + -V, --version show program's version number and exit |
425 | +""") |
426 | + |
427 | + |
428 | +class CustomFileSizeColumn(FileSizeColumn, TimeElapsedColumn): |
429 | + def render(self, task): |
430 | + completed = task.completed |
431 | + total = task.total |
432 | + elapsed = task.elapsed |
433 | + |
434 | + if elapsed > 0.0: # Prevent division by zero |
435 | + download_speed = completed / elapsed # calculate download rate |
436 | + else: |
437 | + download_speed = 0 |
438 | + |
439 | + if total: |
440 | + size = Text.assemble( |
441 | + (f"{self._human_readable_size(completed)}", "green"), # completed |
442 | + (" / ", "none"), # separator |
443 | + (f"{self._human_readable_size(total)}", "red"), # total |
444 | + (" [", "none"), # opening square bracket |
445 | + (f"{self._human_readable_size(download_speed)}/s", "blue"), # download rate |
446 | + ("]", "none"), # closing square bracket |
447 | + ) |
448 | + else: |
449 | + size = Text(str(self._human_readable_size(completed))) |
450 | + return size |
451 | + |
452 | + def _human_readable_size(self, size: int) -> str: |
453 | + for unit in ['B', 'KB', 'MB', 'GB', 'TB']: |
454 | + if abs(size) < 1024.0: |
455 | + return f"{size:.1f}{unit}" |
456 | + size /= 1024.0 |
457 | + return f"{size:.1f}PB" |
458 | diff --git a/dist/ptrack-1.0.0-py3-none-any.whl b/dist/ptrack-1.0.0-py3-none-any.whl |
459 | new file mode 100644 |
460 | index 0000000..c1fa573 |
461 | Binary files /dev/null and b/dist/ptrack-1.0.0-py3-none-any.whl differ |
462 | diff --git a/dist/ptrack-1.0.0.tar.gz b/dist/ptrack-1.0.0.tar.gz |
463 | new file mode 100644 |
464 | index 0000000..c127219 |
465 | Binary files /dev/null and b/dist/ptrack-1.0.0.tar.gz differ |
466 | diff --git a/ptrack.egg-info/PKG-INFO b/ptrack.egg-info/PKG-INFO |
467 | new file mode 100644 |
468 | index 0000000..e28cefc |
469 | --- /dev/null |
470 | +++ b/ptrack.egg-info/PKG-INFO |
471 | @@ -0,0 +1,13 @@ |
472 | +Metadata-Version: 2.1 |
473 | +Name: ptrack |
474 | +Version: 1.0.0 |
475 | +Summary: A simple CLI utility for asthetically tracking progress when copying, moving or downloading files. |
476 | +Author: Connor Etherington |
477 | +Author-email: [email protected] |
478 | +License-File: LICENSE |
479 | +Requires-Dist: rich |
480 | +Requires-Dist: argparse |
481 | +Requires-Dist: requests |
482 | +Requires-Dist: validators |
483 | +Requires-Dist: setuptools |
484 | +Requires-Dist: humanize |
485 | diff --git a/ptrack.egg-info/SOURCES.txt b/ptrack.egg-info/SOURCES.txt |
486 | new file mode 100644 |
487 | index 0000000..086a784 |
488 | --- /dev/null |
489 | +++ b/ptrack.egg-info/SOURCES.txt |
490 | @@ -0,0 +1,12 @@ |
491 | +LICENSE |
492 | +README.md |
493 | +setup.py |
494 | +ptrack/__init__.py |
495 | +ptrack/main.py |
496 | +ptrack/methods.py |
497 | +ptrack.egg-info/PKG-INFO |
498 | +ptrack.egg-info/SOURCES.txt |
499 | +ptrack.egg-info/dependency_links.txt |
500 | +ptrack.egg-info/entry_points.txt |
501 | +ptrack.egg-info/requires.txt |
502 | +ptrack.egg-info/top_level.txt |
503 | diff --git a/ptrack.egg-info/dependency_links.txt b/ptrack.egg-info/dependency_links.txt |
504 | new file mode 100644 |
505 | index 0000000..8b13789 |
506 | --- /dev/null |
507 | +++ b/ptrack.egg-info/dependency_links.txt |
508 | @@ -0,0 +1 @@ |
509 | + |
510 | diff --git a/ptrack.egg-info/entry_points.txt b/ptrack.egg-info/entry_points.txt |
511 | new file mode 100644 |
512 | index 0000000..ea851b3 |
513 | --- /dev/null |
514 | +++ b/ptrack.egg-info/entry_points.txt |
515 | @@ -0,0 +1,5 @@ |
516 | +[console_scripts] |
517 | +ptc = ptrack.main:copy |
518 | +ptd = ptrack.main:download |
519 | +ptm = ptrack.main:move |
520 | +ptrack = ptrack.main:main |
521 | diff --git a/ptrack.egg-info/requires.txt b/ptrack.egg-info/requires.txt |
522 | new file mode 100644 |
523 | index 0000000..d19a378 |
524 | --- /dev/null |
525 | +++ b/ptrack.egg-info/requires.txt |
526 | @@ -0,0 +1,6 @@ |
527 | +rich |
528 | +argparse |
529 | +requests |
530 | +validators |
531 | +setuptools |
532 | +humanize |
533 | diff --git a/ptrack.egg-info/top_level.txt b/ptrack.egg-info/top_level.txt |
534 | new file mode 100644 |
535 | index 0000000..c003217 |
536 | --- /dev/null |
537 | +++ b/ptrack.egg-info/top_level.txt |
538 | @@ -0,0 +1 @@ |
539 | +ptrack |
540 | diff --git a/ptrack/__init__.py b/ptrack/__init__.py |
541 | index a329509..bf11915 100644 |
542 | --- a/ptrack/__init__.py |
543 | +++ b/ptrack/__init__.py |
544 | @@ -1,5 +1,5 @@ |
545 | import argparse |
546 | -version="0.2.5" |
547 | +version="1.0.0" |
548 | |
549 | parser = argparse.ArgumentParser(description='A simple CLI utility for asthetically tracking progress when copying or moving files.') |
550 | parser.add_argument('-v', '--verbose', action='store_true', help='verbose output') |
551 | diff --git a/ptrack/main.py b/ptrack/main.py |
552 | index a0b26dc..44e9aa6 100644 |
553 | --- a/ptrack/main.py |
554 | +++ b/ptrack/main.py |
555 | @@ -96,12 +96,17 @@ def run(process): |
556 | try: |
557 | for src_path in srcPaths: |
558 | if os.path.isfile(src_path): |
559 | + src_file_path = src_path |
560 | dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name) |
561 | + file_premissions = os.stat(src_file_path).st_mode |
562 | progress.update(task, current_file_name=os.path.basename(src_path), refresh=True) # Force refresh |
563 | terminate = regular_copy(src_path, dst_file_path, console, task, progress, file_name=os.path.basename(src_path)) |
564 | if terminate == 'c': |
565 | console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
566 | sys.exit(1) |
567 | + else: |
568 | + os.chmod(dst_file_path, file_premissions) |
569 | + |
570 | else: |
571 | for root, dirs, files in os.walk(src_path): |
572 | for file in files: |
573 | diff --git a/ptrack/methods.py b/ptrack/methods.py |
574 | index 2e9677e..01a2d63 100644 |
575 | --- a/ptrack/methods.py |
576 | +++ b/ptrack/methods.py |
577 | @@ -6,6 +6,7 @@ from rich.progress import Progress, TextColumn, BarColumn, TimeRemainingColumn, |
578 | from rich.text import Text |
579 | from datetime import timedelta |
580 | from humanize import naturalsize |
581 | +import shutil |
582 | |
583 | console = Console() |
584 | operation_cancelled = False |
585 | @@ -45,13 +46,16 @@ def regular_copy(src, dst, console, task, progress, file_name): |
586 | try: |
587 | with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst: |
588 | while True: |
589 | - buf = fsrc.read(1024 * 128) # Reduced buffer size for more frequent checks |
590 | + buf = fsrc.read(1024*1024) |
591 | if not buf or operation_cancelled: |
592 | break |
593 | + filePremissions = os.stat(src).st_mode |
594 | fdst.write(buf) |
595 | progress.update(task, advance=len(buf)) |
596 | progress.refresh() |
597 | |
598 | + os.chmod(dst, filePremissions) |
599 | + |
600 | except KeyboardInterrupt: |
601 | operation_cancelled = True |
602 | progress.stop() |
603 | @@ -86,6 +90,9 @@ def verbose_copy(src, dst, console, current, total_files, file_name): |
604 | fdst.write(buf) |
605 | progress.update(task, advance=len(buf)) |
606 | progress.refresh() |
607 | + |
608 | + shutil.copystat(src, dst) |
609 | + |
610 | except KeyboardInterrupt: |
611 | operation_cancelled = True |
612 | progress.stop() |
613 | diff --git a/recipe/meta.yaml b/recipe/meta.yaml |
614 | index 62dc45a..45860df 100644 |
615 | --- a/recipe/meta.yaml |
616 | +++ b/recipe/meta.yaml |
617 | @@ -1,6 +1,6 @@ |
618 | package: |
619 | name: ptrack |
620 | - version: 0.2.5 |
621 | + version: 1.0.0 |
622 | |
623 | source: |
624 | path: .. |
625 | diff --git a/setup.py b/setup.py |
626 | index 2c8aa5c..1bfa98a 100644 |
627 | --- a/setup.py |
628 | +++ b/setup.py |
629 | @@ -2,7 +2,7 @@ from setuptools import setup, find_packages |
630 | |
631 | setup( |
632 | name='ptrack', |
633 | - version="0.2.5", |
634 | + version="1.0.0", |
635 | description='A simple CLI utility for asthetically tracking progress when copying, moving or downloading files.', |
636 | author='Connor Etherington', |
637 | author_email='[email protected]', |