multiarchive 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {multiarchive-0.2.1 → multiarchive-0.2.2}/PKG-INFO +3 -1
- {multiarchive-0.2.1 → multiarchive-0.2.2}/README.md +2 -0
- {multiarchive-0.2.1 → multiarchive-0.2.2}/pyproject.toml +1 -1
- {multiarchive-0.2.1 → multiarchive-0.2.2}/pyproject.toml.orig +1 -1
- {multiarchive-0.2.1 → multiarchive-0.2.2}/src/multiarchive/_archive.py +82 -0
- {multiarchive-0.2.1 → multiarchive-0.2.2}/src/multiarchive/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: multiarchive
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A high level archive handler for Python.
|
|
5
5
|
Author: NSPC911
|
|
6
6
|
Author-email: NSPC911 <87571998+NSPC911@users.noreply.github.com>
|
|
@@ -222,6 +222,8 @@ The `infolist()` method returns `ArchiveMemberInfo` objects with a unified inter
|
|
|
222
222
|
| `mtime` | `float` | Modification time as epoch seconds |
|
|
223
223
|
| `mode` | `int \| None` | Unix permission bits |
|
|
224
224
|
| `is_dir` | `bool` | Whether the member is a directory |
|
|
225
|
+
| `kind` | `Literal["file", "directory", "symlink", "junction", "hardlink", "fifo", "character-device", "block-device", "unknown"]` | Member type |
|
|
226
|
+
| `link_target` | `str \| None` | Symlink, junction, or hardlink target when available |
|
|
225
227
|
| `raw` | `ZipInfo \| TarInfo \| RarInfo \| None` | Original backend object (`None` for plain compressed files) |
|
|
226
228
|
|
|
227
229
|
Factory methods for direct conversion (you shouldn't need these in normal usage):
|
|
@@ -213,6 +213,8 @@ The `infolist()` method returns `ArchiveMemberInfo` objects with a unified inter
|
|
|
213
213
|
| `mtime` | `float` | Modification time as epoch seconds |
|
|
214
214
|
| `mode` | `int \| None` | Unix permission bits |
|
|
215
215
|
| `is_dir` | `bool` | Whether the member is a directory |
|
|
216
|
+
| `kind` | `Literal["file", "directory", "symlink", "junction", "hardlink", "fifo", "character-device", "block-device", "unknown"]` | Member type |
|
|
217
|
+
| `link_target` | `str \| None` | Symlink, junction, or hardlink target when available |
|
|
216
218
|
| `raw` | `ZipInfo \| TarInfo \| RarInfo \| None` | Original backend object (`None` for plain compressed files) |
|
|
217
219
|
|
|
218
220
|
Factory methods for direct conversion (you shouldn't need these in normal usage):
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import stat
|
|
1
2
|
import sys
|
|
2
3
|
import zipfile
|
|
3
4
|
from dataclasses import dataclass
|
|
@@ -74,6 +75,33 @@ else:
|
|
|
74
75
|
Algos: TypeAlias = Literal[
|
|
75
76
|
"zip", "tar", "rar", "tar.gz", "tar.bz2", "tar.xz", "tar.zst"
|
|
76
77
|
]
|
|
78
|
+
ArchiveMemberKind: TypeAlias = Literal[
|
|
79
|
+
"file",
|
|
80
|
+
"directory",
|
|
81
|
+
"symlink",
|
|
82
|
+
"junction",
|
|
83
|
+
"hardlink",
|
|
84
|
+
"fifo",
|
|
85
|
+
"character-device",
|
|
86
|
+
"block-device",
|
|
87
|
+
"unknown",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _kind_from_mode(mode: int | None) -> ArchiveMemberKind | None:
|
|
92
|
+
if mode is None:
|
|
93
|
+
return None
|
|
94
|
+
return cast(
|
|
95
|
+
ArchiveMemberKind | None,
|
|
96
|
+
{
|
|
97
|
+
stat.S_IFREG: "file",
|
|
98
|
+
stat.S_IFDIR: "directory",
|
|
99
|
+
stat.S_IFLNK: "symlink",
|
|
100
|
+
stat.S_IFIFO: "fifo",
|
|
101
|
+
stat.S_IFCHR: "character-device",
|
|
102
|
+
stat.S_IFBLK: "block-device",
|
|
103
|
+
}.get(stat.S_IFMT(mode)),
|
|
104
|
+
)
|
|
77
105
|
|
|
78
106
|
|
|
79
107
|
class BadArchiveError(RuntimeError):
|
|
@@ -107,6 +135,8 @@ class ArchiveMemberInfo:
|
|
|
107
135
|
mtime: float
|
|
108
136
|
mode: int | None
|
|
109
137
|
is_dir: bool
|
|
138
|
+
kind: ArchiveMemberKind
|
|
139
|
+
link_target: str | None
|
|
110
140
|
raw: InfoType | None
|
|
111
141
|
|
|
112
142
|
@classmethod
|
|
@@ -119,6 +149,12 @@ class ArchiveMemberInfo:
|
|
|
119
149
|
mtime=mtime_dt.timestamp(),
|
|
120
150
|
mode=(info.external_attr >> 16) or None,
|
|
121
151
|
is_dir=info.is_dir(),
|
|
152
|
+
kind=(
|
|
153
|
+
"directory"
|
|
154
|
+
if info.is_dir()
|
|
155
|
+
else _kind_from_mode(info.external_attr >> 16) or "file"
|
|
156
|
+
),
|
|
157
|
+
link_target=None,
|
|
122
158
|
raw=info,
|
|
123
159
|
)
|
|
124
160
|
|
|
@@ -131,11 +167,30 @@ class ArchiveMemberInfo:
|
|
|
131
167
|
mtime=float(info.mtime or 0.0),
|
|
132
168
|
mode=info.mode,
|
|
133
169
|
is_dir=info.isdir(),
|
|
170
|
+
kind=(
|
|
171
|
+
"file"
|
|
172
|
+
if info.isreg()
|
|
173
|
+
else "directory"
|
|
174
|
+
if info.isdir()
|
|
175
|
+
else "symlink"
|
|
176
|
+
if info.issym()
|
|
177
|
+
else "hardlink"
|
|
178
|
+
if info.islnk()
|
|
179
|
+
else "fifo"
|
|
180
|
+
if info.isfifo()
|
|
181
|
+
else "character-device"
|
|
182
|
+
if info.ischr()
|
|
183
|
+
else "block-device"
|
|
184
|
+
if info.isblk()
|
|
185
|
+
else "unknown"
|
|
186
|
+
),
|
|
187
|
+
link_target=info.linkname if info.issym() or info.islnk() else None,
|
|
134
188
|
raw=info,
|
|
135
189
|
)
|
|
136
190
|
|
|
137
191
|
@classmethod
|
|
138
192
|
def from_rarinfo(cls, info: "rarfile.RarInfo") -> "ArchiveMemberInfo":
|
|
193
|
+
assert rarfile is not None
|
|
139
194
|
if info.mtime is not None:
|
|
140
195
|
mtime = info.mtime.timestamp()
|
|
141
196
|
elif info.date_time is not None:
|
|
@@ -145,6 +200,29 @@ class ArchiveMemberInfo:
|
|
|
145
200
|
assert info.filename is not None
|
|
146
201
|
assert info.file_size is not None
|
|
147
202
|
assert info.compress_size is not None
|
|
203
|
+
redir = info.file_redir
|
|
204
|
+
if redir is not None:
|
|
205
|
+
kind = cast(
|
|
206
|
+
ArchiveMemberKind,
|
|
207
|
+
{
|
|
208
|
+
rarfile.RAR5_XREDIR_UNIX_SYMLINK: "symlink",
|
|
209
|
+
rarfile.RAR5_XREDIR_WINDOWS_SYMLINK: "symlink",
|
|
210
|
+
rarfile.RAR5_XREDIR_WINDOWS_JUNCTION: "junction",
|
|
211
|
+
rarfile.RAR5_XREDIR_HARD_LINK: "hardlink",
|
|
212
|
+
rarfile.RAR5_XREDIR_FILE_COPY: "file",
|
|
213
|
+
}.get(redir[0], "unknown"),
|
|
214
|
+
)
|
|
215
|
+
link_target = redir[2]
|
|
216
|
+
else:
|
|
217
|
+
kind = (
|
|
218
|
+
"directory"
|
|
219
|
+
if info.is_dir()
|
|
220
|
+
else "symlink"
|
|
221
|
+
if info.is_symlink()
|
|
222
|
+
else _kind_from_mode(info.mode)
|
|
223
|
+
or ("file" if info.is_file() else "unknown")
|
|
224
|
+
)
|
|
225
|
+
link_target = None
|
|
148
226
|
return cls(
|
|
149
227
|
name=info.filename,
|
|
150
228
|
uncompressed_size=info.file_size,
|
|
@@ -152,6 +230,8 @@ class ArchiveMemberInfo:
|
|
|
152
230
|
mtime=mtime,
|
|
153
231
|
mode=info.mode,
|
|
154
232
|
is_dir=info.is_dir(),
|
|
233
|
+
kind=kind,
|
|
234
|
+
link_target=link_target,
|
|
155
235
|
raw=info,
|
|
156
236
|
)
|
|
157
237
|
|
|
@@ -557,6 +637,8 @@ class Archive:
|
|
|
557
637
|
mtime=stat.st_mtime,
|
|
558
638
|
mode=stat.st_mode & 0o777,
|
|
559
639
|
is_dir=False,
|
|
640
|
+
kind="file",
|
|
641
|
+
link_target=None,
|
|
560
642
|
raw=None,
|
|
561
643
|
)
|
|
562
644
|
]
|
|
File without changes
|