Skip to content
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pyolite [![Build Status](https://travis-ci.org/PressLabs/pyolite.svg?branch=master)](https://travis-ci.org/PressLabs/pyolite) [![Coverage Status](https://coveralls.io/repos/PressLabs/pyolite/badge.png)](https://coveralls.io/r/PressLabs/pyolite) [![Downloads](https://pypip.in/d/pyolite/badge.png)](https://crate.io/packages/pyolite/)
pyolite [![Build Status](https://travis-ci.org/PressLabs/svg?branch=master)](https://travis-ci.org/PressLabs/pyolite) [![Coverage Status](https://coveralls.io/repos/PressLabs/pyolite/badge.png)](https://coveralls.io/r/PressLabs/pyolite) [![Downloads](https://pypip.in/d/pyolite/badge.png)](https://crate.io/packages/pyolite/)
=======
# Python wrapper for gitolite

Expand Down Expand Up @@ -33,6 +33,7 @@ This is required because Pyolite makes changes to files only inside the **repos*
### Repository API

First, we need to initialize a `pyolite` object with the path to `gitolite`'s repository.

```python
from pyolite import Pyolite

Expand All @@ -42,17 +43,27 @@ olite = Pyolite(admin_repository=admin_repository)
```

After that, we can create and get a repo using `create` and `get` methods.

```python
# create a repo
repo = olite.repos.get('my_repo')
repo = olite.repos.create('ydo')
repo = olite.repos.get_or_create('second_repo')

# List existing Pyolite repos
repos = olite.repos.all()
for repo_it in repos:
print repo_it.name
```

Every repo has an `users` object, in order to facilitate basic operations: adding, editing and removing users from a repository.

```python
print "Repo's users: %s" % repo.users

# list a repo's users
users_as_list = repo.users.list()

user = olite.users.create(name='bob', key_path="~/.ssh/third_rsa.pub")

# add a new user
Expand Down Expand Up @@ -94,6 +105,14 @@ vlad.keys.append('just put the key here')

# check if user is admin or not
print vlad.is_admin

# list user's keys and repos
keys_as_list = vlad.list_keys()
repos_as_list = vlad.list_repos()

# delete a user by name
deleted_user = olite.users.delete('username')
print deleted_user
```

If you need any help with this module, write me `[email protected]`
6 changes: 5 additions & 1 deletion pyolite/managers/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from unipath import Path

from pyolite.git import Git
from git import Git


class Manager(object):
Expand All @@ -26,3 +26,7 @@ def get(self, entity):
@abstractmethod
def create(self, entity):
raise NotImplementedError("Each manager needs a create method")

@abstractmethod
def delete(self, entity_name):
raise NotImplementedError("Each manager needs a delete method")
29 changes: 27 additions & 2 deletions pyolite/managers/repository.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import re
from unipath import Path

from pyolite.models.repository import Repository

from models.repository import Repository
from .manager import Manager


Expand All @@ -26,3 +26,28 @@ def create(self, lookup_repo):
self.git.commit([str(repo_file)], 'Created repo %s' % lookup_repo)

return Repository(lookup_repo, self.path, self.git)

def delete(self, lookup_repo_name):
repo = Repository(lookup_repo_name, self.path, self.git)
dest = Path(self.path, 'conf/repos/%s.conf' % lookup_repo_name)
if not dest.exists():
raise ValueError('Repository %s not existing.' % lookup_repo_name)
dest.remove()
self.git.commit([str(dest)], 'Deleted repo %s.' % lookup_repo_name)

return repo

def all(self):
repos = []
repo_dir = Path(self.path, 'conf/repos')

for obj in repo_dir.walk():
if obj.isdir():
continue

files = re.compile('(\w+.conf$)').findall(str(obj))
if files:
repos += files

return [Repository.get_by_name(repo[:-5], self.path, self.git)
for repo in set(repos)]
15 changes: 12 additions & 3 deletions pyolite/managers/user.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import re

from unipath import Path

from pyolite.models.user import User
from pyolite.managers.manager import Manager
from models.user import User
from managers.manager import Manager


class UserManager(Manager):
Expand All @@ -18,6 +17,16 @@ def create(self, name, key=None, key_path=None):
def get(self, name):
return User.get_by_name(name, self.path, self.git)

def delete(self, name):
user = User(self.path, self.git, name)
dest = Path(self.path, 'keydir/%s' % name)
if not dest.exists():
raise ValueError('Repository %s not existing.' % name)
dest.rmtree()
self.git.commit([str(dest)], 'Deleted user %s.' % name)

return user

def all(self):
users = []
key_dir = Path(self.path, 'keydir')
Expand Down
22 changes: 18 additions & 4 deletions pyolite/models/lists/users.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from unipath import Path
import re

from pyolite.repo import Repo
from pyolite.models.user import User
from repo import Repo
from models.user import User


ACCEPTED_PERMISSIONS = set('RW+CD')
Expand Down Expand Up @@ -48,7 +49,7 @@ def add(self, user, permission):

@with_user
def edit(self, user, permission):
pattern = r'(\s*)([RW+DC]*)(\s*)=(\s*)%s' % user.name
pattern = r'(\s*)([RW+DC]*)(\s*)=(\s*)%s\s+' % user.name
string = r"\n %s = %s" % (permission, user.name)

self.repo.replace(pattern, string)
Expand All @@ -60,13 +61,26 @@ def edit(self, user, permission):

@with_user
def remove(self, user):
pattern = r'(\s*)([RW+DC]*)(\s*)=(\s*)%s' % user.name
pattern = r'(\s*)([RW+DC]*)(\s*)=(\s*)%s\s+' % user.name
self.repo.replace(pattern, "")

self.repository_model.git.commit(['conf'],
"Deleted user %s from repository %s" %
(user.name, self.repository_model.name))

def list(self):
users = []
for user in self.repo.users:
if user=="None":
continue
pattern = r'(\s*)([RW+DC]*)(\s*)=(\s*)%s\s+' % user
with open(str(self.repo.path)) as f:
config = f.read()
for match in re.compile(pattern).finditer(config):
perm = match.group(2)
users.append({"name":user,"permission":perm})
return users

def __iter__(self):
for user in self._user:
yield user
Expand Down
2 changes: 1 addition & 1 deletion pyolite/models/repository.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from unipath import Path

from pyolite.models.lists import ListUsers
from models.lists import ListUsers


class Repository(object):
Expand Down
17 changes: 16 additions & 1 deletion pyolite/models/user.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from unipath import Path

from pyolite.models.lists import ListKeys
from models.lists import ListKeys


class User(object):
Expand Down Expand Up @@ -54,6 +54,21 @@ def is_admin(self):
return True
return False

def list_keys(self):
keys = []
for key in self.keys:
if key.isfile():
with open(str(key)) as f:
cont = f.read()
keys.append({"name":key, "key":cont.replace("\n","")})
return keys

def list_repos(self):
repos = []
for repo in self.repos:
repos.append(repo.name.replace(".conf", ""))
return repos

def __str__(self):
return "< %s >" % self.name

Expand Down
6 changes: 3 additions & 3 deletions tests/lists/test_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from mock import patch, MagicMock, call
from nose.tools import eq_

from pyolite.models.lists import ListKeys
from models.lists import ListKeys


class TestKeyList(TestCase):
Expand All @@ -21,7 +21,7 @@ def test_if_we_commit_after_a_key_append(self):
mock_user.path = "path"
mock_user.name = "test"

with patch.multiple('pyolite.models.lists.keys', Path=mock_path,
with patch.multiple('models.lists.keys', Path=mock_path,
hashlib=mock_hashlib):
keys = ListKeys(mock_user)

Expand Down Expand Up @@ -66,7 +66,7 @@ def test_list_remove(self):
mock_user.path = "path"
mock_user.name = "test"

with patch.multiple('pyolite.models.lists.keys', Path=mock_path,
with patch.multiple('models.lists.keys', Path=mock_path,
hashlib=mock_hashlib):
keys = ListKeys(mock_user)

Expand Down
12 changes: 6 additions & 6 deletions tests/lists/test_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from mock import MagicMock, patch, call
from nose.tools import raises
from pyolite.models.lists.users import ListUsers
from models.lists.users import ListUsers


class TestUserList(Spec):
Expand All @@ -18,7 +18,7 @@ def test_it_should_raise_ValueError_if_user_exists_when_we_add_him(self):
mocked_user.get.return_value = MagicMock(name='another_user')
mocked_repo.users = ['another_user']

with patch.multiple('pyolite.models.lists.users',
with patch.multiple('models.lists.users',
Repo=mocked_repo, User=mocked_user):
repo_users = ListUsers(mocked_repository)
repo_users.add('test', 'hiRW+')
Expand All @@ -35,7 +35,7 @@ def test_if_we_add_invalid_permissions_it_should_raise_ValueError(self):
mocked_user.get.return_value = MagicMock(name='another_user')
mocked_repo.users = ['user']

with patch.multiple('pyolite.models.lists.users',
with patch.multiple('models.lists.users',
Repo=mocked_repo, User=mocked_user):
repo_users = ListUsers(mocked_repository)
repo_users.add('test', 'hiRW+')
Expand All @@ -55,7 +55,7 @@ def test_it_should_add_a_new_user_to_repo_if_is_valid(self):
mocked_user.get.return_value = mock_single_user
mocked_repo.users = ['user']

with patch.multiple('pyolite.models.lists.users',
with patch.multiple('models.lists.users',
Repo=MagicMock(return_value=mocked_repo),
User=mocked_user):
repo_users = ListUsers(mocked_repository)
Expand Down Expand Up @@ -83,7 +83,7 @@ def test_user_removing(self):
mocked_user.get.return_value = mock_single_user
mocked_repo.users = ['user']

with patch.multiple('pyolite.models.lists.users',
with patch.multiple('models.lists.users',
Repo=MagicMock(return_value=mocked_repo),
User=mocked_user):
repo_users = ListUsers(mocked_repository)
Expand All @@ -110,7 +110,7 @@ def test_user_edit_permissions(self):
mocked_user.get.return_value = mock_single_user
mocked_repo.users = ['user']

with patch.multiple('pyolite.models.lists.users',
with patch.multiple('models.lists.users',
Repo=MagicMock(return_value=mocked_repo),
User=mocked_user):
repo_users = ListUsers(mocked_repository)
Expand Down
18 changes: 9 additions & 9 deletions tests/managers/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from nose.tools import raises, eq_
from mock import MagicMock, patch

from pyolite.managers.manager import Manager
from managers.manager import Manager


class TestManager(TestCase):
Expand All @@ -15,10 +15,10 @@ def test_if_admin_repository_is_not_dir_it_should_raise_ValueError(self):

mocked_path.isdir.return_value = False

with patch.multiple('pyolite.managers.manager',
with patch.multiple('managers.manager',
Path=MagicMock(return_value=mocked_path),
Git=MagicMock(return_value=mocked_git)):
with patch.multiple('pyolite.managers.manager.Manager',
with patch.multiple('managers.manager.Manager',
__abstractmethods__=set()):

Manager('/path/to/repo')
Expand All @@ -33,10 +33,10 @@ def test_get_or_create_method(self):
Manager.get = mocked_get
Manager.create = mocked_create

with patch.multiple('pyolite.managers.manager',
with patch.multiple('managers.manager',
Path=MagicMock(return_value=mocked_path),
Git=MagicMock(return_value=mocked_git)):
with patch.multiple('pyolite.managers.manager.Manager',
with patch.multiple('managers.manager.Manager',
__abstractmethods__=set()):

manager = Manager('/path/to/admin/repo')
Expand All @@ -49,10 +49,10 @@ def test_get_abstract_method_method(self):
mocked_path = MagicMock()
mocked_git = MagicMock()

with patch.multiple('pyolite.managers.manager',
with patch.multiple('managers.manager',
Path=MagicMock(return_value=mocked_path),
Git=MagicMock(return_value=mocked_git)):
with patch.multiple('pyolite.managers.manager.Manager',
with patch.multiple('managers.manager.Manager',
__abstractmethods__=set()):

manager = Manager('/path/to/admin/repo')
Expand All @@ -63,10 +63,10 @@ def test_create_abstract_method_method(self):
mocked_path = MagicMock()
mocked_git = MagicMock()

with patch.multiple('pyolite.managers.manager',
with patch.multiple('managers.manager',
Path=MagicMock(return_value=mocked_path),
Git=MagicMock(return_value=mocked_git)):
with patch.multiple('pyolite.managers.manager.Manager',
with patch.multiple('managers.manager.Manager',
__abstractmethods__=set()):

manager = Manager('/path/to/admin/repo')
Expand Down
Loading