diff --git a/CHANGELOG.md b/CHANGELOG.md index 7046b3d4..f914a16e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,25 @@ ## next +### New features + * Single script can now execute within `POSIX` or `non-POSIX` environment and it detects/loads features dynamically. +* `lib/opkg`: Add support for `OpenWrt` (and alike) + +### Fixes and Updates +* `tests/`: Support new `ubuntu`/`debian` systems * `lib/yum`, `lib/dpkg`, `lib/apk`: Fix #96, #143 by adding `-q` (quiet) option for `Qs`. -* `tests/`: Support new `ubuntu`/`debian` systems * `lib/00_core.sh`: POSIX going well * `lib/zz_main.sh`: POSIX going well - * `lib/apk`: + * Fix many implementation issues. * `Q` prints version information. * Fix `--noconfirm` issue (#150) - * Fix many implementation issues. - * POSIX going well * POSIX version (`pacapt-POSIX` works perfectly without `bash`) +* Remove `{apk,dnf,zypper}_Sw` methods + and fix the `--download-only` for them ## v2.4.4 diff --git a/Makefile b/Makefile index 8d5d0926..d9a277a2 100644 --- a/Makefile +++ b/Makefile @@ -9,10 +9,12 @@ default: @echo " pacapt : Generate stable script." @echo ' install : Install stable script into $$BINDIR.' @echo " clean : (Experimental) Remove git-ignored files." - @echo " shellcheck : Syntax and style checking. Use http://shellcheck.net/." - @echo " docker.i : Launch interactive Docker container which mounts." - @echo ' your local 'pacapt.dev' script to $$BINDIR/pacman.' - @echo ' Please use DISTRO= to specify Docker image' + @echo " shellcheck : It's shellcheck." + @ecoh " POSIX : Use shellcheck with POSIX checks for some scripts." + @echo " docker.i : Launch interactive Docker container which mounts" + @echo ' your local working directory to /src/' + @echo ' and create symlink /bin/pacman to the local pacapt.dev'. + @echo ' Please use DISTRO= to specify Docker image.' @echo " tests : Run all tests. Please read tests/README.md first." @echo " Use TESTS= to specify a package. Docker is required." @echo " stats : Generate table of implemented operations in development branch." @@ -75,8 +77,8 @@ $(BINDIR)/pacapt: pacapt .PHONY: docker.i docker.i: @docker run --rm -ti \ - -v $(PWD)/pacapt.dev:$(BINDIR)/pacman \ - $(DISTRO) /bin/bash + -v $(PWD)/:/src/ \ + $(DISTRO) /bin/sh -c 'ln -s /src/pacapt.dev /bin/pacman && exec sh' .PHONY: update_stats update_stats: diff --git a/README.md b/README.md index 720d7404..9657a85c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ `pacapt` is a wrapper for many package managers. Simply install package with `pacapt -S htop` or `pacapt install htop` -on any `Linux`, `BSD`, `Mac OS` machines. +on any `Linux`, `BSD`, `OpenWrt` or `Mac OS` machines. It supports the following package managers: * `pacman` by `Arch Linux`, `ArchBang`, `Manjaro`, etc. @@ -19,6 +19,7 @@ It supports the following package managers: * `pkg_tools` by `OpenBSD` * `sun_tools` by `Solaris(SunOS)` * `apk` by `Alpine Linux` +* `opkg` by `OpenWrt` * `tazpkg` by `SliTaz Linux` * `swupd` by `Clear Linux` * `tlmgr` by `TeX Live` @@ -44,7 +45,7 @@ It supports the following package managers: ## Installation 1. This script shouldn't be installed on an Arch-based system; -2. On `FreeBSD` and `Alpine Linux`, please install `bash` package first. +2. On `FreeBSD`, please install `bash` package first. ### Install stable `Bash` script 2.4.x from Github @@ -113,23 +114,24 @@ A long list of options and operations can be found from [`ArchLinux`'s wiki](htt ### Implemented operations ``` - Q Qc Qe Qi Qk Ql Qm Qo Qp Qs Qu R Rn Rns Rs S Sc Scc Sccc Sg Si Sii Sl Ss Su Suy Sw Sy U - apk ~ * * * * * * * * * * * * * * * * * * * * * * - cave * * * * * * * * * * * * * * x * * * * * x + Q Qc Qe Qi Qk Ql Qm Qo Qp Qs Qu R Rn Rns Rs S Sc Scc Sccc Sg Si Sii Sl Ss Su Suy Sy U + apk ~ * * * * * * * * * * * * * * * * * * * * * + cave * * * * * * * * * * * * * * x * * * * * x conda * * * * * * * - dnf ~ * * * * * * * * * * * * * * * * * * * * * * * - dpkg ~ * * * * * * * * * ~ * * * * * * * * * * * - homebrew ~ * * * * * * * * * * * * * * * * * - macports * * * * * ~ * * * * * * * * - pkgng * * * * * * * * * * * * * * * * -pkg_tools ~ * * * * * * * * ~ * * x * * ~ * * x - portage * * * * * * * * * * * * * * * * * -sun_tools * * * * * * * - swupd * * * * * * * * * - tazpkg * * * * * * * * * * * * * - tlmgr * * * * * * * * * * - yum * * * * * * * * * * * * * * * * * * * * * * - zypper * * * * * * * * * * * * * * * * * * * * * * * * * * + dnf ~ * * * * * * * * * * * * * * * * * * * * * * + dpkg ~ * * * * * * * * * ~ * * * * * * * * * * * + homebrew ~ * * * * * * * * * * * * * * * * * + macports * * * * * ~ * * * * * * * * + opkg * * * * * * * * * * * * * * + pkgng * * * * * * * * * * * * * * * * +pkg_tools ~ * * * * * * * * ~ * * x * * ~ * * x + portage * * * * * * * * * * * * * * * * * +sun_tools * * * * * * * + swupd * * * * * * * * * + tazpkg * * * * * * * * * * * * * + tlmgr * * * * * * * * * * + yum * * * * * * * * * * * * * * * * * * * * * * + zypper * * * * * * * * * * * * * * * * * * * * * * * * * ``` **Notes:** diff --git a/bin/check.sh b/bin/check.sh index 95f2f311..3e491ad0 100755 --- a/bin/check.sh +++ b/bin/check.sh @@ -61,36 +61,33 @@ _has_shellcheck() { } _check_file() { - local _file="${1:-/x/x/x/x/x/x/x/}" + local_file="${1:-/x/x/x/x/x/x/x/}" + local_shell="${SHELLCHECK_SHELL:-bash}" - echo >&2 ":: ${FUNCNAME[0]}: $1" + echo >&2 ":: ${FUNCNAME[0]} (${local_shell}): $1" - [[ -f "$_file" ]] \ + [[ -f "$local_file" ]] \ || { - echo >&2 ":: File not found '$_file'" + echo >&2 ":: File not found '$local_file'" return 1 } - _simple_check "$_file" || return + _simple_check "$local_file" || return - shellcheck -s "${SHELLCHECK_SHELL:-bash}" -f json "$_file" \ - | _shellcheck_output_format "$_file" + shellcheck -s "${local_shell}" -f json "$local_file" \ + | _shellcheck_output_format "$local_file" [[ "${PIPESTATUS[0]}" == "0" ]] } -_check_POSIX_file() { - if ! grep -Eiqe "^# +POSIX.*:.*Ready" -- "$1" ; then - >&2 echo ":: $1: POSIX is not required." - else - _check_file "$1" || return 1 - fi -} - _check_POSIX_files() { export SHELLCHECK_SHELL="sh" while (( $# )); do - _check_POSIX_file "$1" || return 1 + if awk 'NR==1' < "$1" \ + | grep -Eiqe '^#!/usr/bin/env sh' ; + then + _check_file "$1" || return 1 + fi shift done } diff --git a/bin/compile.sh b/bin/compile.sh index 5f1087e9..c15ea0ee 100755 --- a/bin/compile.sh +++ b/bin/compile.sh @@ -116,7 +116,7 @@ library_files() { } library_POSIX_ready() { - grep -Eqie "^# +POSIX.*:.*Ready" -- "$@" + grep -Eqie '#!/usr/bin/env sh' -- "$@" } ######################################################################## @@ -129,6 +129,7 @@ for L in $(library_files); do || continue if library_POSIX_ready "$L"; then + >&2 echo ":: POSIX library '$L'" $GREP -v '^#' "$L" else $GREP -v '^#' "$L" | awk '{printf("#_!_POSIX_# %s\n", $0)}' diff --git a/lib/00_core.sh b/lib/00_core.sh index 854db0e8..ba1cef28 100644 --- a/lib/00_core.sh +++ b/lib/00_core.sh @@ -1,6 +1,5 @@ -#!/bin/bash +#!/usr/bin/env sh -# POSIX : Ready # Purpose: Provide some basic functions # Author : Anh K. Huynh # License: Fair license (http://www.opensource.org/licenses/fair) @@ -98,6 +97,7 @@ _PACMAN_detect() { _issue2pacman pkg_tools "OpenBSD" && return _issue2pacman pkg_tools "Bitrig" && return _issue2pacman apk "Alpine Linux" && return + _issue2pacman opkg "OpenWrt" && return [ -z "$_PACMAN" ] || return @@ -121,6 +121,7 @@ _PACMAN_detect() { [ -x "/usr/sbin/pkg_add" ] && _PACMAN="pkg_tools" && return [ -x "/usr/sbin/pkgadd" ] && _PACMAN="sun_tools" && return [ -x "/sbin/apk" ] && _PACMAN="apk" && return + [ -x "/bin/opkg" ] && _PACMAN="opkg" && return [ -x "/usr/bin/tazpkg" ] && _PACMAN="tazpkg" && return [ -x "/usr/bin/swupd" ] && _PACMAN="swupd" && return @@ -141,6 +142,7 @@ _translate_w() { case "$_PACMAN" in "dpkg") local_opt="-d";; "cave") local_opt="-f";; + "dnf") local_opt="--downloadonly";; "macports") local_opt="fetch";; "portage") local_opt="--fetchonly";; "zypper") local_opt="--download-only";; @@ -156,6 +158,7 @@ _translate_w() { local_ret=1 ;; "apk") local_opt="fetch";; + "opkg") local_opt="--download-only";; *) local_opt="" local_ret=1 diff --git a/lib/00_external.sh b/lib/00_external.sh index 02a9f073..d5e71963 100644 --- a/lib/00_external.sh +++ b/lib/00_external.sh @@ -1,6 +1,5 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh -# POSIX : Ready # Purpose : Provide some basic settings for external package managers # Author : Ky-Anh Huynh # License : MIT diff --git a/lib/apk.sh b/lib/apk.sh index 9283341f..3278aa53 100644 --- a/lib/apk.sh +++ b/lib/apk.sh @@ -1,6 +1,5 @@ -#!/bin/bash +#!/usr/bin/env sh -# POSIX : Ready # Purpose: Support next-generation Alpine Linux apk package manager # Author : Carl X. Su # Cuong Manh Le @@ -20,6 +19,7 @@ _apk_init() { } # apk_Q may _not_implemented +# FIXME: Need to support a small list of packages apk_Q() { case "$_TOPT" in "") @@ -162,11 +162,6 @@ apk_Sy() { apk update } -apk_Sw() { - # shellcheck disable=2086 - apk fetch $_TOPT -- "$@" -} - apk_U() { # shellcheck disable=2086 apk add --allow-untrusted $_TOPT -- "$@" diff --git a/lib/dnf.sh b/lib/dnf.sh index 6fd28d02..b357a992 100644 --- a/lib/dnf.sh +++ b/lib/dnf.sh @@ -62,10 +62,6 @@ dnf_Suy() { dnf upgrade "$@" } -dnf_Sw() { - dnf download "$@" -} - dnf_Sy() { dnf clean expire-cache && dnf check-update } diff --git a/lib/dpkg.sh b/lib/dpkg.sh index ea027a39..a91f9ca2 100644 --- a/lib/dpkg.sh +++ b/lib/dpkg.sh @@ -18,6 +18,7 @@ _dpkg_init() { } # dpkg_Q may _not_implemented +# FIXME: Need to support a small list of packages dpkg_Q() { if [[ "$_TOPT" == "q" ]]; then dpkg -l \ diff --git a/lib/opkg.sh b/lib/opkg.sh new file mode 100644 index 00000000..92c69abb --- /dev/null +++ b/lib/opkg.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env sh + +# Purpose: Support opkg (e.g. OpenWrt) +# Author : Ky-Anh Huynh +# License: Fair license (http://www.opensource.org/licenses/fair) +# Source : http://github.com/icy/pacapt/ + +# Copyright (C) 2021 Ky-Anh Huynh +# +# Usage of the works is permitted provided that this instrument is +# retained with the works, so that any entity that uses the works is +# notified of this instrument. +# +# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. + +_opkg_init() { + : +} + +opkg_Sy() { + opkg update +} + +opkg_Q() { + # shellcheck disable=SC2016 + case "$_TOPT" in + "q") + opkg list-installed "$@" | "$AWK" '{print $1}' + ;; + "") + opkg list-installed "$@" + ;; + *) + _not_implemented + ;; + esac +} + +opkg_Qi() { + for pkg in $(opkg__get_local_pkgs "${@}"); do + opkg info "$pkg" + done +} + +# Get list of installed-packages from user list. +opkg__get_local_pkgs() { + if [ "$#" -eq 0 ]; then + # shellcheck disable=SC2016 + opkg list-installed | "$AWK" '{print $1}' + else + # `opkg status` returns empty if package is not installed/removed. + # shellcheck disable=SC2016 + for pkg in "${@}"; do + opkg status "$pkg" + done \ + | "$AWK" '/^Package: / {print $NF}' + fi +} + +opkg_Ql() { + for pkg in $(opkg__get_local_pkgs "${@}"); do + # shellcheck disable=SC2016 + opkg files "$pkg" \ + | PKG="$pkg" "$AWK" \ + '{ if (NR>1) {printf("%s %s\n", ENVIRON["PKG"], $0)} }' + done +} + +opkg_Qo() { + if cmd="$(command -v -- "$@")"; then + opkg search "$cmd" + else + opkg search "$@" + fi +} + +opkg_Qs() { + if command -v sort >/dev/null; then + local_filter="sort -u" + else + local_filter="cat" + fi + + # FIXME: opkg doesn't work with wildcard by default. + case "$@" in + *\**) local_pattern="$*" ;; + *) local_pattern="*${*}*" ;; + esac + + opkg search "$local_pattern" \ + | ${local_filter} \ + | _quiet_field1 +} + +# FIXME: It's not easy to test this method =)) +opkg_Qu() { + opkg list-upgradable +} + +opkg_R() { + opkg remove "$@" +} + +opkg_S() { + opkg install "$@" +} + +opkg_Si() { + # shellcheck disable=2086 + opkg list $_TOPT "$@" +} + +opkg_Sii() { + # shellcheck disable=2086 + opkg list $_TOPT "$@" + opkg whatdepends "$@" +} + +opkg_Ss() { + opkg list "$@" +} + +opkg_Su() { + opkg upgrade "$@" +} + +opkg_U() { + opkg install "$@" +} diff --git a/lib/sun_tools.sh b/lib/sun_tools.sh index ce63e862..09974fbe 100644 --- a/lib/sun_tools.sh +++ b/lib/sun_tools.sh @@ -1,6 +1,5 @@ -#!/bin/bash +#!/usr/bin/env sh -# POSIX : Ready # Purpose: SunOS support # Author : Daniel YC Lin # License: Fair license (http://www.opensource.org/licenses/fair) diff --git a/lib/yum.sh b/lib/yum.sh index 71afc0c3..9f0f8dca 100644 --- a/lib/yum.sh +++ b/lib/yum.sh @@ -17,6 +17,7 @@ _yum_init() { : } +# FIXME: Need to support a small list of packages yum_Q() { if [[ "$_TOPT" == "q" ]]; then rpm -qa --qf "%{NAME}\\n" diff --git a/lib/zypper.sh b/lib/zypper.sh index 0402a1a8..1d88acef 100644 --- a/lib/zypper.sh +++ b/lib/zypper.sh @@ -166,10 +166,6 @@ zypper_S() { zypper install $_TOPT "$@" } -zypper_Sw() { - zypper install --download-only "$@" -} - zypper_U() { zypper install "$@" } diff --git a/lib/zz_main.sh b/lib/zz_main.sh index b35b6141..544e77df 100644 --- a/lib/zz_main.sh +++ b/lib/zz_main.sh @@ -1,6 +1,5 @@ -#!/bin/bash +#!/usr/bin/env sh -# POSIX : Ready # Purpose: A wrapper for all Unix package managers # Author : Anh K. Huynh # License: Fair license (http://www.opensource.org/licenses/fair) @@ -71,6 +70,7 @@ _PACMAN_detect \ if [ -z "${__PACAPT_FORKED__:-}" ]; then case "$_PACMAN" in "apk") ;; + "opkg") ;; "sun_tools" ) ;; *) _die "pacapt($_PACMAN) library is not ready for pure-POSIX features." diff --git a/tests/opkg.txt b/tests/opkg.txt new file mode 100644 index 00000000..623dfc7c --- /dev/null +++ b/tests/opkg.txt @@ -0,0 +1,91 @@ +#!/bin/sh + +# Purpose : Testing script for okpg support +# Author : Ky-Anh Huynh +# Date : June 19th, 2021 +# License : MIT + +im oofnik/openwrt:snapshot-x86-64 +im oofnik/openwrt:19.07.7-x86-64 +im oofnik/openwrt:19.07.6-x86-64 +im oofnik/openwrt:19.07.5-x86-64 + +in -Sy +ou Updated list of available packages in /var/opkg-lists/openwrt_core +ou Downloading.*downloads.openwrt.org +ou Signature check passed. + +in -Q +ou busybox - .* +ou libc - .* + +in -Q busybox +ou busybox + +in -Qq +ou ^busybox$ + +in -Qi +ou busybox +ou libc +ou Status: install user installed + +in -Ql +ou libc +ou busybox + +in -Ql libc +ou libc + +in -Ql ruby +ou empty + +in -Qo +ou empty + +in -Qo busybox +ou busybox - .* + +in -Qo /bin/sh +ou busybox - .* + +in -Qs sh +ou base-files - .* +ou busybox - .* + +in -Qqs sh +ou ^busybox$ + +in -Sw htop +in ! htop +ou Downloading.*htop +ou htop: not found + +in -S htop +in ! command -v htop +ou /usr/bin/htop + +in -R htop +in ! htop -h +ou Removing package htop from root +ou htop: not found + +in -Sw htop +in -U ./htop*.ipk +in ! htop -h +ou Hisham Muhammad + +in -Si ruby +in ! ruby -e true +ou ruby: not found +ou Ruby is .* for quick and easy + +in -Sii librt +ou e2fsprogs.*depends on.* + +in -Ss +ou zoneinfo-core +ou ^zsh + +in -Ss perl +ou Perl is a stable.* programming language.