1
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
2
|
|
3
|
# Handling of software packaged for other distribution systems.
|
4
|
#
|
5
|
# This file is part of Hydrilla
|
6
|
#
|
7
|
# Copyright (C) 2022 Wojtek Kosior
|
8
|
#
|
9
|
# This program is free software: you can redistribute it and/or modify
|
10
|
# it under the terms of the GNU Affero General Public License as
|
11
|
# published by the Free Software Foundation, either version 3 of the
|
12
|
# License, or (at your option) any later version.
|
13
|
#
|
14
|
# This program is distributed in the hope that it will be useful,
|
15
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
# GNU Affero General Public License for more details.
|
18
|
#
|
19
|
# You should have received a copy of the GNU Affero General Public License
|
20
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
21
|
#
|
22
|
#
|
23
|
# I, Wojtek Kosior, thereby promise not to sue for violation of this
|
24
|
# file's license. Although I request that you do not make use this code
|
25
|
# in a proprietary program, I am not going to enforce this in court.
|
26
|
|
27
|
"""
|
28
|
This module contains definitions that may be reused by multiple piggybacked
|
29
|
software system backends.
|
30
|
"""
|
31
|
|
32
|
# Enable using with Python 3.7.
|
33
|
from __future__ import annotations
|
34
|
|
35
|
from pathlib import Path, PurePosixPath
|
36
|
from typing import Optional, Iterable
|
37
|
|
38
|
from .. import util
|
39
|
from .common_errors import *
|
40
|
|
41
|
here = Path(__file__).resolve().parent
|
42
|
|
43
|
_ = util.translation(here / 'locales').gettext
|
44
|
|
45
|
class Piggybacked:
|
46
|
"""
|
47
|
Store information about foreign resources in use.
|
48
|
|
49
|
Public attributes:
|
50
|
'package_must_depend' (read-only)
|
51
|
'package_license_files' (read-only)
|
52
|
"""
|
53
|
def __init__(self, archives: dict[str, Path]={}, roots: dict[str, Path]={},
|
54
|
package_license_files: list[PurePosixPath]=[],
|
55
|
package_must_depend: list[dict]=[]):
|
56
|
"""
|
57
|
Initialize this Piggybacked object.
|
58
|
|
59
|
'archives' maps piggybacked system names to directories that contain
|
60
|
package(s)' archive files. An 'archives' object may look like
|
61
|
{'apt': PosixPath('/path/to/dir/with/debs/and/tarballs')}.
|
62
|
|
63
|
'roots' associates directory names to be virtually inserted under
|
64
|
Hydrilla source package directory with paths to real filesystem
|
65
|
directories that hold their desired contents, i.e. unpacked foreign
|
66
|
packages.
|
67
|
|
68
|
'package_license_files' lists paths to license files that should be
|
69
|
included with the Haketilo package that will be produced. The paths are
|
70
|
to be resolved using 'roots' dictionary.
|
71
|
|
72
|
'package_must_depend' lists names of Haketilo packages that the produced
|
73
|
package will additionally depend on. This is meant to help distribute
|
74
|
common licenses with a separate Haketilo package.
|
75
|
"""
|
76
|
self.archives = archives
|
77
|
self.roots = roots
|
78
|
self.package_license_files = package_license_files
|
79
|
self.package_must_depend = package_must_depend
|
80
|
|
81
|
def resolve_file(self, file_ref_name: PurePosixPath) -> Optional[Path]:
|
82
|
"""
|
83
|
'file_ref_name' is a path as may appear in an index.json file. Check if
|
84
|
the file belongs to one of the roots we have and return either a path
|
85
|
to the relevant file under this root or None.
|
86
|
|
87
|
It is not being checked whether the file actually exists in the
|
88
|
filesystem.
|
89
|
"""
|
90
|
parts = file_ref_name.parts
|
91
|
root_path = self.roots.get(parts and parts[0])
|
92
|
path = root_path
|
93
|
if path is None:
|
94
|
return None
|
95
|
|
96
|
for part in parts[1:]:
|
97
|
path = path / part
|
98
|
|
99
|
path = path.resolve()
|
100
|
|
101
|
if not path.is_relative_to(root_path):
|
102
|
raise FileReferenceError(_('loading_{}_outside_piggybacked_dir')
|
103
|
.format(file_ref_name))
|
104
|
|
105
|
return path
|
106
|
|
107
|
def archive_files(self) -> Iterable[tuple[PurePosixPath, Path]]:
|
108
|
"""
|
109
|
Yield all archive files in use. Each yielded tuple holds file's desired
|
110
|
path relative to the piggybacked archives directory to be created and
|
111
|
its current real path.
|
112
|
"""
|
113
|
for system, real_dir in self.archives.items():
|
114
|
for path in real_dir.rglob('*'):
|
115
|
yield PurePosixPath(system) / path.relative_to(real_dir), path
|