@@ -98,6 +98,47 @@ def mkdir_with_dot_tmp(folder: Path)->Tuple[Path, Path]:
98
98
shutil .rmtree (str (tmpdir ))
99
99
tmpdir .mkdir (parents = True , exist_ok = True )
100
100
return (folder , tmpdir )
101
+
102
+ def flush_package_info (content : str , package_info = {}, new_or_old = True ):
103
+
104
+ for pkg in content .split ('\n \n ' ):
105
+ if len (pkg ) < 10 : # ignore blanks
106
+ continue
107
+ try :
108
+ pkg_filename = pattern_package_name .search (pkg ).group (1 )
109
+ pkg_size = int (pattern_package_size .search (pkg ).group (1 ))
110
+ pkg_checksum = pattern_package_sha256 .search (pkg ).group (1 )
111
+ if pkg_filename not in package_info :
112
+ if new_or_old :
113
+ pkg_info = {
114
+ 'size' : pkg_size ,
115
+ 'sha256' : {
116
+ 'new' : pkg_checksum ,
117
+ 'old' : None
118
+ }
119
+ }
120
+ else :
121
+ pkg_info = {
122
+ 'size' : pkg_size ,
123
+ 'sha256' : {
124
+ 'new' : None ,
125
+ 'old' : pkg_checksum
126
+ }
127
+ }
128
+ else :
129
+ pkg_info = package_info [pkg_filename ]
130
+ if new_or_old :
131
+ pkg_info ['sha256' ]['new' ] = pkg_checksum
132
+ else :
133
+ pkg_info ['sha256' ]['old' ] = pkg_checksum
134
+ package_info .update ({
135
+ pkg_filename : pkg_info
136
+ })
137
+ except :
138
+ print ("Failed to parse one package description" , flush = True )
139
+ traceback .print_exc ()
140
+ return package_info
141
+ return package_info
101
142
102
143
def move_files_in (src : Path , dst : Path ):
103
144
empty = True
@@ -110,6 +151,9 @@ def move_files_in(src: Path, dst: Path):
110
151
print (f"{ src } is empty" )
111
152
112
153
def apt_mirror (base_url : str , dist : str , repo : str , arch : str , dest_base_dir : Path , deb_set : Dict [str , int ])-> int :
154
+
155
+ package_info = {}
156
+
113
157
if not dest_base_dir .is_dir ():
114
158
print ("Destination directory is empty, cannot continue" )
115
159
return 1
@@ -134,6 +178,7 @@ def apt_mirror(base_url: str, dist: str, repo: str, arch: str, dest_base_dir: Pa
134
178
pkgidx_dir ,pkgidx_tmp_dir = mkdir_with_dot_tmp (comp_dir / arch_dir )
135
179
with open (release_file , "r" ) as fd :
136
180
pkgidx_content = None
181
+ pkgidx_content_old = None
137
182
cnt_start = False
138
183
for line in fd :
139
184
if cnt_start :
@@ -146,6 +191,8 @@ def apt_mirror(base_url: str, dist: str, repo: str, arch: str, dest_base_dir: Pa
146
191
filename .startswith (f"Contents-{ arch } " ):
147
192
fn = Path (filename )
148
193
pkgidx_file = dist_dir / fn .parent / ".tmp" / fn .name
194
+ if pkgidx_file .stem == 'Packages' :
195
+ pkgidx_file_old = Path (f'{ dist_dir } /{ filename } ' )
149
196
else :
150
197
print (f"Ignore the file { filename } " )
151
198
continue
@@ -176,12 +223,32 @@ def apt_mirror(base_url: str, dist: str, repo: str, arch: str, dest_base_dir: Pa
176
223
pkgidx_content = content .decode ('utf-8' )
177
224
else :
178
225
print ("unsupported format" )
226
+ continue
227
+
228
+ package_info = flush_package_info (pkgidx_content , package_info = package_info , new_or_old = True )
229
+
230
+ with pkgidx_file_old .open ('rb' ) as t : content = t .read ()
231
+ if pkgidx_content_old is None and pkgidx_file_old .stem == 'Packages' :
232
+ print (f"getting packages index content from { pkgidx_file_old .name } " , flush = True )
233
+ suffix = pkgidx_file .suffix
234
+ if suffix == '.xz' :
235
+ pkgidx_content_old = lzma .decompress (content ).decode ('utf-8' )
236
+ elif suffix == '.bz2' :
237
+ pkgidx_content_old = bz2 .decompress (content ).decode ('utf-8' )
238
+ elif suffix == '.gz' :
239
+ pkgidx_content_old = gzip .decompress (content ).decode ('utf-8' )
240
+ elif suffix == '' :
241
+ pkgidx_content_old = content .decode ('utf-8' )
242
+
243
+ package_info = flush_package_info (pkgidx_content_old , package_info = package_info , new_or_old = False )
244
+
179
245
180
246
# Currently only support SHA-256 checksum, because
181
247
# "Clients may not use the MD5Sum and SHA1 fields for security purposes, and must require a SHA256 or a SHA512 field."
182
248
# from https://wiki.debian.org/DebianRepository/Format#A.22Release.22_files
183
249
if line .startswith ('SHA256:' ):
184
250
cnt_start = True
251
+
185
252
if not cnt_start :
186
253
print ("Cannot find SHA-256 checksum" )
187
254
return 1
@@ -216,18 +283,9 @@ def collect_tmp_dir():
216
283
err = 0
217
284
deb_count = 0
218
285
deb_size = 0
219
- for pkg in pkgidx_content .split ('\n \n ' ):
220
- if len (pkg ) < 10 : # ignore blanks
221
- continue
222
- try :
223
- pkg_filename = pattern_package_name .search (pkg ).group (1 )
224
- pkg_size = int (pattern_package_size .search (pkg ).group (1 ))
225
- pkg_checksum = pattern_package_sha256 .search (pkg ).group (1 )
226
- except :
227
- print ("Failed to parse one package description" , flush = True )
228
- traceback .print_exc ()
229
- err = 1
230
- continue
286
+ for pkg_filename , pkg_info in package_info .items ():
287
+ pkg_size = pkg_info ['size' ]
288
+ pkg_checksum = pkg_info ['sha256' ]
231
289
deb_count += 1
232
290
deb_size += pkg_size
233
291
@@ -237,8 +295,8 @@ def collect_tmp_dir():
237
295
dest_dir .mkdir (parents = True , exist_ok = True )
238
296
if dest_filename .suffix == '.deb' :
239
297
deb_set [str (dest_filename .relative_to (dest_base_dir ))] = pkg_size
240
- if dest_filename .is_file () and dest_filename .stat ().st_size == pkg_size :
241
- print (f"Skipping { pkg_filename } , size { pkg_size } " )
298
+ if dest_filename .is_file () and ( dest_filename .stat ().st_size == pkg_size and pkg_checksum [ 'old' ] == pkg_checksum [ 'new' ]) :
299
+ print (f"Skipping { pkg_filename } , size { pkg_size } , sha256 { pkg_checksum [ 'new' ] } " )
242
300
continue
243
301
244
302
pkg_url = f"{ base_url } /{ pkg_filename } "
@@ -253,8 +311,8 @@ def collect_tmp_dir():
253
311
with dest_tmp_filename .open ("rb" ) as f :
254
312
for block in iter (lambda : f .read (1024 ** 2 ), b"" ):
255
313
sha .update (block )
256
- if sha .hexdigest () != pkg_checksum :
257
- print (f"Invalid checksum of { dest_filename } , expected { pkg_checksum } " )
314
+ if sha .hexdigest () != pkg_checksum [ 'new' ] :
315
+ print (f"Invalid checksum of { dest_filename } , expected { pkg_checksum [ 'new' ] } " )
258
316
dest_tmp_filename .unlink ()
259
317
continue
260
318
dest_tmp_filename .rename (dest_filename )
0 commit comments