From 418c5c3cfc5812f2ea1dfc5219c43ab549878062 Mon Sep 17 00:00:00 2001 From: Tommi Virtanen Date: Mon, 4 Jun 2007 22:12:29 +0300 Subject: [PATCH] Add ``gitosis-gitweb``, for writing gitweb project lists. Takes the list of repositories to publish from the gitosis config file. --- TODO.rst | 5 ++ example.conf | 6 +- gitosis/gitweb.py | 115 ++++++++++++++++++++++++++++++++++++ gitosis/test/test_gitweb.py | 97 ++++++++++++++++++++++++++++++ setup.py | 1 + 5 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 gitosis/gitweb.py create mode 100644 gitosis/test/test_gitweb.py diff --git a/TODO.rst b/TODO.rst index 3930931..b80fa14 100644 --- a/TODO.rst +++ b/TODO.rst @@ -3,3 +3,8 @@ =========== - guard against *.pub files named -foo.pub or foo;bar.pub + +- gitweb doesn't understand mappings, just visible/no, + physical and logical path are always the same + + - maybe remove the whole mapping feature for good? diff --git a/example.conf b/example.conf index 935dccc..b6654ef 100644 --- a/example.conf +++ b/example.conf @@ -1,5 +1,7 @@ [gitosis] repositories = repo +gitweb = no +# daemon-ok = no [group quux] members = jdoe wsmith @anothergroup @@ -8,8 +10,10 @@ readonly = xyzzy map writable visiblename1 = actualname1 map readonly visiblename2 = actualname2 -# [repo foo] +[repo foo] # description = blah blah +gitweb = yes +owner = John Doe # daemon-ok = no # [gitweb] diff --git a/gitosis/gitweb.py b/gitosis/gitweb.py new file mode 100644 index 0000000..2ae682e --- /dev/null +++ b/gitosis/gitweb.py @@ -0,0 +1,115 @@ +""" +Generate ``gitweb`` project list based on ``gitosis.conf``. + +To plug this into ``gitweb``, you have two choices. + +- The global way, edit ``/etc/gitweb.conf`` to say:: + + $projects_list = "/path/to/your/projects.list"; + + Note that there can be only one such use of gitweb. + +- The local way, create a new config file:: + + do "/etc/gitweb.conf" if -e "/etc/gitweb.conf"; + $projects_list = "/path/to/your/projects.list"; + # see ``repositories`` in the ``gitosis`` section + # of ``~/.gitosis.conf``; usually ``~/repos`` + # but you need to expand the tilde here + $projectroot = "/path/to/your/repos"; + + Then in your web server, set environment variable ``GITWEB_CONFIG`` + to point to this file. + + This way allows you have multiple separate uses of ``gitweb``, and + isolates the changes a bit more nicely. Recommended. +""" + +import os, urllib + +from ConfigParser import RawConfigParser, NoSectionError, NoOptionError + +def _escape_filename(s): + s = s.replace('\\', '\\\\') + s = s.replace('$', '\\$') + s = s.replace('"', '\\"') + return s + +def generate(config, fp): + """ + Generate a config file and projects list for ``gitweb``. + + :param config: configuration to read projects from + :type config: RawConfigParser + + :param fp: writable for ``projects.list`` + :type fp: (file-like, anything with ``.write(data)``) + """ + try: + global_enable = config.getboolean('gitosis', 'gitweb') + except (NoSectionError, NoOptionError): + global_enable = False + + for section in config.sections(): + l = section.split(None, 1) + type_ = l.pop(0) + if type_ != 'repo': + continue + if not l: + continue + + try: + enable = config.getboolean(section, 'gitweb') + except (NoSectionError, NoOptionError): + enable = global_enable + + if not enable: + continue + + name, = l + response = [name] + try: + owner = config.get(section, 'owner') + except (NoSectionError, NoOptionError): + pass + else: + response.append(owner) + + line = ' '.join([urllib.quote_plus(s) for s in response]) + print >>fp, line + +def _getParser(): + import optparse + parser = optparse.OptionParser( + usage="%prog [--config=FILE] PROJECTSLIST") + parser.set_defaults( + config=os.path.expanduser('~/.gitosis.conf'), + ) + parser.add_option('--config', + metavar='FILE', + help='read config from FILE (default %s)' + % parser.defaults['config'], + ) + return parser + +def main(): + parser = _getParser() + (options, args) = parser.parse_args() + + if len(args) != 1: + parser.error('Expected one command line argument.') + + path, = args + + cfg = RawConfigParser() + cfg.read(options.config) + + tmp = '%s.%d.tmp' % (path, os.getpid()) + + f = file(tmp, 'w') + try: + generate(config=cfg, fp=f) + finally: + f.close() + + os.rename(tmp, path) diff --git a/gitosis/test/test_gitweb.py b/gitosis/test/test_gitweb.py new file mode 100644 index 0000000..4308371 --- /dev/null +++ b/gitosis/test/test_gitweb.py @@ -0,0 +1,97 @@ +from nose.tools import eq_ as eq + +from ConfigParser import RawConfigParser +from cStringIO import StringIO + +from gitosis import gitweb + +def test_empty(): + cfg = RawConfigParser() + got = StringIO() + gitweb.generate( + config=cfg, + fp=got) + eq(got.getvalue(), '''\ +''') + +def test_trickyFilenames(): + cfg = RawConfigParser() + got = StringIO() + gitweb.generate( + config=cfg, + fp=got) + eq(got.getvalue(), '''\ +''') + +def test_projectsList_repoDenied(): + cfg = RawConfigParser() + cfg.add_section('repo foo/bar') + got = StringIO() + gitweb.generate( + config=cfg, + fp=got) + eq(got.getvalue(), '''\ +''') + +def test_projectsList_noOwner(): + cfg = RawConfigParser() + cfg.add_section('repo foo/bar') + cfg.set('repo foo/bar', 'gitweb', 'yes') + got = StringIO() + gitweb.generate( + config=cfg, + fp=got) + eq(got.getvalue(), '''\ +foo%2Fbar +''') + +def test_projectsList_haveOwner(): + cfg = RawConfigParser() + cfg.add_section('repo foo/bar') + cfg.set('repo foo/bar', 'gitweb', 'yes') + cfg.set('repo foo/bar', 'owner', 'John Doe') + got = StringIO() + gitweb.generate( + config=cfg, + fp=got) + eq(got.getvalue(), '''\ +foo%2Fbar John+Doe +''') + +def test_projectsList_multiple(): + cfg = RawConfigParser() + cfg.add_section('gitosis') + cfg.add_section('repo foo/bar') + cfg.set('repo foo/bar', 'owner', 'John Doe') + cfg.set('repo foo/bar', 'gitweb', 'yes') + cfg.add_section('repo quux') + cfg.set('repo quux', 'gitweb', 'yes') + got = StringIO() + gitweb.generate( + config=cfg, + fp=got) + eq(got.getvalue(), '''\ +quux +foo%2Fbar John+Doe +''') + +def test_projectsList_multiple_globalGitwebYes(): + cfg = RawConfigParser() + cfg.add_section('gitosis') + cfg.set('gitosis', 'gitweb', 'yes') + cfg.add_section('repo foo/bar') + cfg.set('repo foo/bar', 'owner', 'John Doe') + cfg.add_section('repo quux') + # same as default, no effect + cfg.set('repo quux', 'gitweb', 'yes') + cfg.add_section('repo thud') + # this is still hidden + cfg.set('repo thud', 'gitweb', 'no') + got = StringIO() + gitweb.generate( + config=cfg, + fp=got) + eq(got.getvalue(), '''\ +quux +foo%2Fbar John+Doe +''') diff --git a/setup.py b/setup.py index 35def49..8a82e47 100755 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ setup( 'console_scripts': [ 'gitosis-ssh = gitosis.ssh:main', 'gitosis-serve = gitosis.serve:main', + 'gitosis-gitweb = gitosis.gitweb:main', ], }, )