git-p4: print size values in appropriate units

The git-p4 script reports file sizes in various log messages. Previously, in each case the script would print them as the number of bytes divided by 1048576 i.e. the size in mebibytes, rounded down to an integer. This resulted in small files being described as having a size of "0 MB". This patch replaces the existing behaviour with a new helper function: format_size_human_readable, which takes a number of bytes (or any other quantity), and computes the appropriate prefix to use: none, Ki, Mi, Gi, Ti, Pi, Ei, Zi, Yi. For example, a size of 123456 will now be printed as "120.6 KiB" greatly improving the readability of the log output. Large valued prefixes such as pebi, exbi, zebi and yobi are included for completeness, though they not expected to appear in any real-world Perforce repository! Signed-off-by: Joel Holdsworth <jholdsworth@nvidia.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Joel Holdsworth committed Dec 19, 2021 at 15:40 UTC ae9b9509a76e49cbf4fb254b2b75d566be6434a8
1 file changed +19 -5
git-p4.py
+19 -5
@@ -56,6 +56,18 @@ defaultBlockSize = 1<<20
56
57 p4_access_checked = False
58
59 +def format_size_human_readable(num):
60 + """ Returns a number of units (typically bytes) formatted as a human-readable
61 + string.
62 + """
63 + if num < 1024:
64 + return '{:d} B'.format(num)
65 + for unit in ["Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
66 + num /= 1024.0
67 + if num < 1024.0:
68 + return "{:3.1f} {}B".format(num, unit)
69 + return "{:.1f} YiB".format(num)
70 +
71 def p4_build_cmd(cmd):
72 """Build a suitable p4 command line.
73
@@ -2966,7 +2978,8 @@ class P4Sync(Command, P4UserMap):
2978 size = int(self.stream_file['fileSize'])
2979 else:
2980 size = 0 # deleted files don't get a fileSize apparently
2969 - sys.stdout.write('\r%s --> %s (%i MB)\n' % (file_path, relPath, size/1024/1024))
2981 + sys.stdout.write('\r%s --> %s (%s)\n' % (
2982 + file_path, relPath, format_size_human_readable(size)))
2983 sys.stdout.flush()
2984
2985 (type_base, type_mods) = split_p4_type(file["type"])
@@ -3064,9 +3077,8 @@ class P4Sync(Command, P4UserMap):
3077 if not err and 'fileSize' in self.stream_file:
3078 required_bytes = int((4 * int(self.stream_file["fileSize"])) - calcDiskFree())
3079 if required_bytes > 0:
3067 - err = 'Not enough space left on %s! Free at least %i MB.' % (
3068 - os.getcwd(), required_bytes/1024/1024
3069 - )
3080 + err = 'Not enough space left on %s! Free at least %s.' % (
3081 + os.getcwd(), format_size_human_readable(required_bytes))
3082
3083 if err:
3084 f = None
@@ -3110,7 +3122,9 @@ class P4Sync(Command, P4UserMap):
3122 size = int(self.stream_file["fileSize"])
3123 if size > 0:
3124 progress = 100*self.stream_file['streamContentSize']/size
3113 - sys.stdout.write('\r%s %d%% (%i MB)' % (self.stream_file['depotFile'], progress, int(size/1024/1024)))
3125 + sys.stdout.write('\r%s %d%% (%s)' % (
3126 + self.stream_file['depotFile'], progress,
3127 + format_size_human_readable(size)))
3128 sys.stdout.flush()
3129
3130 self.stream_have_file_info = True