Skip to content

Commit

Permalink
Loosen lock selection rules to allow migrations.
Browse files Browse the repository at this point in the history
Previously a subset needed to be successful to select a locked resolve
for syncing. This would fail if the lock was strict or else any single
locked requirement had platform specific artifacts with no available
sdist.
  • Loading branch information
jsirois committed Mar 17, 2024
1 parent a81779e commit ac4f090
Show file tree
Hide file tree
Showing 3 changed files with 255 additions and 75 deletions.
106 changes: 60 additions & 46 deletions pex/cli/commands/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ def update(
updates=(), # type: Iterable[Requirement]
replacements=(), # type: Iterable[Requirement]
deletes=(), # type: Iterable[ProjectName]
pin=False, # type: bool
artifacts_can_change=False, # type: bool
):
# type: (...) -> Union[LockUpdate, Result]
if not self._update_requests:
Expand All @@ -333,24 +333,17 @@ def update(
updates=updates,
replacements=replacements,
deletes=deletes,
pin=pin,
artifacts_can_change=artifacts_can_change,
)

def sync(
self,
requirement_configuration, # type: RequirementConfiguration
pin=False, # type: bool
lock_config_updated=False, # type: bool
):
# type: (...) -> Union[LockUpdate, Result]
def sync(self, requirement_configuration):
# type: (RequirementConfiguration) -> Union[LockUpdate, Result]
if not self._update_requests:
return self._no_updates()

return self._lock_updater.sync(
update_requests=self._update_requests,
requirement_configuration=requirement_configuration,
pin=pin,
lock_config_updated=lock_config_updated,
)

def _no_updates(self):
Expand Down Expand Up @@ -640,20 +633,25 @@ def _add_update_arguments(cls, update_parser):
resolver_options.register_use_pip_config(resolver_options_parser)

@classmethod
def add_update_lock_options(cls, update_parser):
update_parser.add_argument(
"--strict",
"--no-strict",
"--non-strict",
action=HandleBoolAction,
default=True,
type=bool,
help=(
"Require all target platforms in the lock be updated at once. If any target "
"platform in the lock file does not have a representative local interpreter to "
"execute the lock update with, the update will fail."
),
)
def add_update_lock_options(
cls,
update_parser, # type: _ActionsContainer
include_strict=True, # type: bool
):
if include_strict:
update_parser.add_argument(
"--strict",
"--no-strict",
"--non-strict",
action=HandleBoolAction,
default=True,
type=bool,
help=(
"Require all target platforms in the lock be updated at once. If any target "
"platform in the lock file does not have a representative local interpreter to "
"execute the lock update with, the update will fail."
),
)
update_parser.add_argument(
"-n",
"--dry-run",
Expand Down Expand Up @@ -711,7 +709,7 @@ def _add_sync_arguments(cls, sync_parser):
)
cls._add_lockfile_option(sync_parser, verb="sync", positional=False)
cls.add_create_lock_options(sync_parser)
cls.add_update_lock_options(sync_parser)
cls.add_update_lock_options(sync_parser, include_strict=False)

@classmethod
def add_extra_arguments(
Expand Down Expand Up @@ -1002,23 +1000,42 @@ def _create_lock_update_request(
)

with TRACER.timed("Selecting locks to update"):
subset_result = try_(
subset(
targets=targets,
lock=lock_file,
network_configuration=network_configuration,
build_configuration=lock_file.build_configuration(),
transitive=lock_file.transitive,
locked_resolve_count = len(lock_file.locked_resolves)
if lock_file.style is LockStyle.UNIVERSAL and locked_resolve_count != 1:
return Error(
"The lock at {path} contains {count} locked resolves; so it "
"cannot be updated as a universal lock which requires exactly one locked "
"resolve.".format(path=lock_file_path, count=locked_resolve_count)
)
)

update_requests = [
ResolveUpdateRequest(
target=resolved_subset.target, locked_resolve=resolved_subset.resolved.source
)
for resolved_subset in subset_result.subsets
]
if self.options.strict and lock_file.style is not LockStyle.UNIVERSAL:
if locked_resolve_count == 1:
locked_resolve = lock_file.locked_resolves[0]
update_targets = (
[LocalInterpreter.create(targets.interpreter)]
if lock_file.style is LockStyle.UNIVERSAL
else targets.unique_targets()
)
update_requests = [
ResolveUpdateRequest(target=target, locked_resolve=locked_resolve)
for target in update_targets
]
else:
subset_result = try_(
subset(
targets=targets,
lock=lock_file,
network_configuration=network_configuration,
build_configuration=lock_file.build_configuration(),
transitive=lock_file.transitive,
)
)
update_requests = [
ResolveUpdateRequest(
target=resolved_subset.target,
locked_resolve=resolved_subset.resolved.source,
)
for resolved_subset in subset_result.subsets
]
if getattr(self.options, "strict", False) and lock_file.style is not LockStyle.UNIVERSAL:
missing_updates = set(lock_file.locked_resolves) - {
update_request.locked_resolve for update_request in update_requests
}
Expand Down Expand Up @@ -1341,7 +1358,7 @@ def _update(self):
updates=update_requirements,
replacements=replace_requirements,
deletes=delete_projects,
pin=pin,
artifacts_can_change=pin,
)
if isinstance(lock_update, Result):
return lock_update
Expand Down Expand Up @@ -1402,11 +1419,8 @@ def _sync(self):
self._create_lock_update_request(lock_file_path=lock_file_path, lock_file=lock_file)
)

