Add `gitosis-gitweb
`, for writing gitweb project lists.
Takes the list of repositories to publish from the gitosis config file.
This commit is contained in:
parent
67940f4b28
commit
418c5c3cfc
5 changed files with 223 additions and 1 deletions
5
TODO.rst
5
TODO.rst
|
@ -3,3 +3,8 @@
|
||||||
===========
|
===========
|
||||||
|
|
||||||
- guard against *.pub files named -foo.pub or foo;bar.pub
|
- 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?
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
[gitosis]
|
[gitosis]
|
||||||
repositories = repo
|
repositories = repo
|
||||||
|
gitweb = no
|
||||||
|
# daemon-ok = no
|
||||||
|
|
||||||
[group quux]
|
[group quux]
|
||||||
members = jdoe wsmith @anothergroup
|
members = jdoe wsmith @anothergroup
|
||||||
|
@ -8,8 +10,10 @@ readonly = xyzzy
|
||||||
map writable visiblename1 = actualname1
|
map writable visiblename1 = actualname1
|
||||||
map readonly visiblename2 = actualname2
|
map readonly visiblename2 = actualname2
|
||||||
|
|
||||||
# [repo foo]
|
[repo foo]
|
||||||
# description = blah blah
|
# description = blah blah
|
||||||
|
gitweb = yes
|
||||||
|
owner = John Doe
|
||||||
# daemon-ok = no
|
# daemon-ok = no
|
||||||
|
|
||||||
# [gitweb]
|
# [gitweb]
|
||||||
|
|
115
gitosis/gitweb.py
Normal file
115
gitosis/gitweb.py
Normal file
|
@ -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)
|
97
gitosis/test/test_gitweb.py
Normal file
97
gitosis/test/test_gitweb.py
Normal file
|
@ -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
|
||||||
|
''')
|
1
setup.py
1
setup.py
|
@ -16,6 +16,7 @@ setup(
|
||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
'gitosis-ssh = gitosis.ssh:main',
|
'gitosis-ssh = gitosis.ssh:main',
|
||||||
'gitosis-serve = gitosis.serve:main',
|
'gitosis-serve = gitosis.serve:main',
|
||||||
|
'gitosis-gitweb = gitosis.gitweb:main',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue