barecat 0.3.2__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 (60) hide show
  1. barecat/__init__.py +108 -0
  2. barecat/__main__.py +5 -0
  3. barecat/_api.py +143 -0
  4. barecat/_version.py +24 -0
  5. barecat/cli/__init__.py +0 -0
  6. barecat/cli/commands.py +540 -0
  7. barecat/cli/completions.py +27 -0
  8. barecat/cli/impl.py +609 -0
  9. barecat/cli/legacy.py +361 -0
  10. barecat/cli/main.py +1355 -0
  11. barecat/cli/shell.py +827 -0
  12. barecat/completions/__init__.py +1 -0
  13. barecat/completions/barecat.bash +246 -0
  14. barecat/completions/barecat.zsh +268 -0
  15. barecat/core/__init__.py +0 -0
  16. barecat/core/barecat.py +1209 -0
  17. barecat/core/index.py +1983 -0
  18. barecat/core/paths.py +61 -0
  19. barecat/core/sharder.py +328 -0
  20. barecat/core/types.py +340 -0
  21. barecat/exceptions.py +92 -0
  22. barecat/formats/__init__.py +0 -0
  23. barecat/formats/archive_formats.py +234 -0
  24. barecat/formats/from_tar_stream.py +53 -0
  25. barecat/formats/to_tar_stream.py +54 -0
  26. barecat/io/__init__.py +5 -0
  27. barecat/io/codecs.py +622 -0
  28. barecat/io/copyfile.py +550 -0
  29. barecat/io/fileobj.py +556 -0
  30. barecat/io/open.py +41 -0
  31. barecat/maintenance/__init__.py +0 -0
  32. barecat/maintenance/complete_database.py +79 -0
  33. barecat/maintenance/defrag.py +541 -0
  34. barecat/maintenance/merge.py +613 -0
  35. barecat/maintenance/reshard.py +153 -0
  36. barecat/maintenance/rsync.py +1282 -0
  37. barecat/maintenance/upgrade_database.py +200 -0
  38. barecat/maintenance/upgrade_database2.py +74 -0
  39. barecat/man/barecat.1 +284 -0
  40. barecat/sql/indexes.sql +6 -0
  41. barecat/sql/schema.sql +55 -0
  42. barecat/sql/triggers.sql +172 -0
  43. barecat/tui/__init__.py +0 -0
  44. barecat/tui/browse.py +448 -0
  45. barecat/tui/ncdu.py +318 -0
  46. barecat/util/__init__.py +0 -0
  47. barecat/util/consumed_threadpool.py +119 -0
  48. barecat/util/glob_helper.py +584 -0
  49. barecat/util/glob_to_regex.py +353 -0
  50. barecat/util/list_files.py +12 -0
  51. barecat/util/misc.py +174 -0
  52. barecat/util/physical_order.py +77 -0
  53. barecat/util/progbar.py +40 -0
  54. barecat/util/threading.py +59 -0
  55. barecat-0.3.2.dist-info/METADATA +276 -0
  56. barecat-0.3.2.dist-info/RECORD +60 -0
  57. barecat-0.3.2.dist-info/WHEEL +5 -0
  58. barecat-0.3.2.dist-info/entry_points.txt +15 -0
  59. barecat-0.3.2.dist-info/licenses/LICENSE +21 -0
  60. barecat-0.3.2.dist-info/top_level.txt +1 -0
