Compare commits

...

12 Commits

11 changed files with 204 additions and 620 deletions

View File

@@ -4,42 +4,24 @@ Bootstrap an OS instance with bare essentials.
## Usage
To bootstrap a macOS instance:
To bootstrap a Linux instance choose one of:
```console
$ curl -O https://git.infektor.net/config/bootstrap/raw/main/bootstrap-macOS.sh && chmod +x bootstrap-macOS.sh && ./bootstrap-macOS.sh
```bash
wget https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Linux.sh && chmod +x bootstrap-Linux.sh && ./bootstrap-Linux.sh
```
To bootstrap a Debian based Linux instance:
```console
$ wget https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Debian.sh && chmod +x bootstrap-Debian.sh && ./bootstrap-Debian.sh
```
To bootstrap a Arch Linux based instance:
```console
$ curl -O https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Arch.sh && chmod +x bootstrap-Arch.sh && ./bootstrap-Arch.sh
```
To bootstrap a Fedora Linux instance:
```console
$ curl -O https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Fedora.sh && chmod +x bootstrap-Fedora.sh && ./bootstrap-Fedora.sh
```bash
curl -O https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Linux.sh && chmod +x bootstrap-Linux.sh && ./bootstrap-Linux.sh
```
To bootstrap a Windows instance:
```console
$ Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-WebRequest -Uri "https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Windows.ps1" -OutFile "./bootstrap-Windows.ps1"; ./bootstrap-Windows.ps1
```powershell
Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-WebRequest -Uri "https://git.infektor.net/config/bootstrap/raw/main/bootstrap-Windows.ps1" -OutFile "./bootstrap-Windows.ps1"; ./bootstrap-Windows.ps1
```
## Package
To bootstrap a macOS instance:
Install as a pip package to set SSH keys on any of GitHub, GitLab, BitBucket
Cloud, or Gogs servers:
```console
$ pip install git+https://git.infektor.net/config/bootstrap.git
$ python -c 'import bootstrap; bootstrap.set_ssh_keys()'
```bash
curl -O https://git.infektor.net/config/bootstrap/raw/main/bootstrap-macOS.sh && chmod +x bootstrap-macOS.sh && ./bootstrap-macOS.sh
```

View File

@@ -1,105 +0,0 @@
#!/bin/bash
set -e
show_usage() {
echo "usage: $0 [-h] [-y]"
}
show_help() {
show_usage
echo
echo "Bootstrap a Debian based distribution with:"
echo
echo "* update pacman cache"
echo "* upgrade pacman packages"
echo "* git - from pacman"
echo "* python-pip - from pacman"
echo "* virtualenv - from pacman"
echo "* SSH key - from ssh-keygen"
echo "* GitHub public key - with SSH key"
echo "* GitLab public key - with SSH key"
echo "* BitBucket Cloud public key - with SSH key"
echo "* Gogs Cloud public key - with SSH key"
echo "* conduit - configuration manager"
echo
echo "If any already exist they will not be reinstalled."
echo
echo "optional arguments:"
echo " -h show this help message and exit"
echo " -y assume yes when prompted"
}
yes=0
while getopts 'hy' opt; do
case $opt in
h) show_help; exit 0 ;;
y) yes=1 ;;
*) show_usage; exit 1 ;;
esac
done
missing() {
which $1 &> /dev/null && return 1 || return 0
}
agree() {
local check=^[Nn]$
[ $yes -eq 1 ] && [[ ! "$2" =~ $check ]] && return 0
[[ "$2" =~ $check ]] && local default="[y/N]" || local default="[Y/n]"
read -p "$1 $default? " answer
case "$answer" in
y|Y|yes) return 0 ;;
n|N|no) return 1 ;;
'') [[ "$2" =~ $check ]] && return 1 || return 0 ;;
*) echo "invalid input: $answer" && return `agree "$1"` ;;
esac
}
pacman_install() {
sudo pacman -S --needed --noconfirm $1 > /dev/null
}
pip_install() {
pip install --user $1 > /dev/null
}
export PATH=~/.local/bin:$PATH
agree "Update pacman cache" && sudo pacman -Syy > /dev/null
agree "Upgrade pacman packages" "N" && sudo pacman -Syu > /dev/null
missing git && agree "Install git" && pacman_install git
if missing pip; then
agree "Install python-pip" && pacman_install python-pip
agree "Upgrade pip with pip" && \
sudo -H pip_install --upgrade pip > /dev/null
fi
missing virtualenv && agree "Install virtualenv" && pip_install virtualenv
if [ ! -f ~/.ssh/id_rsa ] && agree "Generate SSH key"; then
read -rp "SSH email: " email
[ ! -d ~/.ssh ] && mkdir -p ~/.ssh
ssh-keygen -t rsa -b 4096 -C "$email" -N "" -f ~/.ssh/id_rsa
fi
if ! missing virtualenv && agree "Set SSH keys on remote Git servers"; then
env=$(mktemp -d)
virtualenv $env > /dev/null
source $env/bin/activate
pip install git+https://code.infektor.net/config/bootstrap.git > /dev/null
python -c 'import bootstrap; bootstrap.set_ssh_keys()'
deactivate
rm -r $env
fi
missing conduit && agree "Install conduit" && \
pip_install git+ssh://git@github.com/kbenzie/conduit.git
echo "To use installed pip packages update your PATH:"
echo 'export PATH=~/.local/bin:$PATH'
[ -f $0 ] && agree "Remove $0" "N" && rm $0 || exit 0

