mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
More split up
This commit is contained in:
+82
-227
@@ -1,11 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
from click import (
|
||||
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import click_completion
|
||||
from pipenv.vendor.click import (
|
||||
argument,
|
||||
command,
|
||||
echo,
|
||||
edit,
|
||||
group,
|
||||
Group,
|
||||
option,
|
||||
@@ -14,29 +16,24 @@ from click import (
|
||||
version_option,
|
||||
BadParameter,
|
||||
)
|
||||
from click_didyoumean import DYMCommandCollection
|
||||
|
||||
import click_completion
|
||||
import crayons
|
||||
import delegator
|
||||
|
||||
from .__version__ import __version__
|
||||
from pipenv.vendor.click_didyoumean import DYMCommandCollection
|
||||
|
||||
from . import environments
|
||||
from .__version__ import __version__
|
||||
from .utils import is_valid_url
|
||||
|
||||
# Enable shell completion.
|
||||
click_completion.init()
|
||||
|
||||
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
|
||||
|
||||
|
||||
class PipenvGroup(Group):
|
||||
"""Custom Group class provides formatted main help"""
|
||||
|
||||
"""Custom Group class provides formatted main help.
|
||||
"""
|
||||
def get_help_option(self, ctx):
|
||||
from .core import format_help
|
||||
|
||||
"""Override for showing formatted main help via --help and -h options"""
|
||||
"""Show formatted main help via --help and -h options.
|
||||
"""
|
||||
help_options = self.get_help_option_names(ctx)
|
||||
if not help_options or not self.add_help_option:
|
||||
return
|
||||
@@ -45,6 +42,7 @@ class PipenvGroup(Group):
|
||||
if value and not ctx.resilient_parsing:
|
||||
if not ctx.invoked_subcommand:
|
||||
# legit main help
|
||||
from .operations.help import format_help
|
||||
echo(format_help(ctx.get_help()))
|
||||
else:
|
||||
# legit sub-command help
|
||||
@@ -76,7 +74,9 @@ def validate_python_path(ctx, param, value):
|
||||
# we'll report absolute paths which do not exist:
|
||||
if isinstance(value, (str, bytes)):
|
||||
if os.path.isabs(value) and not os.path.isfile(value):
|
||||
raise BadParameter('Expected Python at path %s does not exist' % value)
|
||||
raise BadParameter(
|
||||
'Expected Python at path {} does not exist'.format(value),
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
@@ -165,120 +165,52 @@ def cli(
|
||||
completion=False,
|
||||
):
|
||||
if completion: # Handle this ASAP to make shell startup fast.
|
||||
from . import shells
|
||||
try:
|
||||
shell = shells.detect_info()[0]
|
||||
except shells.ShellDetectionFailure:
|
||||
echo(
|
||||
'Fail to detect shell. Please provide the {0} environment '
|
||||
'variable.'.format(crayons.normal('PIPENV_SHELL', bold=True)),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
print(click_completion.get_code(shell=shell, prog_name='pipenv'))
|
||||
sys.exit(0)
|
||||
|
||||
from .core import (
|
||||
do_py,
|
||||
warn_in_virtualenv,
|
||||
project,
|
||||
format_help
|
||||
)
|
||||
from .operations.options import do_completion
|
||||
do_completion()
|
||||
return
|
||||
if man:
|
||||
from .utils import system_which
|
||||
if system_which('man'):
|
||||
path = os.sep.join([os.path.dirname(__file__), 'pipenv.1'])
|
||||
os.execle(system_which('man'), 'man', path, os.environ)
|
||||
else:
|
||||
echo(
|
||||
'man does not appear to be available on your system.', err=True
|
||||
)
|
||||
from .operations.options import do_man
|
||||
do_man()
|
||||
return
|
||||
if envs:
|
||||
echo(
|
||||
'The following environment variables can be set, to do various things:\n'
|
||||
)
|
||||
for key in environments.__dict__:
|
||||
if key.startswith('PIPENV'):
|
||||
echo(' - {0}'.format(crayons.normal(key, bold=True)))
|
||||
echo(
|
||||
'\nYou can learn more at:\n {0}'.format(
|
||||
crayons.green(
|
||||
'http://docs.pipenv.org/advanced/#configuration-with-environment-variables'
|
||||
)
|
||||
)
|
||||
)
|
||||
sys.exit(0)
|
||||
from .operations.options import do_envs
|
||||
do_envs()
|
||||
return
|
||||
|
||||
from .operations.options import warn_in_virtualenv
|
||||
warn_in_virtualenv()
|
||||
if ctx.invoked_subcommand is None:
|
||||
# --where was passed...
|
||||
if where:
|
||||
from .operations.where import do_where
|
||||
do_where(bare=True)
|
||||
sys.exit(0)
|
||||
elif py:
|
||||
do_py()
|
||||
sys.exit()
|
||||
# --venv was passed...
|
||||
elif venv:
|
||||
# There is no virtualenv yet.
|
||||
if not project.virtualenv_exists:
|
||||
echo(
|
||||
crayons.red(
|
||||
'No virtualenv has been created for this project yet!'
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
else:
|
||||
echo(project.virtualenv_location)
|
||||
sys.exit(0)
|
||||
# --rm was passed...
|
||||
elif rm:
|
||||
# Abort if --system (or running in a virtualenv).
|
||||
if environments.PIPENV_USE_SYSTEM:
|
||||
echo(
|
||||
crayons.red(
|
||||
'You are attempting to remove a virtualenv that '
|
||||
'Pipenv did not create. Aborting.'
|
||||
)
|
||||
)
|
||||
sys.exit(1)
|
||||
if project.virtualenv_exists:
|
||||
loc = project.virtualenv_location
|
||||
echo(
|
||||
crayons.normal(
|
||||
u'{0} ({1})…'.format(
|
||||
crayons.normal('Removing virtualenv', bold=True),
|
||||
crayons.green(loc),
|
||||
)
|
||||
)
|
||||
)
|
||||
# Remove the virtualenv.
|
||||
# TODO: Where can I better put this import? pipenv.ui?
|
||||
from .operations._utils import spinner
|
||||
with spinner():
|
||||
from .operations.virtualenv import cleanup_virtualenv
|
||||
cleanup_virtualenv(bare=True)
|
||||
sys.exit(0)
|
||||
else:
|
||||
echo(
|
||||
crayons.red(
|
||||
'No virtualenv has been created for this project yet!',
|
||||
bold=True,
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
# --two / --three was passed...
|
||||
if (python or three is not None) or site_packages:
|
||||
from .operations.ensure import ensure_project
|
||||
ensure_project(
|
||||
three=three, python=python, warn=True, site_packages=site_packages
|
||||
)
|
||||
# Check this again before exiting for empty ``pipenv`` command.
|
||||
elif ctx.invoked_subcommand is None:
|
||||
# Display help to user, if no commands were passed.
|
||||
echo(format_help(ctx.get_help()))
|
||||
|
||||
# Pre-hook for subcommands.
|
||||
if ctx.invoked_subcommand is not None:
|
||||
# --two / --three was passed...
|
||||
if (python or three is not None) or site_packages:
|
||||
from .operations.ensure import ensure_project
|
||||
ensure_project(
|
||||
three=three, python=python, warn=True,
|
||||
site_packages=site_packages,
|
||||
)
|
||||
return
|
||||
|
||||
if where:
|
||||
from .operations.where import do_where
|
||||
do_where(bare=True)
|
||||
return
|
||||
if py:
|
||||
from .operations.options import do_py
|
||||
do_py()
|
||||
return
|
||||
if venv:
|
||||
from .operations.options import do_venv
|
||||
do_venv()
|
||||
return
|
||||
if rm:
|
||||
from .operations.options import do_rm
|
||||
do_rm()
|
||||
return
|
||||
|
||||
# Display help to user if nothing were passed.
|
||||
from .operations.help import format_help
|
||||
echo(format_help(ctx.get_help()))
|
||||
|
||||
|
||||
@command(
|
||||
@@ -486,7 +418,7 @@ def uninstall(
|
||||
keep_outdated=False,
|
||||
pypi_mirror=None,
|
||||
):
|
||||
from .core import do_uninstall
|
||||
from .operations.uninstall import do_uninstall
|
||||
|
||||
do_uninstall(
|
||||
package_name=package_name,
|
||||
@@ -569,12 +501,15 @@ def lock(
|
||||
pre=False,
|
||||
keep_outdated=False,
|
||||
):
|
||||
from .core import ensure_project, do_init, do_lock
|
||||
|
||||
# Ensure that virtualenv is available.
|
||||
from .operations.ensure import ensure_project
|
||||
ensure_project(three=three, python=python)
|
||||
|
||||
if requirements:
|
||||
from .operations.init import do_init
|
||||
do_init(dev=dev, requirements=requirements, pypi_mirror=pypi_mirror)
|
||||
|
||||
from .operations.lock import do_lock
|
||||
do_lock(
|
||||
verbose=verbose, clear=clear, pre=pre, keep_outdated=keep_outdated, pypi_mirror=pypi_mirror
|
||||
)
|
||||
@@ -613,7 +548,6 @@ def lock(
|
||||
def shell(
|
||||
three=None, python=False, fancy=False, shell_args=None, anyway=False
|
||||
):
|
||||
from .core import load_dot_env, do_shell
|
||||
# Prevent user from activating nested environments.
|
||||
if 'PIPENV_ACTIVE' in os.environ:
|
||||
# If PIPENV_ACTIVE is set, VIRTUAL_ENV should always be set too.
|
||||
@@ -630,11 +564,8 @@ def shell(
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
# Load .env file.
|
||||
load_dot_env()
|
||||
# Use fancy mode for Windows.
|
||||
if os.name == 'nt':
|
||||
fancy = True
|
||||
|
||||
from .operations.shell import do_shell
|
||||
do_shell(
|
||||
three=three, python=python, fancy=fancy, shell_args=shell_args
|
||||
)
|
||||
@@ -711,7 +642,7 @@ def check(
|
||||
ignore=None,
|
||||
args=None,
|
||||
):
|
||||
from .core import do_check
|
||||
from .operations.check import do_check
|
||||
do_check(
|
||||
three=three,
|
||||
python=python,
|
||||
@@ -791,9 +722,7 @@ def check(
|
||||
help=u"List out-of-date dependencies.",
|
||||
)
|
||||
@argument('package', default=False)
|
||||
@pass_context
|
||||
def update(
|
||||
ctx,
|
||||
three=None,
|
||||
python=False,
|
||||
pypi_mirror=None,
|
||||
@@ -810,59 +739,13 @@ def update(
|
||||
outdated=False,
|
||||
more_packages=None,
|
||||
):
|
||||
from .core import (
|
||||
ensure_project,
|
||||
do_outdated,
|
||||
do_lock,
|
||||
do_sync,
|
||||
ensure_lockfile,
|
||||
do_install,
|
||||
project,
|
||||
)
|
||||
|
||||
ensure_project(three=three, python=python, warn=True)
|
||||
if not outdated:
|
||||
outdated = bool(dry_run)
|
||||
if outdated:
|
||||
do_outdated(pypi_mirror=pypi_mirror)
|
||||
if not package:
|
||||
echo(
|
||||
'{0} {1} {2} {3}{4}'.format(
|
||||
crayons.white('Running', bold=True),
|
||||
crayons.red('$ pipenv lock', bold=True),
|
||||
crayons.white('then', bold=True),
|
||||
crayons.red('$ pipenv sync', bold=True),
|
||||
crayons.white('.', bold=True),
|
||||
)
|
||||
)
|
||||
else:
|
||||
for package in ([package] + list(more_packages) or []):
|
||||
if package not in project.all_packages:
|
||||
echo(
|
||||
'{0}: {1} was not found in your Pipfile! Aborting.'
|
||||
''.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
crayons.green(package, bold=True),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
do_lock(
|
||||
verbose=verbose, clear=clear, pre=pre, keep_outdated=keep_outdated, pypi_mirror=pypi_mirror
|
||||
)
|
||||
do_sync(
|
||||
ctx=ctx,
|
||||
dev=dev,
|
||||
three=three,
|
||||
python=python,
|
||||
bare=bare,
|
||||
dont_upgrade=False,
|
||||
user=False,
|
||||
verbose=verbose,
|
||||
clear=clear,
|
||||
unused=False,
|
||||
sequential=sequential,
|
||||
pypi_mirror=pypi_mirror,
|
||||
from .operations.update import do_update
|
||||
do_update(
|
||||
package, list(more_packages) if more_packages else [],
|
||||
three=three, python=python,
|
||||
pypi_mirror=pypi_mirror, verbose=verbose, clear=clear,
|
||||
keep_outdated=keep_outdated, pre=pre, dev=dev, bare=bare,
|
||||
sequential=sequential, dry_run=dry_run, outdated=outdated,
|
||||
)
|
||||
|
||||
|
||||
@@ -876,9 +759,8 @@ def update(
|
||||
'--reverse', is_flag=True, default=False, help="Reversed dependency graph."
|
||||
)
|
||||
def graph(bare=False, json=False, json_tree=False, reverse=False):
|
||||
from .core import do_graph
|
||||
|
||||
do_graph(bare=bare, json=json, json_tree=json_tree, reverse=reverse)
|
||||
from .operations.graph import do_graph
|
||||
do_graph(bare=bare, json_=json, json_tree=json_tree, reverse=reverse)
|
||||
|
||||
|
||||
@command(short_help="View a given module in your editor.", name="open")
|
||||
@@ -897,29 +779,8 @@ def graph(bare=False, json=False, json_tree=False, reverse=False):
|
||||
)
|
||||
@argument('module', nargs=1)
|
||||
def run_open(module, three=None, python=None):
|
||||
from .core import which, ensure_project
|
||||
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False)
|
||||
c = delegator.run(
|
||||
'{0} -c "import {1}; print({1}.__file__);"'.format(
|
||||
which('python'), module
|
||||
)
|
||||
)
|
||||
try:
|
||||
assert c.return_code == 0
|
||||
except AssertionError:
|
||||
echo(crayons.red('Module not found!'))
|
||||
sys.exit(1)
|
||||
if '__init__.py' in c.out:
|
||||
p = os.path.dirname(c.out.strip().rstrip('cdo'))
|
||||
else:
|
||||
p = c.out.strip().rstrip('cdo')
|
||||
echo(
|
||||
crayons.normal('Opening {0!r} in your EDITOR.'.format(p), bold=True)
|
||||
)
|
||||
edit(filename=p)
|
||||
sys.exit(0)
|
||||
from .operations.open import do_open
|
||||
do_open(module, three=three, python=python)
|
||||
|
||||
|
||||
@command(short_help="Installs all packages specified in Pipfile.lock.")
|
||||
@@ -968,9 +829,7 @@ def run_open(module, three=None, python=None):
|
||||
default=False,
|
||||
help="Install dependencies one-at-a-time, instead of concurrently.",
|
||||
)
|
||||
@pass_context
|
||||
def sync(
|
||||
ctx,
|
||||
dev=False,
|
||||
three=None,
|
||||
python=None,
|
||||
@@ -984,10 +843,8 @@ def sync(
|
||||
sequential=False,
|
||||
pypi_mirror=None,
|
||||
):
|
||||
from .core import do_sync
|
||||
|
||||
from .operations.sync import do_sync
|
||||
do_sync(
|
||||
ctx=ctx,
|
||||
dev=dev,
|
||||
three=three,
|
||||
python=python,
|
||||
@@ -1032,9 +889,7 @@ def sync(
|
||||
default=False,
|
||||
help="Just output unneeded packages.",
|
||||
)
|
||||
@pass_context
|
||||
def clean(
|
||||
ctx,
|
||||
three=None,
|
||||
python=None,
|
||||
dry_run=False,
|
||||
@@ -1042,10 +897,9 @@ def clean(
|
||||
user=False,
|
||||
verbose=False,
|
||||
):
|
||||
from .core import do_clean
|
||||
|
||||
from .operations.clean import do_clean
|
||||
do_clean(
|
||||
ctx=ctx, three=three, python=python, dry_run=dry_run, verbose=verbose
|
||||
three=three, python=python, dry_run=dry_run, verbose=verbose
|
||||
)
|
||||
|
||||
|
||||
@@ -1061,6 +915,7 @@ cli.add_command(shell)
|
||||
cli.add_command(run)
|
||||
cli.add_command(update)
|
||||
cli.add_command(run_open)
|
||||
|
||||
# Only invoke the "did you mean" when an argument wasn't passed (it breaks those).
|
||||
if '-' not in ''.join(sys.argv) and len(sys.argv) > 1:
|
||||
cli = DYMCommandCollection(sources=[cli])
|
||||
|
||||
+1
-774
@@ -1,48 +1,8 @@
|
||||
# -*- coding=utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import signal
|
||||
import json as simplejson
|
||||
|
||||
import click
|
||||
import crayons
|
||||
import delegator
|
||||
from .vendor import pexpect
|
||||
import pipfile
|
||||
|
||||
from .project import Project
|
||||
from .vendor.requirementslib import Requirement
|
||||
from .utils import (
|
||||
is_required_version,
|
||||
pep423_name,
|
||||
escape_grouped_arguments,
|
||||
find_windows_executable,
|
||||
temp_environ,
|
||||
fs_str,
|
||||
)
|
||||
from ._compat import (
|
||||
Path
|
||||
)
|
||||
from . import pep508checker
|
||||
from .environments import (
|
||||
PIPENV_SHELL_FANCY,
|
||||
PIPENV_USE_SYSTEM,
|
||||
PIPENV_SHELL,
|
||||
PIPENV_CACHE_DIR,
|
||||
)
|
||||
|
||||
# Backport required for earlier versions of Python.
|
||||
if sys.version_info < (3, 3):
|
||||
from .vendor.backports.shutil_get_terminal_size import get_terminal_size
|
||||
else:
|
||||
from shutil import get_terminal_size
|
||||
|
||||
|
||||
# ###################3 I PLAN TO KEEP THESE HERE. #########################
|
||||
|
||||
|
||||
from .utils import system_which
|
||||
from .utils import find_windows_executable, system_which
|
||||
|
||||
|
||||
# Packages that should be ignored later.
|
||||
@@ -94,736 +54,3 @@ def which_pip(allow_global=False):
|
||||
|
||||
|
||||
project = Project(which=which)
|
||||
|
||||
|
||||
# ###########################################################################
|
||||
|
||||
|
||||
def parse_download_fname(fname, name):
|
||||
fname, fextension = os.path.splitext(fname)
|
||||
if fextension == '.whl':
|
||||
fname = '-'.join(fname.split('-')[:-3])
|
||||
if fname.endswith('.tar'):
|
||||
fname, _ = os.path.splitext(fname)
|
||||
# Substring out package name (plus dash) from file name to get version.
|
||||
version = fname[len(name) + 1:]
|
||||
# Ignore implicit post releases in version number.
|
||||
if '-' in version and version.split('-')[1].isdigit():
|
||||
version = version.split('-')[0]
|
||||
return version
|
||||
|
||||
|
||||
def get_downloads_info(names_map, section):
|
||||
info = []
|
||||
p = project.parsed_pipfile
|
||||
for fname in os.listdir(project.download_location):
|
||||
# Get name from filename mapping.
|
||||
name = Requirement.from_line(names_map[fname]).name
|
||||
# Get the version info from the filenames.
|
||||
version = parse_download_fname(fname, name)
|
||||
# Get the hash of each file.
|
||||
cmd = '{0} hash "{1}"'.format(
|
||||
escape_grouped_arguments(which_pip()),
|
||||
os.sep.join([project.download_location, fname]),
|
||||
)
|
||||
c = delegator.run(cmd)
|
||||
hash = c.out.split('--hash=')[1].strip()
|
||||
# Verify we're adding the correct version from Pipfile
|
||||
# and not one from a dependency.
|
||||
specified_version = p[section].get(name, '')
|
||||
if is_required_version(version, specified_version):
|
||||
info.append(dict(name=name, version=version, hash=hash))
|
||||
return info
|
||||
|
||||
|
||||
def activate_virtualenv(source=True):
|
||||
"""Returns the string to activate a virtualenv."""
|
||||
# Suffix and source command for other shells.
|
||||
suffix = ''
|
||||
command = ' .' if source else ''
|
||||
# Support for fish shell.
|
||||
if PIPENV_SHELL and 'fish' in PIPENV_SHELL:
|
||||
suffix = '.fish'
|
||||
command = 'source'
|
||||
# Support for csh shell.
|
||||
if PIPENV_SHELL and 'csh' in PIPENV_SHELL:
|
||||
suffix = '.csh'
|
||||
command = 'source'
|
||||
# Escape any spaces located within the virtualenv path to allow
|
||||
# for proper activation.
|
||||
venv_location = project.virtualenv_location.replace(' ', r'\ ')
|
||||
if source:
|
||||
return '{2} {0}/bin/activate{1}'.format(venv_location, suffix, command)
|
||||
|
||||
else:
|
||||
return '{0}/bin/activate'.format(venv_location)
|
||||
|
||||
|
||||
def do_purge(bare=False, downloads=False, allow_global=False, verbose=False):
|
||||
"""Executes the purge functionality."""
|
||||
if downloads:
|
||||
if not bare:
|
||||
click.echo(
|
||||
crayons.normal(u'Clearing out downloads directory...', bold=True)
|
||||
)
|
||||
shutil.rmtree(project.download_location)
|
||||
return
|
||||
|
||||
freeze = delegator.run(
|
||||
'{0} freeze'.format(
|
||||
escape_grouped_arguments(which_pip(allow_global=allow_global))
|
||||
)
|
||||
).out
|
||||
# Remove comments from the output, if any.
|
||||
installed = [
|
||||
line
|
||||
for line in freeze.splitlines()
|
||||
if not line.lstrip().startswith('#')
|
||||
]
|
||||
# Remove setuptools and friends from installed, if present.
|
||||
for package_name in BAD_PACKAGES:
|
||||
for i, package in enumerate(installed):
|
||||
if package.startswith(package_name):
|
||||
del installed[i]
|
||||
actually_installed = []
|
||||
for package in installed:
|
||||
try:
|
||||
dep = Requirement.from_line(package)
|
||||
except AssertionError:
|
||||
dep = None
|
||||
if dep and not dep.is_vcs and not dep.editable:
|
||||
dep = dep.name
|
||||
actually_installed.append(dep)
|
||||
if not bare:
|
||||
click.echo(
|
||||
u'Found {0} installed package(s), purging...'.format(
|
||||
len(actually_installed)
|
||||
)
|
||||
)
|
||||
command = '{0} uninstall {1} -y'.format(
|
||||
escape_grouped_arguments(which_pip(allow_global=allow_global)),
|
||||
' '.join(actually_installed),
|
||||
)
|
||||
if verbose:
|
||||
click.echo('$ {0}'.format(command))
|
||||
c = delegator.run(command)
|
||||
if not bare:
|
||||
click.echo(crayons.blue(c.out))
|
||||
click.echo(crayons.green('Environment now purged and fresh!'))
|
||||
|
||||
|
||||
def pip_download(package_name):
|
||||
cache_dir = Path(PIPENV_CACHE_DIR)
|
||||
pip_config = {
|
||||
'PIP_CACHE_DIR': fs_str(cache_dir.as_posix()),
|
||||
'PIP_WHEEL_DIR': fs_str(cache_dir.joinpath('wheels').as_posix()),
|
||||
'PIP_DESTINATION_DIR': fs_str(cache_dir.joinpath('pkgs').as_posix()),
|
||||
}
|
||||
for source in project.sources:
|
||||
cmd = '{0} download "{1}" -i {2} -d {3}'.format(
|
||||
escape_grouped_arguments(which_pip()),
|
||||
package_name,
|
||||
source['url'],
|
||||
project.download_location,
|
||||
)
|
||||
c = delegator.run(cmd, env=pip_config)
|
||||
if c.return_code == 0:
|
||||
break
|
||||
|
||||
return c
|
||||
|
||||
|
||||
def format_help(help):
|
||||
"""Formats the help string."""
|
||||
help = help.replace('Options:', str(crayons.normal('Options:', bold=True)))
|
||||
help = help.replace(
|
||||
'Usage: pipenv',
|
||||
str('Usage: {0}'.format(crayons.normal('pipenv', bold=True))),
|
||||
)
|
||||
help = help.replace(' check', str(crayons.red(' check', bold=True)))
|
||||
help = help.replace(' clean', str(crayons.red(' clean', bold=True)))
|
||||
help = help.replace(' graph', str(crayons.red(' graph', bold=True)))
|
||||
help = help.replace(
|
||||
' install', str(crayons.magenta(' install', bold=True))
|
||||
)
|
||||
help = help.replace(' lock', str(crayons.green(' lock', bold=True)))
|
||||
help = help.replace(' open', str(crayons.red(' open', bold=True)))
|
||||
help = help.replace(' run', str(crayons.yellow(' run', bold=True)))
|
||||
help = help.replace(' shell', str(crayons.yellow(' shell', bold=True)))
|
||||
help = help.replace(' sync', str(crayons.green(' sync', bold=True)))
|
||||
help = help.replace(
|
||||
' uninstall', str(crayons.magenta(' uninstall', bold=True))
|
||||
)
|
||||
help = help.replace(' update', str(crayons.green(' update', bold=True)))
|
||||
additional_help = """
|
||||
Usage Examples:
|
||||
Create a new project using Python 3.6, specifically:
|
||||
$ {1}
|
||||
|
||||
Install all dependencies for a project (including dev):
|
||||
$ {2}
|
||||
|
||||
Create a lockfile containing pre-releases:
|
||||
$ {6}
|
||||
|
||||
Show a graph of your installed dependencies:
|
||||
$ {4}
|
||||
|
||||
Check your installed dependencies for security vulnerabilities:
|
||||
$ {7}
|
||||
|
||||
Install a local setup.py into your virtual environment/Pipfile:
|
||||
$ {5}
|
||||
|
||||
Use a lower-level pip command:
|
||||
$ {8}
|
||||
|
||||
Commands:""".format(
|
||||
crayons.red('pipenv --three'),
|
||||
crayons.red('pipenv --python 3.6'),
|
||||
crayons.red('pipenv install --dev'),
|
||||
crayons.red('pipenv lock'),
|
||||
crayons.red('pipenv graph'),
|
||||
crayons.red('pipenv install -e .'),
|
||||
crayons.red('pipenv lock --pre'),
|
||||
crayons.red('pipenv check'),
|
||||
crayons.red('pipenv run pip freeze'),
|
||||
)
|
||||
help = help.replace('Commands:', additional_help)
|
||||
return help
|
||||
|
||||
|
||||
def warn_in_virtualenv():
|
||||
if PIPENV_USE_SYSTEM:
|
||||
# Only warn if pipenv isn't already active.
|
||||
if 'PIPENV_ACTIVE' not in os.environ:
|
||||
click.echo(
|
||||
'{0}: Pipenv found itself running within a virtual environment, '
|
||||
'so it will automatically use that environment, instead of '
|
||||
'creating its own for any project. You can set '
|
||||
'{1} to force pipenv to ignore that environment and create '
|
||||
'its own instead.'.format(
|
||||
crayons.green('Courtesy Notice'),
|
||||
crayons.normal('PIPENV_IGNORE_VIRTUALENVS=1', bold=True),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
|
||||
|
||||
def ensure_lockfile(keep_outdated=False, pypi_mirror=None):
|
||||
"""Ensures that the lockfile is up-to-date."""
|
||||
if not keep_outdated:
|
||||
keep_outdated = project.settings.get('keep_outdated')
|
||||
# Write out the lockfile if it doesn't exist, but not if the Pipfile is being ignored
|
||||
if project.lockfile_exists:
|
||||
old_hash = project.get_lockfile_hash()
|
||||
new_hash = project.calculate_pipfile_hash()
|
||||
if new_hash != old_hash:
|
||||
click.echo(
|
||||
crayons.red(
|
||||
u'Pipfile.lock ({0}) out of date, updating to ({1})...'.format(
|
||||
old_hash[-6:], new_hash[-6:]
|
||||
),
|
||||
bold=True,
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
do_lock(keep_outdated=keep_outdated, pypi_mirror=pypi_mirror)
|
||||
else:
|
||||
do_lock(keep_outdated=keep_outdated, pypi_mirror=pypi_mirror)
|
||||
|
||||
|
||||
def do_py(system=False):
|
||||
try:
|
||||
click.echo(which('python', allow_global=system))
|
||||
except AttributeError:
|
||||
click.echo(crayons.red('No project found!'))
|
||||
|
||||
|
||||
def do_outdated(pypi_mirror=None):
|
||||
packages = {}
|
||||
results = delegator.run('{0} freeze'.format(which('pip'))).out.strip(
|
||||
).split(
|
||||
'\n'
|
||||
)
|
||||
results = filter(bool, results)
|
||||
for result in results:
|
||||
dep = Requirement.from_line(result)
|
||||
packages.update(dep.as_pipfile())
|
||||
updated_packages = {}
|
||||
lockfile = do_lock(write=False, pypi_mirror=pypi_mirror)
|
||||
for section in ('develop', 'default'):
|
||||
for package in lockfile[section]:
|
||||
try:
|
||||
updated_packages[package] = lockfile[section][package][
|
||||
'version'
|
||||
]
|
||||
except KeyError:
|
||||
pass
|
||||
outdated = []
|
||||
for package in packages:
|
||||
norm_name = pep423_name(package)
|
||||
if norm_name in updated_packages:
|
||||
if updated_packages[norm_name] != packages[package]:
|
||||
outdated.append(
|
||||
(package, updated_packages[norm_name], packages[package])
|
||||
)
|
||||
for package, new_version, old_version in outdated:
|
||||
click.echo(
|
||||
'Package {0!r} out-of-date: {1!r} installed, {2!r} available.'.format(
|
||||
package, old_version, new_version
|
||||
)
|
||||
)
|
||||
sys.exit(bool(outdated))
|
||||
|
||||
|
||||
def do_uninstall(
|
||||
package_name=False,
|
||||
more_packages=False,
|
||||
three=None,
|
||||
python=False,
|
||||
system=False,
|
||||
lock=False,
|
||||
all_dev=False,
|
||||
all=False,
|
||||
verbose=False,
|
||||
keep_outdated=False,
|
||||
pypi_mirror=None,
|
||||
):
|
||||
# Automatically use an activated virtualenv.
|
||||
if PIPENV_USE_SYSTEM:
|
||||
system = True
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python)
|
||||
package_names = (package_name,) + more_packages
|
||||
pipfile_remove = True
|
||||
# Un-install all dependencies, if --all was provided.
|
||||
if all is True:
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
u'Un-installing all packages from virtualenv...', bold=True
|
||||
)
|
||||
)
|
||||
do_purge(allow_global=system, verbose=verbose)
|
||||
sys.exit(0)
|
||||
# Uninstall [dev-packages], if --dev was provided.
|
||||
if all_dev:
|
||||
if 'dev-packages' not in project.parsed_pipfile:
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
'No {0} to uninstall.'.format(
|
||||
crayons.red('[dev-packages]')
|
||||
),
|
||||
bold=True,
|
||||
)
|
||||
)
|
||||
sys.exit(0)
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
u'Un-installing {0}...'.format(crayons.red('[dev-packages]')),
|
||||
bold=True,
|
||||
)
|
||||
)
|
||||
package_names = project.dev_packages.keys()
|
||||
if package_name is False and not all_dev:
|
||||
click.echo(crayons.red('No package provided!'), err=True)
|
||||
sys.exit(1)
|
||||
for package_name in package_names:
|
||||
click.echo(u'Un-installing {0}...'.format(crayons.green(package_name)))
|
||||
cmd = '{0} uninstall {1} -y'.format(
|
||||
escape_grouped_arguments(which_pip(allow_global=system)),
|
||||
package_name,
|
||||
)
|
||||
if verbose:
|
||||
click.echo('$ {0}'.format(cmd))
|
||||
c = delegator.run(cmd)
|
||||
click.echo(crayons.blue(c.out))
|
||||
if pipfile_remove:
|
||||
in_packages = project.get_package_name_in_pipfile(
|
||||
package_name, dev=False)
|
||||
in_dev_packages = project.get_package_name_in_pipfile(
|
||||
package_name, dev=True)
|
||||
if not in_dev_packages and not in_packages:
|
||||
click.echo(
|
||||
'No package {0} to remove from Pipfile.'.format(
|
||||
crayons.green(package_name)
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
click.echo(
|
||||
u'Removing {0} from Pipfile...'.format(
|
||||
crayons.green(package_name)
|
||||
)
|
||||
)
|
||||
# Remove package from both packages and dev-packages.
|
||||
project.remove_package_from_pipfile(package_name, dev=True)
|
||||
project.remove_package_from_pipfile(package_name, dev=False)
|
||||
if lock:
|
||||
do_lock(system=system, keep_outdated=keep_outdated, pypi_mirror=pypi_mirror)
|
||||
|
||||
|
||||
def do_shell(three=None, python=False, fancy=False, shell_args=None):
|
||||
from .patched.pew import pew
|
||||
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False)
|
||||
# Set an environment variable, so we know we're in the environment.
|
||||
os.environ['PIPENV_ACTIVE'] = '1'
|
||||
compat = (not fancy)
|
||||
# Support shell compatibility mode.
|
||||
if PIPENV_SHELL_FANCY:
|
||||
compat = False
|
||||
# Compatibility mode:
|
||||
if compat:
|
||||
if PIPENV_SHELL:
|
||||
shell = os.path.abspath(PIPENV_SHELL)
|
||||
else:
|
||||
click.echo(
|
||||
crayons.red(
|
||||
'Please ensure that the {0} environment variable '
|
||||
'is set before activating shell.'.format(
|
||||
crayons.normal('SHELL', bold=True)
|
||||
)
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
'Spawning environment shell ({0}). Use {1} to leave.'.format(
|
||||
crayons.red(shell), crayons.normal("'exit'", bold=True)
|
||||
),
|
||||
bold=True,
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
cmd = "{0} -i'".format(shell)
|
||||
args = []
|
||||
# Standard (properly configured shell) mode:
|
||||
else:
|
||||
if project.is_venv_in_project():
|
||||
# use .venv as the target virtualenv name
|
||||
workon_name = '.venv'
|
||||
else:
|
||||
workon_name = project.virtualenv_name
|
||||
cmd = sys.executable
|
||||
args = ['-m', 'pipenv.pew', 'workon', workon_name]
|
||||
# Grab current terminal dimensions to replace the hardcoded default
|
||||
# dimensions of pexpect
|
||||
terminal_dimensions = get_terminal_size()
|
||||
try:
|
||||
with temp_environ():
|
||||
if project.is_venv_in_project():
|
||||
os.environ['WORKON_HOME'] = project.project_directory
|
||||
c = pexpect.spawn(
|
||||
cmd,
|
||||
args,
|
||||
dimensions=(
|
||||
terminal_dimensions.lines, terminal_dimensions.columns
|
||||
),
|
||||
)
|
||||
# Windows!
|
||||
except AttributeError:
|
||||
# import subprocess
|
||||
# Tell pew to use the project directory as its workon_home
|
||||
with temp_environ():
|
||||
if project.is_venv_in_project():
|
||||
os.environ['WORKON_HOME'] = project.project_directory
|
||||
pew.workon_cmd([workon_name])
|
||||
sys.exit(0)
|
||||
# Activate the virtualenv if in compatibility mode.
|
||||
if compat:
|
||||
c.sendline(activate_virtualenv())
|
||||
# Send additional arguments to the subshell.
|
||||
if shell_args:
|
||||
c.sendline(' '.join(shell_args))
|
||||
|
||||
# Handler for terminal resizing events
|
||||
# Must be defined here to have the shell process in its context, since we
|
||||
# can't pass it as an argument
|
||||
def sigwinch_passthrough(sig, data):
|
||||
terminal_dimensions = get_terminal_size()
|
||||
c.setwinsize(terminal_dimensions.lines, terminal_dimensions.columns)
|
||||
|
||||
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
|
||||
# Interact with the new shell.
|
||||
c.interact(escape_character=None)
|
||||
c.close()
|
||||
sys.exit(c.exitstatus)
|
||||
|
||||
|
||||
def do_check(three=None, python=False, system=False, unused=False, ignore=None, args=None):
|
||||
if not system:
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False, warn=False)
|
||||
if not args:
|
||||
args = []
|
||||
if unused:
|
||||
deps_required = [k for k in project.packages.keys()]
|
||||
deps_needed = import_from_code(unused)
|
||||
for dep in deps_needed:
|
||||
try:
|
||||
deps_required.remove(dep)
|
||||
except ValueError:
|
||||
pass
|
||||
if deps_required:
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
'The following dependencies appear unused, and may be safe for removal:'
|
||||
)
|
||||
)
|
||||
for dep in deps_required:
|
||||
click.echo(' - {0}'.format(crayons.green(dep)))
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit(0)
|
||||
click.echo(crayons.normal(u'Checking PEP 508 requirements...', bold=True))
|
||||
if system:
|
||||
python = system_which('python')
|
||||
else:
|
||||
python = which('python')
|
||||
# Run the PEP 508 checker in the virtualenv.
|
||||
c = delegator.run(
|
||||
'"{0}" {1}'.format(
|
||||
python,
|
||||
escape_grouped_arguments(pep508checker.__file__.rstrip('cdo')),
|
||||
)
|
||||
)
|
||||
results = simplejson.loads(c.out)
|
||||
# Load the pipfile.
|
||||
p = pipfile.Pipfile.load(project.pipfile_location)
|
||||
failed = False
|
||||
# Assert each specified requirement.
|
||||
for marker, specifier in p.data['_meta']['requires'].items():
|
||||
if marker in results:
|
||||
try:
|
||||
assert results[marker] == specifier
|
||||
except AssertionError:
|
||||
failed = True
|
||||
click.echo(
|
||||
'Specifier {0} does not match {1} ({2}).'
|
||||
''.format(
|
||||
crayons.green(marker),
|
||||
crayons.blue(specifier),
|
||||
crayons.red(results[marker]),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
if failed:
|
||||
click.echo(crayons.red('Failed!'), err=True)
|
||||
sys.exit(1)
|
||||
else:
|
||||
click.echo(crayons.green('Passed!'))
|
||||
click.echo(
|
||||
crayons.normal(u'Checking installed package safety...', bold=True)
|
||||
)
|
||||
path = pep508checker.__file__.rstrip('cdo')
|
||||
path = os.sep.join(__file__.split(os.sep)[:-1] + ['patched', 'safety.zip'])
|
||||
if not system:
|
||||
python = which('python')
|
||||
else:
|
||||
python = system_which('python')
|
||||
if ignore:
|
||||
ignored = '--ignore {0}'.format('--ignore '.join(ignore))
|
||||
click.echo(crayons.normal('Notice: Ignoring CVE(s) {0}'.format(crayons.yellow(', '.join(ignore)))), err=True)
|
||||
else:
|
||||
ignored = ''
|
||||
c = delegator.run(
|
||||
'"{0}" {1} check --json --key=1ab8d58f-5122e025-83674263-bc1e79e0 {2}'.format(
|
||||
python, escape_grouped_arguments(path), ignored
|
||||
)
|
||||
)
|
||||
try:
|
||||
results = simplejson.loads(c.out)
|
||||
except ValueError:
|
||||
click.echo('An error occurred:', err=True)
|
||||
click.echo(c.err, err=True)
|
||||
sys.exit(1)
|
||||
for (package, resolved, installed, description, vuln) in results:
|
||||
click.echo(
|
||||
'{0}: {1} {2} resolved ({3} installed)!'.format(
|
||||
crayons.normal(vuln, bold=True),
|
||||
crayons.green(package),
|
||||
crayons.red(resolved, bold=False),
|
||||
crayons.red(installed, bold=True),
|
||||
)
|
||||
)
|
||||
click.echo('{0}'.format(description))
|
||||
click.echo()
|
||||
if not results:
|
||||
click.echo(crayons.green('All good!'))
|
||||
else:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def do_graph(bare=False, json=False, json_tree=False, reverse=False):
|
||||
import pipdeptree
|
||||
try:
|
||||
python_path = which('python')
|
||||
except AttributeError:
|
||||
click.echo(
|
||||
u'{0}: {1}'.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
u'Unable to display currently-installed dependency graph information here. '
|
||||
u'Please run within a Pipenv project.',
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
if reverse and json:
|
||||
click.echo(
|
||||
u'{0}: {1}'.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
u'Using both --reverse and --json together is not supported. '
|
||||
u'Please select one of the two options.',
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
if reverse and json_tree:
|
||||
click.echo(
|
||||
u'{0}: {1}'.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
u'Using both --reverse and --json-tree together is not supported. '
|
||||
u'Please select one of the two options.',
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
if json and json_tree:
|
||||
click.echo(
|
||||
u'{0}: {1}'.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
u'Using both --json and --json-tree together is not supported. '
|
||||
u'Please select one of the two options.',
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
flag = ''
|
||||
if json:
|
||||
flag = '--json'
|
||||
if json_tree:
|
||||
flag = '--json-tree'
|
||||
if reverse:
|
||||
flag = '--reverse'
|
||||
if not project.virtualenv_exists:
|
||||
click.echo(
|
||||
u'{0}: No virtualenv has been created for this project yet! Consider '
|
||||
u'running {1} first to automatically generate one for you or see'
|
||||
u'{2} for further instructions.'.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
crayons.green('`pipenv install`'),
|
||||
crayons.green('`pipenv install --help`'),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
cmd = '"{0}" {1} {2}'.format(
|
||||
python_path,
|
||||
escape_grouped_arguments(pipdeptree.__file__.rstrip('cdo')),
|
||||
flag,
|
||||
)
|
||||
# Run dep-tree.
|
||||
c = delegator.run(cmd)
|
||||
if not bare:
|
||||
if json:
|
||||
data = []
|
||||
for d in simplejson.loads(c.out):
|
||||
if d['package']['key'] not in BAD_PACKAGES:
|
||||
data.append(d)
|
||||
click.echo(simplejson.dumps(data, indent=4))
|
||||
sys.exit(0)
|
||||
elif json_tree:
|
||||
def traverse(obj):
|
||||
if isinstance(obj, list):
|
||||
return [traverse(package) for package in obj if package['key'] not in BAD_PACKAGES]
|
||||
else:
|
||||
obj['dependencies'] = traverse(obj['dependencies'])
|
||||
return obj
|
||||
data = traverse(simplejson.loads(c.out))
|
||||
click.echo(simplejson.dumps(data, indent=4))
|
||||
sys.exit(0)
|
||||
else:
|
||||
for line in c.out.split('\n'):
|
||||
# Ignore bad packages as top level.
|
||||
if line.split('==')[0] in BAD_PACKAGES and not reverse:
|
||||
continue
|
||||
|
||||
# Bold top-level packages.
|
||||
if not line.startswith(' '):
|
||||
click.echo(crayons.normal(line, bold=True))
|
||||
# Echo the rest.
|
||||
else:
|
||||
click.echo(crayons.normal(line, bold=False))
|
||||
else:
|
||||
click.echo(c.out)
|
||||
if c.return_code != 0:
|
||||
click.echo(
|
||||
'{0} {1}'.format(
|
||||
crayons.red('ERROR: ', bold=True),
|
||||
crayons.white('{0}'.format(c.err, bold=True)),
|
||||
),
|
||||
err=True
|
||||
)
|
||||
# Return its return code.
|
||||
sys.exit(c.return_code)
|
||||
|
||||
|
||||
def do_clean(
|
||||
ctx, three=None, python=None, dry_run=False, bare=False, verbose=False, pypi_mirror=None
|
||||
):
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False)
|
||||
ensure_lockfile(pypi_mirror=pypi_mirror)
|
||||
|
||||
installed_package_names = []
|
||||
pip_freeze_command = delegator.run('{0} freeze'.format(which_pip()))
|
||||
for line in pip_freeze_command.out.split('\n'):
|
||||
installed = line.strip()
|
||||
if not installed or installed.startswith('#'): # Comment or empty.
|
||||
continue
|
||||
r = Requirement.from_line(installed).requirement
|
||||
# Ignore editable installations.
|
||||
if not r.editable:
|
||||
installed_package_names.append(r.name.lower())
|
||||
else:
|
||||
if verbose:
|
||||
click.echo('Ignoring {0}.'.format(repr(r.name)), err=True)
|
||||
# Remove known "bad packages" from the list.
|
||||
for bad_package in BAD_PACKAGES:
|
||||
if bad_package in installed_package_names:
|
||||
if verbose:
|
||||
click.echo('Ignoring {0}.'.format(repr(bad_package)), err=True)
|
||||
del installed_package_names[
|
||||
installed_package_names.index(bad_package)
|
||||
]
|
||||
# Intelligently detect if --dev should be used or not.
|
||||
develop = [k.lower() for k in project.lockfile_content['develop'].keys()]
|
||||
default = [k.lower() for k in project.lockfile_content['default'].keys()]
|
||||
for used_package in set(develop + default):
|
||||
if used_package in installed_package_names:
|
||||
del installed_package_names[
|
||||
installed_package_names.index(used_package)
|
||||
]
|
||||
failure = False
|
||||
for apparent_bad_package in installed_package_names:
|
||||
if dry_run:
|
||||
click.echo(apparent_bad_package)
|
||||
else:
|
||||
click.echo(
|
||||
crayons.white(
|
||||
'Uninstalling {0}...'.format(repr(apparent_bad_package)),
|
||||
bold=True,
|
||||
)
|
||||
)
|
||||
# Uninstall the package.
|
||||
c = delegator.run(
|
||||
'{0} uninstall {1} -y'.format(
|
||||
which_pip(), apparent_bad_package
|
||||
)
|
||||
)
|
||||
if c.return_code != 0:
|
||||
failure = True
|
||||
sys.exit(int(failure))
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import contextlib
|
||||
import os
|
||||
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import blindspin
|
||||
from pipenv.vendor import blindspin, click
|
||||
|
||||
from pipenv.core import BAD_PACKAGES, project
|
||||
from pipenv.environments import (
|
||||
PIPENV_COLORBLIND,
|
||||
PIPENV_DONT_LOAD_ENV,
|
||||
PIPENV_DOTENV_LOCATION,
|
||||
PIPENV_NOSPIN,
|
||||
)
|
||||
from pipenv.utils import proper_case
|
||||
|
||||
|
||||
# Disable colors, for the color blind and others who do not prefer colors.
|
||||
@@ -44,3 +49,36 @@ def convert_deps_to_pip(deps, project=None, r=True, include_index=False):
|
||||
f.write('\n'.join(dependencies).encode('utf-8'))
|
||||
f.close()
|
||||
return f.name
|
||||
|
||||
|
||||
def load_dot_env():
|
||||
"""Loads .env file into sys.environ.
|
||||
"""
|
||||
if not PIPENV_DONT_LOAD_ENV:
|
||||
# If the project doesn't exist yet, check current directory for a .env file
|
||||
from pipenv.vendor import dotenv
|
||||
project_directory = project.project_directory or '.'
|
||||
denv = dotenv.find_dotenv(
|
||||
PIPENV_DOTENV_LOCATION or os.sep.join([project_directory, '.env'])
|
||||
)
|
||||
if os.path.isfile(denv):
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
'Loading .env environment variables...', bold=True
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
dotenv.load_dotenv(denv, override=True)
|
||||
|
||||
|
||||
def import_from_code(path='.'):
|
||||
from pipreqs import pipreqs
|
||||
rs = []
|
||||
try:
|
||||
for r in pipreqs.get_all_imports(path):
|
||||
if r not in BAD_PACKAGES:
|
||||
rs.append(r)
|
||||
pkg_names = pipreqs.get_pkg_names(rs)
|
||||
return [proper_case(r) for r in pkg_names]
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pipenv.patched import crayons, pipfile
|
||||
from pipenv.vendor import click, delegator
|
||||
|
||||
from pipenv import pep508checker
|
||||
from pipenv.core import project, which
|
||||
from pipenv.utils import escape_grouped_arguments, system_which
|
||||
|
||||
from ._utils import import_from_code
|
||||
from .ensure import ensure_project
|
||||
|
||||
|
||||
def do_check(three=None, python=False, system=False, unused=False, ignore=None, args=None):
|
||||
if not system:
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False, warn=False)
|
||||
if not args:
|
||||
args = []
|
||||
if unused:
|
||||
deps_required = [k for k in project.packages.keys()]
|
||||
deps_needed = import_from_code(unused)
|
||||
for dep in deps_needed:
|
||||
try:
|
||||
deps_required.remove(dep)
|
||||
except ValueError:
|
||||
pass
|
||||
if deps_required:
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
'The following dependencies appear unused, and may be safe for removal:'
|
||||
)
|
||||
)
|
||||
for dep in deps_required:
|
||||
click.echo(' - {0}'.format(crayons.green(dep)))
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit(0)
|
||||
click.echo(crayons.normal(u'Checking PEP 508 requirements...', bold=True))
|
||||
if system:
|
||||
python = system_which('python')
|
||||
else:
|
||||
python = which('python')
|
||||
# Run the PEP 508 checker in the virtualenv.
|
||||
c = delegator.run(
|
||||
'"{0}" {1}'.format(
|
||||
python,
|
||||
escape_grouped_arguments(pep508checker.__file__.rstrip('cdo')),
|
||||
)
|
||||
)
|
||||
results = json.loads(c.out)
|
||||
# Load the pipfile.
|
||||
p = pipfile.Pipfile.load(project.pipfile_location)
|
||||
failed = False
|
||||
# Assert each specified requirement.
|
||||
for marker, specifier in p.data['_meta']['requires'].items():
|
||||
if marker in results:
|
||||
try:
|
||||
assert results[marker] == specifier
|
||||
except AssertionError:
|
||||
failed = True
|
||||
click.echo(
|
||||
'Specifier {0} does not match {1} ({2}).'
|
||||
''.format(
|
||||
crayons.green(marker),
|
||||
crayons.blue(specifier),
|
||||
crayons.red(results[marker]),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
if failed:
|
||||
click.echo(crayons.red('Failed!'), err=True)
|
||||
sys.exit(1)
|
||||
else:
|
||||
click.echo(crayons.green('Passed!'))
|
||||
click.echo(
|
||||
crayons.normal(u'Checking installed package safety...', bold=True)
|
||||
)
|
||||
path = pep508checker.__file__.rstrip('cdo')
|
||||
path = os.sep.join(__file__.split(os.sep)[:-1] + ['patched', 'safety.zip'])
|
||||
if not system:
|
||||
python = which('python')
|
||||
else:
|
||||
python = system_which('python')
|
||||
if ignore:
|
||||
ignored = '--ignore {0}'.format('--ignore '.join(ignore))
|
||||
click.echo(crayons.normal('Notice: Ignoring CVE(s) {0}'.format(crayons.yellow(', '.join(ignore)))), err=True)
|
||||
else:
|
||||
ignored = ''
|
||||
c = delegator.run(
|
||||
'"{0}" {1} check --json --key=1ab8d58f-5122e025-83674263-bc1e79e0 {2}'.format(
|
||||
python, escape_grouped_arguments(path), ignored
|
||||
)
|
||||
)
|
||||
try:
|
||||
results = json.loads(c.out)
|
||||
except ValueError:
|
||||
click.echo('An error occurred:', err=True)
|
||||
click.echo(c.err, err=True)
|
||||
sys.exit(1)
|
||||
for (package, resolved, installed, description, vuln) in results:
|
||||
click.echo(
|
||||
'{0}: {1} {2} resolved ({3} installed)!'.format(
|
||||
crayons.normal(vuln, bold=True),
|
||||
crayons.green(package),
|
||||
crayons.red(resolved, bold=False),
|
||||
crayons.red(installed, bold=True),
|
||||
)
|
||||
)
|
||||
click.echo('{0}'.format(description))
|
||||
click.echo()
|
||||
if not results:
|
||||
click.echo(crayons.green('All good!'))
|
||||
else:
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,66 @@
|
||||
import sys
|
||||
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import click, delegator, requirementslib
|
||||
|
||||
from pipenv.core import BAD_PACKAGES, project, which_pip
|
||||
|
||||
from .ensure import ensure_project, ensure_lockfile
|
||||
|
||||
|
||||
def do_clean(
|
||||
three=None, python=None, dry_run=False, bare=False, verbose=False,
|
||||
):
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False)
|
||||
ensure_lockfile()
|
||||
|
||||
installed_package_names = []
|
||||
pip_freeze_command = delegator.run('{0} freeze'.format(which_pip()))
|
||||
for line in pip_freeze_command.out.split('\n'):
|
||||
installed = line.strip()
|
||||
if not installed or installed.startswith('#'): # Comment or empty.
|
||||
continue
|
||||
r = requirementslib.Requirement.from_line(installed).requirement
|
||||
# Ignore editable installations.
|
||||
if not r.editable:
|
||||
installed_package_names.append(r.name.lower())
|
||||
else:
|
||||
if verbose:
|
||||
click.echo('Ignoring {0}.'.format(repr(r.name)), err=True)
|
||||
# Remove known "bad packages" from the list.
|
||||
for bad_package in BAD_PACKAGES:
|
||||
if bad_package in installed_package_names:
|
||||
if verbose:
|
||||
click.echo('Ignoring {0}.'.format(repr(bad_package)), err=True)
|
||||
del installed_package_names[
|
||||
installed_package_names.index(bad_package)
|
||||
]
|
||||
# Intelligently detect if --dev should be used or not.
|
||||
develop = [k.lower() for k in project.lockfile_content['develop'].keys()]
|
||||
default = [k.lower() for k in project.lockfile_content['default'].keys()]
|
||||
for used_package in set(develop + default):
|
||||
if used_package in installed_package_names:
|
||||
del installed_package_names[
|
||||
installed_package_names.index(used_package)
|
||||
]
|
||||
failure = False
|
||||
for apparent_bad_package in installed_package_names:
|
||||
if dry_run:
|
||||
click.echo(apparent_bad_package)
|
||||
else:
|
||||
click.echo(
|
||||
crayons.white(
|
||||
'Uninstalling {0}...'.format(repr(apparent_bad_package)),
|
||||
bold=True,
|
||||
)
|
||||
)
|
||||
# Uninstall the package.
|
||||
c = delegator.run(
|
||||
'{0} uninstall {1} -y'.format(
|
||||
which_pip(), apparent_bad_package
|
||||
)
|
||||
)
|
||||
if c.return_code != 0:
|
||||
failure = True
|
||||
sys.exit(int(failure))
|
||||
@@ -14,6 +14,7 @@ from pipenv.core import (
|
||||
from pipenv.environments import (
|
||||
PIPENV_SKIP_VALIDATION,
|
||||
PIPENV_USE_SYSTEM,
|
||||
PIPENV_VIRTUALENV,
|
||||
PIPENV_YES,
|
||||
)
|
||||
from pipenv.utils import get_python_executable_version
|
||||
@@ -242,3 +243,26 @@ def ensure_project(
|
||||
sys.exit(1)
|
||||
# Ensure the Pipfile exists.
|
||||
ensure_pipfile(validate=validate, skip_requirements=skip_requirements, system=system)
|
||||
|
||||
|
||||
def ensure_lockfile(keep_outdated=False, pypi_mirror=None):
|
||||
"""Ensures that the lockfile is up-to-date."""
|
||||
if not keep_outdated:
|
||||
keep_outdated = project.settings.get('keep_outdated')
|
||||
# Write out the lockfile if it doesn't exist, but not if the Pipfile is being ignored
|
||||
if project.lockfile_exists:
|
||||
old_hash = project.get_lockfile_hash()
|
||||
new_hash = project.calculate_pipfile_hash()
|
||||
if new_hash == old_hash:
|
||||
return
|
||||
click.echo(
|
||||
crayons.red(
|
||||
u'Pipfile.lock ({0}) out of date, updating to ({1})...'.format(
|
||||
old_hash[-6:], new_hash[-6:]
|
||||
),
|
||||
bold=True,
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
from .lock import do_lock
|
||||
do_lock(keep_outdated=keep_outdated, pypi_mirror=pypi_mirror)
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
import json
|
||||
import sys
|
||||
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import click, delegator
|
||||
|
||||
from pipenv.core import BAD_PACKAGES, project, which
|
||||
from pipenv.utils import escape_grouped_arguments
|
||||
|
||||
|
||||
def do_graph(bare=False, json_=False, json_tree=False, reverse=False):
|
||||
import pipdeptree
|
||||
try:
|
||||
python_path = which('python')
|
||||
except AttributeError:
|
||||
click.echo(
|
||||
u'{0}: {1}'.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
u'Unable to display currently-installed dependency graph information here. '
|
||||
u'Please run within a Pipenv project.',
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
if reverse and json_:
|
||||
click.echo(
|
||||
u'{0}: {1}'.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
u'Using both --reverse and --json together is not supported. '
|
||||
u'Please select one of the two options.',
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
if reverse and json_tree:
|
||||
click.echo(
|
||||
u'{0}: {1}'.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
u'Using both --reverse and --json-tree together is not supported. '
|
||||
u'Please select one of the two options.',
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
if json_ and json_tree:
|
||||
click.echo(
|
||||
u'{0}: {1}'.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
u'Using both --json and --json-tree together is not supported. '
|
||||
u'Please select one of the two options.',
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
flag = ''
|
||||
if json_:
|
||||
flag = '--json'
|
||||
if json_tree:
|
||||
flag = '--json-tree'
|
||||
if reverse:
|
||||
flag = '--reverse'
|
||||
if not project.virtualenv_exists:
|
||||
click.echo(
|
||||
u'{0}: No virtualenv has been created for this project yet! Consider '
|
||||
u'running {1} first to automatically generate one for you or see'
|
||||
u'{2} for further instructions.'.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
crayons.green('`pipenv install`'),
|
||||
crayons.green('`pipenv install --help`'),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
cmd = '"{0}" {1} {2}'.format(
|
||||
python_path,
|
||||
escape_grouped_arguments(pipdeptree.__file__.rstrip('cdo')),
|
||||
flag,
|
||||
)
|
||||
# Run dep-tree.
|
||||
c = delegator.run(cmd)
|
||||
if not bare:
|
||||
if json_:
|
||||
data = []
|
||||
for d in json.loads(c.out):
|
||||
if d['package']['key'] not in BAD_PACKAGES:
|
||||
data.append(d)
|
||||
click.echo(json.dumps(data, indent=4))
|
||||
sys.exit(0)
|
||||
elif json_tree:
|
||||
def traverse(obj):
|
||||
if isinstance(obj, list):
|
||||
return [traverse(package) for package in obj if package['key'] not in BAD_PACKAGES]
|
||||
else:
|
||||
obj['dependencies'] = traverse(obj['dependencies'])
|
||||
return obj
|
||||
data = traverse(json.loads(c.out))
|
||||
click.echo(json.dumps(data, indent=4))
|
||||
sys.exit(0)
|
||||
else:
|
||||
for line in c.out.split('\n'):
|
||||
# Ignore bad packages as top level.
|
||||
if line.split('==')[0] in BAD_PACKAGES and not reverse:
|
||||
continue
|
||||
|
||||
# Bold top-level packages.
|
||||
if not line.startswith(' '):
|
||||
click.echo(crayons.normal(line, bold=True))
|
||||
# Echo the rest.
|
||||
else:
|
||||
click.echo(crayons.normal(line, bold=False))
|
||||
else:
|
||||
click.echo(c.out)
|
||||
if c.return_code != 0:
|
||||
click.echo(
|
||||
'{0} {1}'.format(
|
||||
crayons.red('ERROR: ', bold=True),
|
||||
crayons.white('{0}'.format(c.err, bold=True)),
|
||||
),
|
||||
err=True
|
||||
)
|
||||
# Return its return code.
|
||||
sys.exit(c.return_code)
|
||||
@@ -0,0 +1,61 @@
|
||||
from pipenv.patched import crayons
|
||||
|
||||
|
||||
def format_help(help):
|
||||
"""Formats the help string."""
|
||||
help = help.replace('Options:', str(crayons.normal('Options:', bold=True)))
|
||||
help = help.replace(
|
||||
'Usage: pipenv',
|
||||
str('Usage: {0}'.format(crayons.normal('pipenv', bold=True))),
|
||||
)
|
||||
help = help.replace(' check', str(crayons.red(' check', bold=True)))
|
||||
help = help.replace(' clean', str(crayons.red(' clean', bold=True)))
|
||||
help = help.replace(' graph', str(crayons.red(' graph', bold=True)))
|
||||
help = help.replace(
|
||||
' install', str(crayons.magenta(' install', bold=True))
|
||||
)
|
||||
help = help.replace(' lock', str(crayons.green(' lock', bold=True)))
|
||||
help = help.replace(' open', str(crayons.red(' open', bold=True)))
|
||||
help = help.replace(' run', str(crayons.yellow(' run', bold=True)))
|
||||
help = help.replace(' shell', str(crayons.yellow(' shell', bold=True)))
|
||||
help = help.replace(' sync', str(crayons.green(' sync', bold=True)))
|
||||
help = help.replace(
|
||||
' uninstall', str(crayons.magenta(' uninstall', bold=True))
|
||||
)
|
||||
help = help.replace(' update', str(crayons.green(' update', bold=True)))
|
||||
additional_help = """
|
||||
Usage Examples:
|
||||
Create a new project using Python 3.6, specifically:
|
||||
$ {1}
|
||||
|
||||
Install all dependencies for a project (including dev):
|
||||
$ {2}
|
||||
|
||||
Create a lockfile containing pre-releases:
|
||||
$ {6}
|
||||
|
||||
Show a graph of your installed dependencies:
|
||||
$ {4}
|
||||
|
||||
Check your installed dependencies for security vulnerabilities:
|
||||
$ {7}
|
||||
|
||||
Install a local setup.py into your virtual environment/Pipfile:
|
||||
$ {5}
|
||||
|
||||
Use a lower-level pip command:
|
||||
$ {8}
|
||||
|
||||
Commands:""".format(
|
||||
crayons.red('pipenv --three'),
|
||||
crayons.red('pipenv --python 3.6'),
|
||||
crayons.red('pipenv install --dev'),
|
||||
crayons.red('pipenv lock'),
|
||||
crayons.red('pipenv graph'),
|
||||
crayons.red('pipenv install -e .'),
|
||||
crayons.red('pipenv lock --pre'),
|
||||
crayons.red('pipenv check'),
|
||||
crayons.red('pipenv run pip freeze'),
|
||||
)
|
||||
help = help.replace('Commands:', additional_help)
|
||||
return help
|
||||
@@ -6,13 +6,12 @@ from pipenv.patched import crayons
|
||||
from pipenv.vendor import click, requirementslib
|
||||
|
||||
from pipenv._compat import TemporaryDirectory
|
||||
from pipenv.core import BAD_PACKAGES, project
|
||||
from pipenv.core import project
|
||||
from pipenv.environments import PIPENV_USE_SYSTEM
|
||||
from pipenv.utils import (
|
||||
download_file,
|
||||
is_star,
|
||||
is_valid_url,
|
||||
proper_case,
|
||||
)
|
||||
|
||||
from ._install import (
|
||||
@@ -21,25 +20,11 @@ from ._install import (
|
||||
pip_install,
|
||||
split_argument,
|
||||
)
|
||||
from ._utils import convert_deps_to_pip, spinner
|
||||
from ._utils import convert_deps_to_pip, import_from_code, spinner
|
||||
from .ensure import ensure_project, import_requirements
|
||||
from .init import do_init
|
||||
|
||||
|
||||
def _import_from_code(path='.'):
|
||||
from pipreqs import pipreqs
|
||||
rs = []
|
||||
try:
|
||||
for r in pipreqs.get_all_imports(path):
|
||||
if r not in BAD_PACKAGES:
|
||||
rs.append(r)
|
||||
pkg_names = pipreqs.get_pkg_names(rs)
|
||||
return [proper_case(r) for r in pkg_names]
|
||||
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
def do_install(
|
||||
package_name=False,
|
||||
more_packages=False,
|
||||
@@ -179,7 +164,7 @@ def do_install(
|
||||
u'Discovering imports from local codebase...', bold=True
|
||||
)
|
||||
)
|
||||
for req in _import_from_code(code):
|
||||
for req in import_from_code(code):
|
||||
click.echo(' Found {0}!'.format(crayons.green(req)))
|
||||
project.add_package_to_pipfile(req)
|
||||
# Capture -e argument and assign it to following package_name.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
@@ -7,8 +8,9 @@ except ImportError:
|
||||
from collections import Mapping
|
||||
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import click, delegator, six
|
||||
from pipenv.vendor import click, delegator, requirementslib, six
|
||||
|
||||
from pipenv._compat import Path, TemporaryDirectory
|
||||
from pipenv.core import project, which, which_pip
|
||||
from pipenv.utils import (
|
||||
escape_grouped_arguments,
|
||||
@@ -25,13 +27,68 @@ def _is_pinned(val):
|
||||
return isinstance(val, six.string_types) and val.startswith('==')
|
||||
|
||||
|
||||
def _obtain_vcs_req(vcs_obj, src_dir, name, rev=None):
|
||||
target_dir = os.path.join(src_dir, name)
|
||||
target_rev = vcs_obj.make_rev_options(rev)
|
||||
if not os.path.exists(target_dir):
|
||||
vcs_obj.obtain(target_dir)
|
||||
if not vcs_obj.is_commit_id_equal(target_dir, rev) and not vcs_obj.is_commit_id_equal(target_dir, target_rev):
|
||||
vcs_obj.update(target_dir, target_rev)
|
||||
return vcs_obj.get_revision(target_dir)
|
||||
|
||||
|
||||
def _get_vcs_deps(
|
||||
project,
|
||||
pip_freeze=None,
|
||||
which=None,
|
||||
verbose=False,
|
||||
clear=False,
|
||||
pre=False,
|
||||
allow_global=False,
|
||||
dev=False,
|
||||
pypi_mirror=None,
|
||||
):
|
||||
from pipenv.patched.notpip._internal.vcs import VcsSupport
|
||||
|
||||
section = "vcs_dev_packages" if dev else "vcs_packages"
|
||||
reqs = []
|
||||
lockfile = {}
|
||||
try:
|
||||
packages = getattr(project, section)
|
||||
except AttributeError:
|
||||
return [], []
|
||||
if not os.environ.get("PIP_SRC") and not project.virtualenv_location:
|
||||
_src_dir = TemporaryDirectory(prefix='pipenv-', suffix='-src')
|
||||
src_dir = Path(_src_dir.name)
|
||||
else:
|
||||
src_dir = Path(
|
||||
os.environ.get("PIP_SRC", os.path.join(project.virtualenv_location, "src"))
|
||||
)
|
||||
src_dir.mkdir(mode=0o775, exist_ok=True)
|
||||
vcs_registry = VcsSupport
|
||||
for pkg_name, pkg_pipfile in packages.items():
|
||||
requirement = requirementslib.Requirement.from_pipfile(
|
||||
pkg_name, pkg_pipfile,
|
||||
)
|
||||
backend = vcs_registry()._registry.get(requirement.vcs)
|
||||
__vcs = backend(url=requirement.req.vcs_uri)
|
||||
locked_rev = None
|
||||
name = requirement.normalized_name
|
||||
locked_rev = _obtain_vcs_req(
|
||||
__vcs, src_dir.as_posix(), name, rev=pkg_pipfile.get("ref")
|
||||
)
|
||||
if requirement.is_vcs:
|
||||
requirement.req.ref = locked_rev
|
||||
lockfile[name] = requirement.pipfile_entry[1]
|
||||
reqs.append(requirement)
|
||||
return reqs, lockfile
|
||||
|
||||
|
||||
def _venv_resolve_deps(
|
||||
deps, which, project, pre=False, verbose=False, clear=False,
|
||||
allow_global=False, pypi_mirror=None,
|
||||
):
|
||||
from .vendor import delegator
|
||||
from . import resolver
|
||||
import json
|
||||
from pipenv import resolver
|
||||
if not deps:
|
||||
return []
|
||||
resolver = escape_grouped_arguments(resolver.__file__.rstrip('co'))
|
||||
@@ -145,8 +202,8 @@ def do_lock(
|
||||
write=True,
|
||||
pypi_mirror=None,
|
||||
):
|
||||
"""Executes the freeze functionality."""
|
||||
from .utils import get_vcs_deps
|
||||
"""Executes the freeze functionality.
|
||||
"""
|
||||
cached_lockfile = {}
|
||||
if not pre:
|
||||
pre = project.settings.get('allow_prereleases')
|
||||
@@ -227,7 +284,7 @@ def do_lock(
|
||||
lockfile[settings['lockfile_key']].update(dep_lockfile)
|
||||
# Add refs for VCS installs.
|
||||
# TODO: be smarter about this.
|
||||
vcs_reqs, vcs_lockfile = get_vcs_deps(
|
||||
vcs_reqs, vcs_lockfile = _get_vcs_deps(
|
||||
project,
|
||||
pip_freeze,
|
||||
which=which,
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import click, delegator
|
||||
|
||||
from pipenv.core import which
|
||||
|
||||
from .ensure import ensure_project
|
||||
|
||||
|
||||
def do_open(module, three, python):
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False)
|
||||
c = delegator.run(
|
||||
'{0} -c "import {1}; print({1}.__file__);"'.format(
|
||||
which('python'), module
|
||||
)
|
||||
)
|
||||
try:
|
||||
assert c.return_code == 0
|
||||
except AssertionError:
|
||||
click.echo(crayons.red('Module not found!'))
|
||||
sys.exit(1)
|
||||
if '__init__.py' in c.out:
|
||||
p = os.path.dirname(c.out.strip().rstrip('cdo'))
|
||||
else:
|
||||
p = c.out.strip().rstrip('cdo')
|
||||
click.echo(
|
||||
crayons.normal('Opening {0!r} in your EDITOR.'.format(p), bold=True)
|
||||
)
|
||||
click.edit(filename=p)
|
||||
@@ -0,0 +1,134 @@
|
||||
"""Various utilities for "pipenv --XXXX".
|
||||
|
||||
Global imports should be kept at a minimum to reduce start up time as much
|
||||
as possible.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import click
|
||||
|
||||
|
||||
def do_completion():
|
||||
from pipenv import shells
|
||||
from pipenv.vendor import click_completion
|
||||
try:
|
||||
shell = shells.detect_info()[0]
|
||||
except shells.ShellDetectionFailure:
|
||||
click.echo(
|
||||
'Fail to detect shell. Please provide the {0} environment '
|
||||
'variable.'.format(crayons.normal('PIPENV_SHELL', bold=True)),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
print(click_completion.get_code(shell=shell, prog_name='pipenv'))
|
||||
|
||||
|
||||
def do_man():
|
||||
from pipenv.utils import system_which
|
||||
man = system_which('man')
|
||||
if man:
|
||||
path = os.path.join(os.path.dirname(__file__), 'pipenv.1')
|
||||
os.execle(man, 'man', path, os.environ)
|
||||
return # Shouldn't reach here.
|
||||
click.echo(
|
||||
'man does not appear to be available on your system.',
|
||||
err=True,
|
||||
)
|
||||
click.get_current_context.exit(1)
|
||||
|
||||
|
||||
def do_envs():
|
||||
from pipenv import environments
|
||||
click.echo(
|
||||
'The following environment variables can be set, '
|
||||
'to do various things:\n',
|
||||
)
|
||||
for key in environments.__dict__:
|
||||
if key.startswith('PIPENV'):
|
||||
click.echo(' - {0}'.format(crayons.normal(key, bold=True)))
|
||||
click.echo('\nYou can learn more at:\n {0}'.format(
|
||||
crayons.green(
|
||||
'https://docs.pipenv.org/advanced/'
|
||||
'#configuration-with-environment-variables'
|
||||
)),
|
||||
)
|
||||
|
||||
|
||||
def warn_in_virtualenv():
|
||||
# Only warn if pipenv isn't already active.
|
||||
from pipenv.environments import PIPENV_USE_SYSTEM
|
||||
if not PIPENV_USE_SYSTEM or 'PIPENV_ACTIVE' in os.environ:
|
||||
return
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import click
|
||||
click.echo(
|
||||
'{0}: Pipenv found itself running within a virtual environment, '
|
||||
'so it will automatically use that environment, instead of '
|
||||
'creating its own for any project. You can set '
|
||||
'{1} to force pipenv to ignore that environment and create '
|
||||
'its own instead.'.format(
|
||||
crayons.green('Courtesy Notice'),
|
||||
crayons.normal('PIPENV_IGNORE_VIRTUALENVS=1', bold=True),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
|
||||
|
||||
def do_py(system=False):
|
||||
from pipenv.core import which
|
||||
try:
|
||||
click.echo(which('python', allow_global=system))
|
||||
except AttributeError:
|
||||
click.echo(crayons.red('No project found!'))
|
||||
|
||||
|
||||
def do_venv():
|
||||
# There is no virtualenv yet.
|
||||
from pipenv.core import project
|
||||
if not project.virtualenv_exists:
|
||||
click.echo(
|
||||
crayons.red(
|
||||
'No virtualenv has been created for this project yet!'
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
click.echo(project.virtualenv_location)
|
||||
|
||||
|
||||
def do_rm():
|
||||
# Abort if --system (or running in a virtualenv).
|
||||
from pipenv.environments import PIPENV_USE_SYSTEM
|
||||
if PIPENV_USE_SYSTEM:
|
||||
click.echo(
|
||||
crayons.red(
|
||||
'You are attempting to remove a virtualenv that '
|
||||
'Pipenv did not create. Aborting.'
|
||||
)
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
from pipenv.core import project
|
||||
if not project.virtualenv_exists:
|
||||
click.echo(crayons.red(
|
||||
'No virtualenv has been created for this project yet!',
|
||||
bold=True,
|
||||
), err=True)
|
||||
sys.exit(1)
|
||||
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
u'{0} ({1})…'.format(
|
||||
crayons.normal('Removing virtualenv', bold=True),
|
||||
crayons.green(project.virtualenv_location),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Remove the virtualenv.
|
||||
from ._utils import spinner
|
||||
with spinner():
|
||||
from .operations.virtualenv import cleanup_virtualenv
|
||||
cleanup_virtualenv(bare=True)
|
||||
@@ -2,38 +2,16 @@ import os
|
||||
import sys
|
||||
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import click, dotenv
|
||||
from pipenv.vendor import click
|
||||
|
||||
from pipenv.cmdparse import ScriptEmptyError
|
||||
from pipenv.core import project, which
|
||||
from pipenv.environments import (
|
||||
PIPENV_DONT_LOAD_ENV,
|
||||
PIPENV_DOTENV_LOCATION,
|
||||
)
|
||||
from pipenv.utils import system_which
|
||||
|
||||
from ._utils import load_dot_env
|
||||
from .ensure import ensure_project
|
||||
|
||||
|
||||
def _load_dot_env():
|
||||
"""Loads .env file into sys.environ.
|
||||
"""
|
||||
if not PIPENV_DONT_LOAD_ENV:
|
||||
# If the project doesn't exist yet, check current directory for a .env file
|
||||
project_directory = project.project_directory or '.'
|
||||
denv = dotenv.find_dotenv(
|
||||
PIPENV_DOTENV_LOCATION or os.sep.join([project_directory, '.env'])
|
||||
)
|
||||
if os.path.isfile(denv):
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
'Loading .env environment variables...', bold=True
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
dotenv.load_dotenv(denv, override=True)
|
||||
|
||||
|
||||
def _inline_activate_virtualenv():
|
||||
try:
|
||||
activate_this = which('activate_this.py')
|
||||
@@ -105,7 +83,7 @@ def do_run(command, args, three=None, python=False):
|
||||
"""
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False)
|
||||
_load_dot_env()
|
||||
load_dot_env()
|
||||
# Activate virtualenv under the current interpreter's environment
|
||||
_inline_activate_virtualenv()
|
||||
try:
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
|
||||
from pipenv.patched import crayons, pew
|
||||
from pipenv.vendor import click, pexpect
|
||||
|
||||
from pipenv.core import project
|
||||
from pipenv.environments import (
|
||||
PIPENV_SHELL,
|
||||
PIPENV_SHELL_FANCY,
|
||||
)
|
||||
from pipenv.utils import temp_environ
|
||||
|
||||
from ._utils import load_dot_env
|
||||
from .ensure import ensure_project
|
||||
|
||||
# Backport required for earlier versions of Python.
|
||||
if sys.version_info < (3, 3):
|
||||
from .vendor.backports.shutil_get_terminal_size import get_terminal_size
|
||||
else:
|
||||
from shutil import get_terminal_size
|
||||
|
||||
|
||||
def _activate_virtualenv(source=True):
|
||||
"""Returns the string to activate a virtualenv."""
|
||||
# Suffix and source command for other shells.
|
||||
suffix = ''
|
||||
command = ' .' if source else ''
|
||||
# Support for fish shell.
|
||||
if PIPENV_SHELL and 'fish' in PIPENV_SHELL:
|
||||
suffix = '.fish'
|
||||
command = 'source'
|
||||
# Support for csh shell.
|
||||
if PIPENV_SHELL and 'csh' in PIPENV_SHELL:
|
||||
suffix = '.csh'
|
||||
command = 'source'
|
||||
# Escape any spaces located within the virtualenv path to allow
|
||||
# for proper activation.
|
||||
venv_location = project.virtualenv_location.replace(' ', r'\ ')
|
||||
if source:
|
||||
return '{2} {0}/bin/activate{1}'.format(venv_location, suffix, command)
|
||||
else:
|
||||
return '{0}/bin/activate'.format(venv_location)
|
||||
|
||||
|
||||
def do_shell(three=None, python=False, fancy=False, shell_args=None):
|
||||
# Load .env file.
|
||||
load_dot_env()
|
||||
# Use fancy mode for Windows.
|
||||
if os.name == 'nt':
|
||||
fancy = True
|
||||
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False)
|
||||
# Set an environment variable, so we know we're in the environment.
|
||||
os.environ['PIPENV_ACTIVE'] = '1'
|
||||
compat = (not fancy)
|
||||
# Support shell compatibility mode.
|
||||
if PIPENV_SHELL_FANCY:
|
||||
compat = False
|
||||
# Compatibility mode:
|
||||
if compat:
|
||||
if PIPENV_SHELL:
|
||||
shell = os.path.abspath(PIPENV_SHELL)
|
||||
else:
|
||||
click.echo(
|
||||
crayons.red(
|
||||
'Please ensure that the {0} environment variable '
|
||||
'is set before activating shell.'.format(
|
||||
crayons.normal('SHELL', bold=True)
|
||||
)
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
'Spawning environment shell ({0}). Use {1} to leave.'.format(
|
||||
crayons.red(shell), crayons.normal("'exit'", bold=True)
|
||||
),
|
||||
bold=True,
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
cmd = "{0} -i'".format(shell)
|
||||
args = []
|
||||
# Standard (properly configured shell) mode:
|
||||
else:
|
||||
if project.is_venv_in_project():
|
||||
# use .venv as the target virtualenv name
|
||||
workon_name = '.venv'
|
||||
else:
|
||||
workon_name = project.virtualenv_name
|
||||
cmd = sys.executable
|
||||
args = ['-m', 'pipenv.pew', 'workon', workon_name]
|
||||
# Grab current terminal dimensions to replace the hardcoded default
|
||||
# dimensions of pexpect
|
||||
terminal_dimensions = get_terminal_size()
|
||||
try:
|
||||
with temp_environ():
|
||||
if project.is_venv_in_project():
|
||||
os.environ['WORKON_HOME'] = project.project_directory
|
||||
c = pexpect.spawn(
|
||||
cmd,
|
||||
args,
|
||||
dimensions=(
|
||||
terminal_dimensions.lines, terminal_dimensions.columns
|
||||
),
|
||||
)
|
||||
# Windows!
|
||||
except AttributeError:
|
||||
# import subprocess
|
||||
# Tell pew to use the project directory as its workon_home
|
||||
with temp_environ():
|
||||
if project.is_venv_in_project():
|
||||
os.environ['WORKON_HOME'] = project.project_directory
|
||||
pew.pew.workon_cmd([workon_name])
|
||||
sys.exit(0)
|
||||
# Activate the virtualenv if in compatibility mode.
|
||||
if compat:
|
||||
c.sendline(_activate_virtualenv())
|
||||
# Send additional arguments to the subshell.
|
||||
if shell_args:
|
||||
c.sendline(' '.join(shell_args))
|
||||
|
||||
# Handler for terminal resizing events
|
||||
# Must be defined here to have the shell process in its context, since we
|
||||
# can't pass it as an argument
|
||||
def sigwinch_passthrough(sig, data):
|
||||
terminal_dimensions = get_terminal_size()
|
||||
c.setwinsize(terminal_dimensions.lines, terminal_dimensions.columns)
|
||||
|
||||
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
|
||||
# Interact with the new shell.
|
||||
c.interact(escape_character=None)
|
||||
c.close()
|
||||
sys.exit(c.exitstatus)
|
||||
@@ -10,7 +10,6 @@ from .init import do_init
|
||||
|
||||
|
||||
def do_sync(
|
||||
ctx,
|
||||
dev=False,
|
||||
three=None,
|
||||
python=None,
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import click, delegator, requirementslib
|
||||
|
||||
from pipenv.core import BAD_PACKAGES, project, which_pip
|
||||
from pipenv.environments import PIPENV_USE_SYSTEM
|
||||
from pipenv.utils import escape_grouped_arguments
|
||||
|
||||
from .ensure import ensure_project
|
||||
from .lock import do_lock
|
||||
|
||||
|
||||
def _purge(bare=False, downloads=False, allow_global=False, verbose=False):
|
||||
"""Executes the purge functionality."""
|
||||
if downloads:
|
||||
if not bare:
|
||||
click.echo(
|
||||
crayons.normal(u'Clearing out downloads directory...', bold=True)
|
||||
)
|
||||
shutil.rmtree(project.download_location)
|
||||
return
|
||||
|
||||
freeze = delegator.run(
|
||||
'{0} freeze'.format(
|
||||
escape_grouped_arguments(which_pip(allow_global=allow_global))
|
||||
)
|
||||
).out
|
||||
# Remove comments from the output, if any.
|
||||
installed = [
|
||||
line
|
||||
for line in freeze.splitlines()
|
||||
if not line.lstrip().startswith('#')
|
||||
]
|
||||
# Remove setuptools and friends from installed, if present.
|
||||
for package_name in BAD_PACKAGES:
|
||||
for i, package in enumerate(installed):
|
||||
if package.startswith(package_name):
|
||||
del installed[i]
|
||||
actually_installed = []
|
||||
for package in installed:
|
||||
try:
|
||||
dep = requirementslib.Requirement.from_line(package)
|
||||
except AssertionError:
|
||||
dep = None
|
||||
if dep and not dep.is_vcs and not dep.editable:
|
||||
dep = dep.name
|
||||
actually_installed.append(dep)
|
||||
if not bare:
|
||||
click.echo(
|
||||
u'Found {0} installed package(s), purging...'.format(
|
||||
len(actually_installed)
|
||||
)
|
||||
)
|
||||
command = '{0} uninstall {1} -y'.format(
|
||||
escape_grouped_arguments(which_pip(allow_global=allow_global)),
|
||||
' '.join(actually_installed),
|
||||
)
|
||||
if verbose:
|
||||
click.echo('$ {0}'.format(command))
|
||||
c = delegator.run(command)
|
||||
if not bare:
|
||||
click.echo(crayons.blue(c.out))
|
||||
click.echo(crayons.green('Environment now purged and fresh!'))
|
||||
|
||||
|
||||
def do_uninstall(
|
||||
package_name=False,
|
||||
more_packages=False,
|
||||
three=None,
|
||||
python=False,
|
||||
system=False,
|
||||
lock=False,
|
||||
all_dev=False,
|
||||
all=False,
|
||||
verbose=False,
|
||||
keep_outdated=False,
|
||||
pypi_mirror=None,
|
||||
):
|
||||
# Automatically use an activated virtualenv.
|
||||
if PIPENV_USE_SYSTEM:
|
||||
system = True
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python)
|
||||
package_names = (package_name,) + more_packages
|
||||
pipfile_remove = True
|
||||
# Un-install all dependencies, if --all was provided.
|
||||
if all is True:
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
u'Un-installing all packages from virtualenv...', bold=True
|
||||
)
|
||||
)
|
||||
_purge(allow_global=system, verbose=verbose)
|
||||
sys.exit(0)
|
||||
# Uninstall [dev-packages], if --dev was provided.
|
||||
if all_dev:
|
||||
if 'dev-packages' not in project.parsed_pipfile:
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
'No {0} to uninstall.'.format(
|
||||
crayons.red('[dev-packages]')
|
||||
),
|
||||
bold=True,
|
||||
)
|
||||
)
|
||||
sys.exit(0)
|
||||
click.echo(
|
||||
crayons.normal(
|
||||
u'Un-installing {0}...'.format(crayons.red('[dev-packages]')),
|
||||
bold=True,
|
||||
)
|
||||
)
|
||||
package_names = project.dev_packages.keys()
|
||||
if package_name is False and not all_dev:
|
||||
click.echo(crayons.red('No package provided!'), err=True)
|
||||
sys.exit(1)
|
||||
for package_name in package_names:
|
||||
click.echo(u'Un-installing {0}...'.format(crayons.green(package_name)))
|
||||
cmd = '{0} uninstall {1} -y'.format(
|
||||
escape_grouped_arguments(which_pip(allow_global=system)),
|
||||
package_name,
|
||||
)
|
||||
if verbose:
|
||||
click.echo('$ {0}'.format(cmd))
|
||||
c = delegator.run(cmd)
|
||||
click.echo(crayons.blue(c.out))
|
||||
if pipfile_remove:
|
||||
in_packages = project.get_package_name_in_pipfile(
|
||||
package_name, dev=False)
|
||||
in_dev_packages = project.get_package_name_in_pipfile(
|
||||
package_name, dev=True)
|
||||
if not in_dev_packages and not in_packages:
|
||||
click.echo(
|
||||
'No package {0} to remove from Pipfile.'.format(
|
||||
crayons.green(package_name)
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
click.echo(
|
||||
u'Removing {0} from Pipfile...'.format(
|
||||
crayons.green(package_name)
|
||||
)
|
||||
)
|
||||
# Remove package from both packages and dev-packages.
|
||||
project.remove_package_from_pipfile(package_name, dev=True)
|
||||
project.remove_package_from_pipfile(package_name, dev=False)
|
||||
if lock:
|
||||
do_lock(system=system, keep_outdated=keep_outdated, pypi_mirror=pypi_mirror)
|
||||
@@ -0,0 +1,97 @@
|
||||
import sys
|
||||
|
||||
from pipenv.patched import crayons
|
||||
from pipenv.vendor import click, delegator, requirementslib
|
||||
|
||||
from pipenv.core import project, which
|
||||
from pipenv.utils import pep423_name
|
||||
|
||||
from .ensure import ensure_project
|
||||
from .lock import do_lock
|
||||
from .sync import do_sync
|
||||
|
||||
|
||||
def _do_outdated(pypi_mirror=None):
|
||||
packages = {}
|
||||
results = delegator.run('{0} freeze'.format(which('pip'))).out.strip(
|
||||
).split(
|
||||
'\n'
|
||||
)
|
||||
results = filter(bool, results)
|
||||
for result in results:
|
||||
dep = requirementslib.Requirement.from_line(result)
|
||||
packages.update(dep.as_pipfile())
|
||||
updated_packages = {}
|
||||
lockfile = do_lock(write=False, pypi_mirror=pypi_mirror)
|
||||
for section in ('develop', 'default'):
|
||||
for package in lockfile[section]:
|
||||
try:
|
||||
updated_packages[package] = lockfile[section][package][
|
||||
'version'
|
||||
]
|
||||
except KeyError:
|
||||
pass
|
||||
outdated = []
|
||||
for package in packages:
|
||||
norm_name = pep423_name(package)
|
||||
if norm_name in updated_packages:
|
||||
if updated_packages[norm_name] != packages[package]:
|
||||
outdated.append(
|
||||
(package, updated_packages[norm_name], packages[package])
|
||||
)
|
||||
for package, new_version, old_version in outdated:
|
||||
click.echo(
|
||||
'Package {0!r} out-of-date: {1!r} installed, '
|
||||
'{2!r} available.'.format(package, old_version, new_version),
|
||||
)
|
||||
sys.exit(bool(outdated))
|
||||
|
||||
|
||||
def do_update(
|
||||
package, more_packages, three, python, pypi_mirror, verbose, clear,
|
||||
keep_outdated, pre, dev, bare, sequential, dry_run, outdated,
|
||||
):
|
||||
ensure_project(three=three, python=python, warn=True)
|
||||
if not outdated:
|
||||
outdated = bool(dry_run)
|
||||
if outdated:
|
||||
_do_outdated(pypi_mirror=pypi_mirror)
|
||||
if not package:
|
||||
click.echo(
|
||||
'{0} {1} {2} {3}{4}'.format(
|
||||
crayons.white('Running', bold=True),
|
||||
crayons.red('$ pipenv lock', bold=True),
|
||||
crayons.white('then', bold=True),
|
||||
crayons.red('$ pipenv sync', bold=True),
|
||||
crayons.white('.', bold=True),
|
||||
)
|
||||
)
|
||||
else:
|
||||
for package in ([package] + list(more_packages)):
|
||||
if package not in project.all_packages:
|
||||
click.echo(
|
||||
'{0}: {1} was not found in your Pipfile! Aborting.'
|
||||
''.format(
|
||||
crayons.red('Warning', bold=True),
|
||||
crayons.green(package, bold=True),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
do_lock(
|
||||
verbose=verbose, clear=clear, pre=pre,
|
||||
keep_outdated=keep_outdated, pypi_mirror=pypi_mirror,
|
||||
)
|
||||
do_sync(
|
||||
dev=dev,
|
||||
three=three,
|
||||
python=python,
|
||||
bare=bare,
|
||||
dont_upgrade=False,
|
||||
user=False,
|
||||
verbose=verbose,
|
||||
clear=clear,
|
||||
unused=False,
|
||||
sequential=sequential,
|
||||
pypi_mirror=pypi_mirror,
|
||||
)
|
||||
@@ -983,62 +983,6 @@ def resolve_ref(vcs_obj, target_dir, ref):
|
||||
return vcs_obj.get_revision_sha(target_dir, ref)
|
||||
|
||||
|
||||
def obtain_vcs_req(vcs_obj, src_dir, name, rev=None):
|
||||
target_dir = os.path.join(src_dir, name)
|
||||
target_rev = vcs_obj.make_rev_options(rev)
|
||||
if not os.path.exists(target_dir):
|
||||
vcs_obj.obtain(target_dir)
|
||||
if not vcs_obj.is_commit_id_equal(target_dir, rev) and not vcs_obj.is_commit_id_equal(target_dir, target_rev):
|
||||
vcs_obj.update(target_dir, target_rev)
|
||||
return vcs_obj.get_revision(target_dir)
|
||||
|
||||
|
||||
def get_vcs_deps(
|
||||
project,
|
||||
pip_freeze=None,
|
||||
which=None,
|
||||
verbose=False,
|
||||
clear=False,
|
||||
pre=False,
|
||||
allow_global=False,
|
||||
dev=False,
|
||||
pypi_mirror=None,
|
||||
):
|
||||
from .patched.notpip._internal.vcs import VcsSupport
|
||||
from ._compat import TemporaryDirectory
|
||||
|
||||
section = "vcs_dev_packages" if dev else "vcs_packages"
|
||||
reqs = []
|
||||
lockfile = {}
|
||||
try:
|
||||
packages = getattr(project, section)
|
||||
except AttributeError:
|
||||
return [], []
|
||||
if not os.environ.get("PIP_SRC") and not project.virtualenv_location:
|
||||
_src_dir = TemporaryDirectory(prefix='pipenv-', suffix='-src')
|
||||
src_dir = Path(_src_dir.name)
|
||||
else:
|
||||
src_dir = Path(
|
||||
os.environ.get("PIP_SRC", os.path.join(project.virtualenv_location, "src"))
|
||||
)
|
||||
src_dir.mkdir(mode=0o775, exist_ok=True)
|
||||
vcs_registry = VcsSupport
|
||||
for pkg_name, pkg_pipfile in packages.items():
|
||||
requirement = Requirement.from_pipfile(pkg_name, pkg_pipfile)
|
||||
backend = vcs_registry()._registry.get(requirement.vcs)
|
||||
__vcs = backend(url=requirement.req.vcs_uri)
|
||||
locked_rev = None
|
||||
name = requirement.normalized_name
|
||||
locked_rev = obtain_vcs_req(
|
||||
__vcs, src_dir.as_posix(), name, rev=pkg_pipfile.get("ref")
|
||||
)
|
||||
if requirement.is_vcs:
|
||||
requirement.req.ref = locked_rev
|
||||
lockfile[name] = requirement.pipfile_entry[1]
|
||||
reqs.append(requirement)
|
||||
return reqs, lockfile
|
||||
|
||||
|
||||
def fs_str(string):
|
||||
"""Encodes a string into the proper filesystem encoding
|
||||
|
||||
|
||||
Reference in New Issue
Block a user