Replace binaries and installer scripts with nix config
This commit is contained in:
parent
6419a175bd
commit
531b40f483
20
Makefile
20
Makefile
|
@ -12,9 +12,9 @@ THEMES_TARGETS := $(THEMES_ITEMS:themes/%=$(THEMES_DIR)/%)
|
||||||
LAZY_REPO := https://github.com/folke/lazy.nvim.git
|
LAZY_REPO := https://github.com/folke/lazy.nvim.git
|
||||||
PYENV_DIR := $(if $(PYENV_ROOT), $(PYENV_ROOT), $(HOME)/.pyenv)
|
PYENV_DIR := $(if $(PYENV_ROOT), $(PYENV_ROOT), $(HOME)/.pyenv)
|
||||||
|
|
||||||
.PHONY: default all clean check directories link configure install
|
.PHONY: default all clean check directories link install
|
||||||
|
|
||||||
default: directories link configure
|
default: directories link
|
||||||
|
|
||||||
all: default install
|
all: default install
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ clean:
|
||||||
rm $(HOME)/.bashrc
|
rm $(HOME)/.bashrc
|
||||||
rm $(HOME)/.zshrc
|
rm $(HOME)/.zshrc
|
||||||
rmdir $(HOME)/.ssh/sockets
|
rmdir $(HOME)/.ssh/sockets
|
||||||
rm -rf config/nvim/.venv
|
|
||||||
|
|
||||||
check:
|
check:
|
||||||
echo "Placeholder"
|
echo "Placeholder"
|
||||||
|
@ -50,22 +49,7 @@ $(HOME)/.zshrc: $(HOME)/%: %
|
||||||
$(CONFIG_TARGETS) $(SSH_TARGETS) $(THEMES_TARGETS) $(HOME)/.profile $(HOME)/.inputrc $(HOME)/.bashrc $(HOME)/.zshrc:
|
$(CONFIG_TARGETS) $(SSH_TARGETS) $(THEMES_TARGETS) $(HOME)/.profile $(HOME)/.inputrc $(HOME)/.bashrc $(HOME)/.zshrc:
|
||||||
ln -s $(PWD)/$? $@
|
ln -s $(PWD)/$? $@
|
||||||
|
|
||||||
configure: config/git/user_email config/nvim/.venv
|
|
||||||
|
|
||||||
config/git/user_email:
|
|
||||||
echo "Missing user_email; Add your email to $$(readlink -f config/git)/user_email"
|
|
||||||
|
|
||||||
config/nvim/.venv:
|
|
||||||
python3 -m venv $@
|
|
||||||
$@/bin/python3 -m pip install -U pip wheel
|
|
||||||
$@/bin/python3 -m pip install --use-pep517 pynvim
|
|
||||||
|
|
||||||
install: $(LAZY_DIR)
|
install: $(LAZY_DIR)
|
||||||
command -v direnv > /dev/null || bin_path=$(HOME)/.local/bin bash packages/direnv.sh
|
|
||||||
command -v pipx > /dev/null || bash packages/pipx.sh
|
|
||||||
command -v poetry > /dev/null || python3 packages/poetry.py
|
|
||||||
command -v pyenv > /dev/null || bash packages/pyenv.sh
|
|
||||||
command -v starship > /dev/null || sh packages/starship.sh -b $(HOME)/.local/bin
|
|
||||||
|
|
||||||
$(LAZY_DIR):
|
$(LAZY_DIR):
|
||||||
git clone --depth 1 $(LAZY_REPO) $@
|
git clone --depth 1 $(LAZY_REPO) $@
|
||||||
|
|
BIN
bin/lazygit
BIN
bin/lazygit
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
source .venv/bin/activate
|
|
|
@ -7,7 +7,8 @@
|
||||||
|
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
git
|
git
|
||||||
lazygit
|
|
||||||
gcc
|
gcc
|
||||||
|
lazygit
|
||||||
|
direnv
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
neovim
|
neovim
|
||||||
python310Packages.pynvim
|
python310Packages.pynvim
|
||||||
fzf
|
fzf
|
||||||
|
ripgrep
|
||||||
cargo
|
cargo
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
13
nixos/home/python310.nix
Normal file
13
nixos/home/python310.nix
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./dev.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
python310Full
|
||||||
|
python310Packages.pipx
|
||||||
|
poetry
|
||||||
|
];
|
||||||
|
}
|
38
nixos/vanguard-xenia-home.nix
Normal file
38
nixos/vanguard-xenia-home.nix
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
home-manager = builtins.fetchTarball "https://github.com/nix-community/home-manager/archive/master.tar.gz";
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(import "${home-manager}/nixos")
|
||||||
|
];
|
||||||
|
|
||||||
|
home-manager.users.xenia = { pkgs, ... }: {
|
||||||
|
imports = [
|
||||||
|
./home/common.nix
|
||||||
|
./home/dev.nix
|
||||||
|
./home/python310.nix
|
||||||
|
];
|
||||||
|
# Home Manager needs a bit of information about you and the
|
||||||
|
# paths it should manage.
|
||||||
|
home.username = "xenia";
|
||||||
|
home.homeDirectory = "/home/xenia";
|
||||||
|
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
firefox
|
||||||
|
bitwarden
|
||||||
|
];
|
||||||
|
|
||||||
|
programs.git = {
|
||||||
|
enable = true;
|
||||||
|
userName = "Evie Litherland-Smith";
|
||||||
|
userEmail = "evie@xenia.me.uk";
|
||||||
|
};
|
||||||
|
home.stateVersion = "22.11";
|
||||||
|
|
||||||
|
};
|
||||||
|
home-manager.useUserPackages = true;
|
||||||
|
home-manager.useGlobalPkgs = true;
|
||||||
|
}
|
|
@ -1,15 +1,10 @@
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
let
|
|
||||||
home-manager = builtins.fetchTarball "https://github.com/nix-community/home-manager/archive/master.tar.gz";
|
|
||||||
in
|
|
||||||
|
|
||||||
{
|
{
|
||||||
imports =
|
imports = [
|
||||||
[
|
|
||||||
./common.nix
|
./common.nix
|
||||||
./packages.nix
|
./packages.nix
|
||||||
(import "${home-manager}/nixos")
|
./vanguard-xenia-home.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
networking.hostName = "Vanguard"; # Define your hostname.
|
networking.hostName = "Vanguard"; # Define your hostname.
|
||||||
|
@ -73,32 +68,6 @@ in
|
||||||
extraGroups = [ "networkmanager" "wheel" ];
|
extraGroups = [ "networkmanager" "wheel" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
home-manager.users.xenia = { pkgs, ... }: {
|
|
||||||
imports = [
|
|
||||||
./home/common.nix
|
|
||||||
./home/dev.nix
|
|
||||||
];
|
|
||||||
# Home Manager needs a bit of information about you and the
|
|
||||||
# paths it should manage.
|
|
||||||
home.username = "xenia";
|
|
||||||
home.homeDirectory = "/home/xenia";
|
|
||||||
|
|
||||||
home.packages = with pkgs; [
|
|
||||||
firefox
|
|
||||||
bitwarden
|
|
||||||
];
|
|
||||||
|
|
||||||
programs.git = {
|
|
||||||
enable = true;
|
|
||||||
userName = "Evie Litherland-Smith";
|
|
||||||
userEmail = "evie@xenia.me.uk";
|
|
||||||
};
|
|
||||||
home.stateVersion = "22.11";
|
|
||||||
|
|
||||||
};
|
|
||||||
home-manager.useUserPackages = true;
|
|
||||||
home-manager.useGlobalPkgs = true;
|
|
||||||
|
|
||||||
# Enable automatic login for the user.
|
# Enable automatic login for the user.
|
||||||
services.xserver.displayManager.autoLogin.enable = true;
|
services.xserver.displayManager.autoLogin.enable = true;
|
||||||
services.xserver.displayManager.autoLogin.user = "xenia";
|
services.xserver.displayManager.autoLogin.user = "xenia";
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# A good old bash | curl script for direnv.
|
|
||||||
#
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
{ # Prevent execution if this script was only partially downloaded
|
|
||||||
|
|
||||||
log() {
|
|
||||||
echo "[installer] $*" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
die() {
|
|
||||||
log "$@"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
at_exit() {
|
|
||||||
ret=$?
|
|
||||||
if [[ $ret -gt 0 ]]; then
|
|
||||||
log "the script failed with error $ret.\n" \
|
|
||||||
"\n" \
|
|
||||||
"To report installation errors, submit an issue to\n" \
|
|
||||||
" https://github.com/direnv/direnv/issues/new/choose"
|
|
||||||
fi
|
|
||||||
exit "$ret"
|
|
||||||
}
|
|
||||||
trap at_exit EXIT
|
|
||||||
|
|
||||||
kernel=$(uname -s | tr "[:upper:]" "[:lower:]")
|
|
||||||
case "${kernel}" in
|
|
||||||
mingw*)
|
|
||||||
kernel=windows
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
case "$(uname -m)" in
|
|
||||||
x86_64)
|
|
||||||
machine=amd64
|
|
||||||
;;
|
|
||||||
i686 | i386)
|
|
||||||
machine=386
|
|
||||||
;;
|
|
||||||
aarch64 | arm64)
|
|
||||||
machine=arm64
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
die "Machine $(uname -m) not supported by the installer.\n" \
|
|
||||||
"Go to https://direnv for alternate installation methods."
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
log "kernel=$kernel machine=$machine"
|
|
||||||
|
|
||||||
: "${use_sudo:=}"
|
|
||||||
: "${bin_path:=}"
|
|
||||||
|
|
||||||
if [[ -z "$bin_path" ]]; then
|
|
||||||
log "bin_path is not set, you can set bin_path to specify the installation path"
|
|
||||||
log "e.g. export bin_path=/path/to/installation before installing"
|
|
||||||
log "looking for a writeable path from PATH environment variable"
|
|
||||||
for path in $(echo "$PATH" | tr ':' '\n'); do
|
|
||||||
if [[ -w $path ]]; then
|
|
||||||
bin_path=$path
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
if [[ -z "$bin_path" ]]; then
|
|
||||||
die "did not find a writeable path in $PATH"
|
|
||||||
fi
|
|
||||||
echo "bin_path=$bin_path"
|
|
||||||
|
|
||||||
if [[ -n "${version:-}" ]]; then
|
|
||||||
release="tags/${version}"
|
|
||||||
else
|
|
||||||
release="latest"
|
|
||||||
fi
|
|
||||||
echo "release=$release"
|
|
||||||
|
|
||||||
log "looking for a download URL"
|
|
||||||
download_url=$(
|
|
||||||
curl -fL "https://api.github.com/repos/direnv/direnv/releases/$release" \
|
|
||||||
| grep browser_download_url \
|
|
||||||
| cut -d '"' -f 4 \
|
|
||||||
| grep "direnv.$kernel.$machine"
|
|
||||||
)
|
|
||||||
echo "download_url=$download_url"
|
|
||||||
|
|
||||||
log "downloading"
|
|
||||||
curl -o "$bin_path/direnv" -fL "$download_url"
|
|
||||||
chmod a+x "$bin_path/direnv"
|
|
||||||
|
|
||||||
cat <<DONE
|
|
||||||
|
|
||||||
The direnv binary is now available in:
|
|
||||||
|
|
||||||
$bin_path/direnv
|
|
||||||
|
|
||||||
The last step is to configure your shell to use it. For example for bash, add
|
|
||||||
the following lines at the end of your ~/.bashrc:
|
|
||||||
|
|
||||||
eval "\$(direnv hook bash)"
|
|
||||||
|
|
||||||
Then restart the shell.
|
|
||||||
|
|
||||||
For other shells, see https://direnv.net/docs/hook.html
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
DONE
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
command -v python3 > /dev/null || {
|
|
||||||
echo "python3 executable not found, exiting"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
python3 -c "import sys; assert sys.version_info[0] >= 3 and sys.version_info[1] >= 7" || {
|
|
||||||
echo python3 --version
|
|
||||||
echo "python version too old, requires >=3.7"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
USERSITE=$(python3 -c "import site; print(site._get_path(site._getuserbase()))")
|
|
||||||
mkdir -p $USERSITE
|
|
||||||
|
|
||||||
if [[ ! -e "$USERSITE/pipx" ]]
|
|
||||||
then
|
|
||||||
python3 -m pip install --user pipx
|
|
||||||
fi
|
|
|
@ -1,940 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
r"""
|
|
||||||
This script will install Poetry and its dependencies in an isolated fashion.
|
|
||||||
|
|
||||||
It will perform the following steps:
|
|
||||||
* Create a new virtual environment using the built-in venv module, or the virtualenv zipapp if venv is unavailable.
|
|
||||||
This will be created at a platform-specific path (or `$POETRY_HOME` if `$POETRY_HOME` is set:
|
|
||||||
- `~/Library/Application Support/pypoetry` on macOS
|
|
||||||
- `$XDG_DATA_HOME/pypoetry` on Linux/Unix (`$XDG_DATA_HOME` is `~/.local/share` if unset)
|
|
||||||
- `%APPDATA%\pypoetry` on Windows
|
|
||||||
* Update pip inside the virtual environment to avoid bugs in older versions.
|
|
||||||
* Install the latest (or a given) version of Poetry inside this virtual environment using pip.
|
|
||||||
* Install a `poetry` script into a platform-specific path (or `$POETRY_HOME/bin` if `$POETRY_HOME` is set):
|
|
||||||
- `~/.local/bin` on Unix
|
|
||||||
- `%APPDATA%\Python\Scripts` on Windows
|
|
||||||
* Attempt to inform the user if they need to add this bin directory to their `$PATH`, as well as how to do so.
|
|
||||||
* Upon failure, write an error log to `poetry-installer-error-<hash>.log and restore any previous environment.
|
|
||||||
|
|
||||||
This script performs minimal magic, and should be relatively stable. However, it is optimized for interactive developer
|
|
||||||
use and trivial pipelines. If you are considering using this script in production, you should consider manually-managed
|
|
||||||
installs, or use of pipx as alternatives to executing arbitrary, unversioned code from the internet. If you prefer this
|
|
||||||
script to alternatives, consider maintaining a local copy as part of your infrastructure.
|
|
||||||
|
|
||||||
For full documentation, visit https://python-poetry.org/docs/#installation.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import sysconfig
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
from contextlib import closing
|
|
||||||
from contextlib import contextmanager
|
|
||||||
from functools import cmp_to_key
|
|
||||||
from io import UnsupportedOperation
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Optional
|
|
||||||
from urllib.request import Request
|
|
||||||
from urllib.request import urlopen
|
|
||||||
|
|
||||||
|
|
||||||
SHELL = os.getenv("SHELL", "")
|
|
||||||
WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt")
|
|
||||||
MINGW = sysconfig.get_platform().startswith("mingw")
|
|
||||||
MACOS = sys.platform == "darwin"
|
|
||||||
|
|
||||||
FOREGROUND_COLORS = {
|
|
||||||
"black": 30,
|
|
||||||
"red": 31,
|
|
||||||
"green": 32,
|
|
||||||
"yellow": 33,
|
|
||||||
"blue": 34,
|
|
||||||
"magenta": 35,
|
|
||||||
"cyan": 36,
|
|
||||||
"white": 37,
|
|
||||||
}
|
|
||||||
|
|
||||||
BACKGROUND_COLORS = {
|
|
||||||
"black": 40,
|
|
||||||
"red": 41,
|
|
||||||
"green": 42,
|
|
||||||
"yellow": 43,
|
|
||||||
"blue": 44,
|
|
||||||
"magenta": 45,
|
|
||||||
"cyan": 46,
|
|
||||||
"white": 47,
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTIONS = {"bold": 1, "underscore": 4, "blink": 5, "reverse": 7, "conceal": 8}
|
|
||||||
|
|
||||||
|
|
||||||
def style(fg, bg, options):
|
|
||||||
codes = []
|
|
||||||
|
|
||||||
if fg:
|
|
||||||
codes.append(FOREGROUND_COLORS[fg])
|
|
||||||
|
|
||||||
if bg:
|
|
||||||
codes.append(BACKGROUND_COLORS[bg])
|
|
||||||
|
|
||||||
if options:
|
|
||||||
if not isinstance(options, (list, tuple)):
|
|
||||||
options = [options]
|
|
||||||
|
|
||||||
for option in options:
|
|
||||||
codes.append(OPTIONS[option])
|
|
||||||
|
|
||||||
return "\033[{}m".format(";".join(map(str, codes)))
|
|
||||||
|
|
||||||
|
|
||||||
STYLES = {
|
|
||||||
"info": style("cyan", None, None),
|
|
||||||
"comment": style("yellow", None, None),
|
|
||||||
"success": style("green", None, None),
|
|
||||||
"error": style("red", None, None),
|
|
||||||
"warning": style("yellow", None, None),
|
|
||||||
"b": style(None, None, ("bold",)),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def is_decorated():
|
|
||||||
if WINDOWS:
|
|
||||||
return (
|
|
||||||
os.getenv("ANSICON") is not None
|
|
||||||
or "ON" == os.getenv("ConEmuANSI")
|
|
||||||
or "xterm" == os.getenv("Term")
|
|
||||||
)
|
|
||||||
|
|
||||||
if not hasattr(sys.stdout, "fileno"):
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
|
||||||
return os.isatty(sys.stdout.fileno())
|
|
||||||
except UnsupportedOperation:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def is_interactive():
|
|
||||||
if not hasattr(sys.stdin, "fileno"):
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
|
||||||
return os.isatty(sys.stdin.fileno())
|
|
||||||
except UnsupportedOperation:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def colorize(style, text):
|
|
||||||
if not is_decorated():
|
|
||||||
return text
|
|
||||||
|
|
||||||
return f"{STYLES[style]}{text}\033[0m"
|
|
||||||
|
|
||||||
|
|
||||||
def string_to_bool(value):
|
|
||||||
value = value.lower()
|
|
||||||
|
|
||||||
return value in {"true", "1", "y", "yes"}
|
|
||||||
|
|
||||||
|
|
||||||
def data_dir() -> Path:
|
|
||||||
if os.getenv("POETRY_HOME"):
|
|
||||||
return Path(os.getenv("POETRY_HOME")).expanduser()
|
|
||||||
|
|
||||||
if WINDOWS:
|
|
||||||
base_dir = Path(_get_win_folder("CSIDL_APPDATA"))
|
|
||||||
elif MACOS:
|
|
||||||
base_dir = Path("~/Library/Application Support").expanduser()
|
|
||||||
else:
|
|
||||||
base_dir = Path(os.getenv("XDG_DATA_HOME", "~/.local/share")).expanduser()
|
|
||||||
|
|
||||||
base_dir = base_dir.resolve()
|
|
||||||
return base_dir / "pypoetry"
|
|
||||||
|
|
||||||
|
|
||||||
def bin_dir() -> Path:
|
|
||||||
if os.getenv("POETRY_HOME"):
|
|
||||||
return Path(os.getenv("POETRY_HOME")).expanduser() / "bin"
|
|
||||||
|
|
||||||
if WINDOWS and not MINGW:
|
|
||||||
return Path(_get_win_folder("CSIDL_APPDATA")) / "Python/Scripts"
|
|
||||||
else:
|
|
||||||
return Path("~/.local/bin").expanduser()
|
|
||||||
|
|
||||||
|
|
||||||
def _get_win_folder_from_registry(csidl_name):
|
|
||||||
import winreg as _winreg
|
|
||||||
|
|
||||||
shell_folder_name = {
|
|
||||||
"CSIDL_APPDATA": "AppData",
|
|
||||||
"CSIDL_COMMON_APPDATA": "Common AppData",
|
|
||||||
"CSIDL_LOCAL_APPDATA": "Local AppData",
|
|
||||||
}[csidl_name]
|
|
||||||
|
|
||||||
key = _winreg.OpenKey(
|
|
||||||
_winreg.HKEY_CURRENT_USER,
|
|
||||||
r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders",
|
|
||||||
)
|
|
||||||
path, _ = _winreg.QueryValueEx(key, shell_folder_name)
|
|
||||||
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def _get_win_folder_with_ctypes(csidl_name):
|
|
||||||
import ctypes
|
|
||||||
|
|
||||||
csidl_const = {
|
|
||||||
"CSIDL_APPDATA": 26,
|
|
||||||
"CSIDL_COMMON_APPDATA": 35,
|
|
||||||
"CSIDL_LOCAL_APPDATA": 28,
|
|
||||||
}[csidl_name]
|
|
||||||
|
|
||||||
buf = ctypes.create_unicode_buffer(1024)
|
|
||||||
ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
|
|
||||||
|
|
||||||
# Downgrade to short path name if have highbit chars. See
|
|
||||||
# <http://bugs.activestate.com/show_bug.cgi?id=85099>.
|
|
||||||
has_high_char = False
|
|
||||||
for c in buf:
|
|
||||||
if ord(c) > 255:
|
|
||||||
has_high_char = True
|
|
||||||
break
|
|
||||||
if has_high_char:
|
|
||||||
buf2 = ctypes.create_unicode_buffer(1024)
|
|
||||||
if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
|
|
||||||
buf = buf2
|
|
||||||
|
|
||||||
return buf.value
|
|
||||||
|
|
||||||
|
|
||||||
if WINDOWS:
|
|
||||||
try:
|
|
||||||
from ctypes import windll # noqa: F401
|
|
||||||
|
|
||||||
_get_win_folder = _get_win_folder_with_ctypes
|
|
||||||
except ImportError:
|
|
||||||
_get_win_folder = _get_win_folder_from_registry
|
|
||||||
|
|
||||||
|
|
||||||
PRE_MESSAGE = """# Welcome to {poetry}!
|
|
||||||
|
|
||||||
This will download and install the latest version of {poetry},
|
|
||||||
a dependency and package manager for Python.
|
|
||||||
|
|
||||||
It will add the `poetry` command to {poetry}'s bin directory, located at:
|
|
||||||
|
|
||||||
{poetry_home_bin}
|
|
||||||
|
|
||||||
You can uninstall at any time by executing this script with the --uninstall option,
|
|
||||||
and these changes will be reverted.
|
|
||||||
"""
|
|
||||||
|
|
||||||
POST_MESSAGE = """{poetry} ({version}) is installed now. Great!
|
|
||||||
|
|
||||||
You can test that everything is set up by executing:
|
|
||||||
|
|
||||||
`{test_command}`
|
|
||||||
"""
|
|
||||||
|
|
||||||
POST_MESSAGE_NOT_IN_PATH = """{poetry} ({version}) is installed now. Great!
|
|
||||||
|
|
||||||
To get started you need {poetry}'s bin directory ({poetry_home_bin}) in your `PATH`
|
|
||||||
environment variable.
|
|
||||||
{configure_message}
|
|
||||||
Alternatively, you can call {poetry} explicitly with `{poetry_executable}`.
|
|
||||||
|
|
||||||
You can test that everything is set up by executing:
|
|
||||||
|
|
||||||
`{test_command}`
|
|
||||||
"""
|
|
||||||
|
|
||||||
POST_MESSAGE_CONFIGURE_UNIX = """
|
|
||||||
Add `export PATH="{poetry_home_bin}:$PATH"` to your shell configuration file.
|
|
||||||
"""
|
|
||||||
|
|
||||||
POST_MESSAGE_CONFIGURE_FISH = """
|
|
||||||
You can execute `set -U fish_user_paths {poetry_home_bin} $fish_user_paths`
|
|
||||||
"""
|
|
||||||
|
|
||||||
POST_MESSAGE_CONFIGURE_WINDOWS = """"""
|
|
||||||
|
|
||||||
|
|
||||||
class PoetryInstallationError(RuntimeError):
|
|
||||||
def __init__(self, return_code: int = 0, log: Optional[str] = None):
|
|
||||||
super().__init__()
|
|
||||||
self.return_code = return_code
|
|
||||||
self.log = log
|
|
||||||
|
|
||||||
|
|
||||||
class VirtualEnvironment:
|
|
||||||
def __init__(self, path: Path) -> None:
|
|
||||||
self._path = path
|
|
||||||
self._bin_path = self._path.joinpath(
|
|
||||||
"Scripts" if WINDOWS and not MINGW else "bin"
|
|
||||||
)
|
|
||||||
# str is required for compatibility with subprocess run on CPython <= 3.7 on Windows
|
|
||||||
self._python = str(
|
|
||||||
self._path.joinpath(self._bin_path, "python.exe" if WINDOWS else "python")
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def path(self):
|
|
||||||
return self._path
|
|
||||||
|
|
||||||
@property
|
|
||||||
def bin_path(self):
|
|
||||||
return self._bin_path
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def make(cls, target: Path) -> "VirtualEnvironment":
|
|
||||||
if not sys.executable:
|
|
||||||
raise ValueError(
|
|
||||||
"Unable to determine sys.executable. Set PATH to a sane value or set it explicitly with PYTHONEXECUTABLE."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# on some linux distributions (eg: debian), the distribution provided python
|
|
||||||
# installation might not include ensurepip, causing the venv module to
|
|
||||||
# fail when attempting to create a virtual environment
|
|
||||||
# we import ensurepip but do not use it explicitly here
|
|
||||||
import ensurepip # noqa: F401
|
|
||||||
import venv
|
|
||||||
|
|
||||||
builder = venv.EnvBuilder(clear=True, with_pip=True, symlinks=False)
|
|
||||||
context = builder.ensure_directories(target)
|
|
||||||
|
|
||||||
if (
|
|
||||||
WINDOWS
|
|
||||||
and hasattr(context, "env_exec_cmd")
|
|
||||||
and context.env_exe != context.env_exec_cmd
|
|
||||||
):
|
|
||||||
target = target.resolve()
|
|
||||||
|
|
||||||
builder.create(target)
|
|
||||||
except ImportError:
|
|
||||||
# fallback to using virtualenv package if venv is not available, eg: ubuntu
|
|
||||||
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
||||||
virtualenv_bootstrap_url = (
|
|
||||||
f"https://bootstrap.pypa.io/virtualenv/{python_version}/virtualenv.pyz"
|
|
||||||
)
|
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory(prefix="poetry-installer") as temp_dir:
|
|
||||||
virtualenv_pyz = Path(temp_dir) / "virtualenv.pyz"
|
|
||||||
request = Request(
|
|
||||||
virtualenv_bootstrap_url, headers={"User-Agent": "Python Poetry"}
|
|
||||||
)
|
|
||||||
virtualenv_pyz.write_bytes(urlopen(request).read())
|
|
||||||
cls.run(
|
|
||||||
sys.executable, virtualenv_pyz, "--clear", "--always-copy", target
|
|
||||||
)
|
|
||||||
|
|
||||||
# We add a special file so that Poetry can detect
|
|
||||||
# its own virtual environment
|
|
||||||
target.joinpath("poetry_env").touch()
|
|
||||||
|
|
||||||
env = cls(target)
|
|
||||||
|
|
||||||
# we do this here to ensure that outdated system default pip does not trigger older bugs
|
|
||||||
env.pip("install", "--disable-pip-version-check", "--upgrade", "pip")
|
|
||||||
|
|
||||||
return env
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def run(*args, **kwargs) -> subprocess.CompletedProcess:
|
|
||||||
completed_process = subprocess.run(
|
|
||||||
args,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.STDOUT,
|
|
||||||
**kwargs,
|
|
||||||
)
|
|
||||||
if completed_process.returncode != 0:
|
|
||||||
raise PoetryInstallationError(
|
|
||||||
return_code=completed_process.returncode,
|
|
||||||
log=completed_process.stdout.decode(),
|
|
||||||
)
|
|
||||||
return completed_process
|
|
||||||
|
|
||||||
def python(self, *args, **kwargs) -> subprocess.CompletedProcess:
|
|
||||||
return self.run(self._python, *args, **kwargs)
|
|
||||||
|
|
||||||
def pip(self, *args, **kwargs) -> subprocess.CompletedProcess:
|
|
||||||
return self.python("-m", "pip", *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class Cursor:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self._output = sys.stdout
|
|
||||||
|
|
||||||
def move_up(self, lines: int = 1) -> "Cursor":
|
|
||||||
self._output.write(f"\x1b[{lines}A")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def move_down(self, lines: int = 1) -> "Cursor":
|
|
||||||
self._output.write(f"\x1b[{lines}B")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def move_right(self, columns: int = 1) -> "Cursor":
|
|
||||||
self._output.write(f"\x1b[{columns}C")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def move_left(self, columns: int = 1) -> "Cursor":
|
|
||||||
self._output.write(f"\x1b[{columns}D")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def move_to_column(self, column: int) -> "Cursor":
|
|
||||||
self._output.write(f"\x1b[{column}G")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def move_to_position(self, column: int, row: int) -> "Cursor":
|
|
||||||
self._output.write(f"\x1b[{row + 1};{column}H")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def save_position(self) -> "Cursor":
|
|
||||||
self._output.write("\x1b7")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def restore_position(self) -> "Cursor":
|
|
||||||
self._output.write("\x1b8")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def hide(self) -> "Cursor":
|
|
||||||
self._output.write("\x1b[?25l")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def show(self) -> "Cursor":
|
|
||||||
self._output.write("\x1b[?25h\x1b[?0c")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def clear_line(self) -> "Cursor":
|
|
||||||
"""
|
|
||||||
Clears all the output from the current line.
|
|
||||||
"""
|
|
||||||
self._output.write("\x1b[2K")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def clear_line_after(self) -> "Cursor":
|
|
||||||
"""
|
|
||||||
Clears all the output from the current line after the current position.
|
|
||||||
"""
|
|
||||||
self._output.write("\x1b[K")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def clear_output(self) -> "Cursor":
|
|
||||||
"""
|
|
||||||
Clears all the output from the cursors' current position
|
|
||||||
to the end of the screen.
|
|
||||||
"""
|
|
||||||
self._output.write("\x1b[0J")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def clear_screen(self) -> "Cursor":
|
|
||||||
"""
|
|
||||||
Clears the entire screen.
|
|
||||||
"""
|
|
||||||
self._output.write("\x1b[2J")
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
class Installer:
|
|
||||||
METADATA_URL = "https://pypi.org/pypi/poetry/json"
|
|
||||||
VERSION_REGEX = re.compile(
|
|
||||||
r"v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?"
|
|
||||||
"("
|
|
||||||
"[._-]?"
|
|
||||||
r"(?:(stable|beta|b|rc|RC|alpha|a|patch|pl|p)((?:[.-]?\d+)*)?)?"
|
|
||||||
"([.-]?dev)?"
|
|
||||||
")?"
|
|
||||||
r"(?:\+[^\s]+)?"
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
version: Optional[str] = None,
|
|
||||||
preview: bool = False,
|
|
||||||
force: bool = False,
|
|
||||||
accept_all: bool = False,
|
|
||||||
git: Optional[str] = None,
|
|
||||||
path: Optional[str] = None,
|
|
||||||
) -> None:
|
|
||||||
self._version = version
|
|
||||||
self._preview = preview
|
|
||||||
self._force = force
|
|
||||||
self._accept_all = accept_all
|
|
||||||
self._git = git
|
|
||||||
self._path = path
|
|
||||||
|
|
||||||
self._cursor = Cursor()
|
|
||||||
self._bin_dir = None
|
|
||||||
self._data_dir = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def bin_dir(self) -> Path:
|
|
||||||
if not self._bin_dir:
|
|
||||||
self._bin_dir = bin_dir()
|
|
||||||
return self._bin_dir
|
|
||||||
|
|
||||||
@property
|
|
||||||
def data_dir(self) -> Path:
|
|
||||||
if not self._data_dir:
|
|
||||||
self._data_dir = data_dir()
|
|
||||||
return self._data_dir
|
|
||||||
|
|
||||||
@property
|
|
||||||
def version_file(self) -> Path:
|
|
||||||
return self.data_dir.joinpath("VERSION")
|
|
||||||
|
|
||||||
def allows_prereleases(self) -> bool:
|
|
||||||
return self._preview
|
|
||||||
|
|
||||||
def run(self) -> int:
|
|
||||||
if self._git:
|
|
||||||
version = self._git
|
|
||||||
elif self._path:
|
|
||||||
version = self._path
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
version, current_version = self.get_version()
|
|
||||||
except ValueError:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
if version is None:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
self.display_pre_message()
|
|
||||||
self.ensure_directories()
|
|
||||||
|
|
||||||
def _is_self_upgrade_supported(x):
|
|
||||||
mx = self.VERSION_REGEX.match(x)
|
|
||||||
|
|
||||||
if mx is None:
|
|
||||||
# the version is not semver, perhaps scm or file, we assume upgrade is supported
|
|
||||||
return True
|
|
||||||
|
|
||||||
vx = tuple(int(p) for p in mx.groups()[:3]) + (mx.group(5),)
|
|
||||||
return vx >= (1, 1, 7)
|
|
||||||
|
|
||||||
if version and not _is_self_upgrade_supported(version):
|
|
||||||
self._write(
|
|
||||||
colorize(
|
|
||||||
"warning",
|
|
||||||
f"You are installing {version}. When using the current installer, this version does not support "
|
|
||||||
f"updating using the 'self update' command. Please use 1.1.7 or later.",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if not self._accept_all:
|
|
||||||
continue_install = input("Do you want to continue? ([y]/n) ") or "y"
|
|
||||||
if continue_install.lower() in {"n", "no"}:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.install(version)
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
raise PoetryInstallationError(
|
|
||||||
return_code=e.returncode, log=e.output.decode()
|
|
||||||
)
|
|
||||||
|
|
||||||
self._write("")
|
|
||||||
self.display_post_message(version)
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def install(self, version):
|
|
||||||
"""
|
|
||||||
Installs Poetry in $POETRY_HOME.
|
|
||||||
"""
|
|
||||||
self._write(
|
|
||||||
"Installing {} ({})".format(
|
|
||||||
colorize("info", "Poetry"), colorize("info", version)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.make_env(version) as env:
|
|
||||||
self.install_poetry(version, env)
|
|
||||||
self.make_bin(version, env)
|
|
||||||
self.version_file.write_text(version)
|
|
||||||
self._install_comment(version, "Done")
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def uninstall(self) -> int:
|
|
||||||
if not self.data_dir.exists():
|
|
||||||
self._write(
|
|
||||||
"{} is not currently installed.".format(colorize("info", "Poetry"))
|
|
||||||
)
|
|
||||||
|
|
||||||
return 1
|
|
||||||
|
|
||||||
version = None
|
|
||||||
if self.version_file.exists():
|
|
||||||
version = self.version_file.read_text().strip()
|
|
||||||
|
|
||||||
if version:
|
|
||||||
self._write(
|
|
||||||
"Removing {} ({})".format(
|
|
||||||
colorize("info", "Poetry"), colorize("b", version)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self._write("Removing {}".format(colorize("info", "Poetry")))
|
|
||||||
|
|
||||||
shutil.rmtree(str(self.data_dir))
|
|
||||||
for script in ["poetry", "poetry.bat", "poetry.exe"]:
|
|
||||||
if self.bin_dir.joinpath(script).exists():
|
|
||||||
self.bin_dir.joinpath(script).unlink()
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def _install_comment(self, version: str, message: str):
|
|
||||||
self._overwrite(
|
|
||||||
"Installing {} ({}): {}".format(
|
|
||||||
colorize("info", "Poetry"),
|
|
||||||
colorize("b", version),
|
|
||||||
colorize("comment", message),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def make_env(self, version: str) -> VirtualEnvironment:
|
|
||||||
env_path = self.data_dir.joinpath("venv")
|
|
||||||
env_path_saved = env_path.with_suffix(".save")
|
|
||||||
|
|
||||||
if env_path.exists():
|
|
||||||
self._install_comment(version, "Saving existing environment")
|
|
||||||
if env_path_saved.exists():
|
|
||||||
shutil.rmtree(env_path_saved)
|
|
||||||
shutil.move(env_path, env_path_saved)
|
|
||||||
|
|
||||||
try:
|
|
||||||
self._install_comment(version, "Creating environment")
|
|
||||||
yield VirtualEnvironment.make(env_path)
|
|
||||||
except Exception as e:
|
|
||||||
if env_path.exists():
|
|
||||||
self._install_comment(
|
|
||||||
version, "An error occurred. Removing partial environment."
|
|
||||||
)
|
|
||||||
shutil.rmtree(env_path)
|
|
||||||
|
|
||||||
if env_path_saved.exists():
|
|
||||||
self._install_comment(
|
|
||||||
version, "Restoring previously saved environment."
|
|
||||||
)
|
|
||||||
shutil.move(env_path_saved, env_path)
|
|
||||||
|
|
||||||
raise e
|
|
||||||
else:
|
|
||||||
if env_path_saved.exists():
|
|
||||||
shutil.rmtree(env_path_saved, ignore_errors=True)
|
|
||||||
|
|
||||||
def make_bin(self, version: str, env: VirtualEnvironment) -> None:
|
|
||||||
self._install_comment(version, "Creating script")
|
|
||||||
self.bin_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
script = "poetry.exe" if WINDOWS else "poetry"
|
|
||||||
target_script = env.bin_path.joinpath(script)
|
|
||||||
|
|
||||||
if self.bin_dir.joinpath(script).exists():
|
|
||||||
self.bin_dir.joinpath(script).unlink()
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.bin_dir.joinpath(script).symlink_to(target_script)
|
|
||||||
except OSError:
|
|
||||||
# This can happen if the user
|
|
||||||
# does not have the correct permission on Windows
|
|
||||||
shutil.copy(target_script, self.bin_dir.joinpath(script))
|
|
||||||
|
|
||||||
def install_poetry(self, version: str, env: VirtualEnvironment) -> None:
|
|
||||||
self._install_comment(version, "Installing Poetry")
|
|
||||||
|
|
||||||
if self._git:
|
|
||||||
specification = "git+" + version
|
|
||||||
elif self._path:
|
|
||||||
specification = version
|
|
||||||
else:
|
|
||||||
specification = f"poetry=={version}"
|
|
||||||
|
|
||||||
env.pip("install", specification)
|
|
||||||
|
|
||||||
def display_pre_message(self) -> None:
|
|
||||||
kwargs = {
|
|
||||||
"poetry": colorize("info", "Poetry"),
|
|
||||||
"poetry_home_bin": colorize("comment", self.bin_dir),
|
|
||||||
}
|
|
||||||
self._write(PRE_MESSAGE.format(**kwargs))
|
|
||||||
|
|
||||||
def display_post_message(self, version: str) -> None:
|
|
||||||
if WINDOWS:
|
|
||||||
return self.display_post_message_windows(version)
|
|
||||||
|
|
||||||
if SHELL == "fish":
|
|
||||||
return self.display_post_message_fish(version)
|
|
||||||
|
|
||||||
return self.display_post_message_unix(version)
|
|
||||||
|
|
||||||
def display_post_message_windows(self, version: str) -> None:
|
|
||||||
path = self.get_windows_path_var()
|
|
||||||
|
|
||||||
message = POST_MESSAGE_NOT_IN_PATH
|
|
||||||
if path and str(self.bin_dir) in path:
|
|
||||||
message = POST_MESSAGE
|
|
||||||
|
|
||||||
self._write(
|
|
||||||
message.format(
|
|
||||||
poetry=colorize("info", "Poetry"),
|
|
||||||
version=colorize("b", version),
|
|
||||||
poetry_home_bin=colorize("comment", self.bin_dir),
|
|
||||||
poetry_executable=colorize("b", self.bin_dir.joinpath("poetry")),
|
|
||||||
configure_message=POST_MESSAGE_CONFIGURE_WINDOWS.format(
|
|
||||||
poetry_home_bin=colorize("comment", self.bin_dir)
|
|
||||||
),
|
|
||||||
test_command=colorize("b", "poetry --version"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_windows_path_var(self) -> Optional[str]:
|
|
||||||
import winreg
|
|
||||||
|
|
||||||
with winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) as root:
|
|
||||||
with winreg.OpenKey(root, "Environment", 0, winreg.KEY_ALL_ACCESS) as key:
|
|
||||||
path, _ = winreg.QueryValueEx(key, "PATH")
|
|
||||||
|
|
||||||
return path
|
|
||||||
|
|
||||||
def display_post_message_fish(self, version: str) -> None:
|
|
||||||
fish_user_paths = subprocess.check_output(
|
|
||||||
["fish", "-c", "echo $fish_user_paths"]
|
|
||||||
).decode("utf-8")
|
|
||||||
|
|
||||||
message = POST_MESSAGE_NOT_IN_PATH
|
|
||||||
if fish_user_paths and str(self.bin_dir) in fish_user_paths:
|
|
||||||
message = POST_MESSAGE
|
|
||||||
|
|
||||||
self._write(
|
|
||||||
message.format(
|
|
||||||
poetry=colorize("info", "Poetry"),
|
|
||||||
version=colorize("b", version),
|
|
||||||
poetry_home_bin=colorize("comment", self.bin_dir),
|
|
||||||
poetry_executable=colorize("b", self.bin_dir.joinpath("poetry")),
|
|
||||||
configure_message=POST_MESSAGE_CONFIGURE_FISH.format(
|
|
||||||
poetry_home_bin=colorize("comment", self.bin_dir)
|
|
||||||
),
|
|
||||||
test_command=colorize("b", "poetry --version"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def display_post_message_unix(self, version: str) -> None:
|
|
||||||
paths = os.getenv("PATH", "").split(":")
|
|
||||||
|
|
||||||
message = POST_MESSAGE_NOT_IN_PATH
|
|
||||||
if paths and str(self.bin_dir) in paths:
|
|
||||||
message = POST_MESSAGE
|
|
||||||
|
|
||||||
self._write(
|
|
||||||
message.format(
|
|
||||||
poetry=colorize("info", "Poetry"),
|
|
||||||
version=colorize("b", version),
|
|
||||||
poetry_home_bin=colorize("comment", self.bin_dir),
|
|
||||||
poetry_executable=colorize("b", self.bin_dir.joinpath("poetry")),
|
|
||||||
configure_message=POST_MESSAGE_CONFIGURE_UNIX.format(
|
|
||||||
poetry_home_bin=colorize("comment", self.bin_dir)
|
|
||||||
),
|
|
||||||
test_command=colorize("b", "poetry --version"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def ensure_directories(self) -> None:
|
|
||||||
self.data_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
self.bin_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
def get_version(self):
|
|
||||||
current_version = None
|
|
||||||
if self.version_file.exists():
|
|
||||||
current_version = self.version_file.read_text().strip()
|
|
||||||
|
|
||||||
self._write(colorize("info", "Retrieving Poetry metadata"))
|
|
||||||
|
|
||||||
metadata = json.loads(self._get(self.METADATA_URL).decode())
|
|
||||||
|
|
||||||
def _compare_versions(x, y):
|
|
||||||
mx = self.VERSION_REGEX.match(x)
|
|
||||||
my = self.VERSION_REGEX.match(y)
|
|
||||||
|
|
||||||
vx = tuple(int(p) for p in mx.groups()[:3]) + (mx.group(5),)
|
|
||||||
vy = tuple(int(p) for p in my.groups()[:3]) + (my.group(5),)
|
|
||||||
|
|
||||||
if vx < vy:
|
|
||||||
return -1
|
|
||||||
elif vx > vy:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
self._write("")
|
|
||||||
releases = sorted(
|
|
||||||
metadata["releases"].keys(), key=cmp_to_key(_compare_versions)
|
|
||||||
)
|
|
||||||
|
|
||||||
if self._version and self._version not in releases:
|
|
||||||
msg = f"Version {self._version} does not exist."
|
|
||||||
self._write(colorize("error", msg))
|
|
||||||
|
|
||||||
raise ValueError(msg)
|
|
||||||
|
|
||||||
version = self._version
|
|
||||||
if not version:
|
|
||||||
for release in reversed(releases):
|
|
||||||
m = self.VERSION_REGEX.match(release)
|
|
||||||
if m.group(5) and not self.allows_prereleases():
|
|
||||||
continue
|
|
||||||
|
|
||||||
version = release
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
if current_version == version and not self._force:
|
|
||||||
self._write(
|
|
||||||
f'The latest version ({colorize("b", version)}) is already installed.'
|
|
||||||
)
|
|
||||||
|
|
||||||
return None, current_version
|
|
||||||
|
|
||||||
return version, current_version
|
|
||||||
|
|
||||||
def _write(self, line) -> None:
|
|
||||||
sys.stdout.write(line + "\n")
|
|
||||||
|
|
||||||
def _overwrite(self, line) -> None:
|
|
||||||
if not is_decorated():
|
|
||||||
return self._write(line)
|
|
||||||
|
|
||||||
self._cursor.move_up()
|
|
||||||
self._cursor.clear_line()
|
|
||||||
self._write(line)
|
|
||||||
|
|
||||||
def _get(self, url):
|
|
||||||
request = Request(url, headers={"User-Agent": "Python Poetry"})
|
|
||||||
|
|
||||||
with closing(urlopen(request)) as r:
|
|
||||||
return r.read()
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if sys.version_info < (3, 6):
|
|
||||||
sys.stdout.write(
|
|
||||||
colorize("error", "Poetry installer requires Python 3.6 or newer to run!")
|
|
||||||
)
|
|
||||||
# return error code
|
|
||||||
return 1
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="Installs the latest (or given) version of poetry"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-p",
|
|
||||||
"--preview",
|
|
||||||
help="install preview version",
|
|
||||||
dest="preview",
|
|
||||||
action="store_true",
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
parser.add_argument("--version", help="install named version", dest="version")
|
|
||||||
parser.add_argument(
|
|
||||||
"-f",
|
|
||||||
"--force",
|
|
||||||
help="install on top of existing version",
|
|
||||||
dest="force",
|
|
||||||
action="store_true",
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-y",
|
|
||||||
"--yes",
|
|
||||||
help="accept all prompts",
|
|
||||||
dest="accept_all",
|
|
||||||
action="store_true",
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--uninstall",
|
|
||||||
help="uninstall poetry",
|
|
||||||
dest="uninstall",
|
|
||||||
action="store_true",
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--path",
|
|
||||||
dest="path",
|
|
||||||
action="store",
|
|
||||||
help=(
|
|
||||||
"Install from a given path (file or directory) instead of "
|
|
||||||
"fetching the latest version of Poetry available online."
|
|
||||||
),
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--git",
|
|
||||||
dest="git",
|
|
||||||
action="store",
|
|
||||||
help=(
|
|
||||||
"Install from a git repository instead of fetching the latest version "
|
|
||||||
"of Poetry available online."
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
installer = Installer(
|
|
||||||
version=args.version or os.getenv("POETRY_VERSION"),
|
|
||||||
preview=args.preview or string_to_bool(os.getenv("POETRY_PREVIEW", "0")),
|
|
||||||
force=args.force,
|
|
||||||
accept_all=args.accept_all
|
|
||||||
or string_to_bool(os.getenv("POETRY_ACCEPT", "0"))
|
|
||||||
or not is_interactive(),
|
|
||||||
path=args.path,
|
|
||||||
git=args.git,
|
|
||||||
)
|
|
||||||
|
|
||||||
if args.uninstall or string_to_bool(os.getenv("POETRY_UNINSTALL", "0")):
|
|
||||||
return installer.uninstall()
|
|
||||||
|
|
||||||
try:
|
|
||||||
return installer.run()
|
|
||||||
except PoetryInstallationError as e:
|
|
||||||
installer._write(colorize("error", "Poetry installation failed."))
|
|
||||||
|
|
||||||
if e.log is not None:
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
_, path = tempfile.mkstemp(
|
|
||||||
suffix=".log",
|
|
||||||
prefix="poetry-installer-error-",
|
|
||||||
dir=str(Path.cwd()),
|
|
||||||
text=True,
|
|
||||||
)
|
|
||||||
installer._write(colorize("error", f"See {path} for error logs."))
|
|
||||||
text = f"{e.log}\nTraceback:\n\n{''.join(traceback.format_tb(e.__traceback__))}"
|
|
||||||
Path(path).write_text(text)
|
|
||||||
|
|
||||||
return e.return_code
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
|
@ -1,13 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Usage: curl https://pyenv.run | bash
|
|
||||||
#
|
|
||||||
# For more info, visit: https://github.com/pyenv/pyenv-installer
|
|
||||||
#
|
|
||||||
index_main() {
|
|
||||||
set -e
|
|
||||||
curl -s -S -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash
|
|
||||||
echo "suggested install to build python: base-devel openssl zlib xz tk"
|
|
||||||
}
|
|
||||||
|
|
||||||
index_main
|
|
|
@ -1,517 +0,0 @@
|
||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
set -eu
|
|
||||||
printf '\n'
|
|
||||||
|
|
||||||
BOLD="$(tput bold 2>/dev/null || printf '')"
|
|
||||||
GREY="$(tput setaf 0 2>/dev/null || printf '')"
|
|
||||||
UNDERLINE="$(tput smul 2>/dev/null || printf '')"
|
|
||||||
RED="$(tput setaf 1 2>/dev/null || printf '')"
|
|
||||||
GREEN="$(tput setaf 2 2>/dev/null || printf '')"
|
|
||||||
YELLOW="$(tput setaf 3 2>/dev/null || printf '')"
|
|
||||||
BLUE="$(tput setaf 4 2>/dev/null || printf '')"
|
|
||||||
MAGENTA="$(tput setaf 5 2>/dev/null || printf '')"
|
|
||||||
NO_COLOR="$(tput sgr0 2>/dev/null || printf '')"
|
|
||||||
|
|
||||||
SUPPORTED_TARGETS="x86_64-unknown-linux-gnu x86_64-unknown-linux-musl \
|
|
||||||
i686-unknown-linux-musl aarch64-unknown-linux-musl \
|
|
||||||
arm-unknown-linux-musleabihf x86_64-apple-darwin \
|
|
||||||
aarch64-apple-darwin x86_64-pc-windows-msvc \
|
|
||||||
i686-pc-windows-msvc aarch64-pc-windows-msvc \
|
|
||||||
x86_64-unknown-freebsd"
|
|
||||||
|
|
||||||
info() {
|
|
||||||
printf '%s\n' "${BOLD}${GREY}>${NO_COLOR} $*"
|
|
||||||
}
|
|
||||||
|
|
||||||
warn() {
|
|
||||||
printf '%s\n' "${YELLOW}! $*${NO_COLOR}"
|
|
||||||
}
|
|
||||||
|
|
||||||
error() {
|
|
||||||
printf '%s\n' "${RED}x $*${NO_COLOR}" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
completed() {
|
|
||||||
printf '%s\n' "${GREEN}✓${NO_COLOR} $*"
|
|
||||||
}
|
|
||||||
|
|
||||||
has() {
|
|
||||||
command -v "$1" 1>/dev/null 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Make sure user is not using zsh or non-POSIX-mode bash, which can cause issues
|
|
||||||
verify_shell_is_posix_or_exit() {
|
|
||||||
if [ -n "${ZSH_VERSION+x}" ]; then
|
|
||||||
error "Running installation script with \`zsh\` is known to cause errors."
|
|
||||||
error "Please use \`sh\` instead."
|
|
||||||
exit 1
|
|
||||||
elif [ -n "${BASH_VERSION+x}" ] && [ -z "${POSIXLY_CORRECT+x}" ]; then
|
|
||||||
error "Running installation script with non-POSIX \`bash\` may cause errors."
|
|
||||||
error "Please use \`sh\` instead."
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
true # No-op: no issues detected
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Gets path to a temporary file, even if
|
|
||||||
get_tmpfile() {
|
|
||||||
suffix="$1"
|
|
||||||
if has mktemp; then
|
|
||||||
printf "%s.%s" "$(mktemp)" "${suffix}"
|
|
||||||
else
|
|
||||||
# No really good options here--let's pick a default + hope
|
|
||||||
printf "/tmp/starship.%s" "${suffix}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Test if a location is writeable by trying to write to it. Windows does not let
|
|
||||||
# you test writeability other than by writing: https://stackoverflow.com/q/1999988
|
|
||||||
test_writeable() {
|
|
||||||
path="${1:-}/test.txt"
|
|
||||||
if touch "${path}" 2>/dev/null; then
|
|
||||||
rm "${path}"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
download() {
|
|
||||||
file="$1"
|
|
||||||
url="$2"
|
|
||||||
|
|
||||||
if has curl; then
|
|
||||||
cmd="curl --fail --silent --location --output $file $url"
|
|
||||||
elif has wget; then
|
|
||||||
cmd="wget --quiet --output-document=$file $url"
|
|
||||||
elif has fetch; then
|
|
||||||
cmd="fetch --quiet --output=$file $url"
|
|
||||||
else
|
|
||||||
error "No HTTP download program (curl, wget, fetch) found, exiting…"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
$cmd && return 0 || rc=$?
|
|
||||||
|
|
||||||
error "Command failed (exit code $rc): ${BLUE}${cmd}${NO_COLOR}"
|
|
||||||
printf "\n" >&2
|
|
||||||
info "This is likely due to Starship not yet supporting your configuration."
|
|
||||||
info "If you would like to see a build for your configuration,"
|
|
||||||
info "please create an issue requesting a build for ${MAGENTA}${TARGET}${NO_COLOR}:"
|
|
||||||
info "${BOLD}${UNDERLINE}https://github.com/starship/starship/issues/new/${NO_COLOR}"
|
|
||||||
return $rc
|
|
||||||
}
|
|
||||||
|
|
||||||
unpack() {
|
|
||||||
archive=$1
|
|
||||||
bin_dir=$2
|
|
||||||
sudo=${3-}
|
|
||||||
|
|
||||||
case "$archive" in
|
|
||||||
*.tar.gz)
|
|
||||||
flags=$(test -n "${VERBOSE-}" && echo "-xzvof" || echo "-xzof")
|
|
||||||
${sudo} tar "${flags}" "${archive}" -C "${bin_dir}"
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
*.zip)
|
|
||||||
flags=$(test -z "${VERBOSE-}" && echo "-qqo" || echo "-o")
|
|
||||||
UNZIP="${flags}" ${sudo} unzip "${archive}" -d "${bin_dir}"
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
error "Unknown package extension."
|
|
||||||
printf "\n"
|
|
||||||
info "This almost certainly results from a bug in this script--please file a"
|
|
||||||
info "bug report at https://github.com/starship/starship/issues"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
printf "%s\n" \
|
|
||||||
"install.sh [option]" \
|
|
||||||
"" \
|
|
||||||
"Fetch and install the latest version of starship, if starship is already" \
|
|
||||||
"installed it will be updated to the latest version."
|
|
||||||
|
|
||||||
printf "\n%s\n" "Options"
|
|
||||||
printf "\t%s\n\t\t%s\n\n" \
|
|
||||||
"-V, --verbose" "Enable verbose output for the installer" \
|
|
||||||
"-f, -y, --force, --yes" "Skip the confirmation prompt during installation" \
|
|
||||||
"-p, --platform" "Override the platform identified by the installer [default: ${PLATFORM}]" \
|
|
||||||
"-b, --bin-dir" "Override the bin installation directory [default: ${BIN_DIR}]" \
|
|
||||||
"-a, --arch" "Override the architecture identified by the installer [default: ${ARCH}]" \
|
|
||||||
"-B, --base-url" "Override the base URL used for downloading releases [default: ${BASE_URL}]" \
|
|
||||||
"-h, --help" "Display this help message"
|
|
||||||
}
|
|
||||||
|
|
||||||
elevate_priv() {
|
|
||||||
if ! has sudo; then
|
|
||||||
error 'Could not find the command "sudo", needed to get permissions for install.'
|
|
||||||
info "If you are on Windows, please run your shell as an administrator, then"
|
|
||||||
info "rerun this script. Otherwise, please run this script as root, or install"
|
|
||||||
info "sudo."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if ! sudo -v; then
|
|
||||||
error "Superuser not granted, aborting installation"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install() {
|
|
||||||
ext="$1"
|
|
||||||
|
|
||||||
if test_writeable "${BIN_DIR}"; then
|
|
||||||
sudo=""
|
|
||||||
msg="Installing Starship, please wait…"
|
|
||||||
else
|
|
||||||
warn "Escalated permissions are required to install to ${BIN_DIR}"
|
|
||||||
elevate_priv
|
|
||||||
sudo="sudo"
|
|
||||||
msg="Installing Starship as root, please wait…"
|
|
||||||
fi
|
|
||||||
info "$msg"
|
|
||||||
|
|
||||||
archive=$(get_tmpfile "$ext")
|
|
||||||
|
|
||||||
# download to the temp file
|
|
||||||
download "${archive}" "${URL}"
|
|
||||||
|
|
||||||
# unpack the temp file to the bin dir, using sudo if required
|
|
||||||
unpack "${archive}" "${BIN_DIR}" "${sudo}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Currently supporting:
|
|
||||||
# - win (Git Bash)
|
|
||||||
# - darwin
|
|
||||||
# - linux
|
|
||||||
# - linux_musl (Alpine)
|
|
||||||
# - freebsd
|
|
||||||
detect_platform() {
|
|
||||||
platform="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
||||||
|
|
||||||
case "${platform}" in
|
|
||||||
msys_nt*) platform="pc-windows-msvc" ;;
|
|
||||||
cygwin_nt*) platform="pc-windows-msvc";;
|
|
||||||
# mingw is Git-Bash
|
|
||||||
mingw*) platform="pc-windows-msvc" ;;
|
|
||||||
# use the statically compiled musl bins on linux to avoid linking issues.
|
|
||||||
linux) platform="unknown-linux-musl" ;;
|
|
||||||
darwin) platform="apple-darwin" ;;
|
|
||||||
freebsd) platform="unknown-freebsd" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
printf '%s' "${platform}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Currently supporting:
|
|
||||||
# - x86_64
|
|
||||||
# - i386
|
|
||||||
# - arm
|
|
||||||
# - arm64
|
|
||||||
detect_arch() {
|
|
||||||
arch="$(uname -m | tr '[:upper:]' '[:lower:]')"
|
|
||||||
|
|
||||||
case "${arch}" in
|
|
||||||
amd64) arch="x86_64" ;;
|
|
||||||
armv*) arch="arm" ;;
|
|
||||||
arm64) arch="aarch64" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# `uname -m` in some cases mis-reports 32-bit OS as 64-bit, so double check
|
|
||||||
if [ "${arch}" = "x86_64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then
|
|
||||||
arch=i686
|
|
||||||
elif [ "${arch}" = "aarch64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then
|
|
||||||
arch=arm
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf '%s' "${arch}"
|
|
||||||
}
|
|
||||||
|
|
||||||
detect_target() {
|
|
||||||
arch="$1"
|
|
||||||
platform="$2"
|
|
||||||
target="$arch-$platform"
|
|
||||||
|
|
||||||
if [ "${target}" = "arm-unknown-linux-musl" ]; then
|
|
||||||
target="${target}eabihf"
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf '%s' "${target}"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
confirm() {
|
|
||||||
if [ -z "${FORCE-}" ]; then
|
|
||||||
printf "%s " "${MAGENTA}?${NO_COLOR} $* ${BOLD}[y/N]${NO_COLOR}"
|
|
||||||
set +e
|
|
||||||
read -r yn </dev/tty
|
|
||||||
rc=$?
|
|
||||||
set -e
|
|
||||||
if [ $rc -ne 0 ]; then
|
|
||||||
error "Error reading from prompt (please re-run with the '--yes' option)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ "$yn" != "y" ] && [ "$yn" != "yes" ]; then
|
|
||||||
error 'Aborting (please answer "yes" to continue)'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
check_bin_dir() {
|
|
||||||
bin_dir="${1%/}"
|
|
||||||
|
|
||||||
if [ ! -d "$BIN_DIR" ]; then
|
|
||||||
error "Installation location $BIN_DIR does not appear to be a directory"
|
|
||||||
info "Make sure the location exists and is a directory, then try again."
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# https://stackoverflow.com/a/11655875
|
|
||||||
good=$(
|
|
||||||
IFS=:
|
|
||||||
for path in $PATH; do
|
|
||||||
if [ "${path%/}" = "${bin_dir}" ]; then
|
|
||||||
printf 1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
)
|
|
||||||
|
|
||||||
if [ "${good}" != "1" ]; then
|
|
||||||
warn "Bin directory ${bin_dir} is not in your \$PATH"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
print_install() {
|
|
||||||
# if the shell does not fit the default case change the config file
|
|
||||||
# and or the config cmd variable
|
|
||||||
for s in "bash" "zsh" "ion" "tcsh" "xonsh" "fish"
|
|
||||||
do
|
|
||||||
# shellcheck disable=SC2088
|
|
||||||
# we don't want these '~' expanding
|
|
||||||
config_file="~/.${s}rc"
|
|
||||||
config_cmd="eval \"\$(starship init ${s})\""
|
|
||||||
|
|
||||||
case ${s} in
|
|
||||||
ion )
|
|
||||||
# shellcheck disable=SC2088
|
|
||||||
config_file="~/.config/ion/initrc"
|
|
||||||
config_cmd="eval \$(starship init ${s})"
|
|
||||||
;;
|
|
||||||
fish )
|
|
||||||
# shellcheck disable=SC2088
|
|
||||||
config_file="~/.config/fish/config.fish"
|
|
||||||
config_cmd="starship init fish | source"
|
|
||||||
;;
|
|
||||||
tcsh )
|
|
||||||
config_cmd="eval \`starship init ${s}\`"
|
|
||||||
;;
|
|
||||||
xonsh )
|
|
||||||
config_cmd="execx(\$(starship init xonsh))"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
printf " %s\n Add the following to the end of %s:\n\n\t%s\n\n" \
|
|
||||||
"${BOLD}${UNDERLINE}${s}${NO_COLOR}" \
|
|
||||||
"${BOLD}${config_file}${NO_COLOR}" \
|
|
||||||
"${config_cmd}"
|
|
||||||
done
|
|
||||||
|
|
||||||
for s in "elvish" "nushell"
|
|
||||||
do
|
|
||||||
|
|
||||||
warning="${BOLD}Warning${NO_COLOR}"
|
|
||||||
case ${s} in
|
|
||||||
elvish )
|
|
||||||
# shellcheck disable=SC2088
|
|
||||||
config_file="~/.elvish/rc.elv"
|
|
||||||
config_cmd="eval (starship init elvish)"
|
|
||||||
warning="${warning} Only elvish v0.17 or higher is supported."
|
|
||||||
;;
|
|
||||||
nushell )
|
|
||||||
# shellcheck disable=SC2088
|
|
||||||
config_file="${BOLD}your nu config file${NO_COLOR} (find it by running ${BOLD}\$nu.config-path${NO_COLOR} in Nushell)"
|
|
||||||
config_cmd="mkdir ~/.cache/starship
|
|
||||||
starship init nu | save -f ~/.cache/starship/init.nu
|
|
||||||
source ~/.cache/starship/init.nu"
|
|
||||||
warning="${warning} This will change in the future.
|
|
||||||
Only Nushell v0.73 or higher is supported.
|
|
||||||
Add the following to the end of ${BOLD}your Nushell env file${NO_COLOR} (find it by running ${BOLD}\$nu.env-path${NO_COLOR} in Nushell): \"mkdir ~/.cache/starship; starship init nu | save -f ~/.cache/starship/init.nu\""
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
printf " %s\n %s\n And add the following to the end of %s:\n\n\t%s\n\n" \
|
|
||||||
"${BOLD}${UNDERLINE}${s}${NO_COLOR}" \
|
|
||||||
"${warning}" \
|
|
||||||
"${config_file}" \
|
|
||||||
"${config_cmd}"
|
|
||||||
done
|
|
||||||
|
|
||||||
printf " %s\n Add the following to the end of %s:\n %s\n\n\t%s\n\n" \
|
|
||||||
"${BOLD}${UNDERLINE}PowerShell${NO_COLOR}" \
|
|
||||||
"${BOLD}Microsoft.PowerShell_profile.ps1${NO_COLOR}" \
|
|
||||||
"You can check the location of this file by querying the \$PROFILE variable in PowerShell.
|
|
||||||
Typically the path is ~\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 or ~/.config/powershell/Microsoft.PowerShell_profile.ps1 on -Nix." \
|
|
||||||
"Invoke-Expression (&starship init powershell)"
|
|
||||||
|
|
||||||
printf " %s\n You need to use Clink (v1.2.30+) with Cmd. Add the following to a file %s and place this file in Clink scripts directory:\n\n\t%s\n\n" \
|
|
||||||
"${BOLD}${UNDERLINE}Cmd${NO_COLOR}" \
|
|
||||||
"${BOLD}starship.lua${NO_COLOR}" \
|
|
||||||
"load(io.popen('starship init cmd'):read(\"*a\"))()"
|
|
||||||
|
|
||||||
printf "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
is_build_available() {
|
|
||||||
arch="$1"
|
|
||||||
platform="$2"
|
|
||||||
target="$3"
|
|
||||||
|
|
||||||
good=$(
|
|
||||||
IFS=" "
|
|
||||||
for t in $SUPPORTED_TARGETS; do
|
|
||||||
if [ "${t}" = "${target}" ]; then
|
|
||||||
printf 1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
)
|
|
||||||
|
|
||||||
if [ "${good}" != "1" ]; then
|
|
||||||
error "${arch} builds for ${platform} are not yet available for Starship"
|
|
||||||
printf "\n" >&2
|
|
||||||
info "If you would like to see a build for your configuration,"
|
|
||||||
info "please create an issue requesting a build for ${MAGENTA}${target}${NO_COLOR}:"
|
|
||||||
info "${BOLD}${UNDERLINE}https://github.com/starship/starship/issues/new/${NO_COLOR}"
|
|
||||||
printf "\n"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# defaults
|
|
||||||
if [ -z "${PLATFORM-}" ]; then
|
|
||||||
PLATFORM="$(detect_platform)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${BIN_DIR-}" ]; then
|
|
||||||
BIN_DIR=/usr/local/bin
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${ARCH-}" ]; then
|
|
||||||
ARCH="$(detect_arch)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${BASE_URL-}" ]; then
|
|
||||||
BASE_URL="https://github.com/starship/starship/releases"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Non-POSIX shells can break once executing code due to semantic differences
|
|
||||||
verify_shell_is_posix_or_exit
|
|
||||||
|
|
||||||
# parse argv variables
|
|
||||||
while [ "$#" -gt 0 ]; do
|
|
||||||
case "$1" in
|
|
||||||
-p | --platform)
|
|
||||||
PLATFORM="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-b | --bin-dir)
|
|
||||||
BIN_DIR="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-a | --arch)
|
|
||||||
ARCH="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-B | --base-url)
|
|
||||||
BASE_URL="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
|
|
||||||
-V | --verbose)
|
|
||||||
VERBOSE=1
|
|
||||||
shift 1
|
|
||||||
;;
|
|
||||||
-f | -y | --force | --yes)
|
|
||||||
FORCE=1
|
|
||||||
shift 1
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
usage
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
|
|
||||||
-p=* | --platform=*)
|
|
||||||
PLATFORM="${1#*=}"
|
|
||||||
shift 1
|
|
||||||
;;
|
|
||||||
-b=* | --bin-dir=*)
|
|
||||||
BIN_DIR="${1#*=}"
|
|
||||||
shift 1
|
|
||||||
;;
|
|
||||||
-a=* | --arch=*)
|
|
||||||
ARCH="${1#*=}"
|
|
||||||
shift 1
|
|
||||||
;;
|
|
||||||
-B=* | --base-url=*)
|
|
||||||
BASE_URL="${1#*=}"
|
|
||||||
shift 1
|
|
||||||
;;
|
|
||||||
-V=* | --verbose=*)
|
|
||||||
VERBOSE="${1#*=}"
|
|
||||||
shift 1
|
|
||||||
;;
|
|
||||||
-f=* | -y=* | --force=* | --yes=*)
|
|
||||||
FORCE="${1#*=}"
|
|
||||||
shift 1
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
error "Unknown option: $1"
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
TARGET="$(detect_target "${ARCH}" "${PLATFORM}")"
|
|
||||||
|
|
||||||
is_build_available "${ARCH}" "${PLATFORM}" "${TARGET}"
|
|
||||||
|
|
||||||
printf " %s\n" "${UNDERLINE}Configuration${NO_COLOR}"
|
|
||||||
info "${BOLD}Bin directory${NO_COLOR}: ${GREEN}${BIN_DIR}${NO_COLOR}"
|
|
||||||
info "${BOLD}Platform${NO_COLOR}: ${GREEN}${PLATFORM}${NO_COLOR}"
|
|
||||||
info "${BOLD}Arch${NO_COLOR}: ${GREEN}${ARCH}${NO_COLOR}"
|
|
||||||
|
|
||||||
# non-empty VERBOSE enables verbose untarring
|
|
||||||
if [ -n "${VERBOSE-}" ]; then
|
|
||||||
VERBOSE=v
|
|
||||||
info "${BOLD}Verbose${NO_COLOR}: yes"
|
|
||||||
else
|
|
||||||
VERBOSE=
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf '\n'
|
|
||||||
|
|
||||||
EXT=tar.gz
|
|
||||||
if [ "${PLATFORM}" = "pc-windows-msvc" ]; then
|
|
||||||
EXT=zip
|
|
||||||
fi
|
|
||||||
|
|
||||||
URL="${BASE_URL}/latest/download/starship-${TARGET}.${EXT}"
|
|
||||||
info "Tarball URL: ${UNDERLINE}${BLUE}${URL}${NO_COLOR}"
|
|
||||||
confirm "Install Starship ${GREEN}latest${NO_COLOR} to ${BOLD}${GREEN}${BIN_DIR}${NO_COLOR}?"
|
|
||||||
check_bin_dir "${BIN_DIR}"
|
|
||||||
|
|
||||||
install "${EXT}"
|
|
||||||
completed "Starship installed"
|
|
||||||
|
|
||||||
printf '\n'
|
|
||||||
info "Please follow the steps for your shell to complete the installation:"
|
|
||||||
|
|
||||||
print_install
|
|
Loading…
Reference in a new issue