View File

@@ -1,106 +0,0 @@
#!/bin/bash
set -e
show_usage() {
echo "usage: $0 [-h] [-y]"
}
show_help() {
show_usage
echo
echo "Bootstrap a Debian based distribution with:"
echo
echo "* update apt cache"
echo "* upgrade apt packages"
echo "* git - from apt"
echo "* python - from apt"
echo "* python-pip - from apt"
echo "* virtualenv - from pip"
echo "* SSH key - from ssh-keygen"
echo "* GitHub public key - with SSH key"
echo "* GitLab public key - with SSH key"
echo "* BitBucket Cloud public key - with SSH key"
echo "* Gogs Cloud public key - with SSH key"
echo "* conduit - configuration manager"
echo
echo "If any already exist they will not be reinstalled."
echo
echo "optional arguments:"
echo " -h show this help message and exit"
echo " -y assume yes when prompted"
}
yes=0
while getopts 'hy' opt; do
case $opt in
h) show_help; exit 0 ;;
y) yes=1 ;;
*) show_usage; exit 1 ;;
esac
done
missing() {
which $1 &> /dev/null && return 1 || return 0
}
agree() {
local check=^[Nn]$
[ $yes -eq 1 ] && [[ ! "$2" =~ $check ]] && return 0
[[ "$2" =~ $check ]] && local default="[y/N]" || local default="[Y/n]"
read -p "$1 $default? " answer
case "$answer" in
y|Y|yes) return 0 ;;
n|N|no) return 1 ;;
'') [[ "$2" =~ $check ]] && return 1 || return 0 ;;
*) echo "invalid input: $answer" && return `agree "$1"` ;;
esac
}
apt_install() {
sudo apt install --yes --install-recommends $1 > /dev/null
}
pip_install() {
pip install --user $1 > /dev/null
}
export PATH=~/.local/bin:$PATH
agree "Update apt cache" && sudo apt update > /dev/null
agree "Upgrade apt packages" "N" && sudo apt upgrade > /dev/null
missing git && agree "Install git" && apt_install git
if missing pip; then
agree "Install python-pip" && apt_install python-pip
agree "Upgrade pip with pip" && \
sudo -H pip_install --upgrade pip > /dev/null
fi
missing virtualenv && agree "Install virtualenv" && pip_install virtualenv
if [ ! -f ~/.ssh/id_rsa ] && agree "Generate SSH key"; then
read -rp "SSH email: " email
[ ! -d ~/.ssh ] && mkdir -p ~/.ssh
ssh-keygen -t rsa -b 4096 -C "$email" -N "" -f ~/.ssh/id_rsa
fi
if ! missing virtualenv && agree "Set SSH keys on remote Git servers"; then
env=$(mktemp -d)
virtualenv $env > /dev/null
source $env/bin/activate
pip install git+https://code.infektor.net/config/bootstrap.git > /dev/null
python -c 'import bootstrap; bootstrap.set_ssh_keys()'
deactivate
rm -r $env
fi
missing conduit && agree "Install conduit" && \
pip_install git+ssh://git@github.com/kbenzie/conduit.git
echo "To use installed pip packages update your PATH:"
echo 'export PATH=~/.local/bin:$PATH'
[ -f $0 ] && agree "Remove $0" "N" && rm $0 || exit 0

