Esempio n. 1
0
    def test_simple_local(self):
        f1_1 = make_object(Blob, data=b'f1')
        commit_spec = [[1], [2, 1], [3, 1, 2]]
        trees = {
            1: [(b'f1', f1_1), (b'f2', f1_1)],
            2: [(b'f1', f1_1), (b'f2', f1_1)],
            3: [(b'f1', f1_1), (b'f2', f1_1)],
        }

        c1, c2, c3 = build_commit_graph(self.repo.object_store, commit_spec,
                                        trees)
        self.repo.refs[b"refs/heads/master"] = c3.id
        self.repo.refs[b"refs/tags/foo"] = c3.id
        target_path = tempfile.mkdtemp()
        errstream = BytesIO()
        self.addCleanup(shutil.rmtree, target_path)
        r = porcelain.clone(self.repo.path,
                            target_path,
                            checkout=False,
                            errstream=errstream)
        self.assertEqual(r.path, target_path)
        target_repo = Repo(target_path)
        self.assertEqual(target_repo.head(), c3.id)
        self.assertEqual(c3.id, target_repo.refs[b'refs/tags/foo'])
        self.assertTrue(b'f1' not in os.listdir(target_path))
        self.assertTrue(b'f2' not in os.listdir(target_path))
        c = r.get_config()
        encoded_path = self.repo.path
        if not isinstance(encoded_path, bytes):
            encoded_path = encoded_path.encode('utf-8')
        self.assertEqual(encoded_path, c.get((b'remote', b'origin'), b'url'))
        self.assertEqual(b'+refs/heads/*:refs/remotes/origin/*',
                         c.get((b'remote', b'origin'), b'fetch'))
Esempio n. 2
0
def get_git_versions(repos, get_dirty_status=False, verbose=0):
    """ Returns the repository head guid and dirty status and package version number if installed via pip.
        The version is only returned if the repo is installed as pip package without edit mode.
        NOTE: currently the dirty status is not working correctly due to a bug in dulwich...

        Args:
            repos ([str]): a list with repositories, e.g. ['qtt', 'qcodes']
            get_dirty_status (bool): selects whether to use the dulwich package and collect the local code
                                changes for the repositories.

        Retuns:
            r (dict): dictionary with repo names, head guid and (optionally) dirty status for each given repository.
    """
    heads = dict()
    dirty_stats = dict()
    for repo in repos:
        try:
            package = importlib.import_module(repo)
            init_location = os.path.split(package.__file__)[0]
            repo_location = os.path.join(init_location, '..')
            repository = Repo(repo_location)
            heads[repo] = repository.head().decode('ascii')
            if get_dirty_status:
                status = porcelain.status(repository)
                is_dirty = len(status.unstaged) == 0 or any(
                    len(item) != 0 for item in status.staged.values())
                dirty_stats[repo] = is_dirty
        except (AttributeError, ModuleNotFoundError, NotGitRepository):
            heads[repo] = 'none'
            if get_dirty_status:
                dirty_stats[repo] = 'none'
        if verbose:
            print('{0}: {1}'.format(repo, heads[repo]))
    return (heads, dirty_stats)
Esempio n. 3
0
def checkout(repo_path='.'):
    repo = Repo(repo_path)
    indexfile = repo.index_path()
    obj_sto = repo.object_store
    tree_id = repo[repo.head()].tree
    build_index_from_tree(repo_path, indexfile, obj_sto, tree_id)
    return [obj_sto.iter_tree_contents(tree_id)]
Esempio n. 4
0
    def dulwichCommit(self, filePath, fullPath, kind):

        git = Repo(AUTOGIT_PATH)
        staged = map(str, [filePath])
        git.stage(staged)

        index = git.open_index()

        try:
            committer = git._get_user_identity()
        except ValueError:
            committer = "autogit"

        try:
            head = git.head()
        except KeyError:
            return git.do_commit('%s - autogit commit (via dulwich)' % kind,
                                 committer=committer)

        changes = list(
            tree_changes(git, index.commit(git.object_store),
                         git['HEAD'].tree))
        if changes and len(changes) > 0:
            return git.do_commit('%s - autogit commit (via dulwich)' % kind,
                                 committer=committer)
        return None
Esempio n. 5
0
File: bot.py Progetto: 4p4ch3/bot
    async def info(self, ctx: Context):
        """
        Get information about the bot
        """

        embed = Embed(
            description=
            "A utility bot designed just for the Python server! Try `bot.help()` for more info.",
            url="https://github.com/discord-python/bot")

        repo = Repo(".")
        sha = repo[repo.head()].sha().hexdigest()

        embed.add_field(name="Total Users",
                        value=str(len(
                            self.bot.get_guild(PYTHON_GUILD).members)))
        embed.add_field(name="Git SHA", value=str(sha)[:7])

        embed.set_author(name="Python Bot",
                         url="https://github.com/discord-python/bot",
                         icon_url=BOT_AVATAR_URL)

        log.info(
            f"{ctx.author} called bot.about(). Returning information about the bot."
        )
        await ctx.send(embed=embed)
Esempio n. 6
0
    async def about_command(self, ctx: Context):
        """
        Get information about the bot
        """

        embed = Embed(
            description=
            "A utility bot designed just for the Python server! Try `!help` for more info.",
            url="https://gitlab.com/discord-python/projects/bot")

        repo = Repo(".")
        sha = repo[repo.head()].sha().hexdigest()

        embed.add_field(name="Total Users",
                        value=str(len(self.bot.get_guild(Guild.id).members)))
        embed.add_field(name="Git SHA", value=str(sha)[:7])

        embed.set_author(name="Python Bot",
                         url="https://gitlab.com/discord-python/projects/bot",
                         icon_url=URLs.bot_avatar)

        log.info(
            f"{ctx.author} called !about. Returning information about the bot."
        )
        await ctx.send(embed=embed)
Esempio n. 7
0
    def test_simple_local(self):
        f1_1 = make_object(Blob, data=b'f1')
        commit_spec = [[1], [2, 1], [3, 1, 2]]
        trees = {
            1: [(b'f1', f1_1), (b'f2', f1_1)],
            2: [(b'f1', f1_1), (b'f2', f1_1)],
            3: [(b'f1', f1_1), (b'f2', f1_1)],
        }

        c1, c2, c3 = build_commit_graph(self.repo.object_store, commit_spec,
                                        trees)
        self.repo.refs[b"refs/heads/master"] = c3.id
        self.repo.refs[b"refs/tags/foo"] = c3.id
        target_path = tempfile.mkdtemp()
        errstream = BytesIO()
        self.addCleanup(shutil.rmtree, target_path)
        r = porcelain.clone(self.repo.path,
                            target_path,
                            checkout=False,
                            errstream=errstream)
        self.assertEqual(r.path, target_path)
        target_repo = Repo(target_path)
        self.assertEqual(target_repo.head(), c3.id)
        self.assertEquals(c3.id, target_repo.refs[b'refs/tags/foo'])
        self.assertTrue(b'f1' not in os.listdir(target_path))
        self.assertTrue(b'f2' not in os.listdir(target_path))
Esempio n. 8
0
def commit_style(repo: Repo, format_rule_name: str) -> Tuple[str, str]:
    """
    Call bash script which commit all changes to `style_name` branch and checkout master back.

    :param repo: Repo instance to the repository for which style were applied.
    :param format_rule_name: Applied format rule name.
    :return: Two commit hashes: where style was applied and where style was disrupt.
    """
    def commit(repo: Repo, msg: str) -> str:
        """Commit everything."""
        for tree_path, entry in repo.open_index().items():
            full_path = os.path.join(repo.path.encode(), tree_path)
            blob = blob_from_path_and_stat(full_path, os.lstat(full_path))
            if blob.id != entry.sha:
                repo.stage(tree_path)
        return repo.do_commit(msg.encode(), b"Source{d} ML Team <*****@*****.**>")

    repopath = repo.path
    base = repo.head()
    branch_create(repopath, format_rule_name, force=True)
    update_head(repopath, format_rule_name)
    style_commit_sha = commit(repo, format_rule_name)
    build_index_from_tree(repo.path, repo.index_path(), repo.object_store, repo[base].tree)
    revert_style_commit_sha = commit(repo, "Revert " + format_rule_name)
    update_head(repopath, b"master")
    return style_commit_sha.decode(), revert_style_commit_sha.decode()
Esempio n. 9
0
    async def info(self, ctx: Context):
        """
        Get information about the bot
        """

        embed = Embed(
            description=
            "A utility bot designed just for the Python server! Try `bot.help()` for more info.",
            url="https://github.com/discord-python/bot")

        repo = Repo(".")
        sha = repo[repo.head()].sha().hexdigest()

        embed.add_field(name="Total Users",
                        value=str(len(
                            self.bot.get_guild(PYTHON_GUILD).members)))
        embed.add_field(name="Git SHA", value=str(sha)[:7])

        embed.set_author(
            name="Python Bot",
            url="https://github.com/discord-python/bot",
            icon_url=
            "https://raw.githubusercontent.com/discord-python/branding/master/logos/logo_circle.png"
        )

        await ctx.send(embed=embed)
    def test_simple_local(self):
        f1_1 = make_object(Blob, data=b'f1')
        commit_spec = [[1], [2, 1], [3, 1, 2]]
        trees = {1: [(b'f1', f1_1), (b'f2', f1_1)],
                 2: [(b'f1', f1_1), (b'f2', f1_1)],
                 3: [(b'f1', f1_1), (b'f2', f1_1)], }

        c1, c2, c3 = build_commit_graph(self.repo.object_store,
                                        commit_spec, trees)
        self.repo.refs[b"refs/heads/master"] = c3.id
        self.repo.refs[b"refs/tags/foo"] = c3.id
        target_path = tempfile.mkdtemp()
        errstream = BytesIO()
        self.addCleanup(shutil.rmtree, target_path)
        r = porcelain.clone(self.repo.path, target_path,
                            checkout=False, errstream=errstream)
        self.assertEqual(r.path, target_path)
        target_repo = Repo(target_path)
        self.assertEqual(target_repo.head(), c3.id)
        self.assertEqual(c3.id, target_repo.refs[b'refs/tags/foo'])
        self.assertTrue(b'f1' not in os.listdir(target_path))
        self.assertTrue(b'f2' not in os.listdir(target_path))
        c = r.get_config()
        encoded_path = self.repo.path
        if not isinstance(encoded_path, bytes):
            encoded_path = encoded_path.encode('utf-8')
        self.assertEqual(encoded_path, c.get((b'remote', b'origin'), b'url'))
        self.assertEqual(
            b'+refs/heads/*:refs/remotes/origin/*',
            c.get((b'remote', b'origin'), b'fetch'))
Esempio n. 11
0
def clone_role(url, branch, clone_root_path, clone_folder=None, depth=None):
    """ Git clone
    :param url: Source of the git repo
    :param branch: Branch of the git repo
    :param clone_root_path: The main folder in which the repo will be cloned.
    :param clone_folder: The relative folder name of the git clone to the clone_root_path
    :param depth(str): The git shallow clone depth
    :returns: latest sha of the clone and its location
    """
    gitcall = ["git", "clone"]

    if depth and depth.isdigit():
        gitcall.extend(["--depth", depth, "--no-single-branch"])

    gitcall.append(url)

    gitcall.extend(["-b", branch])

    if not clone_folder:
        clone_folder = url.split("/")[-1]
    dirpath = os.path.join(clone_root_path, clone_folder)
    gitcall.append(dirpath)

    subprocess.check_call(gitcall)
    repo = Repo(dirpath)
    return repo.head(), dirpath
Esempio n. 12
0
class Git():
    """
    object that holds the git repository
    """
    def __init__(self):
        self.repo_path = user_data_dir(appname, appauthor)
        self.files_under_version_controll = ['config.json', 'data.json']
        # initialize repo if it doesn't exist
        try:
            self.repo = Repo(self.repo_path)
        except NotGitRepository:
            # create repo
            if not os.path.exists(self.repo_path):
                try:
                    os.makedirs(self.repo_path)
                except OSError as exc:  # Guard against race condition
                    if exc.errno != errno.EEXIST:
                        raise
            Repo.init(self.repo_path)
            self.repo = Repo(self.repo_path)
            self.commit('initial commit')

    def commit(self, message):
        """
        commits the current status of files_under_version_controll
        :param message: str; commit message
        """
        self.repo.stage(self.files_under_version_controll)
        self.repo.do_commit(str.encode(message), str.encode('nextSongs'))

    def get_current_head(self):
        """
        get sha as bytes of current head
        :return: bytes; sha1 checksum of current head
        """
        return self.repo.head()

    def get_commits(self):
        """
        generates a list of last commits
        :return: list-of-dulwich.objects.Commit
        """
        commits = []
        for i in self.repo.get_walker():
            commits.append(i.commit)
        return reversed(
            sorted(
                commits,
                key=lambda x: datetime.datetime.fromtimestamp(x.author_time)))

    def restore(self, commit):
        """
        does a hard reset to a given commit
        :param commit: list-of-dulwich.objects.Commit; commit to reset to
        """
        porcelain.reset(self.repo, 'hard',
                        str.encode(commit.sha().hexdigest()))
        self.commit("Restored setting and data.")
        Config.read_config()
Esempio n. 13
0
 def test_submodule(self):
     temp_dir = tempfile.mkdtemp()
     repo_dir = os.path.join(os.path.dirname(__file__), "data", "repos")
     shutil.copytree(os.path.join(repo_dir, "a.git"), os.path.join(temp_dir, "a.git"), symlinks=True)
     rel = os.path.relpath(os.path.join(repo_dir, "submodule"), temp_dir)
     os.symlink(os.path.join(rel, "dotgit"), os.path.join(temp_dir, ".git"))
     r = Repo(temp_dir)
     self.assertEqual(r.head(), "a90fa2d900a17e99b433217e988c4eb4a2e9a097")
 def get_last_commit(self):
     try:
         repo = Repo(os.path.dirname(self.path))
     except NotGitRepository:
         repo = Repo.init(os.path.dirname(self.path))
     head = repo.head()
     head_commit = repo.get_object(head)
     return head_commit
Esempio n. 15
0
class ArticleList(object):
    def __init__(self):
        self.repo = Repo('wiki')
        self.head = self.repo.get_object(self.repo.head())
        self.tree = self.repo.get_object(self.head.tree)

    def get_article_titles(self):
        return [a for a in self.tree]
Esempio n. 16
0
 def test_sprouted_tags(self):
     path, gitsha = self.make_onerev_branch()
     r = GitRepo(path)
     r.refs[b"refs/tags/lala"] = r.head()
     oldrepo = Repository.open(path)
     revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
     newbranch = self.clone_git_branch(path, "f")
     self.assertEqual({"lala": revid}, newbranch.tags.get_tag_dict())
     self.assertEqual([revid], newbranch.repository.all_revision_ids())
Esempio n. 17
0
 def test_submodule(self):
     temp_dir = tempfile.mkdtemp()
     repo_dir = os.path.join(os.path.dirname(__file__), 'data', 'repos')
     shutil.copytree(os.path.join(repo_dir, 'a.git'),
                     os.path.join(temp_dir, 'a.git'), symlinks=True)
     rel = os.path.relpath(os.path.join(repo_dir, 'submodule'), temp_dir)
     os.symlink(os.path.join(rel, 'dotgit'), os.path.join(temp_dir, '.git'))
     r = Repo(temp_dir)
     self.assertEqual(r.head(), 'a90fa2d900a17e99b433217e988c4eb4a2e9a097')
Esempio n. 18
0
    def _dulwich_commit(self, author, message=DEFAULT_COMMIT_MSG):
        """
        Commit staged files in the repo
        """
        _repo = Repo(self.config['top_dir'])
        commit_id = _repo.do_commit(message, committer=author)

        if not _repo.head() == commit_id:
            raise SartorisError(message=exit_codes[14], exit_code=14)
Esempio n. 19
0
File: Git.py Progetto: AgarFu/bcfg2
 def get_revision(self):
     """Read git revision information for the bcfg2 repository"""
     try:
         repo = Repo(self.datastore)
         revision = repo.head()
     except:
         logger.error("Failed to read git repository; disabling git support")
         raise Bcfg2.Server.Plugin.PluginInitError
     return revision
Esempio n. 20
0
def git_commit_info():
    git = Repo('.')
    commit = git.get_object(git.head())
    return {
        'id': commit.id.decode("utf-8")[0:7],
        'id_full': commit.id.decode("utf-8"),
        'author': regex.findall("(.*?) <(.*?)>",
                                commit.author.decode("utf-8"))[0],
        'message': commit.message.decode("utf-8").strip('\r\n').split('\n')[0]
    }
Esempio n. 21
0
 def test_submodule(self):
     temp_dir = tempfile.mkdtemp()
     repo_dir = os.path.join(os.path.dirname(__file__), 'data', 'repos')
     shutil.copytree(os.path.join(repo_dir, 'a.git'),
                     os.path.join(temp_dir, 'a.git'),
                     symlinks=True)
     rel = os.path.relpath(os.path.join(repo_dir, 'submodule'), temp_dir)
     os.symlink(os.path.join(rel, 'dotgit'), os.path.join(temp_dir, '.git'))
     r = Repo(temp_dir)
     self.assertEqual(r.head(), 'a90fa2d900a17e99b433217e988c4eb4a2e9a097')
Esempio n. 22
0
 def get_revision(self):
     """Read git revision information for the Bcfg2 repository."""
     try:
         repo = Repo(self.datastore)
         revision = repo.head()
     except:
         logger.error(
             "Failed to read git repository; disabling git support")
         raise Bcfg2.Server.Plugin.PluginInitError
     return revision
Esempio n. 23
0
class Article(object):
    def __init__(self, title):
        self.title =  title.encode('UTF-8')
        self.repo = Repo('wiki')

        self.head = self.repo.get_object(self.repo.head())
        self.tree = self.repo.get_object(self.head.tree)

        try:
            sha = self.tree[self.title][1]
            self.content = self.repo[sha].data
        except KeyError:
            self.content = u'This space intentionally left blank.'

    def __str__(self):
        return self.title

    def get_content(self):
        return self.content

    def get_title(self):
        return self.title

    def update_content(self, new_content, author, email, message):
        new_content = new_content.encode('UTF-8')
        author = author.encode('UTF-8')
        message = message.encode('UTF-8')
        email = email.encode('UTF-8')

        # create blob, add to existing tree
        blob = Blob.from_string(new_content)
        self.tree[self.title] = (0100644, blob.id)

        # commit
        commit = Commit()
        commit.tree = self.tree.id
        commit.parents = [self.head.id]
        commit.author = commit.committer = "%s <%s>" % (author, email)
        commit.commit_time = commit.author_time = int(time())
        tz = parse_timezone('+0100')[0]  # FIXME: get proper timezone
        commit.commit_timezone = commit.author_timezone = tz
        commit.encoding = 'UTF-8'
        commit.message = message

        # save everything
        object_store = self.repo.object_store
        object_store.add_object(blob)
        object_store.add_object(self.tree)
        object_store.add_object(commit)

        self.repo.refs['refs/heads/master'] = commit.id

    def update_title(self, new_title):
        pass
Esempio n. 24
0
def get_source_revision_from_git(folder: Path) -> str:
    dot_git: Path = folder / '.git'
    if not dot_git.is_dir():
        raise OSError('Not a Git working copy')
    repo = Repo(folder)
    # We truncate the hash string to 7 characters,
    # that is also the way Git represents in short form.
    try:
        return repo.head()[:REVISION_LENGTH].decode()
    except KeyError:
        # Folder has just been "git init", no data yet
        return '-'
Esempio n. 25
0
 def get_hash(self, _id, _user):
     """
     Returns the hashes
     :param _id: The _id of the repository
     :return: The hash of the repository
     """
     _result = self.node.find(
         {"_id": ObjectId(_id)},
         _user,
         _error_prefix_if_not_allowed=
         "This user doesn't have permissions for this repository.")
     _repo = Repo(os.path.join(_result["folder"], str(_id)))
     return _repo.head()
Esempio n. 26
0
 def test_submodule(self):
     temp_dir = self.mkdtemp()
     repo_dir = os.path.join(os.path.dirname(__file__), 'data', 'repos')
     if isinstance(temp_dir, bytes):
         temp_dir_str = temp_dir.decode(sys.getfilesystemencoding())
     else:
         temp_dir_str = temp_dir
     shutil.copytree(os.path.join(repo_dir, 'a.git'),
                     os.path.join(temp_dir_str, 'a.git'), symlinks=True)
     rel = os.path.relpath(os.path.join(repo_dir, 'submodule'), temp_dir_str)
     os.symlink(os.path.join(rel, 'dotgit'), os.path.join(temp_dir_str, '.git'))
     r = Repo(temp_dir)
     self.assertEqual(r.head(), b'a90fa2d900a17e99b433217e988c4eb4a2e9a097')
Esempio n. 27
0
 def test_submodule(self):
     temp_dir = self.mkdtemp()
     repo_dir = os.path.join(os.path.dirname(__file__), 'data', 'repos')
     if isinstance(temp_dir, bytes):
         temp_dir_str = temp_dir.decode(sys.getfilesystemencoding())
     else:
         temp_dir_str = temp_dir
     shutil.copytree(os.path.join(repo_dir, 'a.git'),
                     os.path.join(temp_dir_str, 'a.git'), symlinks=True)
     rel = os.path.relpath(os.path.join(repo_dir, 'submodule'), temp_dir_str)
     os.symlink(os.path.join(rel, 'dotgit'), os.path.join(temp_dir_str, '.git'))
     r = Repo(temp_dir)
     self.assertEqual(r.head(), b'a90fa2d900a17e99b433217e988c4eb4a2e9a097')
 def teardown(self):
     folder = Path.cwd()
     try:
         (folder / '.version').unlink()
     except FileNotFoundError:
         pass
     if self.original_revision is None:
         # Remove the Git repo created in test
         try:
             rp = Repo(str(folder))
             head = rp[rp.head()]
             if not len(head.parents):
                 shutil.rmtree(folder / '.git')
         except NotGitRepository:
             pass
Esempio n. 29
0
    def _dulwich_reset_to_tag(self, tag=None):
        """
        Resets the HEAD to the commit
        """
        _repo = Repo(self.config['top_dir'])

        if not tag:
            sha = _repo.head()
        else:
            sha = self._get_commit_sha_for_tag(tag)

        try:
            _repo.refs['HEAD'] = sha
        except AttributeError:
            raise GitMethodsError(message=exit_codes[7], exit_code=7)
