mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			175 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			175 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, 'wb').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='\n',
 | 
						|
                                            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='\n',
 | 
						|
                                        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, 'rb') as fp:
 | 
						|
                                hash = hashlib.md5()
 | 
						|
                                hash.update(fp.read())
 | 
						|
                            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('-', '_')
 |