restructured data in use
This commit is contained in:
parent
991a5c01b0
commit
05067532e2
121
ls.py
121
ls.py
|
|
@ -8,6 +8,7 @@ import argparse
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import subprocess
|
import subprocess
|
||||||
import functools
|
import functools
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
# ANSI escape codes for colors
|
# ANSI escape codes for colors
|
||||||
COLORS = {
|
COLORS = {
|
||||||
|
|
@ -34,21 +35,26 @@ class Filetype(Enum):
|
||||||
S_IFIFO = 0o010000
|
S_IFIFO = 0o010000
|
||||||
ERR = 0
|
ERR = 0
|
||||||
|
|
||||||
def colorize(text, color):
|
Permissions = namedtuple("Permissions", "mode type char color prettybits")
|
||||||
|
|
||||||
|
FileString = namedtuple("FileString", ["path", "file", "file_color",
|
||||||
|
"path_color", "colored_path",
|
||||||
|
"colored_file", "colored_filepath",
|
||||||
|
"link_sep", "link_dest",
|
||||||
|
"link_dest_full", "link_color",
|
||||||
|
"colored_link_dest"
|
||||||
|
], defaults=['','','','',''])
|
||||||
|
|
||||||
|
def colorwrap(text, color):
|
||||||
return f"{COLORS[color]}{text}{COLORS['RESET']}"
|
return f"{COLORS[color]}{text}{COLORS['RESET']}"
|
||||||
|
|
||||||
|
def sizeof_fmt(num):
|
||||||
def gen_color_file_string(filepath, mode):
|
for unit in ("", "K", "M", "G", "T", "P", "E", "Z"):
|
||||||
path, file = os.path.split(filepath)
|
if abs(num) < 1024.0:
|
||||||
perms = parse_permissions(mode)
|
if unit == "": return f"{num}" #exception to not do .0 for bytes
|
||||||
color = perms['color']
|
return f"{num:3.1f}{unit}"
|
||||||
filestring = f"{path and colorize(path+'/', 'DIM')}{colorize(file, color)}"
|
num /= 1024.0
|
||||||
# dircolors var?
|
return f"{num:.1f}Y"
|
||||||
if perms['char'] == 'l':
|
|
||||||
pointfile = os.readlink(filepath)
|
|
||||||
pointfilereal = os.path.join(os.path.dirname(filepath), os.readlink(filepath))
|
|
||||||
filestring += ' -> ' + colorize(pointfile, "GREEN" if os.path.exists(pointfilereal) else "RED" )
|
|
||||||
return filestring
|
|
||||||
|
|
||||||
|
|
||||||
def parse_permissions(mode):
|
def parse_permissions(mode):
|
||||||
|
|
@ -98,15 +104,35 @@ def parse_permissions(mode):
|
||||||
"x" if mode & 0o001 else "-"
|
"x" if mode & 0o001 else "-"
|
||||||
])
|
])
|
||||||
|
|
||||||
return {'mode':mode, 'type': filetype, 'char': char, 'color': color, 'prettybits': prettybits }
|
#return {'mode':mode, 'type': filetype, 'char': char, 'color': color, 'prettybits': prettybits }
|
||||||
|
return Permissions(mode, filetype, char, color, prettybits)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def file_string_gen(filepath, mode):
|
||||||
|
path, file = os.path.split(filepath)
|
||||||
|
perms = parse_permissions(mode)
|
||||||
|
file_color = perms.color
|
||||||
|
path_color = 'DIM'
|
||||||
|
|
||||||
|
colored_path = colorwrap(path+'/', path_color) if path else ''
|
||||||
|
colored_file = colorwrap(file, file_color)
|
||||||
|
colored_filepath = colored_path + colored_file
|
||||||
|
|
||||||
|
# links
|
||||||
|
if perms.type == Filetype.S_IFLNK:
|
||||||
|
link_sep = ' -> '
|
||||||
|
link_dest = os.readlink(filepath)
|
||||||
|
link_dest_real = os.path.join(os.path.dirname(filepath), os.readlink(filepath))
|
||||||
|
link_color = "GREEN" if os.path.exists(link_dest_real) else "RED"
|
||||||
|
colored_link_dest = colorwrap(link_dest, link_color)
|
||||||
|
return FileString(path, file, file_color, path_color, colored_path, colored_file, colored_filepath, link_sep, link_dest, link_dest_real, link_color, colored_link_dest)
|
||||||
|
|
||||||
|
return FileString(path, file, file_color, path_color, colored_path, colored_file, colored_filepath)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def sizeof_fmt(num):
|
|
||||||
for unit in ("", "K", "M", "G", "T", "P", "E", "Z"):
|
|
||||||
if abs(num) < 1024.0:
|
|
||||||
if unit == "": return f"{num}" #exception to not do .0 for bytes
|
|
||||||
return f"{num:3.1f}{unit}"
|
|
||||||
num /= 1024.0
|
|
||||||
return f"{num:.1f}Y"
|
|
||||||
|
|
||||||
def is_path_git_repo_dir(path, mode):
|
def is_path_git_repo_dir(path, mode):
|
||||||
#I hate having to take in the mode here, but it makes it easier for usage
|
#I hate having to take in the mode here, but it makes it easier for usage
|
||||||
|
|
@ -120,9 +146,9 @@ def git_gud(path):
|
||||||
mods = len([x for x in lines if x[0] == 'M'])
|
mods = len([x for x in lines if x[0] == 'M'])
|
||||||
unt = len([x for x in lines if x[0] == '?'])
|
unt = len([x for x in lines if x[0] == '?'])
|
||||||
ding = ''
|
ding = ''
|
||||||
ding += colorize('!'+str(mods), "YELLOW") if mods > 0 else ''
|
ding += colorwrap('!'+str(mods), "YELLOW") if mods > 0 else ''
|
||||||
ding += ' ' if mods > 0 and unt > 0 else ''
|
ding += ' ' if mods > 0 and unt > 0 else ''
|
||||||
ding += colorize('?'+str(unt), "CYAN") if unt > 0 else ''
|
ding += colorwrap('?'+str(unt), "CYAN") if unt > 0 else ''
|
||||||
return ding
|
return ding
|
||||||
|
|
||||||
# output = subprocess.check_output(['git', 'rev-list', '--count', '--left-only', '@{u}...HEAD'], cwd=file_path, stderr=subprocess.DEVNULL)
|
# output = subprocess.check_output(['git', 'rev-list', '--count', '--left-only', '@{u}...HEAD'], cwd=file_path, stderr=subprocess.DEVNULL)
|
||||||
|
|
@ -145,58 +171,55 @@ def list_files(directory='.', args={}):
|
||||||
|
|
||||||
|
|
||||||
#get file metadata
|
#get file metadata
|
||||||
|
FileMeta = namedtuple("FileMeta", "name rel_file_path abs_file_path stats")
|
||||||
def get_file_metadata(path, name):
|
def get_file_metadata(path, name):
|
||||||
rel_file_path = os.path.join(path, name) # for rel paths
|
rel_file_path = os.path.join(path, name) # for rel paths
|
||||||
abs_file_path = os.path.abspath(rel_file_path) # for full path
|
abs_file_path = os.path.abspath(rel_file_path) # for full path
|
||||||
stats = os.lstat(rel_file_path)
|
stats = os.lstat(rel_file_path)
|
||||||
return {
|
return FileMeta(name, rel_file_path, abs_file_path, stats)
|
||||||
"name": name,
|
|
||||||
"rel_file_path": rel_file_path,
|
|
||||||
"abs_file_path": abs_file_path,
|
|
||||||
"stats": stats
|
|
||||||
}
|
|
||||||
files = [ get_file_metadata(directory, name) for name in os.listdir(directory) ]
|
files = [ get_file_metadata(directory, name) for name in os.listdir(directory) ]
|
||||||
|
|
||||||
|
|
||||||
longest_size_length = len(str(functools.reduce(lambda a, b: a if len(str(a['stats'].st_size)) > len(str(b['stats'].st_size)) else b, files)['stats'].st_size))
|
longest_size_length = len(str(functools.reduce(lambda a, b: a if len(str(a.stats.st_size)) > len(str(b.stats.st_size)) else b, files).stats.st_size))
|
||||||
|
|
||||||
print(f"files: {len(files)}")
|
print(f"files: {len(files)}")
|
||||||
|
|
||||||
# Sort stuff
|
# Sort stuff
|
||||||
if args.time_sorted:
|
if args.time_sorted:
|
||||||
files.sort(key=lambda f: f["stats"].st_mtime, reverse=(not args.reverse))
|
files.sort(key=lambda f: f.stats.st_mtime, reverse=(not args.reverse))
|
||||||
elif args.size_sorted:
|
elif args.size_sorted:
|
||||||
files.sort(key=lambda f: f["stats"].st_size, reverse=(not args.reverse))
|
files.sort(key=lambda f: f.stats.st_size, reverse=(not args.reverse))
|
||||||
else:
|
else:
|
||||||
files.sort(key=lambda f:f["name"], reverse=(args.reverse))
|
files.sort(key=lambda f:f.name, reverse=(args.reverse))
|
||||||
|
|
||||||
|
|
||||||
# filter out hidden if not specify -a
|
# filter out hidden if not specify -a
|
||||||
if not args.all:
|
if not args.all:
|
||||||
files = [file for file in files if not file['name'].startswith('.')]
|
files = [file for file in files if not file.name.startswith('.')]
|
||||||
|
|
||||||
if not args.long:
|
if not args.long:
|
||||||
for file in files:
|
for file in files:
|
||||||
colored_file = gen_color_file_string(file["abs_file_path"], file["stats"].st_mode)
|
colored_file = gen_color_file_string(file.abs_file_path, file.stats.st_mode)
|
||||||
# rel is broken
|
# rel is broken
|
||||||
print(colored_file)
|
print(colored_file)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
for file in files:
|
for file in files:
|
||||||
size = file['stats'].st_size
|
size = file.stats.st_size
|
||||||
user = pwd.getpwuid(file['stats'].st_uid).pw_name
|
user = pwd.getpwuid(file.stats.st_uid).pw_name
|
||||||
group = grp.getgrgid(file['stats'].st_gid).gr_name
|
group = grp.getgrgid(file.stats.st_gid).gr_name
|
||||||
permissions = parse_permissions(file['stats'].st_mode)
|
permissions = parse_permissions(file.stats.st_mode)
|
||||||
nlinks = file['stats'].st_nlink
|
nlinks = file.stats.st_nlink
|
||||||
|
|
||||||
perm_prettybits = permissions['prettybits']
|
perm_prettybits = permissions.prettybits
|
||||||
timestring = time.strftime("%b %d %H:%M", time.localtime(file["stats"].st_mtime))
|
timestring = time.strftime("%b %d %H:%M", time.localtime(file.stats.st_mtime))
|
||||||
|
|
||||||
if args.sparse:
|
if args.sparse:
|
||||||
if perm_prettybits == 'l':
|
if perm_prettybits == 'l':
|
||||||
perm_prettybits = 'l '
|
perm_prettybits = 'l '
|
||||||
if permissions['type'] == Filetype.S_IFDIR:
|
if permissions.type == Filetype.S_IFDIR:
|
||||||
size=""
|
size=""
|
||||||
|
|
||||||
if args.human:
|
if args.human:
|
||||||
|
|
@ -206,11 +229,17 @@ def list_files(directory='.', args={}):
|
||||||
timestring = time.strftime("%b %d %Y %X %z", time.localtime(file["stats"].st_mtime)) # -0400
|
timestring = time.strftime("%b %d %Y %X %z", time.localtime(file["stats"].st_mtime)) # -0400
|
||||||
#mtime = time.strftime("%b %d %X %Z", time.localtime(stats.st_mtime)) # CST
|
#mtime = time.strftime("%b %d %X %Z", time.localtime(stats.st_mtime)) # CST
|
||||||
|
|
||||||
colored_file = gen_color_file_string(file["abs_file_path"], file["stats"].st_mode)
|
file_strings = file_string_gen(file.abs_file_path, file.stats.st_mode)
|
||||||
gitstat = git_gud(file["abs_file_path"]) if (args.extend and is_path_git_repo_dir(file["abs_file_path"], file["stats"].st_mode)) else ''
|
file_str = ' ' + file_strings.colored_filepath + file_strings.link_sep + file_strings.colored_link_dest
|
||||||
|
#so hacky
|
||||||
|
if ' ' in file.abs_file_path:
|
||||||
|
file_str = '\'' + file_strings.colored_filepath + '\' ' + file_strings.link_sep + file_strings.colored_link_dest
|
||||||
|
|
||||||
|
#print(file_string_gen(file["abs_file_path"], file["stats"].st_mode))
|
||||||
|
gitstat = git_gud(file.abs_file_path) if (args.extend and is_path_git_repo_dir(file.abs_file_path, file.stats.st_mode)) else ''
|
||||||
|
|
||||||
## do printing
|
## do printing
|
||||||
print(f"{perm_prettybits} {nlinks:2d} {user:<8s} {group:<8s} {size:>{longest_size_length}} {timestring} {colored_file} {gitstat}")
|
print(f"{perm_prettybits} {nlinks:2d} {user:<8s} {group:<8s} {size:>{longest_size_length}} {timestring} {file_str} {gitstat}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue