Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add support for querying attributes
Expose a method in the repository which allows querying an attribute for
a file and converts the result to the python equivalent.
  • Loading branch information
carlosmn committed May 20, 2015
commit 74b81bf18076555fb12369d5f20e4282214116d3
6 changes: 6 additions & 0 deletions pygit2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@
GIT_REPOSITORY_INIT_SHARED_GROUP = C.GIT_REPOSITORY_INIT_SHARED_GROUP
GIT_REPOSITORY_INIT_SHARED_ALL = C.GIT_REPOSITORY_INIT_SHARED_ALL

# GIT_ATTR_CHECK_*
GIT_ATTR_CHECK_FILE_THEN_INDEX = C.GIT_ATTR_CHECK_FILE_THEN_INDEX
GIT_ATTR_CHECK_INDEX_THEN_FILE = C.GIT_ATTR_CHECK_INDEX_THEN_FILE
GIT_ATTR_CHECK_INDEX_ONLY = C.GIT_ATTR_CHECK_INDEX_ONLY
GIT_ATTR_CHECK_NO_SYSTEM = C.GIT_ATTR_CHECK_NO_SYSTEM


def init_repository(path, bare=False,
flags=GIT_REPOSITORY_INIT_MKPATH,
Expand Down
15 changes: 15 additions & 0 deletions pygit2/decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -702,3 +702,18 @@ int git_merge_commits(git_index **out, git_repository *repo, const git_commit *o
int git_merge_trees(git_index **out, git_repository *repo, const git_tree *ancestor_tree, const git_tree *our_tree, const git_tree *their_tree, const git_merge_options *opts);
int git_merge_file_from_index(git_merge_file_result *out, git_repository *repo, const git_index_entry *ancestor, const git_index_entry *ours, const git_index_entry *theirs, const git_merge_file_options *opts);
void git_merge_file_result_free(git_merge_file_result *result);

#define GIT_ATTR_CHECK_FILE_THEN_INDEX ...
#define GIT_ATTR_CHECK_INDEX_THEN_FILE ...
#define GIT_ATTR_CHECK_INDEX_ONLY ...
#define GIT_ATTR_CHECK_NO_SYSTEM ...

typedef enum {
GIT_ATTR_UNSPECIFIED_T = 0,
GIT_ATTR_TRUE_T,
GIT_ATTR_FALSE_T,
GIT_ATTR_VALUE_T,
} git_attr_t;

int git_attr_get(const char **value_out, git_repository *repo, uint32_t flags, const char *path, const char *name);
git_attr_t git_attr_value(const char *attr);
38 changes: 38 additions & 0 deletions pygit2/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,3 +764,41 @@ def ahead_behind(self, local, upstream):
check_error(err)

return int(ahead[0]), int(behind[0])

#
# Git attributes
#
def get_attr(self, path, name, flags=0):
"""Retrieve an attribute for a file by path

Arguments

path
The path of the file to look up attributes for, relative to the
workdir root
name
The name of the attribute to look up
flags
A combination of GIT_ATTR_CHECK_ flags which determine the
lookup order

Returns either a boolean, None (if the value is unspecified) or string
with the value of the attribute.
"""

cvalue = ffi.new('char **')
err = C.git_attr_get(cvalue, self._repo, flags, to_bytes(path), to_bytes(name))
check_error(err)

# Now let's see if we can figure out what the value is
attr_kind = C.git_attr_value(cvalue[0])
if attr_kind == C.GIT_ATTR_UNSPECIFIED_T:
return None
elif attr_kind == C.GIT_ATTR_TRUE_T:
return True
elif attr_kind == C.GIT_ATTR_FALSE_T:
return False
elif attr_kind == C.GIT_ATTR_VALUE_T:
return ffi.string(cvalue[0]).decode('utf-8')

assert False, "the attribute value from libgit2 is invalid"
65 changes: 65 additions & 0 deletions test/test_attributes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
# as published by the Free Software Foundation.
#
# In addition to the permissions in the GNU General Public License,
# the authors give you unlimited permission to link the compiled
# version of this file into combinations with other programs,
# and to distribute those combinations without any restriction
# coming from the use of this file. (The General Public License
# restrictions do apply in other respects; for example, they cover
# modification of the file, and distribution when not linked into
# a combined executable.)
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.

# Import from the future
from __future__ import absolute_import
from __future__ import unicode_literals, print_function

# Import from the Standard Library
import binascii
import unittest
import tempfile
import os
from os.path import join, realpath
import sys

# Import from pygit2
from pygit2 import GIT_OBJ_ANY, GIT_OBJ_BLOB, GIT_OBJ_COMMIT
from pygit2 import init_repository, clone_repository, discover_repository
from pygit2 import Oid, Reference, hashfile
import pygit2
from . import utils

try:
import __pypy__
except ImportError:
__pypy__ = None

class RepositorySignatureTest(utils.RepoTestCase):

def test_no_attr(self):
self.assertIsNone(self.repo.get_attr('file', 'foo'))

with open(join(self.repo.workdir, '.gitattributes'), 'w+') as f:
print('*.py text\n', file=f)
print('*.jpg -text\n', file=f)
print('*.sh eol=lf\n', file=f)

self.assertIsNone(self.repo.get_attr('file.py', 'foo'))
self.assertTrue(self.repo.get_attr('file.py', 'text'))
self.assertFalse(self.repo.get_attr('file.jpg', 'text'))
self.assertEqual("lf", self.repo.get_attr('file.sh', 'eol'))