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"]
speed_history, # change speed )
spl[6], # mount point stats["running"][index] = (
stats['running'][index][3], # free space program start int(spl[4]) * 1024, # free space
spl[5], # usage in % speed_history, # change speed
spl[1], # mount type spl[6], # mount point
int(spl[2])*1024 # total space stats["running"][index][3], # free space program start
) spl[5], # usage in %
spl[1], # mount type
int(spl[2]) * 1024, # total space
)
else: else:
stats['running'].append((int(spl[4])*1024, stats["running"].append(
[int(0)]*5, (
spl[6], int(spl[4]) * 1024,
int(spl[4])*1024, [int(0)] * 5,
spl[5], spl[6],
spl[1], int(spl[4]) * 1024,
int(spl[2])*1024 spl[5],
)) spl[1],
stats['running'].sort(key=SORTKEY) int(spl[2]) * 1024,
)
)
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
human_size(ex[1][0]).rjust(10), )
human_size(ex[1][6]).rjust(8), for ex in enumerate(stats["running"]):
colorize_usage(ex[1][4]), sys.stdout.write(
(human_size(mean_speed(ex[1][1]))+"/s").rjust(10), pos(e + 3 + ex[0], 0)
ex[1][2], + "("
"("+ex[1][5]+")"])+ + str(ex[0] + 1).rjust(2)
CLRLN) + ") "
sys.stdout.write(pos(e+4+ex[0],0)+'Total:'+ + " ".join(
' '.join([' '.rjust(9), [
human_size(stats['totals'][0]).rjust(10), human_size(ex[1][0] - ex[1][3]).rjust(10),
'/', human_size(ex[1][0]).rjust(10),
human_size(stats['totals'][1]).ljust(10) human_size(ex[1][6]).rjust(8),
])+ colorize_usage(ex[1][4]),
CLRLN) (human_size(mean_speed(ex[1][1])) + "/s").rjust(10),
for i in range(stats['size'][0]-7-len(stats['running'])): ex[1][2],
sys.stdout.write(pos(e+5+ex[0]+i,0)+" "+CLRLN) "(" + ex[1][5] + ")",
]
)
+ CLRLN
)
sys.stdout.write(
pos(e + 4 + ex[0], 0)
+ "Total:"
+ " ".join(
[
" ".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]-ex[1][0]).rjust(10), human_size(ex[1][6]).rjust(8),
colorize_usage(ex[1][4]), human_size(ex[1][6] - ex[1][0]).rjust(10),
human_size(ex[1][0]).rjust(10), colorize_usage(ex[1][4]),
ex[1][2], human_size(ex[1][0]).rjust(10),
"("+ex[1][5]+")"])+ ex[1][2],
CLRLN+'\n') "(" + ex[1][5] + ")",
]
)
+ 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)