From 7e610eb8d5d2fd8dfc28778ce1516a7b1bff6dc3 Mon Sep 17 00:00:00 2001 From: Shaun McCance Date: Sat, 16 Jan 2021 12:20:41 -0500 Subject: yelp-new.py: Converted yelp-new to python --- templates/py/templates/concept.duck | 15 ++ templates/py/templates/concept.page | 18 ++ templates/py/templates/guide.duck | 17 ++ templates/py/templates/guide.page | 21 ++ templates/py/templates/info.ducktype.include | 33 +++ templates/py/templates/info.mallard.include | 35 +++ templates/py/templates/reference.duck | 58 +++++ templates/py/templates/reference.page | 65 ++++++ templates/py/templates/task.duck | 29 +++ templates/py/templates/task.page | 35 +++ tools/yelp-check.py | 10 + tools/yelp-new.py | 317 +++++++++++++++++++++++++++ 12 files changed, 653 insertions(+) create mode 100644 templates/py/templates/concept.duck create mode 100644 templates/py/templates/concept.page create mode 100644 templates/py/templates/guide.duck create mode 100644 templates/py/templates/guide.page create mode 100644 templates/py/templates/info.ducktype.include create mode 100644 templates/py/templates/info.mallard.include create mode 100644 templates/py/templates/reference.duck create mode 100644 templates/py/templates/reference.page create mode 100644 templates/py/templates/task.duck create mode 100644 templates/py/templates/task.page create mode 100644 tools/yelp-new.py diff --git a/templates/py/templates/concept.duck b/templates/py/templates/concept.duck new file mode 100644 index 0000000..0e6dff4 --- /dev/null +++ b/templates/py/templates/concept.duck @@ -0,0 +1,15 @@ +@ducktype/1.0 +[-] yelp-tmpl-desc Explanation of a concept or background information + += {{TITLE}} + [topic .concept version=1.1] + +{{INCLUDE info.ducktype.include}} + + +Provide as many paragraphs, lists, or media as necessary to explain. + +[list] +. Next steps +* Optionally, links to other things the user might do now. +* But consider using seealso and other info links instead. diff --git a/templates/py/templates/concept.page b/templates/py/templates/concept.page new file mode 100644 index 0000000..16f56e4 --- /dev/null +++ b/templates/py/templates/concept.page @@ -0,0 +1,18 @@ + + + +{{INCLUDE info.mallard.include}} + + + {{TITLE}} + +

Provide as many paragraphs, lists, or media as necessary to explain.

+ + + Next steps +

Optionally, links to other things the user might do now.

+

But consider using seealso and other info links instead.

+
+
diff --git a/templates/py/templates/guide.duck b/templates/py/templates/guide.duck new file mode 100644 index 0000000..a7d13ea --- /dev/null +++ b/templates/py/templates/guide.duck @@ -0,0 +1,17 @@ +@ducktype/1.0 +[-] yelp-tmpl-desc Navigational glue for Mallard documents + += {{TITLE}} + [guide version=1.1] + +{{INCLUDE info.ducktype.include}} + + +Optionally, an introductory paragraph. + +[-- + The links element is implicit, but you might want to add one + explicitly if you want to do link grouping or styles. +[links topic .STYLE groups="GROUPS"] + . Optional title +--] diff --git a/templates/py/templates/guide.page b/templates/py/templates/guide.page new file mode 100644 index 0000000..90b8a7d --- /dev/null +++ b/templates/py/templates/guide.page @@ -0,0 +1,21 @@ + + + +{{INCLUDE info.mallard.include}} + + + {{TITLE}} + +

Optionally, an introductory paragraph.

