diff options
author | PJ Eby <distutils-sig@python.org> | 2005-07-24 02:41:44 +0000 |
---|---|---|
committer | PJ Eby <distutils-sig@python.org> | 2005-07-24 02:41:44 +0000 |
commit | baaa492f8f3100a24d723a7bb6c1d4c13295d5fb (patch) | |
tree | e8cc9c962a720f5f1a056498211355ccda534888 /setuptools/command/easy_install.py | |
parent | 20851ca9363b0fded18d42c3bd0f2dd2105f5093 (diff) | |
download | external_python_setuptools-baaa492f8f3100a24d723a7bb6c1d4c13295d5fb.tar.gz external_python_setuptools-baaa492f8f3100a24d723a7bb6c1d4c13295d5fb.tar.bz2 external_python_setuptools-baaa492f8f3100a24d723a7bb6c1d4c13295d5fb.zip |
Implement --editable option, which allows you to just download and extract
(or check out from Subversion) one or more source distributions, without
actually building or installing them (or their dependencies).
--HG--
branch : setuptools
extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4041147
Diffstat (limited to 'setuptools/command/easy_install.py')
-rwxr-xr-x | setuptools/command/easy_install.py | 232 |
1 files changed, 116 insertions, 116 deletions
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 37aa496a..110ad211 100755 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -69,17 +69,17 @@ class easy_install(Command): "filename in which to record list of installed files"), ('always-unzip', 'Z', "don't install as a zipfile, no matter what"), ('site-dirs=','S',"list of directories where .pth files work"), + ('editable', 'e', "Install specified packages in editable form"), ] boolean_options = [ 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', - 'delete-conflicting', 'ignore-conflicts-at-my-risk', + 'delete-conflicting', 'ignore-conflicts-at-my-risk', 'editable', ] negative_opt = {'always-unzip': 'zip-ok'} create_index = PackageIndex - def initialize_options(self): self.zip_ok = None self.install_dir = self.script_dir = self.exclude_scripts = None @@ -89,6 +89,8 @@ class easy_install(Command): self.args = None self.optimize = self.record = None self.upgrade = self.always_copy = self.multi_version = None + self.editable = None + # Options not specifiable via command line self.package_index = None self.pth_file = None @@ -119,8 +121,6 @@ class easy_install(Command): - - def finalize_options(self): # If a non-default installation directory was specified, default the # script directory to match it. @@ -203,27 +203,18 @@ class easy_install(Command): "--ignore-conflicts-at-my-risk at the same time" ) - if not self.args: + if self.editable and not self.build_directory: raise DistutilsArgError( - "No urls, filenames, or requirements specified (see --help)") + "Must specify a build directory (-b) when using --editable" + ) - elif len(self.args)>1 and self.build_directory is not None: + if not self.args: raise DistutilsArgError( - "Build directory can only be set when using one URL" - ) + "No urls, filenames, or requirements specified (see --help)") self.outputs = [] - def alloc_tmp(self): - if self.build_directory is None: - return tempfile.mkdtemp(prefix="easy_install-") - tmpdir = os.path.realpath(self.build_directory) - if not os.path.isdir(tmpdir): - os.makedirs(tmpdir) - return tmpdir - - def run(self): if self.verbose<>self.distribution.verbose: log.set_verbosity(self.verbose) @@ -244,21 +235,6 @@ class easy_install(Command): - def add_output(self, path): - if os.path.isdir(path): - for base, dirs, files in os.walk(path): - for filename in files: - self.outputs.append(os.path.join(base,filename)) - else: - self.outputs.append(path) - - - - - - - - @@ -268,9 +244,32 @@ class easy_install(Command): + def add_output(self, path): + if os.path.isdir(path): + for base, dirs, files in os.walk(path): + for filename in files: + self.outputs.append(os.path.join(base,filename)) + else: + self.outputs.append(path) + def not_editable(self, spec): + if self.editable: + raise DistutilsArgError( + "Invalid argument %r: you can't use filenames or URLs " + "with --editable (except via the --find-links option)." + % (spec,) + ) + def check_editable(self,spec): + if not self.editable: + return + if os.path.exists(os.path.join(self.build_directory, spec.key)): + raise DistutilsArgError( + "%r already exists in %s; can't do a checkout there" % + (spec.key, self.build_directory) + ) + @@ -282,36 +281,33 @@ class easy_install(Command): + def easy_install(self, spec): - tmpdir = self.alloc_tmp() + tmpdir = tempfile.mkdtemp(prefix="easy_install-") download = None try: if not isinstance(spec,Requirement): if URL_SCHEME(spec): # It's a url, download it to tmpdir and process + self.not_editable(spec) download = self.package_index.download(spec, tmpdir) return self.install_item(None, download, tmpdir, True) elif os.path.exists(spec): # Existing file or directory, just process it directly + self.not_editable(spec) return self.install_item(None, spec, tmpdir, True) else: - try: - spec = Requirement.parse(spec) - except ValueError: - raise DistutilsError( - "Not a URL, existing file, or requirement spec: %r" - % (spec,) - ) - - if isinstance(spec, Requirement): - download = self.package_index.fetch(spec, tmpdir, self.upgrade) - else: - spec = None + spec = parse_requirement_arg(spec) + + self.check_editable(spec) + download = self.package_index.fetch( + spec, tmpdir, self.upgrade, self.editable + ) if download is None: raise DistutilsError( @@ -321,18 +317,22 @@ class easy_install(Command): return self.install_item(spec, download, tmpdir) finally: - if self.build_directory is None: + if os.path.exists(tmpdir): shutil.rmtree(tmpdir) + + + + def install_item(self, spec, download, tmpdir, install_needed=False): # Installation is also needed if file in tmpdir or is not an egg install_needed = install_needed or os.path.dirname(download) == tmpdir install_needed = install_needed or not download.endswith('.egg') log.info("Processing %s", os.path.basename(download)) if install_needed or self.always_copy: - dists = self.install_eggs(download, tmpdir) + dists = self.install_eggs(spec, download, tmpdir) for dist in dists: self.process_distribution(spec, dist) else: @@ -386,28 +386,28 @@ class easy_install(Command): return True return False - - - - - - - - - - - - - - - - - - - - - - + def maybe_move(self, spec, dist_filename, setup_base): + dst = os.path.join(self.build_directory, spec.key) + if os.path.exists(dst): + log.warn( + "%r already exists in %s; build directory %s will not be kept", + spec.key, self.build_directory, setup_base + ) + return setup_base + if os.path.isdir(dist_filename): + setup_base = dist_filename + else: + if os.path.dirname(dist_filename)==setup_base: + os.unlink(dist_filename) # get it out of the tmp dir + contents = os.listdir(setup_base) + if len(contents)==1: + dist_filename = os.path.join(setup_base,contents[0]) + if os.path.isdir(dist_filename): + # if the only thing there is a directory, move it instead + setup_base = dist_filename + ensure_directory(dst); shutil.move(setup_base, dst) + return dst + def install_script(self, dist, script_name, script_text, dev_path=None): log.info("Installing %s script to %s", script_name,self.script_dir) target = os.path.join(self.script_dir, script_name) @@ -449,7 +449,7 @@ class easy_install(Command): pass - def install_eggs(self, dist_filename, tmpdir): + def install_eggs(self, spec, dist_filename, tmpdir): # .egg dirs or files are already built, so just return them if dist_filename.lower().endswith('.egg'): return [self.install_egg(dist_filename, tmpdir)] @@ -461,8 +461,12 @@ class easy_install(Command): if os.path.isfile(dist_filename): unpack_archive(dist_filename, tmpdir, self.unpack_progress) elif os.path.isdir(dist_filename): + # note that setup_base==tmpdir here if this is a svn checkout setup_base = os.path.abspath(dist_filename) + if setup_base==tmpdir and self.build_directory and spec is not None: + setup_base = self.maybe_move(spec, dist_filename, setup_base) + # Find the setup.py file setup_script = os.path.join(setup_base, 'setup.py') @@ -479,15 +483,11 @@ class easy_install(Command): setup_script = setups[0] # Now run it, and return the result - return self.build_and_install(setup_script, setup_base) - - - - - - - - + if self.editable: + log.warn(self.report_editable(spec, setup_script)) + return [] + else: + return self.build_and_install(setup_script, setup_base) def egg_distribution(self, egg_path): @@ -723,24 +723,24 @@ PYTHONPATH, or by being added to sys.path by your code.) version = dist.version return msg % locals() + def report_editable(self, spec, setup_script): + dirname = os.path.dirname(setup_script) + python = sys.executable + return """\nExtracted editable version of %(spec)s to %(dirname)s +If it uses setuptools in its setup script, you can activate it in +"development" mode by going to that directory and running:: + %(python)s setup.py --develop +See the setuptools documentation for the "develop" command for more info. +""" % locals() - - - - - - - - - - def build_and_install(self, setup_script, setup_base): + def run_setup(self, setup_script, setup_base, args): sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg) - sys.modules.setdefault('distutils.command.bdist_egg', egg_info) + sys.modules.setdefault('distutils.command.egg_info', egg_info) - args = ['bdist_egg', '--dist-dir'] + args = list(args) if self.verbose>2: v = 'v' * self.verbose - 1 args.insert(0,'-'+v) @@ -748,31 +748,31 @@ PYTHONPATH, or by being added to sys.path by your code.) args.insert(0,'-q') if self.dry_run: args.insert(0,'-n') + log.info( + "Running %s %s", setup_script[len(setup_base)+1:], ' '.join(args) + ) + try: + run_setup(setup_script, args) + except SystemExit, v: + raise DistutilsError("Setup script exited with %s" % (v.args[0],)) - dist_dir = tempfile.mkdtemp(prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script)) + def build_and_install(self, setup_script, setup_base): + args = ['bdist_egg', '--dist-dir'] + dist_dir = tempfile.mkdtemp( + prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script) + ) try: args.append(dist_dir) - log.info( - "Running %s %s", setup_script[len(setup_base)+1:], - ' '.join(args) - ) - try: - run_setup(setup_script, args) - except SystemExit, v: - raise DistutilsError( - "Setup script exited with %s" % (v.args[0],) - ) - + self.run_setup(setup_script, setup_base, args) + all_eggs = AvailableDistributions([dist_dir]) eggs = [] - for egg in glob(os.path.join(dist_dir,'*.egg')): - eggs.append(self.install_egg(egg, setup_base)) - + for key in eggs: + for dist in eggs[key]: + eggs.append(self.install_egg(egg, setup_base)) if not eggs and not self.dry_run: log.warn("No eggs found in %s (setup script problem?)", dist_dir) - return eggs - finally: shutil.rmtree(dist_dir) log.set_verbosity(self.verbose) # restore our log verbosity @@ -1010,13 +1010,13 @@ def get_exe_prefixes(exe_filename): return prefixes - - - - - - - +def parse_requirement_arg(spec): + try: + return Requirement.parse(spec) + except ValueError: + raise DistutilsError( + "Not a URL, existing file, or requirement spec: %r" % (spec,) + ) |