View File

@@ -1,102 +0,0 @@
#!/bin/bash
set -e
show_usage() {
echo "usage: $0 [-h] [-y]"
}
show_help() {
show_usage
echo
echo "Bootstrap a Debian based distribution with:"
echo
echo "* upgrade dnf packages"
echo "* git - from dnf"
echo "* virtualenv - from dnf"
echo "* SSH key - from ssh-keygen"
echo "* GitHub public key - with SSH key"
echo "* GitLab public key - with SSH key"
echo "* BitBucket Cloud public key - with SSH key"
echo "* Gogs Cloud public key - with SSH key"
echo "* conduit - configuration manager"
echo
echo "If any already exist they will not be reinstalled."
echo
echo "optional arguments:"
echo " -h show this help message and exit"
echo " -y assume yes when prompted"
}
yes=0
while getopts 'hy' opt; do
case $opt in
h) show_help; exit 0 ;;
y) yes=1 ;;
*) show_usage; exit 1 ;;
esac
done
missing() {
which $1 &> /dev/null && return 1 || return 0
}
agree() {
local check=^[Nn]$
[ $yes -eq 1 ] && [[ ! "$2" =~ $check ]] && return 0
[[ "$2" =~ $check ]] && local default="[y/N]" || local default="[Y/n]"
read -p "$1 $default? " answer
case "$answer" in
y|Y|yes) return 0 ;;
n|N|no) return 1 ;;
'') [[ "$2" =~ $check ]] && return 1 || return 0 ;;
*) echo "invalid input: $answer" && return `agree "$1"` ;;
esac
}
dnf_install() {
sudo dnf install --assumeyes $1
}
pip_install() {
pip install --user $1
}
export PATH=~/.local/bin:$PATH
agree "Upgrade dnf packages" "N" && sudo dnf upgrade
missing git && agree "Install git" && dnf_install git
if missing pip; then
agree "Install python3-pip" && dnf_install python3-pip
agree "Upgrade pip with pip" && \
sudo -H pip_install --upgrade pip
fi
missing virtualenv && agree "Install virtualenv" && pip_install virtualenv
if [ ! -f ~/.ssh/id_rsa ] && agree "Generate SSH key"; then
read -rp "SSH email: " email
[ ! -d ~/.ssh ] && mkdir -p ~/.ssh
ssh-keygen -t rsa -b 4096 -C "$email" -N "" -f ~/.ssh/id_rsa
fi
if ! missing virtualenv && agree "Set SSH keys on remote Git servers"; then
env=$(mktemp -d)
virtualenv $env > /dev/null
source $env/bin/activate
pip install git+https://code.infektor.net/config/bootstrap.git
python -c 'import bootstrap; bootstrap.set_ssh_keys()'
deactivate
rm -r $env
fi
missing conduit && agree "Install conduit" && \
pip_install git+ssh://git@github.com/kbenzie/conduit.git
echo "To use installed pip packages update your PATH:"
echo 'export PATH=~/.local/bin:$PATH'
[ -f $0 ] && agree "Remove $0" "N" && rm $0 || exit 0

91
bootstrap-Linux-rootless.sh Executable file
View File

