diff --git a/README.md b/README.md
index 28cbf6151..55d672385 100644
--- a/README.md
+++ b/README.md
@@ -27,31 +27,61 @@
-
+
+
+
- Soar is a Fast, Modern, Bloat-Free Distro-Independent Package Manager that Just Works
- Supports Static Binaries, AppImages, and other Portable formats on any *Unix-based Distro
+ Soar is a Fast, Modern, Bloat-Free Distro-Independent Package Manager that Just Works
+ Supports Static Binaries, AppImages, and other Portable formats on any *Unix-based Distro
-# Soar Package Manager
+
+## 🪄 Quickstart
+
+> [!TIP]
+> - Soar comes as a single-file, statically-linked executable with no dependencies that you can simply [download](https://github.com/pkgforge/soar/releases/latest) & run.
+> - The [install script](https://github.com/pkgforge/soar/blob/main/install.sh) does this & more automatically for you.
+
+```bash
+❯ cURL
+curl -fsSL "https://raw.githubusercontent.com/pkgforge/soar/main/install.sh" | sh
+
+❯ wget
+wget -qO- "https://raw.githubusercontent.com/pkgforge/soar/main/install.sh" | sh
+```
+
+> [!NOTE]
+> - Please read & verify what's inside the script before running it
+> - The script is also available through https://soar.qaidvoid.dev/install.sh & https://soar.pkgforge.dev/install.sh
+> - Additionally, if you want to customize your installation, please read the docs @ https://soar.qaidvoid.dev/installation.html
+> - For, extra Guide & Information on infra backends & adding more repos: https://docs.pkgforge.dev
+> - Next, Check [Configuration](https://soar.qaidvoid.dev/configuration) & [Usage](https://soar.qaidvoid.dev/package-management)
## 🌟 Key Features
+> [!TIP]
+> - The comparison page @ https://docs.pkgforge.dev/soar/readme goes into more detail.
+
| Feature | Description |
|:--:|:--|
| **Universal Package Format Support** | Soar can install and manage portable package formats including [static binaries](https://docs.pkgforge.dev/formats/binaries/static), [self-extractable archives](https://docs.pkgforge.dev/formats/packages/archive), and [AppImages](https://docs.pkgforge.dev/formats/packages/appimage). |
| **System Integration** | Soar [automatically integrates](https://soar.qaidvoid.dev/#desktop-integration) installed packages with your system to provide a native-like experience. |
| **Flexible Repository System** | While Soar comes preconfigured with [official repositories](https://docs.pkgforge.dev/repositories), you can [configure custom repositories](https://soar.qaidvoid.dev/configuration#custom-repository-support) that use any build format as long as they provide compatible metadata. The `.SBUILD` format is only required for the official repositories, not for custom ones. |
| **Security First** | Soar enforces security through checksums and signing verification for package installations. |
+| **Userspace** | Soar works completely in Userspace without Superuser (admin/sudo) Privileges. |
| **External Repository Support** | Soar can access packages from sources like [ivan-hc/AM](https://github.com/ivan-hc/AM) and [appimage.github.io](https://github.com/AppImage/appimage.github.io) through metadata provided by pkgforge. These external sources don't directly work with soar but are made compatible through pkgforge's metadata conversion. **Note:** Packages from external repositories are not verified. |
| **Fast Package Operations** | Soar provides efficient package searching, installation, and management with minimal overhead. |
-## 📦 Packages Available Through Official Repositories
+## 📦 Packages
-Packages in the official Soar repositories have these characteristics:
+> [!TIP]
+> Check out the detailed documentation @ https://docs.pkgforge.dev/repositories/soarpkgs
| Feature | Description |
|:--:|:--|
@@ -65,57 +95,58 @@ Packages in the official Soar repositories have these characteristics:
| **Decentralized** | The portable nature of packages means they can be downloaded and used independently of Soar if needed. |
## ☢️ Caveats
-#### Soar doesn't reinvent things
-Soar isn't a package manager in the traditional sense, neither is it a [new standard](https://xkcd.com/927/), thus soar doesn't handle core system tools/libraries by design.
-This means soar is not a replacement for your distro's official package manager.
-Instead, Soar complements existing package managers by providing your distro with additional packages or newer version of packages that your distro may not provide.
-Soar is meant to coexist with existing package managers by avoiding conflicts, being completely functional in userspace & using XDG Specifications.
-For more questions, check our [FAQ](https://docs.pkgforge.dev/repositories/soarpkgs/faq) or [create a discussion](https://github.com/pkgforge/soar/discussions).
-## 🔧 Installation
+> [!NOTE]
+> - If you have additional questions, check our [FAQ](https://docs.pkgforge.dev/repositories/soarpkgs/faq) or [create a discussion](https://github.com/pkgforge/soar/discussions).
-Soar comes as a single-file, statically-linked executable with no dependencies that you can simply [download](https://github.com/pkgforge/soar/releases/latest) & run.
-- Docs: https://soar.qaidvoid.dev/installation.html
-- Extra Guide & Information: https://docs.pkgforge.dev
+| Design Decisions | The Rationale |
+|:--:|:--|
+| **Not Reinvent things** | Soar isn't a package manager in the traditional sense, neither is it a [new standard](https://xkcd.com/927/). Think of soar as an amalgamation & the natural progression of tools like [AM](https://github.com/ivan-hc/AM), [bin](https://github.com/marcosnils/bin), [eget](https://github.com/zyedidia/eget), [hysp](https://github.com/pwnwriter/hysp), [nami](https://github.com/txthinking/nami) & [zap](https://github.com/srevinsaju/zap). |
+| **Not a System Package Manager** | Soar intentionally complements rather than replaces your distro's package manager. Unlike [Homebrew](https://github.com/Homebrew/brew), we don't handle core system tools/libraries — we let distro package managers excel at that job. Soar provides additional packages or newer versions while avoiding conflicts by operating entirely in userspace and following XDG specifications. |
+| **Not a Devtools Manager** | Soar doesn't handle development toolchains by design. We do have completely static/relocatable toolchains in our repo, but it will always be better to just use dedicated tools like [asdf](https://github.com/asdf-vm/asdf), [aqua](https://github.com/aquaproj/aqua), [chsrc](https://github.com/RubyMetric/chsrc), [mise](https://github.com/jdx/mise), [vfox](https://github.com/version-fox/vfox) etc. |
-## ⚙️ Configuration
+## 🐞 Bug Reports & Feature Requests
-Soar comes with [sane defaults](https://soar.qaidvoid.dev/configuration.html) & [official repositories](https://docs.pkgforge.dev/repositories/) preconfigured
-For additional configuration guide, see [here](https://soar.qaidvoid.dev/configuration.html)
+> [!WARNING]
+> For reporting any issues related to packaging (Not Soar Core), please use our [Official package repository](https://docs.pkgforge.dev/repositories) at [pkgforge/soarpkgs](https://github.com/pkgforge/soarpkgs).
-## 🎯 Usage
+Soar is a FOSS project primarily maintained by [@QaidVoid](https://github.com/QaidVoid) & a few other [core contributors](https://github.com/pkgforge/soar/graphs/contributors), who are all volunteers and do it as a hobby.
+To save our time triaging & to ensure your issue/feature-request gets addressed quickly, make sure to:
+- Search the [Issues](https://github.com/pkgforge/soar/issues) & [Discussion](https://github.com/pkgforge/soar/discussions?discussions_q=) tab (Both Closed/Opened) for same/similar issue in case it was already addressed.
+- [Open a Discussion](https://github.com/pkgforge/soar/discussions/new/choose) instead of an issue if you have a question. Issues should be only created for bug reports and feature requests.
+- Use our [Issue Templates](https://github.com/pkgforge/soar/issues/new/choose) rather than a blank issue.
-Simply run `soar --help` for general options.
-- General Guide & Manual is maintained at: [soar.qaidvoid.dev](https://soar.qaidvoid.dev/)
-- Detailed guide regarding each format is at: [docs.pkgforge.dev](https://docs.pkgforge.dev/formats/packages)
+> [!NOTE]
+> - We assign a specific [priority level (`p0-p3`)](https://github.com/pkgforge/soar/labels) for each [valid issue](https://github.com/pkgforge/soar/issues) created.
+> - Based on the assigned [priority level (`p0-p3`)](https://github.com/pkgforge/soar/labels) & our free time, we will do our best to respond/address it.
+> - However, this is not a guarantee or an [SLA](https://en.wikipedia.org/wiki/Service-level_agreement). Please have patience & wait before tagging us again for a response. We thank you for your understanding.
-## 📦 Packages
-For reporting any issues related to packaging, please use our [Official package repository](https://docs.pkgforge.dev/repositories) at [pkgforge/soarpkgs](https://github.com/pkgforge/soarpkgs).
## 💬 Community
-Be a part of our community to interact with our team, get quick help, and share your ideas
+We have a growing community on discord to discuss not only Soar/Pkgforge but also other cool projects, feel free to join & hangout anytime.
- [](https://discord.gg/djJUs48Zbu)
- Other Channels: https://docs.pkgforge.dev/contact/chat
## 🤝 Contributing
-We welcome contributions! Please feel free to fork the repository and submit
-pull requests. If you have suggestions or feature requests, open an [discussion](https://github.com/pkgforge/soar/discussions) to
-discuss.
+> [!WARNING]
+> While we welcome contributions of all kinds, please read [CONTRIBUTING.md](https://github.com/pkgforge/soar/blob/main/CONTRIBUTING.md) before submitting us a PR.
Please feel free to:
1. Fork the repository
2. Create your feature branch
3. Submit a pull request
+## 📊 Repo Stats
+

[](https://github.com/pkgforge/soar/stargazers)
[](https://starchart.cc/pkgforge/soar)
## 📝 License
-This project is licensed under [MIT](https://spdx.org/licenses/MIT.html) - see the [LICENSE](LICENSE) file for details.
+This project is licensed under [MIT](https://spdx.org/licenses/MIT.html) - see the [LICENSE](LICENSE) file for details.
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fpkgforge%2Fsoar?ref=badge_large)
## Minimum Supported Rust Version (MSRV)
diff --git a/install.sh b/install.sh
index cdf882f5e..3d309924b 100755
--- a/install.sh
+++ b/install.sh
@@ -2,256 +2,385 @@
# Soar Installation Script (v1.0.0)
# Tries to be as POSIX compliant as possible (Any deviation is intentional)
# Assumptions: User has a supported downloader
-# Supported Downloaders:
+# Supported Downloaders:
# aria2 (aria2c) axel bash (/dev/tcp) busybox curl http (httpie) nushell (http) perl (libww) python/python3 soar-dl soar wget
# If no supported downloaders are found (happens often), a fallback to bash+sed or nushell is used
set -eu
#shellcheck disable=SC2016,SC2059
main() {
- DEFAULT_VERSION="latest"
- SOAR_VERSION="${SOAR_VERSION:-$DEFAULT_VERSION}"
- # ASCII Colors
- RED="\033[0;31m"
- GREEN="\033[0;32m"
- BLUE="\033[0;34m"
- YELLOW="\033[0;33m"
- RESET="\033[0m"
+ # Enable Debug?
+ DEBUG="${DEBUG:-}"
+ if [ -n "$DEBUG" ]; then
+ set -x
+ fi
- # Function to check for a downloader, sorted by sanest choice
- check_download_tool() {
- if command -v curl >/dev/null 2>&1; then
- printf "curl -fSL -o"
- return 0
- elif command -v wget >/dev/null 2>&1; then
- printf "wget -O"
- return 0
- elif command -v soar-dl >/dev/null 2>&1; then
- printf "soar-dl -o"
- return 0
- elif command -v soar >/dev/null 2>&1; then
- printf "soar dl -o"
- return 0
- elif command -v aria2 >/dev/null 2>&1; then
- printf "aria2 -o"
- return 0
- elif command -v aria2c >/dev/null 2>&1; then
- printf "aria2c -o"
- return 0
- elif command -v axel >/dev/null 2>&1; then
- printf "axel -o"
- return 0
- elif command -v http >/dev/null 2>&1; then
- printf "http -Fdm -o"
- return 0
- elif command -v nu >/dev/null 2>&1; then
- printf "NU_HTTP"
- return 0
- elif command -v GET >/dev/null 2>&1; then
- printf "PERL_GET"
- return 0
- elif command -v python >/dev/null 2>&1; then
- printf "PYTHON_GET"
- return 0
- elif command -v python3 >/dev/null 2>&1; then
- printf "PYTHON3_GET"
- return 0
- elif command -v busybox >/dev/null 2>&1; then
- printf "busybox wget --no-check-certificate -O"
- return 0
- elif command -v bash >/dev/null 2>&1 && command -v sed >/dev/null 2>&1; then
- printf "BASH_DEV_TCP"
- return 0
- else
- printf "${RED}✗ Error: Could not find a downloader (curl, wget, soar-dl, aria2, axel, httpie, perl, python, busybox).${RESET}\n" >&2
- return 1
- fi
- }
+ # Default
+ DEFAULT_VERSION="latest"
+ SOAR_VERSION="${SOAR_VERSION:-$DEFAULT_VERSION}"
- # Function to determine installation directory
- get_install_dir() {
- # Check environment variables first
- if [ -n "${SOAR_INSTALL_DIR-}" ]; then
- if [ -d "$SOAR_INSTALL_DIR" ] && [ -w "$SOAR_INSTALL_DIR" ]; then
- printf "%s" "$SOAR_INSTALL_DIR"
- return
- else
- printf "${RED}✗ Error: SOAR_INSTALL_DIR ${BLUE}($SOAR_INSTALL_DIR)${RED} is not writable or doesn't exist${RESET}\n" >&2
- exit 1
- fi
- fi
- if [ -n "${INSTALL_DIR-}" ]; then
- if [ -d "$INSTALL_DIR" ] && [ -w "$INSTALL_DIR" ]; then
- printf "%s" "$INSTALL_DIR"
- return
- else
- printf "${RED}✗ Error: INSTALL_DIR ${BLUE}($INSTALL_DIR)${RED} is not writable or doesn't exist${RESET}\n" >&2
- exit 1
- fi
- fi
+ # ASCII Colors
+ RED="\033[0;31m"
+ GREEN="\033[0;32m"
+ BLUE="\033[0;34m"
+ YELLOW="\033[0;33m"
+ RESET="\033[0m"
- # Check ~/.local/bin
- local_bin="$HOME/.local/bin"
- if [ -d "$local_bin" ] && [ -w "$local_bin" ]; then
- printf "%s" "$local_bin"
- return
- fi
+ # Refresh command -v
+ if command -v hash >/dev/null 2>&1; then
+ hash -r >/dev/null 2>&1
+ fi
- # Fallback to /usr/local/bin if running as root
- if [ "$(id -u)" = "0" ]; then
- if [ -d "/usr/local/bin" ] && [ -w "/usr/local/bin" ]; then
- printf "/usr/local/bin"
- return
- fi
- fi
+ # Ensure HOME
+ if [ -z "$HOME" ]; then
+ printf "${YELLOW}⚠ Notice: ${BLUE}\$HOME${YELLOW} is not set. (Will try guessing...)${RESET}\n" >&2
- # Fallback to current directory
- printf "${YELLOW}⚠ Notice: ${BLUE}~/.local/bin${YELLOW} not found or not writable. Installing in current directory.${RESET}\n" >&2
- printf "${YELLOW}You should move the binary to a location in your ${BLUE}\$PATH.${RESET}\n" >&2
- printf "%s" "$(pwd)"
- }
+ case $(
+ command -v awk getent grep tr whoami >/dev/null 2>&1
+ echo $?
+ ) in
+ 0)
+ [ -z "$USER" ] && {
+ printf "${YELLOW}⚠ Notice: ${BLUE}\$USER${YELLOW} is not set. (Will try guessing...)${RESET}\n" >&2
+ USER="$(whoami | tr -d '[:space:]')"
+ }
+ HOME="$(getent passwd "$USER" | awk -F':' 'NF >= 6 {print $6}' | tr -d '[:space:]')"
+ ;;
+ esac
- # Function to download and install
- install_soar() {
- DOWNLOAD_TOOL=""
- if ! DOWNLOAD_TOOL=$(check_download_tool); then
- exit 1
- fi
- INSTALL_PATH=$(get_install_dir)
+ if [ ! -d "$HOME" ]; then
+ printf "${RED}✗ Error: Could not determine ${BLUE}\$HOME${RESET}\n" >&2
+ else
+ printf "${YELLOW}⚠ Notice: ${BLUE}\$HOME${YELLOW} is set to ${BLUE}$HOME${RESET}\n" >&2
+ fi
+ fi
- # Detect architecture
- ARCH=$(uname -m)
- case "$ARCH" in
- x86_64)
- ARCH="x86_64"
- ;;
- aarch64)
- ARCH="aarch64"
- ;;
- *)
- printf "${RED}Error: Unsupported architecture: ${YELLOW}$ARCH${RESET}\n" >&2
- exit 1
- ;;
- esac
+ # Check XDG/Fallback Vars & Perms
+ for var in X_BIN X_CONFIG X_CACHE X_DATA; do
+ dir_var=""
+ dir_path=""
- # Get latest release URL
- printf "Downloading Soar..."
- case "$SOAR_VERSION" in
- *nightly*)
- RELEASE_URL="https://github.com/pkgforge/soar/releases/download/nightly/soar-$ARCH-linux"
- ;;
- *latest*)
- RELEASE_URL="https://github.com/pkgforge/soar/releases/latest/download/soar-$ARCH-linux"
- ;;
- *)
- RELEASE_URL="https://github.com/pkgforge/soar/releases/download/v$SOAR_VERSION/soar-$ARCH-linux"
- ;;
- esac
- printf " <== $RELEASE_URL\n"
+ case $var in
+ X_BIN)
+ dir_var="BIN_DIR"
+ xdg_var="XDG_BIN_HOME"
+ fallback="$HOME/.local/bin"
+ ;;
+ X_CONFIG)
+ dir_var="CONFIG_DIR"
+ xdg_var="XDG_CONFIG_HOME"
+ fallback="$HOME/.config"
+ ;;
+ X_CACHE)
+ dir_var="CACHE_DIR"
+ xdg_var="XDG_CACHE_HOME"
+ fallback="$HOME/.cache"
+ ;;
+ X_DATA)
+ dir_var="DATA_DIR"
+ xdg_var="XDG_DATA_HOME"
+ fallback="$HOME/.local/share"
+ ;;
+ esac
- # Download and install
- if [ "$DOWNLOAD_TOOL" = "NU_HTTP" ]; then
- printf "[+] Using HTTP (nushell)\n"
- RELEASE_URL="http://http.pkgforge.dev/$RELEASE_URL" INSTALL_PATH="$INSTALL_PATH" nu --no-config-file -c \
- 'http get --redirect-mode follow --insecure --raw $env.RELEASE_URL | save -f ($env.INSTALL_PATH + "/soar")'
- printf "\n"
- elif [ "$DOWNLOAD_TOOL" = "PERL_GET" ]; then
- printf "[+] Using GET\n"
- GET "$RELEASE_URL" > "$INSTALL_PATH/soar"
- printf "\n"
- elif [ "$DOWNLOAD_TOOL" = "PYTHON_GET" ]; then
- printf "[+] Using python -c\n"
- python -c "import urllib.request; urllib.request.urlretrieve('$RELEASE_URL', '$INSTALL_PATH/soar')"
- printf "\n"
- elif [ "$DOWNLOAD_TOOL" = "PYTHON3_GET" ]; then
- printf "[+] Using python3 -c\n"
- python3 -c "import urllib.request; urllib.request.urlretrieve('$RELEASE_URL', '$INSTALL_PATH/soar')"
- printf "\n"
- elif [ "$DOWNLOAD_TOOL" = "BASH_DEV_TCP" ]; then
- printf "\n${YELLOW}⚠ Attempting to download using ${BLUE}Bash${YELLOW} (${GREEN}/dev/tcp${YELLOW}) over HTTP${RESET}\n" >&2
- printf "${YELLOW}⚠ This is highly unreliable & may not Work${RESET}\n\n" >&2
- RELEASE_URL="http://http.pkgforge.dev/$RELEASE_URL" INSTALL_PATH="$INSTALL_PATH" bash -c \
- '
- raw_http_get() {
- #Get Input
- url=$1
- port=${2:-80}
- #Actually Verify we are in bash
- is_bash=0
- [[ -n "${BASH}" ]] && is_bash=1
- if [[ $is_bash -eq 0 ]]; then
- (shopt -p >/dev/null 2>&1) && is_bash=1
- fi
- #Proceed
- if [ $is_bash -eq 1 ]; then
- #Parse Input
- url=${url#http://}
- url=${url#https://}
- host=${url%%/*}
- if [[ "$url" = "$host" ]]; then
- path="/"
- else
- path="/${url#$host/}"
- fi
- #Download
- exec 3<>/dev/tcp/$host/$port
- echo -e "GET $path HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n" >&3
- if command -v dd >/dev/null 2>&1; then
- dd bs=1K <&3
- elif command -v cat >/dev/null 2>&1; then
- cat <&3
- fi
- exec 3>&-
+ xdg_value=""
+ eval "xdg_value=\"\${$xdg_var:-}\""
+
+ if [ -n "$xdg_value" ]; then
+ xdg_path="$xdg_value"
+ mkdir -p "$xdg_path" >/dev/null 2>&1
+ if [ -d "$xdg_path" ] && [ -w "$xdg_path" ]; then
+ eval "$dir_var=\"$xdg_path\""
+ continue
+ fi
+ fi
+
+ if [ -n "$HOME" ]; then
+ mkdir -p "$fallback" >/dev/null 2>&1
+ if [ -d "$fallback" ] && [ -w "$fallback" ]; then
+ eval "$dir_var=\"$fallback\""
+ fi
+ fi
+ done
+
+ # Check for a downloader, sorted by sanest choice
+ check_download_tool() {
+ if command -v curl >/dev/null 2>&1; then
+ printf "curl -fSL -o"
+ return 0
+ elif command -v wget >/dev/null 2>&1; then
+ printf "wget -O"
+ return 0
+ elif command -v soar-dl >/dev/null 2>&1; then
+ printf "soar-dl -o"
+ return 0
+ elif command -v soar >/dev/null 2>&1; then
+ printf "soar dl -o"
+ return 0
+ elif command -v aria2 >/dev/null 2>&1; then
+ printf "aria2 -o"
+ return 0
+ elif command -v aria2c >/dev/null 2>&1; then
+ printf "aria2c -o"
+ return 0
+ elif command -v axel >/dev/null 2>&1; then
+ printf "axel -o"
+ return 0
+ elif command -v http >/dev/null 2>&1; then
+ printf "http -Fdm -o"
+ return 0
+ elif command -v nu >/dev/null 2>&1; then
+ printf "NU_HTTP"
+ return 0
+ elif command -v GET >/dev/null 2>&1; then
+ printf "PERL_GET"
+ return 0
+ elif command -v python >/dev/null 2>&1; then
+ printf "PYTHON_GET"
+ return 0
+ elif command -v python3 >/dev/null 2>&1; then
+ printf "PYTHON3_GET"
+ return 0
+ elif command -v busybox >/dev/null 2>&1; then
+ printf "busybox wget --no-check-certificate -O"
+ return 0
+ elif command -v bash >/dev/null 2>&1 && command -v sed >/dev/null 2>&1; then
+ printf "BASH_DEV_TCP"
+ return 0
+ else
+ printf "${RED}✗ Error: Could not find a downloader (curl, wget, soar-dl, aria2, axel, httpie, perl, python, busybox).${RESET}\n" >&2
+ return 1
+ fi
+ }
+
+ # Determine installation directory
+ get_install_dir() {
+ # Check environment variables first
+ if [ -n "${SOAR_INSTALL_DIR-}" ]; then
+ if [ -d "$SOAR_INSTALL_DIR" ] && [ -w "$SOAR_INSTALL_DIR" ]; then
+ printf "%s" "$SOAR_INSTALL_DIR"
+ return
+ else
+ printf "${RED}✗ Error: SOAR_INSTALL_DIR ${BLUE}($SOAR_INSTALL_DIR)${RED} is not writable or doesn't exist${RESET}\n" >&2
+ exit 1
+ fi
+ fi
+ if [ -n "${INSTALL_DIR-}" ]; then
+ if [ -d "$INSTALL_DIR" ] && [ -w "$INSTALL_DIR" ]; then
+ printf "%s" "$INSTALL_DIR"
+ return
+ else
+ printf "${RED}✗ Error: INSTALL_DIR ${BLUE}($INSTALL_DIR)${RED} is not writable or doesn't exist${RESET}\n" >&2
+ exit 1
+ fi
+ fi
+
+ # Check Writable BIN Dir
+ if [ -n "$BIN_DIR" ]; then
+ if [ -d "$BIN_DIR" ] && [ -w "$BIN_DIR" ]; then
+ printf "%s" "$BIN_DIR"
+ return
+ fi
+ fi
+
+ # Fallback to /usr/local/bin if running as root
+ if [ "$(id -u)" = "0" ]; then
+ if [ -d "/usr/local/bin" ] && [ -w "/usr/local/bin" ]; then
+ printf "/usr/local/bin"
+ return
+ fi
+ fi
+
+ # Fallback to current directory
+ printf "${YELLOW}⚠ Notice: ${BLUE}~/.local/bin${YELLOW} not found or not writable. Installing in current directory.${RESET}\n" >&2
+ printf "${YELLOW}You should move the binary to a location in your ${BLUE}\$PATH.${RESET}\n" >&2
+ printf "%s" "$(pwd)"
+ }
+
+ # Function to download and install
+ install_soar() {
+ DOWNLOAD_TOOL=""
+ if ! DOWNLOAD_TOOL=$(check_download_tool); then
+ exit 1
+ fi
+ INSTALL_PATH=$(get_install_dir)
+
+ # Detect architecture
+ ARCH=$(uname -m)
+ case "$ARCH" in
+ x86_64)
+ ARCH="x86_64"
+ ;;
+ aarch64)
+ ARCH="aarch64"
+ ;;
+ *)
+ printf "${RED}Error: Unsupported architecture: ${YELLOW}$ARCH${RESET}\n" >&2
+ exit 1
+ ;;
+ esac
+
+ # Get latest release URL
+ printf "Downloading Soar..."
+ case "$SOAR_VERSION" in
+ *nightly*)
+ RELEASE_URL="https://github.com/pkgforge/soar/releases/download/nightly/soar-$ARCH-linux"
+ ;;
+ *latest*)
+ RELEASE_URL="https://github.com/pkgforge/soar/releases/latest/download/soar-$ARCH-linux"
+ ;;
+ *)
+ RELEASE_URL="https://github.com/pkgforge/soar/releases/download/v$SOAR_VERSION/soar-$ARCH-linux"
+ ;;
+ esac
+ printf " <== $RELEASE_URL\n"
+
+ # Download and install
+ if [ "$DOWNLOAD_TOOL" = "NU_HTTP" ]; then
+ printf "[+] Using HTTP (nushell)\n"
+ RELEASE_URL="http://http.pkgforge.dev/$RELEASE_URL" INSTALL_PATH="$INSTALL_PATH" nu --no-config-file -c \
+ 'http get --redirect-mode follow --insecure --raw $env.RELEASE_URL | save -f ($env.INSTALL_PATH + "/soar")'
+ printf "\n"
+ elif [ "$DOWNLOAD_TOOL" = "PERL_GET" ]; then
+ printf "[+] Using GET\n"
+ GET "$RELEASE_URL" >"$INSTALL_PATH/soar"
+ printf "\n"
+ elif [ "$DOWNLOAD_TOOL" = "PYTHON_GET" ]; then
+ printf "[+] Using python -c\n"
+ python -c "import urllib.request; urllib.request.urlretrieve('$RELEASE_URL', '$INSTALL_PATH/soar')"
+ printf "\n"
+ elif [ "$DOWNLOAD_TOOL" = "PYTHON3_GET" ]; then
+ printf "[+] Using python3 -c\n"
+ python3 -c "import urllib.request; urllib.request.urlretrieve('$RELEASE_URL', '$INSTALL_PATH/soar')"
+ printf "\n"
+ elif [ "$DOWNLOAD_TOOL" = "BASH_DEV_TCP" ]; then
+ printf "\n${YELLOW}⚠ Attempting to download using ${BLUE}Bash${YELLOW} (${GREEN}/dev/tcp${YELLOW}) over HTTP${RESET}\n" >&2
+ printf "${YELLOW}⚠ This is highly unreliable & may not Work${RESET}\n\n" >&2
+ RELEASE_URL="http://http.pkgforge.dev/$RELEASE_URL" INSTALL_PATH="$INSTALL_PATH" bash -c \
+ '
+ raw_http_get() {
+ #Get Input
+ url=$1
+ port=${2:-80}
+ #Actually Verify we are in bash
+ is_bash=0
+ [[ -n "${BASH}" ]] && is_bash=1
+ if [[ $is_bash -eq 0 ]]; then
+ (shopt -p >/dev/null 2>&1) && is_bash=1
+ fi
+ #Proceed
+ if [ $is_bash -eq 1 ]; then
+ #Parse Input
+ url=${url#http://}
+ url=${url#https://}
+ host=${url%%/*}
+ if [[ "$url" = "$host" ]]; then
+ path="/"
else
- echo "Error: No method available to make HTTP requests. Requires Bash with /dev/tcp" >&2
- return 1
+ path="/${url#$host/}"
fi
- }
- raw_http_get "${RELEASE_URL}" > "${INSTALL_PATH}/soar"
- if [[ -s "${INSTALL_PATH}/soar" ]]; then
- #Removes HTTP Headers
- sed "1,/^\r\{0,1\}$/d" -i "${INSTALL_PATH}/soar"
- fi
- '
- printf "\n"
- else
- printf "[+] Using $DOWNLOAD_TOOL\n"
- $DOWNLOAD_TOOL "$INSTALL_PATH/soar" "$RELEASE_URL"
- fi
- if [ ! -f "$INSTALL_PATH/soar" ]; then
- if [ "$DOWNLOAD_TOOL" = "BASH_DEV_TCP" ]; then
- printf "${RED}Error: Download failed.${YELLOW} Install ${BLUE}curl/wget${YELLOW} & try again${RESET}\n"
- else
- printf "${RED}Error: Download failed${RESET}\n"
- fi
- exit 1
- fi
- # Make executable
- chmod +x "$INSTALL_PATH/soar"
- # Check for valid elf in case sed failed
- if [ "$DOWNLOAD_TOOL" = "BASH_DEV_TCP" ]; then
- if ! "$INSTALL_PATH/soar" --version >/dev/null 2>&1; then
- printf "${RED}Error: Failed to properly extract soar.${YELLOW} Install ${BLUE}curl/wget${YELLOW} & try again${RESET}\n"
- rm -fv "$INSTALL_PATH/soar"
- printf "\n"
- exit 1
+ #Download
+ exec 3<>/dev/tcp/$host/$port
+ echo -e "GET $path HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n" >&3
+ if command -v dd >/dev/null 2>&1; then
+ dd bs=1K <&3
+ elif command -v cat >/dev/null 2>&1; then
+ cat <&3
+ fi
+ exec 3>&-
+ else
+ echo "Error: No method available to make HTTP requests. Requires Bash with /dev/tcp" >&2
+ return 1
fi
- fi
- # Finalize
- "$INSTALL_PATH/soar" --version || printf "${RED}Error: Failed to properly download soar${RESET}"
- printf "${GREEN}✓ Soar has been installed to: ${BLUE}$INSTALL_PATH/soar${RESET}\n"
- printf "${YELLOW}ⓘ Make sure ${BLUE}$INSTALL_PATH${YELLOW} is in your ${BLUE}PATH.${RESET}\n"
- printf "${YELLOW}ⓘ Documentation: ${BLUE}https://soar.qaidvoid.dev${RESET}\n"
- printf "${YELLOW}ⓘ Discord: ${BLUE}https://docs.pkgforge.dev/contact/chat${RESET}\n"
- printf "${YELLOW}ⓘ External Repositories are ${RED}NOT Enabled${YELLOW} by default${RESET}\n"
- printf "${YELLOW}ⓘ Learn More: ${BLUE}https://docs.pkgforge.dev/repositories/external${RESET}\n"
- printf "${YELLOW}ⓘ To enable external repos, Run: ${GREEN}soar defconfig --external${RESET}\n"
- printf "${YELLOW}ⓘ Finally, To synchronize all repos, Run: ${GREEN}soar sync${RESET}\n\n"
- }
+ }
+ raw_http_get "${RELEASE_URL}" > "${INSTALL_PATH}/soar"
+ if [[ -s "${INSTALL_PATH}/soar" ]]; then
+ #Removes HTTP Headers
+ sed "1,/^\r\{0,1\}$/d" -i "${INSTALL_PATH}/soar"
+ fi
+ '
+ printf "\n"
+ else
+ printf "[+] Using $DOWNLOAD_TOOL\n"
+ $DOWNLOAD_TOOL "$INSTALL_PATH/soar" "$RELEASE_URL"
+ fi
+ # Check
+ if [ ! -f "$INSTALL_PATH/soar" ]; then
+ if [ "$DOWNLOAD_TOOL" = "BASH_DEV_TCP" ]; then
+ printf "${RED}Error: Download failed.${YELLOW} Install ${BLUE}curl/wget${YELLOW} & try again${RESET}\n"
+ else
+ printf "${RED}Error: Download failed${RESET}\n"
+ fi
+ exit 1
+ fi
+ # Make executable
+ chmod +x "$INSTALL_PATH/soar"
+ # Check for valid elf in case sed failed
+ if [ "$DOWNLOAD_TOOL" = "BASH_DEV_TCP" ]; then
+ if ! "$INSTALL_PATH/soar" --version >/dev/null 2>&1; then
+ printf "${RED}Error: Failed to properly extract soar.${YELLOW} Install ${BLUE}curl/wget${YELLOW} & try again${RESET}\n"
+ rm -fv "$INSTALL_PATH/soar"
+ printf "\n"
+ exit 1
+ fi
+ fi
+ # Check & Print Docs
+ "$INSTALL_PATH/soar" --version || printf "${RED}Error: Failed to properly download soar${RESET}"
+ printf "\n${GREEN}✓ Soar has been installed to: ${BLUE}$INSTALL_PATH/soar${RESET}\n"
+ printf "${YELLOW}ⓘ Documentation: ${BLUE}https://soar.qaidvoid.dev${RESET}\n"
+ printf "${YELLOW}ⓘ Discord: ${BLUE}https://docs.pkgforge.dev/contact/chat${RESET}\n"
+ # Check if in PATH
+ if command -v expr >/dev/null 2>&1; then
+ if expr ":$PATH:" : ".*:$BIN_DIR:" >/dev/null ||
+ expr ":$PATH:" : ".*:$(expr "$BIN_DIR" : '\(.*\)/$'):" >/dev/null; then
+ :
+ else
+ printf "\n${YELLOW}⚠ ${BLUE}$INSTALL_PATH${RED} is NOT in your ${BLUE}PATH${RESET}\n"
+ printf "${YELLOW}ⓘ Put this in your ${BLUE}SHELL/Profile${YELLOW}:${RESET}\n"
+ printf "\n${GREEN} export PATH=\"\$PATH:$INSTALL_PATH\"${RESET}\n\n"
+ fi
+ else
+ printf "${YELLOW}ⓘ Make sure ${BLUE}$INSTALL_PATH${YELLOW} is in your ${BLUE}PATH.${RESET}\n"
+ fi
+ # Enable External Repos
+ printf "${YELLOW}ⓘ External Repositories are ${RED}NOT Enabled${YELLOW} by default${RESET}\n"
+ printf "${YELLOW}ⓘ Learn More: ${BLUE}https://docs.pkgforge.dev/repositories/external${RESET}\n"
+ printf "${YELLOW}ⓘ To enable external repos, Run: ${GREEN}soar defconfig --external${RESET}\n"
+ # Sync
+ printf "${YELLOW}ⓘ Finally, To synchronize all repos, Run: ${GREEN}soar sync${RESET}\n"
+ # Check Current Config
+ SOAR_ENV_OUT="$($INSTALL_PATH/soar env 2>/dev/null)"
+ if [ -n "$SOAR_ENV_OUT" ]; then
+ if command -v awk >/dev/null 2>&1 && command -v expr >/dev/null 2>&1; then
+ SOAR_BIN_PATH="$(printf "$SOAR_ENV_OUT" | awk -F= '/^SOAR_BIN=/{print $2}')"
+ if [ -n "$SOAR_BIN_PATH" ]; then
+ if expr ":$PATH:" : ".*:$SOAR_BIN_PATH:" >/dev/null ||
+ expr ":$PATH:" : ".*:$(expr "$SOAR_BIN_PATH" : '\(.*\)/$'):" >/dev/null; then
+ :
+ else
+ printf "\n${YELLOW}⚠ ${BLUE}$SOAR_BIN_PATH${RED} is NOT in your ${BLUE}\$PATH${RESET}\n"
+ printf "${YELLOW}ⓘ Put this in your ${BLUE}SHELL/Profile${YELLOW}:${RESET}\n"
+ printf "\n${GREEN} export PATH=\"\$PATH:$INSTALL_PATH:$SOAR_BIN_PATH\"${RESET}\n\n"
+ fi
+ fi
+ fi
+ fi
+ # Print Current config
+ printf "\n${YELLOW}ⓘ Current Soar Configuration:${RESET}\n\n"
+ "$INSTALL_PATH/soar" env
+ printf "\n"
+ }
+
+ # Run Installation
+ install_soar
- # Execute installation
- install_soar
+ # Disable Debug?
+ if [ -z "$DEBUG" ]; then
+ :
+ elif [ -n "$DEBUG" ]; then
+ set +x
+ fi
}
# Call main function