1import io 2import os 3import tarfile 4import zipfile 5 6from .distribution import Distribution 7 8class SDist(Distribution): 9 10 def __init__(self, filename, metadata_version=None): 11 self.filename = filename 12 self.metadata_version = metadata_version 13 self.extractMetadata() 14 15 @classmethod 16 def _get_archive(cls, fqn): 17 if not os.path.exists(fqn): 18 raise ValueError('No such file: %s' % fqn) 19 20 if zipfile.is_zipfile(fqn): 21 archive = zipfile.ZipFile(fqn) 22 names = archive.namelist() 23 def read_file(name): 24 return archive.read(name) 25 elif tarfile.is_tarfile(fqn): 26 archive = tarfile.TarFile.open(fqn) 27 names = archive.getnames() 28 def read_file(name): 29 return archive.extractfile(name).read() 30 else: 31 raise ValueError('Not a known archive format: %s' % fqn) 32 33 return archive, names, read_file 34 35 36 def read(self): 37 fqn = os.path.abspath( 38 os.path.normpath(self.filename)) 39 40 archive, names, read_file = self._get_archive(fqn) 41 42 try: 43 tuples = [x.split('/') for x in names if 'PKG-INFO' in x] 44 schwarz = sorted([(len(x), x) for x in tuples]) 45 for path in [x[1] for x in schwarz]: 46 candidate = '/'.join(path) 47 data = read_file(candidate) 48 if b'Metadata-Version' in data: 49 return data 50 finally: 51 archive.close() 52 53 raise ValueError('No PKG-INFO in archive: %s' % fqn) 54 55 56class UnpackedSDist(SDist): 57 def __init__(self, filename, metadata_version=None): 58 if os.path.isdir(filename): 59 pass 60 elif os.path.isfile(filename): 61 filename = os.path.dirname(filename) 62 else: 63 raise ValueError('No such file: %s' % filename) 64 65 super(UnpackedSDist, self).__init__( 66 filename, metadata_version=metadata_version) 67 68 def read(self): 69 try: 70 pkg_info = os.path.join(self.filename, 'PKG-INFO') 71 with io.open(pkg_info, errors='ignore') as f: 72 return f.read() 73 except Exception as e: 74 raise ValueError('Could not load %s as an unpacked sdist: %s' 75 % (self.filename, e)) 76