39
39
40
40
41
41
class DirEntryType (Enum ):
42
+ """Simple enum of basic file type categories"""
43
+
42
44
DIRECTORY = 1
43
45
REGULAR_FILE = 2
44
46
OTHER = 3
45
47
46
48
47
49
def _dir_entry_type (dir_entry : os .DirEntry ) -> DirEntryType :
50
+ """Compute the high level file type from a dir entry"""
48
51
if dir_entry .is_dir (follow_symlinks = False ):
49
52
return DirEntryType .DIRECTORY
50
53
if dir_entry .is_file (follow_symlinks = False ):
@@ -54,6 +57,8 @@ def _dir_entry_type(dir_entry: os.DirEntry) -> DirEntryType:
54
57
55
58
@dataclasses .dataclass
56
59
class DifferOptions :
60
+ """Dataclass containing options to control diff behavior"""
61
+
57
62
output_uid : Optional [int ] = None
58
63
output_gid : Optional [int ] = None
59
64
scrub_mtime : bool = True
@@ -118,6 +123,20 @@ def _invoke(differ: "Differ", *args, **kwargs):
118
123
119
124
120
125
class Differ :
126
+ """
127
+ Class responsible for performing the complete recursive directory difference
128
+ on the merged and lower direcotires. The merged_dir/lower_dir arguments must
129
+ either be a path-like pointer to an existing directory or a TarFile object.
130
+
131
+ Parameters:
132
+ merged_dir: This is the left-hand side of the directory difference. This
133
+ can be a path-like object or a tar archive.
134
+ lower_dir: This is the right-hand side of the directory difference. This
135
+ can be a path-like object or a tar archive.
136
+ output: This is a DiffOutput instance that actually writes diff results
137
+ options: Additional options that govern diff output and handling of errors
138
+ """
139
+
121
140
def __init__ (
122
141
self ,
123
142
merged_dir : DifferPathLike ,
@@ -135,6 +154,11 @@ def __init__(
135
154
136
155
@_new_stack
137
156
def diff (self ) -> None :
157
+ """
158
+ Main diff entrypoint that starts the diff of the merged and lower directories/archives.
159
+
160
+ Any failures not ignored by the differ options will raised as a DirDiffException.
161
+ """
138
162
try :
139
163
merged = self ._cur_stack .enter_context (_open_dir (self .merged_dir ))
140
164
except IOErrors as exc :
@@ -150,6 +174,12 @@ def diff(self) -> None:
150
174
self ._diff_dirs ("." , merged , lower )
151
175
152
176
def _input_error (self , operand : str , path : str , verb : str ) -> None :
177
+ """
178
+ Handle an input error.
179
+
180
+ Either propagates the error or simply logs it depending on the
181
+ error handler settings.
182
+ """
153
183
_ , exc , _ = sys .exc_info ()
154
184
if exc is not None :
155
185
msg = f"error { verb } path={ path !r} of { operand } : { exc } "
@@ -160,6 +190,12 @@ def _input_error(self, operand: str, path: str, verb: str) -> None:
160
190
LOGGER .warning ("ignoring %s" , msg )
161
191
162
192
def _output_error (self , path : str , verb : str ) -> None :
193
+ """
194
+ Handle an output error.
195
+
196
+ Either propagates the error or simply logs it depending on the
197
+ error handler settings.
198
+ """
163
199
_ , exc , _ = sys .exc_info ()
164
200
if exc is not None :
165
201
msg = f"error { verb } path={ path !r} : { exc } "
@@ -170,9 +206,11 @@ def _output_error(self, path: str, verb: str) -> None:
170
206
LOGGER .warning ("ignoring %s" , msg )
171
207
172
208
def _input_error_merged (self , path : str , verb : str ) -> None :
209
+ """Handle an input error reading from the merged directory"""
173
210
self ._input_error (OPERAND_MERGED , path , verb )
174
211
175
212
def _input_error_lower (self , path : str , verb : str ) -> None :
213
+ """Handle an input error reading from the lower directory"""
176
214
self ._input_error (OPERAND_LOWER , path , verb )
177
215
178
216
@_new_stack
@@ -182,6 +220,9 @@ def _diff_dirs(
182
220
merged : DirectoryManager ,
183
221
lower : DirectoryManager ,
184
222
) -> None :
223
+ """
224
+ Helper method for recursively diffing two directories in the merged and lower
225
+ """
185
226
stack = self ._cur_stack
186
227
LOGGER .debug ("Diffing dirs %s" , archive_path )
187
228
@@ -267,6 +308,7 @@ def _diff_files(
267
308
merged : FileManager ,
268
309
lower : FileManager ,
269
310
) -> None :
311
+ """Helper method for diffing two regular files in the merged and lower"""
270
312
stack = self ._cur_stack
271
313
LOGGER .debug ("Diffing files %s" , archive_path )
272
314
@@ -334,6 +376,13 @@ def _diff_other(
334
376
merged : PathManager ,
335
377
lower : PathManager ,
336
378
) -> None :
379
+ """
380
+ Helper method for diffing two special files in the merged and lower.
381
+
382
+ "Special" in this case means anything that's not either a directory or
383
+ a regular file. The files may not have the same file modes so this method
384
+ is responsible for checking that as well.
385
+ """
337
386
stack = self ._cur_stack
338
387
LOGGER .debug ("Diffing other %s" , archive_path )
339
388
@@ -364,6 +413,12 @@ def _diff_other(
364
413
self ._insert_other (archive_path , merged )
365
414
366
415
def _flush_pending (self ) -> None :
416
+ """
417
+ Flush any pending directory entries to the output. We do this before
418
+ writing any other entries into an archive to ensure its parents have
419
+ been written first. We delay writting the parents because if their are
420
+ no differences in its children we can omit writing an entry for it at all.
421
+ """
367
422
for archive_path , dir_stat in self ._dir_pending :
368
423
LOGGER .debug ("Inserting directory metadata %s" , archive_path )
369
424
try :
@@ -378,6 +433,7 @@ def _insert_dir(
378
433
archive_path : str ,
379
434
obj : DirectoryManager ,
380
435
) -> None :
436
+ """Recursively write a directory to our outout"""
381
437
stack = self ._cur_stack
382
438
self ._flush_pending ()
383
439
LOGGER .debug ("Recursively inserting directory %s" , archive_path )
@@ -410,6 +466,7 @@ def _insert_file(
410
466
archive_path : str ,
411
467
obj : FileManager ,
412
468
) -> None :
469
+ """Write a file to our outout"""
413
470
stack = self ._cur_stack
414
471
self ._flush_pending ()
415
472
LOGGER .debug ("Inserting file %s" , archive_path )
@@ -436,6 +493,7 @@ def _insert_other(
436
493
archive_path : str ,
437
494
obj : PathManager ,
438
495
) -> None :
496
+ """Write any other special file type to our outout"""
439
497
stack = self ._cur_stack
440
498
self ._flush_pending ()
441
499
LOGGER .debug ("Inserting other %s" , archive_path )
0 commit comments