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

@@ -1,249 +1,312 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys,os,glob import sys, os, glob
from datetime import datetime 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
VERSION=3 # ,threading
W= '30' VERSION = 3
R= '31'
G= '32' W = "30"
Y= '33' R = "31"
B= '34' G = "32"
M= '35' Y = "33"
C= '36' B = "34"
S= '1' M = "35"
E= '0' C = "36"
BR= '41' S = "1"
CLR = '\033[2J' E = "0"
SAVE = '\033[s' BR = "41"
LOAD = '\033[u' CLR = "\033[2J"
CLRLN = '\033[K' SAVE = "\033[s"
CLRBLN = '\033[1K' LOAD = "\033[u"
DOWN = '\033[1B' CLRLN = "\033[K"
CLRBLN = "\033[1K"
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, )
help="Disable colored output")
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)
options=parser.parse_args()
parser.add_argument(
"--no-colors",
"--nc",
action="store_false",
dest="colors",
default=True,
help="Disable colored output",
)
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()
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:
string=color_match[co][0].sub(color_match[co][1],string) string = color_match[co][0].sub(color_match[co][1], string)
return string return 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(0)]*5, (
int(spl[4]) * 1024,
[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
except: except:
return False return False
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'])): [
sys.stdout.write(pos(e+5+ex[0]+i,0)+" "+CLRLN) " ".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(DOWN+CLRBLN+CLRLN) sys.stdout.write(DOWN + CLRBLN + CLRLN)
#sys.stdout.write(LOAD) # sys.stdout.write(LOAD)
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))
# string lenght indicates 100% # string lenght indicates 100%
if len(string)==4: if len(string) == 4:
return c((S,R))+string+c((E)) return c((S, R)) + string + c((E))
usage=int(string[0:2]) usage = int(string[0:2])
if usage>95: if usage > 95:
return c((S,R))+" "+string+c((E)) return c((S, R)) + " " + string + c((E))
if usage<80: if usage < 80:
return c((S,G))+" "+string+c((E)) return c((S, G)) + " " + string + c((E))
return c((S,Y))+" "+string+c((E)) return c((S, Y)) + " " + string + c((E))
def mean_speed(history): def mean_speed(history):
speed=sum(history)/len(history) speed = sum(history) / len(history)
return int(speed) return int(speed)
def human_time(dt=False): def human_time(dt=False):
if not dt: if not dt:
dt=datetime.now() dt = datetime.now()
return dt.strftime("%H:%M:%S") return dt.strftime("%H:%M:%S")
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:
suffixIndex += 1 suffixIndex += 1
size = size/1024.0 size = size / 1024.0
defPrecision=precision defPrecision = precision
return "%s%.*f%s"%(sign,defPrecision,size,suffixes[suffixIndex]) return "%s%.*f%s" % (sign, defPrecision, size, suffixes[suffixIndex])
def readinput(lf): def readinput(lf):
try: try:
line = lf.stdout.readline() line = lf.stdout.readline()
#line=lf.readline() # line=lf.readline()
return line return line
except: except:
return "CleanerTimeout" return "CleanerTimeout"
@@ -251,30 +314,31 @@ 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))
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:
sys.stdout.write(CLR+pos(0,0)+"Launching...") sys.stdout.write(CLR + pos(0, 0) + "Launching...")
omit_opts = [] omit_opts = []
for omit in options.exclude.split(","): for omit in options.exclude.split(","):
omit_opts.append("-x") omit_opts.append("-x")
@@ -283,16 +347,16 @@ 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)
stdout,stderr=proc.communicate() stdout, stderr = proc.communicate()
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:
print_stats_once(stats) print_stats_once(stats)
@@ -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)