mirror of
				https://github.com/python/cpython.git
				synced 2025-10-26 19:24:34 +00:00 
			
		
		
		
	
		
			
	
	
		
			176 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			176 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | """Create the PEP 376-compliant .dist-info directory.""" | ||
|  | 
 | ||
|  | # Forked from the former install_egg_info command by Josip Djolonga | ||
|  | 
 | ||
|  | import csv | ||
|  | import os | ||
|  | import re | ||
|  | import hashlib | ||
|  | 
 | ||
|  | from packaging.command.cmd import Command | ||
|  | from packaging import logger | ||
|  | from shutil import rmtree | ||
|  | 
 | ||
|  | 
 | ||
|  | class install_distinfo(Command): | ||
|  | 
 | ||
|  |     description = 'create a .dist-info directory for the distribution' | ||
|  | 
 | ||
|  |     user_options = [ | ||
|  |         ('distinfo-dir=', None, | ||
|  |          "directory where the the .dist-info directory will be installed"), | ||
|  |         ('installer=', None, | ||
|  |          "the name of the installer"), | ||
|  |         ('requested', None, | ||
|  |          "generate a REQUESTED file"), | ||
|  |         ('no-requested', None, | ||
|  |          "do not generate a REQUESTED file"), | ||
|  |         ('no-record', None, | ||
|  |          "do not generate a RECORD file"), | ||
|  |         ('no-resources', None, | ||
|  |          "do not generate a RESSOURCES list installed file") | ||
|  |     ] | ||
|  | 
 | ||
|  |     boolean_options = ['requested', 'no-record', 'no-resources'] | ||
|  | 
 | ||
|  |     negative_opt = {'no-requested': 'requested'} | ||
|  | 
 | ||
|  |     def initialize_options(self): | ||
|  |         self.distinfo_dir = None | ||
|  |         self.installer = None | ||
|  |         self.requested = None | ||
|  |         self.no_record = None | ||
|  |         self.no_resources = None | ||
|  | 
 | ||
|  |     def finalize_options(self): | ||
|  |         self.set_undefined_options('install_dist', | ||
|  |                                    'installer', 'requested', 'no_record') | ||
|  | 
 | ||
|  |         self.set_undefined_options('install_lib', | ||
|  |                                    ('install_dir', 'distinfo_dir')) | ||
|  | 
 | ||
|  |         if self.installer is None: | ||
|  |             # FIXME distutils or packaging? | ||
|  |             # + document default in the option help text above and in install | ||
|  |             self.installer = 'distutils' | ||
|  |         if self.requested is None: | ||
|  |             self.requested = True | ||
|  |         if self.no_record is None: | ||
|  |             self.no_record = False | ||
|  |         if self.no_resources is None: | ||
|  |             self.no_resources = False | ||
|  | 
 | ||
|  |         metadata = self.distribution.metadata | ||
|  | 
 | ||
|  |         basename = "%s-%s.dist-info" % ( | ||
|  |             to_filename(safe_name(metadata['Name'])), | ||
|  |             to_filename(safe_version(metadata['Version']))) | ||
|  | 
 | ||
|  |         self.distinfo_dir = os.path.join(self.distinfo_dir, basename) | ||
|  |         self.outputs = [] | ||
|  | 
 | ||
|  |     def run(self): | ||
|  |         # FIXME dry-run should be used at a finer level, so that people get | ||
|  |         # useful logging output and can have an idea of what the command would | ||
|  |         # have done | ||
|  |         if not self.dry_run: | ||
|  |             target = self.distinfo_dir | ||
|  | 
 | ||
|  |             if os.path.isdir(target) and not os.path.islink(target): | ||
|  |                 rmtree(target) | ||
|  |             elif os.path.exists(target): | ||
|  |                 self.execute(os.unlink, (self.distinfo_dir,), | ||
|  |                              "removing " + target) | ||
|  | 
 | ||
|  |             self.execute(os.makedirs, (target,), "creating " + target) | ||
|  | 
 | ||
|  |             metadata_path = os.path.join(self.distinfo_dir, 'METADATA') | ||
|  |             logger.info('creating %s', metadata_path) | ||
|  |             self.distribution.metadata.write(metadata_path) | ||
|  |             self.outputs.append(metadata_path) | ||
|  | 
 | ||
