#!/bin/python3 # # yelp-new # Copyright (C) 2010-2020 Shaun McCance # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import configparser import datetime import os import subprocess import sys # FIXME: don't hardcode this DATADIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'templates', 'py') class YelpNew: arguments = [ ('help', '-h', None, 'Show this help and exit'), ('stub', None, None, 'Create a stub file with .stub appended'), ('tmpl', None, None, 'Copy an installed template to a local template'), ('version', '-v', 'VERS', 'Specify the version number to substitute') ] def __init__(self): self.options = {} self.fileargs = [] self.parse_args(sys.argv[1:]) self.config = configparser.ConfigParser() try: self.config.read('.yelp-tools.cfg') except: self.config = None def parse_args(self, args): while len(args) > 0: argdef = None if args[0].startswith('--'): for arg_ in self.arguments: if args[0] == '--' + arg_[0]: argdef = arg_ break if argdef is None: self.print_usage() return 1 elif args[0].startswith('-'): for arg_ in self.arguments: if args[0] == arg_[1]: argdef = arg_ break if argdef is None: self.print_usage() return 1 if argdef is not None: takesarg = (argdef[2] is not None) if takesarg: if len(args) < 2: self.print_usage() return 1 self.options.setdefault(argdef[0], []) self.options[argdef[0]].append(args[1]) args = args[2:] else: self.options[argdef[0]] = True args = args[1:] else: self.fileargs.append(args[0]) args = args[1:] def get_option_bool(self, arg): if arg in self.options: return self.options[arg] == True if self.config is not None: val = self.config.get('new', arg, fallback=None) if val is not None: return (val == 'true') val = self.config.get('default', arg, fallback=None) if val is not None: return (val == 'true') return False def get_option_str(self, arg): if arg in self.options: if isinstance(self.options[arg], list): return self.options[arg][-1] if self.config is not None: val = self.config.get('new', arg, fallback=None) if val is not None: return val val = self.config.get('default', arg, fallback=None) if val is not None: return val return None def get_replacements(self, pageid): repl = {'ID' : pageid} if len(self.fileargs) > 2: repl['TITLE'] = ' '.join(self.fileargs[2:]) else: repl['TITLE'] = 'TITLE' today = datetime.datetime.now() repl['DATE'] = today.strftime('%Y-%m-%d') repl['YEAR'] = today.strftime('%Y') username = None useremail = None isgit = False isbzr = False cwd = os.getcwd() while cwd: if os.path.exists(os.path.join(cwd, '.git')): isgit = True break if os.path.exists(os.path.join(cwd, '.bzr')): isbzr = True break newcwd = os.path.dirname(cwd) if newcwd == cwd: break cwd = newcwd if isbzr: try: who = subprocess.run(['bzr', 'whoami'], check=True, capture_output=True, encoding='utf8') username, useremail = who.stdout.split('<') username = username.strip() useremail = useremail.split('>')[0].strip() except: username = None useremail = None if username is None: try: who = subprocess.run(['git', 'config', 'user.name'], check=True, capture_output=True, encoding='utf8') username = who.stdout.strip() who = subprocess.run(['git', 'config', 'user.email'], check=True, capture_output=True, encoding='utf8') useremail = who.stdout.strip() except: username = None useremail = None repl['NAME'] = username or 'YOUR NAME' repl['EMAIL'] = useremail or 'YOUR EMAIL ADDRESS' repl['VERSION'] = self.get_option_str('version') or 'VERSION.NUMBER' return repl def main(self): if len(self.fileargs) < 2: self.print_usage() return 1 tmpl = self.fileargs[0] if '.' not in tmpl: tmpl = tmpl + '.page' ext = '.page' elif tmpl.endswith('.page'): ext = '.page' elif tmpl.endswith('.duck'): ext = '.duck' if self.get_option_bool('stub'): ext = ext + '.stub' tmplfile = os.path.join(os.getcwd(), tmpl + '.tmpl') if not os.path.exists(tmplfile): tmplfile = os.path.join(DATADIR, 'templates', tmpl) if not os.path.exists(tmplfile): print('No template found named ' + tmpl, file=sys.stderr) sys.exit(1) pageid = self.fileargs[1] istmpl = self.get_option_bool('tmpl') if istmpl: ext = ext + '.tmpl' repl = {} else: repl = self.get_replacements(pageid) def _writeout(outfile, infilename, depth=0): if depth > 10: # We could do this smarter by keeping a stack of infilenames, but why? print('Recursion limit reached for template includes', file=sys.stderr) sys.exit(1) for line in open(infilename): if (not istmpl) and line.startswith(' [TITLE]\n') print('Create a new file from an installed or local template file,\n' + 'or create a new local template. TEMPLATE must be the name of\n' + 'an installed or local template. ID is a page ID (and base\n' + 'filename) for the new page. The optional TITLE argument\n' 'provides the page title\n') print('Options:') maxarglen = 2 args = [] for arg in self.arguments: argkey = '--' + arg[0] if arg[1] is not None: argkey = arg[1] + ', ' + argkey if arg[2] is not None: argkey = argkey + ' ' + arg[2] args.append((argkey, arg[3])) for arg in args: maxarglen = max(maxarglen, len(arg[0]) + 1) for arg in args: print(' ' + (arg[0]).ljust(maxarglen) + ' ' + arg[1]) localpages = [] localducks = [] installedpages = [] installedducks = [] descs = {} maxlen = 0 def _getdesc(fpath): for line in open(fpath): if line.startswith(''): s = s[:-2] return s if line.startswith('[-] yelp-tmpl-desc'): return line[18:].strip() return '' for fname in os.listdir(os.getcwd()): if fname.endswith('.page.tmpl'): fname = fname[:-5] maxlen = max(maxlen, len(fname)) localpages.append(fname) elif fname.endswith('.duck.tmpl'): fname = fname[:-5] maxlen = max(maxlen, len(fname)) localducks.append(fname) else: continue descs[fname] = _getdesc(os.path.join(os.getcwd(), fname + '.tmpl')) for fname in os.listdir(os.path.join(DATADIR, 'templates')): if fname.endswith('.page'): if fname in localpages: continue maxlen = max(maxlen, len(fname)) installedpages.append(fname) elif fname.endswith('.duck'): if fname in localducks: continue maxlen = max(maxlen, len(fname)) installedducks.append(fname) else: continue descs[fname] = _getdesc(os.path.join(DATADIR, 'templates', fname)) if len(localpages) > 0: print('\nLocal Mallard Templates:') for page in localpages: print(' ' + page.ljust(maxlen) + ' ' + descs.get(page, '')) if len(localducks) > 0: print('\nLocal Ducktype Templates:') for duck in localducks: print(' ' + duck.ljust(maxlen) + ' ' + descs.get(duck, '')) if len(installedpages) > 0: print('\nInstalled Mallard Templates:') for page in installedpages: print(' ' + page.ljust(maxlen) + ' ' + descs.get(page, '')) if len(installedducks) > 0: print('\nInstalled Ducktype Templates:') for duck in installedducks: print(' ' + duck.ljust(maxlen) + ' ' + descs.get(duck, '')) if __name__ == '__main__': try: sys.exit(YelpNew().main()) except KeyboardInterrupt: sys.exit(1)