Esempio n. 30
0
    def _dulwich_reset_to_tag(self, tag=None):
        """
        Resets the HEAD to the commit
        """
        _repo = Repo(self.config['top_dir'])

        if not tag:
            sha = _repo.head()
        else:
            sha = self._get_commit_sha_for_tag(tag)

        try:
            _repo.refs['HEAD'] = sha
        except AttributeError:
            raise GitMethodsError(message=exit_codes[7], exit_code=7)
Esempio n. 31
0
def read_submodule_head(path):
    """Read the head commit of a submodule.

    :param path: path to the submodule
    :return: HEAD sha, None if not a valid head/repository
    """
    from dulwich.errors import NotGitRepository
    from dulwich.repo import Repo
    try:
        repo = Repo(path)
    except NotGitRepository:
        return None
    try:
        return repo.head()
    except KeyError:
        return None
 def test_normal_from_repo(self):
     # Create repo
     folder = Path.cwd()
     try:
         rp = Repo(str(folder))
     except NotGitRepository:
         rp = Repo.init(str(folder))
     try:
         version = rp.head().decode()
         self.original_revision = version
     except KeyError:
         FILE_NAME_TEST = 'file_test.txt'
         test_file = folder / FILE_NAME_TEST
         test_file.touch()
         rp.stage(FILE_NAME_TEST.encode())
         version = rp.do_commit(b'Test commit').decode()
     v = get_source_revision()
     assert v == version[:10]
Esempio n. 33
0
def project_detail(request, project_slug):
    """Show commits for this project."""
    repo, project = _get_repo(project_slug)

    try:
        repo = Repo(project.path_to_repo)
    except:
        return HttpResponse("Invalid repo path %s" % project.path_to_repo)
        
    commits = repo.revision_history(repo.head())
 
    branches = repo.refs.as_dict('refs/heads').keys()
 
    return render_to_response('project/project_detail.html', {
        'project': project,
        'commits': commits,
        'branches': branches,
    }, context_instance=RequestContext(request))
Esempio n. 34
0
 def _identify(self,scribblearea):
     top = self.select.module_name+"."+self.select.currentText()
     try:
         import os
         if (os.getcwd()).endswith('stopeight'):
             if (self.select.module_name=='stopeight.analyzer.file'):
                 if hasattr(scribblearea,'tablet_id'):
                     sub = str(scribblearea.tablet_id)
                     return (top,sub)
                 else:
                     return (top,'MouseData')
             else:
                 from dulwich.repo import Repo
                 clibs_repo = Repo('../stopeight/')
                 if (self.select.module_name == ('stopeight_clibs_legacy')) or (self.select.module_name == ('stopeight_clibs_analyzer')):
                     clibs_repo = Repo('../stopeight-clibs/')
                 sub = (clibs_repo.head().decode('utf-8'))
                 return (top,sub)
     except:
         return (top)
Esempio n. 35
0
def read_submodule_head(path):
    """Read the head commit of a submodule.

    :param path: path to the submodule
    :return: HEAD sha, None if not a valid head/repository
    """
    from dulwich.errors import NotGitRepository
    from dulwich.repo import Repo
    # Repo currently expects a "str", so decode if necessary.
    # TODO(jelmer): Perhaps move this into Repo() ?
    if not isinstance(path, str):
        path = path.decode(sys.getfilesystemencoding())
    try:
        repo = Repo(path)
    except NotGitRepository:
        return None
    try:
        return repo.head()
    except KeyError:
        return None
Esempio n. 36
0
def read_submodule_head(path):
    """Read the head commit of a submodule.

    :param path: path to the submodule
    :return: HEAD sha, None if not a valid head/repository
    """
    from dulwich.errors import NotGitRepository
    from dulwich.repo import Repo
    # Repo currently expects a "str", so decode if necessary.
    # TODO(jelmer): Perhaps move this into Repo() ?
    if not isinstance(path, str):
        path = path.decode(sys.getfilesystemencoding())
    try:
        repo = Repo(path)
    except NotGitRepository:
        return None
    try:
        return repo.head()
    except KeyError:
        return None
Esempio n. 37
0
    def readme(self, date=True, git_commit=False, git_path=".", info=()):
        """Adds a README.md with useful info.

        The README consists of the name of the directory (passed in at init
        time), followed by a bulleted list with various pieces of info.

        Args:
            date (bool): Add the date and time in the bulleted list of info.
            git_commit (bool): Add the current git commit hash in the bulleted
                list of info.
            git_path (str or pathlib.Path): The path to the git repo (i.e. a
                directory that contains `.git`). Only applicable if `git_commit`
                is True. If the path given is not to a Git repo, a warning is
                issued, and the Git Commit is replaced with `"(no repo found)"`
            info (list of str): A list of additional bullets to add in the
                README.
        Returns:
            pathlib.path: Full path to the README.
        """
        readme_path = self.pfile("README.md")
        with readme_path.open("w") as file:
            lines = [f"# {self._name}", ""]

            if date:
                date_str = self._datetime.strftime("%Y-%m-%d %H:%M:%S")
                lines.append(f"- Date: {date_str}")
            if git_commit:
                git_path = Path(git_path)
                if (git_path / ".git").exists():
                    repo = Repo(str(git_path))
                    commit_hash = repo.head().decode("utf-8")
                else:
                    warnings.warn("No Git repo found")
                    commit_hash = "(no repo found)"
                lines.append(f"- Git Commit: {commit_hash}")

            lines.extend(map(lambda s: f"- {s}", info))
            file.write("\n".join(lines) + "\n")

            return readme_path
Esempio n. 38
0
def git_prelod(abbr):
    if not hasattr(settings, "ENABLE_GIT") or not settings.ENABLE_GIT:
        return

    global git_active_repo
    global git_active_commit
    global git_active_tree
    global git_old_tree
    global HEAD

    gitdir = "%s/%s.git" % (settings.GIT_PATH, abbr)

    if not os.path.exists(gitdir):
        git_repo_init(gitdir)

    git_active_repo = Repo(gitdir)
    git_active_commit = Commit()
    HEAD = git_active_repo.head()
    commit = git_active_repo.commit(HEAD)
    tree = git_active_repo.tree(commit.tree)
    git_old_tree = tree.id
    git_active_tree = tree
Esempio n. 39
0
    def __init__(self, path, init = False):
        if init :
          os.makedirs(path)
          repo = Repo.init_bare(path)
        else:
          repo = Repo(path)


        self._repo    = repo
        self.path     = path
        self.branches = self._getBranches() 

        try:
            head = repo.head()
            commitLast = repo.commit(head)
            
            self.head     = {
                'sha'    : head,
                'tree'   : commitLast.tree
            }
        except KeyError:
            self.head = None
Esempio n. 40
0
def read_submodule_head(path):
    """Read the head commit of a submodule.

    Args:
      path: path to the submodule
    Returns: HEAD sha, None if not a valid head/repository
    """
    from dulwich.errors import NotGitRepository
    from dulwich.repo import Repo

    # Repo currently expects a "str", so decode if necessary.
    # TODO(user): Perhaps move this into Repo() ?
    if not isinstance(path, str):
        path = os.fsdecode(path)
    try:
        repo = Repo(path)
    except NotGitRepository:
        return None
    try:
        return repo.head()
    except KeyError:
        return None
Esempio n. 41
0
	def dulwichCommit(self, filePath, fullPath, kind):

		git = Repo(AUTOGIT_PATH)
		staged = map(str,[filePath])
		git.stage( staged )

		index = git.open_index()

		try:
			committer = git._get_user_identity()
		except ValueError:
			committer = "autogit"

		try:
			head = git.head()
		except KeyError:
			return git.do_commit( '%s - autogit commit (via dulwich)' % kind, committer=committer)

		changes = list(tree_changes(git, index.commit(git.object_store), git['HEAD'].tree))
		if changes and len(changes) > 0:
			return git.do_commit( '%s - autogit commit (via dulwich)' % kind, committer=committer)
		return None
Esempio n. 42
0
def git_prelod(abbr):
    if not hasattr(settings, "ENABLE_GIT") or not settings.ENABLE_GIT:
        return

    global git_active_repo
    global git_active_commit
    global git_active_tree
    global git_old_tree
    global HEAD

    gitdir = "%s/%s.git" % (settings.GIT_PATH, abbr)

    if not os.path.exists(gitdir):
        git_repo_init(gitdir)

    git_active_repo = Repo(gitdir)
    git_active_commit = Commit()
    HEAD = git_active_repo.head()
    commit = git_active_repo.commit(HEAD)
    tree = git_active_repo.tree(commit.tree)
    git_old_tree = tree.id
    git_active_tree = tree
Esempio n. 43
0
    def test_simple_local(self):
        f1_1 = make_object(Blob, data=b"f1")
        commit_spec = [[1], [2, 1], [3, 1, 2]]
        trees = {
            1: [(b"f1", f1_1), (b"f2", f1_1)],
            2: [(b"f1", f1_1), (b"f2", f1_1)],
            3: [(b"f1", f1_1), (b"f2", f1_1)],
        }

        c1, c2, c3 = build_commit_graph(self.repo.object_store, commit_spec, trees)
        self.repo.refs[b"refs/heads/master"] = c3.id
        self.repo.refs[b"refs/tags/foo"] = c3.id
        target_path = tempfile.mkdtemp()
        errstream = BytesIO()
        self.addCleanup(shutil.rmtree, target_path)
        r = porcelain.clone(self.repo.path, target_path, checkout=False, errstream=errstream)
        self.assertEqual(r.path, target_path)
        target_repo = Repo(target_path)
        self.assertEqual(target_repo.head(), c3.id)
        self.assertEqual(c3.id, target_repo.refs[b"refs/tags/foo"])
        self.assertTrue(b"f1" not in os.listdir(target_path))
        self.assertTrue(b"f2" not in os.listdir(target_path))
Esempio n. 44
0
File: Git.py Progetto: timl/bcfg2
    class GitAPI(GitAPIBase):
        """ API for :class:`Git` using :mod:`dulwich` """
        def __init__(self, path):
            GitAPIBase.__init__(self, path)
            self.repo = Repo(self.path)
            self.client, self.origin_path = get_transport_and_path(
                self.repo.get_config().get(("remote", "origin"),
                                           "url"))

        def revision(self):
            return self.repo.head()

        def pull(self):
            try:
                remote_refs = self.client.fetch(
                    self.origin_path, self.repo,
                    determine_wants=self.repo.object_store.determine_wants_all)
            except KeyError:
                etype, err = sys.exc_info()[:2]
                # try to work around bug
                # https://bugs.launchpad.net/dulwich/+bug/1025886
                try:
                    # pylint: disable=W0212
                    self.client._fetch_capabilities.remove('thin-pack')
                # pylint: enable=W0212
                except KeyError:
                    raise etype(err)
                remote_refs = self.client.fetch(
                    self.origin_path, self.repo,
                    determine_wants=self.repo.object_store.determine_wants_all)

            tree_id = self.repo[remote_refs['HEAD']].tree
            # iterate over tree content, giving path and blob sha.
            for entry in self.repo.object_store.iter_tree_contents(tree_id):
                entry_in_path = entry.in_path(self.repo.path)
                ensure_dir_exists(os.path.split(entry_in_path.path)[0])
                GitFile(entry_in_path.path,
                        'wb').write(self.repo[entry.sha].data)
