#!/usr/bin/env python # -*- coding: utf-8 -*- """Generate man pages for the q applets""" from __future__ import print_function import datetime import functools import glob import locale import os import re import subprocess import sys import yaml MKMAN_DIR = os.path.realpath(os.path.join(__file__, '..')) FRAGS_DIR = os.path.join(MKMAN_DIR, 'include') TOPDIR = os.path.join(MKMAN_DIR, '..') Q = os.path.join(TOPDIR, 'q') def FindApplets(): """Return a list of all supported applets""" applets = os.path.join(TOPDIR, 'applets.sh') return subprocess.check_output([applets]).decode('ascii').splitlines() COMMON_AUTHORS = [ 'Ned Ludd ', 'Mike Frysinger ', 'Fabian Groffen ', ] TEMPLATE = r""".\" generated by mkman.py, please do NOT edit! .TH %(applet)s "1" "%(date)s" "Gentoo Foundation" "%(applet)s" .SH NAME %(applet)s \- %(short_desc)s .SH SYNOPSIS .B %(applet)s \fI%(usage)s\fR .SH DESCRIPTION %(description)s .SH OPTIONS %(options)s %(extra_sections)s .SH "REPORTING BUGS" Please report bugs via http://bugs.gentoo.org/ .br Product: Gentoo Linux; Component: Current packages .SH AUTHORS .nf %(authors)s .fi .SH "SEE ALSO" %(see_also)s """ def MkMan(applets, applet, output): """Generate a man page for |applet| and write it to |output|""" print('%-10s: generating %s' % (applet, output)) # Extract the main use string and description: # Usage: q : invoke a portage utility applet try: ahelp = subprocess.check_output([Q, applet, '--help']).decode('ascii') except: return lines = ahelp.splitlines() m = re.search(r'^usage: %s (.*) : (.*)' % applet, ahelp) usage = m.group(1) short_desc = m.group(2) authors = COMMON_AUTHORS[:] see_also = sorted(['.BR %s (1)' % x for x in applets if x != applet]) description = '' desc_file = os.path.join(FRAGS_DIR, '%s.desc' % applet) if os.path.exists(desc_file): fh = open(desc_file) description = fh.read().rstrip() fh.close() optdescs = [] desc_file = os.path.join(FRAGS_DIR, '%s.optdesc.yaml' % applet) if os.path.exists(desc_file): with open(desc_file) as fh: optdescs = yaml.safe_load(fh) # Extract all the options options = [] for line, i in zip(lines, range(len(lines))): if not line.startswith('options: '): continue for option in [x.strip().split() for x in lines[i + 1:]]: flags = [option[0].rstrip(',')] option.pop(0) if option[0][0] == '-': flags += [option[0].rstrip(',')] option.pop(0) optdesc = None for x in flags: if x.lstrip('-') in optdescs: optdesc = optdescs[x.lstrip('-')].strip() if option[0] in ('', '[arg]'): flags = [r'\fB%s\fR \fI%s\fR' % (x, option[0]) for x in flags] option.pop(0) else: flags = [r'\fB%s\fR' % x for x in flags] assert option[0] == '*', 'help line for %s is broken: %r' % (applet, option) option.pop(0) if not optdesc: optdesc = ' '.join(option).rstrip('.') + '.' options += [ '.TP', ', '.join(flags).replace('-', r'\-'), optdesc, ] break # Handle applets that have applets extra_sections = [] if 'currently defined applets:' in ahelp: alines = lines[lines.index('currently defined applets:') + 1:] alines = alines[:alines.index('')] extra_sections += ( ['.SH APPLETS', '.nf', '.B This applet also has sub applets:'] + alines + ['.fi'] ) # Handle any fragments this applet has available for frag in sorted(glob.glob(os.path.join(FRAGS_DIR, '%s-*.include' % applet))): with open(frag) as f: if frag.endswith('-authors.include'): authors += [x.rstrip() for x in f.readlines()] else: extra_sections += [x.rstrip() for x in f.readlines()] data = { 'applet': applet, 'date': datetime.datetime.now().strftime('%b %Y'), 'short_desc': short_desc, 'usage': usage, 'description': description, 'options': '\n'.join(options), 'extra_sections': '\n'.join(extra_sections), 'authors': '\n'.join(authors), 'see_also': ',\n'.join(see_also), 'rcsid': '', } with open(output, 'w') as f: f.write(TEMPLATE % data) def main(argv): os.environ['NOCOLOR'] = '1' if not argv: argv = FindApplets() # Support file completion like "qfile.1" or "./qdepends.1" applets = [os.path.basename(x).split('.', 1)[0] for x in argv] for applet in applets: output = os.path.join(MKMAN_DIR, '%s.1' % applet) MkMan(applets, applet, output) if __name__ == '__main__': sys.exit(main(sys.argv[1:]))