summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build_manpage.py131
-rwxr-xr-xportato.py90
-rw-r--r--portato/__init__.py110
-rw-r--r--setup.cfg3
-rw-r--r--setup.py5
5 files changed, 240 insertions, 99 deletions
diff --git a/build_manpage.py b/build_manpage.py
new file mode 100644
index 0000000..8bdbf2f
--- /dev/null
+++ b/build_manpage.py
@@ -0,0 +1,131 @@
+# -*- coding: utf-8 -*-
+
+#
+# This file is copied from http://andialbrecht.wordpress.com/2009/03/17/creating-a-man-page-with-distutils-and-optparse/
+#
+
+"""build_manpage command -- Generate man page from setup()"""
+
+import datetime
+from distutils.command.build import build
+from distutils.core import Command
+from distutils.errors import DistutilsOptionError
+import optparse
+
+class build_manpage(Command):
+
+ description = 'Generate man page from setup().'
+
+ user_options = [
+ ('output=', 'O', 'output file'),
+ ('parser=', None, 'module path to optparser (e.g. mymod:func)'),
+ ]
+
+ def initialize_options(self):
+ self.output = None
+ self.parser = None
+
+ def finalize_options(self):
+ if self.output is None:
+ raise DistutilsOptionError('\'output\' option is required')
+ if self.parser is None:
+ raise DistutilsOptionError('\'parser\' option is required')
+ mod_name, func_name = self.parser.split(':')
+ fromlist = mod_name.split('.')
+ try:
+ mod = __import__(mod_name, fromlist=fromlist)
+ self._parser = getattr(mod, func_name)()
+ except ImportError, err:
+ raise
+ self._parser.formatter = ManPageFormatter()
+ self._parser.formatter.set_parser(self._parser)
+ self.announce('Writing man page %s' % self.output)
+ self._today = datetime.date.today()
+
+ def _markup(self, txt):
+ return txt.replace('-', '\\-')
+
+ def _write_header(self):
+ appname = self.distribution.get_name()
+ ret = []
+ ret.append('.TH %s 1 %s\n' % (self._markup(appname),
+ self._today.strftime('%Y\\-%m\\-%d')))
+ description = self.distribution.get_description()
+ if description:
+ name = self._markup('%s - %s' % (self._markup(appname),
+ description.splitlines()[0]))
+ else:
+ name = self._markup(appname)
+ ret.append('.SH NAME\n%s\n' % name)
+ synopsis = self._parser.get_usage()
+ if synopsis:
+ synopsis = synopsis.replace('%s ' % appname, '')
+ ret.append('.SH SYNOPSIS\n.B %s\n%s\n' % (self._markup(appname),
+ synopsis))
+ long_desc = self.distribution.get_long_description()
+ if long_desc:
+ ret.append('.SH DESCRIPTION\n%s\n' % self._markup(long_desc))
+ return ''.join(ret)
+
+ def _write_options(self):
+ ret = ['.SH OPTIONS\n']
+ ret.append(self._parser.format_option_help())
+ return ''.join(ret)
+
+ def _write_footer(self):
+ ret = []
+ appname = self.distribution.get_name()
+ author = '%s <%s>' % (self.distribution.get_author(),
+ self.distribution.get_author_email())
+ ret.append(('.SH AUTHORS\n.B %s\nwas written by %s.\n'
+ % (self._markup(appname), self._markup(author))))
+ homepage = self.distribution.get_url()
+ ret.append(('.SH DISTRIBUTION\nThe latest version of %s may '
+ 'be downloaded from\n'
+ '.UR %s\n.UE\n'
+ % (self._markup(appname), self._markup(homepage),)))
+ return ''.join(ret)
+
+ def run(self):
+ manpage = []
+ manpage.append(self._write_header())
+ manpage.append(self._write_options())
+ manpage.append(self._write_footer())
+ stream = open(self.output, 'w')
+ stream.write(''.join(manpage))
+ stream.close()
+
+
+class ManPageFormatter(optparse.HelpFormatter):
+
+ def __init__(self,
+ indent_increment=2,
+ max_help_position=24,
+ width=None,
+ short_first=1):
+ optparse.HelpFormatter.__init__(self, indent_increment,
+ max_help_position, width, short_first)
+
+ def _markup(self, txt):
+ return txt.replace('-', '\\-')
+
+ def format_usage(self, usage):
+ return self._markup(usage)
+
+ def format_heading(self, heading):
+ if self.level == 0:
+ return ''
+ return '.TP\n%s\n' % self._markup(heading.upper())
+
+ def format_option(self, option):
+ result = []
+ opts = self.option_strings[option]
+ result.append('.TP\n.B %s\n' % self._markup(opts))
+ if option.help:
+ help_text = '%s\n' % self._markup(self.expand_default(option))
+ result.append(help_text)
+ return ''.join(result)
+
+
+build.sub_commands.append(('build_manpage', None))
+
diff --git a/portato.py b/portato.py
index bdf3ddb..0f0a61b 100755
--- a/portato.py
+++ b/portato.py
@@ -14,93 +14,7 @@
from __future__ import with_statement, absolute_import
-import sys, os
-import subprocess, threading
-import atexit
-from optparse import OptionParser, SUPPRESS_HELP
-
-from portato import get_listener, log, start
-from portato.su import detect_su_command
-from portato.helper import debug, info, error
-from portato.constants import VERSION
-
-def main ():
- start() # the first thing to do :)
-
- # build the parser
- desc = "Portato - A Portage GUI."
- usage = "%prog [options] [frontend]"
- vers = "%%prog v. %s" % VERSION
-
- parser = OptionParser(version = vers, prog = "Portato", description = desc, usage = usage)
-
- parser.add_option("--shm", action = "store", nargs = 3, type="long", dest = "shm",
- help = SUPPRESS_HELP)
-
- parser.add_option("-F", "--no-fork", "-L", action = "store_true", dest = "nofork", default = False,
- help = _("do not fork off as root") + (" (%s)" % _("-L is deprecated")))
-
- # run parser
- (options, args) = parser.parse_args()
-
- # close listener at exit
- atexit.register(get_listener().close)
-
- if options.nofork or os.getuid() == 0: # start GUI
- log.start(file = True) # start logging to file
-
- from portato.gui import run
- info("%s v. %s", _("Starting Portato"), VERSION)
-
- if options.shm:
- get_listener().set_send(*options.shm)
- else:
- get_listener().set_send()
-
- try:
- run()
- except KeyboardInterrupt:
- debug("Got KeyboardInterrupt.")
-
- else: # start us again in root modus and launch listener
-
- import shm_wrapper as shm
-
- mem = shm.create_memory(1024, permissions=0600)
- sig = shm.create_semaphore(InitialValue = 0, permissions = 0600)
- rw = shm.create_semaphore(InitialValue = 1, permissions = 0600)
-
- # start listener
- lt = threading.Thread(target=get_listener().set_recv, args = (mem, sig, rw))
- lt.setDaemon(False)
- lt.start()
-
- try:
- # set DBUS_SESSION_BUS_ADDRESS to "" to make dbus work as root ;)
- env = os.environ.copy()
- env.update(DBUS_SESSION_BUS_ADDRESS="")
-
- su = detect_su_command()
- if su:
- debug("Using '%s' as su command.", su.bin)
- cmd = su.cmd("%s --no-fork --shm %ld %ld %ld" % (sys.argv[0], mem.key, sig.key, rw.key))
-
- sp = subprocess.Popen(cmd, env = env)
-
- # wait for process to finish
- try:
- sp.wait()
- debug("Subprocess finished")
- except KeyboardInterrupt:
- debug("Got KeyboardInterrupt.")
-
- else:
- error(_("No valid su command detected. Aborting."))
-
- finally:
- if lt.isAlive():
- debug("Listener is still running. Close it.")
- get_listener().close()
+from portato import start
if __name__ == "__main__":
- main()
+ start()
diff --git a/portato/__init__.py b/portato/__init__.py
index f5d7f65..e54354a 100644
--- a/portato/__init__.py
+++ b/portato/__init__.py
@@ -12,17 +12,16 @@
from __future__ import absolute_import
-def start():
- from . import log
- import gettext, locale
- from portato.constants import LOCALE_DIR, APP
-
- # set gettext stuff
- locale.setlocale(locale.LC_ALL, '')
- gettext.install(APP, LOCALE_DIR, unicode = True)
+import gettext, locale
+import sys, os
+import subprocess, threading
+import atexit
+from optparse import OptionParser, SUPPRESS_HELP
- # start logging
- log.start(file=False)
+from . import log
+from .constants import LOCALE_DIR, APP, VERSION
+from .su import detect_su_command
+from .helper import debug, info, error
# listener-handling
__listener = None
@@ -34,3 +33,94 @@ def get_listener():
__listener = Listener()
return __listener
+
+def get_parser (use_ = False):
+ # use_ defaults to False, if it is called from outside
+ # where gettext is not yet initialized
+
+ if not use_: _ = lambda s : s
+
+ desc = "Portato - A Portage GUI."
+ usage = "%prog [options] [frontend]"
+ vers = "%%prog v. %s" % VERSION
+
+ parser = OptionParser(version = vers, prog = "Portato", description = desc, usage = usage)
+
+ parser.add_option("--shm", action = "store", nargs = 3, type="long", dest = "shm",
+ help = SUPPRESS_HELP)
+
+ parser.add_option("-F", "--no-fork", "-L", action = "store_true", dest = "nofork", default = False,
+ help = _("do not fork off as root") + (" (%s)" % _("-L is deprecated")))
+
+ return parser
+
+def start():
+
+ # set gettext stuff
+ locale.setlocale(locale.LC_ALL, '')
+ gettext.install(APP, LOCALE_DIR, unicode = True)
+
+ # start logging
+ log.start(file=False)
+
+ # run parser
+ (options, args) = get_parser().parse_args()
+
+ # close listener at exit
+ atexit.register(get_listener().close)
+
+ if options.nofork or os.getuid() == 0: # start GUI
+ log.start(file = True) # start logging to file
+
+ from .gui import run
+ info("%s v. %s", _("Starting Portato"), VERSION)
+
+ if options.shm:
+ get_listener().set_send(*options.shm)
+ else:
+ get_listener().set_send()
+
+ try:
+ run()
+ except KeyboardInterrupt:
+ debug("Got KeyboardInterrupt.")
+
+ else: # start us again in root modus and launch listener
+
+ import shm_wrapper as shm
+
+ mem = shm.create_memory(1024, permissions=0600)
+ sig = shm.create_semaphore(InitialValue = 0, permissions = 0600)
+ rw = shm.create_semaphore(InitialValue = 1, permissions = 0600)
+
+ # start listener
+ lt = threading.Thread(target=get_listener().set_recv, args = (mem, sig, rw))
+ lt.setDaemon(False)
+ lt.start()
+
+ try:
+ # set DBUS_SESSION_BUS_ADDRESS to "" to make dbus work as root ;)
+ env = os.environ.copy()
+ env.update(DBUS_SESSION_BUS_ADDRESS="")
+
+ su = detect_su_command()
+ if su:
+ debug("Using '%s' as su command.", su.bin)
+ cmd = su.cmd("%s --no-fork --shm %ld %ld %ld" % (sys.argv[0], mem.key, sig.key, rw.key))
+
+ sp = subprocess.Popen(cmd, env = env)
+
+ # wait for process to finish
+ try:
+ sp.wait()
+ debug("Subprocess finished")
+ except KeyboardInterrupt:
+ debug("Got KeyboardInterrupt.")
+
+ else:
+ error(_("No valid su command detected. Aborting."))
+
+ finally:
+ if lt.isAlive():
+ debug("Listener is still running. Close it.")
+ get_listener().close()
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..739ffe6
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,3 @@
+[build_manpage]
+output=doc/portato.1
+parser=portato:get_parser
diff --git a/setup.py b/setup.py
index 58956b6..366298a 100644
--- a/setup.py
+++ b/setup.py
@@ -15,6 +15,8 @@ import sys, os, os.path
from distutils.core import setup
from portato.constants import VERSION, DATA_DIR, ICON_DIR, PLUGIN_DIR, TEMPLATE_DIR
+from build_manpage import build_manpage
+
def plugin_list (*args):
"""Creates a list of correct plugin pathes out of the arguments."""
return [("plugins/%s.py" % x) for x in args]
@@ -34,5 +36,6 @@ setup(name="Portato",
author = "René 'Necoro' Neumann",
author_email = "necoro@necoro.net",
packages = packages,
- data_files = data_files
+ data_files = data_files,
+ cmdclass={'build_manpage': build_manpage}
)