Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Release 0.15.0 (unreleased)
==============================

* Add ``replay-patches`` command to step through patch contributions interactively (#1290)
* Fix a root-level directory matching a license glob being vendored alongside ``src:`` (#1428)

Release 0.14.4 (released 2026-08-28)
====================================
Expand Down
29 changes: 29 additions & 0 deletions dfetch/vcs/git.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Git specific implementation."""

import contextlib
import fnmatch
import functools
import os
import re
Expand All @@ -12,6 +13,7 @@

from dfetch.log import get_logger
from dfetch.util.cmdline import SubprocessCommandError, run_on_cmdline
from dfetch.util.license import is_license_file
from dfetch.util.ssh import InvalidSshCommandError, sanitize_ssh_cmd
from dfetch.util.util import in_directory, safe_rm
from dfetch.vcs import git_submodule
Expand Down Expand Up @@ -487,6 +489,30 @@ def _configure_sparse_checkout(

f.write("\n".join(map(str, patterns)) + "\n")

@staticmethod
def _drop_directories_matching_license_globs(src: str | None) -> None:
"""Undo the license keep patterns matching root-level directories.

The sparse-checkout keep patterns for license files (see
``LICENSE_GLOBS``) are written without a trailing slash so plain
``fnmatch`` can also recognise them elsewhere; in a sparse-checkout
pattern file that same lack of a trailing slash makes them match
directories too, e.g. a root-level ``licensecore/`` folder ends up
vendored whole (#1428). Only files should ever be kept as license
files, so any root-level directory that merely shares the name is
removed again here, unless it is the directory requested via
``src:`` itself -- whose leading path component may itself be a
glob (e.g. ``licen*/``), so it is matched with ``fnmatch`` too.
"""
keep_root = Path(src).parts[0] if src else None
Comment thread
spoorcc marked this conversation as resolved.
for entry in Path(".").iterdir():
if (
entry.is_dir()
and is_license_file(entry.name)
and not (keep_root and fnmatch.fnmatch(entry.name, keep_root))
):
safe_rm(entry, within=".")

def checkout_version(
self,
options: CheckoutOptions,
Expand Down Expand Up @@ -516,6 +542,9 @@ def checkout_version(
)
run_on_cmdline(logger, ["git", "reset", "--hard", "FETCH_HEAD"])

if options.src or options.ignore:
self._drop_directories_matching_license_globs(options.src)

if options.eol is not None:
self._renormalize_eol()

Expand Down
53 changes: 53 additions & 0 deletions features/keep-license-in-project.feature
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,59 @@ Feature: Keep license in project
dfetch.yaml
"""

Scenario: Root-level folder matching a license glob is not vendored alongside 'src:'
Given the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: 0.0
projects:
- name: SomeProjectWithLicenseLikeFolder
url: some-remote-server/SomeProjectWithLicenseLikeFolder.git
src: SomeFolder/
tag: v1
"""
And a git-repository "SomeProjectWithLicenseLikeFolder.git" with the files
| path |
| LICENSE |
| licensecore/SomeUnrelatedFile.txt |
| SomeFolder/SomeFile.txt |
When I run "dfetch update"
Then 'MyProject' looks like:
"""
MyProject/
SomeProjectWithLicenseLikeFolder/
.dfetch_data.yaml
LICENSE
SomeFile.txt
dfetch.yaml
"""

Scenario: A 'src:' glob whose root component looks like a license file is kept
Given the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: 0.0
projects:
- name: SomeProjectWithLicenseLikeSrc
url: some-remote-server/SomeProjectWithLicenseLikeSrc.git
src: licen*/
tag: v1
"""
And a git-repository "SomeProjectWithLicenseLikeSrc.git" with the files
| path |
| LICENSE |
| licensecore/SomeFile.txt |
When I run "dfetch update"
Then 'MyProject' looks like:
"""
MyProject/
SomeProjectWithLicenseLikeSrc/
.dfetch_data.yaml
LICENSE
SomeFile.txt
dfetch.yaml
"""

Scenario: License is preserved in svn repo sparse checkout and cannot be ignored
Given the manifest 'dfetch.yaml' in MyProject
"""
Expand Down
Loading