-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdush
executable file
·147 lines (123 loc) · 4.27 KB
/
dush
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!python3
import os
import signal
import subprocess
import sys
BAR_LENGTH = 20
BAR_FILLED = '#'
BAR_EMPTY = ' '
# trap sigint so that we don't get an ugly stack trace
signal.signal(signal.SIGINT, lambda sig, frame: sys.exit(1))
def lgetor(l, i, default_value):
if i >= len(l):
return default_value
r = l[i]
if r is None:
return default_value
return r
class UpdateLine(object):
def __init__(self, out, total=None):
self.out = out
self.max_len = 0
self.total = total
self.seen = 0
def write(self, message):
if self.total:
self.seen += 1
tot_len = len(str(self.total))
seen_padded = str(self.seen).rjust(tot_len)
message = '[%s/%s] %s' % (seen_padded, self.total, message)
self.__write(message)
def clear(self):
self.__write('')
def __write(self, message):
message_len = len(message)
self.max_len = max(self.max_len, message_len)
overwrite_message = message + (' ' * (self.max_len - message_len))
sys.stdout.write('\r%s' % overwrite_message)
sys.stdout.write('\r%s' % message) # move the cursor back
sys.stdout.flush()
class Table(object):
def __init__(self, paddings=None, justifies=None):
self.paddings = paddings or []
self.justifies = justifies or []
self.rows = []
def add_row(self, *columns):
self.rows.append(columns)
def print_cells(self):
# Deep copy the rows, converting each cell to str as we go
rows = []
for r in self.rows:
rows.append([str(c) for c in r])
# Make each row have the same number of columns
max_row_len = max([len(r) for r in rows])
for r in rows:
r.extend([''] * (max_row_len - len(r)))
# Make each cell have the same number of columns
col_lens = [0] * max_row_len
for r in rows:
for i, c in enumerate(r):
col_lens[i] = max(col_lens[i], len(c))
for r in rows:
for i, c in enumerate(r):
justify = lgetor(self.justifies, i, 'l')
padding_size = (col_lens[i] - len(c))
padding = ' ' * padding_size
if justify == 'r':
r[i] = padding + c
else:
r[i] = c + padding
r[i] += (' ' * lgetor(self.paddings, i, 2))
# Finally, print it all out
for r in rows:
print(''.join(r))
def sizeof_fmt(num):
# adapted from http://stackoverflow.com/a/1094933/1076640
# Get one-char abbreviations, and start at K (not B) since we used du -k
if num < 0:
return ' n/a'
for unit in ['K', 'M', 'G', 'T', 'P', 'E', 'Z']:
if abs(num) < 1024.0:
return "%3.1f%s" % (num, unit)
num /= 1024.0
return "%.1f%s" % (num, 'Y')
files = sys.argv[1:]
if not files:
files = os.listdir('.')
files = [f for f in files if not f.startswith('.')]
files = sorted(files)
if not files:
exit(0)
# First, get all the file sizes
sizes_by_name = {}
status_writer = UpdateLine(sys.stdout, len(files))
for f in files:
message = 'Calculating size for %s...' % f
status_writer.write(message)
try:
f_size_str = subprocess.check_output(['du', '-ks', f])
f_size_str = f_size_str.split(None, 1)[0] # stuff before the first space
f_size = int(f_size_str)
except Exception:
f_size = -1
sizes_by_name[f] = f_size
status_writer.clear()
# Then report them
total_size = float(sum(sizes_by_name.values()))
file_sizes = list(sizes_by_name.items()) # [(name, size)]
file_sizes.sort(key=lambda e: e[1], reverse=True)
table = Table(paddings=[1], justifies=[None, 'r', 'r'])
for f, f_size in file_sizes:
ratio = (f_size / total_size) if (total_size and f_size >= 0) else 0
filled_bars = int(round(ratio * BAR_LENGTH))
unfilled_bars = BAR_LENGTH - filled_bars
if os.path.islink(f):
f = '(link) %s' % f
if f_size >= 0:
bars = '[%s%s]' % (BAR_FILLED * filled_bars, BAR_EMPTY * unfilled_bars)
percent = '%.1f%%' % (ratio * 100)
else:
bars = ' ' * (BAR_LENGTH + 2)
percent = 'n/a%'
table.add_row(bars, percent, sizeof_fmt(f_size), f)
table.print_cells()