From 3a08bcb116b0f07709f7ca43e4f1cd04c948ee57 Mon Sep 17 00:00:00 2001 From: endorphant Date: Fri, 27 May 2016 03:21:11 -0400 Subject: [PATCH] code cleanup moved a whole bunch of functions around for better code clarity. it's 3am and i can't sleep, so i vaguely expect to have to revert this in the morning. --- bin/_ttbp.py | 180 ++++++------------------------------------- bin/core.py | 214 ++++++++++++++++++++++++++++++++++----------------- bin/util.py | 74 +++++++++++++++++- 3 files changed, 242 insertions(+), 226 deletions(-) diff --git a/bin/_ttbp.py b/bin/_ttbp.py index 2e3b3a7..fa54314 100644 --- a/bin/_ttbp.py +++ b/bin/_ttbp.py @@ -72,8 +72,8 @@ SPACER = "\n" INVALID = "please pick a number from the list of options!\n\n" DUST = "sorry about the dust, but this part is still under construction. check back later!\n\n" QUITS = ['exit', 'quit', 'q', 'x'] -BACKS = ['back', 'b', 'q'] EJECT = "eject button fired! going home now." +RAINBOW = True ## ref @@ -156,13 +156,13 @@ def check_init(): ## ttbprc validation while not os.path.isfile(TTBPRC): - setup_handler() + setup_repair() try: SETTINGS = json.load(open(TTBPRC)) except ValueError: - setup_handler() + setup_repair() - ## PATCH CHECK HERE + ## version checker if build_mismatch(): switch_build() if not updated(): @@ -170,7 +170,7 @@ def check_init(): ## when ready, enter main program and load core engine raw_input("press to explore your feels.\n\n") - core.load() + core.load(SETTINGS) return "" else: @@ -217,7 +217,7 @@ press to begin, or to get out of here. ## run user-interactive setup and load core engine setup() - core.load() + core.load(SETTINGS) raw_input("\nyou're all good to go, "+chatter.say("friend")+"! hit to continue.\n\n") return "" @@ -251,9 +251,9 @@ def gen_header(): """ return header -def setup_handler(): +def setup_repair(): ''' - setup wrapper function + setup repair function * calls setup() * handles ^c @@ -281,7 +281,7 @@ def setup(): global SETTINGS print("\n\ttext editor:\t" +SETTINGS.get("editor")) - if publishing(): + if core.publishing(): print("\tpublish dir:\t" +os.path.join(PUBLIC, SETTINGS.get("publish dir"))) print("\tpubishing:\t"+str(SETTINGS.get("publishing"))+"\n") @@ -292,9 +292,9 @@ def setup(): # publishing selection SETTINGS.update({"publishing":select_publishing()}) update_publishing() - redraw("blog publishing: "+str(publishing())) + redraw("blog publishing: "+str(core.publishing())) - if publishing(): + if core.publishing(): print("publish directory: ~"+USER+"/public_html/"+SETTINGS.get("publish dir")) # save settings @@ -309,25 +309,6 @@ def setup(): ## menus -def print_menu(menu): - ''' - pretty menu handler - - * takes list of options and prints them - ''' - - i = 0 - for x in menu: - line = [] - line.append(util.attach_rainbow()) - line.append("\t[ ") - if i < 10: - line.append(" ") - line.append(str(i)+" ] "+x) - line.append(util.attach_reset()) - print("".join(line)) - i += 1 - def main_menu(): ''' main navigation menu @@ -344,7 +325,7 @@ def main_menu(): "read documentation"] print("you're at ttbp home. remember, you can always press to come back here.\n\n") - print_menu(menuOptions) + util.print_menu(menuOptions, RAINBOW) try: choice = raw_input("\ntell me about your feels (or 'quit' to exit): ") @@ -356,12 +337,12 @@ def main_menu(): redraw() today = time.strftime("%Y%m%d") write_entry(os.path.join(DATA, today+".txt")) - www_neighbors(find_ttbps()) + core.www_neighbors() elif choice == '1': redraw("your recorded feels, listed by date:\n") view_feels(USER) elif choice == '2': - users = find_ttbps() + users = core.find_ttbps() redraw("the following "+p.no("user", len(users))+" "+p.plural("is", len(users))+" recording feels on ttbp:\n") view_neighbors(users) elif choice == '3': @@ -370,7 +351,7 @@ def main_menu(): elif choice == '4': redraw("now changing your settings. press if you didn't mean to do this.") try: - setup() + core.load(setup()) # reload settings to core except KeyboardInterrupt(): redraw(EJECT) redraw() @@ -399,7 +380,7 @@ def feedback_menu(): print("you're about to send mail to ~endorphant about ttbp\n\n") - print_menu(SUBJECTS) + util.print_menu(SUBJECTS, RAINBOW) choice = raw_input("\npick a category for your feedback: ") cat = "" @@ -473,10 +454,10 @@ def view_neighbors(users): sortedUsers.append(user[0]) userIndex.append(user[2]) - print_menu(sortedUsers) + util.print_menu(sortedUsers, RAINBOW) #raw_input("\n\npress to go back home.\n\n") - choice = list_select(sortedUsers, "pick a townie to browse their feels, or type 'back' to go home: ") + choice = util.list_select(sortedUsers, "pick a townie to browse their feels, or type 'back' to go home: ") if choice is not False: redraw("~"+userIndex[choice]+"'s recorded feels, listed by date: \n") @@ -571,7 +552,7 @@ editor. left = "" - if publishing(): + if core.publishing(): core.load_files() core.write("index.html") left = "posted to "+LIVE+USER+"/"+SETTINGS["publish dir"]+"/index.html\n\n>" @@ -613,9 +594,9 @@ def list_entries(metas, entries, prompt): displays a list of entries for reading selection ''' - print_menu(entries) + util.print_menu(entries, RAINBOW) - choice = list_select(entries, "pick an entry from the list, or type 'back' to go back: ") + choice = util.list_select(entries, "pick an entry from the list, or type 'back' to go back: ") if choice is not False: @@ -646,7 +627,7 @@ def view_feed(): feedList = [] - for townie in find_ttbps(): + for townie in core.find_ttbps(): entryDir = os.path.join("/home", townie, ".ttbp", "entries") filenames = os.listdir(entryDir) @@ -674,124 +655,13 @@ def view_feed(): ## misc helpers -def find_ttbps(): - ''' - returns a list of users with a ttbp by checking for a valid ttbprc - ''' - - users = [] - - for townie in os.listdir("/home"): - if os.path.exists(os.path.join("/home", townie, ".ttbp", "config", "ttbprc")): - users.append(townie) - - return users - -def www_neighbors(users): - ''' - takes a list of users with publiishing turned on and prepares it for www output - ''' - - userList = [] - - for user in users: - if not publishing(user): - continue - - userRC = json.load(open(os.path.join("/home", user, ".ttbp", "config", "ttbprc"))) - - url = LIVE+user+"/"+userRC["publish dir"] - - lastfile = "" - files = os.listdir(os.path.join("/home", user, ".ttbp", "entries")) - files.sort() - for filename in files: - if core.valid(filename): - lastfile = os.path.join("/home", user, ".ttbp", "entries", filename) - - if lastfile: - last = os.path.getctime(lastfile) - timestamp = time.strftime("%Y-%m-%d at %H:%M", time.localtime(last)) + " (utc"+time.strftime("%z")[0]+time.strftime("%z")[2]+")" - else: - timestamp = "" - last = 0 - - userList.append(["~"+user+" "+timestamp, last]) - - # sort user by most recent entry - userList.sort(key = lambda userdata:userdata[1]) - userList.reverse() - sortedUsers = [] - for user in userList: - sortedUsers.append(user[0]) - - core.write_global_feed(sortedUsers) - -def list_select(options, prompt): - ''' - given a list, cycles through the prompt until a valid index is imputted - ''' - - ans = "" - invalid = True - - while invalid: - choice = raw_input("\n\n"+prompt) - - if choice in BACKS: - return False - - try: - ans = int(choice) - except ValueError: - return list_select(options, prompt) - - invalid = False - - if ans >= len(options): - return list_select(options, prompt) - - return ans - -def input_yn(query): - ''' - given a query, returns boolean True or False by processing y/n input - ''' - - try: - ans = raw_input(query+" [y/n] ") - except KeyboardInterrupt: - input_yn(query) - - while ans not in ["y", "n"]: - ans = raw_input("'y' or 'n' please: ") - - if ans == "y": - return True - else: - return False - -def publishing(username = USER): - ''' - checks .ttbprc for whether or not user opted for www publishing - ''' - - ttbprc = {} - - if username == USER: - ttbprc = SETTINGS - - else: - ttbprc = json.load(open(os.path.join("/home", username, ".ttbp", "config", "ttbprc"))) - - return ttbprc.get("publishing") def select_editor(): ''' setup helper for editor selection ''' - print_menu(EDITORS) + util.print_menu(EDITORS, RAINBOW) choice = raw_input("\npick your favorite text editor: ") while choice not in ['0', '1', '2', '3', '4', '5']: choice = raw_input("\nplease pick a number from the list: ") @@ -837,7 +707,7 @@ def select_publishing(): setup helper for toggling publishing ''' - publish = input_yn("""\ + publish = util.input_yn("""\ do you want to publish your feels online? if yes, your feels will be published to a directory of your choice in @@ -872,7 +742,7 @@ def update_publishing(): global SETTINGS - if publishing(): + if core.publishing(): oldDir = SETTINGS.get("publish dir") newDir = select_publish_dir() SETTINGS.update({"publish dir": newDir}) diff --git a/bin/core.py b/bin/core.py index f5db44b..ba301b2 100644 --- a/bin/core.py +++ b/bin/core.py @@ -33,6 +33,7 @@ import time import subprocess import re import mistune +import json import chatter @@ -47,21 +48,24 @@ DATA = os.path.join(PATH, "entries") FEED = os.path.join(SOURCE, "www", "index.html") DOCS = os.path.join(SOURCE, "www", "help.html") NOPUB = os.path.join(CONFIG, "nopub") +SETTINGS = {} HEADER = "" FOOTER = "" FILES = [] -def load(): +def load(ttbprc): ''' get all them globals set up!! ''' global HEADER global FOOTER + global SETTINGS HEADER = open(os.path.join(CONFIG, "header.txt")).read() FOOTER = open(os.path.join(CONFIG, "footer.txt")).read() + SETTINGS = ttbprc load_files() @@ -92,6 +96,9 @@ def load_files(): FILES.sort() FILES.reverse() + +## html outputting + def write(outurl="default.html"): ''' main page renderer @@ -191,74 +198,6 @@ def write_entry(filename): return entry -def parse_date(file): - ''' - parses date out of pre-validated filename - - * assumes a filename of YYYYMMDD.txt - * returns a list: - [0] 'YYYY' - [1] 'MM' - [2] 'DD' - ''' - - rawdate = os.path.splitext(os.path.basename(file))[0] - - date = [rawdate[0:4], rawdate[4:6], rawdate[6:]] - - return date - -def meta(entries = FILES): - ''' - metadata generator - - * takes a list of filenames and returns a 2d list: - [0] absolute path - [1] mtime - [2] wc -w - [3] timestamp "DD month YYYY at HH:MM" - [4] entry date YYYY-MM-DD - [5] author - - * sorted in reverse date order by [4] - ''' - - meta = [] - - for filename in entries: - mtime = os.path.getmtime(filename) - wc = subprocess.check_output(["wc","-w",filename]).split()[0] - timestamp = time.strftime("%Y-%m-%d at %H:%M", time.localtime(mtime)) - date = "-".join(parse_date(filename)) - author = os.path.split(os.path.split(os.path.split(os.path.split(filename)[0])[0])[0])[1] - - - meta.append([filename, mtime, wc, timestamp, date, author]) - - meta.sort(key = lambda filename:filename[4]) - meta.reverse() - - return meta - -def valid(filename): - ''' - filename validator - - * check if the filename is YYYYMMDD.txt - ''' - - filesplit = os.path.splitext(os.path.basename(filename)) - - if filesplit[1] != ".txt": - return False - - pattern = '^((19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|1\d|2\d|3[01])$' - - if not re.match(pattern, filesplit[0]): - return False - - return True - def write_global_feed(blogList): ''' main ttbp index printer @@ -319,6 +258,143 @@ def write_global_feed(blogList): outfile.close() +## misc helpers + +def meta(entries = FILES): + ''' + metadata generator + + * takes a list of filenames and returns a 2d list: + [0] absolute path + [1] mtime + [2] wc -w + [3] timestamp "DD month YYYY at HH:MM" + [4] entry date YYYY-MM-DD + [5] author + + * sorted in reverse date order by [4] + ''' + + meta = [] + + for filename in entries: + mtime = os.path.getmtime(filename) + wc = subprocess.check_output(["wc","-w",filename]).split()[0] + timestamp = time.strftime("%Y-%m-%d at %H:%M", time.localtime(mtime)) + date = "-".join(parse_date(filename)) + author = os.path.split(os.path.split(os.path.split(os.path.split(filename)[0])[0])[0])[1] + + meta.append([filename, mtime, wc, timestamp, date, author]) + + meta.sort(key = lambda filename:filename[4]) + meta.reverse() + + return meta + +def valid(filename): + ''' + filename validator + + * check if the filename is YYYYMMDD.txt + ''' + + filesplit = os.path.splitext(os.path.basename(filename)) + + if filesplit[1] != ".txt": + return False + + pattern = '^((19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|1\d|2\d|3[01])$' + + if not re.match(pattern, filesplit[0]): + return False + + return True + +def parse_date(file): + ''' + parses date out of pre-validated filename + + * assumes a filename of YYYYMMDD.txt + * returns a list: + [0] 'YYYY' + [1] 'MM' + [2] 'DD' + ''' + + rawdate = os.path.splitext(os.path.basename(file))[0] + + date = [rawdate[0:4], rawdate[4:6], rawdate[6:]] + + return date + +def find_ttbps(): + ''' + returns a list of users with a ttbp by checking for a valid ttbprc + ''' + + users = [] + + for townie in os.listdir("/home"): + if os.path.exists(os.path.join("/home", townie, ".ttbp", "config", "ttbprc")): + users.append(townie) + + return users + +def publishing(username = USER): + ''' + checks .ttbprc for whether or not user opted for www publishing + ''' + + ttbprc = {} + + if username == USER: + ttbprc = SETTINGS + + else: + ttbprc = json.load(open(os.path.join("/home", username, ".ttbp", "config", "ttbprc"))) + + return ttbprc.get("publishing") + +def www_neighbors(): + ''' + takes a list of users with publiishing turned on and prepares it for www output + ''' + + userList = [] + + for user in find_ttbps(): + if not publishing(user): + continue + + userRC = json.load(open(os.path.join("/home", user, ".ttbp", "config", "ttbprc"))) + + url = LIVE+user+"/"+userRC["publish dir"] + + lastfile = "" + files = os.listdir(os.path.join("/home", user, ".ttbp", "entries")) + files.sort() + for filename in files: + if valid(filename): + lastfile = os.path.join("/home", user, ".ttbp", "entries", filename) + + if lastfile: + last = os.path.getctime(lastfile) + timestamp = time.strftime("%Y-%m-%d at %H:%M", time.localtime(last)) + " (utc"+time.strftime("%z")[0]+time.strftime("%z")[2]+")" + else: + timestamp = "" + last = 0 + + userList.append(["~"+user+" "+timestamp, last]) + + # sort user by most recent entry + userList.sort(key = lambda userdata:userdata[1]) + userList.reverse() + sortedUsers = [] + for user in userList: + sortedUsers.append(user[0]) + + write_global_feed(sortedUsers) + ############# ############# ############# diff --git a/bin/util.py b/bin/util.py index b94b7d8..8f4dfca 100644 --- a/bin/util.py +++ b/bin/util.py @@ -24,10 +24,12 @@ import time import random import colorama +## misc globals +BACKS = ['back', 'b', 'q'] + +## color stuff colorama.init() - textcolors = [ colorama.Fore.RED, colorama.Fore.GREEN, colorama.Fore.YELLOW, colorama.Fore.BLUE, colorama.Fore.MAGENTA, colorama.Fore.WHITE, colorama.Fore.CYAN] - lastcolor = colorama.Fore.RESET p = inflect.engine() @@ -125,3 +127,71 @@ def genID(digits=5): x += 1 return id + +def print_menu(menu, rainbow=False): + ''' + A pretty menu handler that takes an incoming lists of + options and prints them nicely. + + Set rainbow=True for colorized menus. + ''' + + i = 0 + for x in menu: + line = [] + if rainbow: + line.append(attach_rainbow()) + line.append("\t[ ") + if i < 10: + line.append(" ") + line.append(str(i)+" ] "+x) + line.append(attach_reset()) + print("".join(line)) + i += 1 + +def list_select(options, prompt): + ''' + Given a list and query prompt, returns either False as an + eject flag, or an integer index of the list Catches cancel + option from list defined by BACKS; otherwise, retries on + ValueError or IndexError. + ''' + + ans = "" + invalid = True + + choice = raw_input("\n\n"+prompt) + + if choice in BACKS: + return False + + try: + ans = int(choice) + except ValueError: + return list_select(options, prompt) + + try: + options[ans] + except IndexError: + return list_select(options, prompt) + + return ans + +def input_yn(query): + ''' + Given a query, returns boolean True or False by processing y/n input + ''' + + try: + ans = raw_input(query+" [y/n] ") + except KeyboardInterrupt: + input_yn(query) + + while ans not in ["y", "n"]: + ans = raw_input("'y' or 'n' please: ") + + if ans == "y": + return True + else: + return False +