Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve package operations management #4336

Merged
merged 1 commit into from
Jul 31, 2021
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: 16 additions & 6 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,19 @@ The `--dev-only` option is now deprecated. You should use the `--only dev` notat
See [Dependency groups]({{< relref "managing-dependencies#dependency-groups" >}}) for more information
about dependency groups.

If you want to remove old dependencies no longer present in the lock file, use the
`--remove-untracked` option.
If you want to synchronize your environment – and ensure it matches the lock file use the
`--sync` option.

```bash
poetry install --remove-untracked
poetry install --sync
```

The `--sync` can be combined with group-related options:

```bash
poetry install --without dev --sync
poetry install --with docs --sync
poetry install --only dev
```

You can also specify the extras you want installed
Expand Down Expand Up @@ -204,12 +212,14 @@ option is used.
* `--with`: The optional dependency groups to include for installation.
* `--only`: The only dependency groups to install.
* `--default`: Only install the default dependencies.
* `--no-dev`: Do not install dev dependencies. (**Deprecated**)
* `--dev-only`: Only install dev dependencies. (**Deprecated**)
* `--sync`: Synchronize the environment with the locked packages and the specified groups.
* `--no-root`: Do not install the root package (your project).
* `--dry-run`: Output the operations but do not execute anything (implicitly enables --verbose).
* `--remove-untracked`: Remove dependencies not presented in the lock file
* `--extras (-E)`: Features to install (multiple values allowed).
* `--no-dev`: Do not install dev dependencies. (**Deprecated**)
* `--dev-only`: Only install dev dependencies. (**Deprecated**)
* `--remove-untracked`: Remove dependencies not presented in the lock file. (**Deprecated**)


## update

Expand Down
26 changes: 26 additions & 0 deletions docs/managing-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,29 @@ to remove packages from a specific group:
```bash
poetry remove mkdocs --group docs
```


## Synchronizing dependencies

Poetry supports what's called dependency synchronization. What this does is ensuring
that the locked dependencies in the `poetry.lock` file are the only ones present
in the environment, removing anything that's not necessary.

This is done by using the `--sync` option of the `install` command:

```bash
poetry install --sync
```

The `--sync` option can be combined with any [dependency groups]({{< relref "#dependency-groups" >}}) related options
to synchronize the environment with specific groups.

```bash
poetry install --without dev --sync
poetry install --with docs --sync
poetry install --only dev
```

{{% note %}}
The `--sync` option replaces the `--remove-untracked` option which is now deprecated.
{{% /note %}}
4 changes: 2 additions & 2 deletions poetry/console/commands/debug/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def handle(self) -> Optional[int]:

solver = Solver(package, pool, Repository(), Repository(), self._io)

ops = solver.solve()
ops = solver.solve().calculate_operations()

self.line("")
self.line("Resolution results:")
Expand Down Expand Up @@ -123,7 +123,7 @@ def handle(self) -> Optional[int]:

solver = Solver(package, pool, Repository(), Repository(), NullIO())
with solver.use_environment(env):
ops = solver.solve()
ops = solver.solve().calculate_operations()

for op in ops:
if self.option("install") and op.skipped:
Expand Down
16 changes: 15 additions & 1 deletion poetry/console/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ class InstallCommand(InstallerCommand):
None,
"Only install the development dependencies. (<warning>Deprecated</warning>)",
),
option(
"sync",
None,
"Synchronize the environment with the locked packages and the specified groups.",
),
option(
"no-root", None, "Do not install the root package (the current project)."
),
Expand Down Expand Up @@ -138,11 +143,20 @@ def handle(self) -> int:
if self.option("default"):
only_groups.append("default")

with_synchronization = self.option("sync")
if self.option("remove-untracked"):
self.line(
"<warning>The `<fg=yellow;options=bold>--remove-untracked</>` option is deprecated,"
"use the `<fg=yellow;options=bold>--sync</>` option instead.</warning>"
)

with_synchronization = True

self._installer.only_groups(only_groups)
self._installer.without_groups(excluded_groups)
self._installer.with_groups(included_groups)
self._installer.dry_run(self.option("dry-run"))
self._installer.remove_untracked(self.option("remove-untracked"))
self._installer.requires_synchronization(with_synchronization)
self._installer.verbose(self._io.is_verbose())

return_code = self._installer.run()
Expand Down
2 changes: 1 addition & 1 deletion poetry/console/commands/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def handle(self) -> Optional[int]:
)
solver.provider.load_deferred(False)
with solver.use_environment(self.env):
ops = solver.solve()
ops = solver.solve().calculate_operations()

required_locked_packages = set([op.package for op in ops if not op.skipped])

Expand Down
46 changes: 30 additions & 16 deletions poetry/installation/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def __init__(
self._pool = pool

self._dry_run = False
self._remove_untracked = False
self._requires_synchronization = False
self._update = False
self._verbose = False
self._write_lock = True
Expand Down Expand Up @@ -122,14 +122,13 @@ def dry_run(self, dry_run: bool = True) -> "Installer":
def is_dry_run(self) -> bool:
return self._dry_run

def remove_untracked(self, remove_untracked: bool = True) -> "Installer":
self._remove_untracked = remove_untracked
def requires_synchronization(
self, requires_synchronization: bool = True
) -> "Installer":
self._requires_synchronization = requires_synchronization

return self

def is_remove_untracked(self) -> bool:
return self._remove_untracked

def verbose(self, verbose: bool = True) -> "Installer":
self._verbose = verbose
self._executor.verbose(verbose)
Expand Down Expand Up @@ -212,7 +211,7 @@ def _do_refresh(self) -> int:
self._io,
)

ops = solver.solve(use_latest=[])
ops = solver.solve(use_latest=[]).calculate_operations()

local_repo = Repository()
self._populate_local_repo(local_repo, ops)
Expand Down Expand Up @@ -247,10 +246,9 @@ def _do_install(self, local_repo: Repository) -> int:
self._installed_repository,
locked_repository,
self._io,
remove_untracked=self._remove_untracked,
)

ops = solver.solve(use_latest=self._whitelist)
ops = solver.solve(use_latest=self._whitelist).calculate_operations()
else:
self._io.write_line("<info>Installing dependencies from lock file</>")

Expand Down Expand Up @@ -318,19 +316,35 @@ def _do_install(self, local_repo: Repository) -> int:
pool.add_repository(repo)

solver = Solver(
root,
pool,
self._installed_repository,
locked_repository,
NullIO(),
remove_untracked=self._remove_untracked,
root, pool, self._installed_repository, locked_repository, NullIO()
)
# Everything is resolved at this point, so we no longer need
# to load deferred dependencies (i.e. VCS, URL and path dependencies)
solver.provider.load_deferred(False)

with solver.use_environment(self._env):
ops = solver.solve(use_latest=self._whitelist)
ops = solver.solve(use_latest=self._whitelist).calculate_operations(
with_uninstalls=self._requires_synchronization,
synchronize=self._requires_synchronization,
)

if not self._requires_synchronization:
# If no packages synchronisation has been requested we need
# to calculate the uninstall operations
from poetry.puzzle.transaction import Transaction

transaction = Transaction(
locked_repository.packages,
[(package, 0) for package in local_repo.packages],
installed_packages=self._installed_repository.packages,
root_package=root,
)

ops = [
op
for op in transaction.calculate_operations(with_uninstalls=True)
if op.job_type == "uninstall"
] + ops

# We need to filter operations so that packages
# not compatible with the current system,
Expand Down
Loading