diff -r fd6446a88fe3 -r aa68d35988bb Lib/packaging/command/__init__.py --- a/Lib/packaging/command/__init__.py Wed Jun 15 23:58:57 2011 +0200 +++ b/Lib/packaging/command/__init__.py Thu Jun 16 17:15:53 2011 +0800 @@ -22,6 +22,7 @@ 'install_data': 'packaging.command.install_data.install_data', 'install_distinfo': 'packaging.command.install_distinfo.install_distinfo', + 'develop_source': 'packaging.command.develop_source.develop_source', 'sdist': 'packaging.command.sdist.sdist', 'bdist': 'packaging.command.bdist.bdist', 'bdist_dumb': 'packaging.command.bdist_dumb.bdist_dumb', diff -r fd6446a88fe3 -r aa68d35988bb Lib/packaging/command/cmd.py --- a/Lib/packaging/command/cmd.py Wed Jun 15 23:58:57 2011 +0200 +++ b/Lib/packaging/command/cmd.py Thu Jun 16 17:15:53 2011 +0800 @@ -307,6 +307,12 @@ setattr(self, dst_option, getattr(src_cmd_obj, src_option)) + def reinitialize_command(self, command, reinit_subcommands=False, **kw): + cmd = self.get_reinitialized_command(command, reinit_subcommands) + for k,v in kw.items(): + setattr(cmd,k,v) # update command with keywords + return cmd + def get_finalized_command(self, command, create=True): """Wrapper around Distribution's 'get_command_obj()' method: find (create if necessary and 'create' is true) the command object for diff -r fd6446a88fe3 -r aa68d35988bb Lib/packaging/command/develop_source.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/packaging/command/develop_source.py Thu Jun 16 17:15:53 2011 +0800 @@ -0,0 +1,171 @@ +"""Develop command, which can deploy a project source in 'Development Mode'. """ +import os +import sys + +from packaging import logger +from packaging.util import (write_file, convert_path) +from packaging.command.cmd import Command + +from packaging.errors import PackagingOptionError + +from packaging.dist import Distribution + +import sysconfig + +from sysconfig import get_paths + + +class develop_source(Command): + + description = "install package in 'development mode'" + + # Note 4: these user options may be not complete, and should be modified or + # improved in future + user_options = [ + ('uninstall', None, "Uninstall this source package"), + ('multi-version', None, "Make apps have to require() a version"), + ('install-dir', None, "Install package to DIR"), + ('script-dir', None, "Install scripts to DIR"), + ('exclude-scripts', None, "Don't install scripts"), + ('always-copy', None, "Copy all needed packages to install dir"), + ('egg-path', None, "Set the path to be used in the .dist-link file")] + + boolean_options = ['multi-version', 'always-copy', 'uninstall'] + + def run(self): + if self.uninstall: + self.multi_version = True + self.uninstall_link() + else: + self.install_for_development() + # self.warn_deprecated_options??? + ## + def initialize_options(self): + self.uninstall = None + self.dist_path = None # .dist-info directory path + self.install_dir = None #self.install_lib # + + self.path_file = None # the .pth file name + self.multi_version = None # Note 7: should be set from setup.cfg + + self.always_copy_from = '.' # always copy .dist-info directory installed in curdir??? + + def finalize_options(self):#not complete function , need careful consideration + self.reinitialize_command('install_distinfo', distinfo_dir = os.curdir) + di = self.get_finalized_command("install_distinfo") + self.path_file = di.dist_name + # Note 2: install_distinfo always create new dist-info files, instead of copying + # so broken_dist_info is unuseful now + # if di.broken_dist_info:#Fix: does not have broken_dist_info yet !! + # pass + # + # should act as easy_install.finalize_options(self) ??? + + # the following is to check if it is safe to install this distribution in a directory + # here for 'develop' command, just two files will be created in it: + # .pth file and .dist-link file + + #-----------------may be taken as a function------------------- + scheme = get_paths(os.name, expand = False) + purelib = scheme.get('purelib') + if os.name == 'posix' or os.name == 'nt': + purelib = os.path.expanduser(purelib) + config_vars={} + config_vars['base'] = os.path.normpath(sys.prefix) + purelib = sysconfig._subst_vars(purelib, config_vars)#'prefix' and 'base' ??? + self.install_dir = convert_path(purelib) # the default value of install_dir always is the purelib path, configuration of setup.cfg will be added later; should be noramlized + #print('installdir:'+self.install_dir) + #--------------------------------------------------------- + + #PYTHONPATH = os.environ.get('PYTHONPATH','').split(os.pathsep) + #PYTHONPATH = map(normalize_path, list(filter(None, PYTHONPATH))) #python3.x format + sys_path = map(normalize_path, sys.path) + instdir = normalize_path(self.install_dir) + #print(instdir) + if instdir not in sys_path: + raise PackagingOptionError("'install_dir' should be contained in 'sys.path' list") + + self.dist_link = os.path.join(self.install_dir, di.dist_name + '.dist-link') + #print('now dist info dir:'+di.distinfo_dir) + self.dist_base = os.path.dirname(di.distinfo_dir)# should create .dist-info directory on curdir + #self.dist_base = os.curdir# should always create dist-dir in place + if self.dist_path is None: + self.dist_path = os.path.abspath(self.dist_base) + + target = normalize_path(self.dist_base) + # check --dist-path option here + # Note 3: we should add a --dist-path option here + # it's named 'egg-path' in setuptools + if normalize_path(os.path.join(self.install_dir, self.dist_path)) != target: + raise PackagingOptionError("'dist-path' must be a relative path from the install" + " directory to " + target) + + # Make a distribution for the package's source + # Is it the right way? + self.dist = Distribution() + self.dist.parse_config_files() #Note 6: add install_dir option support in setup.cfg + + + #print('distbase:'+self.dist_base) + p = self.dist_base.replace(os.sep, '/') + if p != os.curdir: + p = '../' * (p.count('/')+1) + self.setup_path = p + p = normalize_path(os.path.join(self.install_dir, self.dist_path, p)) + if p != normalize_path(os.curdir): + raise PackagingOptionError("Can't get a consistent path to setup.cfg from" + " installation directory", p, normalize_path(os.curdir)) + + def install_for_development(self):# Now focus here: 2011-6-8 21:22 + # Ensure metadata is up-to-date + self.run_command('install_distinfo') + # Build extensions in-place + self.reinitialize_command('build_ext', inplace=1) + self.run_command('build_ext') + #self.install_site_py() # ensure that target dir is site-safe + + # Note 1: site.py is just used by setuptools, so in packaging a proper 'site dir' + # does not have the need of having a site.py in it + + # Fix 1:Any 'bootstrap_install_from' here? + # ???? + + # create a .dist-link file in the installation dir, pointing to our .dist-info directory + logger.info("Creating %s (link to %S)", self.dist_link, self.dist_base) + + if not self.dry_run: + f = open(self.dist_link, "w") + f.write(self.dist_path + "\n" + self.setup_path) + f.close() + # Fix 3: process_distribution() here?? + # ???? + + # create or update the .pth file + self.update_path_file() + + def update_path_file(self): + """Creates/Updates the .pth file""" + + filename = os.path.join(self.install_dir, + self.path_file + ".pth") + + self.dist_location = normalize_path(self.dist_base) # shoud add other locations? be improved in future + + # Remove old .pth file and create new one if necessary + if os.path.islink(filename): + os.path.unlink(filename) + logger.info('removing old path file %r', filename)#warning or info? + + if not self.multi_version: + self.execute(write_file, + (filename, [self.dist_location]), # locations? + "creating %s" % filename) + else: + logger.info("'multi-version' is set, no .pth file will be created") + + + +# The following functions are taken from setuptools' pkg_resources module. +def normalize_path(filename): + """Normalize a file/dir name for comparison purposes""" + return os.path.normcase(os.path.realpath(filename)) \ No newline at end of file diff -r fd6446a88fe3 -r aa68d35988bb Lib/packaging/command/install_distinfo.py --- a/Lib/packaging/command/install_distinfo.py Wed Jun 15 23:58:57 2011 +0200 +++ b/Lib/packaging/command/install_distinfo.py Thu Jun 16 17:15:53 2011 +0800 @@ -61,6 +61,8 @@ self.no_resources = False metadata = self.distribution.metadata + + self.dist_name = to_filename(safe_name(metadata['Name'])) basename = "%s-%s.dist-info" % ( to_filename(safe_name(metadata['Name'])), diff -r fd6446a88fe3 -r aa68d35988bb Lib/packaging/develop.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/packaging/develop.py Thu Jun 16 17:15:53 2011 +0800 @@ -0,0 +1,57 @@ +"""Building blocks for different tools when excuating 'develop' command. + +""" +import os + +from packaging import logger +from packaging.util import (egginfo_to_distinfo, get_develop_method) + +from packaging.dist import Distribution +from packaging.errors import (PackagingError, CCompilerError) + + +# The function term is studying from 'install_local_project' of install.py +def develop_local_project(path): + """ Deploy a project source in the 'development mode' from a source directory. + + If the source directory contains a setup.py, using distutils1. + If a setup.cfg is found, then using the XXX command. + """ + path = os.path.abspath(path) + if os.path.isdir(path): + logger.info('deploying from source directory:%s', path) + _run_develop_from_dir(path) + else: + logger.warn('no projects to install') + +def _run_develop_from_dir(source_dir): + old_dir = os.getcwd() + os.chdir(source_dir) + develop_method = get_develop_method(source_dir) + try: + func = develop_methods[develop_method] + return func(source_dir) + finally: + os.chdir(old_dir) + +def _run_packaging_develop(path): + dist = Distribution() + dist.parse_config_files() + try: + dist.run_command('develop_source') + except (IOError, os.error, PackagingError, CCompilerError) as msg: + raise SystemExit("error: " + str(msg)) + +def _run_setuptools_develop(path): # check!!! + cmd = '%s setup.py develop --record=%s' # Note 5: check if there are other options should be supported? + record_file = os.path.join(path, 'RECORD') + os.system(cmd % (sys.executable, record_file)) + if not os.path.exists(record_file): + raise ValueError('failed to install') + else: + egginfo_to_distinfo(record_file, remove_egginfo = True) + +# different develop methods +develop_methods = { + 'packaging': _run_packaging_develop, + 'setuptools': _run_setuptools_develop} \ No newline at end of file diff -r fd6446a88fe3 -r aa68d35988bb Lib/packaging/run.py --- a/Lib/packaging/run.py Wed Jun 15 23:58:57 2011 +0200 +++ b/Lib/packaging/run.py Thu Jun 16 17:15:53 2011 +0800 @@ -11,6 +11,7 @@ from packaging.util import _is_archive_file, generate_setup_py from packaging.command import get_command_class, STANDARD_COMMANDS from packaging.install import install, install_local_project, remove +from packaging.develop import develop_local_project from packaging.database import get_distribution, get_distributions from packaging.depgraph import generate_graph from packaging.fancy_getopt import FancyGetopt @@ -70,6 +71,17 @@ """ +develop_usage = """\ +Usage: pysetup develop [src_dir] + or: pysetup develop --help + +Deploy a project source in 'development mode'. + +positional arguments: + scr_dir path to source directory + +""" + metadata_usage = """\ Usage: pysetup metadata [dist] [-f field ...] or: pysetup metadata [dist] [--all] @@ -255,6 +267,21 @@ else: return 1 +@action_help(develop_usage) +def _develop(dispatcher, args, **kw): + # first check if we are in a source directory + if len(args) < 2: + # are we inside a project source dir? + listing = os.listdir(os.getcwd()) + if 'setup.py' in listing or 'setup.cfg' in listing: + args.insert(1, os.getcwd()) + else: + logger.warning('no project to deploy') + return + # installing from a source dir + if os.path.isdir(args[1]): + develop_local_project(args[1]) + @action_help(metadata_usage) def _metadata(dispatcher, args, **kw): @@ -389,6 +416,7 @@ ('run', 'Run one or several commands', _run), ('metadata', 'Display the metadata of a project', _metadata), ('install', 'Install a project', _install), + ('develop', 'Deploy a project source in development mode', _develop), ('remove', 'Remove a project', _remove), ('search', 'Search for a project in the indexes', _search), ('list', 'List installed releases', _list),