pin = getattr(self.options, "pin", False)
lock_update = lock_update_request.sync(
requirement_configuration=requirement_configuration,
pin=pin,
lock_config_updated=lock_file != original_lock_file,
)
if isinstance(lock_update, Result):
return lock_update
Expand Down
36 changes: 9 additions & 27 deletions pex/resolve/lockfile/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,10 +350,10 @@ def iter_updated_requirements(self):
def _calculate_requirement_configuration(
self,
locked_resolve, # type: LockedResolve
pin_all=False, # type: bool
artifacts_can_change=False, # type: bool
):
# type: (...) -> Iterator[Optional[RequirementConfiguration]]
if not self.update_constraints_by_project_name and not pin_all:
if not self.update_constraints_by_project_name and not artifacts_can_change:
yield None
return

Expand Down Expand Up @@ -402,15 +402,14 @@ def update_resolve(
self,
locked_resolve, # type: LockedResolve
target, # type: Target
pin_all=False, # type: bool
artifacts_can_change=False, # type: bool
):
# type: (...) -> Union[ResolveUpdate, Error]

updated_resolve = locked_resolve
updated_requirements = self.original_requirements
with self._calculate_requirement_configuration(
locked_resolve, pin_all=pin_all
locked_resolve, artifacts_can_change=artifacts_can_change
) as requirement_configuration:
if requirement_configuration:
updated_lock_file = try_(
Expand Down Expand Up @@ -626,8 +625,6 @@ def sync(
self,
update_requests, # type: Iterable[ResolveUpdateRequest]
requirement_configuration, # type: RequirementConfiguration
pin=False, # type: bool
lock_config_updated=False, # type: bool
):
# type: (...) -> Union[LockUpdate, Error]

Expand All @@ -636,20 +633,6 @@ def sync(
self.pip_configuration.network_configuration
)
)
constraints = tuple(
requirement_configuration.parse_constraints(
self.pip_configuration.network_configuration
)
)
if not any((pin, lock_config_updated, requirements, constraints)):
return LockUpdate(
requirements=self.lock_file.requirements,
resolves=tuple(
ResolveUpdate(updated_resolve=update_request.locked_resolve)
for update_request in update_requests
),
)

resolve_updater = try_(
ResolveUpdater.derived(
requirement_configuration=requirement_configuration,
Expand All @@ -662,8 +645,7 @@ def sync(
return self._perform_update(
update_requests=update_requests,
resolve_updater=resolve_updater,
pin=pin,
artifacts_can_change=lock_config_updated,
artifacts_can_change=True,
)

def update(
Expand All @@ -672,11 +654,11 @@ def update(
updates=(), # type: Iterable[Requirement]
replacements=(), # type: Iterable[Requirement]
deletes=(), # type: Iterable[ProjectName]
pin=False, # type: bool
artifacts_can_change=False, # type: bool
):
# type: (...) -> Union[LockUpdate, Error]

if not any((pin, updates, replacements, deletes)):
if not any((artifacts_can_change, updates, replacements, deletes)):
return LockUpdate(
requirements=self.lock_file.requirements,
resolves=tuple(
Expand All @@ -694,14 +676,15 @@ def update(
pip_configuration=self.pip_configuration,
)
return self._perform_update(
update_requests=update_requests, resolve_updater=resolve_updater, pin=pin
update_requests=update_requests,
resolve_updater=resolve_updater,
artifacts_can_change=artifacts_can_change,
)

def _perform_update(
self,
update_requests, # type: Iterable[ResolveUpdateRequest]
resolve_updater, # type: ResolveUpdater
pin=False, # type: bool
artifacts_can_change=False, # type: bool
):
# type: (...) -> Union[LockUpdate, Error]
Expand All @@ -722,7 +705,6 @@ def _perform_update(
resolve_updater.update_resolve,
locked_resolve=update_request.locked_resolve,
target=update_request.target,
pin_all=pin,
artifacts_can_change=artifacts_can_change,
)
if isinstance(result, Error):
Expand Down
Loading

0 comments on commit ac4f090

Please sign in to comment.