+ + + +
diff --git a/templates/py/templates/info.ducktype.include b/templates/py/templates/info.ducktype.include new file mode 100644 index 0000000..fdc6de1 --- /dev/null +++ b/templates/py/templates/info.ducktype.include @@ -0,0 +1,33 @@ +[-- + Recommended statuses: stub incomplete draft outdated review candidate final + Remove version attributes you don't use. +--] +@revision[version={{VERSION}} date={{DATE}} status=stub] + +@credit[author copyright] + @name {{NAME}} + @email {{EMAIL}} + @years {{YEAR}} + +[-- + This puts a link to this topic on the index page. + Change the xref to link it from another guide. +--] +@link[guide >index] + +[-- + Think about whether other pages should be in the seealso list. + The target page will automatically get a seealso link back. +@link[seealso >someotherid] +--] + +[-- + Think about whether external resources should be in the seealso + list. These require a title. +@link[seealso >>http://someurl] + @title Link title +--] + +@desc Write a short page description here. + +@keywords comma-separated list, of keywords, for search diff --git a/templates/py/templates/info.mallard.include b/templates/py/templates/info.mallard.include new file mode 100644 index 0000000..d3209d7 --- /dev/null +++ b/templates/py/templates/info.mallard.include @@ -0,0 +1,35 @@ + + + + + {{NAME}} + {{EMAIL}} + {{YEAR}} + + + + + + + + + + Write a short page description here. + + comma-separated list, of keywords, for search diff --git a/templates/py/templates/reference.duck b/templates/py/templates/reference.duck new file mode 100644 index 0000000..2d1a770 --- /dev/null +++ b/templates/py/templates/reference.duck @@ -0,0 +1,58 @@ +@ducktype/1.0 +[-] yelp-tmpl-desc Lists or tables of information for quick lookup + += {{TITLE}} + [topic .reference version=1.1] + +{{INCLUDE info.ducktype.include}} + + +Optionally provide introductory text. +Use terms lists, tables, and bullet lists for reference material. + + +[terms] +. Example terms list (title optional) + +- Term 1 +* Description + +- Term 2 +* Terms can have multiple paragraphs. + + [screen] + Or any other block element. + +- Term 3.1 +- Term 3.2 +* Terms can also have multiple titles. + + +[table] +. Example table (title optional) + +[thead] +[tr] +- Column 1 +- Column 2 + +[tbody] +[tr] +* Row 1, column 1 +* Row 1, column 2 + +[tr] +* Row 2, column 1 +* Row 2, column 2 + + +[list] +. Example list (title optional) + +* Item 1 + +* Item 2 + * Subitem 2.1 + * Subitem 2.2 + +* Item 3 diff --git a/templates/py/templates/reference.page b/templates/py/templates/reference.page new file mode 100644 index 0000000..3551452 --- /dev/null +++ b/templates/py/templates/reference.page @@ -0,0 +1,65 @@ + + + +{{INCLUDE info.mallard.include}} + + + {{TITLE}} + +

Optionally provide introductory text. + Use terms lists, tables, and bullet lists for reference material.

+ + + Example terms list (title optional) + + Term 1 + Description + + + Term 2 +

Terms can have multiple paragraphs.

+ Or any other block element. +
+ + Term 3.1 + Term 3.2 +

Terms can also have multiple titles.

+
+
+ + + Example table (title optional) + + + + + + + + + + + + + + + + +
Column 1Column 2
Row 1, column 1Row 1, column 2
Row 2, column 1Row 2, column 2
+ + + Example list (title optional) +

Item 1

+ +

Item 2

+ +

Subitem 2.1

+

Subitem 2.2

+
+
+

Item 3

+
+ +
diff --git a/templates/py/templates/task.duck b/templates/py/templates/task.duck new file mode 100644 index 0000000..aab510c --- /dev/null +++ b/templates/py/templates/task.duck @@ -0,0 +1,29 @@ +@ducktype/1.0 +[-] yelp-tmpl-desc Description of how to accomplish a user task + += {{TITLE}} + [topic .task version=1.1] + +{{INCLUDE info.ducktype.include}} + + +Short introductory text: Write a couple sentences about what the +user is doing here, and why they might want to do it. + +[list] +. Prerequisites +* Optionally, list things the user needs to know or do first. +* Use links to other pages whenever they make sense. + +[steps] +. Optional title if different from page title or if prereqs present +* First step... +* Second step... +* Third step... + +Optionally, write expected results if non-obvious. + +[list] +. Next steps +* Optionally, links to other things the user might do now. +* But consider using seealso and other info links instead. diff --git a/templates/py/templates/task.page b/templates/py/templates/task.page new file mode 100644 index 0000000..ba6da8b --- /dev/null +++ b/templates/py/templates/task.page @@ -0,0 +1,35 @@ + + + +{{INCLUDE info.mallard.include}} + + + {{TITLE}} + +

Short introductory text: Write a couple sentences about what the + user is doing here, and why they might want to do it.

+ + + Prerequisites +

Optionally, list things the user needs to know or do first.

+

Use links to other pages whenever they make sense.

+
+ + + Optional title if different from page title or if prereqs present +

First step...

+

Second step...

+

Third step...

+
+ +

Optionally, write expected results if non-obvious.

+ + + Next steps +

Optionally, links to other things the user might do now.

+

But consider using seealso and other info links instead.

+
+ +
diff --git a/tools/yelp-check.py b/tools/yelp-check.py index 652062e..a3eb486 100644 --- a/tools/yelp-check.py +++ b/tools/yelp-check.py @@ -152,6 +152,9 @@ class Checker: val = self.config.get('check', 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): @@ -165,6 +168,9 @@ class Checker: val = self.config.get('check', 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_option_list(self, arg): @@ -181,6 +187,9 @@ class Checker: val = self.config.get('check', arg, fallback=None) if val is not None: return val.replace(',', ' ').split() + val = self.config.get('default', arg, fallback=None) + if val is not None: + return val.replace(',', ' ').split() return None def iter_files(self, sitedir=None): @@ -208,6 +217,7 @@ class Checker: for fname in os.listdir(filepath): newpath = os.path.join(filepath, fname) if os.path.isdir(newpath): + # FIXME https://github.com/projectmallard/pintail/issues/36 if fname == '__pintail__': continue for infile in self.iter_site(newpath, sitedir + fname + '/'): diff --git a/tools/yelp-new.py b/tools/yelp-new.py new file mode 100644 index 0000000..5b8f6f0 --- /dev/null +++ b/tools/yelp-new.py @@ -0,0 +1,317 @@ +#!/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) -- cgit v1.2.1