Source code for maggit.db.repo

# This file is part of maggit.
#
# Copyright 2015 Matthieu Gautier <dev@mgautier.fr>
#
# Pit is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# Additional permission under the GNU Affero GPL version 3 section 7:
#
# If you modify this Program, or any covered work, by linking or
# combining it with other code, such other code is not for that reason
# alone subject to any of the requirements of the GNU Affero GPL
# version 3.
#
# You should have received a copy of the GNU Affero General Public License
# along with maggit.  If not, see http://www.gnu.org/licenses
#
# In summary:
# - You can use this program for no cost.
# - You can use this program for both personal and commercial reasons.
# - You do not have to share your own program's code which uses this program.
# - You have to share modifications (e.g bug-fixes, improvements) you've made to this program.

from .db import Gitdb
import os
from pathlib import Path
from .ref_handler import RefHandler
from weakref import WeakValueDictionary

default_config = '''[core]
    repositoryformatversion = 0
    filemode = true
    bare = {bare}
    logallrefupdates = true
'''

git_init_file = {
    'HEAD': "ref: refs/heads/master",
    'description': "Unnamed repository; edit this file 'description' to "
        "name the repository.\n",
    'config': default_config,
}


[docs]class Repo: """This is the low level Repository class. The repo make the link between all other low level subsystems and recreate a coherent database. Arguments: gitdir(path): The directory path of the repository, If is None, the current working directory is assumed. disable_directoryLooking(bool): If True, assume that the gitdir is a valid path so do not search for a valid git repository in parents and gitdir must not be None. bare(bool): Does the repository is a bare one. Only relevant if disable_directoryLooking is True. Else, the bare attribute is detected from the git repository structure. """ def __init__(self, gitdir=None, disable_directoryLooking=False, bare=False): self.bare = bare if disable_directoryLooking: self.gitdir = Path(gitdir) if not self._check_is_git_dir(self.gitdir): raise Exception("%r is not a valid git directory", self.gitdir) else: self.bare, self.gitdir = self.get_git_dir(gitdir) object_dir = self._get_object_dir() self.db = Gitdb(object_dir) self.refs = RefHandler(self.gitdir) self.objectCache = WeakValueDictionary() @classmethod
[docs] def init_repo(cls, gitdir, bare=False): """Instantiate a new git repo at the given location.""" gitdirpath = Path(gitdir) if not bare: gitdirpath = gitdirpath/'.git' for folder in [ 'branches', 'hooks', Path('info')/'excludes', Path('objects')/'info', Path('objects')/'pack', Path('refs')/'heads', Path('refs')/'tags', ]: nfolder = gitdirpath/folder try: nfolder.mkdir(parents=True) except FileExistsError: pass for filename, content in git_init_file.items(): nfile = gitdirpath/filename try: with nfile.open('x') as stream: stream.write(content.format(bare="true" if bare else "false")) except FileExistsError: pass return cls(gitdir)
@staticmethod def _check_is_git_dir(path): return ( path.joinpath('HEAD').is_file() and path.joinpath('config').is_file() and path.joinpath('refs').is_dir() and path.joinpath('objects').is_dir()) @classmethod
[docs] def get_git_dir(cls, dirToCheck=None): # [TODO] We probably need to read the config # instead of supposing from directories structure. git_dir = os.environ.get('GIT_DIR', None) if git_dir: if cls._check_is_git_dir(git_dir): raise Exception("$GIT_DIRĀ (%s) is not a valid git directory"%gitdir) return False, Path(git_dir) # Should we use Path.resolve here ? if dirToCheck is None: dirToCheck = os.getcwd() currentDir = Path(dirToCheck) while True: gitdir = currentDir/'.git' if gitdir.is_file(): with gitdir.open("br") as f: gitdir = Path(f.read().strip()) if cls._check_is_git_dir(gitdir): return False, gitdir if cls._check_is_git_dir(currentDir): return True, currentDir parent = currentDir.parent if parent == currentDir: # We are at top raise Exception("No a git repository") currentDir = parent
def _get_object_dir(self): object_dir = os.environ.get('GIT_OBJECT_DIRECTORY', None) if object_dir: return Path(object_dir) return self.gitdir/'objects'