Skip to content

Commit

Permalink
Fix -s option not pulling in transitive dependencies, fixes #22.
Browse files Browse the repository at this point in the history
Takes packages passed in via -s and builds source distributions out of them
and then feeds them through the standard requirement resolution pipeline.
This ensures that transitive requirements are pulled in.

Also adds some debugging information in the package translation step when
certain packages are untranslateable.
  • Loading branch information
wickman committed Nov 22, 2014
1 parent 7abe3ad commit c5c2444
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 12 deletions.
35 changes: 25 additions & 10 deletions pex/bin/pex.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
from __future__ import absolute_import, print_function

import os
import shutil
import sys
from optparse import OptionParser

from pex.common import safe_delete, safe_mkdtemp
from pex.fetcher import Fetcher, PyPIFetcher
from pex.installer import EggInstaller, WheelInstaller
from pex.installer import EggInstaller, Packager, WheelInstaller
from pex.interpreter import PythonInterpreter
from pex.package import EggPackage, SourcePackage, WheelPackage
from pex.package import EggPackage, Package, SourcePackage, WheelPackage
from pex.pex import PEX
from pex.pex_builder import PEXBuilder
from pex.platforms import Platform
Expand Down Expand Up @@ -269,9 +270,30 @@ def build_pex(args, options):
else:
precedence = (EggPackage, SourcePackage)

requirements = options.requirements[:]

if options.source_dirs:
temporary_package_root = safe_mkdtemp()

for source_dir in options.source_dirs:
try:
sdist = Packager(source_dir).sdist()
except installer.Error:
die('Failed to run installer for %s' % source_dir, CANNOT_DISTILL)

# record the requirement information
sdist_pkg = Package.from_href(sdist)
requirements.append('%s==%s' % (sdist_pkg.name, sdist_pkg.raw_version))

# copy the source distribution
shutil.copyfile(sdist, os.path.join(temporary_package_root, os.path.basename(sdist)))

# Tell pex where to find the packages
fetchers.append(Fetcher([temporary_package_root]))

with TRACER.timed('Resolving distributions'):
resolveds = requirement_resolver(
options.requirements,
requirements,
fetchers=fetchers,
translator=translator,
interpreter=interpreter,
Expand All @@ -285,13 +307,6 @@ def build_pex(args, options):
pex_builder.add_distribution(pkg)
pex_builder.add_requirement(pkg.as_requirement())

for source_dir in options.source_dirs:
try:
bdist = installer(source_dir).bdist()
except installer.Error:
die('Failed to run installer for %s' % source_dir, CANNOT_DISTILL)
pex_builder.add_dist_location(bdist)

if options.entry_point is not None:
log('Setting entry point to %s' % options.entry_point, v=options.verbosity)
pex_builder.info.entry_point = options.entry_point
Expand Down
2 changes: 1 addition & 1 deletion pex/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def __init__(self, source_dir, strict=True, interpreter=None, install_dir=None):
self._interpreter = interpreter or PythonInterpreter.get()
if not self._interpreter.satisfies(self.capability) and strict:
raise self.IncapableInterpreter('Interpreter %s not capable of running %s' % (
self._interpreter, self.__class__.__name__))
self._interpreter.binary, self.__class__.__name__))

def mixins(self):
"""Return a map from import name to requirement to load into setup script prior to invocation.
Expand Down
8 changes: 7 additions & 1 deletion pex/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,18 @@ def translate(self, package, into=None):
with TRACER.timed('Packaging %s' % package.name):
try:
dist_path = installer.bdist()
except self._installer_impl.InstallFailure:
except self._installer_impl.InstallFailure as e:
TRACER.log('Failed to install package at %s: %s' % (unpack_path, e))
return None
target_path = os.path.join(into, os.path.basename(dist_path))
safe_copy(dist_path, target_path)
target_package = Package.from_href(target_path)
if not target_package:
TRACER.log('Target path %s does not look like a Package.' % target_path)
return None
if not target_package.compatible(self._interpreter.identity, platform=self._platform):
TRACER.log('Target package %s is not compatible with %s / %s' % (
target_package, self._interpreter.identity, self._platform))
return None
return DistributionHelper.distribution_from_path(target_path)
except Exception as e:
Expand Down Expand Up @@ -131,6 +135,8 @@ def translate(self, package, into=None):
if not isinstance(package, self._package_type):
return None
if not package.compatible(identity=self._identity, platform=self._platform):
TRACER.log('Target package %s is not compatible with %s / %s' % (
package, self._identity, self._platform))
return None
into = into or safe_mkdtemp()
target_path = os.path.join(into, package.filename)
Expand Down

0 comments on commit c5c2444

Please sign in to comment.