Skip to content

Commit 56ae935

Browse files
jsiroiskaos
andauthored
Implement pex3 lock sync. (#2373)
Introduce the high level `pex3 lock sync` command. This should generally suffice for typical use cases and works as follows: + On first use (where the specified `--lock` does not yet exist), it acts just like `pex3 lock create`. + On subsequent uses it does a minimal synchronization of the lock based on the diff of the given current requirements against the requirements used to generate the specified `--lock`. This amounts to formulating a `pex3 lock update` command with the appropriate `-p`, `-R` and `-d` arguments. In addition to creating and syncing a lock, it can also create and sync a venv (--venv) based on the lock. Further, a command can be specified to run in the synchronized venv with arguments following the `--` option terminator. This latter set of features allow Pex to act as a concise tool in `tox` / `nox` / `invoke` / `make` setups to implement a simple build system. Fixes #2344 --------- Co-authored-by: Andreas Stenius <[email protected]>
1 parent 70b6d47 commit 56ae935

23 files changed

+2628
-337
lines changed

pex/cli/command.py

+27-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from contextlib import contextmanager
99

1010
from pex.commands.command import Command
11-
from pex.result import Result
11+
from pex.result import Error, Result
1212
from pex.typing import TYPE_CHECKING, Generic, cast
1313

1414
if TYPE_CHECKING:
@@ -35,11 +35,23 @@ def parser(
3535
help, # type: str
3636
func=None, # type: Optional[Callable[[_C], Result]]
3737
include_verbosity=None, # type: Optional[bool]
38+
passthrough_args=None, # type: Optional[str]
3839
):
3940
# type: (...) -> Iterator[ArgumentParser]
4041
subcommand_parser = self._subparsers.add_parser(name=name, help=help)
4142
yield subcommand_parser
4243
if func:
44+
if passthrough_args:
45+
# N.B.: This is a dummy arg for usage string display purposes; thus the "_" name.
46+
subcommand_parser.add_argument(
47+
"_", metavar="-- passthrough args", nargs="*", help=passthrough_args
48+
)
49+
else:
50+
func = functools.partial(
51+
BuildTimeCommand._check_no_passthrough_args_and_run,
52+
subcommand_name=name,
53+
subcommand_func=func,
54+
)
4355
subcommand_parser.set_defaults(subcommand_func=func)
4456
Command.register_global_arguments(
4557
subcommand_parser,
@@ -75,6 +87,20 @@ def create_subcommands(
7587
subparsers = parser.add_subparsers(description=description)
7688
return cls.Subcommands(subparsers, include_verbosity=cls.include_global_verbosity_option)
7789

90+
def _check_no_passthrough_args_and_run(
91+
self,
92+
subcommand_name, # type: str
93+
subcommand_func, # type: Callable[[BuildTimeCommand], Result]
94+
):
95+
# type: (...) -> Result
96+
if self.passthrough_args is not None:
97+
return Error(
98+
"The {subcommand} {command} subcommand does not accept pass through args.".format(
99+
subcommand=subcommand_name, command=self.name()
100+
)
101+
)
102+
return subcommand_func(self)
103+
78104
def run(self):
79105
# type: (_C) -> Result
80106
subcommand_func = cast(

0 commit comments

Comments
 (0)