Esempio n. 45
0
def get_sha_and_dirtiness(
        prompt_on_dirty: bool = True) -> Optional[Tuple[str, bool]]:
    try:
        git_status = status()
    except NotGitRepository:
        return None
    dirty = False

    def to_str(string: Union[str, bytes]) -> str:
        if isinstance(string, str):
            return string
        return string.decode("utf8")

    def print_files(filenames: Iterable[Union[str, bytes]]) -> None:
        print("\n".join(f"  - {to_str(filename)}" for filename in filenames))

    if git_status.untracked:
        print("Those files are untracked:", file=stderr)
        print_files(git_status.untracked)
        dirty = True
    if git_status.unstaged:
        print("Those files are unstaged:", file=stderr)
        print_files(git_status.unstaged)
        dirty = True
    if any(git_status.staged.values()):
        print("Those files are uncommited:", file=stderr)
        print_files(chain(*git_status.staged.values()))
        dirty = True
    if dirty:
        print("Are you sure you want to continue [y/n]? ", end="")
        answer = input()
        if answer != "y":
            exit(1)

    repo = Repo(".")
    sha = to_str(repo.head())
    return sha, dirty
Esempio n. 46
0
File: git.py Progetto: npryce/deft
class GitStorageHistory(object):
    def __init__(self, repodir, storage_root_subdir=os.curdir):
        self.repo = Repo(repodir)
        self.storage_root_subdir = storage_root_subdir
    
    def __getitem__(self, commit_sha):
        commit = self.repo.commit(commit_sha)
        tree = self.repo.tree(commit.tree)
        return GitTreeStorage(self.repo, tree, self.storage_root_subdir)
    
    @property
    def latest_revision(self):
        return self.repo.head()
    
    def eod_revisions(self, max_revision=None):
        if max_revision is None:
            max_revision = self.latest_revision
        
        results = {}
        commit_shas = set([max_revision])
        
        while commit_shas:
            commit_sha = commit_shas.pop()
            commit = self.repo.commit(commit_sha)
            commit_date = date_of(commit)
            
            commit_info = (time_of(commit), commit_sha)
            
            if commit_date in results:
                results[commit_date] = max(results[commit_date], commit_info)
            else:
                results[commit_date] = commit_info
            
            commit_shas.update(commit.parents)
        
        return dict((date, sha) for (date, (time, sha)) in results.iteritems())