|  |             installer_path = os.path.join(self.distinfo_dir, 'INSTALLER') | ||
|  |             logger.info('creating %s', installer_path) | ||
|  |             with open(installer_path, 'w') as f: | ||
|  |                 f.write(self.installer) | ||
|  |             self.outputs.append(installer_path) | ||
|  | 
 | ||
|  |             if self.requested: | ||
|  |                 requested_path = os.path.join(self.distinfo_dir, 'REQUESTED') | ||
|  |                 logger.info('creating %s', requested_path) | ||
|  |                 open(requested_path, 'w').close() | ||
|  |                 self.outputs.append(requested_path) | ||
|  | 
 | ||
|  | 
 | ||
|  |             if not self.no_resources: | ||
|  |                 install_data = self.get_finalized_command('install_data') | ||
|  |                 if install_data.get_resources_out() != []: | ||
|  |                     resources_path = os.path.join(self.distinfo_dir, | ||
|  |                                                   'RESOURCES') | ||
|  |                     logger.info('creating %s', resources_path) | ||
|  |                     with open(resources_path, 'wb') as f: | ||
|  |                         writer = csv.writer(f, delimiter=',', | ||
|  |                                             lineterminator=os.linesep, | ||
|  |                                             quotechar='"') | ||
|  |                         for tuple in install_data.get_resources_out(): | ||
|  |                             writer.writerow(tuple) | ||
|  | 
 | ||
|  |                         self.outputs.append(resources_path) | ||
|  | 
 | ||
|  |             if not self.no_record: | ||
|  |                 record_path = os.path.join(self.distinfo_dir, 'RECORD') | ||
|  |                 logger.info('creating %s', record_path) | ||
|  |                 with open(record_path, 'w', encoding='utf-8') as f: | ||
|  |                     writer = csv.writer(f, delimiter=',', | ||
|  |                                         lineterminator=os.linesep, | ||
|  |                                         quotechar='"') | ||
|  | 
 | ||
|  |                     install = self.get_finalized_command('install_dist') | ||
|  | 
 | ||
|  |                     for fpath in install.get_outputs(): | ||
|  |                         if fpath.endswith('.pyc') or fpath.endswith('.pyo'): | ||
|  |                             # do not put size and md5 hash, as in PEP-376 | ||
|  |                             writer.writerow((fpath, '', '')) | ||
|  |                         else: | ||
|  |                             size = os.path.getsize(fpath) | ||
|  |                             with open(fpath, 'r') as fp: | ||
|  |                                 hash = hashlib.md5() | ||
|  |                                 hash.update(fp.read().encode()) | ||
|  |                             md5sum = hash.hexdigest() | ||
|  |                             writer.writerow((fpath, md5sum, size)) | ||
|  | 
 | ||
|  |                     # add the RECORD file itself | ||
|  |                     writer.writerow((record_path, '', '')) | ||
|  |                     self.outputs.append(record_path) | ||
|  | 
 | ||
|  |     def get_outputs(self): | ||
|  |         return self.outputs | ||
|  | 
 | ||
|  | 
 | ||
|  | # The following functions are taken from setuptools' pkg_resources module. | ||
|  | 
 | ||
|  | def safe_name(name): | ||
|  |     """Convert an arbitrary string to a standard distribution name
 | ||
|  | 
 | ||
|  |     Any runs of non-alphanumeric/. characters are replaced with a single '-'. | ||
|  |     """
 | ||
|  |     return re.sub('[^A-Za-z0-9.]+', '-', name) | ||
|  | 
 | ||
|  | 
 | ||
|  | def safe_version(version): | ||
|  |     """Convert an arbitrary string to a standard version string
 | ||
|  | 
 | ||
|  |     Spaces become dots, and all other non-alphanumeric characters become | ||
|  |     dashes, with runs of multiple dashes condensed to a single dash. | ||
|  |     """
 | ||
|  |     version = version.replace(' ', '.') | ||
|  |     return re.sub('[^A-Za-z0-9.]+', '-', version) | ||
|  | 
 | ||
|  | 
 | ||
|  | def to_filename(name): | ||
|  |     """Convert a project or version name to its filename-escaped form
 | ||
|  | 
 | ||
|  |     Any '-' characters are currently replaced with '_'. | ||
|  |     """
 | ||
|  |     return name.replace('-', '_') |