Skip to content

Commit 33c287f

Browse files
committed
Add auto_klaus.py to autodetect repositories with low complexity
1 parent 3d090ec commit 33c287f

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

klaus/contrib/auto_klaus.py

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"""
2+
Alternative take on the "automatically discovered repositories" concept
3+
that requires no threads, polling or inotify. Instead the filesystem is
4+
consulted whenever a repository name is looked up.
5+
6+
Since os.path.exists() and os.listdir() are fairly quick filesystem
7+
operations, performance should be good for small to medium sites.
8+
FancyRepo() objects are cached.
9+
10+
Repositories are identified by the existence of a
11+
12+
<reponame>/git-daemon-export-ok
13+
14+
file (for compatibility with gitweb).
15+
16+
Example usage:
17+
18+
from klaus.contrib.auto_klaus import Klaus, SlashDynamicRepos
19+
20+
application = Klaus('/srv/git', "My git repositories", False)
21+
22+
application.wsgi_app = httpauth.AlwaysFailingAuthMiddleware(
23+
wsgi_app=dulwich.web.make_wsgi_chain(
24+
backend=dulwich.server.DictBackend(SlashDynamicRepos(application.valid_repos)),
25+
fallback_app=application.wsgi_app,
26+
),
27+
)
28+
"""
29+
30+
import collections.abc
31+
import pathlib
32+
import os
33+
import os.path
34+
35+
import klaus
36+
import klaus.repo
37+
38+
class FilesystemRepoDict(collections.abc.Mapping):
39+
"""
40+
Maintain a virtual read-only dictionary whose contents represent
41+
the presence of git repositories in the given root directory.
42+
"""
43+
44+
def __init__(self, root):
45+
self._root = pathlib.Path(root)
46+
self._repos = {}
47+
48+
def __getitem__(self, name):
49+
if not name or name[0] == '.' or '/' in name or '\0' in name:
50+
raise KeyError(name)
51+
52+
repos = self._repos
53+
path = self._root / name
54+
if not os.path.exists(path / 'git-daemon-export-ok'):
55+
repos.pop(name, None)
56+
raise KeyError(name)
57+
58+
try:
59+
return repos[name]
60+
except KeyError:
61+
pass
62+
63+
repo = klaus.repo.FancyRepo(str(path))
64+
repos[name] = repo
65+
return repo
66+
67+
def __iter__(self):
68+
root = self._root
69+
return (
70+
repo for repo in os.listdir(root)
71+
if os.path.exists(root / repo / 'git-daemon-export-ok')
72+
)
73+
74+
def __len__(self):
75+
return sum(1 for _ in self)
76+
77+
class SlashFilesystemRepoDict(collections.abc.Mapping):
78+
"""
79+
Proxy for FilesystemRepoDict that makes it so that keys start with a '/'
80+
character. Needed for dulwich.server.DictBackend.
81+
"""
82+
83+
def __init__(self, base):
84+
self._base = base
85+
86+
def __getitem__(self, path):
87+
if not path or path[0] != '/':
88+
raise KeyError(path)
89+
return self._base[path[1:]]
90+
91+
def __iter__(self):
92+
return ('/' + name for name in self._base)
93+
94+
def __len__(self):
95+
return len(self._base)
96+
97+
class Klaus(klaus.Klaus):
98+
def __init__(self, root, *args):
99+
super().__init__([], *args)
100+
self.valid_repos = FilesystemRepoDict(root)
101+
102+
def load_repos(self, repo_paths):
103+
return [], []

0 commit comments

Comments
 (0)