barecat/cli/legacy.py ADDED
@@ -0,0 +1,361 @@
1
+ # Legacy CLI entry points for backwards compatibility.
2
+ # The primary CLI is now the unified 'barecat' command in cli_main.py.
3
+ # These entry points are kept for users who have scripts depending on them.
4
+
5
+ import argparse
6
+ import warnings
7
+ import csv
8
+ import pickle
9
+ import sys
10
+
11
+ import barecat
12
+ from ..cli import impl as impl
13
+ from ..core.types import Order
14
+ from ..util.consumed_threadpool import ConsumedThreadPool, IterableQueue
15
+ from ..maintenance.defrag import BarecatDefragger
16
+ from ..util.misc import parse_size
17
+ from ..util.progbar import progressbar
18
+
19
+
20
+ def create():
21
+ warnings.warn(
22
+ "barecat-create is deprecated, use 'barecat create' instead",
23
+ DeprecationWarning,
24
+ stacklevel=2,
25
+ )
26
+ parser = argparse.ArgumentParser(
27
+ description='Concatenate files to sharded blobs and create an sqlite index.'
28
+ )
29
+ parser.add_argument('--file', type=str, help='target path', required=True)
30
+ parser.add_argument(
31
+ '--null',
32
+ action='store_true',
33
+ help='read input paths from stdin, separated by null bytes as output by '
34
+ 'the find command with the -print0 option (otherwise newlines are '
35
+ 'interpreted as delimiters)',
36
+ )
37
+ parser.add_argument('--workers', type=int, default=None)
38
+ parser.add_argument(
39
+ '--shard-size-limit',
40
+ type=str,
41
+ default=None,
42
+ help='maximum size of a shard in bytes (if not specified, '
43
+ 'all files will be concatenated into a single shard)',
44
+ )
45
+ parser.add_argument('--overwrite', action='store_true', help='overwrite existing files')
46
+
47
+ args = parser.parse_args()
48
+ impl.create_from_stdin_paths(
49
+ target_path=args.file,
50
+ shard_size_limit=parse_size(args.shard_size_limit),
51
+ zero_terminated=args.null,
52
+ overwrite=args.overwrite,
53
+ workers=args.workers,
54
+ )
55
+
56
+
57
+ def create_recursive():
58
+ warnings.warn(
59
+ "barecat-create-recursive is deprecated, use 'barecat create' instead",
60
+ DeprecationWarning,
61
+ stacklevel=2,
62
+ )
63
+ # args are --file, and --shard-size-limit and --workers and --overwrite, and positional args
64
+ # are what you wanna pack in. if ya supply a single posarg thing then ya can use also the
65
+ # flag --strip-root and then the root will be stripped from the paths
66
+ parser = argparse.ArgumentParser(
67
+ description='Concatenate files to sharded blobs and create an sqlite index.'
68
+ )
69
+ parser.add_argument('--file', type=str, help='target path', required=True)
70
+ parser.add_argument('--workers', type=int, default=1)
71
+ parser.add_argument(
72
+ '--shard-size-limit',
73
+ type=str,
74
+ default=None,
75
+ help='maximum size of a shard in bytes (if not specified, '
76
+ 'all files will be concatenated into a single shard)',
77
+ )
78
+ parser.add_argument('--overwrite', action='store_true', help='overwrite existing files')
79
+ parser.add_argument(
80
+ '--physical-order',
81
+ action='store_true',
82
+ help='store files in the order as they are found on disk physically',
83
+ )
84
+ parser.add_argument('paths', type=str, nargs='+', help='paths to pack')
85
+ parser.add_argument(
86
+ '--strip-root',
87
+ action='store_true',
88
+ help='strip the root from the paths (only applicable if a single path is provided)',
89
+ default=True,
90
+ )
91
+
92
+ args = parser.parse_args()
93
+ impl.create_recursive(
94
+ target_path=args.file,
95
+ shard_size_limit=parse_size(args.shard_size_limit),
96
+ roots=args.paths,
97
+ overwrite=args.overwrite,
98
+ workers=args.workers,
99
+ strip_root=args.strip_root,
100
+ physical_order=args.physical_order,
101
+ )
102
+
103
+
104
+ def extract():
105
+ warnings.warn(
106
+ "barecat-extract is deprecated, use 'barecat extract' instead",
107
+ DeprecationWarning,
108
+ stacklevel=2,
109
+ )
110
+ parser = argparse.ArgumentParser(description='Extract files from a barecat archive.')
111
+ parser.add_argument('--file', type=str, help='path to the archive file')
112
+ parser.add_argument('--target-directory', type=str, help='path to the target directory')
113
+ args = parser.parse_args()
114
+ impl.extract(args.file, args.target_directory)
115
+
116
+
117
+ def extract_single():
118
+ warnings.warn(
119
+ "barecat-extract-single is deprecated, use 'barecat cat' instead",
120
+ DeprecationWarning,
121
+ stacklevel=2,
122
+ )
123
+ parser = argparse.ArgumentParser(description='Extract a single file from a barecat archive.')
124
+ parser.add_argument('--barecat-file', type=str, help='path to the archive file')
125
+ parser.add_argument('--path', type=str, help='path to the file to extract, within the archive')
126
+ args = parser.parse_args()
127
+ with barecat.Barecat(args.barecat_file) as reader:
128
+ sys.stdout.buffer.write(reader[args.path])
129
+
130
+
131
+ def index_to_csv():
132
+ warnings.warn(
133
+ "barecat-index-to-csv is deprecated, use 'barecat index-to-csv' instead",
134
+ DeprecationWarning,
135
+ stacklevel=2,
136
+ )
137
+ parser = argparse.ArgumentParser(description='Dump the index contents as csv')
138
+ parser.add_argument('file', type=str, help='path to the index file')
139
+ args = parser.parse_args()
140
+
141
+ writer = csv.writer(sys.stdout, delimiter=',', quotechar='"', quoting=csv.QUOTE_NONNUMERIC)
142
+ writer.writerow(['path', 'shard', 'offset', 'size', 'crc32c'])
143
+ with barecat.Index(args.file) as index:
144
+ for f in index.iter_all_fileinfos(order=Order.PATH):
145
+ writer.writerow([f.path, f.shard, f.offset, f.size, f.crc32c])
146
+
147
+
148
+ def index_to_pickledict():
149
+ warnings.warn('barecat-index-to-pickledict is deprecated', DeprecationWarning, stacklevel=2)
150
+ parser = argparse.ArgumentParser(description='Dump the index contents as a pickled dictionary')
151
+ parser.add_argument('file', type=str, help='path to the index file')
152
+ parser.add_argument('outfile', type=str, help='path to the result file')
153
+ args = parser.parse_args()
154
+
155
+ with barecat.Index(args.file) as index_reader:
156
+ dicti = dict(index_reader.items())
157
+
158
+ with open(args.outfile, 'xb') as outfile:
159
+ pickle.dump(dicti, outfile)
160
+
161
+
162
+ def merge():
163
+ warnings.warn(
164
+ "barecat-merge is deprecated, use 'barecat merge' instead",
165
+ DeprecationWarning,
166
+ stacklevel=2,
167
+ )
168
+ parser = argparse.ArgumentParser(description='Merge existing Barecat archives into one.')
169
+ parser.add_argument(
170
+ 'input_paths', metavar='N', type=str, nargs='+', help='paths to the archives to merge'
171
+ )
172
+ parser.add_argument('--output', required=True, help='output path')
173
+ parser.add_argument(
174
+ '--shard-size-limit',
175
+ type=str,
176
+ default=None,
177
+ help='maximum size of a shard in bytes (if not specified, '
178
+ 'all files will be concatenated into a single shard)',
179
+ )
180
+ parser.add_argument('--overwrite', action='store_true', help='overwrite existing files')
181
+ parser.add_argument(
182
+ '--ignore-duplicates',
183
+ action='store_true',
184
+ help='if true then if a later file has the same path as an earlier one,'
185
+ ' skip it; if false then raise an error',
186
+ )
187
+
188
+ args = parser.parse_args()
189
+ impl.merge(
190
+ source_paths=args.input_paths,
191
+ target_path=args.output,
192
+ shard_size_limit=parse_size(args.shard_size_limit),
193
+ overwrite=args.overwrite,
194
+ ignore_duplicates=args.ignore_duplicates,
195
+ )
196
+
197
+
198
+ def merge_symlink():
199
+ warnings.warn(
200
+ "barecat-merge-symlink is deprecated, use 'barecat merge --symlink' instead",
201
+ DeprecationWarning,
202
+ stacklevel=2,
203
+ )
204
+ parser = argparse.ArgumentParser(description='Merge existing Barecat archives into one.')
205
+ parser.add_argument(
206
+ 'input_paths', metavar='N', type=str, nargs='+', help='paths to the archives to merge'
207
+ )
208
+ parser.add_argument('--output', required=True, help='output path')
209
+ parser.add_argument('--overwrite', action='store_true', help='overwrite existing files')
210
+ parser.add_argument(
211
+ '--ignore-duplicates',
212
+ action='store_true',
213
+ help='if true then if a later file has the same path as an earlier one,'
214
+ ' skip it; if false then raise an error',
215
+ )
216
+
217
+ args = parser.parse_args()
218
+ impl.merge_symlink(
219
+ source_paths=args.input_paths,
220
+ target_path=args.output,
221
+ overwrite=args.overwrite,
222
+ ignore_duplicates=args.ignore_duplicates,
223
+ )
224
+
225
+
226
+ def verify_integrity():
227
+ warnings.warn(
228
+ "barecat-verify is deprecated, use 'barecat verify' instead",
229
+ DeprecationWarning,
230
+ stacklevel=2,
231
+ )
232
+ parser = argparse.ArgumentParser(
233
+ description='Verify the integrity of a Barecat archive, including CRC32C, directory '
234
+ 'stats and no gaps between stored files.'
235
+ )
236
+ parser.add_argument('file', type=str, help='path to the index file')
237
+ parser.add_argument(
238
+ '--quick', action='store_true', help='CRC32C is only verified on the last file'
239
+ )
240
+ args = parser.parse_args()
241
+
242
+ with barecat.Barecat(args.file, threadsafe=True) as bc:
243
+ if args.quick:
244
+ if not bc.verify_integrity(quick=True):
245
+ print('Integrity verification failed.', file=sys.stderr)
246
+ sys.exit(1)
247
+ else:
248
+ if not verify_crc_parallel(bc, workers=1):
249
+ print('CRC32C verification failed.', file=sys.stderr)
250
+ sys.exit(1)
251
+
252
+ if not bc.index.verify_integrity():
253
+ print('Index integrity errors were found.', file=sys.stderr)
254
+ sys.exit(1)
255
+
256
+
257
+ def verify_crc_parallel(bc: barecat.Barecat, workers: int):
258
+ is_good = True
259
+
260
+ def checker_main(future_iter: IterableQueue):
261
+ for future in future_iter:
262
+ finfo = future.userdata
263
+ crc32c_ok = future.result()
264
+ if not crc32c_ok:
265
+ nonlocal is_good
266
+ is_good = False
267
+ print(f'CRC32C mismatch for file: {finfo.path}')
268
+
269
+ with ConsumedThreadPool(checker_main, max_workers=workers) as ctp:
270
+ for finfo in progressbar(bc.index.iter_all_fileinfos(order=Order.ADDRESS), total=len(bc)):
271
+ ctp.submit(fn=bc.check_crc32c, userdata=finfo, args=(finfo,))
272
+
273
+ return is_good
274
+
275
+
276
+ def defrag():
277
+ warnings.warn(
278
+ "barecat-defrag is deprecated, use 'barecat defrag' instead",
279
+ DeprecationWarning,
280
+ stacklevel=2,
281
+ )
282
+ parser = argparse.ArgumentParser(
283
+ description='Defragment a Barecat archive to remove gaps left by deleted files.'
284
+ )
285
+ parser.add_argument('file', type=str, help='path to the index file')
286
+ parser.add_argument(
287
+ '--quick',
288
+ action='store_true',
289
+ help='faster but less thorough attempt at defrag, using the best-fit '
290
+ 'algorithm to move the last files into gaps.',
291
+ )
292
+
293
+ args = parser.parse_args()
294
+ with barecat.Barecat(args.file, readonly=False, append_only=False) as bc:
295
+ defragger = BarecatDefragger(bc)
296
+ if defragger.needs_defrag():
297
+ if args.quick:
298
+ defragger.defrag_quick()
299
+ else:
300
+ defragger.defrag()
301
+
302
+
303
+ def archive2barecat():
304
+ warnings.warn(
305
+ "archive2barecat is deprecated, use 'barecat convert' instead",
306
+ DeprecationWarning,
307
+ stacklevel=2,
308
+ )
309
+ parser = argparse.ArgumentParser(
310
+ description='Convert a tar or zip archive to a Barecat archive.'
311
+ )
312
+ # 2 positional args are the tar file and the target barecat file
313
+ parser.add_argument('archive_file', type=str, help='path to the tar or zip file')
314
+ parser.add_argument('barecat_file', type=str, help='path to the target barecat file')
315
+
316
+ parser.add_argument(
317
+ '--shard-size-limit',
318
+ type=str,
319
+ default=None,
320
+ help='maximum size of a shard in bytes (if not specified, '
321
+ 'all files will be concatenated into a single shard)',
322
+ )
323
+ parser.add_argument('--overwrite', action='store_true', help='overwrite existing files')
324
+ args = parser.parse_args()
325
+ impl.archive2barecat(
326
+ src_path=args.archive_file,
327
+ target_path=args.barecat_file,
328
+ shard_size_limit=parse_size(args.shard_size_limit),
329
+ overwrite=args.overwrite,
330
+ )
331
+
332
+
333
+ def barecat2archive():
334
+ warnings.warn(
335
+ "barecat2archive is deprecated, use 'barecat convert' instead",
336
+ DeprecationWarning,
337
+ stacklevel=2,
338
+ )
339
+ parser = argparse.ArgumentParser(
340
+ description='Convert a Barecat archive to a tar or tar or zip archive.'
341
+ )
342
+ # 2 positional args are the barecat file and the target tar file
343
+ parser.add_argument('barecat_file', type=str, help='path to the barecat file')
344
+ parser.add_argument('archive_file', type=str, help='path to the target archive file')
345
+
346
+ args = parser.parse_args()
347
+ impl.barecat2archive(src_path=args.barecat_file, target_path=args.archive_file)
348
+
349
+
350
+ def print_ncdu_json():
351
+ warnings.warn(
352
+ "barecat-to-ncdu-json is deprecated, use 'barecat to-ncdu-json' instead",
353
+ DeprecationWarning,
354
+ stacklevel=2,
355
+ )
356
+ parser = argparse.ArgumentParser(
357
+ description='Print the contents of a Barecat as JSON in the format expected by ncdu.'
358
+ )
359
+ parser.add_argument('file', type=str, help='path to the index file')
360
+ args = parser.parse_args()
361
+ impl.print_ncdu_json(args.file)