Esempio n. 47
0
class Gittle(object):
    """All paths used in Gittle external methods must be paths relative to the git repository
    """

    DEFAULT_COMMIT = "HEAD"
    DEFAULT_BRANCH = "master"
    DEFAULT_REMOTE = "origin"
    DEFAULT_MESSAGE = "**No Message**"
    DEFAULT_USER_INFO = {"name": None, "email": None}

    DIFF_FUNCTIONS = {
        "classic": utils.git.classic_tree_diff,
        "dict": utils.git.dict_tree_diff,
        "changes": utils.git.dict_tree_diff,
    }
    DEFAULT_DIFF_TYPE = "dict"

    HIDDEN_REGEXES = [
        # Hide git directory
        r".*\/\.git\/.*"
    ]

    # References
    REFS_BRANCHES = "refs/heads/"
    REFS_REMOTES = "refs/remotes/"
    REFS_TAGS = "refs/tags/"

    # Name pattern truths
    # Used for detecting if files are :
    # - deleted
    # - added
    # - changed
    PATTERN_ADDED = (False, True)
    PATTERN_REMOVED = (True, False)
    PATTERN_MODIFIED = (True, True)

    # Permissions
    MODE_DIRECTORY = 040000  # Used to tell if a tree entry is a directory

    # Tree depth
    MAX_TREE_DEPTH = 1000

    # Acceptable Root paths
    ROOT_PATHS = (os.path.curdir, os.path.sep)

    def __init__(self, repo_or_path, origin_uri=None, auth=None, report_activity=None, *args, **kwargs):
        if isinstance(repo_or_path, DulwichRepo):
            self.repo = repo_or_path
        elif isinstance(repo_or_path, Gittle):
            self.repo = DulwichRepo(repo_or_path.path)
        elif isinstance(repo_or_path, basestring):
            path = os.path.abspath(repo_or_path)
            self.repo = DulwichRepo(path)
        else:
            logging.warning("Repo is of type %s" % type(repo_or_path))
            raise Exception("Gittle must be initialized with either a dulwich repository or a string to the path")

        # Set path
        self.path = self.repo.path

        # The remote url
        self.origin_uri = origin_uri

        # Report client activty
        self._report_activity = report_activity

        # Build ignore filter
        self.hidden_regexes = copy.copy(self.HIDDEN_REGEXES)
        self.hidden_regexes.extend(self._get_ignore_regexes())
        self.ignore_filter = utils.paths.path_filter_regex(self.hidden_regexes)
        self.filters = [self.ignore_filter]

        # Get authenticator
        if auth:
            self.authenticator = auth
        else:
            self.auth(*args, **kwargs)

    def report_activity(self, *args, **kwargs):
        if not self._report_activity:
            return
        return self._report_activity(*args, **kwargs)

    def _format_author(self, name, email):
        return "%s <%s>" % (name, email)

    def _format_userinfo(self, userinfo):
        name = userinfo.get("name")
        email = userinfo.get("email")
        if name and email:
            return self._format_author(name, email)
        return None

    def _format_ref(self, base, extra):
        return "".join([base, extra])

    def _format_ref_branch(self, branch_name):
        return self._format_ref(self.REFS_BRANCHES, branch_name)

    def _format_ref_remote(self, remote_name):
        return self._format_ref(self.REFS_REMOTES, remote_name)

    def _format_ref_tag(self, tag_name):
        return self._format_ref(self.REFS_TAGS, tag_name)

    @property
    def head(self):
        """Return SHA of the current HEAD
        """
        return self.repo.head()

    @property
    def is_bare(self):
        """Bare repositories have no working directories or indexes
        """
        return self.repo.bare

    @property
    def is_working(self):
        return not (self.is_bare)

    def has_index(self):
        """Opposite of is_bare
        """
        return self.repo.has_index()

    @property
    def has_commits(self):
        """
        If the repository has no HEAD we consider that is has no commits
        """
        try:
            self.repo.head()
        except KeyError:
            return False
        return True

    def ref_walker(self, ref=None):
        """
        Very simple, basic walker
        """
        ref = ref or "HEAD"
        sha = self._commit_sha(ref)
        return self.repo.revision_history(sha)

    def branch_walker(self, branch):
        branch = branch or self.DEFAULT_BRANCH
        ref = self._format_ref_branch(branch)
        return self.ref_walker(ref)

    def commit_info(self, start=0, end=None, branch=None):
        """Return a generator of commits with all their attached information
        """
        if not self.has_commits:
            return []
        commits = [utils.git.commit_info(entry) for entry in self.branch_walker(branch)]
        if not end:
            return commits
        return commits[start:end]

    @funky.uniquify
    def recent_contributors(self, n=None, branch=None):
        n = n or 10
        return funky.pluck(self.commit_info(end=n, branch=branch), "author")

    @property
    def commit_count(self):
        try:
            return len(self.ref_walker())
        except KeyError:
            return 0

    def commits(self):
        """Return a list of SHAs for all the concerned commits
        """
        return [commit["sha"] for commit in self.commit_info()]

    @property
    def git_dir(self):
        return self.repo.controldir()

    def auth(self, *args, **kwargs):
        self.authenticator = GittleAuth(*args, **kwargs)
        return self.authenticator

    # Generate a branch selector (used for pushing)
    def _wants_branch(self, branch_name=None):
        branch_name = branch_name or self.DEFAULT_BRANCH
        refs_key = self._format_ref_branch(branch_name)
        sha = self.branches[branch_name]

        def wants_func(old):
            refs_key = self._format_ref_branch(branch_name)
            return {refs_key: sha}

        return wants_func

    def _get_ignore_regexes(self):
        gitignore_filename = os.path.join(self.path, ".gitignore")
        if not os.path.exists(gitignore_filename):
            return []
        lines = open(gitignore_filename).readlines()
        globers = map(lambda line: line.rstrip(), lines)
        return utils.paths.globers_to_regex(globers)

    # Get the absolute path for a file in the git repo
    def abspath(self, repo_file):
        return os.path.abspath(os.path.join(self.path, repo_file))

    # Get the relative path from the absolute path
    def relpath(self, abspath):
        return os.path.relpath(abspath, self.path)

    @property
    def last_commit(self):
        return self[self.repo.head()]

    @property
    def index(self):
        return self.repo.open_index()

    @classmethod
    def init(cls, path, bare=None, *args, **kwargs):
        """Initialize a repository"""
        mkdir_safe(path)

        # Constructor to use
        if bare:
            constructor = DulwichRepo.init_bare
        else:
            constructor = DulwichRepo.init

        # Create dulwich repo
        repo = constructor(path)

        # Create Gittle repo
        return cls(repo, *args, **kwargs)

    @classmethod
    def init_bare(cls, *args, **kwargs):
        kwargs.setdefault("bare", True)
        return cls.init(*args, **kwargs)

    def get_client(self, origin_uri=None, **kwargs):
        # Get the remote URL
        origin_uri = origin_uri or self.origin_uri

        # Fail if inexistant
        if not origin_uri:
            raise InvalidRemoteUrl()

        client_kwargs = {}
        auth_kwargs = self.authenticator.kwargs()

        client_kwargs.update(auth_kwargs)
        client_kwargs.update(kwargs)
        client_kwargs.update({"report_activity": self.report_activity})

        client, remote_path = get_transport_and_path(origin_uri, **client_kwargs)
        return client, remote_path

    def push_to(self, origin_uri, branch_name=None, progress=None, progress_stderr=None):
        selector = self._wants_branch(branch_name=branch_name)
        client, remote_path = self.get_client(origin_uri, progress_stderr=progress_stderr)
        return client.send_pack(remote_path, selector, self.repo.object_store.generate_pack_contents, progress=progress)

    # Like: git push
    def push(self, origin_uri=None, branch_name=None, progress=None, progress_stderr=None):
        return self.push_to(origin_uri, branch_name, progress, progress_stderr)

    # Not recommended at ALL ... !!!
    def dirty_pull_from(self, origin_uri, branch_name=None):
        # Remove all previously existing data
        rmtree(self.path)
        mkdir_safe(self.path)
        self.repo = DulwichRepo.init(self.path)

        # Fetch brand new copy from remote
        return self.pull_from(origin_uri, branch_name)

    def pull_from(self, origin_uri, branch_name=None):
        return self.fetch(origin_uri)

    # Like: git pull
    def pull(self, origin_uri=None, branch_name=None):
        return self.pull_from(origin_uri, branch_name)

    def fetch_remote(self, origin_uri=None):
        # Get client
        client, remote_path = self.get_client(origin_uri=origin_uri)

        # Fetch data from remote repository
        remote_refs = client.fetch(remote_path, self.repo)

        return remote_refs

    def _setup_fetched_refs(self, refs, origin, bare):
        remote_tags = utils.git.subrefs(refs, "refs/tags")
        remote_heads = utils.git.subrefs(refs, "refs/heads")

        # Filter refs
        clean_remote_tags = utils.git.clean_refs(remote_tags)
        clean_remote_heads = utils.git.clean_refs(remote_heads)

        # Base of new refs
        heads_base = "refs/remotes/" + origin
        if bare:
            heads_base = "refs/heads"

        # Import branches
        self.import_refs(heads_base, clean_remote_heads)

        # Import tags
        self.import_refs("refs/tags", clean_remote_tags)

        # Update HEAD
        self["HEAD"] = refs["HEAD"]

    def fetch(self, origin_uri=None, bare=None, origin=None):
        bare = bare or False
        origin = origin or self.DEFAULT_REMOTE

        # Remote refs
        remote_refs = self.fetch_remote(origin_uri)

        # Update head
        # Hit repo because head doesn't yet exist so
        # print("REFS = %s" % remote_refs)

        # Update refs (branches, tags, HEAD)
        self._setup_fetched_refs(remote_refs, origin, bare)

        # Checkout working directories
        if not bare:
            self.checkout_all()
        else:
            self.update_server_info()

    @classmethod
    def clone(cls, origin_uri, local_path, auth=None, mkdir=True, bare=False, *args, **kwargs):
        """Clone a remote repository"""
        mkdir_safe(local_path)

        # Initialize the local repository
        if bare:
            local_repo = cls.init_bare(local_path)
        else:
            local_repo = cls.init(local_path)

        repo = cls(local_repo, origin_uri=origin_uri, auth=auth, *args, **kwargs)

        repo.fetch(bare=bare)

        # Add origin
        # TODO

        return repo

    @classmethod
    def clone_bare(cls, *args, **kwargs):
        """Same as .clone except clones to a bare repository by default
        """
        kwargs.setdefault("bare", True)
        return cls.clone(*args, **kwargs)

    def _commit(self, committer=None, author=None, message=None, files=None, tree=None, *args, **kwargs):

        if not tree:
            # If no tree then stage files
            modified_files = files or self.modified_files
            logging.warning("STAGING : %s" % modified_files)
            self.add(modified_files)

        # Messages
        message = message or self.DEFAULT_MESSAGE
        author_msg = self._format_userinfo(author)
        committer_msg = self._format_userinfo(committer)

        return self.repo.do_commit(
            message=message, author=author_msg, committer=committer_msg, encoding="UTF-8", tree=tree, *args, **kwargs
        )

    def _tree_from_structure(self, structure):
        # TODO : Support directories
        tree = Tree()

        for file_info in structure:

            # str only
            try:
                data = file_info["data"].encode("ascii")
                name = file_info["name"].encode("ascii")
                mode = file_info["mode"]
            except:
                # Skip file on encoding errors
                continue

            blob = Blob()

            blob.data = data

            # Store file's contents
            self.repo.object_store.add_object(blob)

            # Add blob entry
            tree.add(name, mode, blob.id)

        # Store tree
        self.repo.object_store.add_object(tree)

        return tree.id

    # Like: git commmit -a
    def commit(self, name=None, email=None, message=None, files=None, *args, **kwargs):
        user_info = {"name": name, "email": email}
        return self._commit(committer=user_info, author=user_info, message=message, files=files, *args, **kwargs)

    def commit_structure(self, name=None, email=None, message=None, structure=None, *args, **kwargs):
        """Main use is to do commits directly to bare repositories
        For example doing a first Initial Commit so the repo can be cloned and worked on right away
        """
        if not structure:
            return
        tree = self._tree_from_structure(structure)

        user_info = {"name": name, "email": email}

        return self._commit(committer=user_info, author=user_info, message=message, tree=tree, *args, **kwargs)

    # Push all local commits
    # and pull all remote commits
    def sync(self, origin_uri=None):
        self.push(origin_uri)
        return self.pull(origin_uri)

    def lookup_entry(self, relpath, trackable_files=set()):
        if not relpath in trackable_files:
            raise KeyError

        abspath = self.abspath(relpath)

        with open(abspath, "rb") as git_file:
            data = git_file.read()
            s = sha1()
            s.update("blob %u\0" % len(data))
            s.update(data)
        return (s.hexdigest(), os.stat(abspath).st_mode)

    @property
    @funky.transform(set)
    def tracked_files(self):
        return list(self.index)

    @property
    @funky.transform(set)
    def raw_files(self):
        return utils.paths.subpaths(self.path)

    @property
    @funky.transform(set)
    def ignored_files(self):
        return utils.paths.subpaths(self.path, filters=self.filters)

    @property
    @funky.transform(set)
    def trackable_files(self):
        return self.raw_files - self.ignored_files

    @property
    @funky.transform(set)
    def untracked_files(self):
        return self.trackable_files - self.tracked_files

    """
    @property
    @funky.transform(set)
    def modified_staged_files(self):
        "Checks if the file has changed since last commit"
        timestamp = self.last_commit.commit_time
        index = self.index
        return [
            f
            for f in self.tracked_files
            if index[f][1][0] > timestamp
        ]
    """

    # Return a list of tuples
    # representing the changed elements in the git tree
    def _changed_entries(self, ref=None):
        ref = ref or self.DEFAULT_COMMIT
        if not self.has_commits:
            return []
        obj_sto = self.repo.object_store
        tree_id = self[ref].tree
        names = self.trackable_files

        lookup_func = partial(self.lookup_entry, trackable_files=names)

        # Format = [((old_name, new_name), (old_mode, new_mode), (old_sha, new_sha)), ...]
        tree_diff = changes_from_tree(names, lookup_func, obj_sto, tree_id, want_unchanged=False)
        return list(tree_diff)

    @funky.transform(set)
    def _changed_entries_by_pattern(self, pattern):
        changed_entries = self._changed_entries()
        filtered_paths = [
            funky.first_true(names)
            for names, modes, sha in changed_entries
            if tuple(map(bool, names)) == pattern and funky.first_true(names)
        ]

        return filtered_paths

    @property
    @funky.transform(set)
    def removed_files(self):
        return self._changed_entries_by_pattern(self.PATTERN_REMOVED) - self.ignored_files

    @property
    @funky.transform(set)
    def added_files(self):
        return self._changed_entries_by_pattern(self.PATTERN_ADDED) - self.ignored_files

    @property
    @funky.transform(set)
    def modified_files(self):
        modified_files = self._changed_entries_by_pattern(self.PATTERN_MODIFIED) - self.ignored_files
        return modified_files

    @property
    @funky.transform(set)
    def modified_unstaged_files(self):
        timestamp = self.last_commit.commit_time
        return [f for f in self.tracked_files if os.stat(self.abspath(f)).st_mtime > timestamp]

    @property
    def pending_files(self):
        """
        Returns a list of all files that could be possibly staged
        """
        # Union of both
        return self.modified_files | self.added_files | self.removed_files

    @property
    def pending_files_by_state(self):
        files = {"modified": self.modified_files, "added": self.added_files, "removed": self.removed_files}

        # "Flip" the dictionary
        return {path: state for state, paths in files.items() for path in paths}

    """
    @property
    @funky.transform(set)
    def modified_files(self):
        return self.modified_staged_files | self.modified_unstaged_files
    """

    # Like: git add
    @funky.arglist_method
    def stage(self, files):
        return self.repo.stage(files)

    def add(self, *args, **kwargs):
        return self.stage(*args, **kwargs)

    # Like: git rm
    @funky.arglist_method
    def rm(self, files, force=False):
        index = self.index
        index_files = filter(lambda f: f in index, files)
        for f in index_files:
            del self.index[f]
        return index.write()

    def mv_fs(self, file_pair):
        old_name, new_name = file_pair
        os.rename(old_name, new_name)

    # Like: git mv
    @funky.arglist_method
    def mv(self, files_pair):
        index = self.index
        files_in_index = filter(lambda f: f[0] in index, files_pair)
        map(self.mv_fs, files_in_index)
        old_files = map(funky.first, files_in_index)
        new_files = map(funky.last, files_in_index)
        self.add(new_files)
        self.rm(old_files)
        self.add(old_files)
        return

    @working_only
    def _checkout_tree(self, tree):
        return build_index_from_tree(self.repo.path, self.repo.index_path(), self.repo.object_store, tree)

    def checkout_all(self, commit_sha=None):
        commit_sha = commit_sha or self.head
        commit_tree = self._commit_tree(commit_sha)
        # Rebuild index from the current tree
        return self._checkout_tree(commit_tree)

    def checkout(self, commit_sha=None, files=None):
        """Checkout only a select amount of files
        """
        commit_sha = commit_sha or self.head
        files = files or []

        return self

    @funky.arglist_method
    def reset(self, files, commit="HEAD"):
        pass

    def rm_all(self):
        self.index.clear()
        return self.index.write()

    def _to_commit(self, commit_obj):
        """Allows methods to accept both SHA's or dulwich Commit objects as arguments
        """
        if isinstance(commit_obj, basestring):
            return self.repo[commit_obj]
        return commit_obj

    def _commit_sha(self, commit_obj):
        """Extracts a Dulwich commits SHA
        """
        if utils.git.is_sha(commit_obj):
            return commit_obj
        elif isinstance(commit_obj, basestring):
            # Can't use self[commit_obj] to avoid infinite recursion
            commit_obj = self.repo[commit_obj]
        return commit_obj.id

    def _blob_data(self, sha):
        """Return a blobs content for a given SHA
        """
        return self[sha].data

    # Get the nth parent back for a given commit
    def get_parent_commit(self, commit, n=None):
        """ Recursively gets the nth parent for a given commit
            Warning: Remember that parents aren't the previous commits
        """
        if n is None:
            n = 1
        commit = self._to_commit(commit)
        parents = commit.parents

        if n <= 0 or not parents:
            # Return a SHA
            return self._commit_sha(commit)

        parent_sha = parents[0]
        parent = self[parent_sha]

        # Recur
        return self.get_parent_commit(parent, n - 1)

    def get_previous_commit(self, commit_ref, n=None):
        commit_sha = self._parse_reference(commit_ref)
        n = n or 1
        commits = self.commits()
        return funky.next(commits, commit_sha, n=n, default=commit_sha)

    def _parse_reference(self, ref_string):
        # COMMIT_REF~x
        if "~" in ref_string:
            ref, count = ref_string.split("~")
            count = int(count)
            commit_sha = self._commit_sha(ref)
            return self.get_previous_commit(commit_sha, count)
        return self._commit_sha(ref_string)

    def _commit_tree(self, commit_sha):
        """Return the tree object for a given commit
        """
        return self[commit_sha].tree

    def diff(self, commit_sha, compare_to=None, diff_type=None, filter_binary=True):
        diff_type = diff_type or self.DEFAULT_DIFF_TYPE
        diff_func = self.DIFF_FUNCTIONS[diff_type]

        if not compare_to:
            compare_to = self.get_previous_commit(commit_sha)

        return self._diff_between(compare_to, commit_sha, diff_function=diff_func)

    def diff_working(self, ref=None, filter_binary=True):
        """Diff between the current working directory and the HEAD
        """
        return utils.git.diff_changes_paths(
            self.repo.object_store, self.path, self._changed_entries(ref=ref), filter_binary=filter_binary
        )

    def get_commit_files(self, commit_sha, parent_path=None, is_tree=None, paths=None):
        """Returns a dict of the following Format :
            {
                "directory/filename.txt": {
                    'name': 'filename.txt',
                    'path': "directory/filename.txt",
                    "sha": "xxxxxxxxxxxxxxxxxxxx",
                    "data": "blablabla",
                    "mode": 0xxxxx",
                },
                ...
            }
        """
        # Default values
        context = {}
        is_tree = is_tree or False
        parent_path = parent_path or ""

        if is_tree:
            tree = self[commit_sha]
        else:
            tree = self[self._commit_tree(commit_sha)]

        for mode, path, sha in tree.entries():
            # Check if entry is a directory
            if mode == self.MODE_DIRECTORY:
                context.update(
                    self.get_commit_files(sha, parent_path=os.path.join(parent_path, path), is_tree=True, paths=paths)
                )
                continue

            subpath = os.path.join(parent_path, path)

            # Only add the files we want
            if not (paths is None or subpath in paths):
                continue

            # Add file entry
            context[subpath] = {"name": path, "path": subpath, "mode": mode, "sha": sha, "data": self._blob_data(sha)}
        return context

    def file_versions(self, path):
        """Returns all commits where given file was modified
        """
        versions = []
        commits_info = self.commit_info()
        seen_shas = set()

        for commit in commits_info:
            try:
                files = self.get_commit_files(commit["sha"], paths=[path])
                file_path, file_data = files.items()[0]
            except IndexError:
                continue

            file_sha = file_data["sha"]

            if file_sha in seen_shas:
                continue
            else:
                seen_shas.add(file_sha)

            # Add file info
            commit["file"] = file_data
            versions.append(file_data)
        return versions

    def _diff_between(self, old_commit_sha, new_commit_sha, diff_function=None, filter_binary=True):
        """Internal method for getting a diff between two commits
            Please use .diff method unless you have very speciic needs
        """

        # If commit is first commit (new_commit_sha == old_commit_sha)
        # then compare to an empty tree
        if new_commit_sha == old_commit_sha:
            old_tree = Tree()
        else:
            old_tree = self._commit_tree(old_commit_sha)

        new_tree = self._commit_tree(new_commit_sha)

        return diff_function(self.repo.object_store, old_tree, new_tree, filter_binary=filter_binary)

    def changes(self, *args, **kwargs):
        """ List of changes between two SHAs
            Returns a list of lists of tuples :
            [
                [
                    (oldpath, newpath), (oldmode, newmode), (oldsha, newsha)
                ],
                ...
            ]
        """
        kwargs["diff_type"] = "changes"
        return self.diff(*args, **kwargs)

    def changes_count(self, *args, **kwargs):
        return len(self.changes(*args, **kwargs))

    def _refs_by_pattern(self, pattern):
        refs = self.refs

        def item_filter(key_value):
            """Filter only concered refs"""
            key, value = key_value
            return key.startswith(pattern)

        def item_map(key_value):
            """Rewrite keys"""
            key, value = key_value
            new_key = key[len(pattern) :]
            return (new_key, value)

        return dict(map(item_map, filter(item_filter, refs.items())))

    @property
    def refs(self):
        return self.repo.get_refs()

    def set_refs(refs_dict):
        for k, v in refs_dict.items():
            self.repo[k] = v

    def import_refs(self, base, other):
        return self.repo.refs.import_refs(base, other)

    @property
    def branches(self):
        return self._refs_by_pattern(self.REFS_BRANCHES)

    def _active_branch(self, refs=None, head=None):
        head = head or self.head
        refs = refs or self.branches
        try:
            return {branch: branch_head for branch, branch_head in refs.items() if branch_head == head}.items()[0]
        except IndexError:
            pass
        return (None, None)

    @property
    def active_branch(self):
        return self._active_branch()[0]

    @property
    def active_sha(self):
        return self._active_branch()[1]

    @property
    def remote_branches(self):
        return self._refs_by_pattern(self.REFS_REMOTES)

    @property
    def tags(self):
        return self._refs_by_pattern(self.REFS_TAGS)

    @property
    def remotes(self):
        """ Dict of remotes
        {
            'origin': 'http://friendco.de/some_user/repo.git',
            ...
        }
        """
        config = self.repo.get_config()
        return {keys[1]: values["url"] for keys, values in config.items() if keys[0] == "remote"}

    def add_ref(self, new_ref, old_ref):
        self.repo.refs[new_ref] = self.repo.refs[old_ref]
        self.update_server_info()

    def remove_ref(self, ref_name):
        # Returns False if ref doesn't exist
        if not ref_name in self.repo.refs:
            return False
        del self.repo.refs[ref_name]
        self.update_server_info()
        return True

    def create_branch(self, base_branch, new_branch, tracking=None):
        """Try creating a new branch which tracks the given remote
            if such a branch does not exist then branch off a local branch
        """

        # The remote to track
        tracking = self.DEFAULT_REMOTE

        # Already exists
        if new_branch in self.branches:
            raise Exception("branch %s already exists" % new_branch)

        # Get information about remote_branch
        remote_branch = os.path.sep.join([tracking, base_branch])

        # Fork Local
        if base_branch in self.branches:
            base_ref = self._format_ref_branch(base_branch)
        # Fork remote
        elif remote_branch in self.remote_branches:
            base_ref = self._format_ref_remote(remote_branch)
            # TODO : track
        else:
            raise Exception(
                "Can not find the branch named '%s' to fork either locally or in '%s'" % (base_branch, tracking)
            )

        # Reference of new branch
        new_ref = self._format_ref_branch(new_branch)

        # Copy reference to create branch
        self.add_ref(new_ref, base_ref)

        return new_ref

    def remove_branch(self, branch_name):
        ref = self._format_ref_branch(branch_name)
        return self.remove_ref(ref)

    def switch_branch(self, branch_name, tracking=None, create=None):
        """Changes the current branch
        """
        if create is None:
            create = True

        # Check if branch exists
        if not branch_name in self.branches:
            self.create_branch(branch_name, branch_name, tracking=tracking)

        # Get branch reference
        branch_ref = self._format_ref_branch(branch_name)

        # Change main branch
        self.repo.refs.set_symbolic_ref("HEAD", branch_ref)

        if self.is_working:
            # Remove all files
            self.clean_working()

            # Add files for the current branch
            self.checkout_all()

    def clean(self, force=None, directories=None):
        untracked_files = self.untracked_files
        map(os.remove, untracked_files)
        return untracked_files

    def clean_working(self):
        """Purges all the working (removes everything except .git)
            used by checkout_all to get clean branch switching
        """
        return self.clean()

    def _get_fs_structure(self, tree_sha, depth=None, parent_sha=None):
        tree = self[tree_sha]
        structure = {}
        if depth is None:
            depth = self.MAX_TREE_DEPTH
        elif depth == 0:
            return structure
        for mode, path, sha in tree.entries():
            # tree
            if mode == self.MODE_DIRECTORY:
                # Recur
                structure[path] = self._get_fs_structure(sha, depth=depth - 1, parent_sha=tree_sha)
            # commit
            else:
                structure[path] = sha
        structure["."] = tree_sha
        structure[".."] = parent_sha or tree_sha
        return structure

    def _get_fs_structure_by_path(self, tree_sha, path):
        parts = path.split(os.path.sep)
        depth = len(parts) + 1
        structure = self._get_fs_structure(tree_sha, depth=depth)

        return funky.subkey(structure, parts)

    def commit_ls(self, ref, subpath=None):
        """List a "directory" for a given commit
            using the tree of thqt commit
        """
        tree_sha = self._commit_tree(ref)

        # Root path
        if subpath in self.ROOT_PATHS or not subpath:
            return self._get_fs_structure(tree_sha, depth=1)
        # Any other path
        return self._get_fs_structure_by_path(tree_sha, subpath)

    def commit_file(self, ref, path):
        """Return info on a given file for a given commit
        """
        name, info = self.get_commit_files(ref, paths=[path]).items()[0]
        return info

    def commit_tree(self, ref, *args, **kwargs):
        tree_sha = self._commit_tree(ref)
        return self._get_fs_structure(tree_sha, *args, **kwargs)

    def update_server_info(self):
        if not self.is_bare:
            return
        update_server_info(self.repo)

    def _is_fast_forward(self):
        pass

    def _merge_fast_forward(self):
        pass

    def __hash__(self):
        """This is required otherwise the memoize function will just mess it up
        """
        return hash(self.path)

    def __getitem__(self, key):
        sha = self._parse_reference(key)
        return self.repo[sha]

    def __setitem__(self, key, value):
        self.repo[key] = value

    # Alias to clone_bare
    fork = clone_bare
    log = commit_info
    diff_count = changes_count
    comtributors = recent_contributors
