@@ -158,19 +158,23 @@ def dumpMode(mode):
158158
159159
160160class Extractor ():
161+ SUPPORT_STRIP = False
162+
161163 def __init__ (self , dir , file , strip , separateDownload ):
164+ if strip != 0 and not self .SUPPORT_STRIP :
165+ raise BuildError ("Extractor does not support 'stripComponents'!" )
162166 self .dir = dir
163167 self .file = file
164168 self .strip = strip
165169 self .separateDownload = separateDownload
166170
167- async def _extract (self , cmds , invoker ):
171+ async def _extract (self , cmds , invoker , stdout = None ):
168172 destination = self .getCompressedFilePath (invoker )
169173 canary = destination + ".extracted"
170174 if isYounger (destination , canary ):
171175 for cmd in cmds :
172176 if shutil .which (cmd [0 ]) is None : continue
173- await invoker .checkCommand (cmd , cwd = self .dir )
177+ await invoker .checkCommand (cmd , cwd = self .dir , stdout = stdout )
174178 invoker .trace ("<touch>" , canary )
175179 with open (canary , "wb" ) as f :
176180 pass
@@ -191,8 +195,7 @@ async def extract(self, invoker, destination, cwd):
191195# case of tarfile broken in certain ways (e.g. tarfile will result in
192196# different file modes!). But it shouldn't make a difference on Windows.
193197class TarExtractor (Extractor ):
194- def __init__ (self , dir , file , strip , separateDownload ):
195- super ().__init__ (dir , file , strip , separateDownload )
198+ SUPPORT_STRIP = True
196199
197200 async def extract (self , invoker ):
198201 cmds = []
@@ -210,10 +213,6 @@ async def extract(self, invoker):
210213
211214
212215class ZipExtractor (Extractor ):
213- def __init__ (self , dir , file , strip , separateDownload ):
214- super ().__init__ (dir , file , strip , separateDownload )
215- if strip != 0 :
216- raise BuildError ("Extractor does not support 'stripComponents'!" )
217216
218217 async def extract (self , invoker ):
219218 cmds = []
@@ -226,47 +225,60 @@ async def extract(self, invoker):
226225 await self ._extract (cmds , invoker )
227226
228227
229- class GZipExtractor (Extractor ):
230- def __init__ (self , dir , file , strip , separateDownload ):
231- super ().__init__ (dir , file , strip , separateDownload )
232- if strip != 0 :
233- raise BuildError ("Extractor does not support 'stripComponents'!" )
228+ class SingleFileExtractor (Extractor ):
234229
235230 async def extract (self , invoker ):
236- # gunzip extracts the file at the location of the input file. Copy the
237- # downloaded file to the workspace directory prio to uncompressing it
238- cmd = ["gunzip" ]
239- if self .separateDownload :
240- shutil .copyfile (self .getCompressedFilePath (invoker ),
241- invoker .joinPath (self .dir , self .file ))
231+ # The gunzip and unxz tools extracts the file at the location of the
232+ # input file. In case the separateDownload policy is active, the
233+ # destination might be in a separete folder.
234+ src = self .getCompressedFilePath (invoker )
235+ dst = invoker .joinPath (self .dir , self .file )
236+
237+ suffix = dst [- 4 :]
238+ if self .EXT_IGNORE_CASE :
239+ suffix = suffix .lower ()
240+
241+ for ext , repl in self .EXT_MAP .items ():
242+ if suffix .endswith (ext ):
243+ dst = dst [:- len (ext )] + repl
244+ break
242245 else :
243- cmd .append ("-k" )
244- cmd .extend (["-f" , self .file ])
245- await self ._extract ([cmd ], invoker )
246-
246+ raise BuildError ("unkown suffix" )
247+
248+ with open (dst , 'wb' ) as f :
249+ cmd = [self .CMD , "-c" , src ]
250+ await self ._extract ([cmd ], invoker , f )
251+
252+ shutil .copystat (src , dst )
253+
254+
255+ class GZipExtractor (SingleFileExtractor ):
256+ CMD = "gunzip"
257+ EXT_IGNORE_CASE = True
258+ EXT_MAP = {
259+ ".gz" : "" ,
260+ "-gz" : "" ,
261+ ".z" : "" ,
262+ "-z" : "" ,
263+ "_z" : "" ,
264+ ".tgz" : ".tar" ,
265+ ".taz" : ".tar" ,
266+ }
247267
248- class XZExtractor (Extractor ):
249- def __init__ (self , dir , file , strip , separateDownload ):
250- super ().__init__ (dir , file , strip , separateDownload )
251- if strip != 0 :
252- raise BuildError ("Extractor does not support 'stripComponents'!" )
253268
254- async def extract (self , invoker ):
255- cmd = ["unxz" ]
256- if self .separateDownload :
257- shutil .copyfile (self .getCompressedFilePath (invoker ),
258- invoker .joinPath (self .dir , self .file ))
259- else :
260- cmd .append ("-k" )
261- cmd .extend (["-f" , self .file ])
262- await self ._extract ([cmd ], invoker )
269+ class XZExtractor (SingleFileExtractor ):
270+ CMD = "unxz"
271+ EXT_IGNORE_CASE = False
272+ EXT_MAP = {
273+ ".xz" : "" ,
274+ ".lzma" : "" ,
275+ ".lz" : "" ,
276+ ".txz" : ".tar" ,
277+ ".tlz" : ".tar" ,
278+ }
263279
264280
265281class SevenZipExtractor (Extractor ):
266- def __init__ (self , dir , file , strip , separateDownload ):
267- super ().__init__ (dir , file , strip , separateDownload )
268- if strip != 0 :
269- raise BuildError ("Extractor does not support 'stripComponents'!" )
270282
271283 async def extract (self , invoker ):
272284 cmds = [["7z" , "x" , "-y" , self .getCompressedFilePath (invoker )]]
0 commit comments