Source code for skaff.clitools

#!/usr/bin/env python3

"""
A suite of command line based tools.
"""
# --------------------------------- MODULES -----------------------------------
import errno
import fcntl
import os
import signal
import sys
import termios

from functools import wraps
# --------------------------------- MODULES -----------------------------------


[docs]class ANSIColor: RED = "\x1b[31m" GREEN = "\x1b[32m" YELLOW = "\x1b[33m" KHAKI = "\x1b[1;33m" BLUE = "\x1b[34m" MAGENTA = "\x1b[35m" PURPLE = "\x1b[1;35m" CYAN = "\x1b[36m" BOLD = "\x1b[1m" RESET = "\x1b[0m"
[docs]class TimeOutError(Exception): pass
[docs]def timeout(seconds, error_message=os.strerror(errno.ETIME)): """Sets a timer on a function; should be used as a decorator. Raises 'TimeOutError' upon expiration. """ # Borrowed from stackoverflow: # /questions/2281850/timeout-function-if-it-takes-too-long-to-finish def decorator(func): def _timeout_handle(signum, frame): raise TimeOutError(error_message) def wrapper(*args, **kwargs): signal.signal(signal.SIGALRM, _timeout_handle) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wraps(func)(wrapper) return decorator
[docs]def single_keypress_read(): """Waits for a single keypress on stdin. This is a silly function to call if you need to do it a lot because it has to store stdin's current setup, setup stdin for reading single keystrokes then read the single keystroke then revert stdin back after reading the keystroke. Returns the character of the key that was pressed (zero on KeyboardInterrupt which can happen when a signal gets handled) """ # Borrowed from stackoverflow: # /questions/983354/how-do-i-make-python-to-wait-for-a-pressed-key # Windows support is added but not tested. if "nt" == os.name: import msvcrt try: ret = msvcrt.getch() except KeyboardInterrupt: ret = 0 return ret fd = sys.stdin.fileno() # save old state flags_save = fcntl.fcntl(fd, fcntl.F_GETFL) attrs_save = termios.tcgetattr(fd) # make raw - the way to do this comes from the termios(3) man page. attrs = list(attrs_save) # copy the stored version to update # iflag attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK | termios.ISTRIP | termios.INLCR | termios. IGNCR | termios.ICRNL | termios.IXON) # oflag attrs[1] &= ~termios.OPOST # cflag attrs[2] &= ~(termios.CSIZE | termios. PARENB) attrs[2] |= termios.CS8 # lflag attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON | termios.ISIG | termios.IEXTEN) termios.tcsetattr(fd, termios.TCSANOW, attrs) # turn off non-blocking fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK) # read a single keystroke try: ret = sys.stdin.read(1) # returns a single character except KeyboardInterrupt: ret = 0 finally: # restore old state termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save) fcntl.fcntl(fd, fcntl.F_SETFL, flags_save) return ret