Skip to content

Commit

Permalink
Dist removal (#5074)
Browse files Browse the repository at this point in the history
* Copy over Dist and related functions from conda

* Copy over plan instructions from conda

* Remove Dist

* Inline one-off execute_/install_actions functions

* Simplify _plan_from_actions

* Collapse _plan_from_actions into execute_actions

* Remove unused args for execute/install_actions

* Use PackageRecord "prec" naming when unambiguous

* Move install actions to .environ

* Mark functions from conda.plan as non-public

These will be changed/superseded/removed in a future version and thus
should not be used elsewhere.

---------

Signed-off-by: Marcel Bargull <[email protected]>
Co-authored-by: Ken Odegard <[email protected]>
Co-authored-by: Jannis Leidel <[email protected]>
  • Loading branch information
3 people authored Jan 26, 2024
1 parent e4fd8d7 commit 3cba0b9
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 87 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@
* Mark `conda_build.inspect_pkg.check_install(package)` as pending deprecation in favor of `conda_build.inspect_pkg.check_install(subdir)`. (#5033)
* Mark `conda_build.inspect_pkg.check_install(prepend)` as pending deprecation. (#5033)
* Mark `conda_build.inspect_pkg.check_install(minimal_hint)` as pending deprecation. (#5033)
* Mark `conda_build.conda_interface.Dist` as pending deprecation. (#5074)
* Mark `conda_build.conda_interface.display_actions` as pending deprecation. (#5074)
* Mark `conda_build.conda_interface.execute_actions` as pending deprecation. (#5074)
* Mark `conda_build.conda_interface.execute_plan` as pending deprecation. (#5074)
* Mark `conda_build.conda_interface.get_index` as pending deprecation. (#5074)
* Mark `conda_build.conda_interface.install_actions` as pending deprecation. (#5074)
* Mark `conda_build.conda_interface.linked` as pending deprecation. (#5074)
* Mark `conda_build.conda_interface.linked_data` as pending deprecation. (#5074)
* Mark `conda_build.utils.linked_data_no_multichannels` as pending deprecation. (#5074)
* Remove `conda_build.api.update_index`. (#5151)
* Remove `conda_build.cli.main_build.main`. (#5151)
* Remove `conda_build.cli.main_convert.main`. (#5151)
Expand Down Expand Up @@ -77,6 +86,9 @@
### Other

* Remove unused Allure test report collection. (#5113)
* Remove dependency on `conda.plan`. (#5074)
* Remove almost all dependency on `conda.models.dist`. (#5074)
* Replace usage of legacy `conda.models.dist.Dist` with `conda.models.records.PackageRecord`. (#5074)

### Contributors

Expand Down
2 changes: 1 addition & 1 deletion conda_build/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -3841,7 +3841,7 @@ def build_tree(
meta,
actions,
"host",
package_subset=dep,
package_subset=[dep],
require_files=True,
)
# test that package, using the local channel so that our new
Expand Down
31 changes: 22 additions & 9 deletions conda_build/conda_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
InstalledPackages,
MatchSpec,
NoPackagesFound,
PackageRecord,
PathType,
Resolve,
StringIO,
Expand All @@ -43,23 +44,15 @@
_toposort,
add_parser_channels,
add_parser_prefix,
display_actions,
download,
execute_actions,
execute_plan,
get_index,
handle_proxy_407,
hashsum_file,
human_bytes,
input,
install_actions,
lchmod,
linked,
linked_data,
md5_file,
memoized,
normalized_version,
package_cache,
prefix_placeholder,
rm_rf,
spec_from_line,
Expand All @@ -72,8 +65,28 @@
walk_prefix,
win_path_to_unix,
)
from conda.exports import display_actions as _display_actions
from conda.exports import execute_actions as _execute_actions
from conda.exports import execute_plan as _execute_plan
from conda.exports import get_index as _get_index
from conda.exports import install_actions as _install_actions
from conda.exports import linked as _linked
from conda.exports import linked_data as _linked_data
from conda.exports import package_cache as _package_cache
from conda.models.channel import get_conda_build_local_url # noqa: F401
from conda.models.dist import Dist # noqa: F401
from conda.models.dist import Dist as _Dist

from .deprecations import deprecated

deprecated.constant("24.1.0", "24.3.0", "Dist", _Dist)
deprecated.constant("24.1.0", "24.3.0", "display_actions", _display_actions)
deprecated.constant("24.1.0", "24.3.0", "execute_actions", _execute_actions)
deprecated.constant("24.1.0", "24.3.0", "execute_plan", _execute_plan)
deprecated.constant("24.1.0", "24.3.0", "get_index", _get_index)
deprecated.constant("24.1.0", "24.3.0", "install_actions", _install_actions)
deprecated.constant("24.1.0", "24.3.0", "linked", _linked)
deprecated.constant("24.1.0", "24.3.0", "linked_data", _linked_data)
deprecated.constant("24.1.0", "24.3.0", "package_cache", _package_cache)

# TODO: Go to references of all properties below and import them from `context` instead
binstar_upload = context.binstar_upload
Expand Down
203 changes: 191 additions & 12 deletions conda_build/environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,35 @@
import subprocess
import sys
import warnings
from collections import defaultdict
from functools import lru_cache
from glob import glob
from logging import getLogger
from os.path import join, normpath

from conda.base.constants import DEFAULTS_CHANNEL_NAME, UNKNOWN_CHANNEL
from conda.common.io import env_vars
from conda.core.index import LAST_CHANNEL_URLS
from conda.core.link import PrefixSetup, UnlinkLinkTransaction
from conda.core.prefix_data import PrefixData
from conda.models.channel import prioritize_channels

from . import utils
from .conda_interface import (
Channel,
CondaError,
LinkError,
LockError,
MatchSpec,
NoPackagesFoundError,
PackageRecord,
PaddingError,
ProgressiveFetchExtract,
TemporaryDirectory,
UnsatisfiableError,
context,
create_default_packages,
display_actions,
execute_actions,
get_version_from_git_tag,
install_actions,
pkgs_dirs,
reset_context,
root_dir,
Expand All @@ -42,10 +53,16 @@
env_var,
on_mac,
on_win,
package_record_to_requirement,
prepend_bin_path,
)
from .variants import get_default_variant

log = getLogger(__name__)

PREFIX_ACTION = "PREFIX"
LINK_ACTION = "LINK"

# these are things that we provide env vars for more explicitly. This list disables the
# pass-through of variant values to env vars for these keys.
LANGUAGES = ("PERL", "LUA", "R", "NUMPY", "PYTHON")
Expand Down Expand Up @@ -890,16 +907,16 @@ def get_install_actions(
disable_pip,
) in cached_actions and last_index_ts >= index_ts:
actions = cached_actions[(specs, env, subdir, channel_urls, disable_pip)].copy()
if "PREFIX" in actions:
actions["PREFIX"] = prefix
if PREFIX_ACTION in actions:
actions[PREFIX_ACTION] = prefix
elif specs:
# this is hiding output like:
# Fetching package metadata ...........
# Solving package specifications: ..........
with utils.LoggingContext(conda_log_level):
with capture():
try:
actions = install_actions(prefix, index, specs, force=True)
actions = _install_actions(prefix, index, specs)
except (NoPackagesFoundError, UnsatisfiableError) as exc:
raise DependencyNeedsBuildingError(exc, subdir=subdir)
except (
Expand Down Expand Up @@ -973,8 +990,8 @@ def get_install_actions(
if not any(
re.match(r"^%s(?:$|[\s=].*)" % pkg, str(dep)) for dep in specs
):
actions["LINK"] = [
spec for spec in actions["LINK"] if spec.name != pkg
actions[LINK_ACTION] = [
prec for prec in actions[LINK_ACTION] if prec.name != pkg
]
utils.trim_empty_keys(actions)
cached_actions[(specs, env, subdir, channel_urls, disable_pip)] = actions.copy()
Expand Down Expand Up @@ -1051,13 +1068,13 @@ def create_env(
timeout=config.timeout,
)
utils.trim_empty_keys(actions)
display_actions(actions, index)
_display_actions(actions)
if utils.on_win:
for k, v in os.environ.items():
os.environ[k] = str(v)
with env_var("CONDA_QUIET", not config.verbose, reset_context):
with env_var("CONDA_JSON", not config.verbose, reset_context):
execute_actions(actions, index)
_execute_actions(actions)
except (
SystemExit,
PaddingError,
Expand Down Expand Up @@ -1096,7 +1113,7 @@ def create_env(
# Set this here and use to create environ
# Setting this here is important because we use it below (symlink)
prefix = config.host_prefix if host else config.build_prefix
actions["PREFIX"] = prefix
actions[PREFIX_ACTION] = prefix

create_env(
prefix,
Expand Down Expand Up @@ -1234,6 +1251,168 @@ def get_pinned_deps(m, section):
channel_urls=tuple(m.config.channel_urls),
)
runtime_deps = [
" ".join(link.dist_name.rsplit("-", 2)) for link in actions.get("LINK", [])
package_record_to_requirement(prec) for prec in actions.get(LINK_ACTION, [])
]
return runtime_deps


# NOTE: The function has to retain the "install_actions" name for now since
# conda_libmamba_solver.solver.LibMambaSolver._called_from_conda_build
# checks for this name in the call stack explicitly.
def install_actions(prefix, index, specs):
# This is copied over from https://github.com/conda/conda/blob/23.11.0/conda/plan.py#L471
# but reduced to only the functionality actually used within conda-build.

with env_vars(
{
"CONDA_ALLOW_NON_CHANNEL_URLS": "true",
"CONDA_SOLVER_IGNORE_TIMESTAMPS": "false",
},
callback=reset_context,
):
# a hack since in conda-build we don't track channel_priority_map
if LAST_CHANNEL_URLS:
channel_priority_map = prioritize_channels(LAST_CHANNEL_URLS)
# tuple(dict.fromkeys(...)) removes duplicates while preserving input order.
channels = tuple(
dict.fromkeys(Channel(url) for url in channel_priority_map)
)
subdirs = (
tuple(
dict.fromkeys(
subdir for subdir in (c.subdir for c in channels) if subdir
)
)
or context.subdirs
)
else:
channels = subdirs = None

specs = tuple(MatchSpec(spec) for spec in specs)

PrefixData._cache_.clear()

solver_backend = context.plugin_manager.get_cached_solver_backend()
solver = solver_backend(prefix, channels, subdirs, specs_to_add=specs)
if index:
# Solver can modify the index (e.g., Solver._prepare adds virtual
# package) => Copy index (just outer container, not deep copy)
# to conserve it.
solver._index = index.copy()
txn = solver.solve_for_transaction(prune=False, ignore_pinned=False)
prefix_setup = txn.prefix_setups[prefix]
actions = {
PREFIX_ACTION: prefix,
LINK_ACTION: [prec for prec in prefix_setup.link_precs],
}
return actions


_install_actions = install_actions
del install_actions


def _execute_actions(actions):
# This is copied over from https://github.com/conda/conda/blob/23.11.0/conda/plan.py#L575
# but reduced to only the functionality actually used within conda-build.

assert PREFIX_ACTION in actions and actions[PREFIX_ACTION]
prefix = actions[PREFIX_ACTION]

if LINK_ACTION not in actions:
log.debug(f"action {LINK_ACTION} not in actions")
return

link_precs = actions[LINK_ACTION]
if not link_precs:
log.debug(f"action {LINK_ACTION} has None value")
return

# Always link menuinst first/last on windows in case a subsequent
# package tries to import it to create/remove a shortcut
link_precs = [p for p in link_precs if p.name == "menuinst"] + [
p for p in link_precs if p.name != "menuinst"
]

progressive_fetch_extract = ProgressiveFetchExtract(link_precs)
progressive_fetch_extract.prepare()

stp = PrefixSetup(prefix, (), link_precs, (), [], ())
unlink_link_transaction = UnlinkLinkTransaction(stp)

log.debug(" %s(%r)", "PROGRESSIVEFETCHEXTRACT", progressive_fetch_extract)
progressive_fetch_extract.execute()
log.debug(" %s(%r)", "UNLINKLINKTRANSACTION", unlink_link_transaction)
unlink_link_transaction.execute()


def _display_actions(actions):
# This is copied over from https://github.com/conda/conda/blob/23.11.0/conda/plan.py#L58
# but reduced to only the functionality actually used within conda-build.

prefix = actions.get(PREFIX_ACTION)
builder = ["", "## Package Plan ##\n"]
if prefix:
builder.append(" environment location: %s" % prefix)
builder.append("")
print("\n".join(builder))

show_channel_urls = context.show_channel_urls

def channel_str(rec):
if rec.get("schannel"):
return rec["schannel"]
if rec.get("url"):
return Channel(rec["url"]).canonical_name
if rec.get("channel"):
return Channel(rec["channel"]).canonical_name
return UNKNOWN_CHANNEL

def channel_filt(s):
if show_channel_urls is False:
return ""
if show_channel_urls is None and s == DEFAULTS_CHANNEL_NAME:
return ""
return s

packages = defaultdict(lambda: "")
features = defaultdict(lambda: "")
channels = defaultdict(lambda: "")

for prec in actions.get(LINK_ACTION, []):
assert isinstance(prec, PackageRecord)
pkg = prec["name"]
channels[pkg] = channel_filt(channel_str(prec))
packages[pkg] = prec["version"] + "-" + prec["build"]
features[pkg] = ",".join(prec.get("features") or ())

fmt = {}
if packages:
maxpkg = max(len(p) for p in packages) + 1
maxver = max(len(p) for p in packages.values())
maxfeatures = max(len(p) for p in features.values())
maxchannels = max(len(p) for p in channels.values())
for pkg in packages:
# That's right. I'm using old-style string formatting to generate a
# string with new-style string formatting.
fmt[pkg] = f"{{pkg:<{maxpkg}}} {{vers:<{maxver}}}"
if maxchannels:
fmt[pkg] += " {channel:<%s}" % maxchannels
if features[pkg]:
fmt[pkg] += " [{features:<%s}]" % maxfeatures

lead = " " * 4

def format(s, pkg):
return lead + s.format(
pkg=pkg + ":",
vers=packages[pkg],
channel=channels[pkg],
features=features[pkg],
)

if packages:
print("\nThe following NEW packages will be INSTALLED:\n")
for pkg in sorted(packages):
print(format(fmt[pkg], pkg))
print()
Loading

0 comments on commit 3cba0b9

Please sign in to comment.