def write_record(self, bdist_dir, distinfo_dir): from wheel.util import urlsafe_b64encode record_path = os.path.join(distinfo_dir, 'RECORD') record_relpath = os.path.relpath(record_path, bdist_dir) def walk(): for dir, dirs, files in os.walk(bdist_dir): dirs.sort() for f in sorted(files): yield os.path.join(dir, f) def skip(path): """Wheel hashes every possible file.""" return (path == record_relpath) with open_for_csv(record_path, 'w+') as record_file: writer = csv.writer(record_file) for path in walk(): relpath = os.path.relpath(path, bdist_dir) if skip(relpath): hash = '' size = '' else: with open(path, 'rb') as f: data = f.read() digest = hashlib.sha256(data).digest() hash = 'sha256=' + native(urlsafe_b64encode(digest)) size = len(data) record_path = os.path.relpath( path, bdist_dir).replace(os.path.sep, '/') writer.writerow((record_path, hash, size))
def write_record(bdist_dir, distinfo_dir): record_path = os.path.join(distinfo_dir, 'RECORD') record_relpath = os.path.relpath(record_path, bdist_dir) def walk(): for dir, dirs, files in os.walk(bdist_dir): dirs.sort() for f in sorted(files): yield os.path.join(dir, f) def skip(path): """Wheel hashes every possible file.""" return (path == record_relpath) with open_for_csv(record_path, 'w+') as record_file: writer = csv.writer(record_file) for path in walk(): relpath = os.path.relpath(path, bdist_dir) if skip(relpath): hash = '' size = '' else: with open(path, 'rb') as f: data = f.read() digest = hashlib.sha256(data).digest() hash = 'sha256=' + native(urlsafe_b64encode(digest)) size = len(data) record_path = os.path.relpath(path, bdist_dir).replace(os.path.sep, '/') writer.writerow((record_path, hash, size))
def write_record(self, bdist_dir, distinfo_dir): from wheel.util import urlsafe_b64encode record_path = os.path.join(distinfo_dir, "RECORD") record_relpath = os.path.relpath(record_path, bdist_dir) def walk(): for dir, dirs, files in os.walk(bdist_dir): dirs.sort() for f in sorted(files): yield os.path.join(dir, f) def skip(path): """Wheel hashes every possible file.""" return path == record_relpath with open_for_csv(record_path, "w+") as record_file: writer = csv.writer(record_file) for path in walk(): relpath = os.path.relpath(path, bdist_dir) if skip(relpath): hash = "" size = "" else: with open(path, "rb") as f: data = f.read() digest = hashlib.sha256(data).digest() hash = "sha256=" + native(urlsafe_b64encode(digest)) size = len(data) record_path = os.path.relpath(path, bdist_dir).replace( os.path.sep, "/") writer.writerow((record_path, hash, size))
def rewrite_record(bdist_dir): """ Rewrite RECORD file with hashes for all files in `wheel_sdir` Copied from :method:`wheel.bdist_wheel.bdist_wheel.write_record` Will also unsign wheel Parameters ---------- bdist_dir : str Path of unpacked wheel file """ info_dir = _dist_info_dir(bdist_dir) record_path = pjoin(info_dir, 'RECORD') record_relpath = relpath(record_path, bdist_dir) # Unsign wheel - because we're invalidating the record hash sig_path = pjoin(info_dir, 'RECORD.jws') if exists(sig_path): os.unlink(sig_path) def walk(): for dir, dirs, files in os.walk(bdist_dir): for f in files: yield pjoin(dir, f) def skip(path): """Wheel hashes every possible file.""" return path == record_relpath with open_for_csv(record_path, 'w+') as record_file: writer = csv.writer(record_file) for path in walk(): relative_path = relpath(path, bdist_dir) if skip(relative_path): hash = '' size = '' else: with open(path, 'rb') as f: data = f.read() digest = hashlib.sha256(data).digest() hash = 'sha256=' + native(urlsafe_b64encode(digest)) size = len(data) record_path = relpath(path, bdist_dir).replace(psep, '/') writer.writerow((record_path, hash, size))
def rewrite_record(bdist_dir): """ Rewrite RECORD file with hashes for all files in `wheel_sdir` Copied from :method:`wheel.bdist_wheel.bdist_wheel.write_record` Will also unsign wheel Parameters ---------- bdist_dir : str Path of unpacked wheel file """ info_dir = _dist_info_dir(bdist_dir) record_path = pjoin(info_dir, 'RECORD') record_relpath = relpath(record_path, bdist_dir) # Unsign wheel - because we're invalidating the record hash sig_path = pjoin(info_dir, 'RECORD.jws') if exists(sig_path): os.unlink(sig_path) def walk(): for dir, dirs, files in os.walk(bdist_dir): for f in files: yield pjoin(dir, f) def skip(path): """Wheel hashes every possible file.""" return (path == record_relpath) with open_for_csv(record_path, 'w+') as record_file: writer = csv.writer(record_file) for path in walk(): relative_path = relpath(path, bdist_dir) if skip(relative_path): hash = '' size = '' else: with open(path, 'rb') as f: data = f.read() digest = hashlib.sha256(data).digest() hash = 'sha256=' + native(urlsafe_b64encode(digest)) size = len(data) record_path = relpath(path, bdist_dir).replace(psep, '/') writer.writerow((record_path, hash, size))
def add_files(self, files_to_add=None, basedir='.'): if files_to_add == None or len(files_to_add) == 0: return records = ZipPackageVerifier(self.filename).get_records() if (len(records) < 1): raise ValueError('Invalid wheel file no records found') last_record_name = records[0] # new_record_name = "RECORD.{}".format(len(records)) # tmp_dir = tempfile.mkdtemp() try: record_path = '/'.join((self.distinfo_name, last_record_name)) tmp_new_record_file = '/'.join((tmp_dir, self.distinfo_name, last_record_name)) self.zipfile.extract('/'.join((self.distinfo_name, last_record_name)), path = tmp_dir) self.remove_files('/'.join((self.distinfo_name, 'config'))) with closing(open_for_csv(tmp_new_record_file,"a+")) as record_file: writer = csv.writer(record_file) if files_to_add: if 'config_file' in files_to_add.keys(): try: data = open(files_to_add['config_file']).read() except OSError as e: _log.error("couldn't access {}" % files_to_add['config_file']) raise self.zipfile.writestr("%s/%s" % (self.distinfo_name, 'config'), data) (hash_data, size, digest) = self._record_digest(data) record_path = '/'.join((self.distinfo_name, 'config')) writer.writerow((record_path, hash_data, size)) if 'contract' in files_to_add.keys() and files_to_add['contract'] is not None: try: data = open(files_to_add['contract']).read() except OSError as e: _log.error("couldn't access {}" % files_to_add['contract']) raise if files_to_add['contract'] != 'execreqs.json': msg = 'WARNING: renaming passed contract file: {}'.format( files_to_add['contract']) msg += ' to execreqs.json' sys.stderr.write(msg) _log.warn(msg) self.zipfile.writestr("%s/%s" % (self.distinfo_name, 'execreqs.json'), data) (hash_data, size, digest) = self._record_digest(data) record_path = '/'.join((self.distinfo_name, 'execreqs.json')) writer.writerow((record_path, hash_data, size)) self.__setupzipfile__() self.pop_records_file() new_record_content = open(tmp_new_record_file, 'r').read() self.zipfile.writestr(self.distinfo_name+"/"+last_record_name, new_record_content) self.zipfile.close() self.__setupzipfile__() finally: shutil.rmtree(tmp_dir, True)
def install(self, force=False, overrides={}): """ Install the wheel into site-packages. """ # Utility to get the target directory for a particular key def get_path(key): return overrides.get(key) or self.install_paths[key] # The base target location is either purelib or platlib if self.parsed_wheel_info['Root-Is-Purelib'] == 'true': root = get_path('purelib') else: root = get_path('platlib') # Parse all the names in the archive name_trans = {} for info in self.zipfile.infolist(): name = info.filename # Zip files can contain entries representing directories. # These end in a '/'. # We ignore these, as we create directories on demand. if name.endswith('/'): continue # Pathnames in a zipfile namelist are always /-separated. # In theory, paths could start with ./ or have other oddities # but this won't happen in practical cases of well-formed wheels. # We'll cover the simple case of an initial './' as it's both easy # to do and more common than most other oddities. if name.startswith('./'): name = name[2:] # Split off the base directory to identify files that are to be # installed in non-root locations basedir, sep, filename = name.partition('/') if sep and basedir == self.datadir_name: # Data file. Target destination is elsewhere key, sep, filename = filename.partition('/') if not sep: raise ValueError( "Invalid filename in wheel: {0}".format(name)) target = get_path(key) else: # Normal file. Target destination is root key = '' target = root filename = name # Map the actual filename from the zipfile to its intended target # directory and the pathname relative to that directory. dest = os.path.normpath(os.path.join(target, filename)) name_trans[info] = (key, target, filename, dest) # We're now ready to start processing the actual install. The process # is as follows: # 1. Prechecks - is the wheel valid, is its declared architecture # OK, etc. [[Responsibility of the caller]] # 2. Overwrite check - do any of the files to be installed already # exist? # 3. Actual install - put the files in their target locations. # 4. Update RECORD - write a suitably modified RECORD file to # reflect the actual installed paths. if not force: for info, v in name_trans.items(): k = info.filename key, target, filename, dest = v if os.path.exists(dest): raise ValueError( "Wheel file {0} would overwrite {1}. Use force if this is intended" .format(k, dest)) # Get the name of our executable, for use when replacing script # wrapper hashbang lines. # We encode it using getfilesystemencoding, as that is "the name of # the encoding used to convert Unicode filenames into system file # names". exename = sys.executable.encode(sys.getfilesystemencoding()) record_data = [] record_name = self.distinfo_name + '/RECORD' for info, (key, target, filename, dest) in name_trans.items(): name = info.filename source = self.zipfile.open(info) # Skip the RECORD file if name == record_name: continue ddir = os.path.dirname(dest) if not os.path.isdir(ddir): os.makedirs(ddir) destination = HashingFile(open(dest, 'wb')) if key == 'scripts': hashbang = source.readline() if hashbang.startswith(b'#!python'): hashbang = b'#!' + exename + binary(os.linesep) destination.write(hashbang) shutil.copyfileobj(source, destination) reldest = os.path.relpath(dest, root) reldest.replace(os.sep, '/') record_data.append( (reldest, destination.digest(), destination.length)) destination.close() source.close() # preserve attributes (especially +x bit for scripts) attrs = info.external_attr >> 16 if attrs: # tends to be 0 if Windows. os.chmod(dest, info.external_attr >> 16) record_name = os.path.join(root, self.record_name) writer = csv.writer(open_for_csv(record_name, 'w+')) for reldest, digest, length in sorted(record_data): writer.writerow((reldest, digest, length)) writer.writerow((self.record_name, '', ''))
def install(self, force=False, overrides={}): """ Install the wheel into site-packages. """ # Utility to get the target directory for a particular key def get_path(key): return overrides.get(key) or self.install_paths[key] # The base target location is either purelib or platlib if self.parsed_wheel_info['Root-Is-Purelib'] == 'true': root = get_path('purelib') else: root = get_path('platlib') # Parse all the names in the archive name_trans = {} for info in self.zipfile.infolist(): name = info.filename # Zip files can contain entries representing directories. # These end in a '/'. # We ignore these, as we create directories on demand. if name.endswith('/'): continue # Pathnames in a zipfile namelist are always /-separated. # In theory, paths could start with ./ or have other oddities # but this won't happen in practical cases of well-formed wheels. # We'll cover the simple case of an initial './' as it's both easy # to do and more common than most other oddities. if name.startswith('./'): name = name[2:] # Split off the base directory to identify files that are to be # installed in non-root locations basedir, sep, filename = name.partition('/') if sep and basedir == self.datadir_name: # Data file. Target destination is elsewhere key, sep, filename = filename.partition('/') if not sep: raise ValueError("Invalid filename in wheel: {0}".format(name)) target = get_path(key) else: # Normal file. Target destination is root key = '' target = root filename = name # Map the actual filename from the zipfile to its intended target # directory and the pathname relative to that directory. dest = os.path.normpath(os.path.join(target, filename)) name_trans[info] = (key, target, filename, dest) # We're now ready to start processing the actual install. The process # is as follows: # 1. Prechecks - is the wheel valid, is its declared architecture # OK, etc. [[Responsibility of the caller]] # 2. Overwrite check - do any of the files to be installed already # exist? # 3. Actual install - put the files in their target locations. # 4. Update RECORD - write a suitably modified RECORD file to # reflect the actual installed paths. if not force: for info, v in name_trans.items(): k = info.filename key, target, filename, dest = v if os.path.exists(dest): raise ValueError("Wheel file {0} would overwrite {1}. Use force if this is intended".format(k, dest)) # Get the name of our executable, for use when replacing script # wrapper hashbang lines. # We encode it using getfilesystemencoding, as that is "the name of # the encoding used to convert Unicode filenames into system file # names". exename = sys.executable.encode(sys.getfilesystemencoding()) record_data = [] record_name = self.distinfo_name + '/RECORD' for info, (key, target, filename, dest) in name_trans.items(): name = info.filename source = self.zipfile.open(info) # Skip the RECORD file if name == record_name: continue ddir = os.path.dirname(dest) if not os.path.isdir(ddir): os.makedirs(ddir) destination = HashingFile(open(dest, 'wb')) if key == 'scripts': hashbang = source.readline() if hashbang.startswith(b'#!python'): hashbang = b'#!' + exename + binary(os.linesep) destination.write(hashbang) shutil.copyfileobj(source, destination) reldest = os.path.relpath(dest, root) reldest.replace(os.sep, '/') record_data.append((reldest, destination.digest(), destination.length)) destination.close() source.close() # preserve attributes (especially +x bit for scripts) attrs = info.external_attr >> 16 if attrs: # tends to be 0 if Windows. os.chmod(dest, info.external_attr >> 16) record_name = os.path.join(root, self.record_name) writer = csv.writer(open_for_csv(record_name, 'w+')) for reldest, digest, length in sorted(record_data): writer.writerow((reldest, digest, length)) writer.writerow((self.record_name, '', ''))
def add_files(self, files_to_add=None, basedir='.'): if files_to_add == None or len(files_to_add) == 0: return records = ZipPackageVerifier(self.filename).get_records() if (len(records) < 1): raise ValueError('Invalid wheel file no records found') last_record_name = records[0] # new_record_name = "RECORD.{}".format(len(records)) # tmp_dir = tempfile.mkdtemp() try: record_path = '/'.join((self.distinfo_name, last_record_name)) tmp_new_record_file = '/'.join( (tmp_dir, self.distinfo_name, last_record_name)) self.zipfile.extract('/'.join( (self.distinfo_name, last_record_name)), path=tmp_dir) self.remove_files('/'.join((self.distinfo_name, 'config'))) with closing(open_for_csv(tmp_new_record_file, "a+")) as record_file: writer = csv.writer(record_file) if files_to_add: if 'config_file' in files_to_add.keys(): try: data = open(files_to_add['config_file']).read() except OSError as e: _log.error("couldn't access {}" % files_to_add['config_file']) raise self.zipfile.writestr( "%s/%s" % (self.distinfo_name, 'config'), data) (hash_data, size, digest) = self._record_digest(data) record_path = '/'.join((self.distinfo_name, 'config')) writer.writerow((record_path, hash_data, size)) if 'identity_file' in files_to_add.keys(): try: data = open(files_to_add['identity_file']).read() except OSError as e: _log.error("couldn't access {}" % files_to_add['identity_file']) raise self.zipfile.writestr( "%s/%s" % (self.distinfo_name, 'IDENTITY_TEMPLATE'), data) (hash_data, size, digest) = self._record_digest(data) record_path = '/'.join( (self.distinfo_name, 'IDENTITY_TEMPLATE')) writer.writerow((record_path, hash_data, size)) if 'contract' in files_to_add.keys( ) and files_to_add['contract'] is not None: try: data = open(files_to_add['contract']).read() except OSError as e: _log.error("couldn't access {}" % files_to_add['contract']) raise if files_to_add['contract'] != 'execreqs.json': msg = 'WARNING: renaming passed contract file: {}'.format( files_to_add['contract']) msg += ' to execreqs.json' sys.stderr.write(msg) _log.warn(msg) self.zipfile.writestr( "%s/%s" % (self.distinfo_name, 'execreqs.json'), data) (hash_data, size, digest) = self._record_digest(data) record_path = '/'.join( (self.distinfo_name, 'execreqs.json')) writer.writerow((record_path, hash_data, size)) self.__setupzipfile__() self.pop_records_file() new_record_content = open(tmp_new_record_file, 'r').read() self.zipfile.writestr(self.distinfo_name + "/" + last_record_name, new_record_content) self.zipfile.close() self.__setupzipfile__() finally: shutil.rmtree(tmp_dir, True)