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
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.12.1 (released 2026-02-24)
====================================

* Fix missing unicode data in standalone binaries (#1014)
* Rename child-manifests to sub-manifests in documentation and code (#1027)

Release 0.12.0 (released 2026-02-21)
====================================
Expand Down
14 changes: 7 additions & 7 deletions dfetch/commands/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@

.. scenario-include:: ../features/check-svn-repo.feature

Child-manifests
~~~~~~~~~~~~~~~
Sub-manifests
~~~~~~~~~~~~~

It is possible that fetched projects have manifests of their own.
After these projects are fetched (with ``dfetch update``), the manifests are read as well
It is possible that fetched subprojects have manifests of their own.
After these subprojects are fetched (with ``dfetch update``), the manifests are read as well
and will be checked to look for further dependencies. If you don't want recommendations,
you can prevent *Dfetch* from checking child-manifests with ``--no-recommendations``.
you can prevent *Dfetch* from checking sub-manifests with ``--no-recommendations``.

.. scenario-include:: ../features/checked-project-has-dependencies.feature

Expand All @@ -32,7 +32,7 @@

import dfetch.commands.command
import dfetch.project
from dfetch.commands.common import check_child_manifests
from dfetch.commands.common import check_sub_manifests
from dfetch.log import get_logger
from dfetch.manifest.manifest import Manifest
from dfetch.project import create_super_project
Expand Down Expand Up @@ -104,7 +104,7 @@ def __call__(self, args: argparse.Namespace) -> None:

if not args.no_recommendations and os.path.isdir(project.destination):
with in_directory(project.destination):
check_child_manifests(superproject.manifest, project)
check_sub_manifests(superproject.manifest, project)

for reporter in reporters:
reporter.dump_to_file()
Expand Down
30 changes: 15 additions & 15 deletions dfetch/commands/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,43 @@

from dfetch.log import get_logger
from dfetch.manifest.manifest import Manifest
from dfetch.manifest.parse import get_childmanifests
from dfetch.manifest.parse import get_submanifests
from dfetch.manifest.project import ProjectEntry

logger = get_logger(__name__)


def check_child_manifests(manifest: Manifest, project: ProjectEntry) -> None:
"""Check for child manifests within a project.
def check_sub_manifests(manifest: Manifest, project: ProjectEntry) -> None:
"""Check for sub-manifests within a project.

Args:
manifest (dfetch.manifest.manifest.Manifest): The parent manifest with projects.
project (ProjectEntry): The parent project.
"""
for childmanifest in get_childmanifests(skip=[manifest.path]):
manifest_remote_urls = {project.remote_url for project in manifest.projects}

for submanifest in get_submanifests(skip=[manifest.path]):
recommendations: list[ProjectEntry] = []
for childproject in childmanifest.projects:
if childproject.remote_url not in [
project.remote_url for project in manifest.projects
]:
recommendations.append(childproject.as_recommendation())
for subproject in submanifest.projects:
if subproject.remote_url not in manifest_remote_urls:
recommendations.append(subproject.as_recommendation())

if recommendations:
childmanifest_relpath = os.path.relpath(
childmanifest.path, start=os.path.dirname(manifest.path)
submanifest_relpath = os.path.relpath(
submanifest.path, start=os.path.dirname(manifest.path)
).replace("\\", "/")
_make_recommendation(project, recommendations, childmanifest_relpath)
_make_recommendation(project, recommendations, submanifest_relpath)


def _make_recommendation(
project: ProjectEntry, recommendations: list[ProjectEntry], childmanifest_path: str
project: ProjectEntry, recommendations: list[ProjectEntry], submanifest_path: str
) -> None:
"""Make recommendations to the user.

Args:
project (ProjectEntry): The parent project.
recommendations (List[ProjectEntry]): List of recommendations
childmanifest_path (str): Path to the source of recommendations
submanifest_path (str): Path to the source of recommendations
"""
recommendation_json = yaml.dump(
[proj.as_yaml() for proj in recommendations],
Expand All @@ -54,7 +54,7 @@ def _make_recommendation(
"\n".join(
[
f'"{project.name}" depends on the following project(s) which are not part of your manifest:',
f"(found in {childmanifest_path})",
f"(found in {submanifest_path})",
"",
recommendation_json,
"",
Expand Down
8 changes: 4 additions & 4 deletions dfetch/commands/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@

.. scenario-include:: ../features/fetch-svn-repo.feature

Child-manifests
Sub-manifests
~~~~~~~~~~~~~~~

It is possible that fetched projects have manifests of their own.
When these projects are fetched (with ``dfetch update``), the manifests are read as well
and will be checked to look for further dependencies. If you don't what recommendations, you can prevent *Dfetch*
checking child-manifests with ``--no-recommendations``.
checking sub-manifests with ``--no-recommendations``.

.. scenario-include:: ../features/updated-project-has-dependencies.feature

Expand All @@ -34,7 +34,7 @@
import dfetch.commands.command
import dfetch.manifest.project
import dfetch.project
from dfetch.commands.common import check_child_manifests
from dfetch.commands.common import check_sub_manifests
from dfetch.log import get_logger
from dfetch.project import create_super_project
from dfetch.util.util import catch_runtime_exceptions, in_directory
Expand Down Expand Up @@ -94,7 +94,7 @@ def __call__(self, args: argparse.Namespace) -> None:
project.destination
):
with in_directory(project.destination):
check_child_manifests(superproject.manifest, project)
check_sub_manifests(superproject.manifest, project)

if exceptions:
raise RuntimeError("\n".join(exceptions))
Expand Down
10 changes: 5 additions & 5 deletions dfetch/manifest/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ def find_manifest() -> str:
return os.path.realpath(paths[0])


def get_childmanifests(skip: list[str] | None = None) -> list[Manifest]:
def get_submanifests(skip: list[str] | None = None) -> list[Manifest]:
"""Parse & validate any manifest file in cwd and return a list of all valid manifests."""
skip = skip or []
logger.debug("Looking for sub-manifests")

childmanifests: list[Manifest] = []
submanifests: list[Manifest] = []
root_dir = os.getcwd()
for path in find_file(DEFAULT_MANIFEST_NAME, root_dir):
path = os.path.realpath(path)
Expand All @@ -97,10 +97,10 @@ def get_childmanifests(skip: list[str] | None = None) -> list[Manifest]:
continue

if path not in skip:
logger.debug(f"Found sub-manifests {path}")
logger.debug(f"Found sub-manifest {path}")
with prefix_runtime_exceptions(
pathlib.Path(path).relative_to(os.path.dirname(os.getcwd())).as_posix()
):
childmanifests += [parse(path)]
submanifests += [parse(path)]

return childmanifests
return submanifests
4 changes: 2 additions & 2 deletions doc/internal.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ Remote
projects in a manifest. A single remote may contain multiple
(sub-)projects to fetch.

Child Manifest
Sub-manifest
Some subprojects can themselves contain a manifest. When
fetching a subproject, dfetch can optionally check these
child manifests for additional dependencies or recommendations.
sub-manifests for additional dependencies or recommendations.

Metadata
A file created by *DFetch* to store some relevant information about
Expand Down
30 changes: 15 additions & 15 deletions features/updated-project-has-dependencies.feature
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ Feature: Updated project has dependencies
manifest:
version: 0.0
projects:
- name: SomeProjectWithChild
dst: third-party/SomeProjectWithChild
url: some-remote-server/SomeProjectWithChild.git
- name: SomeProjectWithManifest
dst: third-party/SomeProjectWithManifest
url: some-remote-server/SomeProjectWithManifest.git
tag: v1
- name: SomeProjectWithoutChild
dst: third-party/SomeProjectWithoutChild
url: some-remote-server/SomeProjectWithoutChild.git
- name: SomeProjectWithoutManifest
dst: third-party/SomeProjectWithoutManifest
url: some-remote-server/SomeProjectWithoutManifest.git
tag: v1
"""
And a git-repository "SomeProjectWithChild.git" with the manifest:
And a git-repository "SomeProjectWithManifest.git" with the manifest:
"""
manifest:
version: 0.0
Expand All @@ -36,15 +36,15 @@ Feature: Updated project has dependencies
- name: ext/test-repo-tag-v1
tag: v1
"""
And a git repository "SomeProjectWithoutChild.git"
And a git repository "SomeProjectWithoutManifest.git"
When I run "dfetch update" in MyProject
Then the output shows
"""
Dfetch (0.12.1)
SomeProjectWithChild:
SomeProjectWithManifest:
> Fetched v1
> "SomeProjectWithChild" depends on the following project(s) which are not part of your manifest:
(found in third-party/SomeProjectWithChild/dfetch.yaml)
> "SomeProjectWithManifest" depends on the following project(s) which are not part of your manifest:
(found in third-party/SomeProjectWithManifest/dfetch.yaml)

- name: SomeOtherProject
url: some-remote-server/SomeOtherProject.git
Expand All @@ -53,24 +53,24 @@ Feature: Updated project has dependencies
url: https://github.com/dfetch-org/test-repo
tag: v1

SomeProjectWithoutChild:
SomeProjectWithoutManifest:
> Fetched v1
"""
And 'MyProject' looks like:
"""
MyProject/
dfetch.yaml
third-party/
SomeProjectWithChild/
SomeProjectWithManifest/
.dfetch_data.yaml
README.md
dfetch.yaml
SomeProjectWithoutChild/
SomeProjectWithoutManifest/
.dfetch_data.yaml
README.md
"""

Scenario: A child-project has an invalid manifest
Scenario: A project from a submanifest has an invalid manifest
Given the manifest 'dfetch.yaml' in MyProject
"""
manifest:
Expand Down
6 changes: 2 additions & 4 deletions tests/test_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,12 @@ def test_check(name, projects):
with patch(
"dfetch.commands.check.create_super_project", return_value=fake_superproject
):
with patch(
"dfetch.manifest.parse.get_childmanifests"
) as mocked_get_childmanifests:
with patch("dfetch.manifest.parse.get_submanifests") as mocked_get_submanifests:
with patch("dfetch.project.create_sub_project") as mocked_create:
with patch("os.path.exists"):
with patch("dfetch.commands.check.in_directory"):
with patch("dfetch.commands.check.CheckStdoutReporter"):
mocked_get_childmanifests.return_value = []
mocked_get_submanifests.return_value = []

check(DEFAULT_ARGS)

Expand Down
14 changes: 7 additions & 7 deletions tests/test_manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
ManifestEntryLocation,
RequestedProjectNotFoundError,
)
from dfetch.manifest.parse import find_manifest, get_childmanifests
from dfetch.manifest.parse import find_manifest, get_submanifests
from dfetch.manifest.project import ProjectEntry

BASIC_MANIFEST = """
Expand Down Expand Up @@ -123,29 +123,29 @@ def test_single_manifest_found() -> None:
"name, manifest_paths",
[
(
"no-childmanifests",
"no-submanifests",
[],
),
(
"single-childmanifest",
"single-submanifest",
["some-manifest.yaml"],
),
(
"multi-childmanifests",
"multi-submanifests",
["some-manifest.yaml", "some-other-manifest.yaml"],
),
],
)
def test_get_childmanifests(name, manifest_paths) -> None:
def test_get_submanifests(name, manifest_paths) -> None:
parent = ProjectEntry({"name": "name"})

with patch("dfetch.manifest.parse.find_file") as find_file_mock:
with patch("dfetch.manifest.parse.parse") as parse_mock:
find_file_mock.return_value = manifest_paths

found_childmanifests = get_childmanifests([parent.name])
found_submanifests = get_submanifests([parent.name])

assert len(found_childmanifests) == len(manifest_paths)
assert len(found_submanifests) == len(manifest_paths)

for path, call in zip(
manifest_paths,
Expand Down
12 changes: 4 additions & 8 deletions tests/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,12 @@ def test_update(name, projects):
with patch(
"dfetch.commands.update.create_super_project", return_value=fake_superproject
):
with patch(
"dfetch.manifest.parse.get_childmanifests"
) as mocked_get_childmanifests:
with patch("dfetch.manifest.parse.get_submanifests") as mocked_get_submanifests:
with patch("dfetch.project.create_sub_project") as mocked_create:
with patch("os.path.exists"):
with patch("dfetch.commands.update.in_directory"):
with patch("dfetch.commands.update.Update._check_destination"):
mocked_get_childmanifests.return_value = []
mocked_get_submanifests.return_value = []

update(DEFAULT_ARGS)

Expand All @@ -62,14 +60,12 @@ def test_forced_update():
with patch(
"dfetch.commands.update.create_super_project", return_value=fake_superproject
):
with patch(
"dfetch.manifest.parse.get_childmanifests"
) as mocked_get_childmanifests:
with patch("dfetch.manifest.parse.get_submanifests") as mocked_get_submanifests:
with patch("dfetch.project.create_sub_project") as mocked_create:
with patch("os.path.exists"):
with patch("dfetch.commands.update.in_directory"):
with patch("dfetch.commands.update.Update._check_destination"):
mocked_get_childmanifests.return_value = []
mocked_get_submanifests.return_value = []

args = argparse.Namespace(
no_recommendations=False,
Expand Down
Loading