Skip to content

Commit

Permalink
feat: exclude files untracked by git from archive
Browse files Browse the repository at this point in the history
Automatically exclude from generated archive files untracked by git (ex:
referenced in .gitignore file) when building from local source tree with
an initialized git repository.

fix #153
  • Loading branch information
rezib committed Mar 5, 2024
1 parent ac7a4a0 commit 3362734
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
definition of different values for different distributions and formats (#156).
- Support installation of DNF modules as prescript dependencies for RPM packages
builds (#155).
- Automatically exclude from generated archive files untracked by git (ex:
referenced in `.gitignore`) when building or managing patches from local
source tree with initialized git repository (#153).
- cli:
- Possibility to list artifacts in registries in remote instance with the REST
API (#141)
Expand Down
56 changes: 35 additions & 21 deletions fatbuildr/cli/fatbuildrctl.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from ..protocols.wire import WireSourceArchive
from ..artifact import ArtifactDefs, ArtifactDefsFactory
from ..patches import PatchQueue
from ..git import load_git_repository
from ..tokens import ClientTokensManager
from ..console.client import tty_console_renderer
from ..errors import (
Expand Down Expand Up @@ -85,27 +86,6 @@ def prepare_tarball(apath, rundir: bool):
return tarball


def source_tarball_filter(tarinfo):
"""Custom tar add filter to filter out .git directory, .git* files (eg.
.gitignore) and debian subdirectory from source tarball."""

# Extract filename from tarinfo.name without tarball top-level directory by
# removing part before the first OS separator. If the OS separator is not
# found in filename, then consider the whole filename.
try:
filename = tarinfo.name.split(os.sep, 1)[1]
except IndexError:
filename = tarinfo.name
if (
filename.startswith('.git')
or filename == 'debian'
or filename.startswith('debian/')
):
return None
logger.debug("File added in archive: %s", tarinfo.name)
return tarinfo


def prepare_source_tarball(artifact, path, version, rundir: bool):
"""Generates a source tarball for the given artifact, tagged with the given
main version, using sources in path."""
Expand Down Expand Up @@ -145,6 +125,40 @@ def prepare_source_tarball(artifact, path, version, rundir: bool):
tarball,
path,
)

# If .git directory is present in source path, load existing git repository.
git_repo = None
if path.joinpath(".git").exists():
git_repo = load_git_repository(path)

def source_tarball_filter(tarinfo):
"""Custom tar add filter to filter out .git directory, .git* files (eg.
.gitignore), debian subdirectory and files mentioned in .gitignore from
source tarball."""

# Extract filename from tarinfo.name without tarball top-level directory
# by removing part before the first OS separator. If the OS separator is
# not found in filename, then consider the whole filename.
try:
filename = tarinfo.name.split(os.sep, 1)[1]
except IndexError:
filename = tarinfo.name
if (
filename.startswith('.git')
or filename == 'debian'
or filename.startswith('debian/')
):
return None
# If the source tree is a git repository and the file is ignored in the
# repository, exclude this file from generated archive.
if git_repo is not None and git_repo.path_is_ignored(filename):
logger.debug(
"Excluded file untracked in git repository: %s", tarinfo.name
)
return None
logger.debug("File added in archive: %s", tarinfo.name)
return tarinfo

with tarfile.open(tarball, 'x:xz') as tar:
tar.add(
path, arcname=subdir, recursive=True, filter=source_tarball_filter
Expand Down
4 changes: 4 additions & 0 deletions fatbuildr/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ def is_meta_generic(meta):
return 'Generic' in meta and meta['Generic'] == 'yes'


def load_git_repository(path: str):
return pygit2.Repository(path)


# It is not possible to inherit directory from pathlib.Path as this class
# constructor actually returns the specialized type according to the underlying
# OS. One solution is to discover the actual specialized type for the current OS
Expand Down

0 comments on commit 3362734

Please sign in to comment.