@@ -0,0 +1,91 @@
#!/usr/bin/env bash
error() {
echo "$1 not found" >&2
exit 1
}
download() {
local url=$1
local output=$2
if command -v curl &> /dev/null; then
curl -o $output --location $url
elif command -v wget &> /dev/null; then
wget -O $output $url
else
error "curl/wget not found"
fi
}
download https://git.infektor.net/config/local/raw/branch/main/roles/bash/templates/bashrc ~/.bashrc
download https://git.infektor.net/config/local/raw/branch/main/roles/readline/templates/inputrc ~/.inputrc
if ! command -v git &> /dev/null; then
error "git not found"
fi
git-clone-or-pull() {
local repo=$1
local dir=$2
if [ -d $dir ]; then
git -C $dir pull
else
git clone $repo $dir
fi
}
git-clone-or-pull https://git.infektor.net/config/nvim.git ~/.config/nvim
# TODO: install nvim
git-clone-or-pull https://git.infektor.net/config/zsh.git ~/.config/zsh
# TODO: build & install zsh
if command -v zsh &> /dev/null; then
zsh ~/.config/zsh/install.zsh
fi
git-clone-or-pull https://git.infektor.net/config/tmux.git ~/.config/tmux
~/.config/tmux/install.sh
mkdir -p ~/.local/bin
mkdir -p ~/.local/share/man/man1
mkdir -p ~/.local/share/zsh/site-functions
if ! command -v rg &> /dev/null; then
mkdir -p ~/.cache/tmp
pushd ~/.cache/tmp
download https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-x86_64-unknown-linux-musl.tar.gz rg.tar.gz
tar zxf rg.tar.gz --strip-components=1 --no-same-owner
mv rg ~/.local/bin
mv doc/rg.1 ~/.local/share/man/man1/rg.1
mv complete/_rg ~/.local/share/zsh/site-functions
popd
rm -r ~/.cache/tmp
fi
if ! command -v fzf &> /dev/null; then
mkdir -p ~/.cache/tmp
pushd ~/.cache/tmp
download https://github.com/junegunn/fzf/releases/download/v0.64.0/fzf-0.64.0-linux_amd64.tar.gz fzf.tar.gz
tar zxf fzf.tar.gz
mv fzf ~/.local/bin
popd
rm -r ~/.cache/tmp
fi
if ! command -v bat &> /dev/null; then
mkdir -p ~/.cache/tmp
pushd ~/.cache/tmp
download https://github.com/sharkdp/bat/releases/download/v0.25.0/bat-v0.25.0-x86_64-unknown-linux-musl.tar.gz bat.tar.gz
tar zxf bat.tar.gz --strip-components=1 --no-same-owner
mv bat ~/.local/bin
mv bat.1 ~/.local/share/man/man1
mv autocomplete/bat.zsh ~/.local/share/zsh/site-functions/_bat
popd
rm -r ~/.cache/tmp
fi

77
bootstrap-Linux.sh Executable file
View File

@@ -0,0 +1,77 @@
#!/bin/bash
set -e
show_usage() {
echo "usage: $0 [-h] [-y]"
}
show_help() {
show_usage
echo
echo "Bootstrap Fedora or Debian-based Linux distribution with:"
echo
echo "* Update packages"
echo "* Install git, python3-pip"
echo "* Install ansible"
echo "* Clone configuration repository"
echo "* Install 1password"
echo
echo "If any already exist they will not be reinstalled."
echo
echo "optional arguments:"
echo " -h show this help message and exit"
echo " -y assume yes when prompted"
}
yes=0
while getopts 'hy' opt; do
case $opt in
h) show_help; exit 0 ;;
y) yes=1 ;;
*) show_usage; exit 1 ;;
esac
done
agree() {
local check=^[Nn]$
[ $yes -eq 1 ] && [[ ! "$2" =~ $check ]] && return 0
[[ "$2" =~ $check ]] && local default="[y/N]" || local default="[Y/n]"
read -p "$1 $default? " answer
case "$answer" in
y|Y|yes) return 0 ;;
n|N|no) return 1 ;;
'') [[ "$2" =~ $check ]] && return 1 || return 0 ;;
*) echo "invalid input: $answer" && return `agree "$1"` ;;
esac
}
if command -v apt &> /dev/null; then
agree "Update apt cache" && sudo apt-get update
agree "Upgrade apt packages" "N" && sudo apt-get upgrade
echo "Install git python3-pip"
sudo apt-get install --yes git python3-pip
fi
if command -v dnf &> /dev/null; then
agree "Upgrade dnf packages" "N" && sudo dnf upgrade
echo "Install git python3-pip"
sudo dnf install --assumeyes git python3-pip python3-libdnf5
fi
echo "Install ansible"
pip install --user --break-system-packages ansible jmespath
if [ ! -d ~/.config/local ]; then
echo "Clone configuration repository"
git clone https://git.infektor.net/config/local.git ~/.config/local
fi
if agree "Install 1password"; then
pushd ~/.config/local
~/.local/bin/ansible-playbook ~/.config/local/playbooks/1password.yaml
popd
fi
[ -f $0 ] && agree "Remove $0" "N" && rm $0 || exit 0

