PyHardLinkBackup 1.5.0__py3-none-any.whl

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.
Files changed (42) hide show
  1. PyHardLinkBackup/__init__.py +7 -0
  2. PyHardLinkBackup/__main__.py +10 -0
  3. PyHardLinkBackup/backup.py +261 -0
  4. PyHardLinkBackup/cli_app/__init__.py +41 -0
  5. PyHardLinkBackup/cli_app/phlb.py +123 -0
  6. PyHardLinkBackup/cli_dev/__init__.py +70 -0
  7. PyHardLinkBackup/cli_dev/benchmark.py +138 -0
  8. PyHardLinkBackup/cli_dev/code_style.py +12 -0
  9. PyHardLinkBackup/cli_dev/packaging.py +65 -0
  10. PyHardLinkBackup/cli_dev/shell_completion.py +23 -0
  11. PyHardLinkBackup/cli_dev/testing.py +52 -0
  12. PyHardLinkBackup/cli_dev/update_readme_history.py +33 -0
  13. PyHardLinkBackup/compare_backup.py +212 -0
  14. PyHardLinkBackup/constants.py +16 -0
  15. PyHardLinkBackup/logging_setup.py +124 -0
  16. PyHardLinkBackup/rebuild_databases.py +176 -0
  17. PyHardLinkBackup/tests/__init__.py +36 -0
  18. PyHardLinkBackup/tests/test_backup.py +628 -0
  19. PyHardLinkBackup/tests/test_compare_backup.py +86 -0
  20. PyHardLinkBackup/tests/test_doc_write.py +26 -0
  21. PyHardLinkBackup/tests/test_doctests.py +10 -0
  22. PyHardLinkBackup/tests/test_project_setup.py +46 -0
  23. PyHardLinkBackup/tests/test_readme.py +75 -0
  24. PyHardLinkBackup/tests/test_readme_history.py +9 -0
  25. PyHardLinkBackup/tests/test_rebuild_database.py +224 -0
  26. PyHardLinkBackup/utilities/__init__.py +0 -0
  27. PyHardLinkBackup/utilities/file_hash_database.py +62 -0
  28. PyHardLinkBackup/utilities/file_size_database.py +46 -0
  29. PyHardLinkBackup/utilities/filesystem.py +158 -0
  30. PyHardLinkBackup/utilities/humanize.py +39 -0
  31. PyHardLinkBackup/utilities/rich_utils.py +99 -0
  32. PyHardLinkBackup/utilities/sha256sums.py +61 -0
  33. PyHardLinkBackup/utilities/tee.py +40 -0
  34. PyHardLinkBackup/utilities/tests/__init__.py +0 -0
  35. PyHardLinkBackup/utilities/tests/test_file_hash_database.py +143 -0
  36. PyHardLinkBackup/utilities/tests/test_file_size_database.py +138 -0
  37. PyHardLinkBackup/utilities/tests/test_filesystem.py +126 -0
  38. PyHardLinkBackup/utilities/tyro_cli_shared_args.py +12 -0
  39. pyhardlinkbackup-1.5.0.dist-info/METADATA +600 -0
  40. pyhardlinkbackup-1.5.0.dist-info/RECORD +42 -0
  41. pyhardlinkbackup-1.5.0.dist-info/WHEEL +4 -0
  42. pyhardlinkbackup-1.5.0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,600 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyHardLinkBackup
