enable df path selection

This commit is contained in:
Ville Rantanen
2021-03-01 10:10:41 +02:00
parent eec678b0f9
commit 92c72edd02

View File

@@ -5,66 +5,83 @@ from datetime import datetime
from datetime import timedelta from datetime import timedelta
import re, signal, time import re, signal, time
import subprocess import subprocess
# ,threading # ,threading
VERSION = 3 VERSION = 3
W= '30' W = "30"
R= '31' R = "31"
G= '32' G = "32"
Y= '33' Y = "33"
B= '34' B = "34"
M= '35' M = "35"
C= '36' C = "36"
S= '1' S = "1"
E= '0' E = "0"
BR= '41' BR = "41"
CLR = '\033[2J' CLR = "\033[2J"
SAVE = '\033[s' SAVE = "\033[s"
LOAD = '\033[u' LOAD = "\033[u"
CLRLN = '\033[K' CLRLN = "\033[K"
CLRBLN = '\033[1K' CLRBLN = "\033[1K"
DOWN = '\033[1B' DOWN = "\033[1B"
SORTKEY = lambda key: (key[2].split("/")[-1].lower())
SORTKEY = lambda key: (key[2].split('/')[-1].lower())
def setup_options(): def setup_options():
''' Setup the command line options ''' """ Setup the command line options """
from argparse import ArgumentParser from argparse import ArgumentParser
import argparse import argparse
parser=ArgumentParser(description=''' parser = ArgumentParser(
description="""
Shows the output of df in colour. Shows the output of df in colour.
''',formatter_class=argparse.RawTextHelpFormatter) """,
formatter_class=argparse.RawTextHelpFormatter,
)
parser.add_argument("--no-colors",'--nc',action="store_false",dest="colors",default=True, parser.add_argument(
help="Disable colored output") "--no-colors",
parser.add_argument("-n",type=int,dest="delay",default=3, "--nc",
help="Refresh delay") action="store_false",
parser.add_argument("-1",action="store_true",dest="once",default=False, dest="colors",
help="Run once and exit") default=True,
parser.add_argument("-x",'--exclude',type=str,dest="exclude",default="tmpfs,devtmpfs,squashfs,overlay", help="Disable colored output",
help="Comma separated list of excluded filesystem types. Defaults: %(default)s") )
parser.add_argument("--version",action='version', version=VERSION) parser.add_argument("-n", type=int, dest="delay", default=3, help="Refresh delay")
parser.add_argument(
"-1", action="store_true", dest="once", default=False, help="Run once and exit"
)
parser.add_argument(
"-x",
"--exclude",
type=str,
dest="exclude",
default="tmpfs,devtmpfs,squashfs,overlay",
help="Comma separated list of excluded filesystem types. Defaults: %(default)s",
)
parser.add_argument("--version", action="version", version=VERSION)
parser.add_argument("paths", action="store", nargs="*", help="Only include disks. Defaults to all.")
options = parser.parse_args() options = parser.parse_args()
return options return options
def c(attribs): def c(attribs):
''' ANSI colorizer ''' """ ANSI colorizer """
if not options.colors: if not options.colors:
return "" return ""
return '\033['+';'.join(attribs)+'m' return "\033[" + ";".join(attribs) + "m"
def pos(y, x): def pos(y, x):
''' ANSI absolute position set ''' """ ANSI absolute position set """
return "\033[" + str(y) + ";" + str(x) + "H" return "\033[" + str(y) + ";" + str(x) + "H"
def colorize(string): def colorize(string):
''' colorizes a string based on color_match ''' """ colorizes a string based on color_match """
if not options.colors: if not options.colors:
return string return string
for co in color_match: for co in color_match:
@@ -73,48 +90,55 @@ def colorize(string):
def count_running(string, stats): def count_running(string, stats):
''' Counts the running executions ''' """ Counts the running executions """
spl=[i for i in " ".join(string.split()).split(' ')] spl = [i for i in " ".join(string.split()).split(" ")]
if len(spl) != 7: if len(spl) != 7:
return stats return stats
if spl[6] in stats['files']: if spl[6] in stats["files"]:
index=stats['files'].index(spl[6]) index = stats["files"].index(spl[6])
speed_history=stats['running'][index][1][1:] speed_history = stats["running"][index][1][1:]
speed_history.append((int(spl[4])*1024-(stats['running'][index][0]))/stats['delay']) speed_history.append(
stats['running'][index]=(int(spl[4])*1024, # free space (int(spl[4]) * 1024 - (stats["running"][index][0])) / stats["delay"]
)
stats["running"][index] = (
int(spl[4]) * 1024, # free space
speed_history, # change speed speed_history, # change speed
spl[6], # mount point spl[6], # mount point
stats['running'][index][3], # free space program start stats["running"][index][3], # free space program start
spl[5], # usage in % spl[5], # usage in %
spl[1], # mount type spl[1], # mount type
int(spl[2])*1024 # total space int(spl[2]) * 1024, # total space
) )
else: else:
stats['running'].append((int(spl[4])*1024, stats["running"].append(
(
int(spl[4]) * 1024,
[int(0)] * 5, [int(0)] * 5,
spl[6], spl[6],
int(spl[4]) * 1024, int(spl[4]) * 1024,
spl[5], spl[5],
spl[1], spl[1],
int(spl[2])*1024 int(spl[2]) * 1024,
)) )
stats['running'].sort(key=SORTKEY) )
stats["running"].sort(key=SORTKEY)
stats['files']=[i[2] for i in stats['running']] stats["files"] = [i[2] for i in stats["running"]]
totalfree=sum([i[0] for i in stats['running']]) totalfree = sum([i[0] for i in stats["running"]])
total=sum([i[6] for i in stats['running']]) total = sum([i[6] for i in stats["running"]])
stats['totals']=[totalfree, total] stats["totals"] = [totalfree, total]
return stats return stats
class EndProgram(Exception): class EndProgram(Exception):
''' Nice way of exiting the program ''' """ Nice way of exiting the program """
pass pass
def is_number(s): def is_number(s):
''' Check if string is float ''' """ Check if string is float """
try: try:
out = float(s) out = float(s)
return True return True
@@ -123,44 +147,73 @@ def is_number(s):
def str_short(s, stats): def str_short(s, stats):
''' shorten text to fit screen ''' """ shorten text to fit screen """
maxL=stats['size'][1] - 16 maxL = stats["size"][1] - 16
if len(s) < maxL: if len(s) < maxL:
return s return s
spl=s.split('/') spl = s.split("/")
sNew=spl[0]+'/...'+'/'.join(spl[1:])[-(maxL-len(spl[0])-5):] sNew = spl[0] + "/..." + "/".join(spl[1:])[-(maxL - len(spl[0]) - 5) :]
return sNew return sNew
def print_stats(stats): def print_stats(stats):
''' Prints logged errors, and the status line ''' """ Prints logged errors, and the status line """
# sys.stdout.write(SAVE) # sys.stdout.write(SAVE)
e = 0 e = 0
sys.stdout.write(pos(e+1,0)+c((S,C))+"= DISK FREE = "+c((E))+ sys.stdout.write(
human_time(stats['time'])+'=>'+c((S,G))+human_time()+c((E))+CLRLN) pos(e + 1, 0)
if (stats['running']): + c((S, C))
+ "= DISK FREE = "
+ c((E))
+ human_time(stats["time"])
+ "=>"
+ c((S, G))
+ human_time()
+ c((E))
+ CLRLN
)
if stats["running"]:
pass pass
else: else:
return return
sys.stdout.write(pos(e+2,0)+" TotalDiff Free Total (usage%) Diff/s (positive=more free space)"+CLRLN) sys.stdout.write(
for ex in enumerate(stats['running']): pos(e + 2, 0)
sys.stdout.write(pos(e+3+ex[0],0)+'('+str(ex[0]+1).rjust(2)+') '+ + " TotalDiff Free Total (usage%) Diff/s (positive=more free space)"
' '.join([human_size(ex[1][0]-ex[1][3]).rjust(10), + CLRLN
)
for ex in enumerate(stats["running"]):
sys.stdout.write(
pos(e + 3 + ex[0], 0)
+ "("
+ str(ex[0] + 1).rjust(2)
+ ") "
+ " ".join(
[
human_size(ex[1][0] - ex[1][3]).rjust(10),
human_size(ex[1][0]).rjust(10), human_size(ex[1][0]).rjust(10),
human_size(ex[1][6]).rjust(8), human_size(ex[1][6]).rjust(8),
colorize_usage(ex[1][4]), colorize_usage(ex[1][4]),
(human_size(mean_speed(ex[1][1])) + "/s").rjust(10), (human_size(mean_speed(ex[1][1])) + "/s").rjust(10),
ex[1][2], ex[1][2],
"("+ex[1][5]+")"])+ "(" + ex[1][5] + ")",
CLRLN) ]
sys.stdout.write(pos(e+4+ex[0],0)+'Total:'+ )
' '.join([' '.rjust(9), + CLRLN
human_size(stats['totals'][0]).rjust(10), )
'/', sys.stdout.write(
human_size(stats['totals'][1]).ljust(10) pos(e + 4 + ex[0], 0)
])+ + "Total:"
CLRLN) + " ".join(
for i in range(stats['size'][0]-7-len(stats['running'])): [
" ".rjust(9),
human_size(stats["totals"][0]).rjust(10),
"/",
human_size(stats["totals"][1]).ljust(10),
]
)
+ CLRLN
)
for i in range(stats["size"][0] - 7 - len(stats["running"])):
sys.stdout.write(pos(e + 5 + ex[0] + i, 0) + " " + CLRLN) sys.stdout.write(pos(e + 5 + ex[0] + i, 0) + " " + CLRLN)
sys.stdout.write(DOWN + CLRBLN + CLRLN) sys.stdout.write(DOWN + CLRBLN + CLRLN)
@@ -168,35 +221,45 @@ def print_stats(stats):
def print_stats_once(stats): def print_stats_once(stats):
''' Prints logged errors, once ''' """ Prints logged errors, once """
e = 0 e = 0
sys.stdout.write(c((S,C))+"= DISK FREE = "+c((E,))+CLRLN+'\n') sys.stdout.write(c((S, C)) + "= DISK FREE = " + c((E,)) + CLRLN + "\n")
if (stats['running']): if stats["running"]:
pass pass
else: else:
return return
sys.stdout.write(" Total Used Use% Free"+CLRLN+'\n') sys.stdout.write(" Total Used Use% Free" + CLRLN + "\n")
for ex in enumerate(stats['running']): for ex in enumerate(stats["running"]):
sys.stdout.write( sys.stdout.write(
' '.join([ " ".join(
[
human_size(ex[1][6]).rjust(8), human_size(ex[1][6]).rjust(8),
human_size(ex[1][6] - ex[1][0]).rjust(10), human_size(ex[1][6] - ex[1][0]).rjust(10),
colorize_usage(ex[1][4]), colorize_usage(ex[1][4]),
human_size(ex[1][0]).rjust(10), human_size(ex[1][0]).rjust(10),
ex[1][2], ex[1][2],
"("+ex[1][5]+")"])+ "(" + ex[1][5] + ")",
CLRLN+'\n') ]
)
+ CLRLN
+ "\n"
)
sys.stdout.write( sys.stdout.write(
' '.join([ " ".join(
human_size(stats['totals'][1]).rjust(8), [
human_size(stats['totals'][1]-stats['totals'][0]).rjust(10), ' ', human_size(stats["totals"][1]).rjust(8),
human_size(stats['totals'][0]).rjust(10) human_size(stats["totals"][1] - stats["totals"][0]).rjust(10),
])+ " ",
CLRLN+'\n') human_size(stats["totals"][0]).rjust(10),
]
)
+ CLRLN
+ "\n"
)
def colorize_usage(string): def colorize_usage(string):
''' colorizes the usage string ''' """ colorizes the usage string """
# string length indicates value <10 # string length indicates value <10
if len(string) < 3: if len(string) < 3:
return c((S, G)) + " " + string + c((E)) return c((S, G)) + " " + string + c((E))
@@ -225,12 +288,12 @@ def human_time(dt=False):
def human_size(size, precision=1): def human_size(size, precision=1):
if size == None: if size == None:
return 'nan' return "nan"
sign = "" sign = ""
if size < 0: if size < 0:
sign = "-" sign = "-"
size = -size size = -size
suffixes=['B','KB','MB','GB','TB','PB','EB','ZB'] suffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]
suffixIndex = 0 suffixIndex = 0
defPrecision = 0 defPrecision = 0
while size > 1024: while size > 1024:
@@ -251,7 +314,7 @@ def readinput(lf):
def termsize(): def termsize():
try: try:
rows, columns = os.popen('stty size', 'r').read().split() rows, columns = os.popen("stty size", "r").read().split()
except: except:
(rows, columns) = (25, 80) (rows, columns) = (25, 80)
return (int(rows), int(columns)) return (int(rows), int(columns))
@@ -260,17 +323,18 @@ def termsize():
options = setup_options() options = setup_options()
color_match = { #'line_ends':(re.compile('$'),c.END), color_match = { #'line_ends':(re.compile('$'),c.END),
'err':(re.compile('(Failed)'),c([R,S])+'\\1'+c([E])), "err": (re.compile("(Failed)"), c([R, S]) + "\\1" + c([E])),
'done':(re.compile('(Done)'),c([G,S])+'\\1'+c([E])), "done": (re.compile("(Done)"), c([G, S]) + "\\1" + c([E])),
'percent':(re.compile('([0-9]+%)'),c([Y,S])+'\\1'+c([E])), "percent": (re.compile("([0-9]+%)"), c([Y, S]) + "\\1" + c([E])),
} }
stats={'time':datetime.now(), stats = {
'running':[], "time": datetime.now(),
'files':[], "running": [],
'totals':[], "files": [],
'size': termsize(), "totals": [],
'delay': options.delay "size": termsize(),
"delay": options.delay,
} }
if not options.once: if not options.once:
@@ -283,7 +347,7 @@ while 1:
try: try:
proc = subprocess.Popen(['df','-T'] + omit_opts,stdout=subprocess.PIPE) proc = subprocess.Popen(["df", "-T"] + omit_opts + options.paths, stdout=subprocess.PIPE)
# set a 5 second timeout for the line read. # set a 5 second timeout for the line read.
# ~ signal.signal(signal.SIGALRM, transfers.readline) # ~ signal.signal(signal.SIGALRM, transfers.readline)
# ~ signal.alarm(5) # ~ signal.alarm(5)
@@ -291,7 +355,7 @@ while 1:
if not stdout: if not stdout:
raise EndProgram raise EndProgram
for line in stdout.decode('utf-8').split('\n')[1:]: for line in stdout.decode("utf-8").split("\n")[1:]:
stats = count_running(line, stats) stats = count_running(line, stats)
if options.once: if options.once:
@@ -302,9 +366,7 @@ while 1:
time.sleep(options.delay) time.sleep(options.delay)
except (EndProgram, KeyboardInterrupt): except (EndProgram, KeyboardInterrupt):
sys.stdout.write(DOWN+'\n') sys.stdout.write(DOWN + "\n")
sys.stdout.flush() sys.stdout.flush()
sys.exit(0) sys.exit(0)