bsdiff4 1.4.0__tar.gz → 1.4.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bsdiff4
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: binary diff and patch using the BSDIFF4-format
5
5
  Home-page: https://github.com/ilanschnell/bsdiff4
6
6
  Author: Ilan Schnell
@@ -42,14 +42,19 @@ The code is mostly derived from ``cx_bsdiff`` (written by Anthony Tuininga,
42
42
  http://cx-bsdiff.sourceforge.net/). The ``cx_bsdiff`` code in turn was
43
43
  derived from bsdiff, the standalone utility produced for BSD which can be
44
44
  found at http://www.daemonology.net/bsdiff.
45
- In addition to the two functions (diff and patch) cx_bsdiff provides, this
46
- package includes:
47
45
 
48
- * an interface to the BSDIFF4-format
49
- * improved error handling for malformed patches
50
- * functions for creating and applying patches directly to files
51
- * command line interfaces: ``bsdiff4`` and ``bspatch4``
52
- * tests
46
+ Key features of this package include:
47
+
48
+ * high-level ``diff`` and ``patch`` functions
49
+ * an interface to the BSDIFF4 format
50
+ * stricter validation and improved error handling of malformed patches than
51
+ the standard ``bspatch`` tool; in particular overlong blocks are rejected
52
+ * functions for creating patches from files and applying them to files
53
+ * command-line interfaces: ``bsdiff4`` and ``bspatch4`` (the latter can also
54
+ inspect patches using ``bspatch4 PATCH``)
55
+ * support for free-threaded Python
56
+ * type hints
57
+ * extensive tests
53
58
 
54
59
 
55
60
  The bsdiff4 package defines the following high level functions:
@@ -62,15 +67,15 @@ The bsdiff4 package defines the following high level functions:
62
67
  Apply the BSDIFF4-format ``patch_bytes`` to ``src_bytes`` and return
63
68
  the bytes.
64
69
 
65
- ``file_diff(src_path, dst_path, patch_path)``
70
+ ``file_diff(src_path, dst_path, patch_path)`` -> None
66
71
  Write a BSDIFF4-format patch (from the file ``src_path`` to the
67
72
  file ``dst_path``) to the file ``patch_path``.
68
73
 
69
- ``file_patch(src_path, dst_path, patch_path)``
74
+ ``file_patch(src_path, dst_path, patch_path)`` -> None
70
75
  Apply the BSDIFF4-format file ``patch_path`` to the file ``src_path``
71
76
  and write the result to the file ``dst_path``.
72
77
 
73
- ``file_patch_inplace(path, patch_path)``
78
+ ``file_patch_inplace(path, patch_path)`` -> None
74
79
  Apply the BSDIFF4-format file ``patch_path`` to the file ``path``
75
80
  in place.
76
81
 
@@ -6,14 +6,19 @@ The code is mostly derived from ``cx_bsdiff`` (written by Anthony Tuininga,
6
6
  http://cx-bsdiff.sourceforge.net/). The ``cx_bsdiff`` code in turn was
7
7
  derived from bsdiff, the standalone utility produced for BSD which can be
8
8
  found at http://www.daemonology.net/bsdiff.
9
- In addition to the two functions (diff and patch) cx_bsdiff provides, this
10
- package includes:
11
9
 
12
- * an interface to the BSDIFF4-format
13
- * improved error handling for malformed patches
14
- * functions for creating and applying patches directly to files
15
- * command line interfaces: ``bsdiff4`` and ``bspatch4``
16
- * tests
10
+ Key features of this package include:
11
+
12
+ * high-level ``diff`` and ``patch`` functions
13
+ * an interface to the BSDIFF4 format
14
+ * stricter validation and improved error handling of malformed patches than
15
+ the standard ``bspatch`` tool; in particular overlong blocks are rejected
16
+ * functions for creating patches from files and applying them to files
17
+ * command-line interfaces: ``bsdiff4`` and ``bspatch4`` (the latter can also
18
+ inspect patches using ``bspatch4 PATCH``)
19
+ * support for free-threaded Python
20
+ * type hints
21
+ * extensive tests
17
22
 
18
23
 
19
24
  The bsdiff4 package defines the following high level functions:
@@ -26,15 +31,15 @@ The bsdiff4 package defines the following high level functions:
26
31
  Apply the BSDIFF4-format ``patch_bytes`` to ``src_bytes`` and return
27
32
  the bytes.
28
33
 
29
- ``file_diff(src_path, dst_path, patch_path)``
34
+ ``file_diff(src_path, dst_path, patch_path)`` -> None
30
35
  Write a BSDIFF4-format patch (from the file ``src_path`` to the
31
36
  file ``dst_path``) to the file ``patch_path``.
32
37
 
33
- ``file_patch(src_path, dst_path, patch_path)``
38
+ ``file_patch(src_path, dst_path, patch_path)`` -> None
34
39
  Apply the BSDIFF4-format file ``patch_path`` to the file ``src_path``
35
40
  and write the result to the file ``dst_path``.
36
41
 
37
- ``file_patch_inplace(path, patch_path)``
42
+ ``file_patch_inplace(path, patch_path)`` -> None
38
43
  Apply the BSDIFF4-format file ``patch_path`` to the file ``path``
39
44
  in place.
40
45
 
@@ -1,11 +1,15 @@
1
1
  from bsdiff4.format import (diff, patch, file_diff, file_patch,
2
2
  file_patch_inplace)
3
3
 
4
- __version__ = "1.4.0"
4
+ __version__ = "1.4.2"
5
5
 
6
6
  __all__ = ["diff", "patch", "file_diff", "file_patch", "file_patch_inplace"]
7
7
 
8
8
 
9
9
  def test(verbosity=1):
10
- from .test_all import run
10
+ """test(verbosity=1) -> TextTestResult
11
+
12
+ Run self-test, and return `unittest.runner.TextTestResult` object.
13
+ """
14
+ from bsdiff4.tests import run
11
15
  return run(verbosity=verbosity)
@@ -0,0 +1,145 @@
1
+ import sys
2
+ from argparse import ArgumentParser
3
+ from os.path import getsize
4
+
5
+ import bsdiff4.core as core # type: ignore
6
+ from bsdiff4 import __version__
7
+ from bsdiff4.format import (file_diff, file_patch, read_patch,
8
+ unpack_header, unpack_control_block)
9
+
10
+
11
+ def human_bytes(n):
12
+ """
13
+ return the number of bytes 'n' in more human readable form
14
+ """
15
+ if n < 1024:
16
+ return '%d B' % n
17
+ k = n / 1024
18
+ if k < 1024:
19
+ return '%.1f K' % k
20
+ m = k / 1024
21
+ if m < 1024:
22
+ return '%.1f M' % m
23
+ g = m / 1024
24
+ return '%.2f G' % g
25
+
26
+
27
+ def show_filesizes(*args):
28
+ for i, name in enumerate(['src', 'dst', 'patch']):
29
+ size = getsize(args[i])
30
+ print('%s: %s (%s)' % (name, args[i], human_bytes(size)))
31
+
32
+
33
+ def show_header(fi):
34
+ total_len = fi.seek(0, 2) # go to EOF and return position
35
+ fi.seek(0)
36
+ control_len, diff_len, dst_len = unpack_header(fi.read(32))
37
+ print("sizes:")
38
+ for name, size in [
39
+ ('total', total_len),
40
+ ('control', control_len),
41
+ ('diff', diff_len),
42
+ ('extra', total_len - 32 - control_len - diff_len),
43
+ ('dst', dst_len),
44
+ ]:
45
+ print('%10s: %10d (%s)' % (name, size, human_bytes(size)))
46
+
47
+
48
+ def show_control(control_block, verbose=False):
49
+ print('\nnumber of control tuples: %d' % (len(control_block) // 24))
50
+ print('%10s %10s %10s %10s' % ('x', 'y', 'z', 'src pos'))
51
+ omitted = False
52
+ src_pos = 0
53
+ totals = (0, 0) # x, y totals
54
+ for i, (x, y, z) in enumerate(unpack_control_block(control_block)):
55
+ if i < 5 or verbose:
56
+ print('%10d %10d %10d %10d' % (x, y, z, src_pos))
57
+ else:
58
+ omitted = True
59
+ totals = (totals[0] + x, totals[1] + y)
60
+ src_pos += x + z
61
+
62
+ if omitted:
63
+ print('%10s %10s %10s' % (3 * ('...',)))
64
+ print('%10s %10s' % (2 * ('------',)))
65
+ print('%10d %10d' % totals)
66
+
67
+
68
+ def show_patch(fi, verbose=False):
69
+ show_header(fi)
70
+ fi.seek(0)
71
+ control_block, diff_block, extra_block = read_patch(fi)
72
+ print("\nuncompressed block sizes:")
73
+ for name, size in [
74
+ ('control', len(control_block)),
75
+ ('diff', len(diff_block)),
76
+ ('extra', len(extra_block)),
77
+ ]:
78
+ note = ""
79
+ if name == 'diff' and diff_block:
80
+ nonzero = len(diff_block) - diff_block.count(b'\x00')
81
+ note = ' (non-zero bytes: %d)' % nonzero
82
+ print('%10s: %10d (%s)%s' % (name, size, human_bytes(size), note))
83
+
84
+ show_control(control_block, verbose)
85
+ # validate patch by applying it to empty source
86
+ core.patch(b'', control_block, diff_block, extra_block)
87
+
88
+
89
+ def main_bsdiff4():
90
+ """
91
+ Generate a BSDIFF4-format PATCH from SRC to DST and write it to PATCH.
92
+ """
93
+ p = ArgumentParser(description=main_bsdiff4.__doc__)
94
+ p.add_argument('-v', '--verbose', action='store_true',
95
+ help="show file sizes")
96
+ p.add_argument('--version', action='version',
97
+ version="bsdiff4 %s" % __version__)
98
+ p.add_argument('src', metavar='SRC')
99
+ p.add_argument('dst', metavar='DST')
100
+ p.add_argument('patch', metavar='PATCH')
101
+ args = p.parse_args()
102
+
103
+ paths = args.src, args.dst, args.patch
104
+ try:
105
+ file_diff(*paths)
106
+ except (OSError, MemoryError) as e:
107
+ sys.exit("%s: %s" % (p.prog, str(e) or type(e).__name__))
108
+ if args.verbose:
109
+ show_filesizes(*paths)
110
+
111
+
112
+ def main_bspatch4():
113
+ """
114
+ Generate DST by applying the BSDIFF4-format PATCH file to SRC;
115
+ with only PATCH, display information about and verify the patch.
116
+ """
117
+ p = ArgumentParser(
118
+ usage="%(prog)s [options] SRC DST PATCH\n"
119
+ " %(prog)s [options] PATCH",
120
+ description=main_bspatch4.__doc__,
121
+ )
122
+ p.add_argument('-v', '--verbose', action='store_true',
123
+ help="show file sizes or all control tuples")
124
+ p.add_argument('--version', action='version',
125
+ version="bsdiff4 %s" % __version__)
126
+ p.add_argument('paths', nargs='+', metavar='PATH')
127
+ args = p.parse_args()
128
+
129
+ if len(args.paths) == 1:
130
+ try:
131
+ with open(args.paths[0], 'rb') as fi:
132
+ show_patch(fi, args.verbose)
133
+ except (ValueError, OSError, MemoryError) as e:
134
+ sys.exit("%s: %s" % (p.prog, str(e) or type(e).__name__))
135
+ return
136
+
137
+ if len(args.paths) != 3:
138
+ p.error("requires either PATCH or SRC DST PATCH")
139
+
140
+ try:
141
+ file_patch(*args.paths)
142
+ except (ValueError, OSError, MemoryError) as e:
143
+ sys.exit("%s: %s" % (p.prog, str(e) or type(e).__name__))
144
+ if args.verbose:
145
+ show_filesizes(*args.paths)