3
+ Version: 1.5.0
4
+ Summary: HardLink/Deduplication Backups with Python
5
+ Project-URL: Documentation, https://github.com/jedie/PyHardLinkBackup
6
+ Project-URL: Source, https://github.com/jedie/PyHardLinkBackup
7
+ Author-email: Jens Diemer <PyHardLinkBackup@jensdiemer.de>
8
+ License: GPL-3.0-or-later
9
+ Requires-Python: >=3.12
10
+ Requires-Dist: bx-py-utils
11
+ Requires-Dist: cli-base-utilities>=0.27.0
12
+ Requires-Dist: rich
13
+ Requires-Dist: tyro
14
+ Description-Content-Type: text/markdown
15
+
16
+ # PyHardLinkBackup
17
+
18
+ [![tests](https://github.com/jedie/PyHardLinkBackup/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/jedie/PyHardLinkBackup/actions/workflows/tests.yml)
19
+ [![codecov](https://codecov.io/github/jedie/PyHardLinkBackup/branch/main/graph/badge.svg)](https://app.codecov.io/github/jedie/PyHardLinkBackup)
20
+ [![PyHardLinkBackup @ PyPi](https://img.shields.io/pypi/v/PyHardLinkBackup?label=PyHardLinkBackup%20%40%20PyPi)](https://pypi.org/project/PyHardLinkBackup/)
21
+ [![Python Versions](https://img.shields.io/pypi/pyversions/PyHardLinkBackup)](https://github.com/jedie/PyHardLinkBackup/blob/main/pyproject.toml)
22
+ [![License GPL-3.0-or-later](https://img.shields.io/pypi/l/PyHardLinkBackup)](https://github.com/jedie/PyHardLinkBackup/blob/main/LICENSE)
23
+
24
+ HardLink/Deduplication Backups with Python
25
+
26
+ **WIP:** v1.0.0 is a complete rewrite of PyHardLinkBackup.
27
+
28
+ It's similar to `rsync --link-dest` but the deduplication is done globally for all backups and all paths.
29
+
30
+ ## installation
31
+
32
+ You can use [pipx](https://pipx.pypa.io/stable/installation/) to install and use PyHardLinkBackup, e.g.:
33
+
34
+ ```bash
35
+ sudo apt install pipx
36
+
37
+ pipx install PyHardLinkBackup
38
+ ```
39
+
40
+ After this you can call the CLI via `phlb` command.
41
+ The main command is `phlb backup <source> <destination>`:
42
+
43
+ [comment]: <> (✂✂✂ auto generated backup help start ✂✂✂)
44
+ ```
45
+ usage: phlb backup [-h] [BACKUP OPTIONS]
46
+
47
+ Backup the source directory to the destination directory using hard links for deduplication.
48
+
49
+ ╭─ positional arguments ──────────────────────────────────────────────────────────────────────────────────────╮
50
+ │ source Source directory to back up. (required) │
51
+ │ destination Destination directory for the backup. (required) │
52
+ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
53
+ ╭─ options ───────────────────────────────────────────────────────────────────────────────────────────────────╮
54
+ │ -h, --help show this help message and exit │
55
+ │ --excludes [STR [STR ...]] │
56
+ │ List of directories to exclude from backup. (default: __pycache__ .cache .temp .tmp .tox .nox) │
57
+ │ --verbosity {debug,info,warning,error} │
58
+ │ Log level for console logging. (default: warning) │
59
+ │ --log-file-level {debug,info,warning,error} │
60
+ │ Log level for the log file (default: info) │
61
+ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
62
+ ```
63
+ [comment]: <> (✂✂✂ auto generated backup help end ✂✂✂)
64
+
65
+
66
+
67
+ Running a backup looks like:
68
+
69
+ ![2026-01-15-phlb1.png](https://raw.githubusercontent.com/jedie/jedie.github.io/main/screenshots/PyHardLinkBackup/2026-01-15-phlb1.png "2026-01-15-phlb1.png")
70
+
71
+
72
+
73
+ If it's finished it display a summary:
74
+
75
+ ![2026-01-15-phlb2.png](https://raw.githubusercontent.com/jedie/jedie.github.io/main/screenshots/PyHardLinkBackup/2026-01-15-phlb2.png "2026-01-15-phlb2.png")
76
+
77
+
78
+
79
+ complete help for main CLI app:
80
+
81
+ [comment]: <> (✂✂✂ auto generated main help start ✂✂✂)
82
+ ```
83
+ usage: phlb [-h] {backup,compare,rebuild,version}
84
+
85
+
86
+
87
+ ╭─ options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
88
+ │ -h, --help show this help message and exit │
89
+ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
90
+ ╭─ subcommands ────────────────────────────────────────────────────────────────────────────────────────────────────────╮
91
+ │ (required) │
92
+ │ • backup Backup the source directory to the destination directory using hard links for deduplication. │
93
+ │ • compare Compares a source tree with the last backup and validates all known file hashes. │
94
+ │ • rebuild Rebuild the file hash and size database by scanning all backup files. And also verify SHA256SUMS and/or │
95
+ │ store missing hashes in SHA256SUMS files. │
96
+ │ • version Print version and exit │
97
+ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
98
+ ```
99
+ [comment]: <> (✂✂✂ auto generated main help end ✂✂✂)
100
+
101
+
102
+ ### update
103
+
104
+ If you use pipx, just call:
105
+ ```bash
106
+ pipx upgrade PyHardLinkBackup
107
+ ```
108
+ see: https://pipx.pypa.io/stable/docs/#pipx-upgrade
109
+
110
+
111
+ ## concept
112
+
113
+ ### Implementation boundaries
114
+
115
+ * pure Python using >=3.12
116
+ * pathlib for path handling
117
+ * iterate filesystem with `os.scandir()`
118
+
119
+ ### overview
120
+
121
+ * Backups should be saved as normal files in the filesystem:
122
+ * non-proprietary format
123
+ * accessible without any extra software or extra meta files
124
+ * Create backups with versioning
125
+ * every backup run creates a complete filesystem snapshot tree
126
+ * every snapshot tree can be deleted, without affecting the other snapshots
127
+ * Deduplication with hardlinks:
128
+ * space-efficient incremental backups by linking unchanged files across snapshots instead of duplicating them
129
+ * find duplicate files everywhere (even if renamed or moved files)
130
+
131
+
132
+ ### used solutions
133
+
134
+ * Used `sha256` hash algorithm to identify file content
135
+ * Small file handling
136
+ * Always copy small files and never hardlink them
137
+ * Don't store size and hash of these files in the deduplication lookup tables
138
+
139
+ #### Deduplication lookup methods
140
+
141
+ To avoid unnecessary file copy operations, we need a fast method to find duplicate files.
142
+ Our approach is based on two steps: file size and file content hash.
143
+ Because the file size is very fast to compare.
144
+
145
+ ###### size "database"
146
+
147
+ We store all existing file sizes as empty files in a special folder structure:
148
+
149
+ * 1st level: first 2 digits of the size in bytes
150
+ * 2nd level: next 2 digits of the size in bytes
151
+ * file: full size in bytes as filename
152
+
153
+ e.g.: file size `123456789` bytes stored in: `{destination}/.phlb/size-lookup/89/67/123456789`
154
+ We skip files lower than `1000` bytes, so no filling with leading zeros is needed ;)
155
+
156
+ ###### hash "database"
157
+
158
+ We store the `file hash` <-> `hardlink pointer` mapping in a special folder structure:
159
+
160
+ * 1st level: first 2 chars of the hex encoded hash
161
+ * 2nd level: next 2 chars of the hex encoded hash
162
+ * file: full hex encoded hash as filename
163
+
164
+ e.g.: hash like `abcdef123...` stored in: `{destination}/.phlb/hash-lookup/ab/cd/abcdef123...`
165
+ The file contains only the relative path to the first hardlink of this file content.
166
+
167
+
168
+ ## start development
169
+
170
+ ```bash
171
+ ~$ git clone https://github.com/jedie/PyHardLinkBackup.git
172
+ ~$ cd PyHardLinkBackup
173
+ ~/PyHardLinkBackup$ ./cli.py --help
174
+ ~/PyHardLinkBackup$ ./dev-cli.py --help
175
+ ```
176
+
177
+ [comment]: <> (✂✂✂ auto generated dev help start ✂✂✂)
178
+ ```
179
+ usage: ./dev-cli.py [-h] {benchmark-hashes,coverage,install,lint,mypy,nox,pip-audit,publish,scan-benchmark,shell-completion,test,update,update-readme-history,update-test-snapshot-files,version}
180
+
181
+
182
+
183
+ ╭─ options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
184
+ │ -h, --help show this help message and exit │
185
+ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
186
+ ╭─ subcommands ────────────────────────────────────────────────────────────────────────────────────────────────────────╮
187
+ │ (required) │
188
+ │ • benchmark-hashes │
189
+ │ Benchmark different file hashing algorithms on the given path. │
190
+ │ • coverage Run tests and show coverage report. │
191
+ │ • install Install requirements and 'PyHardLinkBackup' via pip as editable. │
192
+ │ • lint Check/fix code style by run: "ruff check --fix" │
193
+ │ • mypy Run Mypy (configured in pyproject.toml) │
194
+ │ • nox Run nox │
195
+ │ • pip-audit Run pip-audit check against current requirements files │
196
+ │ • publish Build and upload this project to PyPi │
197
+ │ • scan-benchmark │
198
+ │ Benchmark our filesystem scan routine. │
199
+ │ • shell-completion │
200
+ │ Setup shell completion for this CLI (Currently only for bash shell) │
201
+ │ • test Run unittests │
202
+ │ • update Update dependencies (uv.lock) and git pre-commit hooks │
203
+ │ • update-readme-history │
204
+ │ Update project history base on git commits/tags in README.md Will be exited with 1 if the README.md │
205
+ │ was updated otherwise with 0. │
206
+ │ │
207
+ │ Also, callable via e.g.: │
208
+ │ python -m cli_base update-readme-history -v │
209
+ │ • update-test-snapshot-files │
210
+ │ Update all test snapshot files (by remove and recreate all snapshot files) │
211
+ │ • version Print version and exit │
212
+ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
213
+ ```
214
+ [comment]: <> (✂✂✂ auto generated dev help end ✂✂✂)
215
+
216
+
217
+ ## Backwards-incompatible changes
218
+
219
+ ### v1.0.0
220
+
221
+ v1 is a complete rewrite of PyHardLinkBackup.
222
+
223
+ Overview of main changes:
224
+
225
+ * Remove Django dependency:
226
+ * No SQlite database anymore -> Data for deduplication stored in filesystem only
227
+ * No Django Admin, because we have no database anymore ;)
228
+ * Change hash algorithm from SHA512 to SHA256, because it's faster and still secure enough
229
+ * Don't store `*.sha512` for every file anymore -> We store one `SHA256SUMS` file in every backup directory
230
+
231
+ ## History
232
+
233
+ [comment]: <> (✂✂✂ auto generated history start ✂✂✂)
234
+
235
+ * [v1.5.0](https://github.com/jedie/PyHardLinkBackup/compare/v1.4.1...v1.5.0)
236
+ * 2026-01-17 - NEW: Compare command to verify source tree with last backup
237
+ * [v1.4.1](https://github.com/jedie/PyHardLinkBackup/compare/v1.4.0...v1.4.1)
238
+ * 2026-01-16 - Bugfix large file handling
239
+ * [v1.4.0](https://github.com/jedie/PyHardLinkBackup/compare/v1.3.0...v1.4.0)
240
+ * 2026-01-16 - Create log file in backup and a summary.txt
241
+ * 2026-01-16 - Run CI tests on macos, too.
242
+ * 2026-01-16 - add dev cli command "scan-benchmark"
243
+ * [v1.3.0](https://github.com/jedie/PyHardLinkBackup/compare/v1.2.0...v1.3.0)
244
+ * 2026-01-15 - Verify SHA256SUMS files in "rebuild" command, too.
245
+ * 2026-01-15 - Code cleanup: use more generic names for and in BackupProgress
246
+ * 2026-01-15 - Add tests for rebuild
247
+ * 2026-01-15 - Add command to "rebuld" the size and hash filesystem database
248
+ * 2026-01-15 - Add screenshots in the README
249
+
250
+ <details><summary>Expand older history entries ...</summary>
251
+
252
+ * [v1.2.0](https://github.com/jedie/PyHardLinkBackup/compare/v1.1.0...v1.2.0)
253
+ * 2026-01-15 - Add error handling: Log exception but continue with the backup
254
+ * 2026-01-15 - Check permission and hadlink support on destination path
255
+ * 2026-01-14 - Enhance progress bars
256
+ * 2026-01-14 - A a note to rsync --link-dest
257
+ * 2026-01-14 - Use cli_base.cli_tools.test_utils.base_testcases
258
+ * [v1.1.0](https://github.com/jedie/PyHardLinkBackup/compare/v1.0.1...v1.1.0)
259
+ * 2026-01-14 - Change backup timestamp directory to old schema: '%Y-%m-%d-%H%M%S'
260
+ * 2026-01-14 - Add "Overview of main changes" to README
261
+ * [v1.0.1](https://github.com/jedie/PyHardLinkBackup/compare/v1.0.0...v1.0.1)
262
+ * 2026-01-13 - Store SHA256SUMS files in backup directories
263
+ * [v1.0.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.13.0...v1.0.0)
264
+ * 2026-01-13 - Change "./cli.py" to "phlb" (because it's the name installed via pipx)
265
+ * 2026-01-13 - Update README
266
+ * 2026-01-13 - Fix benchmark moved to dev CLI ;)
267
+ * 2026-01-13 - Remove tyro warning
268
+ * 2026-01-13 - Move "benchmark_hashes" from app to dev cli (It's more for testing)
269
+ * 2026-01-13 - Rename [project.scripts] hooks
270
+ * 2026-01-13 - Add DocWrite, handle broken symlinks, keep file meta, handle missing hardlink sources
271
+ * 2026-01-12 - First working iteration with rich progess bar
272
+ * 2026-01-08 - Rewrite everything
273
+ * [v0.13.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.12.3...v0.13.0)
274
+ * 2020-03-18 - release v0.13.0
275
+ * 2020-03-17 - deactivate pypy tests in travis, because of SQLite errors, like:
276
+ * 2020-03-17 - make CI pipeline easier
277
+ * 2020-03-17 - update README
278
+ * 2020-03-17 - Fix misleading error msg for dst OSError, bad exception handling #23
279
+ * 2020-03-17 - Change Django Admin header
280
+ * 2020-03-17 - Fix "run django server doesn't work" #39
281
+ * 2020-03-17 - test release v0.12.4.rc1
282
+ * 2020-03-17 - Simplify backup process bar update code
283
+ * 2020-03-17 - Bugfix add command if "phlb_config.ini" doesn't match with database entry
284
+ * 2020-03-17 - bugfix "add" command
285
+ * 2020-03-17 - change CHUNK_SIZE in ini config to MIN_CHUNK_SIZE
286
+ * 2020-03-17 - update requirements
287
+ * 2020-03-17 - release v0.12.4.rc0
288
+ * 2020-03-17 - dynamic chunk size
289
+ * 2020-03-17 - ignore *.sha512 by default
290
+ * 2020-03-17 - Update boot_pyhardlinkbackup.sh
291
+ * [v0.12.3](https://github.com/jedie/PyHardLinkBackup/compare/v0.12.2...v0.12.3)
292
+ * 2020-03-17 - update README.rst
293
+ * 2020-03-17 - don't publish if tests fail
294
+ * 2020-03-17 - cleanup pytest config
295
+ * 2020-03-17 - Fix "Files to backup" message and update tests
296
+ * 2020-03-16 - Fix #44 - wroing file size in process bar
297
+ * 2020-03-16 - just warn if used directly (needfull for devlopment to call this directly ;)
298
+ * 2020-03-16 - update requirements
299
+ * 2020-03-16 - +pytest-randomly
300
+ * [v0.12.2](https://github.com/jedie/PyHardLinkBackup/compare/v0.12.1...v0.12.2)
301
+ * 2020-03-06 - repare v0.12.2 release
302
+ * 2020-03-06 - enhance log file content
303
+ * 2020-03-06 - update requirements
304
+ * 2020-03-06 - Update README.creole
305
+ * 2020-03-05 - Fix #40 by decrease log level
306
+ * 2020-03-05 - Update boot_pyhardlinkbackup.cmd
307
+ * 2020-03-05 - Update boot_pyhardlinkbackup.sh
308
+ * [v0.12.1](https://github.com/jedie/PyHardLinkBackup/compare/v0.12.0...v0.12.1)
309
+ * 2020-03-05 - update tests and set version to 0.12.1
310
+ * 2020-03-05 - less verbose pytest output
311
+ * 2020-03-05 - pyhardlinkbackup.ini -> PyHardLinkBackup.ini
312
+ * 2020-03-05 - revert renaming the main destination directory back to: "PyHardLinkBackup"
313
+ * [v0.12.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.11.0...v0.12.0)
314
+ * 2020-03-05 - repare v0.12.0 release
315
+ * 2020-03-05 - use poetry_publish.tests.test_project_setup code parts
316
+ * 2020-03-05 - Update README.creole
317
+ * 2020-03-05 - renove unused code parts
318
+ * 2020-03-05 - don't test with pypy
319
+ * 2020-03-05 - fix code style
320
+ * 2020-03-05 - Fix tests with different python versions
321
+ * 2020-03-05 - bugfix test: getting manage.py in tox
322
+ * 2020-03-05 - update requirements
323
+ * 2020-03-05 - Don't create "summary" file: log everything in .log file
324
+ * 2020-02-16 - Handle Backup errors.
325
+ * 2020-02-16 - Bugfix processed files count
326
+ * 2020-02-16 - Bugfix: Mark backup run instance as "completed"
327
+ * 2020-02-16 - code cleanup
328
+ * 2020-02-16 - Use assert_is_file() from django-tools and Path().read_text()
329
+ * 2020-02-16 - Don't init a second PathHelper instance!
330
+ * 2020-02-02 - WIP: update Tests
331
+ * 2020-02-02 - run linters as last step
332
+ * 2020-02-02 - remove unused import
333
+ * 2020-02-02 - update IterFilesystem
334
+ * 2020-02-02 - bugfix file size formats
335
+ * 2020-02-02 - stats_helper.abort always exists in newer IterFilesystem version
336
+ * 2020-02-02 - Link or copy the log file to backup and fix summary/output
337
+ * 2020-02-02 - remove converage config from pytest.ini
338
+ * 2020-02-02 - pytest-django: reuse db + nomigrations
339
+ * 2020-02-02 - remove not needed django_project/wsgi.py
340
+ * 2020-02-02 - update README
341
+ * 2020-02-02 - pyhardlinkbackup/{phlb_cli.py => phlb/cli.py}
342
+ * 2020-02-02 - fix Django project setup and add tests for it
343
+ * 2020-02-02 - update Django project settings
344
+ * 2020-02-02 - test release 0.12.0.dev0
345
+ * 2020-02-02 - include poetry.lock file
346
+ * 2020-02-02 - set version to v0.11.0.dev0
347
+ * 2020-02-02 - remove flak8 test (will be done in ci via Makefile)
348
+ * 2020-02-02 - some code updates
349
+ * 2020-02-02 - apply "make fix-code-style"
350
+ * 2020-02-02 - update Makefile: poetry_publish -> pyhardlinkbackup ;)
351
+ * 2020-02-02 - add README.rst
352
+ * 2020-02-02 - /{PyHardLinkBackup => pyhardlinkbackup}/
353
+ * 2020-02-02 - + "make runserver"
354
+ * 2020-02-02 - delete setup.py and setup.cfg
355
+ * 2020-02-02 - WIP: use poetry and poetry-publish
356
+ * 2020-02-02 - update to Django v2.2.x LTS
357
+ * 2019-10-20 - fixup! WIP: update tests
358
+ * 2019-10-20 - +tests_require=['pytest',]
359
+ * 2019-10-20 - update "add" command
360
+ * 2019-10-20 - add setup.cfg
361
+ * 2019-10-13 - use https://github.com/jedie/IterFilesystem
362
+ * 2019-09-18 - remove support for old python versions
363
+ * 2019-09-18 - fix pytest run
364
+ * 2019-03-03 - use pytest + tox and add flake8+isort config files
365
+ * [v0.11.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.10.1...v0.11.0)
366
+ * 2019-03-03 - +email
367
+ * 2019-03-03 - use django v1.11.x
368
+ * 2019-03-03 - update django
369
+ * 2019-03-03 - remove: create_dev_env.sh
370
+ * 2019-03-03 - just code formatting with black
371
+ * 2019-03-03 - update setup.py
372
+ * 2019-03-03 - +create_dev_env.sh
373
+ * 2018-09-12 - Update boot_pyhardlinkbackup.cmd
374
+ * 2018-08-03 - Update phlb_run_tests.sh
375
+ * 2018-08-03 - Update phlb_upgrade_PyHardLinkBackup.sh
376
+ * 2017-12-11 - code cleanup
377
+ * 2017-12-10 - Update boot_pyhardlinkbackup.sh
378
+ * 2017-12-10 - set DJANGO_SETTINGS_MODULE
379
+ * 2017-11-17 - +codecov.io
380
+ * [v0.10.1](https://github.com/jedie/PyHardLinkBackup/compare/v0.10.0...v0.10.1)
381
+ * 2016-09-09 - fix #24 by skip not existing files
382
+ * 2016-08-20 - fix typos, improve grammar, add borgbackup
383
+ * 2016-06-28 - use the origin model to use the config methods:
384
+ * 2016-06-27 - use get_model()
385
+ * 2016-06-27 - add missing migrations for:
386
+ * 2016-04-28 - Update README.creole
387
+ * 2016-04-27 - bugfix ~/
388
+ * [v0.10.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.9.0...v0.10.0)
389
+ * 2016-04-27 - -%APPDATA% +%ProgramFiles%
390
+ * 2016-04-26 - v0.9.1
391
+ * 2016-04-26 - bugfix boot cmd
392
+ * 2016-04-26 - add note
393
+ * 2016-04-26 - migrate after boot
394
+ * 2016-04-26 - add migrate scripts
395
+ * 2016-03-08 - bugfix if path contains spaces
396
+ * 2016-02-29 - Update README.creole
397
+ * [v0.9.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.8.0...v0.9.0)
398
+ * 2016-02-10 - v0.9.0
399
+ * 2016-02-10 - fix AppVeyor
400
+ * 2016-02-10 - fix path?
401
+ * 2016-02-10 - add pathlib_revised
402
+ * 2016-02-10 - typo
403
+ * 2016-02-08 - try to combine linux and windows tests coverage via:
404
+ * 2016-02-08 - move Path2() to external lib: https://github.com/jedie/pathlib_revised
405
+ * 2016-02-08 - Use existing hash files in "phlb add" command:
406
+ * 2016-02-08 - Work-a-round for Windows MAX_PATH limit: Use \?\ path prefix internally.
407
+ * [v0.8.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.7.0...v0.8.0)
408
+ * 2016-02-04 - release v0.8.0
409
+ * 2016-02-04 - seems that windows/NTFS is less precise ;)
410
+ * 2016-02-04 - tqdm will not accept 0 bytes files ;)
411
+ * 2016-02-04 - new: "phlb add"
412
+ * 2016-02-04 - bugfix: display skip pattern info
413
+ * [v0.7.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.6.4...v0.7.0)
414
+ * 2016-02-03 - release v0.7.0
415
+ * 2016-02-03 - remove obsolete cli command and update cli unittests
416
+ * 2016-02-03 - do 'migrate' on every upgrade run, too.
417
+ * 2016-02-03 - Update README.creole
418
+ * 2016-02-03 - Fix: #17 and save a "phlb_config.ini" in every backup:
419
+ * 2016-02-02 - New: verify a existing backup
420
+ * 2016-02-02 - remove editable=False
421
+ * [v0.6.4](https://github.com/jedie/PyHardLinkBackup/compare/v0.6.3...v0.6.4)
422
+ * 2016-02-01 - v0.6.4
423
+ * 2016-02-01 - prepare for v0.6.4 release
424
+ * 2016-02-01 - Fix #13 - temp rename error, because of the Windows API limitation
425
+ * 2016-01-31 - bugfix in scanner if symlink is broken
426
+ * 2016-01-31 - display local variables on low level errors
427
+ * [v0.6.3](https://github.com/jedie/PyHardLinkBackup/compare/v0.6.2...v0.6.3)
428
+ * 2016-01-29 - Less verbose and better information about SKIP_DIRS/SKIP_PATTERNS hits
429
+ * 2016-01-29 - error -> info
430
+ * 2016-01-29 - +keywords +license
431
+ * [v0.6.2](https://github.com/jedie/PyHardLinkBackup/compare/v0.6.1...v0.6.2)
432
+ * 2016-01-29 - fix tests by change the mtime of the test files to get always the same order
433
+ * 2016-01-28 - Handle unexpected errors and KeyboardInterrupt
434
+ * [v0.6.1](https://github.com/jedie/PyHardLinkBackup/compare/v0.6.0...v0.6.1)
435
+ * 2016-01-28 - release v0.6.1
436
+ * 2016-01-28 - fix #13 by use a better rename routine
437
+ * [v0.6.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.5.1...v0.6.0)
438
+ * 2016-01-28 - start maring the admin nicer, see also: #7
439
+ * 2016-01-28 - faster backup by compare mtime/size only if old backup files exists
440
+ * [v0.5.1](https://github.com/jedie/PyHardLinkBackup/compare/v0.5.0...v0.5.1)
441
+ * 2016-01-27 - Squashed commit of the following:
442
+ * [v0.5.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.4.2...v0.5.0)
443
+ * 2016-01-27 - release v0.5.0
444
+ * 2016-01-27 - refactory source tree scan and use pathlib everywhere:
445
+ * 2016-01-24 - try to fix DB memory usage
446
+ * 2016-01-24 - Simulate not working os.link with mock
447
+ * 2016-01-24 - fix if duration==0
448
+ * 2016-01-24 - use mock to simulate not readable files
449
+ * 2016-01-24 - just move class
450
+ * 2016-01-23 - fix #10 and add --name cli argument and add unittests for the changes
451
+ * 2016-01-23 - alternative solutions
452
+ * [v0.4.2](https://github.com/jedie/PyHardLinkBackup/compare/v0.4.1...v0.4.2)
453
+ * 2016-01-22 - work-a-round for junction under windows
454
+ * 2016-01-22 - Display if out path can't created
455
+ * 2016-01-22 - print some more status information in between.
456
+ * 2016-01-22 - Update README.creole
457
+ * 2016-01-22 - typo
458
+ * 2016-01-22 - try to reproduce #11
459
+ * 2016-01-22 - check if test settings are active
460
+ * 2016-01-22 - needless
461
+ * 2016-01-22 - importand to change into current directory for:
462
+ * [v0.4.1](https://github.com/jedie/PyHardLinkBackup/compare/v0.4.0...v0.4.1)
463
+ * 2016-01-21 - merge get log content and fix windows tests
464
+ * 2016-01-21 - Skip files that can't be read/write
465
+ * 2016-01-21 - Update README.creole
466
+ * [v0.4.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.3.1...v0.4.0)
467
+ * 2016-01-21 - save summary and log file for every backup run
468
+ * 2016-01-21 - increase default chunk size to 20MB
469
+ * 2016-01-21 - typo
470
+ * 2016-01-21 - moved TODO:
471
+ * 2016-01-21 - journal_mode = MEMORY
472
+ * 2016-01-21 - wip
473
+ * 2016-01-21 - bugfix: use pathlib instance
474
+ * 2016-01-21 - activate py3.4 32bit tests
475
+ * 2016-01-21 - update
476
+ * 2016-01-21 - Bugfix for python < 3.5
477
+ * 2016-01-16 - WIP: Bugfix unittests for: Change .ini search path to every parent directory WIP: Save summary and log file for every backup run
478
+ * 2016-01-16 - Change .ini search path to every parent directory
479
+ * 2016-01-16 - Add a unittest for the NTFS 1024 hardlink limit
480
+ * 2016-01-15 - bugfix if unittests failed under appveyor
481
+ * 2016-01-15 - change timestamp stuff in unittests
482
+ * 2016-01-15 - Update README.creole
483
+ * 2016-01-15 - Create WindowsDevelopment.creole
484
+ * [v0.3.1](https://github.com/jedie/PyHardLinkBackup/compare/v0.3.0...v0.3.1)
485
+ * 2016-01-15 - v0.3.1
486
+ * 2016-01-15 - try to fix 'coveralls':
487
+ * 2016-01-15 - ignore temp cleanup error
488
+ * 2016-01-15 - fix some unittests under windows:
489
+ * 2016-01-15 - obsolete
490
+ * [v0.3.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.2.0...v0.3.0)
491
+ * 2016-01-15 - release v0.3.0
492
+ * 2016-01-14 - Squashed commit of the following:
493
+ * [v0.2.0](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.13...v0.2.0)
494
+ * 2016-01-13 - fix appveyor
495
+ * 2016-01-13 - Refactoring unitests and add more tests
496
+ * [v0.1.13](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.12...v0.1.13)
497
+ * 2016-01-12 - 0.1.13
498
+ * 2016-01-11 - set python versions
499
+ * 2016-01-11 - test oder versions
500
+ * 2016-01-11 - print path with %s and not with %r
501
+ * 2016-01-11 - start backup unittests
502
+ * 2016-01-11 - wip
503
+ * 2016-01-11 - wip: fix CI
504
+ * 2016-01-11 - own tests run with :memory: database in temp dir
505
+ * 2016-01-11 - wtf
506
+ * 2016-01-11 - wip: fix appveyor
507
+ * 2016-01-11 - Update README.creole
508
+ * 2016-01-11 - Fix appveyor
509
+ * 2016-01-11 - bugfix
510
+ * [v0.1.12](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.11...v0.1.12)
511
+ * 2016-01-11 - 0.1.12
512
+ * 2016-01-11 - unify .cmd files
513
+ * 2016-01-11 - update
514
+ * 2016-01-11 - use "phlb.exe helper" and merge code
515
+ * 2016-01-11 - bugfix
516
+ * 2016-01-11 - Appveyor work-a-round
517
+ * 2016-01-11 - +cmd_shell.cmd
518
+ * [v0.1.11](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.10...v0.1.11)
519
+ * 2016-01-10 - wip
520
+ * 2016-01-10 - cd checkout dir
521
+ * 2016-01-10 - don't wait for user input
522
+ * 2016-01-10 - appveyor.yml
523
+ * 2016-01-10 - fix travis CI?
524
+ * 2016-01-10 - test 'py'
525
+ * 2016-01-10 - update boot
526
+ * 2016-01-10 - +migrate
527
+ * 2016-01-10 - try to use the own boot script
528
+ * 2016-01-10 - +# http://www.appveyor.com
529
+ * 2016-01-10 - add badge icons
530
+ * 2016-01-10 - coveralls token
531
+ * 2016-01-10 - migrate database
532
+ * 2016-01-10 - abs path to work?
533
+ * 2016-01-10 - fix?
534
+ * 2016-01-10 - test local .ini change config
535
+ * 2016-01-10 - travis
536
+ * 2016-01-10 - debug config
537
+ * 2016-01-10 - bugfix extras_require
538
+ * 2016-01-10 - simple cli output test
539
+ * 2016-01-10 - refactor cli and start travis CI
540
+ * 2016-01-10 - install scandir via extras_require
541
+ * [v0.1.10](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.9...v0.1.10)
542
+ * 2016-01-10 - v0.1.10
543
+ * 2016-01-10 - cleanup after KeyboardInterrupt
544
+ * 2016-01-10 - always activate venv
545
+ * 2016-01-10 - shell scripts for linux
546
+ * 2016-01-10 - update README
547
+ * 2016-01-10 - add boot script for linux
548
+ * [v0.1.9](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.8...v0.1.9)
549
+ * 2016-01-08 - Helper files for Windows:
550
+ * 2016-01-08 - Update setup.py
551
+ * 2016-01-08 - Update README.creole
552
+ * [v0.1.8](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.7...v0.1.8)
553
+ * 2016-01-08 - django reloaded will not work under windows with venv
554
+ * 2016-01-08 - create more batch helper files
555
+ * 2016-01-08 - work-a-round for path problem under windows.
556
+ * [v0.1.7](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.6...v0.1.7)
557
+ * 2016-01-08 - bugfix line endings in config file
558
+ * [v0.1.6](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.5...v0.1.6)
559
+ * 2016-01-08 - remove checks: doesn't work with py3 venv
560
+ * [v0.1.5](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.4...v0.1.5)
561
+ * 2016-01-08 - add "pip upgrade" batch
562
+ * 2016-01-08 - bugfix to include the default config ini file ;)
563
+ * [v0.1.4](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.3...v0.1.4)
564
+ * 2016-01-07 - update windows boot file
565
+ * 2016-01-07 - include .ini files
566
+ * 2016-01-07 - rename
567
+ * [v0.1.3](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.2...v0.1.3)
568
+ * 2016-01-07 - remove 'scandir' from 'install_requires'
569
+ * [v0.1.2](https://github.com/jedie/PyHardLinkBackup/compare/v0.1.1...v0.1.2)
570
+ * 2016-01-07 - install and use "scandir" only if needed
571
+ * [v0.1.1](https://github.com/jedie/PyHardLinkBackup/compare/629bc4f...v0.1.1)
572
+ * 2016-01-07 - fix headline levels (for reSt)
573
+ * 2016-01-07 - start boot script for windows
574
+ * 2016-01-07 - v0.1.1
575
+ * 2016-01-07 - refactory .ini config usage
576
+ * 2016-01-07 - WIP: Use .ini file for base config
577
+ * 2016-01-07 - Update README.creole
578
+ * 2016-01-06 - move database to ~/PyHardLinkBackups.sqlite3
579
+ * 2016-01-06 - PyHardlinkBackup -> PyHardLinkBackup
580
+ * 2016-01-06 - +.idea
581
+ * 2016-01-06 - Refactor:
582
+ * 2016-01-06 - add a auto login to django admin with auto created default user
583
+ * 2016-01-06 - nicer output
584
+ * 2016-01-06 - Use database to deduplicate
585
+ * 2016-01-06 - add human time
586
+ * 2016-01-06 - add dev reset script
587
+ * 2016-01-06 - force DJANGO_SETTINGS_MODULE
588
+ * 2016-01-06 - Display shortend hash and add filesize
589
+ * 2016-01-04 - refactor django stuff
590
+ * 2016-01-04 - add some meta files
591
+ * 2016-01-04 - start using django
592
+ * 2016-01-03 - use https://pypi.python.org/pypi/scandir as fallback
593
+ * 2015-12-29 - Create README.creole
594
+ * 2015-12-29 - Create proof_of_concept.py
595
+ * 2015-12-29 - Initial commit
596
+
597
+ </details>
598
+
599
+
600
+ [comment]: <> (✂✂✂ auto generated history end ✂✂✂)
@@ -0,0 +1,42 @@
1
+ PyHardLinkBackup/__init__.py,sha256=S8_cyvBlTRZUFXxfwrEJlpOjKFoXRT2H-yW6JwP1kv0,256
2
+ PyHardLinkBackup/__main__.py,sha256=8sVwu5kFpdpoqplYdp4w-h2BKfmIdF7TEvgiaRPQq7s,177
3
+ PyHardLinkBackup/backup.py,sha256=VRk2Z-HjA2h-be-IlTlQVflro0Q04NzijVp0_Ji2ewA,9491
4
+ PyHardLinkBackup/compare_backup.py,sha256=Z6DMUEt0AhRGB2oHbVKmv81zWQPhG34e4STg1TVTPLk,7342
5
+ PyHardLinkBackup/constants.py,sha256=GgHOuFF57uRPUvkQpGAGF2rN-SorGPLy21qlD0GT8nw,389
6
+ PyHardLinkBackup/logging_setup.py,sha256=s1SJBwf5qz1mEJlxBZhTddQVMoeqOKvKRmzlJfermfY,3554
7
+ PyHardLinkBackup/rebuild_databases.py,sha256=hOeLWsDyae7JIA3BPY6FAttDdRvUZNcyenl6jl5JHy4,6059
8
+ PyHardLinkBackup/cli_app/__init__.py,sha256=RZh-BkFae2lb2POIzWVOCan7WOvXZUmVUlj5IGG3Asg,970
9
+ PyHardLinkBackup/cli_app/phlb.py,sha256=DfggKL_I-gEHAwcWywTHIFcKyNgGC6nl0o7eIoS6swQ,3321
10
+ PyHardLinkBackup/cli_dev/__init__.py,sha256=izEe0a9WhGDt9tbqxkSkMVIb6SCKHUjM_boe_1OYxow,1918
11
+ PyHardLinkBackup/cli_dev/benchmark.py,sha256=p2qeXm6XypzY6oAWpzbnlf2oSnIa0GPvQR_6Jo3QQfc,4914
12
+ PyHardLinkBackup/cli_dev/code_style.py,sha256=Lj1lMkFwCTN2Ms01D1Dn3xfdGdLJgLDAXYRb6MNPfXc,391
13
+ PyHardLinkBackup/cli_dev/packaging.py,sha256=xvEOp-Y4Bi9nuRgLVx9vXzmpuRVqsvyd8HsTd9Ij8q8,1966
14
+ PyHardLinkBackup/cli_dev/shell_completion.py,sha256=-FAmlhdGMoVWqlntEDs96a18S7P7L9XzopxJik_CE_Q,654
15
+ PyHardLinkBackup/cli_dev/testing.py,sha256=AUAMWNJo5IMQw6Fyqb_M9Y3Z4v_noB5WTAJYYFfmCZo,1390
16
+ PyHardLinkBackup/cli_dev/update_readme_history.py,sha256=sLEwq4TjQ_2KdAtvdNsMTp5yWTonRGrhuiNKOiQiWZI,909
17
+ PyHardLinkBackup/tests/__init__.py,sha256=jvGwZozc3NGcEOxJTDITB_OrLyjCmOljiiSY56CrqZI,1347
18
+ PyHardLinkBackup/tests/test_backup.py,sha256=i0TZ7kLg01bIiCxYFB8TvRAYU0nH9tT6YMLbqDNgpDE,29685
19
+ PyHardLinkBackup/tests/test_compare_backup.py,sha256=xb8AMVROpvJ59t3OWSt6dHOihM4kVlGHfxS0S9pJ950,3637
20
+ PyHardLinkBackup/tests/test_doc_write.py,sha256=KScwX1o0WdC-bSZd0RTHYTXWaPsglHer6YVUwgmt5B8,1012
21
+ PyHardLinkBackup/tests/test_doctests.py,sha256=mC3GLysHucqDXpn5edtIoGgGhmX4qzkYEN_u5uJtRQs,227
22
+ PyHardLinkBackup/tests/test_project_setup.py,sha256=HW2-Qwekt-ntZ3OfeSnTrbvKN_L6c8Gvgjo9lPAWvws,1795
23
+ PyHardLinkBackup/tests/test_readme.py,sha256=6cHHj_tVhQqLYcoVTgDmjRjaJT2hRfPQUMXVi6O9ihI,2643
24
+ PyHardLinkBackup/tests/test_readme_history.py,sha256=PbxF_yRspyRwkVCQosZXevIHrsla3WFBTUVeLI0bb-s,263
25
+ PyHardLinkBackup/tests/test_rebuild_database.py,sha256=pCt_uUjTYN96E1MPeMuipcrsCjAS33M4zHbN3HLzaYU,9438
26
+ PyHardLinkBackup/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ PyHardLinkBackup/utilities/file_hash_database.py,sha256=xdvyaBq1JK5cADsx4hpAizrHvNi7sTl06TP6giLjAAo,2387
28
+ PyHardLinkBackup/utilities/file_size_database.py,sha256=jwwxBaNmev3B7f4ZgYq-uqoJ-ixlS9zuCU38jdBL-i8,1662
29
+ PyHardLinkBackup/utilities/filesystem.py,sha256=xjpyh0BFsuLz8GTMrN2XB-0LAygrjabJF27kbWGbe4k,5084
30
+ PyHardLinkBackup/utilities/humanize.py,sha256=56Zh-YnsHkL0-KVJsN7k1kuXHU47UR_gOoTKb7IPn7w,1096
31
+ PyHardLinkBackup/utilities/rich_utils.py,sha256=MYSH4i0b3bWXFA3KfXTWcxN_yP5JAVwbN89ZSXH3C_s,3718
32
+ PyHardLinkBackup/utilities/sha256sums.py,sha256=iOXCXq9v5WsfnOECmiiDMs032dy53Awfz4uYLRYRseI,2057
33
+ PyHardLinkBackup/utilities/tee.py,sha256=9EXfITXF0FdQ3-j6b4Q-YRo6_TUBRVm_3geBtYTAq1I,923
34
+ PyHardLinkBackup/utilities/tyro_cli_shared_args.py,sha256=737MuQBsPZHh6c4Gpupm5DruydF-Ne8JMlOH5T5iPmA,285
35
+ PyHardLinkBackup/utilities/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ PyHardLinkBackup/utilities/tests/test_file_hash_database.py,sha256=9cku0SMjvjDXGTO5wlaEEQgmjT0-yzX-zSelyNeBPCE,5990
37
+ PyHardLinkBackup/utilities/tests/test_file_size_database.py,sha256=wlb7zWbHPF42RydzUwGB3TCoOxhas_GiUeogv_epquI,5413
38
+ PyHardLinkBackup/utilities/tests/test_filesystem.py,sha256=XppySBAO-0yevp6WIHSHxgT6Z-k0ZXBcx112_4_BYOE,4837
39
+ pyhardlinkbackup-1.5.0.dist-info/METADATA,sha256=_MH7BQZNZh5QF2eUumMe8vcCcSwx-KybNRYa6NuMtpQ,33713
40
+ pyhardlinkbackup-1.5.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
41
+ pyhardlinkbackup-1.5.0.dist-info/entry_points.txt,sha256=E4bezkCcPCTCpdBDmI3YiUSpxBWoc-wHsnDby4PjeGc,110
42
+ pyhardlinkbackup-1.5.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ _PyHardLinkBackup_dev = PyHardLinkBackup.cli_dev:main
3
+ phlb = PyHardLinkBackup.__main__:main