Esempio n. 48
0
#!/usr/bin/env python2

import os.path
import urlparse
from email.utils import formatdate
from dulwich.repo import Repo
from dulwich.objects import Blob, Tree, Commit
from docutils import io, nodes
from docutils.core import publish_doctree, publish_from_doctree
from render import MyWriter

repo = Repo(".")
commit_sha = repo.head()
commit = repo.get_object(commit_sha)
index = repo.open_index()
assert not list(index.changes_from_tree(repo.object_store, commit.tree)), "uncommited changes"

store = repo.object_store


def render_rst(blob, path):
    doc = publish_doctree(blob.as_raw_string())
    for node in doc.traverse(nodes.reference):
        uri = urlparse.urlparse(node['refuri'])
        if not uri.netloc and os.path.basename(uri.path) == "README.rst":
            node['refuri'] = urlparse.urlunparse(
                (uri.scheme, uri.netloc, uri.path[:-10] or "./", uri.params, uri.query, uri.fragment))

    output = publish_from_doctree(
        doc,
        destination_path=path,
Esempio n. 49
0
 def get_version(cls):
     from dulwich.repo import Repo
     repo = Repo(cls.src_path)
     return cls.version + "git" + repo.head()
Esempio n. 50
0
class Repo(object):
    """
    Wrapper around a libgit Repository that knows:

    * How to get all the files in the repository
    * How to get the oid of HEAD
    * How to get the commit times of the files we want commit times for

    It's written with speed in mind, given the constraints of making
    performant code in python!
    """
    def __init__(self, root_folder):
        self.git = Repository(root_folder)

    def all_files(self):
        """Return a set of all the files under git control"""
        return set([entry.decode() for entry, _ in self.git.open_index().items()])

    @property
    def first_commit(self):
        """Return the oid of HEAD"""
        return self.git.head().decode()

    def file_commit_times(self, use_files_paths, debug=False):
        """
        Traverse the commits in the repository, starting from HEAD until we have
        found the commit times for all the files we care about.

        Yield each file once, only when it is found to be changed in some commit.

        If self.debug is true, also output log.debug for the speed we are going
        through commits (output commits/second every 1000 commits and every
        100000 commits)
        """
        prefixes = PrefixTree()
        prefixes.fill(use_files_paths)

        for entry in self.git.get_walker():
            # Commit time taking into account the timezone
            commit_time = entry.commit.commit_time - entry.commit.commit_timezone

            # Get us the two different tree structures between parents and current
            cf_and_pf, changes = self.tree_structures_for(()
                , entry.commit.tree
                , [self.git.get_object(oid).tree for oid in entry.commit.parents]
                , prefixes
                )

            # Deep dive into any differences
            difference = []
            if changes:
                cfs_and_pfs = [(cf_and_pf, changes)]
                while cfs_and_pfs:
                    nxt, changes = cfs_and_pfs.pop(0)
                    for thing, changes, is_path in self.differences_between(nxt[0], nxt[1], changes, prefixes):
                        if is_path:
                            found = prefixes.remove(thing[:-1], thing[-1])
                            if found:
                                difference.append('/'.join(thing))
                        else:
                            cfs_and_pfs.append((thing, changes))

            # Only yield if there was a difference
            if difference:
                yield entry.commit.sha().hexdigest(), commit_time, difference

            # If nothing remains, then break!
            if not prefixes:
                break

    def entries_in_tree_oid(self, prefix, tree_oid):
        """Find the tree at this oid and return entries prefixed with ``prefix``"""
        try:
            tree = self.git.get_object(tree_oid)
        except KeyError:
            log.warning("Couldn't find object {0}".format(tree_oid))
            return empty
        else:
            return frozenset(self.entries_in_tree(prefix, tree))

    def entries_in_tree(self, prefix, tree):
        """
        Traverse the entries in this tree and yield (prefix, is_tree, oid)

        Where prefix is a tuple of the given prefix and the name of the entry.
        """
        for entry in tree.items():
            if prefix:
                new_prefix = prefix + (entry.path.decode(), )
            else:
                new_prefix = (entry.path.decode(), )

            yield (new_prefix, stat.S_ISDIR(entry.mode), entry.sha)

    def tree_structures_for(self, prefix, current_oid, parent_oids, prefixes):
        """
        Return the entries for this commit, the entries of the parent commits,
        and the difference between the two (current_files - parent_files)
        """
        if prefix and prefixes and prefix not in prefixes:
            return empty, empty

        parent_files = set()
        for oid in parent_oids:
            parent_files.update(self.entries_in_tree_oid(prefix, oid))

        current_files = self.entries_in_tree_oid(prefix, current_oid)
        return (current_files, parent_files), (current_files - parent_files)

    def differences_between(self, current_files, parent_files, changes, prefixes):
        """
        yield (thing, changes, is_path)

        If is_path is true, changes is None and thing is the path as a tuple.

        If is_path is false, thing is the current_files and parent_files for
        that changed treeentry and changes is the difference between current_files
        and parent_files.

        The code here is written to squeeze as much performance as possible out
        of this operation.
        """
        parent_oid = None

        if any(is_tree for _, is_tree, _ in changes):
            if len(changes) == 1:
                wanted_path = list(changes)[0][0]
                parent_oid = frozenset([oid for path, is_tree, oid in parent_files if path == wanted_path and is_tree])
            else:
                parent_values = defaultdict(set)
                parent_changes = parent_files - current_files
                for path, is_tree, oid in parent_changes:
                    if is_tree:
                        parent_values[path].add(oid)

        for path, is_tree, oid in changes:
            if is_tree and path not in prefixes:
                continue

            if not is_tree:
                yield path, None, True
            else:
                parent_oids = parent_oid if parent_oid is not None else parent_values.get(path, empty)
                cf_and_pf, changes = self.tree_structures_for(path, oid, parent_oids, prefixes)
                if changes:
                    yield cf_and_pf, changes, False
Esempio n. 51
0
def git_commit_info():
    git = Repo('.')
    commit = git.get_object(git.head())
    return {'id': commit.id.decode("utf-8")[0:7], 'id_full': commit.id.decode("utf-8"),
            'author': regex.findall("(.*?) <(.*?)>", commit.author.decode("utf-8"))[0],
            'message': commit.message.decode("utf-8").strip('\r\n').split('\n')[0]}
Esempio n. 52
0
    def clone(
        cls,
        url: str,
        name: str | None = None,
        branch: str | None = None,
        tag: str | None = None,
        revision: str | None = None,
        source_root: Path | None = None,
        clean: bool = False,
    ) -> Repo:
        source_root = source_root or cls.get_default_source_root()
        source_root.mkdir(parents=True, exist_ok=True)

        name = name or cls.get_name_from_source_url(url=url)
        target = source_root / name
        refspec = GitRefSpec(branch=branch, revision=revision, tag=tag)

        if target.exists():
            if clean:
                # force clean the local copy if it exists, do not reuse
                remove_directory(target, force=True)
            else:
                # check if the current local copy matches the requested ref spec
                try:
                    current_repo = Repo(str(target))  # type: ignore[no-untyped-call]

                    with current_repo:
                        current_sha = current_repo.head().decode("utf-8")
                except (NotGitRepository, AssertionError, KeyError):
                    # something is wrong with the current checkout, clean it
                    remove_directory(target, force=True)
                else:
                    if not is_revision_sha(revision=current_sha):
                        # head is not a sha, this will cause issues later, lets reset
                        remove_directory(target, force=True)
                    elif (
                        refspec.is_sha
                        and refspec.revision is not None
                        and current_sha.startswith(refspec.revision)
                    ):
                        # if revision is used short-circuit remote fetch head matches
                        return current_repo

        try:
            if not cls.is_using_legacy_client():
                local = cls._clone(url=url, refspec=refspec, target=target)
                cls._clone_submodules(repo=local)
                return local
        except HTTPUnauthorized:
            # we do this here to handle http authenticated repositories as dulwich
            # does not currently support using credentials from git-credential helpers.
            # upstream issue: https://github.com/jelmer/dulwich/issues/873
            #
            # this is a little inefficient, however preferred as this is transparent
            # without additional configuration or changes for existing projects that
            # use http basic auth credentials.
            logger.debug(
                "Unable to fetch from private repository '%s', falling back to"
                " system git",
                url,
            )

        # fallback to legacy git client
        return cls._clone_legacy(url=url, refspec=refspec, target=target)
Esempio n. 53
0
        if n == 0: break
    return ''.join(reversed(s))

CACHE_PREFIX = num_encode(os.getpid()) + '.'
CACHE_PREFIX += '.'.join(str(num_encode(int(p))) for p in str(time.time()).split('.'))

try:
    BACKLOG_ARCHIVE = settings.BACKLOG_ARCHIVE
    if not os.path.exists(os.path.join(BACKLOG_ARCHIVE, '.git')):
        BACKLOG_ARCHIVE = None
except AttributeError:
    BACKLOG_ARCHIVE = None
except ImportError:
    BACKLOG_ARCHIVE = None

RELEASE = None
__projectdir__ = os.path.abspath(os.path.dirname(__file__))
while __projectdir__ != '/' and not os.path.exists(os.path.join(__projectdir__, 'settings.py')):
    __projectdir__ = os.path.dirname(__projectdir__)
if __projectdir__ != '/' and os.path.exists(os.path.join(__projectdir__, '.git')):
    repo = Repo(__projectdir__)
    for commit in repo.revision_history(repo.head()):
        RELEASE = 'Git: ' + commit.tree
        break
if RELEASE is None:
    try:
        import agilitorelease
        RELEASE = agilitorelease.RELEASE
    except:
        pass
Esempio n. 54
0
class GitStorage():
    def _ignoreFile(self, dirName, fileName):
        """
        used for the copTree stuff
        ``dirName``
            the working directory
        ``fileName``
            list of files inside the directory (dirName)
        """
        result = []
        for i in fileName:
            path = dirName + i
            if path not in fileToIgnore:
                result.append(path)
        return result

    def _commit(self, tree):
        """
        commit a tree used only by the init
        ``tree``
            tree to commit
        """
        commit = Commit()
        commit.tree = tree.id
        commit.encoding = "UTF-8"
        commit.committer = commit.author = 'debexpo <%s>' % (pylons.config['debexpo.email'])
        commit.commit_time = commit.author_time = int(time())
        tz = parse_timezone('-0200')[0]
        commit.commit_timezone = commit.author_timezone = tz
        commit.message = " "
        self.repo.object_store.add_object(tree)
        self.repo.object_store.add_object(commit)
        self.repo.refs["HEAD"] = commit.id
        log.debug('commiting')
        return commit.id

    def __init__(self, path):
        #creating the repository
        if os.path.isdir(path):
            log.debug("directory exist, taking it as a git repository")
            self.repo = Repo(path)
        else:
            log.debug("directory doesn't exist, creating")
            os.makedirs(path)
            log.debug("initiate the repo")
            self.repo = Repo.init(path)
            log.debug("adding an empty tree to the repository")
            self._commit(Tree())

    #only this function will be used on upload
    def change(self, files):
        """
        used to change  afile in the git storage can be called for the first upload we don't care
        ``files``
            a list of file to change
        """
        if len(files) == 0:
            log.debug("trying to change nothing will do... nothing")
        else:
            log.debug("this will change %i files" % (len(files)))
            for f in files:
                self.repo.stage(str(f))
            log.debug("stages dones")
            self.repo.do_commit("this is so awesome that nobody will never see it",
                committer="same here <*****@*****.**>")

    def buildTreeDiff(self, dest, tree=None, originalTree=None):
        """
        creating files from the diff between 2 trees, it will be used in the code browser to get older version
        (walking on history)
        ``tree``
            the tree that you want to compare to
        ``dest``
            the destination folder to build sources
        ``originalTree``
            the original Tree, by default it's the last one

        by default it's retun the last changed files

        """
        if tree is None:
            head = self.repo.commit(self.repo.commit(self.repo.head()).parents[0])
            tree = self.repo.tree(head.tree)
        if originalTree is None:
            originalTree = self.repo.tree(self.repo.commit(self.repo.head()).tree)
        blobToBuild = []
        #getting blob that have changed
        for blob in self.repo.object_store.iter_tree_contents(tree.id):
            if blob not in originalTree:
                blobToBuild.append(blob)
                fileToIgnore.append(blob.path)
        repoLocation = os.path.join(str(self.repo).split("'")[1])
        #creating the folder with link to older files
        if os.path.exists(repoLocation + dest):
            log.warning("%s already exist, copy will not work")
        else:
            log.debug("copying files")
            shutil.copytree(repoLocation, repoLocation + dest, symlinks=True, ignore=self._ignoreFile)
        for b in blobToBuild:
            fileDirectory = os.path.split(b.path)
            fileDirectory.pop()
            if not os.path.exists(os.path.join(repoLocation + dest, os.path.join(fileDirectory))):
                os.makedirs(os.path.join(repoLocation + dest, os.path.join(fileDirectory)))
            file = open(os.path.join(repoLocation + dest, b.path), 'w')
            file.write(self.repo.get_object(b.sha).as_raw_string())
            file.close()
        tree = None
        originalTree = None

    #get*
    def getLastTree(self):
        """
        return the last tree
        """
        return self.repo.tree(self.repo._commit(self.repo.head()).tree)

    def getAllTrees(self):
        """
        return trees
        """
        result = []
        commit = self.repo._commit(self.repo.head())
        for c in commit._get_parents():
            result.append(c.tree)
        return result

    def getOlderFileContent(self, file):
        """
        return the first file's content that changed from the file
        ``file``
            the file to work on
        """
        with open(file) as f:
            originalBlob = Blob.from_string("".join(f.readlines()))
        trees = self.getAllTrees()
        for t in trees:
            #parsing tree in order to find the tree where the file change
            if originalBlob not in t:
                tree = t
                break
                #tree must be existent, other way file is not correct
        if tree is None:
            log.error(
                "there is no tree that contain this blob this souldn't happen, other way this file does not appear to come from this package")
        else:
            if self.repo._commit(self.repo.head()).tree == tree:
                olderTree = self.repo.commit(self.repo.head())._get_parents()[0].tree
            else:
                for c in self.repo._commit(self.repo.head())._get_parents():
                    if c.tree == tree:
                        try:
                            olderTree = c.get_parents()[0]
                        except IndexError:
                            log.debug("file is the last version")
                            olderTree = tree
            if olderTree != tree:
                #we must check here the blob that contains the older file
                for b in self.repo.object_store.iter_tree_contents(olderTree.id):
                    if originalBlob.path == b.path:
                        #older blob find! awesome, in the first loop we already test if they are the same
                        # that's why we can now return the content of the file
                        return self.repo.get_object(b.sha).as_raw_string()
        return ""

    def getOlderCommits(self):
        """
        return a list of all commits
        """
        return self.repo.commit(self.repo.head())._get_parents()
Esempio n. 55
0
# -*- coding: utf-8 -*-

from distutils.core import setup

try:
    from dulwich.repo import Repo
    repo = Repo('.')
    version = repo.head()
except:
    version = 'unknown'

datafiles = []

setup(name='vcsstats',
      version=version,
      author='Henrik Stuart, Alexander Færøy',
      author_email='*****@*****.**',
      url='http://github.com/ahf/vcsstats/tree/master',
      description='Version control system statistics',
      license='MIT',
      scripts=[],
      data_files=datafiles,
      packages=['vcsstatslib', 'vcsstatslib.charts']
      )
Esempio n. 56
0
    def edit(self, content=None, username=None, *virtual_path, **keywords):
        '''id: the git id of the blob before it was edited
        branch: master (default)'''
        #setup the defaults
        branch = "master"
        url = ManagedPath(virtual_path)
        if "branch" in keywords: branch = keywords["branch"]
        sha = self.sha
        print "sha is: ", sha
        print "keywords: ", keywords

        commit = sha
        print "content is: ", content
        print "self.filename is: ", self.filename
        if content is None:
            repo = Repo(self.package.path())
            set_head(repo, branch)
            if not sha:
                print "repo.head() = ", repo.head()
                sha = dulwich.object_store.tree_lookup_path(repo.get_object, repo.get_object(repo.head()).tree, self.filename)[1]
            obj = repo.get_object(sha)
            
            contents = obj.as_pretty_string()
            return_contents = "<form action=\"" + cherrypy.url() + "\" method=\"POST\">"
            return_contents = return_contents + "<textarea name=content rows='20' cols='120'>" + contents + "</textarea><br />"
            #if the user isn't logged in ...
            if not hasattr(cherrypy.session, "login"): return_contents = return_contents + "username: <input type=text name=username value=\"anonymous\"><br />"
            if sha: return_contents = return_contents + "<input type=hidden name=id value=\"" + sha + "\">"
            return_contents = return_contents + "<input type=hidden name=\"branch\" value=\"" + branch + "\">"
            return_contents = return_contents + "<input type=submit name=submit value=edit></form>"
            self.content = return_contents
            self.branch = branch
            return self.respond()
        elif (sha or branch): #it's been edited
            if username==None and hasattr(cherrypy.session, "login"): 
                if cherrypy.session.login==None: raise ValueError, "FileViewer.edit: no username supplied"
            elif username==None or username=="anonymous":
                anon = True #whether or not the user is anonymous
                if SESSION_KEY in cherrypy.session.keys():
                    username = cherrypy.session[SESSION_KEY].username
                    anon = False
                else: username = "******"

                #at least until we get access control lists working
                if anon:
                    if branch=="master": #don't let anonymous users modify branch "master"
                        branch = "anonymous"
                    branch = "anonymous"
                
                #make the blob
                blob = Blob.from_string(content)
                
                repo = Repo(self.package.path())
                #change to the right branch
                last_head = repo.head()
                set_head(repo, "master")
                last_commit = repo.get_object(repo.head())
                tree = repo.tree(repo.get_object(repo.head()).tree)

                #set the file
                tree[self.filename] = (0100644, blob.id)
                
                #make the commit
                commit = Commit()
                commit.tree = tree.id
                commit.parents = [last_head]
                commit.author = commit.committer = username
                commit.commit_time = commit.author_time = int(time.time())
                commit.commit_timezone = commit.author_timezone = parse_timezone("-0600")
                commit.encoding = "UTF-8"
                commit.message = "not implemented yet"

                repo.object_store.add_object(blob)
                repo.object_store.add_object(tree)
                repo.object_store.add_object(commit)
                repo.refs["refs/heads/" + branch] = commit.id
                repo.refs["HEAD"] = "ref: refs/heads/" + branch
                new_link = "<a href=\"/package/" + self.package.name + ":" + branch + "/" + self.filename + "/" + blob.id + "\">go to the new version</a>"
                self.new_link = new_link

            self.content = add_newlines("edited (name=%s, branch=%s, sha=%s) new link: %s\n\n\n" % (username, branch, sha, new_link))
            self.content = self.content + "<pre>" + content + "</pre>"
            self.branch = branch

            return self.respond()
Esempio n. 57
0
class GitRepo(object):
    def __init__(self, path):
        if os.path.exists(path):
            if not os.path.isdir(path):
                raise IOError('Git repository "%s" must be a directory.' %
                              path)
        try:
            self.repo = Repo(path)
        except NotGitRepository:
            # repo does not exist
            self.repo = Repo.init(path, not os.path.exists(path))
    
        self.temp_persist_files = []

    def _get_commit(self, version="HEAD"):
        commit = self.repo[version]
        if not isinstance(commit, Commit):
            raise NotCommitError(commit)
        return commit

    def get_type(self, name, version="HEAD"):
        commit = self._get_commit(version)

        tree = self.repo.tree(commit.tree)
        if name not in tree:
            raise KeyError('Cannot find object "%s"' % name)
        if tree[name][0] & stat.S_IFDIR:
            return "tree"
        else:
            return "blob"

    def get_path(self, name, version="HEAD", path_type=None, out_name=None,
                 out_suffix=''):
        if path_type is None:
            path_type = self.get_type(name, version)
        if path_type == 'tree':
            return self.get_dir(name, version, out_name, out_suffix)
        elif path_type == 'blob':
            return self.get_file(name, version, out_name, out_suffix)

        raise TypeError("Unknown path type '%s'" % path_type)

    def _write_blob(self, blob_sha, out_fname=None, out_suffix=''):
        if out_fname is None:
            # create a temporary file
            (fd, out_fname) = tempfile.mkstemp(suffix=out_suffix,
                                               prefix='vt_persist')
            os.close(fd)
            self.temp_persist_files.append(out_fname)
        else:
            out_dirname = os.path.dirname(out_fname)
            if out_dirname and not os.path.exists(out_dirname):
                os.makedirs(out_dirname)
        
        blob = self.repo.get_blob(blob_sha)
        with open(out_fname, "wb") as f:
            for b in blob.as_raw_chunks():
                f.write(b)
        return out_fname

    def get_file(self, name, version="HEAD", out_fname=None, 
                 out_suffix=''):
        commit = self._get_commit(version)
        tree = self.repo.tree(commit.tree)
        if name not in tree:
            raise KeyError('Cannot find blob "%s"' % name)
        blob_sha = tree[name][1]
        out_fname = self._write_blob(blob_sha, out_fname, out_suffix)
        return out_fname

    def get_dir(self, name, version="HEAD", out_dirname=None, 
                out_suffix=''):
        if out_dirname is None:
            # create a temporary directory
            out_dirname = tempfile.mkdtemp(suffix=out_suffix,
                                           prefix='vt_persist')
            self.temp_persist_files.append(out_dirname)
        elif not os.path.exists(out_dirname):
            os.makedirs(out_dirname)
        
        commit = self._get_commit(version)
        tree = self.repo.tree(commit.tree)
        if name not in tree:
            raise KeyError('Cannot find tree "%s"' % name)
        subtree_id = tree[name][1]
        # subtree = self.repo.tree(subtree_id)
        for entry in self.repo.object_store.iter_tree_contents(subtree_id):
            out_fname = os.path.join(out_dirname, entry.path)
            self._write_blob(entry.sha, out_fname)
        return out_dirname

    def get_hash(self, name, version="HEAD", path_type=None):
        commit = self._get_commit(version)
        tree = self.repo.tree(commit.tree)
        if name not in tree:
            raise KeyError('Cannot find object "%s"' % name)
        return tree[name][1]

    @staticmethod
    def compute_blob_hash(fname, chunk_size=1<<16):
        obj_len = os.path.getsize(fname)
        head = object_header(Blob.type_num, obj_len)
        with open(fname, "rb") as f:
            def read_chunk():
                return f.read(chunk_size)
            my_iter = chain([head], iter(read_chunk,''))
            return iter_sha1(my_iter)
        return None

    @staticmethod
    def compute_tree_hash(dirname):
        tree = Tree()
        for entry in sorted(os.listdir(dirname)):
            fname = os.path.join(dirname, entry)
            if os.path.isdir(fname):
                thash = GitRepo.compute_tree_hash(fname)
                mode = stat.S_IFDIR # os.stat(fname)[stat.ST_MODE]
                tree.add(entry, mode, thash)
            elif os.path.isfile(fname):
                bhash = GitRepo.compute_blob_hash(fname)
                mode = os.stat(fname)[stat.ST_MODE]
                tree.add(entry, mode, bhash)
        return tree.id

    @staticmethod
    def compute_hash(path):
        if os.path.isdir(path):
            return GitRepo.compute_tree_hash(path)
        elif os.path.isfile(path):
            return GitRepo.compute_blob_hash(path)
        raise TypeError("Do not support this type of path")

    def get_latest_version(self, path):
        head = self.repo.head()
        walker = Walker(self.repo.object_store, [head], max_entries=1, 
                        paths=[path])
        return iter(walker).next().commit.id

    def _stage(self, filename):
        fullpath = os.path.join(self.repo.path, filename)
        if os.path.islink(fullpath):
            debug.warning("Warning: not staging symbolic link %s" % os.path.basename(filename))
        elif os.path.isdir(fullpath):
            for f in os.listdir(fullpath):
                self._stage(os.path.join(filename, f))
        else:
            if os.path.sep != '/':
                filename = filename.replace(os.path.sep, '/')
            self.repo.stage(filename)

    def add_commit(self, filename):
        self.setup_git()
        self._stage(filename)
        commit_id = self.repo.do_commit('Updated %s' % filename)
        return commit_id

    def setup_git(self):
        config_stack = self.repo.get_config_stack()

        try:
            config_stack.get(('user',), 'name')
            config_stack.get(('user',), 'email')
        except KeyError:
            from vistrails.core.system import current_user
            from dulwich.config import ConfigFile
            user = current_user()
            repo_conf = self.repo.get_config()
            repo_conf.set(('user',), 'name', user)
            repo_conf.set(('user',), 'email', '%s@localhost' % user)
            repo_conf.write_to_path()
Esempio n. 58
0
import multiprocessing

bind = "0.0.0.0:5000"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "eventlet"
reload = True

try:
    from dulwich.repo import Repo
    r = Repo('.')
    # gittle
    def active_branch(repo, SYMREF=b'ref: ', REFS_BRANCHES=b'refs/heads/'):
        """Returns the name of the active branch, or None, if HEAD is detached
        """
        x = repo.refs.read_ref('HEAD')
        if not x.startswith(SYMREF):
            return b''
        else:
            symref = x[len(SYMREF):]
            if not symref.startswith(REFS_BRANCHES):
                return b''
            else:
                return symref[len(REFS_BRANCHES):]
    import gunicorn
    gunicorn.SERVER_SOFTWARE = 'MarryBird %s(%s)' % (active_branch(r).decode('ascii'), r.head().decode('ascii')[:11])
except:
    pass