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

Support installing and uninstalling on Fish shell #1536

Merged
merged 18 commits into from
Nov 18, 2019
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Added a `env use` command to control the Python version used by the project.
- Added a `env list` command to list the virtualenvs associated with the current project.
- Added a `env remove` command to delete virtualenvs associated with the current project.
- Added support for `POETRY_HOME` declaration within `get-poetry.py`.
- Added support for declaring a specific source for dependencies.
- Added support for disabling PyPI and making another repository the default one.
- Added support for declaring private repositories as secondary.
Expand Down
22 changes: 14 additions & 8 deletions docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ python get-poetry.py --uninstall
POETRY_UNINSTALL=1 python get-poetry.py
```

By default, Poetry is installed into the user's platform-specific home directory. If you wish to change this, you may define the `POETRY_HOME` environment variable:

```bash
POETRY_HOME=/etc/poetry python get-poetry.py
```

If you want to install prerelease versions, you can do so by passing `--preview` to `get-poetry.py`
or by using the `POETRY_PREVIEW` environment variable:

Expand Down Expand Up @@ -111,28 +117,28 @@ pipx uninstall poetry

## Updating `poetry`

Updating poetry to the latest stable version is as simple as calling the `self:update` command.
Updating Poetry to the latest stable version is as simple as calling the `self update` command.

```bash
poetry self:update
poetry self update
```

If you want to install prerelease versions, you can use the `--preview` option.
If you want to install pre-release versions, you can use the `--preview` option.

```bash
poetry self:update --preview
poetry self update --preview
```

And finally, if you want to install a specific version you can pass it as an argument
to `self:update`.
And finally, if you want to install a specific version, you can pass it as an argument
to `self update`.

```bash
poetry self:update 0.8.0
poetry self update 0.8.0
```

!!!note

The `self:update` command will only work if you used the recommended
The `self update` command will only work if you used the recommended
installer to install Poetry.


Expand Down
89 changes: 83 additions & 6 deletions get-poetry.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
This script will install poetry and its dependencies
This script will install Poetry and its dependencies
in isolation from the rest of the system.

It does, in order:
Expand Down Expand Up @@ -65,6 +65,7 @@
except NameError:
u = str

SHELL = os.getenv("SHELL", "")
WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt")


Expand Down Expand Up @@ -189,7 +190,7 @@ def expanduser(path):


HOME = expanduser("~")
POETRY_HOME = os.path.join(HOME, ".poetry")
POETRY_HOME = os.environ.get("POETRY_HOME") or os.path.join(HOME, ".poetry")
POETRY_BIN = os.path.join(POETRY_HOME, "bin")
POETRY_ENV = os.path.join(POETRY_HOME, "env")
POETRY_LIB = os.path.join(POETRY_HOME, "lib")
Expand Down Expand Up @@ -249,6 +250,9 @@ def expanduser(path):
{rcfiles}"""


PRE_MESSAGE_FISH = """This path will then be added to your `PATH` environment variable by
modifying the `fish_user_paths` universal variable."""

PRE_MESSAGE_WINDOWS = """This path will then be added to your `PATH` environment variable by
modifying the `HKEY_CURRENT_USER/Environment/PATH` registry key."""

Expand All @@ -264,6 +268,12 @@ def expanduser(path):
To configure your current shell run `source {poetry_home_env}`
"""

POST_MESSAGE_FISH = """{poetry} ({version}) is installed now. Great!

{poetry}'s bin directory ({poetry_home_bin}) has been added to your `PATH`
environment variable by modifying the `fish_user_paths` universal variable.
"""

POST_MESSAGE_WINDOWS = """{poetry} ({version}) is installed now. Great!

To get started you need Poetry's bin directory ({poetry_home_bin}) in your `PATH`
Expand All @@ -279,6 +289,15 @@ def expanduser(path):
To configure your current shell run `source {poetry_home_env}`
"""

POST_MESSAGE_FISH_NO_MODIFY_PATH = """{poetry} ({version}) is installed now. Great!

To get started you need {poetry}'s bin directory ({poetry_home_bin})
in your `PATH` environment variable, which you can add by running
the following command:

set -U fish_user_paths {poetry_home_bin} $fish_user_paths
"""

POST_MESSAGE_WINDOWS_NO_MODIFY_PATH = """{poetry} ({version}) is installed now. Great!

To get started you need Poetry's bin directory ({poetry_home_bin}) in your `PATH`
Expand Down Expand Up @@ -605,6 +624,9 @@ def update_path(self):
if not self._modify_path:
return

if "fish" in SHELL:
return self.add_to_fish_path()

if WINDOWS:
return self.add_to_windows_path()

Expand All @@ -625,6 +647,40 @@ def update_path(self):
with open(profile, "a") as f:
f.write(u(addition))

def add_to_fish_path(self):
"""
Ensure POETRY_BIN directory is on Fish shell $PATH
"""
current_path = os.environ.get("PATH", None)
if current_path is None:
print(
colorize(
"warning",
"\nUnable to get the PATH value. It will not be updated automatically.",
)
)
self._modify_path = False

return

if POETRY_BIN not in current_path:
fish_user_paths = subprocess.check_output(
["fish", "-c", "echo $fish_user_paths"]
).decode("utf-8")
if POETRY_BIN not in fish_user_paths:
cmd = "set -U fish_user_paths {} $fish_user_paths".format(POETRY_BIN)
set_fish_user_path = ["fish", "-c", "{}".format(cmd)]
subprocess.check_output(set_fish_user_path)
else:
print(
colorize(
"warning",
"\nPATH already contains {} and thus was not modified.".format(
POETRY_BIN
),
)
)

def add_to_windows_path(self):
try:
old_path = self.get_windows_path_var()
Expand Down Expand Up @@ -685,11 +741,25 @@ def set_windows_path_var(self, value):
)

def remove_from_path(self):
if WINDOWS:
if "fish" in SHELL:
return self.remove_from_fish_path()

elif WINDOWS:
return self.remove_from_windows_path()

return self.remove_from_unix_path()

def remove_from_fish_path(self):
fish_user_paths = subprocess.check_output(
["fish", "-c", "echo $fish_user_paths"]
).decode("utf-8")
if POETRY_BIN in fish_user_paths:
cmd = "set -U fish_user_paths (string match -v {} $fish_user_paths)".format(
POETRY_BIN
)
set_fish_user_path = ["fish", "-c", "{}".format(cmd)]
subprocess.check_output(set_fish_user_path)

def remove_from_windows_path(self):
path = self.get_windows_path_var()

Expand Down Expand Up @@ -741,8 +811,7 @@ def get_export_string(self):
def get_unix_profiles(self):
profiles = [os.path.join(HOME, ".profile")]

shell = os.getenv("SHELL", "")
if "zsh" in shell:
if "zsh" in SHELL:
zdotdir = os.getenv("ZDOTDIR", HOME)
profiles.append(os.path.join(zdotdir, ".zprofile"))

Expand All @@ -766,7 +835,9 @@ def display_pre_message(self):
if not self._modify_path:
kwargs["platform_msg"] = PRE_MESSAGE_NO_MODIFY_PATH
else:
if WINDOWS:
if "fish" in SHELL:
kwargs["platform_msg"] = PRE_MESSAGE_FISH
elif WINDOWS:
kwargs["platform_msg"] = PRE_MESSAGE_WINDOWS
else:
profiles = [
Expand Down Expand Up @@ -809,6 +880,12 @@ def display_post_message(self, version):
poetry_home_bin = POETRY_BIN.replace(
os.getenv("USERPROFILE", ""), "%USERPROFILE%"
)
elif "fish" in SHELL:
message = POST_MESSAGE_FISH
if not self._modify_path:
message = POST_MESSAGE_FISH_NO_MODIFY_PATH

poetry_home_bin = POETRY_BIN.replace(os.getenv("HOME", ""), "$HOME")
else:
message = POST_MESSAGE_UNIX
if not self._modify_path:
Expand Down
31 changes: 6 additions & 25 deletions poetry/installation/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from clikit.api.io import IO
from clikit.io import NullIO

from poetry.packages import Dependency
from poetry.packages import Locker
from poetry.packages import Package
from poetry.puzzle import Solver
Expand All @@ -16,6 +15,7 @@
from poetry.repositories import Repository
from poetry.repositories.installed_repository import InstalledRepository
from poetry.semver import parse_constraint
from poetry.utils.extras import get_extra_package_names
from poetry.utils.helpers import canonicalize_name

from .base_installer import BaseInstaller
Expand Down Expand Up @@ -399,7 +399,7 @@ def _get_operations_from_lock(
installed_repo = self._installed_repository
ops = []

extra_packages = [p.name for p in self._get_extra_packages(locked_repository)]
extra_packages = self._get_extra_packages(locked_repository)
for locked in locked_repository.packages:
is_installed = False
for installed in installed_repo.packages:
Expand Down Expand Up @@ -429,7 +429,7 @@ def _get_operations_from_lock(
def _filter_operations(
self, ops, repo
): # type: (List[Operation], Repository) -> None
extra_packages = [p.name for p in self._get_extra_packages(repo)]
extra_packages = self._get_extra_packages(repo)
for op in ops:
if isinstance(op, Update):
package = op.target_package
Expand Down Expand Up @@ -468,9 +468,9 @@ def _filter_operations(
if package.category == "dev" and not self.is_dev_mode():
op.skip("Dev dependencies not requested")

def _get_extra_packages(self, repo):
def _get_extra_packages(self, repo): # type: (Repository) -> List[str]
"""
Returns all packages required by extras.
Returns all package names required by extras.

Maybe we just let the solver handle it?
"""
Expand All @@ -479,26 +479,7 @@ def _get_extra_packages(self, repo):
else:
extras = self._locker.lock_data.get("extras", {})

extra_packages = []
for extra_name, packages in extras.items():
if extra_name not in self._extras:
continue

extra_packages += [Dependency(p, "*") for p in packages]

def _extra_packages(packages):
pkgs = []
for package in packages:
for pkg in repo.packages:
if pkg.name == package.name:
pkgs.append(package)
pkgs += _extra_packages(pkg.requires)

break

return pkgs

return _extra_packages(extra_packages)
return list(get_extra_package_names(repo.packages, extras, self._extras))

def _get_installer(self): # type: () -> BaseInstaller
return PipInstaller(self._env, self._io, self._pool)
Expand Down
14 changes: 11 additions & 3 deletions poetry/masonry/builders/builder.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
import os
import re
import shutil
import tempfile
Expand Down Expand Up @@ -34,7 +33,6 @@


class Builder(object):

AVAILABLE_PYTHONS = {"2", "2.7", "3", "3.4", "3.5", "3.6", "3.7"}

format = None
Expand Down Expand Up @@ -86,8 +84,18 @@ def find_excluded_files(self): # type: () -> Set[str]

explicitely_excluded = set()
for excluded_glob in self._package.exclude:
excluded_path = Path(self._path, excluded_glob)

try:
is_dir = excluded_path.is_dir()
except OSError:
# On Windows, testing if a path with a glob is a directory will raise an OSError
is_dir = False
if is_dir:
excluded_glob = Path(excluded_glob, "**/*")

for excluded in glob(
os.path.join(self._path.as_posix(), str(excluded_glob)), recursive=True
Path(self._path, excluded_glob).as_posix(), recursive=True
):
explicitely_excluded.add(
Path(excluded).relative_to(self._path).as_posix()
Expand Down
7 changes: 1 addition & 6 deletions poetry/masonry/builders/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

from base64 import urlsafe_b64encode
from io import StringIO
from typing import Set

from clikit.api.io.flags import VERY_VERBOSE

Expand Down Expand Up @@ -154,7 +153,7 @@ def _copy_module(self, wheel):
else:
rel_file = file.relative_to(self._path)

if file in excluded:
if rel_file.as_posix() in excluded:
continue

if file.suffix == ".pyc":
Expand Down Expand Up @@ -200,10 +199,6 @@ def _write_record(self, wheel):
# RECORD itself is recorded with no hash or size
f.write(self.dist_info + "/RECORD,,\n")

def find_excluded_files(self): # type: () -> Set
# Checking VCS
return set()

@property
def dist_info(self): # type: () -> str
return self.dist_info_name(self._package.name, self._meta.version)
Expand Down
Loading