Installer v2 (#3798)

* add initial advanced installer

* add symlink

* add dist detection

* make output uniform

* switch command to use wget
leave the installer on device

* regen script

* only install if not already there

* add os/version check
Closes #3835

* regenerate script

* fix case syntax

* fix typo

* rename assets to replace installer

* Add issue template for install problems

* Add link to open issue

* Update linked file
This commit is contained in:
Matthias Mair 2022-11-08 00:12:43 +01:00 committed by GitHub
parent 92260f2059
commit adcb975853
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 871 additions and 50 deletions

42
.github/ISSUE_TEMPLATE/install.yaml vendored Normal file
View File

@ -0,0 +1,42 @@
name: "Install problems"
description: "If you have problems deploying InvenTree"
labels: ["question", "triage:not-checked", "setup"]
body:
- type: checkboxes
id: deployment
attributes:
label: "Deployment Method"
options:
- label: "Installer"
- label: "Docker Development"
- label: "Docker Production"
- label: "Bare metal Development"
- label: "Bare metal Production"
- type: textarea
id: description
validations:
required: true
attributes:
label: "Describe the problem*"
description: "A clear and concise description of what is failing."
- type: textarea
id: steps-to-reproduce
validations:
required: true
attributes:
label: "Steps to Reproduce"
description: "Steps to reproduce the behavior, please make it detailed"
placeholder: |
0. Link to all docs you used
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
- type: textarea
id: logs
attributes:
label: "Relevant log output"
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: bash
validations:
required: false

View File

@ -139,7 +139,7 @@ There are several options to deploy InvenTree.
Single line install - read [the docs](https://inventree.readthedocs.io/en/latest/start/installer/) for supported distros and details about the function:
```bash
curl https://raw.githubusercontent.com/InvenTree/InvenTree/master/contrib/install.sh | sh
wget -Nq https://raw.githubusercontent.com/InvenTree/InvenTree/master/contrib/install.sh && bash install.sh
```
<!-- Contributing -->

View File

@ -1,54 +1,341 @@
get_distribution() {
lsb_dist=""
# Every system that we officially support has /etc/os-release
if [ -r /etc/os-release ]; then
lsb_dist="$(. /etc/os-release && echo "$ID")"
fi
# Returning an empty string here should be alright since the
# case statements don't act unless you provide an actual value
echo "$lsb_dist"
#!/usr/bin/env bash
# This script was generated by bashly 0.8.9 (https://bashly.dannyb.co)
# Modifying it manually is not recommended
# :wrapper.bash3_bouncer
if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
printf "bash version 4 or higher is required\n" >&2
exit 1
fi
# :command.master_script
# :command.root_command
root_command() {
# src/root_command.sh
# Settings
source_url=${args[source]}
publisher=${args[publisher]}
# Flags
no_call=${args[--no-call]}
dry_run=${args[--dry-run]}
REQS="wget apt-transport-https"
function do_call() {
if [[ $dry_run ]]; then
echo -e "### DRY RUN: \n$1"
else
$1
fi
}
function get_distribution {
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$NAME
VER=$VERSION_ID
elif type lsb_release >/dev/null 2>&1; then
OS=$(lsb_release -si)
VER=$(lsb_release -sr)
elif [ -f /etc/lsb-release ]; then
. /etc/lsb-release
OS=$DISTRIB_ID
VER=$DISTRIB_RELEASE
elif [ -f /etc/debian_version ]; then
OS=Debian
VER=$(cat /etc/debian_version)
elif [ -f /etc/SuSe-release ]; then
OS=SEL
elif [ -f /etc/redhat-release ]; then
OS=RedHat
else
OS=$(uname -s)
VER=$(uname -r)
fi
}
echo "### Installer for InvenTree - source: $publisher/$source_url"
# Check if os and version is supported
get_distribution
echo "### Detected distribution: $OS $VER"
NOT_SUPPORTED=false
case "$OS" in
Ubuntu)
if [[ $VER != "20.04" ]]; then
NOT_SUPPORTED=true
fi
;;
Debian | Raspbian)
if [[ $VER != "11" ]]; then
NOT_SUPPORTED=true
fi
;;
*)
echo "### Distribution not supported"
NOT_SUPPORTED=true
;;
esac
if [[ $NOT_SUPPORTED ]]; then
echo "This OS is currently not supported"
echo "please install manually using https://inventree.readthedocs.io/en/stable/start/install/"
echo "or check https://github.com/inventree/InvenTree/issues/3836 for packaging for your OS."
echo "If you think this is a bug please file an issue at"
echo "https://github.com/inventree/InvenTree/issues/new?template=install.yaml"
exit 1
fi
echo "### Installing required packages for download"
for pkg in $REQS; do
if dpkg-query -W -f'${Status}' "$pkg" 2>/dev/null | grep -q "ok installed"; then
true
else
do_call "sudo apt-get -yqq install $pkg"
fi
done
echo "### Adding key and package source"
# Add key
do_call "wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -"
# Add packagelist
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/${lsb_dist}/${dist_version}.repo"
echo "### Updateing package lists"
do_call "sudo apt-get update"
# Set up environment for install
echo "### Setting installer args"
if [[ $no_call ]]; then
do_call "export NO_CALL=true"
fi
echo "### Installing InvenTree"
do_call "sudo apt-get install inventree -y"
echo "### Install done!"
}
get_distribution
case "$lsb_dist" in
ubuntu)
if command_exists lsb_release; then
dist_version="$(lsb_release -r | cut -f2)"
fi
if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then
dist_version="$(. /etc/lsb-release && echo "$DISTRIB_RELEASE")"
fi
;;
debian | raspbian)
dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')"
lsb_dist="debian"
;;
centos | rhel | sles)
if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
fi
;;
*)
if command_exists lsb_release; then
dist_version="$(lsb_release --release | cut -f2)"
fi
if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
fi
;;
esac
echo "### ${lsb_dist} ${dist_version} detected"
# :command.version_command
version_command() {
echo "$version"
}
# Make sure the depencies are there
sudo apt-get install wget apt-transport-https -y
# :command.usage
install_usage() {
if [[ -n $long_usage ]]; then
printf "install - Interactive installer for InvenTree\n"
echo
echo "### Add key and package source"
# Add key
wget -qO- https://dl.packager.io/srv/matmair/InvenTree/key | sudo apt-key add -
# Add packagelist
sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/matmair/InvenTree/deploy-test/installer/${lsb_dist}/${dist_version}.repo
else
printf "install - Interactive installer for InvenTree\n"
echo
echo "### Install InvenTree"
# Update repos and install inventree
sudo apt-get update
sudo apt-get install inventree -y
fi
printf "Usage:\n"
printf " install [SOURCE] [PUBLISHER] [OPTIONS]\n"
printf " install --help | -h\n"
printf " install --version | -v\n"
echo
# :command.long_usage
if [[ -n $long_usage ]]; then
printf "Options:\n"
# :command.usage_fixed_flags
echo " --help, -h"
printf " Show this help\n"
echo
echo " --version, -v"
printf " Show version number\n"
echo
# :command.usage_flags
# :flag.usage
echo " --no-call, -n"
printf " Do not call outside APIs (only functionally needed)\n"
echo
# :flag.usage
echo " --dry-run, -d"
printf " Dry run (do not install anything)\n"
echo
# :command.usage_args
printf "Arguments:\n"
# :argument.usage
echo " SOURCE"
printf " Package source that should be used\n"
printf " Allowed: stable, master, main\n"
printf " Default: stable\n"
echo
# :argument.usage
echo " PUBLISHER"
printf " Publisher that should be used\n"
printf " Default: inventree\n"
echo
# :command.usage_examples
printf "Examples:\n"
printf " install\n"
printf " install master --no-call\n"
printf " install master matmair --dry-run\n"
echo
fi
}
# :command.normalize_input
normalize_input() {
local arg flags
while [[ $# -gt 0 ]]; do
arg="$1"
if [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then
input+=("${BASH_REMATCH[1]}")
input+=("${BASH_REMATCH[2]}")
elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then
input+=("${BASH_REMATCH[1]}")
input+=("${BASH_REMATCH[2]}")
elif [[ $arg =~ ^-([a-zA-Z0-9][a-zA-Z0-9]+)$ ]]; then
flags="${BASH_REMATCH[1]}"
for (( i=0 ; i < ${#flags} ; i++ )); do
input+=("-${flags:i:1}")
done
else
input+=("$arg")
fi
shift
done
}
# :command.inspect_args
inspect_args() {
readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
if (( ${#args[@]} )); then
echo args:
for k in "${sorted_keys[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done
else
echo args: none
fi
if (( ${#other_args[@]} )); then
echo
echo other_args:
echo "- \${other_args[*]} = ${other_args[*]}"
for i in "${!other_args[@]}"; do
echo "- \${other_args[$i]} = ${other_args[$i]}"
done
fi
}
# :command.command_functions
# :command.parse_requirements
parse_requirements() {
# :command.fixed_flags_filter
case "${1:-}" in
--version | -v )
version_command
exit
;;
--help | -h )
long_usage=yes
install_usage
exit
;;
esac
# :command.command_filter
action="root"
# :command.parse_requirements_while
while [[ $# -gt 0 ]]; do
key="$1"
case "$key" in
# :flag.case
--no-call | -n )
# :flag.case_no_arg
args[--no-call]=1
shift
;;
# :flag.case
--dry-run | -d )
# :flag.case_no_arg
args[--dry-run]=1
shift
;;
-?* )
printf "invalid option: %s\n" "$key" >&2
exit 1
;;
* )
# :command.parse_requirements_case
# :command.parse_requirements_case_simple
if [[ -z ${args[source]+x} ]]; then
args[source]=$1
shift
elif [[ -z ${args[publisher]+x} ]]; then
args[publisher]=$1
shift
else
printf "invalid argument: %s\n" "$key" >&2
exit 1
fi
;;
esac
done
# :command.default_assignments
[[ -n ${args[source]:-} ]] || args[source]="stable"
[[ -n ${args[publisher]:-} ]] || args[publisher]="inventree"
# :command.whitelist_filter
if [[ ! ${args[source]} =~ ^(stable|master|main)$ ]]; then
printf "%s\n" "source must be one of: stable, master, main" >&2
exit 1
fi
}
# :command.initialize
initialize() {
version="2.0"
long_usage=''
set -e
# src/initialize.sh
}
# :command.run
run() {
declare -A args=()
declare -a other_args=()
declare -a input=()
normalize_input "$@"
parse_requirements "${input[@]}"
if [[ $action == "root" ]]; then
root_command
fi
}
initialize
run "$@"

14
contrib/installer/README Normal file
View File

@ -0,0 +1,14 @@
The installer is generated using bashly.
## Installation
Check out the docs: https://bashly.dannyb.co/installation/
If you have ruby already installed run
```bash
gem install bashly
```
## Regenerate script
```bash
bashly generate
```

341
contrib/installer/install Executable file
View File

@ -0,0 +1,341 @@
#!/usr/bin/env bash
# This script was generated by bashly 0.8.9 (https://bashly.dannyb.co)
# Modifying it manually is not recommended
# :wrapper.bash3_bouncer
if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
printf "bash version 4 or higher is required\n" >&2
exit 1
fi
# :command.master_script
# :command.root_command
root_command() {
# src/root_command.sh
# Settings
source_url=${args[source]}
publisher=${args[publisher]}
# Flags
no_call=${args[--no-call]}
dry_run=${args[--dry-run]}
REQS="wget apt-transport-https"
function do_call() {
if [[ $dry_run ]]; then
echo -e "### DRY RUN: \n$1"
else
$1
fi
}
function get_distribution {
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$NAME
VER=$VERSION_ID
elif type lsb_release >/dev/null 2>&1; then
OS=$(lsb_release -si)
VER=$(lsb_release -sr)
elif [ -f /etc/lsb-release ]; then
. /etc/lsb-release
OS=$DISTRIB_ID
VER=$DISTRIB_RELEASE
elif [ -f /etc/debian_version ]; then
OS=Debian
VER=$(cat /etc/debian_version)
elif [ -f /etc/SuSe-release ]; then
OS=SEL
elif [ -f /etc/redhat-release ]; then
OS=RedHat
else
OS=$(uname -s)
VER=$(uname -r)
fi
}
echo "### Installer for InvenTree - source: $publisher/$source_url"
# Check if os and version is supported
get_distribution
echo "### Detected distribution: $OS $VER"
NOT_SUPPORTED=false
case "$OS" in
Ubuntu)
if [[ $VER != "20.04" ]]; then
NOT_SUPPORTED=true
fi
;;
Debian | Raspbian)
if [[ $VER != "11" ]]; then
NOT_SUPPORTED=true
fi
;;
*)
echo "### Distribution not supported"
NOT_SUPPORTED=true
;;
esac
if [[ $NOT_SUPPORTED ]]; then
echo "This OS is currently not supported"
echo "please install manually using https://inventree.readthedocs.io/en/stable/start/install/"
echo "or check https://github.com/inventree/InvenTree/issues/3836 for packaging for your OS."
echo "If you think this is a bug please file an issue at"
echo "https://github.com/inventree/InvenTree/issues/new?template=install.yaml"
exit 1
fi
echo "### Installing required packages for download"
for pkg in $REQS; do
if dpkg-query -W -f'${Status}' "$pkg" 2>/dev/null | grep -q "ok installed"; then
true
else
do_call "sudo apt-get -yqq install $pkg"
fi
done
echo "### Adding key and package source"
# Add key
do_call "wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -"
# Add packagelist
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/${lsb_dist}/${dist_version}.repo"
echo "### Updateing package lists"
do_call "sudo apt-get update"
# Set up environment for install
echo "### Setting installer args"
if [[ $no_call ]]; then
do_call "export NO_CALL=true"
fi
echo "### Installing InvenTree"
do_call "sudo apt-get install inventree -y"
echo "### Install done!"
}
# :command.version_command
version_command() {
echo "$version"
}
# :command.usage
install_usage() {
if [[ -n $long_usage ]]; then
printf "install - Interactive installer for InvenTree\n"
echo
else
printf "install - Interactive installer for InvenTree\n"
echo
fi
printf "Usage:\n"
printf " install [SOURCE] [PUBLISHER] [OPTIONS]\n"
printf " install --help | -h\n"
printf " install --version | -v\n"
echo
# :command.long_usage
if [[ -n $long_usage ]]; then
printf "Options:\n"
# :command.usage_fixed_flags
echo " --help, -h"
printf " Show this help\n"
echo
echo " --version, -v"
printf " Show version number\n"
echo
# :command.usage_flags
# :flag.usage
echo " --no-call, -n"
printf " Do not call outside APIs (only functionally needed)\n"
echo
# :flag.usage
echo " --dry-run, -d"
printf " Dry run (do not install anything)\n"
echo
# :command.usage_args
printf "Arguments:\n"
# :argument.usage
echo " SOURCE"
printf " Package source that should be used\n"
printf " Allowed: stable, master, main\n"
printf " Default: stable\n"
echo
# :argument.usage
echo " PUBLISHER"
printf " Publisher that should be used\n"
printf " Default: inventree\n"
echo
# :command.usage_examples
printf "Examples:\n"
printf " install\n"
printf " install master --no-call\n"
printf " install master matmair --dry-run\n"
echo
fi
}
# :command.normalize_input
normalize_input() {
local arg flags
while [[ $# -gt 0 ]]; do
arg="$1"
if [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then
input+=("${BASH_REMATCH[1]}")
input+=("${BASH_REMATCH[2]}")
elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then
input+=("${BASH_REMATCH[1]}")
input+=("${BASH_REMATCH[2]}")
elif [[ $arg =~ ^-([a-zA-Z0-9][a-zA-Z0-9]+)$ ]]; then
flags="${BASH_REMATCH[1]}"
for (( i=0 ; i < ${#flags} ; i++ )); do
input+=("-${flags:i:1}")
done
else
input+=("$arg")
fi
shift
done
}
# :command.inspect_args
inspect_args() {
readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
if (( ${#args[@]} )); then
echo args:
for k in "${sorted_keys[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done
else
echo args: none
fi
if (( ${#other_args[@]} )); then
echo
echo other_args:
echo "- \${other_args[*]} = ${other_args[*]}"
for i in "${!other_args[@]}"; do
echo "- \${other_args[$i]} = ${other_args[$i]}"
done
fi
}
# :command.command_functions
# :command.parse_requirements
parse_requirements() {
# :command.fixed_flags_filter
case "${1:-}" in
--version | -v )
version_command
exit
;;
--help | -h )
long_usage=yes
install_usage
exit
;;
esac
# :command.command_filter
action="root"
# :command.parse_requirements_while
while [[ $# -gt 0 ]]; do
key="$1"
case "$key" in
# :flag.case
--no-call | -n )
# :flag.case_no_arg
args[--no-call]=1
shift
;;
# :flag.case
--dry-run | -d )
# :flag.case_no_arg
args[--dry-run]=1
shift
;;
-?* )
printf "invalid option: %s\n" "$key" >&2
exit 1
;;
* )
# :command.parse_requirements_case
# :command.parse_requirements_case_simple
if [[ -z ${args[source]+x} ]]; then
args[source]=$1
shift
elif [[ -z ${args[publisher]+x} ]]; then
args[publisher]=$1
shift
else
printf "invalid argument: %s\n" "$key" >&2
exit 1
fi
;;
esac
done
# :command.default_assignments
[[ -n ${args[source]:-} ]] || args[source]="stable"
[[ -n ${args[publisher]:-} ]] || args[publisher]="inventree"
# :command.whitelist_filter
if [[ ! ${args[source]} =~ ^(stable|master|main)$ ]]; then
printf "%s\n" "source must be one of: stable, master, main" >&2
exit 1
fi
}
# :command.initialize
initialize() {
version="2.0"
long_usage=''
set -e
# src/initialize.sh
}
# :command.run
run() {
declare -A args=()
declare -a other_args=()
declare -a input=()
normalize_input "$@"
parse_requirements "${input[@]}"
if [[ $action == "root" ]]; then
root_command
fi
}
initialize
run "$@"

View File

@ -0,0 +1,28 @@
name: install
help: Interactive installer for InvenTree
version: 2.0
args:
- name: source
help: Package source that should be used
default: stable
allowed:
- stable
- master
- main
- name: publisher
help: Publisher that should be used
default: inventree
flags:
- long: --no-call
short: -n
help: Do not call outside APIs (only functionally needed)
- long: --dry-run
short: -d
help: Dry run (do not install anything)
examples:
- install
- install master --no-call
- install master matmair --dry-run

View File

@ -0,0 +1,6 @@
## Code here runs inside the initialize() function
## Use it for anything that you need to run before any other function, like
## setting environment variables:
## CONFIG_FILE=settings.ini
##
## Feel free to empty (but not delete) this file.

View File

@ -0,0 +1,103 @@
# Settings
source_url=${args[source]}
publisher=${args[publisher]}
# Flags
no_call=${args[--no-call]}
dry_run=${args[--dry-run]}
REQS="wget apt-transport-https"
function do_call() {
if [[ $dry_run ]]; then
echo -e "### DRY RUN: \n$1"
else
$1
fi
}
function get_distribution {
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$NAME
VER=$VERSION_ID
elif type lsb_release >/dev/null 2>&1; then
OS=$(lsb_release -si)
VER=$(lsb_release -sr)
elif [ -f /etc/lsb-release ]; then
. /etc/lsb-release
OS=$DISTRIB_ID
VER=$DISTRIB_RELEASE
elif [ -f /etc/debian_version ]; then
OS=Debian
VER=$(cat /etc/debian_version)
elif [ -f /etc/SuSe-release ]; then
OS=SEL
elif [ -f /etc/redhat-release ]; then
OS=RedHat
else
OS=$(uname -s)
VER=$(uname -r)
fi
}
echo "### Installer for InvenTree - source: $publisher/$source_url"
# Check if os and version is supported
get_distribution
echo "### Detected distribution: $OS $VER"
NOT_SUPPORTED=false
case "$OS" in
Ubuntu)
if [[ $VER != "20.04" ]]; then
NOT_SUPPORTED=true
fi
;;
Debian | Raspbian)
if [[ $VER != "11" ]]; then
NOT_SUPPORTED=true
fi
;;
*)
echo "### Distribution not supported"
NOT_SUPPORTED=true
;;
esac
if [[ $NOT_SUPPORTED ]]; then
echo "This OS is currently not supported"
echo "please install manually using https://inventree.readthedocs.io/en/stable/start/install/"
echo "or check https://github.com/inventree/InvenTree/issues/3836 for packaging for your OS."
echo "If you think this is a bug please file an issue at"
echo "https://github.com/inventree/InvenTree/issues/new?template=install.yaml"
exit 1
fi
echo "### Installing required packages for download"
for pkg in $REQS; do
if dpkg-query -W -f'${Status}' "$pkg" 2>/dev/null | grep -q "ok installed"; then
true
else
do_call "sudo apt-get -yqq install $pkg"
fi
done
echo "### Adding key and package source"
# Add key
do_call "wget -qO- https://dl.packager.io/srv/$publisher/InvenTree/key | sudo apt-key add -"
# Add packagelist
do_call "sudo wget -O /etc/apt/sources.list.d/inventree.list https://dl.packager.io/srv/$publisher/InvenTree/$source_url/installer/${lsb_dist}/${dist_version}.repo"
echo "### Updateing package lists"
do_call "sudo apt-get update"
# Set up environment for install
echo "### Setting installer args"
if [[ $no_call ]]; then
do_call "export NO_CALL=true"
fi
echo "### Installing InvenTree"
do_call "sudo apt-get install inventree -y"
echo "### Install done!"