View File

@@ -11,11 +11,16 @@ if (-Not $IsElevated) {
Invoke-WebRequest -Uri https://get.scoop.sh -OutFile $ScoopInstaller
&$ScoopInstaller -ScoopDir "$env:LocalAppData/Scoop" -ScoopGlobalDir "$env:ProgramData/Scoop"
$Bootstrap = $MyInvocation.MyCommand.Path
$Decision = $Host.UI.PromptForChoice('Relaunch as Administrator', 'Proceed?', $Choices, 0)
if ($Decision -eq 0) {
$Bootstrap = $MyInvocation.MyCommand.Path
Start-Process powershell.exe "-ExecutionPolicy ByPass -NoProfile -File $Bootstrap" -Verb RunAs
}
$Decision = $Host.UI.PromptForChoice("Remove $Bootstrap", "Proceed?", $Choices, 1)
if ($Decision -eq 0) {
Remove-Item $Bootstrap -Force
}
} else {
Write-Host "Running as Administrator. Performing privileged actions."
@@ -26,24 +31,18 @@ if (-Not $IsElevated) {
Invoke-WebRequest -Uri "https://downloads.1password.com/win/1PasswordSetup-latest.exe" -OutFile "$1passwordInstaller"
&$1passwordInstaller
Remove-Item $1passwordInstaller
} else {
echo 'Skipping 1Password'
}
# Enable Hyper-V
$Decision = $Host.UI.PromptForChoice('Enable Hyper-V', 'Proceed?', $Choices, 0)
if ($Decision -eq 0) {
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
} else {
echo 'Skipping Hyper-V'
}
# Enable Containters
$Decision = $Host.UI.PromptForChoice('Enable Containers', 'Proceed?', $Choices, 0)
if ($Decision -eq 0) {
Enable-WindowsOptionalFeature -Online -FeatureName Containers -All
} else {
echo 'Skipping Containers'
}
# Install Chocolatey
@@ -56,8 +55,6 @@ if (-Not $IsElevated) {
choco install --yes "--package-parameters=/SSHServerFeature" openssh
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
} else {
echo 'Skipping SSH Server'
}
Write-Host 'Press any key to continue...'

View File

@@ -1,27 +0,0 @@
#!/usr/bin/env bash
# Copy SSH keys from Windows host.
cp -r /mnt/c/Users/Benie/.ssh ~/.ssh
chown benie:benie ~/.ssh
for file in ~/.ssh/*; do
chmod 0600 $file
done
# Upgrade Debian to unstable
sudo apt-get update
sudo apt-get upgrade --yes
sudo sed 's/stretch/buster/g' -i /etc/apt/sources.list
sudo apt-get update
sudo apt-get full-upgrade --yes
sudo sed 's/buster/bullseye/g' -i /etc/apt/sources.list
sudo apt-get update
sudo apt-get full-upgrade --yes
sudo sed 's/bullseye/unstable/g' -i /etc/apt/sources.list
sudo apt-get update
sudo apt-get full-upgrade --yes
# Install ansible
sudo apt-get install ansible git python3-apt python3-pip

View File

@@ -11,16 +11,13 @@ show_help() {
echo
echo "Bootstrap a macOS instance with:"
echo
echo "* Xcode command line developer tools"
echo "* Homebrew - package manager"
echo "* python - from Homebrew"
echo "* virtualenv - from pip"
echo "* SSH key - from ssh-keygen"
echo "* GitHub public key - with SSH key"
echo "* GitLab public key - with SSH key"
echo "* BitBucket Cloud public key - with SSH key"
echo "* Gogs Cloud public key - with SSH key"
echo "* conduit - configuration manager"
echo "* Install xcode command line developer tools"
echo "* Install homebrew"
echo "* Update packages"
echo "* Install python, pip"
echo "* Install ansible"
echo "* Clone configuration repository"
echo "* Install 1password"
echo
echo "If any already exist they will not be reinstalled."
echo
@@ -56,14 +53,6 @@ agree() {
esac
}
brew_install() {
brew install $1 > /dev/null
}
pip_install() {
pip install --user $1 > /dev/null
}
export PATH=~/.local/bin:$PATH
export PYTHONUSERBASE=~/.local
@@ -71,40 +60,23 @@ if ! xcode-select --print-path &> /dev/null; then
agree "Install Xcode command line developer tools" && xcode-select --install
fi
missing brew && agree "Intalll Homebrew" && /usr/bin/ruby -e \
missing brew && agree "Install homebrew" && /usr/bin/ruby -e \
"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
agree "Update Homebrew packages" && brew update > /dev/null
agree "Update homebrew packages" && brew update
brew install python
if missing /usr/local/bin/python2 && agree "Install Homebrew python"; then
brew_install python
export PATH=/usr/local/opt/python/libexec/bin:$PATH
echo "To use Homebrew python update your PATH:"
echo 'export PATH=/usr/local/opt/python/libexec/bin:$PATH'
# TODO: Update PATH for pip?
echo "Install ansible"
pip install --user --break-system-packages ansible jmespath
if [ ! -d ~/.config/local ]; then
echo "Clone configuration repository"
git clone https://git.infektor.net/config/local.git ~/.config/local
fi
missing virtualenv && agree "Install virtualenv" && pip_install virtualenv
if [ ! -f ~/.ssh/id_rsa ] && agree "Generate SSH key"; then
read -rp "SSH email: " email
[ ! -d ~/.ssh ] && mkdir -p ~/.ssh
ssh-keygen -t rsa -b 4096 -C "$email" -N "" -f ~/.ssh/id_rsa
fi
if ! missing virtualenv && agree "Set SSH keys on remote Git servers"; then
env=$(mktemp -d)
virtualenv $env &> /dev/null
source $env/bin/activate
pip install git+https://code.infektor.net/config/bootstrap.git > /dev/null
python -c 'import bootstrap; bootstrap.set_ssh_keys()'
deactivate
rm -r $env
fi
! missing pip && missing conduit && agree "Install conduit" && \
pip_install git+ssh://git@github.com/kbenzie/conduit.git
echo "To use installed pip packages update your PATH and PYTHONUSERBASE:"
echo 'export PATH=~/.local/bin:$PATH && export PYTHONUSERBASE=~/.local'
agree "Install 1password" && \
~/.local/bin/ansible-playbook ~/.config/local/playbooks/1password.yaml
[ -f $0 ] && agree "Remove $0" "N" && rm $0 || exit 0

View File

@@ -1,184 +0,0 @@
"""Interactively set SSH keys on remote Git servers."""
from __future__ import print_function
from getpass import getpass
from os import environ
from os.path import join
from platform import node, system
from requests import ConnectionError, get, post
from requests.auth import HTTPBasicAuth
from requests.compat import urlparse
try:
input = raw_input
except NameError:
pass
class BootstrapError(Exception):
"""Bootstrap Exception."""
pass
def bootstrap_error(response):
"""Create a BootstrapError from a Response."""
return BootstrapError('%s %s' % (response.status_code, response.reason))
def agree(question, default='Y'):
"""Prompt user to answer a yes/no question."""
valid = {
'y': True,
'Y': True,
'yes': True,
'n': False,
'N': False,
'no': False,
'': {'Y': True,
'N': False}[default]
}
answer = input('%s [%s]? ' % (question, {'Y': 'Y/n', 'N': 'y/N'}[default]))
try:
return valid[answer]
except KeyError:
print('invalid input: %s' % answer)
return agree(question)
def get_url(service, default):
"""Get URL."""
url = input('%s URL%s: ' % (service, ' (%s)' % default if default else ''))
if url == '':
if default:
return default
else:
print('invalid input: %s' % url)
return get_url(service, default)
return url
def get_username_password(service):
"""Get username/password."""
username = input('%s username: ' % service)
password = getpass('%s password: ' % service)
return (username, password)
def get_local_key():
"""Get local SSH key."""
if system() == 'Windows':
home = environ['userprofile']
else:
home = environ['HOME']
with open(join(home, '.ssh', 'id_rsa.pub'), 'r') as key_file:
return key_file.read().rstrip()
def key_exists(keys, local_key):
"""Check if local SSH key is already set."""
for key in keys:
if local_key.startswith(key['key']):
return True
return False
def set_github_ssh_key():
"""Set GitHub SSH key."""
url = urlparse(get_url('GitHub', 'https://github.com'))
keys_url = '%s://api.%s/user/keys' % (url.scheme, url.netloc)
username, password = get_username_password('GitHub')
auth = HTTPBasicAuth(username, password)
response = get(keys_url, auth=auth)
if response.status_code != 200:
raise bootstrap_error(response)
keys = response.json()
local_key = get_local_key()
if not key_exists(keys, local_key):
response = post(
keys_url, auth=auth, json={'title': node(),
'key': local_key})
if response.status_code != 201:
raise bootstrap_error(response)
def set_gitlab_ssh_key():
"""Set GitLab SSH key."""
api_url = '%s/api/v4' % get_url('GitLab', 'https://gitlab.com')
keys_url = '%s/user/keys' % api_url
username, password = get_username_password('GitLab')
credentials = {'login': username, 'password': password}
response = get(keys_url, credentials)
if response.status_code != 200:
raise bootstrap_error(response)
keys = response.json()
local_key = get_local_key()
if not key_exists(keys, local_key):
response = post(keys_url,
credentials,
json={
'title': node(),
'key': local_key
})
if response.status_code != 201:
raise bootstrap_error(response)
def set_bitbucket_cloud_ssh_key():
"""Set BitBucket Cloud SSH key."""
username, password = get_username_password('BitBucket Cloud')
keys_url = 'https://api.bitbucket.org/1.0/users/%s/ssh-keys' % username
auth = HTTPBasicAuth(username, password)
response = get(keys_url, auth=auth)
if response.status_code != 200:
raise bootstrap_error(response)
keys = response.json()
local_key = get_local_key()
if not key_exists(keys, local_key):
response = post(
keys_url, auth=auth, data={'label': node(),
'key': local_key})
if response.status_code != 200:
raise bootstrap_error(response)
def set_gogs_ssh_key():
"""Set Gogs SSH key."""
keys_url = '%s/api/v1/user/keys' % get_url('Gogs', None)
username, password = get_username_password('Gogs')
auth = HTTPBasicAuth(username, password)
response = get(keys_url, auth=auth)
if response.status_code != 200:
raise bootstrap_error(response)
keys = response.json()
local_key = get_local_key()
if not key_exists(keys, local_key):
response = post(
keys_url, auth=auth, json={'title': node(),
'key': local_key})
if response.status_code != 201:
raise bootstrap_error(response)
def set_ssh_keys():
"""Interactively set SSH keys on remote Git servers."""
try:
for service in ['GitHub', 'GitLab', 'BitBucket Cloud', 'Gogs']:
question = 'Set %s SSH key' % service
default = 'Y'
while agree(question, default):
try:
{
'GitHub': set_github_ssh_key,
'GitLab': set_gitlab_ssh_key,
'BitBucket Cloud': set_bitbucket_cloud_ssh_key,
'Gogs': set_gogs_ssh_key,
}[service]()
if service == 'BitBucket Cloud':
break
question = 'Set another %s SSH key' % service
default = 'N'
except (BootstrapError, ConnectionError) as error:
print('error: %s' % error.message)
except KeyboardInterrupt:
exit(130)

View File

@@ -1,11 +0,0 @@
"""Setup bootstrap package."""
from setuptools import find_packages, setup
setup(
name='bootstrap',
version='0.1.0',
packages=find_packages(),
install_requires=[
'requests',
])