Skip to content

Commit

Permalink
WIP: Add Git attributes parser
Browse files Browse the repository at this point in the history
Signed-off-by: Andrej Shadura <[email protected]>
  • Loading branch information
andrewshadura committed Apr 2, 2022
1 parent 83521a1 commit 8499f5f
Showing 1 changed file with 95 additions and 0 deletions.
95 changes: 95 additions & 0 deletions dulwich/attrs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# attrs.py -- Git attributes for dulwich
# Copyright (C) 2019-2020 Collabora Ltd
# Copyright (C) 2019-2020 Andrej Shadura <[email protected]>
#
# Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
# General Public License as public by the Free Software Foundation; version 2.0
# or (at your option) any later version. You can redistribute it and/or
# modify it under the terms of either of these two licenses.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# You should have received a copy of the licenses; if not, see
# <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
# and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
# License, Version 2.0.
#

"""Parse .gitattributes file.
"""

import sys
from typing import (
Generator,
IO,
List,
Mapping,
Optional,
Sequence,
Tuple,
Union,
)


AttributeValue = Union[str, bool, None]


def _parse_attr(attr: str) -> Tuple[str, AttributeValue]:
"""Parse a git attribute into its value:
>>> _parse_attr('attr')
('attr', True)
>>> _parse_attr('-attr')
('attr', False)
>>> _parse_attr('!attr')
('attr', None)
>>> _parse_attr('attr=text')
('attr', 'text')
"""
if attr.startswith('!'):
return attr[1:], None
if attr.startswith('-'):
return attr[1:], False
if '=' not in attr:
return attr, True
return tuple(attr.split('='))


def parse_git_attributes(f: IO[bytes]) -> Generator[Tuple[bytes, Mapping[str, AttributeValue]], None, None]:
"""Parse a Git attributes string
Args:
f: File-like object to read bytes from
Returns:
List of patterns and corresponding patterns in the order or them being encountered
>>> from io import BytesIO
>>> list(parse_git_attributes(BytesIO(b'''*.tar.* filter=lfs diff=lfs merge=lfs -text
...
... # store signatures in Git
... *.tar.*.asc -filter -diff merge=binary -text
...
... # store .dsc verbatim
... *.dsc -filter !diff merge=binary !text
... '''))) #doctest: +NORMALIZE_WHITESPACE
[(b'*.tar.*', {'filter': 'lfs', 'diff': 'lfs', 'merge': 'lfs', 'text': False}),
(b'*.tar.*.asc', {'filter': False, 'diff': False, 'merge': 'binary', 'text': False}),
(b'*.dsc', {'filter': False, 'diff': None, 'merge': 'binary', 'text': None})]
"""
for line in f:
line = line.strip()

# Ignore blank lines, they're used for readability.
if not line:
continue

if line.startswith(b'#'):
# Comment
continue

pattern, *attrs = line.split()

yield (pattern, {k: v for k, v in (_parse_attr(a.decode()) for a in attrs)})

0 comments on commit 8499f5f

Please sign in to comment.