diff --git a/getmystuph/backends/c4science/repo.py b/getmystuph/backends/c4science/repo.py index 79dcbc5..2e831f4 100644 --- a/getmystuph/backends/c4science/repo.py +++ b/getmystuph/backends/c4science/repo.py @@ -1,32 +1,32 @@ import copy import logging from ... import export from ..repos.phabricator import PhabRepo __author__ = "Nicolas Richart" __copyright__ = "Copyright (C) 2016, EPFL (Ecole Polytechnique Fédérale " \ "de Lausanne) - SCITAS (Scientific IT and Application " \ "Support)" __credits__ = ["Nicolas Richart"] __license__ = "BSD" __version__ = "0.1" __maintainer__ = "Nicolas Richart" __email__ = "nicolas.richart@epfl.ch" _logger = logging.getLogger(__name__) @export class C4ScienceRepo(PhabRepo): def __init__(self, **kwargs): args = copy.copy(kwargs) - if 'host' in args and args['host'] != 'https://c4science.ch/api/': + if 'host' in args and args['host'] != 'https://c4science.ch/': _msg = 'You cannot specify an \'host\'' + \ ' if you use the c4science backend' _logger.error(_msg) raise RuntimeError(_msg) - args['host'] = 'https://c4science.ch/api/' + args['host'] = 'https://c4science.ch/' super().__init__(**args) diff --git a/getmystuph/backends/epfl/repo.py b/getmystuph/backends/epfl/repo.py index 48f5161..bdc2422 100644 --- a/getmystuph/backends/epfl/repo.py +++ b/getmystuph/backends/epfl/repo.py @@ -1,234 +1,237 @@ # -*- coding: utf-8 -*- from bs4 import BeautifulSoup import re import copy import logging from ... import export from ... import colored from ... import color_code from ...repo import Repo from .tequila import TequilaGet __author__ = "Nicolas Richart" __copyright__ = "Copyright (C) 2016, EPFL (Ecole Polytechnique Fédérale " \ "de Lausanne) - SCITAS (Scientific IT and Application " \ "Support)" __credits__ = ["Nicolas Richart"] __license__ = "BSD" __version__ = "0.1" __maintainer__ = "Nicolas Richart" __email__ = "nicolas.richart@epfl.ch" _logger = logging.getLogger(__name__) class RepoEPFL(Repo): ''' Description of a repostitory on {svn git}.epfl.ch ''' _LIST_REPOS = '{root}/repository/my.go' _MANAGE_REPO = '{root}/repository/manage.go?id={id}' _PERMISSION_URL = '{root}/objectRole/list.go?objectId={id}' _REPO_REGEX = '/polyrepo/private/repository/manage\.go\?id=([0-9]+)' _PERMISSIONS = {'Reader': Repo.VIEW, 'Contributor': Repo.PUSH + Repo.VIEW, 'Administrator': Repo.EDIT + Repo.PUSH + Repo.VIEW} _repo_list_cache = {} def __init__(self, name, *args, **kwargs): super().__init__(name, *args, **kwargs) option = copy.copy(kwargs) self._id = option.pop('id', None) self.__tequila_ctx = self._tequila_ctx(**kwargs) self._permissions = None if self._id is None: - if self.repo_type in self._repo_list_cache: - cache = self._repo_list_cache[self.repo_type] + if self._type in self._repo_list_cache: + cache = self._repo_list_cache[self._type] if name in cache: self._id = cache[name] _logger.debug('repo_id {0} for {1} was found in' ' repositories cache'.format( colored(self._id, color_code['repo']), self._colored_name)) else: _logger.debug('No repo_id provided for {0}'.format( self._colored_name)) self.list_repositories( tequila_ctx=self.__tequila_ctx, list_perm=False) - cache = self._repo_list_cache[self.repo_type] + cache = self._repo_list_cache[self._type] if name in cache: self._id = cache[name] _logger.debug('repo_id {0} for {1} was found in' ' repositories list'.format( colored(self._id, color_code['repo']), self._colored_name)) if self._id is None: _msg = 'The repo {0} was not found in' \ ' your list of repositories'.format( self._colored_name) _logger.error(_msg) raise RuntimeError(_msg) @property def permissions(self): '''Get the group and user permissions on the repository''' if self._permissions is not None: pass self._permissions = Repo.Permissions(self) _logger.info('Retrieving list of permissions' + ' for repositories {0}'.format(self._colored_name)) _html_resp = None try: _html_resp = self.__tequila_ctx.get( self._PERMISSION_URL.format(root=self._ROOT_URL, id=self._id)) except: return self._permissions _html_soup = BeautifulSoup(_html_resp.text, 'html.parser') _anonymous_perm = _html_soup.find( 'input', {'id': 'anonymousAccess'}).has_attr('checked') _logger.debug(' anonymous access: {0}'.format(_anonymous_perm)) self._permissions.anonymous = _anonymous_perm _group_regex = re.compile('([US][0-9]+)') _list_soup = _html_soup.find( 'form', {'name': 'lister'}).find_all('tr') for _tr in _list_soup: _tds = _tr.find_all('td') if not _tds: continue _perm_txt = _tds[-2].text.strip() _perm = self._PERMISSIONS[_perm_txt] _id_td = _tds[-1] _ug_id = _id_td.text _is_group = _group_regex.match(_ug_id) _name = '' if _is_group: _perm_type = 'group' if _logger.getEffectiveLevel() == logging.DEBUG: _name = self.directory.get_group_name(_ug_id) else: _perm_type = 'user' if _logger.getEffectiveLevel() == logging.DEBUG: _name = self.directory.get_user_name(_ug_id) getattr(self._permissions, 'add_{0}'.format(_perm_type))(_ug_id, _perm) _logger.debug(' {0}: {1} [{2}] -> {3} [{4}]'.format( _perm_type, self.directory.color_name(_name, type=_perm_type), self.directory.color_name(_ug_id), _perm_txt.lower(), _perm)) return self._permissions @classmethod def _tequila_ctx(cls, tequila_ctx=None, **kwargs): if tequila_ctx is None: return TequilaGet( cls._LIST_REPOS.format(root=cls._ROOT_URL), **kwargs) else: return tequila_ctx @classmethod def list_repositories(cls, list_perm=False, **kwargs): _logger.info("Retrieving the list of repositories") _repos = [] _extra_info = {} tequila_ctx = kwargs.pop('tequila_ctx', None) _tequila_ctx = cls._tequila_ctx(tequila_ctx=tequila_ctx, **kwargs) _html_resp = _tequila_ctx.get( cls._LIST_REPOS.format(root=cls._ROOT_URL) ) _html_soup = BeautifulSoup(_html_resp.text, 'html.parser') _list_soup = _html_soup.find('tbody') _id_regex = re.compile(cls._REPO_REGEX) for _link in _list_soup.find_all('a'): _repo = _link.get_text() _repos.append(_repo) _repo_link = _link.get('href') _match = _id_regex.match(_repo_link) if _match: _id = _match.group(1) _extra_info[_repo] = {'id': _id} if list_perm and ('directory' in kwargs): _repo_epfl = Repo(name=_repo, id=_id, tequila_ctx=_tequila_ctx, **kwargs) _perms = _repo_epfl.permissions _perm = _perms.user_perm( kwargs['directory'].whoami ) _extra_info[_repo]['perm'] = _perm - _logger.debug(' List of repositories:') for _repo in _repos: _logger.debug( ' [{1}] {0} - {2}'.format( colored(_repo, color_code['repo'], attrs=['bold']), colored('{:>5}'.format(_extra_info[_repo]['id']), color_code['repo']), _extra_info[_repo])) - if cls.repo_type not in cls._repo_list_cache: - cls._repo_list_cache[cls.repo_type] = dict() + if issubclass(cls, RepoGitEPFL): + _type = 'git' + elif issubclass(cls, RepoSvnEPFL): + _type = 'svn' + + if _type not in cls._repo_list_cache: + cls._repo_list_cache[_type] = dict() - cache = cls._repo_list_cache[cls.repo_type] + cache = cls._repo_list_cache[_type] for name, info in _extra_info.items(): if 'id' in info: cache[name] = info['id'] return (_repos, _extra_info) @export class RepoGitEPFL(RepoEPFL): _ROOT_URL = 'https://git.epfl.ch/polyrepo/private' - repo_type = 'git' + __repo_type = 'git' def __init__(self, name, *args, **kwargs): - super(RepoGitEPFL, self).__init__(name, *args, **kwargs) + super().__init__(name, *args, **kwargs) self._url = 'https://{0}@git.epfl.ch/repo/{1}.git'.format( self._username, name) @export class RepoSvnEPFL(RepoEPFL): _ROOT_URL = 'https://svn.epfl.ch/polyrepo/private' - repo_type = 'svn' def __init__(self, name, *args, **kwargs): - super(RepoSvnEPFL, self).__init__(name, *args, **kwargs) + super().__init__(name, *args, **kwargs) self._url = 'https://{0}@svn.epfl.ch/svn/{1}'.format( self._username, name) diff --git a/getmystuph/backends/repos/git.py b/getmystuph/backends/repos/git.py index 2d30be1..ec46a0d 100644 --- a/getmystuph/backends/repos/git.py +++ b/getmystuph/backends/repos/git.py @@ -1,58 +1,112 @@ # -*- coding: utf-8 -*- import os +import re import git import logging from ... import colored -from ...repo import Repo, RepoQuery +from ...repo import RepoQuery __author__ = "Nicolas Richart" __copyright__ = "Copyright (C) 2016, EPFL (Ecole Polytechnique Fédérale " \ "de Lausanne) - SCITAS (Scientific IT and Application " \ "Support)" __credits__ = ["Nicolas Richart"] __license__ = "BSD" __version__ = "0.1" __maintainer__ = "Nicolas Richart" __email__ = "nicolas.richart@epfl.ch" _logger = logging.getLogger(__name__) class RepoGit(RepoQuery): """This class handles the common part on git repositories, cloning, retreiving tags/branches doing subtrees """ def __enter__(self): - super(RepoGit, self).__enter__() - + super().__enter__() _logger.info('Cloning repo {0} [{1}] in {2}'.format( - Repo.color_name(self._name), + self._repo_info.color_name(self._name), self._url, colored(self.working_dir, attrs=['bold']))) if not os.path.isdir(os.path.join(self.working_dir, '.git')): self._repo = git.Repo.clone_from(self._url, self.working_dir) else: _logger.warning('Repo {0} is already cloned in {1}'.format( - Repo.color_name(self._name), + self._repo_info.color_name(self._name), colored(self.working_dir, attrs=['bold']))) self._repo = git.Repo(self.working_dir) - def list_tags(self): + return self + + @property + def tags(self): _tags = [] for ref in self._repo.refs: if type(ref) == git.refs.tag.TagReference: - _tags.append(ref.name) + _tags.append(str(ref)) return _tags - def list_branches(self): + @property + def branches(self): _refs = [] for ref in self._repo.refs: if type(ref) == git.refs.remote.RemoteReference and\ ref.name != 'origin/HEAD': - _refs.append(ref.name) + _refs.append(str(ref)) return _refs + + def add_remote(self, out_repo): + + if out_repo.backend_name in [_r.name + for _r in self._repo.remotes]: + return + + _logger.debug('Adding remote {0} [{1}] to clone of {2}'.format( + out_repo.backend_name, out_repo.url, self._name)) + + git.remote.Remote.create( + self._repo, out_repo.backend_name, + out_repo.url) + + +class RepoGitSvn(RepoGit): + """This class handles the git svn""" + + def __enter__(self): + self._create_stage() + + _logger.info('Cloning repo {0} [{1}] in {2}'.format( + self._repo_info.color_name(self._name), + self._url, + colored(self.working_dir, attrs=['bold']))) + + if not os.path.isdir(os.path.join(self.working_dir, '.git')): + _git = git.Git(self.working_dir) + _git.svn('clone', '--preserve-empty-dirs', '--stdlayout', self._url, self.working_dir) + self._repo = git.Repo(self.working_dir) + + super().__enter__() + + _tag_re = re.compile('origin/tags/(.*)') + for _ref in self._repo.refs: + if type(_ref) == git.refs.remote.RemoteReference: + _match = _tag_re.match(_ref.name) + if _match is not None: + _tag_name = _match.group(1) + _logger.debug('Creating tag {0} from branch {1}'.format( + _tag_name, _ref.name)) + git.refs.tag.TagReference.create( + self._repo, _tag_name, + ref=_ref.name) + _logger.debug('Deleting remote branch {1}'.format( + _tag_name, _ref.name)) + git.refs.remote.RemoteReference.delete( + self._repo, _ref) + + return self diff --git a/getmystuph/backends/repos/phabricator.py b/getmystuph/backends/repos/phabricator.py index 6b74744..0d0ad1c 100644 --- a/getmystuph/backends/repos/phabricator.py +++ b/getmystuph/backends/repos/phabricator.py @@ -1,131 +1,151 @@ # -*- coding: utf-8 -*- import logging import copy +import re from ... import export from ... import colored from ... import dry_do from ...repo import Repo from ...utils import get_phabricator_instance from .. import color_phid __author__ = "Nicolas Richart" __copyright__ = "Copyright (C) 2016, EPFL (Ecole Polytechnique Fédérale " \ "de Lausanne) - SCITAS (Scientific IT and Application " \ "Support)" __credits__ = ["Nicolas Richart"] __license__ = "BSD" __version__ = "0.1" __maintainer__ = "Nicolas Richart" __email__ = "nicolas.richart@epfl.ch" _logger = logging.getLogger(__name__) @export class PhabRepo(Repo): def __init__(self, *args, host=None, username=None, token=None, **kwargs): super().__init__(**kwargs, username=username) options = copy.copy(kwargs) self._repo_type = options.pop('repo_type', 'git') # _create = options.pop('create', False) - self._phab = get_phabricator_instance(host=host, + self._host = host + self._phab = get_phabricator_instance(host='{0}api/'.format(host), username=username, token=token) _data = self._phab.diffusion.repository.search( queryKey="all", constraints={"name": self._name})['data'] self._phab_id = None if len(_data) > 0: self._phab_id = _data[0]['phid'] _logger.debug('Repositories {0} has id {1}'.format( self._colored_name, self._phab_id)) else: _logger.debug('Repositories {0} not in phabricator'.format( self._colored_name)) def create(self): if self._phab_id is not None: _msg = 'The repository {0}:{1} already exists'.format( self._colored_name, self._phab_id) _logger.error(_msg) raise RuntimeError(_msg) if self._dry_run: self._phab_id = "PHID-REPO-notarealrepo" else: _data = self._phab.diffusion.repository.edit( transactions=[{'type': 'name', 'value': self._name}, {'type': 'vcs', 'value': self._repo_type}]) - self._phab_id = _data['object']['phid'] + self._creation_data = _data['object'] + self._phab_id = self._creation_data['phid'] _msg = 'Created repository {0} id {1}'.format(self._colored_name, color_phid(self._phab_id)) _logger.info(_msg) if self._dry_run: dry_do(_msg) + self._id = 666 + + _server_re = re.compile(r'https?://(.*)/?') + _match = _server_re.match(self._host) + if _match is not None: + _server = _match.group(1) + else: + raise RuntimeError( + 'Cannot extract the server name for repo {0}'.format( + self.name)) + + if self.repo_type == 'git': + self._url = 'git@{0}:/diffusion/{1}/{2}.git'.format( + _server, self._id, self._name) + elif self.repo_type == 'svn': + self._url = 'svn+ssh://git@{0}/diffusion/{1}/{2}.git'.format( + _server, self._id) def set_permissions(self, permissions): _perms = {'edit': [], 'push': [], 'view': []} _equivalent = {'edit': Repo.EDIT, 'view': Repo.VIEW, 'push': Repo.PUSH} _phab_perms = {'edit': 'edit', 'view': 'view', 'push': 'policy.push'} _special_perms = {'_author_': 'obj.repository.author', '_users_': 'users', '_public_': 'public'} for _type in {'group', 'user'}: _perms_ug = getattr(permissions, '{0}s'.format(_type)) for _entity in _perms_ug: _id = _entity['id'] if _id in _special_perms: _id = _special_perms[_id] for _phab, _gen in _equivalent.items(): if _entity['perm'] & _gen: _perms[_phab].append(_id) if permissions.anonymous: _perms['view'] = ['public'] for _type in ['push', 'view', 'edit']: if _type not in _perms: continue _perms[_type] = set(_perms[_type]) if len(_perms[_type]) > 1: # create custom policy to replace the list _logger.warning( 'Cannot create complicated policies, {0}'.format( _perms[_type]) + ' changing permissions to user instead') _perms[_type] = ['obj.repository.author'] _msg = 'Setting \'{0}\' permissions for {1} to {2}:'.format( _type, self._colored_name, ', '.join([color_phid(_id) for _id in _perms[_type]])) _logger.info(_msg) if not self._dry_run: self._in_directory self._phab.diffusion.repository.edit( transactions=[{'type': _phab_perms[_type], 'value': self._perms[_type][0]}], objectIdentifier=self._phab_id) else: dry_do(_msg) diff --git a/getmystuph/importers/repo_importer.py b/getmystuph/importers/repo_importer.py index 6791a81..3db611e 100644 --- a/getmystuph/importers/repo_importer.py +++ b/getmystuph/importers/repo_importer.py @@ -1,166 +1,199 @@ # -*- coding: utf-8 -*- import logging import copy from .. import export from .. import colored from .. import color_code -from .. import Repo -from . import Importer -from . import GroupImporter +from ..repo import Repo +from .importer import Importer + __author__ = "Nicolas Richart" __copyright__ = "Copyright (C) 2016, EPFL (Ecole Polytechnique Fédérale " \ "de Lausanne) - SCITAS (Scientific IT and Application " \ "Support)" __credits__ = ["Nicolas Richart"] __license__ = "BSD" __version__ = "0.1" __maintainer__ = "Nicolas Richart" __email__ = "nicolas.richart@epfl.ch" _logger = logging.getLogger(__name__) @export class RepoImporter(Importer): __default_import_scheme = {'type': 'git', 'permissions': {'scheme': 'import'}} def __init__(self, name, config, **kwargs): super().__init__(name, config, self.__default_import_scheme, **kwargs) _logger.info( 'Initializing importer for Repo {0}' ' with configuration: {1}'.format(self._colored_name, self._config)) def transfer(self, name): _colored_name = colored(name, color_code['repo'], attrs=['bold']) _logger.info('Locking for repo: {0} ({1})'.format(_colored_name, self._colored_name)) _import_scheme = copy.copy(self._config['import-scheme']) _logger.debug(' --> repo info {0}'.format(colored(self._config, attrs=['bold']))) _config = copy.copy(self._config) _type = _config.pop('type', self.__default_import_scheme['type']) _in_repo = Repo(name=name, keyring=self._keyring, dry_run=self._dry_run, type=_type, **self._backend_in) _type = _import_scheme['type'] if _type == 'same': _type = _in_repo.repo_type _name = _import_scheme.pop('name', self._name).format( original_name=self._name) _out_repo = Repo(name=_name, keyring=self._keyring, dry_run=self._dry_run, type=_type, **self._backend_out) + _queries = {'git': {'git': 'RepoGit', 'svn': 'RepoGitSvn'}, + #'svn': {'svn': 'svn.RepoSvnSync'}} + } + + _query_class = None + if _type in _queries and _in_repo.repo_type in _queries[_type]: + _class_name = _queries[_type][_in_repo.repo_type] + _module = __import__('getmystuph.backends.repos.{0}'.format(_type), + globals(), + locals(), + [_class_name], 0) + _query_class = getattr(_module, _class_name) + else: + _msg = 'Cannot import a {0} repo in a {1} repo'.format( + _type, _in_repo.repo_type) + _logger.error(_msg) + #raise RuntimeError(_msg) + _out_repo.create() _permissions_scheme = _import_scheme['permissions'] _out_perms = Repo.Permissions(_out_repo) if _permissions_scheme['scheme'] == 'import': _in_perms = _in_repo.permissions _logger.debug("Replicating permissions {0}".format(_in_perms)) for _type in {'group', 'user'}: _perms_ug = getattr(_in_perms, '{0}s'.format(_type)) for _entity in _perms_ug: _in_id = _entity['id'] _out_id = getattr( self._user_db, _type)(_in_id, create=True) if _type == 'user' and \ _out_id == self._user_db.directory.whoami: _out_id = '_author_' if _out_id is not None: getattr(_out_perms, 'add_{0}'.format(_type))(_out_id, _entity['perm']) else: _logger.warning( 'No permissions to replicate for repository {0}'.format( _colored_name)) elif _permissions_scheme['scheme'] == 'project': if 'project' in _permissions_scheme: _gid = self._user_db.directory.get_group_unique_id( _permissions_scheme['project']) if _gid is not None: _out_perms.groups = [ {'id': _gid, 'perm': Repo.EDIT + Repo.PUSH + Repo.VIEW}] else: - _msg = 'You should specify a project name specified' + \ - ' in permissions of repo {0} does not exists' + \ - ' in {1}'.format( - _colored_name, - self._user_db.directory.backend_name) + _msg = str('The project {0} you specified in the ' + + 'permissions of repo {1} does not exists' + + ' in {2}').format( + colored(_permissions_scheme['project'], + color_code['group'], + attrs=['bold']), + _colored_name, + self._user_db.directory.backend_name) _logger.error(_msg) raise RuntimeError(_msg) else: _msg = 'You should specify a project name in the ' + \ - 'permissions of repo {0} to be able to use the ' + \ - '\'project\' import scheme'.format(_colored_name) + 'permissions of repo {0}' .format(_colored_name) + \ + ' to be able to use the \'project\' import scheme' _logger.error(_msg) raise RuntimeError(_msg) elif _permissions_scheme['scheme'] == 'user': _out_perms.groups = [ {'id': '_author_', 'perm': Repo.EDIT + Repo.PUSH + Repo.VIEW}] elif _permissions_scheme['scheme'] == 'static': for _perm_type in ['edit', 'view', 'push']: if _perm_type not in _permissions_scheme: _msg = 'You should specify a \'{0}\' in the ' + \ 'permissions of repo {1} to be able to use the ' + \ '\'project\' import scheme'.format(_perm_type, _colored_name) _logger.error(_msg) raise RuntimeError(_msg) _equivalent = {'edit': Repo.EDIT, 'view': Repo.VIEW, 'push': Repo.PUSH} for _perm_type in _equivalent.keys(): if _perm_type in _permissions_scheme: _perm_list = _permissions_scheme[_perm_type] if type(_perm_list) is not list: _perm_list = [_perm_list] if _equivalent[_perm_type] is Repo.VIEW: _out_perms.anonymous = False _out_perms.remove_permission(_equivalent[_perm_type]) for _entity in _perm_list: if _entity == '_author_' or \ _entity == '_users_' or \ _entity == '_public_': _out_perms.add_user(_entity, _equivalent[_perm_type]) else: _id = self._user_db.directory.get_group_unique_id( _entity) if _id is not None: _out_perms.add_group(_entity, _equivalent[_perm_type]) else: _logger.error( 'The project {0} was not found in {1}'.format( _entity, self._user_db.directory.backend_name)) if _out_perms is not None: _out_repo.set_permissions(_out_perms) + + if _query_class: + with _query_class(_in_repo) as _clone: + _branches = _clone.branches + _tags = _clone.tags + for b in _branches: + _logger.debug("Branch: {0}".format(colored(b, attrs=['bold']))) + + for t in _tags: + _logger.debug("Tag: {0}".format(colored(t, attrs=['bold']))) + + _clone.add_remote(_out_repo) diff --git a/getmystuph/repo.py b/getmystuph/repo.py index 9c485a0..db792a9 100644 --- a/getmystuph/repo.py +++ b/getmystuph/repo.py @@ -1,202 +1,236 @@ # -*- coding: utf-8 -*- import copy import logging import tempfile from . import export from . import colored from . import color_code from .backends import _get_class from .directory import Directory __author__ = "Nicolas Richart" __copyright__ = "Copyright (C) 2016, EPFL (Ecole Polytechnique Fédérale " \ "de Lausanne) - SCITAS (Scientific IT and Application " \ "Support)" __credits__ = ["Nicolas Richart"] __license__ = "BSD" __version__ = "0.1" __maintainer__ = "Nicolas Richart" __email__ = "nicolas.richart@epfl.ch" _logger = logging.getLogger(__name__) @export class Repo(object): '''Interface class to define for your backend''' VIEW = 0x1 PUSH = 0x2 EDIT = 0x4 _repo_backends = dict() def __new__(cls, *args, **kwargs): """ Factory constructor depending on the chosen backend """ option = copy.copy(kwargs) backend = option.pop('backend', None) repo_type = option.pop('type', 'git') _class = _get_class(repo_type, backend) return super(Repo, cls).__new__(_class) def __init__(self, name, *args, **kwargs): self._name = name self._colored_name = self.color_name(name) options = copy.copy(kwargs) self._username = options.pop('username', None) self._type = options.pop('type', None) self._dry_run = options.pop("dry_run", False) self._backend_name = options.pop("backend", None) self._directory = options.pop('directory', None) if self._directory is None: self._directory = Directory(type='directory', backend=self._backend_name, username=self._username, dry_run=self._dry_run, **options) @property def backend_name(self): return self._backend_name + @property + def repo_type(self): + return self._type + def color_name(self, name): return colored(name, color_code['repo'], attrs=['bold']) @property def directory(self): return self._directory class Permissions(object): def __init__(self, repo): self.__groups = [] self.__users = [] self.__anonymous = False self.__repo = repo @property def groups(self): return self.__groups @groups.setter def groups(self, groups_perms): self.__groups = copy.copy(groups_perms) def add_group(self, group_id, perm): self.__groups.append({'id': group_id, 'perm': perm}) def add_user(self, user_id, perm): self.__users.append({'id': user_id, 'perm': perm}) def remove_permission(self, perm): _lists = {'group': self.__groups, 'user': self.__users} for _type in _lists.keys(): for _entity in _lists[_type]: _entity['perm'] = \ _entity['perm'] ^ (_entity['perm'] & perm) def user_perm(self, _id): for _user in self.__users: if _user['id'] == _id: return _user['perm'] return 0 @property def users(self): return self.__users @users.setter def users(self, users_perms): self.__users = copy.copy(users_perms) @property def anonymous(self): return self.__anonymous @anonymous.setter def anonymous(self, anonymous): self.__anonymous = anonymous @property def all_users(self): _users = [u['id'] for u in self.__users] _directory = self.__repo.directory for g in self._groups: _users.extend(_directory.get_users_from_group(g['id'])) return set(_users) def __repr__(self): return ''.format( self.__groups, self.__users, self.__anonymous) def set_permissions(self, permissions): pass @property def permissions(self): ''' Returns a dictionary of permissions of the form: {'groups': [{'id': id, 'perm': perm, ...}, ...], 'users': [{'id': id, 'perm': perm, ...}, ...], 'anonymous': True/False} perm should be read, write, admin, or None ''' return self.Permissions(self) + @property + def name(self): + return self._name + + @property + def url(self): + return self._url + + @property + def username(self): + return self._username + def get_query(self): if self._type == 'git': from .repo_backends import RepoGit - return RepoGit(self._name, self._url, self._username) + return RepoGit(self) else: raise RuntimeError( 'No backend for \'{0}\' implemented yet'.format(self._type)) class RepoQuery(object): - def __init__(self, name, url, username, **kwargs): - self._name = name - self._url = url - self._username = username - self._dry_run = kwargs.pop('dry_run', False) - - def __enter__(self): - def debug_mktemp(name): - _path = '/tmp/richart/{0}'.format(name) + class debug_mktemp: + def __init__(self, name): import os + + self._path = '{0}/getmystuph/{1}'.format(os.environ['TMPDIR'], name) try: - os.mkdir(_path) + os.makedirs(self._path) except FileExistsError: pass - return _path - self._stage_path = tempfile.TemporaryDirectory( - prefix=self._name + '-') - # self._stage_path = debug_mktemp(self._name) + @property + def name(self): + return self._path + + def cleanup(self): + pass + + def __init__(self, repo, **kwargs): + self._repo_info = repo + self._name = repo.name + self._url = repo.url + self._username = repo.username + self._dry_run = kwargs.pop('dry_run', False) + + def __enter__(self): + if self._stage_path is not None: + self._create_stage() + return self + + def _create_stage(self): + #self._stage_path = tempfile.TemporaryDirectory( + # prefix=self._name + '-') + self._stage_path = RepoQuery.debug_mktemp(self._name) _logger.debug('Creating stage folder {0} for repo {1}'.format( colored(self.working_dir, attrs=['bold']), - Repo.color_name(self._name))) + self._repo_info.color_name(self._name))) def __exit__(self, *arg, **kwargs): _logger.debug('Cleaning staged folder {0}'.format( colored(self.working_dir, attrs=['bold']))) self._stage_path.cleanup() - def list_tags(self): + def add_remote(self, out_repo): + pass + + @property + def tags(self): return [] - def list_branches(self): + @property + def branches(self): return [] @property def working_dir(self): return self._stage_path.name - # return self._stage_path diff --git a/getmystuph/utils.py b/getmystuph/utils.py index 644a362..77d3327 100644 --- a/getmystuph/utils.py +++ b/getmystuph/utils.py @@ -1,88 +1,88 @@ # -*- coding: utf-8 -*- import logging import getpass from . import colored from phabricator import Phabricator __author__ = "Nicolas Richart" __copyright__ = "Copyright (C) 2016, EPFL (Ecole Polytechnique Fédérale " \ "de Lausanne) - SCITAS (Scientific IT and Application " \ "Support)" __credits__ = ["Nicolas Richart"] __license__ = "BSD" __version__ = "0.1" __maintainer__ = "Nicolas Richart" __email__ = "nicolas.richart@epfl.ch" _logger = logging.getLogger(__name__) def ask_question(question, possible_answer=None, default='y'): if possible_answer is None: possible_answer = {'y': True, 'n': False} answers = '/'.join([k if not k == default else k.upper() for k in possible_answer.keys()]) answer = None while answer not in possible_answer.keys(): answer = input('{0} ({1})? '.format(question, answers)) answer = answer.lower() if answer == '': return possible_answer[default] return possible_answer[answer] def get_password(service, username, keyring=None, **kwargs): service = 'getmystuph/' + service if keyring: _print_service = colored('{0}@{1}'.format(username, service), 'blue') _logger.debug('Try to retrieve password from keyring \'{0}\''.format(_print_service)) # noqa: E501 keyring_passwd = keyring.get_password(service, username) if keyring_passwd is None: _logger.debug('Password for \'{0}\' not in keyring'.format(_print_service)) # noqa: E501 keyring_passwd = getpass.getpass( "Password for {0}@{1}: ".format(username, service)) store = ask_question("Do you want to store your password " + "in the system keyring ?") if store: _logger.debug('Adding password for \'{0}\' in keyring'.format(_print_service)) # noqa: E501 keyring.set_password(service, username, keyring_passwd) else: _logger.warning('To avoid this message to reappear, ' + 'remove the \'use_keyring\' from the ' + 'configuration file.') else: _logger.debug('Password for \'{0}\' found in keyring'.format(_print_service)) # noqa: E501 return keyring_passwd else: getpass_passwd = getpass.getpass( "Password for {0}@{1}: ".format(username, service)) return getpass_passwd def get_phabricator_instance(host=None, username=None, token=None): _phab = None try: _phab = Phabricator(host=host, username=username, token=token) _phab.update_interfaces() # this request is just to make an actual connection _phab.user.whoami() except Exception as e: _logger.error( 'Could not connect to phabricator, either give the' + ' connection with the default configuration of arc' + ' or in the backend configuration of the configuration' + ' file:\n' + ' in/out:\n' + ' username: mylogin\n' + - ' host: https://c4science.ch/api/\n' + + ' host: https://c4science.ch/\n' + ' token: cli-g3amff25kdpnnv2tqvigmr4omnn7\n') raise e return _phab