Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions rsconnect/bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"__pycache__/",
"env/",
"packrat/",
"renv/",
"rsconnect-python/",
"rsconnect/",
"venv/",
Expand Down Expand Up @@ -401,6 +402,23 @@ def create_glob_set(directory, excludes):
return GlobSet(work)


def is_environment_dir(directory):
python_path = join(directory, "bin", "python")
return exists(python_path)


def list_environment_dirs(directory):
# type: (...) -> typing.List[str]
"""Returns a list of subdirectories in `directory` that appear to contain virtual environments."""
envs = []

for name in os.listdir(directory):
path = join(directory, name)
if is_environment_dir(path):
envs.append(name)
return envs


def _create_api_file_list(
directory, # type: str
requirements_file_name, # type: str
Expand Down Expand Up @@ -429,6 +447,7 @@ def _create_api_file_list(
excludes = list(excludes) if excludes else []
excludes.append("manifest.json")
excludes.append(requirements_file_name)
excludes.extend(list_environment_dirs(directory))
glob_set = create_glob_set(directory, excludes)

file_list = []
Expand Down Expand Up @@ -470,6 +489,9 @@ def make_api_manifest(
:param excludes: a sequence of glob patterns that will exclude matched files.
:return: the manifest and a list of the files involved.
"""
if is_environment_dir(directory):
excludes = list(excludes or []) + ["bin/", "lib/"]

relevant_files = _create_api_file_list(directory, environment.filename, extra_files, excludes)
manifest = make_source_manifest(entry_point, environment, app_mode)

Expand Down
25 changes: 21 additions & 4 deletions rsconnect/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
)

from . import api
from .bundle import make_manifest_bundle
from .bundle import is_environment_dir, make_manifest_bundle
from .metadata import ServerStore, AppStore
from .models import AppModes

Expand Down Expand Up @@ -403,6 +403,20 @@ def _warn_if_no_requirements_file(directory):
)


def _warn_if_environment_directory(directory):
"""
Issue a warning if the deployment directory is itself a virtualenv (yikes!).

:param directory: the directory to check in.
"""
if is_environment_dir(directory):
click.secho(
" Warning: The deployment directory appears to be a python virtual environment.\n"
" Excluding the 'bin' and 'lib' directories.",
fg="yellow",
)


def _warn_on_ignored_conda_env(environment):
"""
Checks for a discovered Conda environment and produces a warning that it will be ignored when
Expand Down Expand Up @@ -575,8 +589,10 @@ def deploy_notebook(

click.secho(' Deploying %s to server "%s"' % (file, connect_server.url))

_warn_on_ignored_manifest(dirname(file))
_warn_if_no_requirements_file(dirname(file))
base_dir = dirname(file)
_warn_on_ignored_manifest(base_dir)
_warn_if_no_requirements_file(base_dir)
_warn_if_environment_directory(base_dir)

with cli_feedback("Inspecting Python environment"):
python, environment = get_python_env_info(file, python, conda, force_generate)
Expand All @@ -588,7 +604,7 @@ def deploy_notebook(
_warn_on_ignored_conda_env(environment)

if force_generate:
_warn_on_ignored_requirements(dirname(file), environment.filename)
_warn_on_ignored_requirements(base_dir, environment.filename)

with cli_feedback("Creating deployment bundle"):
bundle = create_notebook_deployment_bundle(
Expand Down Expand Up @@ -881,6 +897,7 @@ def _deploy_by_framework(

_warn_on_ignored_manifest(directory)
_warn_if_no_requirements_file(directory)
_warn_if_environment_directory(directory)

with cli_feedback("Inspecting Python environment"):
_, environment = get_python_env_info(module_file, python, conda, force_generate)
Expand Down