├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── ARCHITECTURE.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── COPYING ├── Makefile ├── README.md ├── bin ├── check.sh ├── compile.sh ├── gen_stats.sh ├── gen_tests.sh └── update_stats.sh ├── contrib ├── README.md └── pacapt.spec ├── lib ├── 00_core.sh ├── 00_external.sh ├── apk.sh ├── apt_cyg.sh ├── cave.sh ├── conda.sh ├── dnf.sh ├── dpkg.sh ├── help.txt ├── homebrew.sh ├── macports.sh ├── opkg.sh ├── pkg_tools.sh ├── pkgng.sh ├── portage.sh ├── sun_tools.sh ├── swupd.sh ├── tazpkg.sh ├── tlmgr.sh ├── xbps.sh ├── yum.sh ├── zypper.sh └── zz_main.sh ├── pacapt └── tests ├── Dockerfile.alpine_bash4 ├── Dockerfile.debian_bash3 ├── Dockerfile.opkg_bash4 ├── Dockerfile.oraclelinux-8_dnf ├── Dockerfile.slitaz40_bash3 ├── Dockerfile.voidlinux ├── Dockerfile.zypper_bash3 ├── Makefile ├── README.md ├── apk.txt ├── dnf.txt ├── dpkg.txt ├── homebrew.txt ├── opkg.txt ├── pkgng.txt ├── slitaz40.txt ├── sun_tools.txt ├── swupd.txt ├── test.sh ├── xbps.txt ├── yum.txt └── zypper.txt /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: pacapt-tests 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - no-we-want-to-run-check-on-all-branches 7 | 8 | jobs: 9 | shellcheck: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: prepare 15 | run: | 16 | sudo apt-get install libjson-perl liburi-perl 17 | 18 | - name: shellcheck 19 | run: | 20 | export CI_SHELLCHECK_UPDATE=yes 21 | make shellcheck 22 | 23 | - name: shellcheck-POSIX 24 | run: | 25 | export CI_SHELLCHECK_UPDATE=yes 26 | make POSIX 27 | 28 | dpkg: 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v2 32 | - run: make tests TESTS=dpkg 33 | 34 | zypper: 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v2 38 | - run: make tests TESTS=zypper 39 | 40 | # See also 41 | # 42 | # * https://github.com/icy/pacapt/pull/207#issuecomment-929220016 43 | # * https://bugzilla.opensuse.org/show_bug.cgi?id=1190670 44 | # * https://github.com/moby/moby/pull/42836 45 | # 46 | zypper-seccomp: 47 | runs-on: ubuntu-latest 48 | steps: 49 | - uses: actions/checkout@v2 50 | - run: make tests TESTS=zypper IMAGES=opensuse/tumbleweed:latest 51 | 52 | opkg: 53 | runs-on: ubuntu-latest 54 | steps: 55 | - uses: actions/checkout@v2 56 | - run: make tests TESTS=opkg 57 | 58 | apk: 59 | runs-on: ubuntu-latest 60 | steps: 61 | - uses: actions/checkout@v2 62 | - run: make tests TESTS=apk 63 | 64 | dnf: 65 | runs-on: ubuntu-latest 66 | steps: 67 | - uses: actions/checkout@v2 68 | - run: make tests TESTS=dnf 69 | 70 | yum: 71 | runs-on: ubuntu-latest 72 | steps: 73 | - uses: actions/checkout@v2 74 | - run: make tests TESTS=yum 75 | 76 | swupd: 77 | runs-on: ubuntu-latest 78 | steps: 79 | - uses: actions/checkout@v2 80 | - run: make tests TESTS=swupd 81 | 82 | xbps: 83 | runs-on: ubuntu-latest 84 | steps: 85 | - uses: actions/checkout@v2 86 | - run: make tests TESTS=xbps 87 | 88 | others: 89 | runs-on: ubuntu-latest 90 | steps: 91 | - uses: actions/checkout@v2 92 | - run: make tests TESTS="slitaz40" 93 | 94 | homebrew: 95 | runs-on: macos-latest 96 | steps: 97 | - uses: actions/checkout@v2 98 | - run: | 99 | # test_homebrew 100 | set -x 101 | make pacapt.dev 102 | export PATH="$(pwd -P):$PATH" 103 | ln -s pacapt.dev pacman 104 | cd tests/ 105 | make test_homebrew 106 | 107 | pkgng: 108 | runs-on: macos-10.15 109 | steps: 110 | - uses: actions/checkout@v2 111 | - uses: vmactions/freebsd-vm@v0.1.5 112 | with: 113 | usesh: true 114 | prepare: pkg install -y bash git 115 | run: | 116 | set -x 117 | make pacapt.dev 118 | ln -s pacapt.dev pacman 119 | export PATH="$(pwd -P):$PATH" 120 | cd tests/ 121 | make test_pkgng 122 | 123 | sun_tools: 124 | runs-on: macos-10.15 125 | steps: 126 | - uses: actions/checkout@v2 127 | - name: Build pacapt and tests 128 | run: make pacapt.dev && mkdir -pv tests/tmp/ && cd tests && sh ../bin/gen_tests.sh < sun_tools.txt > tmp/sun_tools.sh 129 | - uses: actions/cache@v2 130 | with: 131 | key: sol-11_4 132 | path: | 133 | sol-11_4.ova 134 | - uses: mondeja/solaris-vm-action@v1 135 | with: 136 | run: | 137 | set -x 138 | mv pacapt.dev /bin/pacman 139 | cd tests/ 140 | make test_sun_tools 141 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .*.swp 3 | pacapt.dev 4 | pacapt-* 5 | tests/tmp/* 6 | -------------------------------------------------------------------------------- /ARCHITECTURE.md: -------------------------------------------------------------------------------- 1 | ## TOC 2 | 3 | - [ ] [Introduction](#introduction) 4 | - [ ] [Components](#components) 5 | - [ ] [`pacapt`](#pacapt) 6 | - [ ] [`lib`](#lib) 7 | - [ ] [`tests`](#tests) 8 | - [ ] [CI with github-action](#ci-with-github-action) 9 | - [ ] [`bin`](#bin) 10 | - [ ] [History. Languages](#history-languages) 11 | 12 | ## Introduction 13 | 14 | This documentation is about the design of `pacapt` program. 15 | It describes how some components are connected to each other. 16 | And it's useful if you want to learn to contribute/improve the project. 17 | 18 | `pacapt` is just small program, with a bunch of scripts. 19 | There is no such thing `architecture`; the name is inspired by 20 | the HN topic https://news.ycombinator.com/item?id=26048784 21 | 22 | ## Components 23 | 24 | ### `pacapt` 25 | 26 | [`pacapt`](pacapt) is our main program. 27 | It's a shell wrapper for many package managers on your system/OS, 28 | and now works perfectly in `POSIX` environment (except a few exceptions). 29 | 30 | But we don't make changes in `pacapt` directly. The program is actually 31 | generated for every new release, and it's considered the _stable_ 32 | version where everyone can easily download it (with `curl` or `wget`) 33 | on their system. 34 | 35 | ### `lib` 36 | 37 | The [`lib`](lib/) directory contains all shell scripts that would be 38 | combined into the main program `pacapt`. Each package manager has their 39 | own (separate) library file, for example [`lib/apk.sh`](lib/apk.sh) 40 | contains all code used on `Alpine`-based system. 41 | 42 | Other than that, there are a few important/essential files: 43 | 44 | * [`00_core.sh`](lib/00_core.sh): 45 | Contains DRY functions to be used in any other places. 46 | * [`00_external.sh`](lib/00_external.sh): 47 | Contains some script to support non-system package managers 48 | (`pip`, `npm`) 49 | * [`zz_main.sh`](lib/zz_main.sh): 50 | Contains an argument parser, shell switching (change from `sh` 51 | to `bash` if necessary), and invocations of the real back-end 52 | package manager. 53 | * The help contents are provided in a plain text 54 | file [`lib/help.txt`](lib/help.txt). 55 | 56 | ### `tests` 57 | 58 | Contains all tests files written in a simple `DSL`. Some useful information 59 | about them can be read from [`tests/README.md`](tests/README.md). 60 | See real examples in [`tests/dpkg.txt`](tests/dpkg.txt) (this is one 61 | of the richest test files we have). 62 | 63 | ### `bin` 64 | 65 | Contains two important scripts 66 | 67 | * [`compile.sh`](bin/compile.sh): Glue all files under `lib` directory 68 | and create the main program `pacapt`. It's also used to generate 69 | a development version of the script: Please check out 70 | `make pacapt.dev` for more details 71 | * [`gen_tests.sh`](bin/gen_tests.sh): To deal with our tests DSL 72 | as mentioned in the section [`tests`](#tests) 73 | 74 | The very tricky program [`bin/gen_stats.sh`](bin/gen_stats.sh) 75 | is used to generate the table of all supported operations that you see from 76 | the [README.md](README.md#implemented-operations). The algorithm 77 | was designed and implemented _once_ and since then no further change 78 | has ever been made :D Well, it's so scary to touch that part, 79 | as long as it's working. 80 | It requires all methods in [`lib/`](lib/) to follow a strict syntax 81 | which you can see from the code: 82 | 83 | ``` 84 | <( 85 | # shellcheck disable=2016 86 | $GREP -hE "^${_PKGNAME}_[^ \\t]+\\(\\)" "$L" \ 87 | | $AWK -F '(' '{print $1}' 88 | ) 89 | ``` 90 | 91 | Don't worry. As long as you define a shell method as below, it's fine: 92 | 93 | ``` 94 | # method_name, follows by (), then a space, then a { 95 | my_method() { 96 | : the body of the method 97 | } 98 | ``` 99 | 100 | ### CI with github-action 101 | 102 | Please visit the self-doc YAML file [`.github/workflows/ci.yaml`](.github/workflows/ci.yaml). 103 | 104 | ## History. Languages 105 | 106 | The first implementation was submitted in 2010. 107 | 108 | The project is using 109 | 110 | * `Ruby` 111 | * `Perl` 112 | * `Bourne` and `Bourne-Again` shell scripting language 113 | * `Dockerfile` 114 | * (GNU) `parallel`, `awk`, `sed`, `grep` 115 | * `Dlang` on some deprecated branches 116 | * its own DSL for test files 117 | * `Markdown` (Github format) 118 | * `English` 119 | 120 | :P 121 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v3.0.7 2 | 3 | * `lib/{apk,macports,pkgng}`: Fixed fetch option #214 4 | * `lib/portage`: Fixed syntax error #218 (Thanks @owl4ce) 5 | 6 | ## v3.0.6 7 | 8 | * New support `Void Linux` (Thanks Tabulate @TabulateJarl8) 9 | 10 | ## v3.0.5 11 | 12 | * `lib/apt-cyg`: Add initial support for `apt-cyg` on Cygwin systems 13 | * Rewrote `bin/gen_tests.rb` in `bash` (@mondeja) 14 | * Minor typo/tests fixes 15 | 16 | WARNING: The script won't work with docker container image 17 | `opensuse/tumbleweed:latest`. See also 18 | https://bugzilla.opensuse.org/show_bug.cgi?id=1190670 19 | and https://github.com/moby/moby/pull/42836 20 | 21 | ## v3.0.4 22 | 23 | * `lib/swupd`: Add tests and more operations (credit: @mondeja) 24 | * `lib/conda/Qo`: added (credit: @anntzer) 25 | * `lib/yum/Qe`: Added (credit: @mondeja) 26 | * `yum` or `dnf`: Tests improvements (credit: @mondeja) 27 | 28 | ## v3.0.3 29 | 30 | Minor bug fixes and features added. 31 | More development improvements. 32 | This release is mainly driven by @mondeja. 33 | 34 | * Add architecture documentation 35 | * `lib/apk/Qe`: Add (credit: @mondeja) 36 | * `lib/dpkg/Sg`: Add (credit: @mondeja) 37 | * `lib/yum`: Minor fixes (credit: @mondeja) 38 | * `lib/yum/Sg`: Add (credit: @mondeja) 39 | * `lib/zypper/Sg`: Add (credit: @mondeja) 40 | * `tests/yum`: Add (credit: @mondeja) 41 | * Add CI support on Github-Action for many package managers 42 | (`dnf`, `yum`, `homebrew`, `pkgng`, `sun_tools`) 43 | 44 | ## v3.0.2 45 | 46 | * `tests/apk`: Add tests (Credit: @mondeja) 47 | * `lib/*`: All `POSIX`, except `lib/cave` 48 | * `lib/homebrew`: Fix shell switching issue (Fixes #170) 49 | that makes the program broken since `v3.0.0` 50 | * `lib/dpkg/{Qc,Qe}`: Add (Credit: @mondeja) 51 | * `lib/zypper`: `POSIX` ready, tests added, minor fixes 52 | * `lib/zypper/Sg`: Add (credit: @mondeja) 53 | * `lib/zypper/Sii`: Removed as it's too slow. 54 | * Improve the way the program deals with back-end's 55 | optional arguments (Fixes #173) 56 | 57 | ### Deprecation 58 | 59 | * `lib/homebrew/Rs`: temporarily deprecated 60 | * `lib/homebrew/Qo`: temporarily deprecated 61 | 62 | ### Development 63 | 64 | * `tests/` can run in `parallel` 65 | * `tests` can support any custom `Dockerfile` 66 | 67 | ## v3.0.1 68 | 69 | * More `POSIX` ports: `pkg_tools`, `conda`, `tlmgr`, `dnf`, `swupd`, `yum`, `macports` 70 | 71 | ## v3.0.0 72 | 73 | ### New features 74 | 75 | * `lib/opkg`: Add support for `OpenWrt` (and alike) 76 | * `Bash` is not required on `Alpine`, `SunOS` or `OpenWrt`: 77 | The program can work perfectly with `POSIX` shell on those systems. 78 | * Single script can now execute within `POSIX` or `non-POSIX` 79 | environment and it detects/loads features dynamically. 80 | If the system has `bash` installed, the program switches to 81 | `bash` as soon as possible. 82 | 83 | ### Fixes and Updates 84 | 85 | * `tests/`: Support new `ubuntu`/`debian` systems 86 | * `lib/yum`, `lib/dpkg`, `lib/apk`: Fix #96, #143 87 | by adding `-q` (quiet) option for `Qs`. 88 | * `lib/00_core.sh`: POSIX going well 89 | * `lib/zz_main.sh`: POSIX going well 90 | * `lib/apk`: 91 | * Fix many implementation issues. 92 | * `Q` prints version information. 93 | * Fix `--noconfirm` issue (#150) 94 | * POSIX version (`pacapt-POSIX` works perfectly without `bash`) 95 | * Remove `{apk,dnf,zypper}_Sw` methods 96 | and fix the `--download-only` for them 97 | 98 | ## v2.4.4 99 | 100 | * `lib/dnf`: Minor improvements (#148) 101 | 102 | ## v2.4.3 103 | 104 | * `lib/homebrew`: Support `cask` (fix #117) 105 | * `tests/dpkg`: Support new distros, drop support for old distro 106 | 107 | ## v2.4.2 108 | 109 | * Update README.md 110 | * Support sysget-style sub commands (`pacapt install`, `pacapt upgrade`,...) 111 | * `lib/homebrew/Rs`: Improvements (#124, @Mnkai) 112 | * `lib/dpkg`: Use `dist-upgrade` for `Suy` and `Su` operations 113 | 114 | ## v2.4.0 115 | 116 | * `lib/tlmgr`: Add TeXLive support (Antony Lee) 117 | * `lib/conda`: Conda support (Antony Lee) 118 | 119 | For developers: 120 | 121 | * Ability to support non-system package manager (`npm`, `gem`, ...) 122 | * Reduce shellcheck warning/error reports 123 | 124 | ## v2.3.15 125 | 126 | * A warm up release with very minor updates. 127 | 128 | ## v2.3.14 129 | 130 | * `lib/homebrew`: `brew upgrade` is equivalent to `brew upgrade --all`. 131 | See #90 and #101. 132 | * Support `Clear Linux`. See #94. 133 | 134 | For developers: 135 | 136 | * Add Travis support 137 | * Add and update test cases for Ubuntu 16.04, Ubuntu 14.04 138 | 139 | ## v2.3.13 140 | 141 | * `lib/dpkg`: Fix `-Qs` for old `dpkg`. 142 | 143 | For developers: 144 | 145 | * Test scripts can now be automated thanks to `tests/*`; 146 | * `tests/slitz40`: Add; 147 | * `tests/dpkg`: Update. 148 | 149 | ## v2.3.12 150 | 151 | * `lib/dpkg`: Fix #84 (incorrect implementation of `-Qs`.) 152 | 153 | For developers: 154 | 155 | * `bin/gen_tests.rb`: Add; 156 | * `lib/dpkg`: Add and update test cases; 157 | * `CONTRIBUTING`: Add new section `Writing test cases`. 158 | 159 | ## v2.3.11 160 | 161 | * `lib/tazpkg`: Improve `-U`. 162 | 163 | ## v2.3.10 164 | 165 | * `lib/tazpkg`: Support `-Scc`. 166 | 167 | ## v2.3.9 168 | 169 | * `lib/tazpkg`: Support `SliTaz` distribution. 170 | 171 | For developers: 172 | 173 | * `contrib/*`: Add instructions to build packages on some distributions (Credit: `Pival81`). 174 | 175 | ## v2.3.8 176 | 177 | * `lib/alpine`: Support `Alpine` distirubtion (Credit: `Carl X. Su`, `Cuong Manh Le`); 178 | * `lib/dnf`: Support new package manager on `Fedora` system (Credit: `Huy Ngô`); 179 | * `lib/termux`: Support `termux` on Android (Credit: `Jiawei Zhou`); 180 | * `lib/zypper`: New option `-Sw` (Forgot to merge #72); 181 | * `lib/yum`: New option `-Qs` (Credit: `Siôn Le Roux`); 182 | 183 | For developers: 184 | 185 | * Improve translation method `_translate_all`; 186 | 187 | ## v2.2.7 188 | 189 | * `lib/zypper`: Complete query/removal options (Credit: `Janne Heß`); 190 | * `lib/cave`: Fix an issue with `-R` option; 191 | * New option `--noconfirm` to help non-interactive scripts (Cf. #43). 192 | Currently available for `pkgng`, `yum`, `dpkg` and `zypper`. 193 | 194 | For developers: 195 | 196 | * `lib/{00_core,zz_main}`: Refactor to support future option translation; 197 | * Refactor code supports `-w` (download only) and `-v` (debug) options; 198 | * Improve coding quality thanks to `shellcheck`; 199 | * Move `compile.sh` to `bin/compile.sh`; 200 | * Use `lib/00_core#_translate_all` to add future option translation; 201 | * `bin/check`: Add script to inspect coding style issues (Cf. #54). 202 | 203 | ## v2.1.6 204 | 205 | * `lib/sun_tools`: `SunOS` support (Credit: `Daniel YC Lin`); 206 | * Fix a minor bug related to argument parsing (4287ff16e869a0960ea54233); 207 | * Improve documentation; 208 | * `lib/dnf`: Add some initial support; 209 | * Adding `GREP` and `AWK` environments to future non-`Linux` systems; 210 | * `compile.sh` will exit if it can't detect version information; 211 | * `README` has a table of supported operations generated by `compile.sh`; 212 | * In debug mode, `pacapt` will print body of function it would execute. 213 | 214 | ## v2.0.5 215 | 216 | * `lib/zz_main`: Improve secondary option parsing; 217 | * `lib/pkg_tools`: Remove `Rns` support. 218 | 219 | ## v2.0.4 220 | 221 | * `openbsd/pkg_tools`: Add (Credit: `Somasis`); 222 | * `homebrew/Su*`: Use `--all` flag when upgrading; 223 | * `homebrew/*`: Some typo fixes; 224 | * `compile.sh`: `git` becomes optional (useful for `docker` tester.); 225 | * `compile.sh`: Get list of authors from `README.md`; 226 | * `Makefile`: Various improvements; 227 | * `lib/00_core`: Add `_removing_is_dangerous` method; 228 | * `lib/00_core`: `_not_implemented` now returns `1`; 229 | * `lib/help.txt`: Remove list of authors from help message; 230 | * `CHANGELOG.md`: Add. 231 | 232 | ## v2.0.3 233 | 234 | * `homebrew/Qs`: Add; 235 | * `homebrew/*`: Fix minor bugs. 236 | 237 | ## v2.0.2 238 | 239 | * `lib/zz_main`: Fix quoting issue (Credit: `Cuong Manh Le`). 240 | 241 | ## v2.0.1 242 | 243 | * `git log v2.0.1`. 244 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Table of contents 2 | 3 | 1. [The design of the program](ARCHITECTURE.md) 4 | 1. [Coding style](#coding-style) 5 | 1. [Testing. Writing test cases](#testing-writing-test-cases) 6 | 1. [Generating pacapt script](#generating-pacapt-script) 7 | 1. [Branches](#branches) 8 | 1. [Closed branches](#closed-branches) 9 | 10 | ## Coding style 11 | 12 | 1. Don't use tab or smart tab; 13 | 1. Use `2-space` instead of a tab; 14 | 1. Contribute to library file under `./lib/` directory; 15 | 1. We try to follow the convention from: 16 | https://github.com/icy/bash-coding-style. 17 | 18 | ## Testing. Writing test cases 19 | 20 | See also `tests/README.md` and https://github.com/icy/pacapt/actions. 21 | 22 | 1. Use `make shellcheck POSIX` if you have shellcheck 23 | and enough `Perl` packages (`JSON`, `URI::Escape`) on your system; 24 | 1. Use `PACAPT_DEBUG=foo` where `foo` is a package manager 25 | (`dpkg`, `pacman`, `zypper`, ...) to print what `pacapt` will do. 26 | Use `PACAPT_DEBUG=auto` for auto-detection; 27 | 1. You can use `docker` for testing, by mounting the `pacapt.dev` script 28 | to the container. See also `docker.i` section in `Makefile`. Example: 29 | 30 | ```` 31 | $ make pacapt.dev 32 | $ docker run --rm -ti \ 33 | -v $PWD/pacapt.dev:/usr/bin/pacman \ 34 | debian:stable /bin/bash 35 | # Your container's shell is available from this point 36 | ```` 37 | 38 | Alternatively you can use the `Makefile` 39 | 40 | ``` 41 | $ make docker.i DISTRO=debian:stable 42 | # # Your Bourne shell is available now 43 | # # Type `bash` to start more convenient interactive shell. 44 | ``` 45 | 46 | ## Generating `pacapt.dev` script 47 | 48 | 1. For your development, use `make pacapt.dev`; 49 | 1. Please **do not** use `make pacapt` to update `pacapt`, 50 | and/or modify it manually; 51 | 52 | ## Branches 53 | 54 | 1. `ng`: 55 | The current development branch. 56 | Some pull requests are merged on to this branch, 57 | but the work may not be ready for production. 58 | 1. `your feature branch`: 59 | For new feature or bug fix, please work on your own branch 60 | and create pull request. 61 | Do not put different ideas on a same branch 62 | because that makes future tracking harder. 63 | 64 | ## Closed branches 65 | 66 | 1. `master`: 67 | The old stable code of the `pacapt`. 68 | This branch is closed on May 4th, 2014. 69 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2010 - 2021 Anh K. Huynh 2 | 3 | Usage of the works is permitted provided that this instrument is 4 | retained with the works, so that any entity that uses the works is 5 | notified of this instrument. 6 | 7 | DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BINDIR = /usr/local/bin/ 2 | DISTRO = debian:stable 3 | 4 | default: 5 | @echo "This is an experimental Makefile. Use it at your own risk." 6 | @echo "" 7 | @echo "## During development process" 8 | @echo "" 9 | @echo " pacapt.dev : Generate development script." 10 | @echo ' install.dev : Install development script into $$BINDIR.' 11 | @echo " clean : (Experimental) Remove git-ignored files." 12 | @echo " shellcheck : It's shellcheck." 13 | @echo " POSIX : Use shellcheck with POSIX checks for some scripts." 14 | @echo " docker.i : Launch interactive Docker container which mounts" 15 | @echo ' your local working directory to /src/' 16 | @echo ' and create symlink /bin/pacman to the local pacapt.dev'. 17 | @echo ' Please use DISTRO= to specify Docker image. For example:' 18 | @echo 19 | @echo ' make docker.i DISTRO=debian' 20 | @echo 21 | @echo " tests : Run all tests. Please read tests/README.md first." 22 | @echo " Use TESTS= to specify a package. Docker is required." 23 | @echo " For example:" 24 | @echo "" 25 | @echo " make tests TESTS=dpkg IMAGES=debian" 26 | @echo "" 27 | @echo "## During release process" 28 | @echo "" 29 | @echo " stats : Generate table of implemented operations in development branch." 30 | @echo " update_stats: Update README.md using results from 'stats' section." 31 | @echo " pacapt : Generate stable script." 32 | @echo ' install : Install stable script into $$BINDIR.' 33 | @echo "" 34 | @echo "## Environments" 35 | @echo "" 36 | @echo " VERSION : Version information. Default: git commit hash." 37 | @echo " BINDIR : Destination directory. Default: /usr/local/bin." 38 | @echo " DISTRO : Container image. Default: debian:stable." 39 | 40 | # Build and install development script 41 | 42 | .PHONY: pacapt.dev 43 | pacapt.dev: ./lib/*.sh ./lib/*.txt bin/compile.sh 44 | @./bin/compile.sh > $(@) || { rm -fv $(@); exit 1; } 45 | @bash -n $(@) 46 | @chmod 755 $(@) 47 | @echo 1>&2 "The output file is '$(@)' (unstable version)" 48 | 49 | .PHONY: install.dev 50 | install.dev: pacapt.dev 51 | @if [ -e $(@) ] && ! file $(@) | grep -q 'script'; then \ 52 | echo >&2 "Makefile Will not overwrite non-script $(@)"; \ 53 | exit 1; \ 54 | else \ 55 | install -vm755 pacapt.dev $(BINDIR)/pacapt; \ 56 | fi 57 | 58 | # Build and install stable script 59 | 60 | .PHONY: pacapt.check 61 | 62 | pacapt.check: 63 | @test -n "${VERSION}" || { echo ":: Please specify VERSION, i.e., make pacapt VERSION=1.2.3"; exit 1; } 64 | 65 | pacapt: pacapt.check ./lib/*.sh ./lib/*.txt bin/compile.sh 66 | @./bin/compile.sh > $(@).tmp || { rm -fv $(@).tmp; exit 1; } 67 | @mv -fv $(@).tmp $(@) 68 | @bash -n $(@) 69 | @chmod 755 $(@) 70 | @echo 1>&2 "The output file is '$(@)' (stable version)" 71 | 72 | .PHONY: install 73 | install: $(BINDIR)/pacapt 74 | 75 | $(BINDIR)/pacman: 76 | @if [ ! -e $(@) ]; then \ 77 | ln -vs $(BINDIR)/pacapt $(@); \ 78 | fi 79 | 80 | $(BINDIR)/pacapt: pacapt 81 | @if [ -e $(@) ] && ! file $(@) | grep -q 'script'; then \ 82 | echo >&2 "Makefile Will not overwrite non-script $(@)"; \ 83 | exit 1; \ 84 | else \ 85 | install -vm755 pacapt $(BINDIR)/pacapt; \ 86 | fi 87 | 88 | .PHONY: docker.i 89 | docker.i: 90 | @docker run --rm -ti \ 91 | -v $(PWD)/:/src/ \ 92 | $(DISTRO) /bin/sh -c 'ln -s /src/pacapt.dev /bin/pacman && exec sh' 93 | 94 | .PHONY: update_stats 95 | update_stats: 96 | @./bin/update_stats.sh 97 | 98 | .PHONY: stats 99 | stats: 100 | @./bin/gen_stats.sh 101 | 102 | .PHONY: clean 103 | clean: 104 | @if git clean -nX | grep -q .; then \ 105 | git clean -nX; \ 106 | echo -n "Remove these files? [y/N] "; \ 107 | read ANS; \ 108 | case "$$ANS" in \ 109 | [yY]*) git clean -fX ;; \ 110 | *) exit 1;; \ 111 | esac ; \ 112 | fi 113 | @cd tests/ && make -s clean 114 | 115 | .PHONY: shellcheck 116 | shellcheck: 117 | @./bin/check.sh _check_files bin/*.sh lib/*.sh 118 | 119 | .PHONY: POSIX 120 | POSIX: 121 | @./bin/check.sh _check_POSIX_files bin/*.sh lib/*.sh 122 | 123 | .PHONY: tests 124 | tests: 125 | @cd tests/ && make all 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## `pacapt` - An `ArchLinux`'s pacman-like wrapper for many package managers 2 | 3 | [![Build Status](https://github.com/icy/pacapt/actions/workflows/ci.yaml/badge.svg)](https://github.com/icy/pacapt/actions) 4 | 5 | `pacapt` is a 56KB `shell` wrapper for many package managers. 6 | Simply install package with `pacapt -S htop` or `pacapt install htop` 7 | on any `Linux`, `BSD`, `OpenWrt` or `Mac OS` machines. 8 | It supports the following package managers: 9 | 10 | * `pacman` from `Arch Linux`-based systems, `ArchBang`, `Manjaro`, etc. 11 | * `apt-cyg` from Cygwin (via [apt-cyg](https://github.com/transcode-open/apt-cyg)) 12 | * `apt-get` from `Debian`, `Ubuntu`, etc. 13 | * `homebrew` from `Mac OS X` 14 | * `macports` from `Mac OS X` 15 | * `yum/rpm` from `Redhat`, `CentOS`, `Fedora`, `Oracle Linux`, etc. 16 | * `portage` from `Gentoo` 17 | * `zypper` from `OpenSUSE` 18 | * `pkgng` from `FreeBSD` 19 | * `cave` from `Exherbo Linux` 20 | * `pkg_tools` from `OpenBSD` 21 | * `sun_tools` from `Solaris(SunOS)` 22 | * `apk` from `Alpine Linux` 23 | * `opkg` from `OpenWrt` 24 | * `tazpkg` from `SliTaz Linux` 25 | * `swupd` from `Clear Linux` 26 | * `xbps` from `Void Linux` 27 | * `tlmgr` from `TeX Live` 28 | * `conda` from [`Conda`](https://conda.io/docs/) 29 | 30 | ## TOC 31 | 32 | - [Description](#pacapt---an-archlinuxs-pacman-like-wrapper-for-many-package-managers) 33 | - [Installation](#installation) 34 | - [Install the stable script from Github](#install-the-stable-script-from-github) 35 | - [Usage](#usage) 36 | - [Basic operations](#basic-operations) 37 | - [Basic options](#basic-options) 38 | - [Implemented operations](#implemented-operations) 39 | - [Related projects](#related-projects) 40 | - [Similar projects](#similar-projects) 41 | - [Development](#development) 42 | - [General steps](#general-steps) 43 | - [License](#license) 44 | - [Authors and Contributors](#authors-contributors) 45 | 46 | ## Installation 47 | 48 | This script shouldn't be installed on an Arch-based system. 49 | On `cave`-based system, `bash` is required. 50 | 51 | ### Install the stable script from Github 52 | 53 | You can download the stable script and make it executable. 54 | On non-Arch-based system, you may use `pacman` as script name instead of `pacapt`. 55 | 56 | ```` 57 | $ sudo wget -O /usr/local/bin/pacapt https://github.com/icy/pacapt/raw/ng/pacapt 58 | $ sudo chmod 755 /usr/local/bin/pacapt 59 | $ sudo ln -sv /usr/local/bin/pacapt /usr/local/bin/pacman || true 60 | ```` 61 | 62 | If you have `curl` and want some interesting output: 63 | 64 | ``` 65 | # WARNING: Don't do this on Arch-based system! 66 | $ curl -Lo /usr/bin/pacman https://github.com/icy/pacapt/raw/ng/pacapt 67 | $ chmod 755 /usr/bin/pacman 68 | ``` 69 | 70 | For non-system package manager, you need to create symbolic links 71 | 72 | ``` 73 | $ ln -s /usr/local/bin/pacapt /usr/local/bin/pacapt-tlmgr 74 | $ ln -s /usr/local/bin/pacapt /usr/local/bin/pacapt-conda 75 | ``` 76 | 77 | You can also use shorter links: 78 | 79 | ``` 80 | $ ln -s /usr/local/bin/pacapt /usr/local/bin/p-tlmgr 81 | $ ln -s /usr/local/bin/pacapt /usr/local/bin/p-conda 82 | ``` 83 | 84 | noting the suffix (e.g., `-tlmgr`, `-conda`) is mandatory. 85 | 86 | ## Usage 87 | 88 | ### Basic operations 89 | 90 | For system package manager 91 | 92 | * Update package database: `pacapt -Sy`, or `pacapt update` 93 | * Install a package: `pacapt -S foo`, or `pacapt install foo` 94 | * Search a package: `pacapt -Ss foo`, or `pacapt search foo` 95 | * Remove a package: `pacapt -R foo`, or `pacapt remove foo` 96 | * Upgrade system: `pacapt -Su`, or `pacapt upgrade` 97 | * Remove orphans: `pacapt -Sc`, or `pacapt autoremove foo` 98 | * Clean up: `pacapt -Scc` or `pacapt -Sccc`, or `pacapt clean` 99 | 100 | For non-system package manager: Similar as above, however you need to call correct script name, e.g., 101 | 102 | * Install a Conda package: `pacapt-conda -S foo` 103 | * Remove a Conda package: `pacapt-conda -R foo` 104 | 105 | ### Basic options 106 | 107 | See also https://github.com/icy/pacapt/blob/ng/lib/help.txt. 108 | 109 | Some basic command line options 110 | 111 | * `-h` (`--help`): Print help message; 112 | * `-P`: Print list of supported operations; 113 | * `-V`: Print script version 114 | 115 | Some popular options of the original `ArchLinux`'s `pacman` program 116 | are supported and listed in the table in the next section. 117 | 118 | A long list of options and operations can be found from [`ArchLinux`'s wiki](https://wiki.archlinux.org/index.php/Pacman/Rosetta). 119 | 120 | ### Implemented operations 121 | 122 | ``` 123 | 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 124 | apk ~ * * * * * * * * * * * * * * * * * * * * * * 125 | apt_cyg * * * * * * * 126 | cave * * * * * * * * * * * * * * x * * * * * x 127 | conda * * * * * * * * 128 | dnf ~ * * * * * * * * * * * * * * * * * * * * * * * 129 | dpkg ~ * * * * * * * * * * * * ~ * * * * * * * * * * * * 130 | homebrew * * * * * * * * * * * * * * * * 131 | macports * * * * * ~ * * * * * * * * 132 | opkg * * * * * * * * * * * * * * 133 | pkgng * * * * * * * * * * * * * * * * 134 | pkg_tools ~ * * * * * * * * ~ * * x * * ~ * * x 135 | portage * * * * * * * * * * * * * * * * * 136 | sun_tools * * * * * * * 137 | swupd * * * * * * * * * * * * * 138 | tazpkg * * * * * * * * * * * * * 139 | tlmgr * * * * * * * * * * 140 | xbps * * * * * * * * * * * * * 141 | yum * * * * * * * * * * * * * * * * * * * * * * * * 142 | zypper * * * * * * * * * * * * * * * * * * * * * * * * * * 143 | ``` 144 | 145 | **Notes:** 146 | 147 | * `*`: Implemented; 148 | * `~`: Implemented. Some options may not supported/implemented; 149 | * `x`: Operation is not supported by Operating system; 150 | * The table is generated from source. Please don't update it manually. 151 | 152 | ## Related projects 153 | 154 | * [`batch-pacapt`](https://github.com/Grenadingue/batch-pacapt): An Arch's pacman-like package manager for Windows 155 | * [`node-pacapt`](https://github.com/Grenadingue/node-pacapt): A node.js wrapper of pacapt + batch-pacapt 156 | * `pacapt`'s [`nd`](https://github.com/icy/pacapt/tree/nd) branch: A rewrite in Dlang, now deprecated. 157 | * [`pacapt-py`](https://github.com/rami3l/pacapt-py): A proof of concept in Python to provide pacapt-like experience to Homebrew. 158 | * [`pacapt-go`](https://github.com/rami3l/pacaptr/tree/go-dev): A more complete rewrite in Go, now lives in the [`go-dev`](https://github.com/rami3l/pacaptr/tree/go-dev) branch of `pacaptr` as legacy code. 159 | 160 | ## Similar projects 161 | 162 | * [`sysget`](https://github.com/emilengler/sysget) is `a front-end for every package manager`, written in `C++`. It provides some basic features to manipulate packages on your system. 163 | * [`pacaptr`](https://github.com/rami3l/pacaptr) was originally started as a `Rust` port of this project (`pacapt`) (See also #126), now it's growing with their own new features and support. 164 | 165 | ## Development 166 | 167 | ### General steps 168 | 169 | Make sure you read some instructions in `CONTRIBUTING.md`. 170 | 171 | A development script can be compiled from the source code. 172 | 173 | ```` 174 | $ git clone https://github.com/icy/pacapt.git 175 | $ cd pacapt 176 | 177 | # switch to development branch 178 | $ git checkout ng 179 | 180 | # compile the script 181 | $ ./bin/compile.sh > pacapt.dev 182 | 183 | # check if syntax is good 184 | $ bash -n pacapt.dev 185 | 186 | $ sudo install -m755 ./pacapt.dev /usr/local/bin/pacapt 187 | ```` 188 | 189 | Please read the sample `Makefile` for some details. 190 | 191 | ## License 192 | 193 | This work is released under the terms of Fair license 194 | (http://opensource.org/licenses/fair). 195 | 196 | ## AUTHORS. CONTRIBUTORS 197 | 198 | Many people have contributed to the project by sending pull requests 199 | and/or reporting on the ticket system. Here is an incomplete list of 200 | authors and contributors. 201 | 202 | * 10sr (@10sr) 203 | * Alexander Dupuy (@dupuy) 204 | * Anh K. Huynh (@icy) 205 | * Antony Lee (@anntzer) 206 | * Alex Lyon (@Arcterus) 207 | * Álvaro Mondéjar (@mondeja) 208 | * Carl X. Su (@bcbcarl) 209 | * Cuong Manh Le (@Gnouc) 210 | * Daniel YC Lin (@dlintw) 211 | * Danny George (@dangets) 212 | * Darshit Shah (@darnir) 213 | * Dmitry Kudriavtsev (@dkudriavtsev) 214 | * Eric Crosson (@EricCrosson) 215 | * Evan Relf (@evanrelf) 216 | * GijsTimmers (@GijsTimmers) 217 | * Hà-Dương Nguyễn (@cmpitg) 218 | * Huy Ngô (@NgoHuy) 219 | * James Pearson (@xiongchiamiov) 220 | * Janne Heß (@dasJ) 221 | * Jiawei Zhou (@4679) 222 | * Karol Blazewicz 223 | * Kevin Brubeck (@unhammer) 224 | * Konrad Borowski (@xfix) 225 | * Kylie McClain (@somasis) 226 | * Gen Li (@Rami3L) 227 | * Valerio Pizzi (@Pival81) 228 | * Siôn Le Roux (@sinisterstuf) 229 | * Tabulate (@TabulateJarl8) 230 | * Thiago Perrotta (@thiagowfx) 231 | * Vojtech Letal (@letalvoj) 232 | -------------------------------------------------------------------------------- /bin/check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Purpose: Check script for error 4 | # Author : Anh K. Huynh 5 | # Date : 2015 Aug 06 6 | # License: MIT license 7 | 8 | _simple_check() { 9 | bash -n "$@" 10 | } 11 | 12 | _has_perl_json() { 13 | perl -MURI::Escape -MJSON -e 'exit(0)' 14 | } 15 | 16 | _shellcheck_output_format() { 17 | PREFIX="[ ${*} ] " \ 18 | perl -e ' 19 | use JSON; 20 | my $stream = do { local $/; <>; }; 21 | my $output = decode_json($stream); 22 | my $colors = { 23 | "error" => "\e[1;31m", 24 | "warning" => "\e[1;33m", 25 | "style" => "\e[1;36m", 26 | "default" => "\e[0m", 27 | "reset" => "\e[0m" 28 | }; 29 | 30 | foreach (keys @{$output}) { 31 | my $comment = @{$output}[$_]; 32 | my $color = $colors->{$comment->{"level"}} || $colors->{"default"}; 33 | 34 | printf("%s%s%7s %4d: line %4d col %2d, msg %s%s\n", 35 | $ENV{"PREFIX"}, 36 | $color, 37 | $comment->{"level"}, $comment->{"code"}, 38 | $comment->{"line"}, $comment->{"column"}, 39 | $comment->{"message"}, 40 | $colors->{"reset"} 41 | ); 42 | } 43 | ' 44 | } 45 | 46 | # See discussion in https://github.com/icy/pacapt/pull/59 47 | _has_shellcheck() { 48 | : "${SHELLCHECK_TAG:=v0.7.2}" 49 | if [[ -n "${CI_SHELLCHECK_UPDATE:-}" && "$OSTYPE" =~ linux.* ]]; then 50 | echo >&2 ":: Downloading shellcheck to $(pwd -P)..." 51 | wget --quiet -O shellcheck.tar.xz -c "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_TAG}/shellcheck-${SHELLCHECK_TAG}.linux.x86_64.tar.xz" 52 | tar xJf shellcheck.tar.xz 53 | PATH="$(pwd -P)"/shellcheck-${SHELLCHECK_TAG}/:$PATH 54 | export PATH 55 | fi 56 | 57 | if ! command -v shellcheck >/dev/null 2>&1; then 58 | >&2 echo ":: Sorry, shellcheck is required." 59 | return 1 60 | fi 61 | } 62 | 63 | _check_file() { 64 | local_file="${1:-/x/x/x/x/x/x/x/}" 65 | local_shell="${SHELLCHECK_SHELL:-bash}" 66 | 67 | echo >&2 ":: ${FUNCNAME[0]} (${local_shell}): $1" 68 | 69 | [[ -f "$local_file" ]] \ 70 | || { 71 | echo >&2 ":: File not found '$local_file'" 72 | return 1 73 | } 74 | 75 | _simple_check "$local_file" || return 76 | 77 | shellcheck -s "${local_shell}" -f json "$local_file" \ 78 | | _shellcheck_output_format "$local_file" 79 | 80 | [[ "${PIPESTATUS[0]}" == "0" ]] 81 | } 82 | 83 | _check_POSIX_files() { 84 | export SHELLCHECK_SHELL="sh" 85 | while (( $# )); do 86 | if awk 'NR==1' < "$1" \ 87 | | grep -iq '^#!/usr/bin/env sh' ; 88 | then 89 | _check_file "$1" || return 1 90 | # We only care POSIX issue for files under `lib/` 91 | elif echo "$1" | grep -qs "lib/"; then 92 | >&2 echo ":: WARNING: POSIX help-wanted '$1'" 93 | fi 94 | 95 | shift 96 | done 97 | } 98 | 99 | _check_files() { 100 | while (( $# )); do 101 | # FIXME: For now, we always return 0!!! 102 | _check_file "$1" 103 | shift 104 | done 105 | } 106 | 107 | _has_perl_json && _has_shellcheck || exit 1 108 | shellcheck --version 109 | 110 | "$@" 111 | -------------------------------------------------------------------------------- /bin/compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Purpose: `Compile` libraries from `lib/*` to create `pacapt` script. 4 | # Author : Anh K. Huynh 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2010 - 2015 Anh K. Huynh et al. 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | set -u 17 | set -e 18 | unset GREP_OPTIONS 19 | 20 | VERSION="${VERSION:-$(git log --pretty="%h" -1 2>/dev/null || true)}" 21 | VERSION="${VERSION:-unknown}" 22 | 23 | if [[ "${VERSION}" == "unknown" ]]; then 24 | echo >&2 ":: Unable to get version information." 25 | echo >&2 ":: You may to install or reconfigure your 'git' package." 26 | exit 1 27 | fi 28 | 29 | : "${PACAPT_STATS:=yes}" # List implemented operations to STDERR 30 | : "${GREP:=grep}" # Need to update on SunOS 31 | : "${AWK:=awk}" # Need to update on SunOS 32 | 33 | # At compile time, `_sun_tools_init` is not yet defined. 34 | if [[ -f "lib/sun_tools.sh" ]]; then 35 | # shellcheck disable=1091 36 | source "lib/sun_tools.sh" : 37 | _sun_tools_init || true 38 | fi 39 | 40 | export GREP AWK VERSION PACAPT_STATS 41 | 42 | ######################################################################## 43 | # Print the shebang and header 44 | ######################################################################## 45 | 46 | cat <&2 echo ":: POSIX library '$L'" 133 | $GREP -v '^#' "$L" 134 | else 135 | $GREP -v '^#' "$L" | awk '{printf("#_!_POSIX_# %s\n", $0)}' 136 | fi 137 | done 138 | 139 | ######################################################################## 140 | # Create the `_validate_operation` method. 141 | # Detect all supported operations. 142 | ######################################################################## 143 | 144 | echo "_validate_operation() {" 145 | echo " case \"\$1\" in" 146 | 147 | for L in $(library_files); do 148 | _PKGNAME="${L##*/}" 149 | _PKGNAME="${_PKGNAME%.*}" 150 | 151 | case "$_PKGNAME" in 152 | "zz_main"|"00_*") continue ;; 153 | esac 154 | 155 | while read -r F; do 156 | echo " \"$F\") ;;" 157 | done < \ 158 | <( 159 | # shellcheck disable=2016 160 | $GREP -hE "^${_PKGNAME}_[^ \\t]+\\(\\)" "$L" \ 161 | | $AWK -F '(' '{print $1}' 162 | ) 163 | done 164 | 165 | echo " *) return 1 ;;" 166 | echo " esac" 167 | echo "}" 168 | 169 | ######################################################################## 170 | # Print the source of `zz_main.sh`. 171 | # `zz_main` doesn't contain only Bash function. 172 | # It should be included in the last part of the script. 173 | ######################################################################## 174 | 175 | $GREP -v '^#' lib/zz_main.sh 176 | 177 | echo >&2 "pacapt version '$VERSION' has been generated." 178 | -------------------------------------------------------------------------------- /bin/gen_stats.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Purpose : Generate the table of implemented operations 4 | # Author : Ky-Anh Huynh 5 | # License : MIT 6 | # Origin : ./bin/compile.sh 7 | 8 | # 9 | : "${PACAPT_STATS:=yes}" # List implemented operations to STDERR 10 | : "${GREP:=grep}" # Need to update on SunOS 11 | : "${AWK:=awk}" # Need to update on SunOS 12 | : "${SYM_PARTIALLY_SUPPORTED:=~}" 13 | : "${SYM_FULLY_SUPPORTED:=*}" 14 | : "${SYM_NOT_SUPPORTED:=x}" 15 | : "${SYM_UNKNOWN:= }" 16 | 17 | # At compile time, `_sun_tools_init` is not yet defined. 18 | if [[ -f "lib/sun_tools.sh" ]]; then 19 | # shellcheck disable=1091 20 | source "lib/sun_tools.sh" : 21 | _sun_tools_init 22 | fi 23 | 24 | export GREP AWK VERSION PACAPT_STATS 25 | # 26 | 27 | # $1: 28 | _implState() { 29 | if grep -qs "# ${1} _not_implemented" ./lib/*.sh; then 30 | echo "${SYM_NOT_SUPPORTED}" 31 | elif grep -qs "# ${1} may _not_implemented" ./lib/*.sh; then 32 | echo "${SYM_PARTIALLY_SUPPORTED}" 33 | else 34 | echo "${SYM_FULLY_SUPPORTED}" 35 | fi 36 | } 37 | 38 | printf >&2 ":: %s: Generating statistics (table of implemented operations)..." "$0" 39 | 40 | # Operations (FQDN) 41 | _OPERATIONS=() 42 | for L in ./lib/*.sh; do 43 | _PKGNAME="${L##*/}" 44 | _PKGNAME="${_PKGNAME%.*}" 45 | 46 | case "$_PKGNAME" in 47 | "zz_main"|"00_core") continue ;; 48 | esac 49 | 50 | while read -r F; do 51 | _OPERATIONS+=( "$F" ) 52 | done < \ 53 | <( 54 | # shellcheck disable=2016 55 | $GREP -hE "^${_PKGNAME}_[^ \\t]+\\(\\)" "$L" \ 56 | | $AWK -F '(' '{print $1}' 57 | ) 58 | done 59 | 60 | # Secondary options 61 | _SOPERATIONS="$( 62 | echo "${_OPERATIONS[@]}" \ 63 | | sed -e 's# #\n#g' \ 64 | | sed -e 's#^.*_\([A-Z][a-z]*\)#\1#g' \ 65 | | sort -u 66 | )" 67 | 68 | printf "\\n" 69 | printf "\`\`\`\\n" 70 | 71 | # Print the headers 72 | _ret="$(printf "%9s " "")" 73 | for _sopt in $_SOPERATIONS; do 74 | _size="$(( ${#_sopt} + 1))" 75 | _ret="$(printf "%s%${_size}s" "$_ret" "$_sopt")" 76 | done 77 | printf "%s\\n" "$_ret" 78 | 79 | i=0 # index 80 | rs=0 # restart 81 | 82 | _OPERATIONS+=( "xxx_yyy" ) 83 | 84 | while :; do 85 | _ret="" 86 | 87 | [[ "$i" -lt "${#_OPERATIONS[@]}" ]] \ 88 | || break 89 | 90 | _cur_pkg="${_OPERATIONS[$i]}" 91 | _cur_pkg="${_cur_pkg%_*}" 92 | 93 | for _sopt in $_SOPERATIONS; do 94 | # Detect flag for this secondary option 95 | _flag="${SYM_UNKNOWN}" 96 | 97 | # Start from the #rs index, 98 | # go to boundary of the next package name. 99 | # xx_Qi, xx_Qs,... yy_Qi, yy_Qs,... 100 | # 101 | i=$rs 102 | while [[ "$i" -lt "${#_OPERATIONS[@]}" ]]; do 103 | _opt="${_OPERATIONS[$i]}" 104 | 105 | _cur2_opt="${_opt##*_}" 106 | _cur2_pkg="${_opt%_*}" 107 | 108 | # echo >&2 "(cur_pkg = $_cur_pkg, look up $_sopt [from $rs], found $_cur2_opt)" 109 | 110 | # Reach the boundary of the next package name 111 | if [[ "$_cur2_pkg" != "$_cur_pkg" ]]; then 112 | break 113 | else 114 | if [[ "$_cur2_opt" == "$_sopt" ]]; then 115 | # detect real state of this operation... 116 | _flag="$(_implState "$_opt")" 117 | break 118 | else 119 | (( i ++ )) ||: 120 | fi 121 | fi 122 | done 123 | 124 | _size="$(( ${#_sopt} + 1))" 125 | _ret="$(printf "%s%${_size}s" "$_ret" "$_flag")" 126 | done 127 | 128 | # Detect the next #restart index 129 | i=$rs 130 | while [[ "$i" -lt "${#_OPERATIONS[@]}" ]]; do 131 | _opt="${_OPERATIONS[$i]}" 132 | _cur2_pkg="${_opt%_*}" 133 | 134 | if [[ "$_cur2_pkg" != "$_cur_pkg" ]]; then 135 | rs=$i 136 | break 137 | fi 138 | 139 | (( i ++ )) ||: 140 | done 141 | 142 | if [[ "$_cur_pkg" != "xxx" ]]; then 143 | printf "%9s %s\\n" "$_cur_pkg" "$_ret" 144 | fi 145 | done 146 | 147 | printf "\`\`\`\\n" 148 | printf "\\n**Notes:**\\n\\n" 149 | printf "* \`%s\`: Implemented;\\n" "${SYM_FULLY_SUPPORTED}" 150 | printf "* \`%s\`: Implemented. Some options may not supported/implemented;\\n" "${SYM_PARTIALLY_SUPPORTED}" 151 | printf "* \`%s\`: Operation is not supported by Operating system;\\n" "${SYM_NOT_SUPPORTED}" 152 | printf "* The table is generated from source. Please don't update it manually.\\n" 153 | printf "\\n" 154 | -------------------------------------------------------------------------------- /bin/gen_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Generate test scripts 4 | # Author : Álvaro Mondéjar Rubio 5 | # License: MIT 6 | # Date : 2021 September 29th 7 | # Example: 8 | # 9 | # $ sh ./bin/gen_tests.sh < lib/dpkg.txt > ./test.sh 10 | # $ docker run --rm \ 11 | # -v $PWD/test.sh:/tmp/test.sh \ 12 | # -v $PWD/pacapt.dev:/usr/bin/pacman \ 13 | # -e "MSG_PREFIX=:: (INFO) " \ 14 | # ubuntu:14.04 \ 15 | # /bin/sh /tmp/test.sh 2>test.log 16 | 17 | /bin/echo "#!/bin/sh" 18 | /bin/echo "" 19 | /bin/echo "# Notes: This file is generated. Please don't modify them manually." 20 | /bin/echo "" 21 | /bin/echo "export PATH=/sbin:/bin:/usr/sbin:/usr/bin:\$PATH" 22 | /bin/echo "" 23 | /bin/echo "N_TEST=0 # Total number of tests" 24 | /bin/echo "N_FAIL=0 # Number of failed tests" 25 | /bin/echo "F_TMP= # Temporary file" 26 | /bin/echo "T_FAIL=0 # Number of failed tests in current block" 27 | /bin/echo "" 28 | /bin/echo "set -u" 29 | /bin/echo "" 30 | /bin/echo ": \"\${GGREP:=grep}\"" 31 | /bin/echo "" 32 | /bin/echo "if [ \"\$(uname)\" = \"SunOS\" ]; then" 33 | /bin/echo " GGREP=ggrep" 34 | /bin/echo "fi" 35 | /bin/echo "" 36 | # 37 | # Just send message to STDERR 38 | # 39 | # When CI is set, we expect the current test script is executed directly 40 | # by Github-Runner shell (not via our Docker launcher.) 41 | # This is the case for non-docker tests (homebrew, pkgng). 42 | # We need to reduce the duplicate log message in these cases. 43 | # 44 | /bin/echo "_log() { if [ -z \"\${CI:-}\" ]; then echo \"\$*\" 1>&2 ; fi; }" 45 | 46 | # A fancy wrappers of _log 47 | # 48 | # Where there is any message, we need to ensure they are on both 49 | # channels (STDIN, STDERR). Normally, the STDERR has more verbose 50 | # information, i.e, the output of all executions. The STDERR will 51 | # be [often] captured for later investigation and it's done via 52 | # the `tests/test.sh`. From STDIN we try to keep it compact. 53 | # ... 54 | # 55 | # shellcheck disable=SC2016 56 | printf '_fail() { _log "${MSG_PREFIX}Fail: $*"; printf "${MSG_PREFIX}Fail: %%s\n' # red 57 | printf '" "$*"; }\n' 58 | /bin/echo "_erro() { _log \"\${MSG_PREFIX}Erro: \$*\"; echo \"\${MSG_PREFIX}Erro: \$*\"; }" 59 | /bin/echo "_info() { _log \"\${MSG_PREFIX}Info: \$*\"; echo \"\${MSG_PREFIX}Info: \$*\"; }" 60 | /bin/echo "_pass() { _log \"\${MSG_PREFIX}Pass: \$*\"; echo \"\${MSG_PREFIX}Pass: \$*\"; }" 61 | /bin/echo "_exec() { _log \"\${MSG_PREFIX}Exec: \$*\"; echo \"\${MSG_PREFIX}Exec: \$*\"; }" 62 | /bin/echo "_warn() { _log \"\${MSG_PREFIX}Warn: \$*\"; echo \"\${MSG_PREFIX}Warn: \$*\"; }" 63 | /bin/echo "_stde() { _log \"\${MSG_PREFIX}Info: \$*\"; }" 64 | 65 | # Create a secure log (file) stream. If the file was set in \$F_TMP 66 | # we print out all output and remove that too. 67 | /bin/echo "_slog() {" 68 | /bin/echo " if [ -n \"\${F_TMP:-}\" ]; then" 69 | # ... first we record all logs to STDERR for later investigation 70 | /bin/echo " if [ -z \"\${CI:-}\" ]; then" 71 | /bin/echo " _stde 'Exec. output:'" 72 | /bin/echo " 1>&2 cat \$F_TMP" 73 | /bin/echo " fi" 74 | # ... 75 | # but when our test fails, we also print the first 100 lines to 76 | # the STDOUT, so that we can see them quickly. It can be tricky 77 | # when homebrew/pkgng fails, because we don't have any access 78 | # to MacOS environment on github-action runner. But let's see... 79 | /bin/echo " if [ \$T_FAIL -ge 1 ]; then" 80 | /bin/echo " cat \$F_TMP \\" 81 | # shellcheck disable=SC2028 82 | /bin/echo " | awk '{ if (NR <= 100) { printf(\" > %s\\n\", \$0); }}" 83 | # shellcheck disable=SC2028 84 | /bin/echo " END { if (NR > 100) { printf(\" > ...\\n\");}}'" 85 | /bin/echo " fi" 86 | /bin/echo " rm -f \"\${F_TMP}\"" 87 | # We record a seperator in the output because it's too verbose 88 | /bin/echo " _stde =====================================================" 89 | /bin/echo " export T_FAIL=0" 90 | /bin/echo " else" 91 | /bin/echo " export T_FAIL=0" 92 | /bin/echo " export F_TMP=\"\$(mktemp)\"" 93 | /bin/echo " if [ -z \"\${F_TMP:-}\" ]; then" 94 | /bin/echo " _fail 'Unable to create temporary file.'" 95 | /bin/echo " fi" 96 | /bin/echo " fi" 97 | /bin/echo "}" 98 | 99 | new_test=1 100 | 101 | while read -r line; do 102 | first_3_chars="$(/bin/echo "$line" | cut -c -1,2,3)" 103 | if [ "$first_3_chars" = "in " ]; then 104 | if [ "$new_test" -eq 1 ]; then 105 | /bin/echo "" 106 | /bin/echo "_slog" 107 | new_test=0 108 | fi 109 | 110 | cmd="$( 111 | /bin/echo "$line" \ 112 | | cut -c 4- \ 113 | | PATTERN=\$LOG REPL=\$F_TMP awk '{gsub(ENVIRON["PATTERN"], ENVIRON["REPL"]); print}' 114 | )" 115 | 116 | if [ "$cmd" = "clear" ]; then 117 | cmd="echo > \$F_TMP" 118 | elif [ "$(echo "$cmd" | cut -c 1-2)" = "! " ]; then 119 | # stripped command without ! 120 | cmd="$(echo "$cmd" | cut -c 3-)" 121 | else 122 | cmd="pacman $cmd" 123 | fi 124 | 125 | # FIXME: We wanted to use `tee` here, but that will create new pipes, 126 | # FIXME: and hence some feature didn't work (e.g., export FOO=). 127 | /bin/echo "if [ -n \"\${F_TMP:-}\" ]; then" 128 | /bin/echo " _exec \"$cmd\"" 129 | /bin/echo " { $cmd ; } 1>>\$F_TMP 2>&1" 130 | /bin/echo "fi" 131 | elif [ "$first_3_chars" = "ou " ]; then 132 | new_test=1 133 | expected="$(/bin/echo "$line" | cut -c 4-)" 134 | 135 | /bin/echo "N_TEST=\$(( N_TEST + 1 ))" 136 | /bin/echo "if [ -n \"\${F_TMP:-}\" ]; then" 137 | if [ -z "$expected" ] || [ "$expected" = "empty" ]; then 138 | /bin/echo " ret=\"\$(\"\$GGREP\" -Ec '.+' \$F_TMP)\"" 139 | /bin/echo " if [ -z \"\$ret\" ] || [ \"\$ret\" -ge 1 ]; then" 140 | else 141 | /bin/echo " ret=\"\$(\"\$GGREP\" -Ec \"$expected\" \$F_TMP)\"" 142 | /bin/echo " if [ -z \"\$ret\" ] || [ \"\$ret\" -eq 0 ]; then" 143 | fi 144 | /bin/echo " _fail Expected \"$expected\"" 145 | /bin/echo " N_FAIL=\$(( N_FAIL + 1 ))" 146 | /bin/echo " T_FAIL=\$(( T_FAIL + 1 ))" 147 | /bin/echo " else" 148 | /bin/echo " _pass Matched \"$expected\"" 149 | /bin/echo " fi" 150 | /bin/echo "else" 151 | /bin/echo " N_FAIL=\$(( N_FAIL + 1 ))" 152 | /bin/echo "fi" 153 | fi 154 | done 155 | 156 | /bin/echo "_slog" 157 | /bin/echo "if [ \$N_FAIL -ge 1 ]; then" 158 | /bin/echo " _fail \"\$N_FAIL/\$N_TEST test(s) failed.\"" 159 | /bin/echo " exit 1" 160 | /bin/echo "else" 161 | /bin/echo " _pass \"All \$N_TEST tests(s) passed.\"" 162 | /bin/echo "fi" 163 | -------------------------------------------------------------------------------- /bin/update_stats.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Purpose : Update table of implemented operations in README.md 4 | # Author : Ky-Anh Huynh 5 | # License : MIT 6 | 7 | ./bin/gen_stats.sh > stats.tmp 8 | 9 | < README.md awk ' 10 | BEGIN { 11 | ins = 0 12 | } 13 | { 14 | if ($0 ~ /## Implemented operations/) { 15 | print $0; 16 | ins = 1; 17 | } 18 | else { 19 | if ($0 ~ /##/) { 20 | print $0; 21 | ins = 0; 22 | } 23 | else if (ins == 0) { 24 | print $0; 25 | } 26 | } 27 | } 28 | ' \ 29 | | sed -e '/## Implemented operations/r stats.tmp' \ 30 | > README.md.tmp 31 | 32 | mv README.md.tmp README.md 33 | git diff README.md 34 | rm stats.tmp 35 | -------------------------------------------------------------------------------- /contrib/README.md: -------------------------------------------------------------------------------- 1 | 2 | First, install all the dependencies 3 | 4 | For Fedora: 5 | ```` 6 | # dnf install @development-tools 7 | # dnf install fedora-packager 8 | # dnf install rpmdevtools 9 | ```` 10 | For CentOS, RHEL: 11 | ```` 12 | # yum install rpm-build 13 | ```` 14 | For OpenSuSE, refer to the OpenSuSE wiki (https://en.opensuse.org/SDB:Compiling_software#Prerequisites). 15 | 16 | Now, if you haven't created the rpmbuild directory in your home yet, you can do this using this command: 17 | ```` 18 | $ cd $HOME 19 | $ rpmdev-setuptree 20 | ```` 21 | Ok, now we're set up for compiling, now just download the latest release of pacapt (you can find it on the github page, go on Releases), download it in .tar.gz format: 22 | ```` 23 | $ cd $HOME/rpmbuild/SOURCES 24 | $ wget https://github.com/icy/pacapt/archive/v2.3.15.tar.gz 25 | $ mv v2.3.15.tar.gz pacapt-2.3.15.tar.gz 26 | ```` 27 | And now download the spec file in this contrib directory and place it in ````$HOME/rpmbuild/SPECS```` 28 | 29 | Then, compile it: 30 | ```` 31 | $ rpmbuild -ba $HOME/rpmbuild/SPECS/pacapt.spec 32 | ```` 33 | And you're done! Your generated RPM will be in ````$HOME/rpmbuild/RPMS/noarch>/```` 34 | -------------------------------------------------------------------------------- /contrib/pacapt.spec: -------------------------------------------------------------------------------- 1 | %global debug_package %{nil} 2 | Name: pacapt 3 | Version: 2.3.15 4 | Release: 1%{?dist} 5 | Summary: An Arch's pacman-like package manager for some Unices 6 | License: Fair 7 | URL: https://github.com/icy/pacapt 8 | Source0: %{name}-%{version}.tar.gz 9 | BuildArch: noarch 10 | 11 | %description 12 | An Arch's pacman-like package manager for some Unices. Actually this Bash script provides a wrapper for system's package manager. For example, on CentOS machines, you can install htop with command 13 | 14 | $ pacapt -S htop 15 | 16 | Instead of remembering various options/tools on different OSs, you only need a common way to manipulate packages. Not all options of the native package manager are ported; the tool only provides a very basic interface to search, install, remove packages, and/or update the system. 17 | 18 | Arch's pacman is chosen, as pacman is quite smart when it divides all packages-related operations into three major groups: Synchronize, Query and Remove/Clean up. It has a clean man page, and it is the only tool needed to manipulate official packages on system. (Debian, for example, requires you to use apt-get, dpkg, and/or aptitude.) 19 | 20 | The tool supports the following package managers: 21 | 22 | pacman by Arch Linux, ArchBang, Manjaro, etc. 23 | dpkg/apt-get by Debian, Ubuntu, etc. 24 | homebrew by Mac OS X 25 | macports by Mac OS X 26 | yum/rpm by Redhat, CentOS, Fedora, etc. 27 | portage by Gentoo 28 | zypper by OpenSUSE 29 | pkgng by FreeBSD 30 | cave by Exherbo Linux 31 | pkg_tools by OpenBSD 32 | sun_tools by Solaris(SunOS) 33 | apk by Alpine Linux 34 | 35 | %prep 36 | %setup -q 37 | 38 | %build 39 | rm -rf bin,contrib,tests,lib,.gitignore,CHANGELOG.md,CONTRIBUTING.md,COPYING,Makefile,README.md,TODO 40 | 41 | %install 42 | mkdir -p %buildroot/usr/local/bin 43 | install -m755 pacapt %buildroot/usr/local/bin 44 | ln -s /usr/local/bin/pacapt %buildroot/usr/local/bin/pacman 45 | 46 | %clean 47 | rm -rf %_buildrootdir 48 | 49 | %files 50 | /usr/local/bin/pacapt 51 | /usr/local/bin/pacman 52 | 53 | %changelog 54 | * Sun Jun 17 2018 Ky-Anh Huynh(icy) - 1 55 | - Updated version (2.3.14 -> 2.3.15) 56 | * Thu Oct 20 2017 Ky-Anh Huynh(icy) - 1 57 | - Updated version (2.3.13 -> 2.3.14) 58 | * Thu Jul 21 2016 Ky-Anh Huynh(icy) - 1 59 | - Updated version (2.3.12 -> 2.3.13) 60 | * Wed Jul 20 2016 Ky-Anh Huynh(icy) - 1 61 | - Updated version (2.3.11 -> 2.3.12) 62 | * Mon Jul 11 2016 Ky-Anh Huynh(icy) - 1 63 | - Updated version (2.3.10 -> 2.3.11) 64 | * Mon Jul 11 2016 Ky-Anh Huynh(icy) - 1 65 | - Updated version (2.3.9 -> 2.3.10) 66 | * Fri Jul 8 2016 Ky-Anh Huynh(icy) - 1 67 | - Updated version (2.3.8 -> 2.3.9) 68 | * Fri Jul 8 2016 Valerio Pizzi(Pival81) - 1 69 | - Changed the installation directory (/usr/local/bin instead of /bin). 70 | * Fri Jun 10 2016 Valerio Pizzi(Pival81) - 1 71 | - Updated version (2.2.7 -> 2.3.8) 72 | * Thu Jun 9 2016 Valerio Pizzi(Pival81) - 1 73 | - Initial package. 74 | -------------------------------------------------------------------------------- /lib/00_core.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Provide some basic functions 4 | # Author : Anh K. Huynh 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2010 - 2021 Anh K. Huynh 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _error() { 17 | echo >&2 ":: Error: $*" 18 | return 1 19 | } 20 | 21 | _warn() { 22 | echo >&2 ":: Warning: $*" 23 | return 0 24 | } 25 | 26 | _die() { 27 | echo >&2 ":: $*" 28 | exit 1 29 | } 30 | 31 | _debug() { 32 | if [ -n "${PACAPT_DEBUG:-}" ]; then 33 | >&2 echo ":: [debug] $*" 34 | fi 35 | } 36 | 37 | _not_implemented() { 38 | # shellcheck disable=2153 39 | echo >&2 "${_PACMAN}: '${_POPT}:${_SOPT}:${_TOPT}' operation is invalid or not implemented." 40 | return 1 41 | } 42 | 43 | _removing_is_dangerous() { 44 | echo >&2 "${_PACMAN}: removing with '$*' is too dangerous" 45 | return 1 46 | } 47 | 48 | _require_programs() { 49 | for cmd in "$@"; do 50 | if ! command -v "$cmd" >/dev/null; then 51 | _die "pacapt(${_PACMAN:-_init}) requires '$cmd' but the tool is not found." 52 | fi 53 | done 54 | } 55 | 56 | # Detect package type from /etc/issue 57 | # FIXME: Using new `issue` file (location) 58 | _issue2pacman() { 59 | local_pacman="$1"; shift 60 | 61 | # The following line is added by Daniel YC Lin to support SunOS. 62 | # 63 | # [ `uname` = "$1" ] && _PACMAN="$_pacman" && return 64 | # 65 | # This is quite tricky and fast, however I don't think it works 66 | # on Linux/BSD systems. To avoid extra check, I slightly modify 67 | # the code to make sure it's only applicable on SunOS. 68 | # 69 | [ "$(uname)" = "SunOS" ] && _PACMAN="$local_pacman" && return 70 | 71 | $GREP -qis "$@" /etc/issue \ 72 | && _PACMAN="$local_pacman" && return 73 | 74 | $GREP -qis "$@" /etc/os-release \ 75 | && _PACMAN="$local_pacman" && return 76 | } 77 | 78 | # Detect package type 79 | _PACMAN_detect() { 80 | _PACMAN_found_from_script_name && return 81 | 82 | _issue2pacman sun_tools "SunOS" && return 83 | _issue2pacman pacman "Arch Linux" && return 84 | _issue2pacman dpkg "Debian GNU/Linux" && return 85 | _issue2pacman dpkg "Ubuntu" && return 86 | _issue2pacman cave "Exherbo Linux" && return 87 | _issue2pacman yum "CentOS" && return 88 | _issue2pacman yum "Red Hat" && return 89 | # 90 | # FIXME: The multiple package issue. 91 | # 92 | # On #63, Huy commented out this line. This is because new generation 93 | # of Fedora uses `dnf`, and `yum` becomes a legacy tool. On old Fedora 94 | # system, `yum` is still detectable by looking up `yum` binary. 95 | # 96 | # I'm not sure how to support this case easily. Let's wait, e.g, 5 years 97 | # from now to make `dnf` becomes a default? Oh no! 98 | # 99 | # And here why `pacman` is still smart. Debian has a set of tools. 100 | # Fedora has `yum` (and a set of add-ons). Now Fedora moves to `dnf`. 101 | # This means that a package manager is not a heart of a system ;) 102 | # 103 | # _issue2pacman yum "Fedora" && return 104 | _issue2pacman zypper "SUSE" && return 105 | _issue2pacman pkg_tools "OpenBSD" && return 106 | _issue2pacman pkg_tools "Bitrig" && return 107 | _issue2pacman apk "Alpine Linux" && return 108 | _issue2pacman opkg "OpenWrt" && return 109 | _issue2pacman xbps "Void" && return 110 | 111 | [ -z "$_PACMAN" ] || return 112 | 113 | # Prevent a loop when this script is installed on non-standard system 114 | if [ -x "/usr/bin/pacman" ]; then 115 | $GREP -q "_PACMAN_detect" '/usr/bin/pacman' >/dev/null 2>&1 116 | [ $? -ge 1 ] && _PACMAN="pacman" \ 117 | && return 118 | fi 119 | 120 | if uname -a | "$GREP" -q Cygwin; then 121 | command -v "apt-cyg" >/dev/null && _PACMAN="apt_cyg" && return 122 | fi 123 | [ -x "/usr/bin/apt-get" ] && _PACMAN="dpkg" && return 124 | [ -x "/data/data/com.termux/files/usr/bin/apt-get" ] && _PACMAN="dpkg" && return 125 | [ -x "/usr/bin/cave" ] && _PACMAN="cave" && return 126 | [ -x "/usr/bin/dnf" ] && _PACMAN="dnf" && return 127 | [ -x "/usr/bin/yum" ] && _PACMAN="yum" && return 128 | [ -x "/opt/local/bin/port" ] && _PACMAN="macports" && return 129 | [ -x "/usr/bin/emerge" ] && _PACMAN="portage" && return 130 | [ -x "/usr/bin/zypper" ] && _PACMAN="zypper" && return 131 | [ -x "/usr/sbin/pkg" ] && _PACMAN="pkgng" && return 132 | # make sure pkg_add is after pkgng, FreeBSD base comes with it until converted 133 | [ -x "/usr/sbin/pkg_add" ] && _PACMAN="pkg_tools" && return 134 | [ -x "/usr/sbin/pkgadd" ] && _PACMAN="sun_tools" && return 135 | [ -x "/sbin/apk" ] && _PACMAN="apk" && return 136 | [ -x "/bin/opkg" ] && _PACMAN="opkg" && return 137 | [ -x "/usr/bin/tazpkg" ] && _PACMAN="tazpkg" && return 138 | [ -x "/usr/bin/swupd" ] && _PACMAN="swupd" && return 139 | [ -x "/bin/xbps-install" ] && _PACMAN="xbps" && return 140 | 141 | command -v brew >/dev/null && _PACMAN="homebrew" && return 142 | 143 | return 1 144 | } 145 | 146 | # Translate -w option. Please note this is only valid when installing 147 | # a package from remote, aka. when '-S' operation is performed. 148 | _translate_w() { 149 | 150 | echo "$_EOPT" | $GREP -q ":w:" || return 0 151 | 152 | local_opt= 153 | local_ret=0 154 | 155 | case "$_PACMAN" in 156 | "dpkg") local_opt="-d";; 157 | "cave") local_opt="-f";; 158 | "dnf") local_opt="--downloadonly";; 159 | "macports") local_opt="fetch";; 160 | "portage") local_opt="--fetchonly";; 161 | "zypper") local_opt="--download-only";; 162 | "pkgng") local_opt="fetch";; 163 | "yum") local_opt="--downloadonly"; 164 | if ! rpm -q 'yum-downloadonly' >/dev/null 2>&1; then 165 | _error "'yum-downloadonly' package is required when '-w' is used." 166 | local_ret=1 167 | fi 168 | ;; 169 | "tazpkg") 170 | _error "$_PACMAN: Use '$_PACMAN get' to download and save packages to current directory." 171 | local_ret=1 172 | ;; 173 | "apk") local_opt="fetch";; 174 | "opkg") local_opt="--download-only";; 175 | "xbps") local_opt="-D";; 176 | *) 177 | local_opt="" 178 | local_ret=1 179 | 180 | _error "$_PACMAN: Option '-w' is not supported/implemented." 181 | ;; 182 | esac 183 | 184 | echo "$local_opt" 185 | return "$local_ret" 186 | } 187 | 188 | _translate_debug() { 189 | echo "$_EOPT" | $GREP -q ":v:" || return 0 190 | 191 | case "$_PACMAN" in 192 | "tazpkg") 193 | _error "$_PACMAN: Option '-v' (debug) is not supported/implemented by tazpkg" 194 | return 1 195 | ;; 196 | esac 197 | 198 | echo "-v" 199 | } 200 | 201 | # Translate the --noconfirm option. 202 | # FIXME: does "yes | pacapt" just help? 203 | _translate_noconfirm() { 204 | echo "$_EOPT" | $GREP -q ":noconfirm:" || return 0 205 | 206 | local_opt= 207 | local_ret=0 208 | 209 | case "$_PACMAN" in 210 | # FIXME: Update environment DEBIAN_FRONTEND=noninteractive 211 | # FIXME: There is also --force-yes for a stronger case 212 | "dpkg") local_opt="--yes";; 213 | "dnf") local_opt="--assumeyes";; 214 | "yum") local_opt="--assumeyes";; 215 | # FIXME: pacman has 'assume-yes' and 'assume-no' 216 | # FIXME: zypper has better mode. Similar to dpkg (Debian). 217 | "zypper") local_opt="--no-confirm";; 218 | "pkgng") local_opt="-y";; 219 | "tazpkg") local_opt="--auto";; 220 | "apk") local_opt="";; 221 | "xbps") local_opt="-y";; 222 | *) 223 | local_opt="" 224 | local_ret=1 225 | _error "$_PACMAN: Option '--noconfirm' is not supported/implemented." 226 | ;; 227 | esac 228 | 229 | echo "$local_opt" 230 | return "$local_ret" 231 | } 232 | 233 | _translate_all() { 234 | local_args="" 235 | local_debug= 236 | local_noconfirm= 237 | 238 | local_debug="$(_translate_debug)" || return 1 239 | local_noconfirm="$(_translate_noconfirm)" || return 1 240 | 241 | # WARNING: Order does matter, see also 242 | # https://github.com/icy/pacapt/pull/219#issuecomment-1006079629 243 | local_args="$(_translate_w)" || return 1 244 | local_args="${local_args}${local_noconfirm:+ }${local_noconfirm}" 245 | local_args="${local_args}${local_debug:+ }${local_debug}" 246 | 247 | export _EOPT="${local_args# }" 248 | } 249 | 250 | _print_supported_operations() { 251 | local_pacman="$1" 252 | printf "pacapt(%s): available operations:" "$local_pacman" 253 | # shellcheck disable=2016 254 | $GREP -E "^(#_!_POSIX_# )?${local_pacman}_[^ \\t]+\\(\\)" "$0" \ 255 | | $AWK -F '(' '{print $1}' \ 256 | | sed -e "s/.*${local_pacman}_//g" \ 257 | | while read -r O; do 258 | printf " %s" "$O" 259 | done 260 | echo 261 | } 262 | 263 | # NOTE: A few package managers will require their own implementation 264 | # NOTE: hence it's better to give some flexible option here. 265 | _quiet_field1() { 266 | if [ -z "${_TOPT}" ]; then 267 | cat 268 | else 269 | awk '{print $1}' 270 | fi 271 | } 272 | 273 | # Get nth char of from a string [the first index: 1] 274 | # https://github.com/icy/pacapt/pull/161/files#r654797953 275 | _string_nth() { 276 | local_idx="${1}"; shift 277 | local_args="${*}" 278 | 279 | local_args="${local_args}" local_idx="${local_idx}" \ 280 | "$AWK" 'BEGIN{printf("%s",substr(ENVIRON["local_args"],ENVIRON["local_idx"],1))}' 281 | } 282 | 283 | # https://github.com/icy/pacapt/pull/161/files#r654799601 284 | _string_less_than() { 285 | a="${1}" b="${2}" "$AWK" 'BEGIN {exit !(ENVIRON["a"] < ENVIRON["b"]) }' 286 | } 287 | -------------------------------------------------------------------------------- /lib/00_external.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose : Provide some basic settings for external package managers 4 | # Author : Ky-Anh Huynh 5 | # License : MIT 6 | # Date : 2018 July 26th 7 | # Ref. : https://github.com/icy/pacapt/issues/106 8 | 9 | export _SUPPORTED_EXTERNALS=" 10 | :conda 11 | :tlmgr 12 | :texlive 13 | :gem 14 | :npm 15 | :pip 16 | " 17 | readonly _SUPPORTED_EXTERNALS 18 | 19 | _PACMAN_found_from_script_name() { 20 | local_tmp_name= 21 | local_pacman= 22 | 23 | local_tmp_name="${0}" 24 | # https://github.com/icy/pacapt/pull/161/files#r654800412 25 | case "$local_tmp_name" in 26 | *-*) : ;; 27 | *) return 1 ;; 28 | esac 29 | 30 | local_tmp_name="${local_tmp_name##*/}" # base name (remove everything before the last `/`) 31 | local_tmp_name="${local_tmp_name%.*}" # remove extension if any (remove everything from the last `.`) 32 | local_pacman="${local_tmp_name##*-}" # remove every thing before the last `-` 33 | 34 | if echo "$_SUPPORTED_EXTERNALS" \ 35 | | "$GREP" -Eq -e ":${local_pacman}[[:space:]]*"; 36 | then 37 | export _PACMAN="$local_pacman" 38 | return 0 39 | else 40 | export _PACMAN="" 41 | _die "Unable to guess non-system package manager ($local_pacman) from script name '$0'." 42 | fi 43 | } 44 | -------------------------------------------------------------------------------- /lib/apk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Support next-generation Alpine Linux apk package manager 4 | # Author : Carl X. Su 5 | # Cuong Manh Le 6 | # License: Fair license (http://www.opensource.org/licenses/fair) 7 | # Source : http://github.com/icy/pacapt/ 8 | 9 | # Copyright (C) 2016 CuongLM 10 | # 11 | # Usage of the works is permitted provided that this instrument is 12 | # retained with the works, so that any entity that uses the works is 13 | # notified of this instrument. 14 | # 15 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 16 | 17 | _apk_init() { 18 | : 19 | } 20 | 21 | # apk_Q may _not_implemented 22 | # FIXME: Need to support a small list of packages 23 | apk_Q() { 24 | case "$_TOPT" in 25 | "") 26 | apk list --installed "$@" 27 | ;; 28 | "q") 29 | apk info 30 | ;; 31 | *) 32 | _not_implemented 33 | ;; 34 | esac 35 | } 36 | 37 | apk_Qe() { 38 | apk info | grep -x -f /etc/apk/world 39 | } 40 | 41 | apk_Qi() { 42 | if [ "$#" -eq 0 ]; then 43 | # shellcheck disable=SC2046 44 | apk info --all $(apk info) 45 | return 46 | fi 47 | 48 | # shellcheck disable=2086 49 | if apk info --installed $_TOPT "$@"; then 50 | # shellcheck disable=2086 51 | apk info --all $_TOPT "$@" 52 | else 53 | >&2 echo ":: Error: Package not installed: '${*}'" 54 | fi 55 | } 56 | 57 | apk_Ql() { 58 | if [ "$#" -eq 0 ]; then 59 | packages="$(apk info)" 60 | else 61 | packages="$*" 62 | fi 63 | 64 | for pkg in ${packages:-}; do 65 | apk info --contents "$pkg" \ 66 | | awk -v pkg="$pkg" '/\// {printf("%s %s\n", pkg, $0)}' 67 | done \ 68 | | { 69 | case $_TOPT in 70 | "q") awk '{print $NF}';; 71 | "") cat ;; 72 | *) _not_implemented ; exit 1;; 73 | esac 74 | } 75 | } 76 | 77 | apk_Qo() { 78 | if cmd="$(command -v -- "$@")"; then 79 | apk info --who-owns -- "$cmd" 80 | else 81 | apk info --who-owns -- "$@" 82 | fi 83 | } 84 | 85 | apk_Qs() { 86 | # shellcheck disable=2086 87 | apk list --installed $_TOPT "*${*}*" 88 | } 89 | 90 | apk_Qu() { 91 | apk version -l '<' 92 | } 93 | 94 | apk_R() { 95 | # shellcheck disable=2086 96 | apk del $_TOPT -- "$@" 97 | } 98 | 99 | apk_Rn() { 100 | # shellcheck disable=2086 101 | apk del --purge $_TOPT -- "$@" 102 | } 103 | 104 | apk_Rns() { 105 | # shellcheck disable=2086 106 | apk del --purge -r $_TOPT -- "$@" 107 | } 108 | 109 | apk_Rs() { 110 | # shellcheck disable=2086 111 | apk del -r $_TOPT -- "$@" 112 | } 113 | 114 | apk_S() { 115 | # shellcheck disable=2086 116 | case ${_EOPT} in 117 | # Download only 118 | (fetch*) shift 119 | apk fetch $_TOPT "$@" ;; 120 | (*) apk add $_TOPT "$@" ;; 121 | esac 122 | } 123 | 124 | apk_Sc() { 125 | apk cache -v clean 126 | } 127 | 128 | apk_Scc() { 129 | rm -rf /var/cache/apk/* 130 | } 131 | 132 | apk_Sccc() { 133 | apk_Scc 134 | } 135 | 136 | apk_Si() { 137 | # shellcheck disable=2086 138 | apk info $_TOPT "$@" 139 | } 140 | 141 | apk_Sii() { 142 | apk info -r -- "$@" 143 | } 144 | 145 | apk_Sl() { 146 | apk search -v -- "$@" 147 | } 148 | 149 | apk_Ss() { 150 | apk_Sl "$@" 151 | } 152 | 153 | apk_Su() { 154 | apk upgrade 155 | } 156 | 157 | apk_Suy() { 158 | if [ "$#" -gt 0 ]; then 159 | apk add -U -u -- "$@" 160 | else 161 | apk upgrade -U -a 162 | fi 163 | } 164 | 165 | apk_Sy() { 166 | apk update 167 | } 168 | 169 | apk_U() { 170 | # shellcheck disable=2086 171 | apk add --allow-untrusted $_TOPT -- "$@" 172 | } 173 | -------------------------------------------------------------------------------- /lib/apt_cyg.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose : pacman-style wrapper for cygwin/apt-cyg tool 4 | # Authors : Ky-Anh Huynh (icy) 5 | # Date : 2021-10-04 6 | # License : Public domain 7 | 8 | _apt_cyg_init() { 9 | : 10 | } 11 | 12 | apt_cyg_Ss() { 13 | apt-cyg search "$@" 14 | } 15 | 16 | apt_cyg_S() { 17 | apt-cyg install "$@" 18 | } 19 | 20 | apt_cyg_Sy() { 21 | apt-cyg update "$@" 22 | } 23 | 24 | apt_cyg_Q() { 25 | apt-cyg list "$@" 26 | } 27 | 28 | apt_cyg_Qi() { 29 | apt-cyg show "$@" 30 | } 31 | 32 | apt_cyg_Ql() { 33 | for pkg in "$@"; do 34 | if [ "$_TOPT" = "q" ]; then 35 | apt-cyg listfiles "$pkg" 36 | else 37 | apt-cyg listfiles "$pkg" \ 38 | | pkg="$pkg" \ 39 | awk '{printf("%s %s\n", ENVIRON["pkg"], $0)}' 40 | fi 41 | done 42 | } 43 | 44 | apt_cyg_R() { 45 | apt-cyg remove "$@" 46 | } 47 | -------------------------------------------------------------------------------- /lib/cave.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Purpose: Gentoo (+ Paludis) / Exherbo support 4 | # Author : Somasis 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/somasis/pacapt/ 7 | 8 | # Copyright (C) 2014 Somasis 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | # cave uses asterisks pretty liberally, this is for output parsing correctness 17 | # FIXME: This is the only thing we can't port this script to POSIX 18 | _cave_init() { 19 | shopt -u globstar 20 | } 21 | 22 | cave_Q() { 23 | if [ "$_TOPT" = "q" ]; then 24 | cave show -f "${@:-world}" \ 25 | | grep -v '^$' 26 | else 27 | cave show -f "${@:-world}" 28 | fi 29 | } 30 | 31 | cave_Qi() { 32 | cave show "$@" 33 | } 34 | 35 | cave_Ql() { 36 | if [ $# -ge 1 ]; then 37 | cave contents "$@" 38 | return 39 | fi 40 | 41 | cave show -f "${@:-world}" \ 42 | | grep -v '^$' \ 43 | | while read -r _pkg; do 44 | if [ "$_TOPT" = "q" ]; then 45 | cave --color no contents "$_pkg" 46 | else 47 | cave contents "$_pkg" 48 | fi 49 | done 50 | } 51 | 52 | cave_Qo() { 53 | if cmd="$(command -v -- "$@")"; then 54 | cave owner "$cmd" 55 | else 56 | cave owner "$@" 57 | fi 58 | } 59 | 60 | cave_Qp() { 61 | _not_implemented 62 | } 63 | 64 | cave_Qu() { 65 | if [ $# -eq 0 ];then 66 | cave resolve -c world \ 67 | | grep '^u.*' \ 68 | | while read -r _pkg; do 69 | echo "$_pkg" | cut -d'u' -f2- 70 | done 71 | else 72 | cave resolve -c world \ 73 | | grep '^u.*' \ 74 | | grep -- "$@" 75 | fi 76 | } 77 | 78 | cave_Qs() { 79 | cave show -f world | grep -- "$@" 80 | } 81 | 82 | cave_Rs() { 83 | if [ -z "$_TOPT" ]; then 84 | cave uninstall -r "$@" \ 85 | && echo "Control-C to stop uninstalling..." \ 86 | && sleep 2s \ 87 | && cave uninstall -xr "$@" 88 | else 89 | cave purge "$@" \ 90 | && echo "Control-C to stop uninstalling (+ dependencies)..." \ 91 | && sleep 2s \ 92 | && cave purge -x "$@" 93 | fi 94 | } 95 | 96 | cave_Rn() { 97 | _not_implemented 98 | } 99 | 100 | cave_Rns() { 101 | _not_implemented 102 | } 103 | 104 | cave_R() { 105 | cave uninstall "$@" \ 106 | && echo "Control-C to stop uninstalling..." \ 107 | && sleep 2s \ 108 | && cave uninstall -x "$@" 109 | } 110 | 111 | cave_Si() { 112 | cave show "$@" 113 | } 114 | 115 | cave_Suy() { 116 | cave sync && cave resolve -c "${@:-world}" \ 117 | && echo "Control-C to stop upgrading..." \ 118 | && sleep 2s \ 119 | && cave resolve -cx "${@:-world}" 120 | } 121 | 122 | cave_Su() { 123 | cave resolve -c "$@" \ 124 | && echo "Control-C to stop upgrading..." \ 125 | && sleep 2s \ 126 | && cave resolve -cx "$@" 127 | } 128 | 129 | cave_Sy() { 130 | cave sync "$@" 131 | } 132 | 133 | cave_Ss() { 134 | cave search "$@" 135 | } 136 | 137 | cave_Sc() { 138 | cave fix-cache "$@" 139 | } 140 | 141 | cave_Scc() { 142 | cave fix-cache "$@" 143 | } 144 | 145 | # cave_Sccc _not_implemented 146 | cave_Sccc() { 147 | #rm -fv /var/cache/paludis/* 148 | _not_implemented 149 | } 150 | 151 | cave_S() { 152 | # shellcheck disable=SC2086 153 | cave resolve $_TOPT "$@" \ 154 | && echo "Control-C to stop installing..." \ 155 | && sleep 2s \ 156 | && cave resolve -x $_TOPT "$@" 157 | } 158 | 159 | # cave_U _not_implemented 160 | cave_U() { 161 | _not_implemented 162 | } 163 | -------------------------------------------------------------------------------- /lib/conda.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose : conda support 4 | # Author : Antony Lee 5 | # License : MIT 6 | # Date : September 4, 2018 7 | 8 | # Copyright (C) 2018 Antony Lee 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _conda_init() { 17 | : 18 | } 19 | 20 | conda_Q() { 21 | if [ $# -gt 0 ]; then 22 | conda list "$(python -c 'import sys; print("^" + "|".join(sys.argv[1:]) + "$")' "$@")" 23 | else 24 | conda list 25 | fi 26 | } 27 | 28 | conda_Qo() { 29 | conda package --which "$@" 30 | } 31 | 32 | conda_R() { 33 | conda remove "$@" 34 | } 35 | 36 | conda_S() { 37 | conda install "$@" 38 | } 39 | 40 | conda_Sc() { 41 | conda clean --all "$@" 42 | } 43 | 44 | conda_Si() { 45 | conda search "$@" --info 46 | } 47 | 48 | conda_Ss() { 49 | conda search "*${*}*" 50 | } 51 | 52 | conda_Suy() { 53 | conda update --all "$@" 54 | } 55 | -------------------------------------------------------------------------------- /lib/dnf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Support next-generation Yum package manager 4 | # Author : Severus 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2015 Severus 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _dnf_init() { 17 | : 18 | } 19 | 20 | dnf_S() { 21 | # shellcheck disable=SC2086 22 | dnf install $_TOPT "$@" 23 | } 24 | 25 | dnf_Sc() { 26 | dnf clean expire-cache "$@" 27 | } 28 | 29 | dnf_Scc() { 30 | dnf clean packages "$@" 31 | } 32 | 33 | dnf_Sccc() { 34 | dnf clean all "$@" 35 | } 36 | 37 | dnf_Si() { 38 | dnf repoquery --requires --resolve "$@" 39 | } 40 | 41 | dnf_Sii() { 42 | dnf repoquery --installed --whatrequires "$@" 43 | } 44 | 45 | dnf_Sg() { 46 | if [ $# -gt 0 ]; then 47 | dnf group info "$@" 48 | else 49 | dnf group list 50 | fi 51 | } 52 | 53 | dnf_Sl() { 54 | dnf list available "$@" 55 | } 56 | 57 | dnf_Ss() { 58 | dnf search "$@" 59 | } 60 | 61 | dnf_Su() { 62 | dnf upgrade "$@" 63 | } 64 | 65 | dnf_Suy() { 66 | dnf upgrade "$@" 67 | } 68 | 69 | dnf_Sy() { 70 | dnf clean expire-cache && dnf check-update 71 | } 72 | 73 | # dnf_Q may _not_implemented 74 | dnf_Q() { 75 | if [ "$_TOPT" = "q" ]; then 76 | rpm -qa --qf "%{NAME}\\n" 77 | elif [ -z "$_TOPT" ]; then 78 | rpm -qa --qf "%{NAME} %{VERSION}\\n" 79 | else 80 | _not_implemented 81 | fi 82 | } 83 | 84 | dnf_Qc() { 85 | rpm -q --changelog "$@" 86 | } 87 | 88 | dnf_Qe() { 89 | dnf repoquery --userinstalled "$@" 90 | } 91 | 92 | dnf_Qi() { 93 | dnf info --installed "$@" && dnf repoquery --deplist "$@" 94 | } 95 | 96 | dnf_Ql() { 97 | rpm -ql "$@" 98 | } 99 | 100 | dnf_Qm() { 101 | dnf list extras 102 | } 103 | 104 | dnf_Qo() { 105 | if cmd="$(command -v -- "$@")"; then 106 | rpm -qf "$cmd" 107 | else 108 | rpm -qf "$@" 109 | fi 110 | } 111 | 112 | dnf_Qp() { 113 | rpm -qp "$@" 114 | } 115 | 116 | dnf_Qs() { 117 | rpm -qa "*${*}*" 118 | } 119 | 120 | dnf_Qu() { 121 | dnf list updates "$@" 122 | } 123 | 124 | dnf_R() { 125 | dnf remove "$@" 126 | } 127 | 128 | dnf_U() { 129 | dnf install "$@" 130 | } 131 | -------------------------------------------------------------------------------- /lib/dpkg.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Debian / Ubuntu support 4 | # Author : Anh K. Huynh 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2010 - 2021 Anh K. Huynh 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _dpkg_init() { 17 | : 18 | } 19 | 20 | # dpkg_Q may _not_implemented 21 | # FIXME: Need to support a small list of packages 22 | dpkg_Q() { 23 | if [ "$_TOPT" = "q" ]; then 24 | dpkg -l \ 25 | | grep -E '^[hi]i' \ 26 | | awk '{print $2}' 27 | elif [ -z "$_TOPT" ]; then 28 | dpkg -l "$@" \ 29 | | grep -E '^[hi]i' 30 | else 31 | _not_implemented 32 | fi 33 | } 34 | 35 | dpkg_Qc() { 36 | apt-get changelog "$@" 37 | } 38 | 39 | dpkg_Qi() { 40 | dpkg-query -s "$@" 41 | } 42 | 43 | dpkg_Qe() { 44 | apt-mark showmanual "$@" 45 | } 46 | 47 | dpkg_Qk() { 48 | _require_programs debsums 49 | debsums "$@" 50 | } 51 | 52 | dpkg_Ql() { 53 | if [ $# -ge 1 ]; then 54 | dpkg-query -L "$@" 55 | return 56 | fi 57 | 58 | dpkg -l \ 59 | | grep -E '^[hi]i' \ 60 | | awk '{print $2}' \ 61 | | while read -r _pkg; do 62 | if [ "$_TOPT" = "q" ]; then 63 | dpkg-query -L "$_pkg" 64 | else 65 | dpkg-query -L "$_pkg" \ 66 | | while read -r _line; do 67 | echo "$_pkg $_line" 68 | done 69 | fi 70 | done 71 | } 72 | 73 | dpkg_Qo() { 74 | if cmd="$(command -v -- "$@")"; then 75 | dpkg-query -S "$cmd" 76 | else 77 | dpkg-query -S "$@" 78 | fi 79 | } 80 | 81 | dpkg_Qp() { 82 | dpkg-deb -I "$@" 83 | } 84 | 85 | dpkg_Qu() { 86 | apt-get upgrade --trivial-only "$@" 87 | } 88 | 89 | # NOTE: Some field is available for dpkg >= 1.16.2 90 | # NOTE: Debian:Squeeze has dpkg < 1.16.2 91 | dpkg_Qs() { 92 | # dpkg >= 1.16.2 dpkg-query -W -f='${db:Status-Abbrev} ${binary:Package}\t${Version}\t${binary:Summary}\n' 93 | dpkg-query -W -f='${Status} ${Package}\t${Version}\t${Description}\n' \ 94 | | grep -E '^((hold)|(install)|(deinstall))' \ 95 | | sed -r -e 's#^(\w+ ){3}##g' \ 96 | | grep -Ei "${@:-.}" \ 97 | | _quiet_field1 98 | } 99 | 100 | # dpkg_Rs may _not_implemented 101 | dpkg_Rs() { 102 | if [ -z "$_TOPT" ]; then 103 | apt-get autoremove "$@" 104 | else 105 | _not_implemented 106 | fi 107 | } 108 | 109 | dpkg_Rn() { 110 | apt-get purge "$@" 111 | } 112 | 113 | dpkg_Rns() { 114 | apt-get --purge autoremove "$@" 115 | } 116 | 117 | dpkg_R() { 118 | apt-get remove "$@" 119 | } 120 | 121 | dpkg_Sg() { 122 | _require_programs tasksel 123 | 124 | if [ $# -gt 0 ]; then 125 | tasksel --task-packages "$@" 126 | else 127 | tasksel --list-task 128 | fi 129 | } 130 | 131 | dpkg_Si() { 132 | apt-cache show "$@" 133 | } 134 | 135 | dpkg_Suy() { 136 | apt-get update \ 137 | && apt-get upgrade "$@" \ 138 | && apt-get dist-upgrade "$@" 139 | } 140 | 141 | dpkg_Su() { 142 | apt-get upgrade "$@" \ 143 | && apt-get dist-upgrade "$@" 144 | } 145 | 146 | # See also https://github.com/icy/pacapt/pull/78 147 | # This `-w` option is implemented in `00_core/_translate_w` 148 | # 149 | # dpkg_Sw() { 150 | # apt-get --download-only install "$@" 151 | # } 152 | 153 | dpkg_Sy() { 154 | apt-get update "$@" 155 | } 156 | 157 | # FIXME: A simple implementation for #53 and 158 | # FIXME: https://github.com/icy/pacapt/pull/156 159 | # FIXME: but I'm not sure there is any issue... 160 | dpkg_Ss() { 161 | apt-cache search "${@:-.}" \ 162 | | while read -r name _ desc; do 163 | if ! dpkg-query -W "$name" > /dev/null 2>&1; then 164 | printf "package/%s \n %s\n" \ 165 | "$name" "$desc" 166 | else 167 | dpkg-query -W -f='package/${binary:Package} ${Version}\n ${binary:Summary}\n' "$name" 168 | fi 169 | done 170 | } 171 | 172 | dpkg_Sc() { 173 | apt-get clean "$@" 174 | } 175 | 176 | dpkg_Scc() { 177 | apt-get autoclean "$@" 178 | } 179 | 180 | dpkg_S() { 181 | # shellcheck disable=SC2086 182 | apt-get install $_TOPT "$@" 183 | } 184 | 185 | dpkg_U() { 186 | dpkg -i "$@" 187 | } 188 | 189 | dpkg_Sii() { 190 | apt-cache rdepends "$@" 191 | } 192 | 193 | dpkg_Sccc() { 194 | rm -fv /var/cache/apt/*.bin 195 | rm -fv /var/cache/apt/archives/*.* 196 | rm -fv /var/lib/apt/lists/*.* 197 | apt-get autoclean 198 | } 199 | -------------------------------------------------------------------------------- /lib/help.txt: -------------------------------------------------------------------------------- 1 | NAME 2 | pacapt - An `ArchLinux`'s pacman-like wrapper for many package managers. 3 | 4 | SYNTAX 5 | 6 | $ pacapt 7 | 8 | BASIC OPTIONS 9 | 10 | -h or --help print this help message 11 | -P print supported operations 12 | -V print version information 13 | 14 | SYSGET STYLE OPERATIONS 15 | 16 | update Update package database 17 | upgrade Upgrade system 18 | install Install some packages 19 | search Search some package 20 | remove Remove some packages 21 | autoremove Remove orphans (WIP; may not work correctly) 22 | clean Clean package manager caches 23 | 24 | PACMAN STYLE OPERATIONS 25 | 26 | Query 27 | -Q list all installed packages 28 | -Qc show package's changelog 29 | -Qe [] only list explicitly installed packages 30 | -Qi print package status 31 | -Ql list package's files 32 | -Qm list installed packages that aren't available 33 | in any installation source 34 | -Qo query package that provides 35 | -Qp query a package file (don't use package database) 36 | -Qs search for installed package 37 | 38 | Synchronize 39 | -S install package(s) 40 | -Sg list groups 41 | -Sg list packages in group 42 | -Ss search for packages 43 | -Su upgrade the system 44 | -Sy update package database 45 | -Suy update package database, then upgrade the system 46 | 47 | Remove / Clean up 48 | -R remove some packages 49 | -Sc delete old downloaded packages 50 | -Scc delete all downloaded packages 51 | -Sccc clean variant files. 52 | (debian) See also http://dragula.viettug.org/blogs/646 53 | 54 | Upgrade 55 | -U upgrade or add package from local file path (or remote uri) 56 | 57 | OPTIONS 58 | 59 | -w download packages but don't install them 60 | --noconfirm don't wait for user's confirmation 61 | 62 | EXAMPLES 63 | 64 | 1. To install a package from Debian's backports repository 65 | $ pacapt -S foobar -t lenny-backports 66 | $ pacapt -S -- -t lenny-backports foobar 67 | 68 | 2. To update package database and then update your system 69 | $ pacapt -Syu 70 | 71 | 3. To download a package without installing it 72 | $ pacapt -Sw foobar 73 | 74 | 75 | ENVIRONMENT 76 | 77 | PACAPT_DEBUG 78 | 79 | This is useful for debugging purpose. The variable can be set to `auto` 80 | or any valid packager. For example, on `Debian` system the two following 81 | commands are the same and they will print out what the script would do: 82 | 83 | PACAPT_DEBUG=auto pacman -Su 84 | PACAPT_DEBUG=dpkg pacman -Su 85 | 86 | NOTES 87 | 88 | When being executed on Arch-based system, the tool simply invokes 89 | the system package manager (`/usr/bin/pacman`). 90 | 91 | Though you can specify option by its own word, for example, 92 | $ pacapt -S -y -u 93 | 94 | it's always the best to combine them 95 | $ pacapt -Syu 96 | 97 | READMORE 98 | 99 | Please visit https://github.com/icy/pacapt. 100 | -------------------------------------------------------------------------------- /lib/homebrew.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Homebrew support 4 | # Author : James Pearson 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2010 - 2014 James Pearson 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _homebrew_init() { 17 | : 18 | } 19 | 20 | homebrew_Qi() { 21 | brew info "$@" 22 | } 23 | 24 | # NOTE: `Ql` will print list of packages! This is a `brew` feature 25 | # 26 | # NOTE: $ brew list # list all packages 27 | # NOTE: $ brew list nano # list all nano's files (short list) 28 | # 29 | # NOTE: `homebrew` detects the stdout stream and modifies the result. 30 | # NOTE: For example, `homebrew list nano` only gives short output 31 | # NOTE: by default, but when being used with pipe it will print all 32 | # NOTE: files (which can be very slow/long) 33 | # 34 | # NOTE: $ brew list nano | cat # list all files (full list) 35 | # 36 | homebrew_Ql() { 37 | local_casks= 38 | local_forumlas= 39 | 40 | if [ $# -eq 0 ]; then 41 | local_casks="$(brew list --casks)" 42 | local_forumlas="$(brew list --formula)" 43 | else 44 | # FIXME: this awk is not perfect! 45 | local_casks="$(brew list --casks | LIST="$*" awk '$0 ~ ENVIRON["LIST"]')" 46 | local_forumlas="$(brew list --formula | LIST="$*" awk '$0 ~ ENVIRON["LIST"]')" 47 | fi 48 | 49 | if [ -z "$_TOPT" ]; then 50 | for package in $local_casks; do 51 | brew list --cask "$package" \ 52 | | grep ^/ \ 53 | | PACKAGE="$package" awk '{printf("%s %s\n", ENVIRON["PACKAGE"], $0)}' 54 | done 55 | for package in $local_forumlas; do 56 | brew list --formula "$package" \ 57 | | PACKAGE="$package" awk '{printf("%s %s\n", ENVIRON["PACKAGE"], $0)}' 58 | done 59 | elif [ "$_TOPT" = "q" ]; then 60 | for package in $local_casks; do 61 | brew list --cask "$package" \ 62 | | grep ^/ 63 | done 64 | for package in $local_forumlas; do 65 | brew list --formula "$package" 66 | done 67 | fi 68 | } 69 | 70 | # Please note that `brew list` lists all packages, 71 | # but `brew list nano` lists all files from `nano`. 72 | # Hence we need to provide `grep` command here. 73 | # FIXME: Also search in ... package description 74 | # FIXME: `homebrew search` does search online/locally (both!) 75 | # FIXME: and it may provide more options. We don't use them now. 76 | homebrew_Qs() { 77 | if [ -z "$_TOPT" ]; then 78 | local_flags="--versions" 79 | else 80 | local_flags="" 81 | fi 82 | # shellcheck disable=SC2086 83 | brew list $local_flags | grep "${@:-.}" 84 | } 85 | 86 | # FIXME # homebrew_Qo() { 87 | # FIXME # local_pkg= 88 | # FIXME # local_prefix= 89 | # FIXME # local_cellar= 90 | # FIXME # 91 | # FIXME # # FIXME: What happens if the file is not exectutable? 92 | # FIXME # cd "$(dirname -- "$(command -v "$@")")" || return 93 | # FIXME # 94 | # FIXME # local_pkg="$(pwd -P)/$(basename -- "$@")" 95 | # FIXME # local_prefix="$(brew --prefix)" 96 | # FIXME # local_cellar="$(brew --cellar)" 97 | # FIXME # 98 | # FIXME # for package in "${local_cellar}"/*; do 99 | # FIXME # files=(${package}/*/${local_pkg/#${local_prefix}\//}) 100 | # FIXME # if [[ -e "${files[${#files[@]} - 1]}" ]]; then 101 | # FIXME # echo "${package/#${local_cellar}\//}" 102 | # FIXME # break 103 | # FIXME # fi 104 | # FIXME # done 105 | # FIXME # } 106 | 107 | homebrew_Qc() { 108 | brew log "$@" 109 | } 110 | 111 | # FIXME: The result may vary and we don't have a fixed expectation 112 | homebrew_Qu() { 113 | brew outdated "$@" 114 | } 115 | 116 | homebrew_Q() { 117 | if [ -z "$_TOPT" ]; then 118 | local_flags="--versions" 119 | else 120 | local_flags="" 121 | fi 122 | # shellcheck disable=SC2086 123 | brew list $local_flags --formula "$@" 124 | # shellcheck disable=SC2086 125 | brew list $local_flags --cask "$@" 126 | } 127 | 128 | # FIXME # homebrew_Rs() { 129 | # FIXME # _require_programs join sort 130 | # FIXME # 131 | # FIXME # if [ $# -eq 0 ]; then 132 | # FIXME # _die "pacapt(homebrew_Rs) missing arguments." 133 | # FIXME # fi 134 | # FIXME # 135 | # FIXME # for _target in "$@"; do 136 | # FIXME # brew rm "$_target" 137 | # FIXME # 138 | # FIXME # while [ "$(join <(sort <(brew leaves)) <(sort <(brew deps $_target)))" != "" ] 139 | # FIXME # do 140 | # FIXME # brew rm $(join <(sort <(brew leaves)) <(sort <(brew deps $_target))) 141 | # FIXME # done 142 | # FIXME # done 143 | # FIXME # } 144 | 145 | homebrew_R() { 146 | brew remove "$@" 147 | } 148 | 149 | homebrew_Si() { 150 | brew info "$@" 151 | } 152 | 153 | homebrew_Suy() { 154 | brew update \ 155 | && brew upgrade "$@" 156 | } 157 | 158 | homebrew_Su() { 159 | brew upgrade "$@" 160 | } 161 | 162 | homebrew_Sy() { 163 | brew update "$@" 164 | } 165 | 166 | homebrew_Ss() { 167 | brew search "$@" 168 | } 169 | 170 | homebrew_Sc() { 171 | brew cleanup "$@" 172 | } 173 | 174 | homebrew_Scc() { 175 | brew cleanup -s "$@" 176 | } 177 | 178 | homebrew_Sccc() { 179 | # See more discussion in 180 | # https://github.com/icy/pacapt/issues/47 181 | local_dcache="$(brew --cache)" 182 | case "$local_dcache" in 183 | ""|"/"|" ") 184 | _error "pacapt(homebrew_Sccc): Unable to delete '$local_dcache'." 185 | ;; 186 | 187 | *) 188 | # FIXME: This can be wrong. But it's an easy way 189 | # FIXME: to avoid some warning from #shellcheck. 190 | # FIXME: Please note that, $_dcache is not empty now. 191 | rm -rf "${local_dcache:-/x/x/x/x/x/x/x/x/x/x/x//x/x/x/x/x/}/" 192 | ;; 193 | esac 194 | } 195 | 196 | # NOTE: New version of homebrew will automatically invoke `brew cask install` 197 | # NOTE: if formula is not available. 198 | homebrew_S() { 199 | # shellcheck disable=SC2086 200 | 2>&1 brew install $_TOPT "$@" \ 201 | | awk '{print; if ($0 ~ /brew cask install/) { exit(126); }}' 202 | if [ "${?}" = 126 ]; then 203 | _warn "Failed to install package, now trying with 'brew cask' as suggested..." 204 | # shellcheck disable=SC2086 205 | brew cask install $_TOPT "$@" 206 | fi 207 | } 208 | -------------------------------------------------------------------------------- /lib/macports.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Macports support 4 | # Author : 10sr 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2010 - 2014 10sr 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _macports_init() { 17 | : 18 | } 19 | 20 | macports_Ql() { 21 | port contents "$@" 22 | } 23 | 24 | macports_Qo() { 25 | if cmd="$(command -v -- "$@")"; then 26 | port provides "$cmd" 27 | else 28 | port provides "$@" 29 | fi 30 | } 31 | 32 | macports_Qc() { 33 | port log "$@" 34 | } 35 | 36 | macports_Qu() { 37 | port outdated "$@" 38 | } 39 | 40 | # macports_Rs may _not_implemented 41 | macports_Rs() { 42 | if [ -z "$_TOPT" ]; then 43 | port uninstall --follow-dependencies "$@" 44 | else 45 | _not_implemented 46 | fi 47 | } 48 | 49 | macports_R() { 50 | port uninstall "$@" 51 | } 52 | 53 | macports_Si() { 54 | port info "$@" 55 | } 56 | 57 | macports_Suy() { 58 | port selfupdate \ 59 | && port upgrade outdated "$@" 60 | } 61 | 62 | macports_Su() { 63 | port upgrade outdate "$@" 64 | } 65 | 66 | # FIXME: update or sync? 67 | macports_Sy() { 68 | port selfupdate "$@" 69 | } 70 | 71 | macports_Ss() { 72 | port search "$@" 73 | } 74 | 75 | macports_Sc() { 76 | port clean --all inactive "$@" 77 | } 78 | 79 | macports_Scc() { 80 | port clean --all installed "$@" 81 | } 82 | 83 | macports_S() { 84 | # shellcheck disable=SC2153 85 | case "$_EOPT" in 86 | fetch*) 87 | shift 88 | port patch "$@" 89 | ;; 90 | *) 91 | port install "$@" 92 | ;; 93 | esac 94 | } 95 | -------------------------------------------------------------------------------- /lib/opkg.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Support opkg (e.g. OpenWrt) 4 | # Author : Ky-Anh Huynh 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2021 Ky-Anh Huynh 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _opkg_init() { 17 | : 18 | } 19 | 20 | opkg_Sy() { 21 | opkg update 22 | } 23 | 24 | opkg_Q() { 25 | # shellcheck disable=SC2016 26 | case "$_TOPT" in 27 | "q") 28 | opkg list-installed "$@" | "$AWK" '{print $1}' 29 | ;; 30 | "") 31 | opkg list-installed "$@" 32 | ;; 33 | *) 34 | _not_implemented 35 | ;; 36 | esac 37 | } 38 | 39 | opkg_Qi() { 40 | for pkg in $(opkg__get_local_pkgs "$@"); do 41 | opkg info "$pkg" 42 | done 43 | } 44 | 45 | # Get list of installed-packages from user list. 46 | opkg__get_local_pkgs() { 47 | if [ "$#" -eq 0 ]; then 48 | # shellcheck disable=SC2016 49 | opkg list-installed | "$AWK" '{print $1}' 50 | else 51 | # `opkg status` returns empty if package is not installed/removed. 52 | # shellcheck disable=SC2016 53 | for pkg in "$@"; do 54 | opkg status "$pkg" 55 | done \ 56 | | "$AWK" '/^Package: / {print $NF}' 57 | fi 58 | } 59 | 60 | opkg_Ql() { 61 | for pkg in $(opkg__get_local_pkgs "$@"); do 62 | # shellcheck disable=SC2016 63 | opkg files "$pkg" \ 64 | | PKG="$pkg" "$AWK" \ 65 | '{ if (NR>1) {printf("%s %s\n", ENVIRON["PKG"], $0)} }' 66 | done 67 | } 68 | 69 | opkg_Qo() { 70 | if cmd="$(command -v -- "$@")"; then 71 | opkg search "$cmd" 72 | else 73 | opkg search "$@" 74 | fi 75 | } 76 | 77 | opkg_Qs() { 78 | if command -v sort >/dev/null; then 79 | local_filter="sort -u" 80 | else 81 | local_filter="cat" 82 | fi 83 | 84 | # FIXME: opkg doesn't work with wildcard by default. 85 | case "$@" in 86 | *\**) local_pattern="$*" ;; 87 | *) local_pattern="*${*}*" ;; 88 | esac 89 | 90 | opkg search "$local_pattern" \ 91 | | ${local_filter} \ 92 | | _quiet_field1 93 | } 94 | 95 | # FIXME: It's not easy to test this method =)) 96 | opkg_Qu() { 97 | opkg list-upgradable 98 | } 99 | 100 | opkg_R() { 101 | opkg remove "$@" 102 | } 103 | 104 | opkg_S() { 105 | opkg install "$@" 106 | } 107 | 108 | opkg_Si() { 109 | # shellcheck disable=2086 110 | opkg list $_TOPT "$@" 111 | } 112 | 113 | opkg_Sii() { 114 | # shellcheck disable=2086 115 | opkg list $_TOPT "$@" 116 | opkg whatdepends "$@" 117 | } 118 | 119 | opkg_Ss() { 120 | opkg list "$@" 121 | } 122 | 123 | opkg_Su() { 124 | opkg upgrade "$@" 125 | } 126 | 127 | opkg_U() { 128 | opkg install "$@" 129 | } 130 | -------------------------------------------------------------------------------- /lib/pkg_tools.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: OpenBSD support 4 | # Author : Somasis 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/somasis/pacapt 7 | 8 | # Copyright (C) 2014 Somasis 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _pkg_tools_init() { 17 | : 18 | } 19 | 20 | pkg_tools_Qi() { 21 | # disable searching mirrors for packages 22 | export PKG_PATH= 23 | pkg_info "$@" 24 | } 25 | 26 | pkg_tools_Ql() { 27 | export PKG_PATH= 28 | pkg_info -L "$@" 29 | } 30 | 31 | pkg_tools_Qo() { 32 | export PKG_PATH= 33 | if cmd="$(command -v -- "$@")"; then 34 | pkg_info -E "$cmd" 35 | else 36 | pkg_info -E "$@" 37 | fi 38 | } 39 | 40 | pkg_tools_Qp() { 41 | _not_implemented 42 | } 43 | 44 | pkg_tools_Qu() { 45 | export PKG_PATH= 46 | pkg_add -u "$@" 47 | } 48 | 49 | # pkg_tools_Q may _not_implemented 50 | pkg_tools_Q() { 51 | export PKG_PATH= 52 | # the dash after the pkg name is so we don't catch partial matches 53 | # because all packages in openbsd have the format 'pkgname-pkgver' 54 | if [ "$_TOPT" = "q" ] && [ -n "$*" ]; then 55 | pkg_info -q | grep "^${*}-" 56 | elif [ "$_TOPT" = "q" ] && [ -z "$*" ];then 57 | pkg_info -q 58 | elif [ "$_TOPT" = "" ] && [ -n "$*" ]; then 59 | pkg_info | grep "^${*}-" 60 | elif [ "$_TOPT" = "" ] && [ -z "$*" ];then 61 | pkg_info 62 | else 63 | _not_implemented 64 | fi 65 | } 66 | 67 | # pkg_tools_Rs may _not_implemented 68 | pkg_tools_Rs() { 69 | if [ -z "$_TOPT" ]; then 70 | pkg_delete -D dependencies "$@" 71 | else 72 | _not_implemented 73 | fi 74 | } 75 | 76 | # pkg_tools_rn may _not_implemented 77 | pkg_tools_Rn() { 78 | if [ -z "$_TOPT" ];then 79 | pkg_delete -c "$@" 80 | else 81 | _not_implemented 82 | fi 83 | } 84 | 85 | # pkg_tools_rns _not_implemented 86 | pkg_tools_Rns() { 87 | _not_implemented 88 | } 89 | 90 | pkg_tools_R() { 91 | pkg_delete "$@" 92 | } 93 | 94 | pkg_tools_Si() { 95 | pkg_info "$@" 96 | } 97 | 98 | pkg_tools_Sl() { 99 | pkg_info -L "$@" 100 | } 101 | 102 | pkg_tools_Suy() { 103 | # pkg_tools doesn't really have any concept of a database 104 | # there's actually not really any database to update, so 105 | # this function is mostly just for convenience since on arch 106 | # doing -Su is normally a bad thing to do since it's a partial upgrade 107 | 108 | pkg_tools_Su "$@" 109 | } 110 | 111 | pkg_tools_Su() { 112 | pkg_add -u "$@" 113 | } 114 | 115 | # pkg_tools_Sy _not_implemented 116 | pkg_tools_Sy() { 117 | _not_implemented 118 | } 119 | 120 | # pkg_tools_Ss may _not_implemented 121 | pkg_tools_Ss() { 122 | if [ -z "$*" ];then 123 | _not_implemented 124 | else 125 | pkg_info -Q "$@" 126 | fi 127 | } 128 | 129 | pkg_tools_Sc() { 130 | # by default no cache directory is used 131 | if [ -z "$PKG_CACHE" ];then 132 | echo "You have no cache directory set, set \$PKG_CACHE for a cache directory." 133 | elif [ ! -d "$PKG_CACHE" ];then 134 | echo "You have a cache directory set, but it does not exist. Create \"$PKG_CACHE\"." 135 | else 136 | _removing_is_dangerous "rm -rf $PKG_CACHE/*" 137 | fi 138 | } 139 | 140 | # pkg_tools_Scc _not_implemented 141 | pkg_tools_Scc() { 142 | _not_implemented 143 | } 144 | 145 | pkg_tools_S() { 146 | pkg_add "$@" 147 | } 148 | -------------------------------------------------------------------------------- /lib/pkgng.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: FreeBSD support 4 | # Author : Konrad Borowski 5 | # Date : Dec 18 2013 6 | # License: Fair license (http://www.opensource.org/licenses/fair) 7 | # Source : http://github.com/icy/pacapt/ 8 | # Pull : https://github.com/icy/pacapt/pull/25 9 | # Note : The pull request is applicable to `master` branch. 10 | # Anh K. Huynh slightly modified the pull request to 11 | # use them on the `ng` branch (on May 05 2014) 12 | 13 | # Copyright (C) 2013 - 2014 Konrad Borowski 14 | # 15 | # Usage of the works is permitted provided that this instrument is 16 | # retained with the works, so that any entity that uses the works is 17 | # notified of this instrument. 18 | # 19 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 20 | 21 | _pkgng_init() { 22 | : 23 | } 24 | 25 | pkgng_Qi() { 26 | pkg info "$@" 27 | } 28 | 29 | pkgng_Ql() { 30 | pkg info -l "$@" 31 | } 32 | 33 | pkgng_Qo() { 34 | if cmd="$(command -v -- "$@")"; then 35 | pkg which "$cmd" 36 | else 37 | pkg which "$@" 38 | fi 39 | } 40 | 41 | pkgng_Qp() { 42 | pkg query -F "$@" '%n %v' 43 | } 44 | 45 | pkgng_Qu() { 46 | pkg upgrade -n "$@" 47 | } 48 | 49 | pkgng_Q() { 50 | if [ "$_TOPT" = "q" ]; then 51 | pkg query '%n' "$@" 52 | elif [ -z "$_TOPT" ]; then 53 | pkg query '%n %v' "$@" 54 | else 55 | _not_implemented 56 | fi 57 | } 58 | 59 | pkgng_Rs() { 60 | if [ -z "$_TOPT" ]; then 61 | pkg remove "$@" 62 | pkg autoremove 63 | else 64 | _not_implemented 65 | fi 66 | } 67 | 68 | pkgng_R() { 69 | pkg remove "$@" 70 | } 71 | 72 | pkgng_Si() { 73 | pkg search -S name -ef "$@" 74 | } 75 | 76 | pkgng_Suy() { 77 | pkg upgrade "$@" 78 | } 79 | 80 | pkgng_Su() { 81 | pkg upgrade -U "$@" 82 | } 83 | 84 | pkgng_Sy() { 85 | pkg update "$@" 86 | } 87 | 88 | pkgng_Ss() { 89 | pkg search "$@" 90 | } 91 | 92 | pkgng_Sc() { 93 | pkg clean "$@" 94 | } 95 | 96 | pkgng_Scc() { 97 | pkg clean -a "$@" 98 | } 99 | 100 | pkgng_S() { 101 | # shellcheck disable=SC2153 102 | case "$_EOPT" in 103 | fetch*) 104 | shift 105 | pkg fetch "$@" 106 | ;; 107 | *) 108 | pkg install "$@" 109 | ;; 110 | esac 111 | } 112 | -------------------------------------------------------------------------------- /lib/portage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Gentoo support 4 | # Author : Hà-Dương Nguyễn 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2010 - 2014 Hà-Dương Nguyễn 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _portage_init() { 17 | : 18 | } 19 | 20 | portage_Qi() { 21 | emerge --info "$@" 22 | } 23 | 24 | portage_Ql() { 25 | if [ -x '/usr/bin/qlist' ]; then 26 | qlist "$@" 27 | elif [ -x '/usr/bin/equery' ]; then 28 | equery files "$@" 29 | else 30 | _error "'portage-utils' or 'gentoolkit' package is required to perform this operation." 31 | fi 32 | } 33 | 34 | portage_Qo() { 35 | if [ -x '/usr/bin/equery' ]; then 36 | if cmd="$(command -v -- "$@")"; then 37 | equery belongs "$cmd" 38 | else 39 | equery belongs "$@" 40 | fi 41 | else 42 | _error "'gentoolkit' package is required to perform this operation." 43 | fi 44 | } 45 | 46 | portage_Qc() { 47 | emerge -p --changelog "$@" 48 | } 49 | 50 | # FIXME: may not be correct 51 | portage_Qu() { 52 | emerge -uvN "$@" 53 | } 54 | 55 | portage_Q() { 56 | if [ -z "$_TOPT" ]; then 57 | if [ -x '/usr/bin/eix' ]; then 58 | eix -I "$@" 59 | elif [ -x '/usr/bin/equery' ]; then 60 | equery list -i "$@" 61 | else 62 | LS_COLORS="never" \ 63 | ls -1 -d /var/db/pkg/*/* 64 | fi 65 | else 66 | _not_implemented 67 | fi 68 | } 69 | 70 | portage_Rs() { 71 | if [ -z "$_TOPT" ]; then 72 | emerge --depclean world "$@" 73 | else 74 | _not_implemented 75 | fi 76 | } 77 | 78 | portage_R() { 79 | emerge --depclean "$@" 80 | } 81 | 82 | portage_Si() { 83 | emerge --info "$@" 84 | } 85 | 86 | portage_Suy() { 87 | if [ -x '/usr/bin/layman' ]; then 88 | layman --sync-all \ 89 | && emerge --sync \ 90 | && emerge -auND world "$@" 91 | else 92 | emerge --sync \ 93 | && emerge -uND world "$@" 94 | fi 95 | } 96 | 97 | portage_Su() { 98 | emerge -uND world "$@" 99 | } 100 | 101 | portage_Sy() { 102 | if [ -x "/usr/bin/layman" ]; then 103 | layman --sync-all \ 104 | && emerge --sync "$@" 105 | else 106 | emerge --sync "$@" 107 | fi 108 | } 109 | 110 | portage_Ss() { 111 | if [ -x "/usr/bin/eix" ]; then 112 | eix "$@" 113 | else 114 | emerge --search "$@" 115 | fi 116 | } 117 | 118 | portage_Sc() { 119 | if [ -x "/usr/bin/eclean-dist" ]; then 120 | eclean-dist -d -t1m -s50 -f "$@" 121 | else 122 | _error "'gentoolkit' package is required to perform this operation." 123 | fi 124 | } 125 | 126 | portage_Scc() { 127 | if [ -x "/usr/bin/eclean" ]; then 128 | eclean -i distfiles "$@" 129 | else 130 | _error "'gentoolkit' package is required to perform this operation." 131 | fi 132 | } 133 | 134 | portage_Sccc() { 135 | rm -fv /usr/portage/distfiles/*.* 136 | } 137 | 138 | portage_S() { 139 | emerge "$@" 140 | } 141 | -------------------------------------------------------------------------------- /lib/sun_tools.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: SunOS support 4 | # Author : Daniel YC Lin 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/dlintw/pacapt 7 | 8 | # Copyright (C) 2015 Daniel YC Lin 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | # Initialize special things for SunOS system. 17 | # This method is invoked on any system though, 18 | # and it returns 1 if the current OS is not SunOS. 19 | _sun_tools_init() { 20 | # The purpose of `if` is to make sure this function 21 | # can be invoked on other system (Linux, BSD). 22 | if [ "$(uname)" = "SunOS" ]; then 23 | export GREP=/usr/xpg4/bin/grep 24 | export AWK=nawk 25 | return 0 26 | fi 27 | return 1 28 | } 29 | 30 | sun_tools_Qi() { 31 | pkginfo -l "$@" 32 | } 33 | 34 | sun_tools_Ql() { 35 | pkginfo -l "$@" 36 | } 37 | 38 | sun_tools_Qo() { 39 | if cmd="$(command -v -- "$@")"; then 40 | $GREP "$cmd" /var/sadm/install/contents 41 | else 42 | $GREP "$@" /var/sadm/install/contents 43 | fi 44 | } 45 | 46 | sun_tools_Qs() { 47 | pkginfo | $GREP -i "$@" 48 | } 49 | 50 | sun_tools_Q() { 51 | # the dash after the pkg name is so we don't catch partial matches 52 | # because all packages in openbsd have the format 'pkgname-pkgver' 53 | if [ "$_TOPT" = "q" ] && [ -n "$*" ]; then 54 | pkginfo | $GREP "$@" 55 | elif [ "$_TOPT" = "q" ] && [ -z "$*" ]; then 56 | pkginfo 57 | else 58 | pkginfo "$@" 59 | fi 60 | } 61 | 62 | sun_tools_R() { 63 | pkgrm "$@" 64 | } 65 | 66 | sun_tools_U() { 67 | pkgadd "$@" 68 | } 69 | -------------------------------------------------------------------------------- /lib/swupd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Clear Linux support 4 | # Author : Dmitry Kudriavtsev 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/dkudriavtsev/pacapt/ 7 | 8 | # Copyright (C) 2014 Dmitry Kudriavtsev 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _swupd_init() { 17 | : 18 | } 19 | 20 | swupd_Q() { 21 | swupd bundle-list "$@" 22 | } 23 | 24 | swupd_Qi() { 25 | swupd bundle-info "$@" 26 | } 27 | 28 | swupd_Qk() { 29 | swupd verify "$@" 30 | } 31 | 32 | swupd_Qo() { 33 | if cmd="$(command -v -- "$@")"; then 34 | swupd search "$cmd" 35 | else 36 | swupd search "$@" 37 | fi 38 | } 39 | 40 | swupd_Qs() { 41 | swupd search "$@" 42 | } 43 | 44 | swupd_R() { 45 | swupd bundle-remove "$@" 46 | } 47 | 48 | swupd_Sc() { 49 | swupd clean "$@" 50 | } 51 | 52 | swupd_Scc() { 53 | swupd clean --all "$@" 54 | } 55 | 56 | swupd_Suy() { 57 | swupd update 58 | } 59 | 60 | swupd_Su() { 61 | swupd update 62 | } 63 | 64 | swupd_Sy() { 65 | swupd update 66 | } 67 | 68 | swupd_Ss() { 69 | swupd search "$@" 70 | } 71 | 72 | swupd_S() { 73 | swupd bundle-add "$@" 74 | } 75 | -------------------------------------------------------------------------------- /lib/tazpkg.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Provide Slitaz support for pacapt script 4 | # Author : Anh K. Huynh 5 | # Date : 2016 July 08th 6 | # License: MIT 7 | 8 | _tazpkg_init() { 9 | : 10 | } 11 | 12 | # tarpkg_Q may _not_implemented 13 | tazpkg_Q() { 14 | if [ "$_TOPT" = "q" ]; then 15 | tazpkg list "$@" \ 16 | | awk '{ if (NF == 2 || NF == 3) { print $1; }}' 17 | elif [ -z "$_TOPT" ]; then 18 | tazpkg list "$@" 19 | else 20 | _not_implemented 21 | fi 22 | } 23 | 24 | tazpkg_Qi() { 25 | tazpkg info "$@" 26 | } 27 | 28 | # tarpkg_Ql may _not_implemented 29 | tazpkg_Ql() { 30 | if [ "$#" -eq 0 ]; then 31 | _not_implemented 32 | return 33 | fi 34 | 35 | if [ "$_TOPT" = "q" ]; then 36 | { 37 | tazpkg list-files "$@" 38 | tazpkg list-config "$@" 39 | } \ 40 | | grep "^/" 41 | else 42 | tazpkg list-files "$@" 43 | tazpkg list-config "$@" 44 | fi 45 | } 46 | 47 | tazpkg_Sy() { 48 | tazpkg recharge 49 | } 50 | 51 | tazpkg_Su() { 52 | tazpkg up 53 | } 54 | 55 | tazpkg_Suy() { 56 | tazpkg_Sy \ 57 | && tazpkg_Su 58 | } 59 | 60 | tazpkg_S() { 61 | local_forced="" 62 | 63 | if echo "$*" | grep -qs -- "--forced"; then 64 | local_forced="--forced" 65 | fi 66 | 67 | while [ $# -gt 0 ]; do 68 | if [ "$1" = "--forced" ]; then 69 | local_forced="--forced" 70 | shift 71 | continue 72 | fi 73 | 74 | tazpkg get-install "$1" $local_forced 75 | shift 76 | done 77 | } 78 | 79 | tazpkg_R() { 80 | local_auto="" 81 | 82 | if echo "*" | grep -sq -- "--auto"; then 83 | local_auto="--auto" 84 | fi 85 | 86 | while [ $# -ge 1 ]; do 87 | if [ "$1" = "--auto" ]; then 88 | local_auto="--auto" 89 | shift 90 | continue 91 | fi 92 | 93 | tazpkg remove "$1" $local_auto 94 | shift 95 | done 96 | } 97 | 98 | tazpkg_Sc() { 99 | tazpkg clean-cache 100 | } 101 | 102 | tazpkg_Scc() { 103 | tazpkg clean-cache 104 | cd /var/lib/tazpkg/ \ 105 | && { 106 | rm -fv \ 107 | ./*.bak \ 108 | ID \ 109 | packages.* \ 110 | files.list.* 111 | } 112 | } 113 | 114 | # Option: tazpkg search ... [option] 115 | # -i: installed packages 116 | # -l: available packages 117 | tazpkg_Ss() { 118 | tazpkg search "$@" 119 | } 120 | 121 | tazpkg_Qo() { 122 | if cmd="$(command -v -- "$@")"; then 123 | tazpkg search-pkgname "$cmd" 124 | else 125 | tazpkg search-pkgname "$@" 126 | fi 127 | } 128 | 129 | tazpkg_U() { 130 | local_forced="" 131 | 132 | if echo "*" | grep -sq -- "--forced"; then 133 | local_forced="--forced" 134 | fi 135 | 136 | while [ $# -ge 1 ]; do 137 | if [ "$1" = "--forced" ]; then 138 | local_forced="--forced" 139 | shift 140 | continue 141 | fi 142 | 143 | tazpkg install "$1" $local_forced 144 | shift 145 | done 146 | } 147 | -------------------------------------------------------------------------------- /lib/tlmgr.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose : tlmgr support 4 | # Author : Antony Lee 5 | # License : MIT 6 | # Date : July 26, 2018 7 | 8 | # Copyright (C) 2018 Antony Lee 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _tlmgr_init() { 17 | : 18 | } 19 | 20 | tlmgr_Qi() { 21 | tlmgr info --only-installed "$@" 22 | } 23 | 24 | tlmgr_Qk() { 25 | tlmgr check files 26 | } 27 | 28 | tlmgr_Ql() { 29 | tlmgr info --only-installed --list "$@" 30 | } 31 | 32 | tlmgr_R() { 33 | tlmgr remove "$@" 34 | } 35 | 36 | tlmgr_S() { 37 | tlmgr install "$@" 38 | } 39 | 40 | tlmgr_Si() { 41 | tlmgr info "$@" 42 | } 43 | 44 | tlmgr_Sl() { 45 | tlmgr info 46 | } 47 | 48 | tlmgr_Ss() { 49 | tlmgr search --global "$@" 50 | } 51 | 52 | tlmgr_Suy() { 53 | tlmgr update --all 54 | } 55 | 56 | tlmgr_U() { 57 | tlmgr install --file "$@" 58 | } 59 | -------------------------------------------------------------------------------- /lib/xbps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: Void Linux support 4 | # Author : Connor Sample 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2021 Connor Sample 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _xbps_init() { 17 | : 18 | } 19 | 20 | xbps_Q() { 21 | xbps-query -l 22 | } 23 | 24 | xbps_Qe() { 25 | xbps-query -m 26 | } 27 | 28 | xbps_Qi() { 29 | xbps-query -s "$@" 30 | } 31 | 32 | xbps_Ql() { 33 | xbps-query -f "$@" 34 | } 35 | 36 | xbps_Qo() { 37 | xbps-query -o "$@" 38 | } 39 | 40 | xbps_Qs() { 41 | xbps-query -s "$@" 42 | } 43 | 44 | xbps_S() { 45 | xbps-install "$@" 46 | } 47 | 48 | xbps_Ss() { 49 | xbps-query -Rs "$@" 50 | } 51 | 52 | xbps_Su() { 53 | xbps-install -u 54 | } 55 | 56 | xbps_Sy() { 57 | xbps-install -S 58 | } 59 | 60 | xbps_Suy() { 61 | xbps-install -Su 62 | } 63 | 64 | xbps_R() { 65 | xbps-remove "$@" 66 | } 67 | 68 | xbps_Scc() { 69 | xbps-remove -O 70 | } 71 | -------------------------------------------------------------------------------- /lib/yum.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: RedHat / Fedora Core support 4 | # Author : Anh K. Huynh 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2010 - 2014 Anh K. Huynh 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _yum_init() { 17 | : 18 | } 19 | 20 | # FIXME: Need to support a small list of packages 21 | yum_Q() { 22 | if [ "$_TOPT" = "q" ]; then 23 | rpm -qa --qf "%{NAME}\\n" 24 | elif [ -z "$_TOPT" ]; then 25 | rpm -qa --qf "%{NAME} %{VERSION}\\n" 26 | else 27 | _not_implemented 28 | fi 29 | } 30 | 31 | yum_Qe() { 32 | # in Centos8, repoquery takes 'reason' as format placeholder 33 | centos_version="$($GREP -ohP '(?<=VERSION_ID=")([^"]+)(?=")' /etc/*elease)" 34 | [ "$centos_version" -eq "8" ] && reason="reason" || reason="yumdb_info.reason" 35 | 36 | repoquery --installed --qf "%{name} - %{$reason}" --all \ 37 | | $GREP 'user$' | cut -d' ' -f1 38 | } 39 | 40 | yum_Qi() { 41 | yum info "$@" 42 | } 43 | 44 | yum_Qs() { 45 | if [ "$_TOPT" = "q" ]; then 46 | rpm -qa --qf "%{NAME}\\n" "*${*}*" 47 | elif [ -z "$_TOPT" ]; then 48 | rpm -qa --qf "%{NAME} %{VERSION}\\n" "*${*}*" 49 | else 50 | _not_implemented 51 | fi 52 | } 53 | 54 | yum_Ql() { 55 | rpm -ql "$@" 56 | } 57 | 58 | yum_Qo() { 59 | if cmd="$(command -v -- "$@")"; then 60 | rpm -qf "$cmd" 61 | else 62 | rpm -qf "$@" 63 | fi 64 | } 65 | 66 | yum_Qp() { 67 | rpm -qp "$@" 68 | } 69 | 70 | yum_Qc() { 71 | rpm -q --changelog "$@" 72 | } 73 | 74 | yum_Qu() { 75 | yum list updates "$@" 76 | } 77 | 78 | yum_Qm() { 79 | yum list extras "$@" 80 | } 81 | 82 | yum_Rs() { 83 | if [ -z "$_TOPT" ]; then 84 | yum erase "$@" 85 | else 86 | _not_implemented 87 | fi 88 | } 89 | 90 | yum_R() { 91 | yum erase "$@" 92 | } 93 | 94 | yum_Sg() { 95 | if [ $# -eq 0 ]; then 96 | yum grouplist hidden 97 | else 98 | yum groups info "$@" 99 | fi 100 | } 101 | 102 | yum_Si() { 103 | _require_programs repoquery 104 | repoquery --requires --resolve "$@" 105 | } 106 | 107 | yum_Suy() { 108 | yum update "$@" 109 | } 110 | 111 | yum_Su() { 112 | yum update "$@" 113 | } 114 | 115 | yum_Sy() { 116 | yum check-update "$@" 117 | } 118 | 119 | yum_Ss() { 120 | yum -C search "$@" 121 | } 122 | 123 | yum_Sc() { 124 | yum clean expire-cache "$@" 125 | } 126 | 127 | yum_Scc() { 128 | yum clean packages "$@" 129 | } 130 | 131 | yum_Sccc() { 132 | yum clean all "$@" 133 | } 134 | 135 | yum_S() { 136 | # shellcheck disable=SC2086 137 | yum install $_TOPT "$@" 138 | } 139 | 140 | yum_U() { 141 | yum localinstall "$@" 142 | } 143 | 144 | yum_Sii() { 145 | _require_programs repoquery 146 | repoquery --installed --whatrequires "$@" 147 | } 148 | -------------------------------------------------------------------------------- /lib/zypper.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: OpenSUSE support 4 | # Author : Anh K. Huynh 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2010 - 2014 Anh K. Huynh 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | _zypper_init() { 17 | : 18 | } 19 | 20 | zypper_Qc() { 21 | rpm -q --changelog "$@" 22 | } 23 | 24 | zypper_Qi() { 25 | zypper info "$@" 26 | } 27 | 28 | zypper_Ql() { 29 | rpm -ql "$@" 30 | } 31 | 32 | zypper_Qu() { 33 | zypper list-updates "$@" 34 | } 35 | 36 | zypper_Qm() { 37 | zypper search -si "$@" \ 38 | | grep 'System Packages' 39 | } 40 | 41 | zypper_Qo() { 42 | if cmd="$(command -v -- "$@")"; then 43 | rpm -qf "$cmd" 44 | else 45 | rpm -qf "$@" 46 | fi 47 | } 48 | 49 | zypper_Qp() { 50 | rpm -qip "$@" 51 | } 52 | 53 | zypper_Qs() { 54 | zypper search --search-descriptions --installed-only "$@" \ 55 | | { 56 | if [ "$_TOPT" = "q" ]; then 57 | awk -F ' *| *' '/^[a-z]/ {print $3}' 58 | else 59 | cat 60 | fi 61 | } 62 | } 63 | 64 | zypper_Q() { 65 | if [ "$_TOPT" = "q" ]; then 66 | zypper search -i "$@" \ 67 | | grep ^i \ 68 | | awk '{print $3}' 69 | elif [ -z "$_TOPT" ]; then 70 | zypper search -i "$@" 71 | else 72 | _not_implemented 73 | fi 74 | } 75 | 76 | zypper_Rs() { 77 | if [ "$_TOPT" = "s" ]; then 78 | zypper remove "$@" --clean-deps 79 | else 80 | _not_implemented 81 | fi 82 | } 83 | 84 | zypper_R() { 85 | zypper remove "$@" 86 | } 87 | 88 | zypper_Rn() { 89 | # Remove configuration files 90 | rpm -ql "$@" \ 91 | | while read -r file; do 92 | if [ -f "$file" ]; then 93 | rm -fv "$file" 94 | fi 95 | done 96 | 97 | # Now remove the package per-se 98 | zypper remove "$@" 99 | } 100 | 101 | zypper_Rns() { 102 | # Remove configuration files 103 | rpm -ql "$@" \ 104 | | while read -r file; do 105 | if [ -f "$file" ]; then 106 | rm -fv "$file" 107 | fi 108 | done 109 | 110 | zypper remove "$@" --clean-deps 111 | } 112 | 113 | zypper_Suy() { 114 | zypper dup "$@" 115 | } 116 | 117 | zypper_Sy() { 118 | zypper refresh "$@" 119 | } 120 | 121 | zypper_Sl() { 122 | if [ $# -eq 0 ]; then 123 | zypper pa -R 124 | else 125 | zypper pa -r "$@" 126 | fi 127 | } 128 | 129 | zypper_Sg() { 130 | if [ $# -gt 0 ]; then 131 | zypper info "$@" 132 | else 133 | zypper patterns 134 | fi 135 | } 136 | 137 | zypper_Ss() { 138 | zypper search "$@" 139 | } 140 | 141 | zypper_Su() { 142 | zypper --no-refresh dup "$@" 143 | } 144 | 145 | zypper_Sc() { 146 | zypper clean "$@" 147 | } 148 | 149 | zypper_Scc() { 150 | zypper clean "$@" 151 | } 152 | 153 | zypper_Sccc() { 154 | # Not way to do this in zypper 155 | _not_implemented 156 | } 157 | 158 | zypper_Si() { 159 | zypper info --requires "$@" 160 | } 161 | 162 | zypper_Sii() { 163 | if [ $# -eq 0 ]; then 164 | _error "Missing some package name." 165 | return 1 166 | fi 167 | _not_implemented 168 | return 169 | 170 | # TOO SLOW ! # # Ugly and slow, but does the trick 171 | # TOO SLOW ! # local_packages="$( \ 172 | # TOO SLOW ! # zypper pa --installed-only -R \ 173 | # TOO SLOW ! # | grep -E '^[a-z]' \ 174 | # TOO SLOW ! # | cut -d \| -f 3 | sort -u)" 175 | # TOO SLOW ! # 176 | # TOO SLOW ! # for package in $local_packages; do 177 | # TOO SLOW ! # zypper info --requires "$package" \ 178 | # TOO SLOW ! # | grep -q "$@" && echo "$package" 179 | # TOO SLOW ! # done 180 | } 181 | 182 | zypper_S() { 183 | # shellcheck disable=SC2086 184 | zypper install $_TOPT "$@" 185 | } 186 | 187 | zypper_U() { 188 | zypper install "$@" 189 | } 190 | -------------------------------------------------------------------------------- /lib/zz_main.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose: A wrapper for all Unix package managers 4 | # Author : Anh K. Huynh 5 | # License: Fair license (http://www.opensource.org/licenses/fair) 6 | # Source : http://github.com/icy/pacapt/ 7 | 8 | # Copyright (C) 2010 - 2021 Anh K. Huynh 9 | # 10 | # Usage of the works is permitted provided that this instrument is 11 | # retained with the works, so that any entity that uses the works is 12 | # notified of this instrument. 13 | # 14 | # DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 15 | 16 | set -u 17 | 18 | unset GREP_OPTIONS 19 | 20 | : "${PACAPT_DEBUG=}" # Show what will be going 21 | : "${GREP:=grep}" # Need to update in, e.g, _sun_tools_init 22 | : "${AWK:=awk}" # Need to update in, e.g, _sun_tools_init 23 | 24 | # Dirty tricky patch for SunOS 25 | local_requirements="$GREP $AWK" 26 | if ! _sun_tools_init; then 27 | local_requirements="${local_requirements} sed" 28 | fi 29 | 30 | # shellcheck disable=SC2086 31 | _require_programs $local_requirements 32 | 33 | export PACAPT_DEBUG GREP AWK 34 | 35 | # Shell switching, as fast as possible 36 | if [ -z "${__PACAPT_FORKED__:-}" ]; then 37 | if command -v bash >/dev/null \ 38 | && bash -c 'echo ${BASH_VERSION[*]}' \ 39 | | "$GREP" -Ee "^[4-9]." >/dev/null 2>&1 \ 40 | ; then 41 | 42 | _debug "Switching to Bash shell" 43 | export __PACAPT_FORKED__="yes" 44 | readonly __PACAPT_FORKED__ 45 | 46 | exec bash -- "$0" "$@" 47 | fi 48 | else 49 | # Hey, this is very awesome strick to avoid syntax issue. 50 | # Note: in `bocker` (github.com/icy/bocker/) we use `base64`. 51 | # FIXME: `source /dev/stdin` doesn't work without Bash >=4 52 | eval 'source /dev/stdin < <("$GREP" '^#_!_POSIX_#' "$0" | sed -e 's/^#_!_POSIX_#//')' \ 53 | || _die "$0: Unable to load non-POSIX definitions". 54 | fi 55 | # /Shell switching 56 | 57 | ## Pacman stuff 58 | 59 | _POPT="" # primary operation 60 | _SOPT="" # secondary operation 61 | _TOPT="" # options for operations 62 | _EOPT="" # extra options (directly given to package manager) 63 | # these options will be translated by (_translate_all) method. 64 | _PACMAN="" # name of the package manager 65 | 66 | _PACMAN_detect \ 67 | || _die "'pacapt' doesn't support your package manager." 68 | 69 | # Once we haven't switcher over `bash`, there is great chance 70 | # the current system are missing `Bash` ; on these systems 71 | # our library are not ready for pure-POSIX features! 72 | if [ -z "${__PACAPT_FORKED__:-}" ]; then 73 | case "$_PACMAN" in 74 | "cave") 75 | _die "pacapt($_PACMAN) library is not ready for pure-POSIX features (or your Bash version is not >= 4)." 76 | ;; 77 | *) 78 | ;; 79 | esac 80 | fi 81 | 82 | # FIXME: If `pacman-foo` is being used, `PACAPT_DEBUG` is still overwriting that. 83 | if [ -z "$PACAPT_DEBUG" ]; then 84 | [ "$_PACMAN" != "pacman" ] \ 85 | || exec "/usr/bin/pacman" "$@" 86 | elif [ "$PACAPT_DEBUG" != "auto" ]; then 87 | _PACMAN="$PACAPT_DEBUG" 88 | fi 89 | 90 | case "${1:-}" in 91 | "update") shift; set -- -Sy "$@" ;; 92 | "upgrade") shift; set -- -Su "$@" ;; 93 | "install") shift; set -- -S "$@" ;; 94 | "search") shift; set -- -Ss "$@" ;; 95 | "remove") shift; set -- -R "$@" ;; 96 | "autoremove") shift; set -- -Rs "$@" ;; 97 | "clean") shift; set -- -Scc "$@" ;; 98 | esac 99 | 100 | while :; do 101 | _args="${1-}" 102 | 103 | [ "$(printf "%.1s" "$_args")" = "-" ] || break 104 | 105 | case "${_args}" in 106 | "--help") 107 | _help 108 | exit 0 109 | ;; 110 | 111 | "--noconfirm") 112 | shift 113 | _EOPT="$_EOPT:noconfirm:" 114 | continue 115 | ;; 116 | 117 | "-"|"--") 118 | shift 119 | break 120 | ;; 121 | esac 122 | 123 | i=1 124 | while [ "$i" -lt "${#_args}" ]; do 125 | i=$(( i + 1)) 126 | _opt="$(_string_nth "$i" "$_args")" 127 | 128 | case "$_opt" in 129 | h) 130 | _help 131 | exit 0 132 | ;; 133 | V) 134 | _print_pacapt_version; 135 | exit 0 136 | ;; 137 | P) 138 | _print_supported_operations "$_PACMAN" 139 | exit 0 140 | ;; 141 | 142 | Q|S|R|U) 143 | if [ -n "$_POPT" ] && [ "$_POPT" != "$_opt" ]; then 144 | _error "Only one operation may be used at a time" 145 | exit 1 146 | fi 147 | _POPT="$_opt" 148 | ;; 149 | 150 | # Comment 2015 May 26th: This part deals with the 2nd option. 151 | # Most of the time, there is only one 2nd option. But some 152 | # operation may need extra and/or duplicate (e.g, Sy <> Syy). 153 | # 154 | # See also 155 | # 156 | # * https://github.com/icy/pacapt/issues/13 157 | # 158 | # This implementation works, but with a bug. #Rsn works 159 | # but #Rns is translated to #Rn (incorrectly.) 160 | # Thanks Huy-Ngo for this nice catch. 161 | # 162 | # FIXME: Please check pacman(8) to see if they are really 2nd operation 163 | # 164 | e|g|i|l|m|n|o|p|s|k) 165 | if [ -z "$_SOPT" ]; then 166 | _SOPT="$_opt" 167 | continue 168 | fi 169 | 170 | # Understand it: 171 | # If there is already an option recorded, the incoming option 172 | # will come and compare itself with known one. 173 | # We have a table 174 | # 175 | # known one vs. incoming ? | result 176 | # < | one-new 177 | # = | one-one 178 | # > | new-one 179 | # 180 | # Let's say, after this step, the 3rd option comes (named X), 181 | # and the current result is "a-b". We have a table 182 | # 183 | # a(b) vs. X | result 184 | # < | aX (b dropped) 185 | # = | aa (b dropped) 186 | # > | Xa (b dropped) 187 | # 188 | # In any case, the first one matters. 189 | # 190 | f_SOPT="$(printf "%.1s" "$_SOPT")" 191 | if _string_less_than "$f_SOPT" "$_opt"; then 192 | _SOPT="${f_SOPT}$_opt" 193 | elif [ "${f_SOPT}" = "$_opt" ]; then 194 | _SOPT="$_opt$_opt" 195 | else 196 | _SOPT="$_opt${f_SOPT}" 197 | fi 198 | 199 | ;; 200 | 201 | q) 202 | _TOPT="$_opt" ;; # Thanks to James Pearson 203 | 204 | u) 205 | f_SOPT="$(printf "%.1s" "$_SOPT")" 206 | if [ "$f_SOPT" = "y" ]; then 207 | _SOPT="uy" 208 | else 209 | _SOPT="u" 210 | fi 211 | ;; 212 | 213 | y) 214 | f_SOPT="$(printf "%.1s" "$_SOPT")" 215 | if [ "${f_SOPT}" = "y" ]; then 216 | _SOPT="uy" 217 | else 218 | _SOPT="y" 219 | fi 220 | ;; 221 | 222 | c) 223 | if [ "$(printf "%.2s" "$_SOPT")" = "cc" ]; then 224 | _SOPT="ccc" 225 | elif [ "$(printf "%.1s" "$_SOPT")" = "c" ]; then 226 | _SOPT="cc" 227 | else 228 | _SOPT="$_opt" 229 | fi 230 | ;; 231 | 232 | w|v) 233 | _EOPT="$_EOPT:$_opt:" 234 | ;; 235 | 236 | *) 237 | # FIXME: If option is unknown, we will break the loop 238 | # FIXME: and this option will be used by the native program. 239 | # FIXME: break 2 240 | _die "$0: Unknown option '$_opt'." 241 | ;; 242 | esac 243 | done 244 | 245 | shift 246 | 247 | # If the primary option and the secondary are known 248 | # we would break the argument detection, but for sure we will look 249 | # forward to see there is anything interesting... 250 | if [ -n "$_POPT" ] && [ -n "$_SOPT" ]; then 251 | case "${1:-}" in 252 | "-w"|"--noconfirm") ;; 253 | *) break;; 254 | esac 255 | 256 | # Don't have anything from the **first** argument. Something wrong. 257 | # FIXME: This means that user must enter at least primary action 258 | # FIXME: or secondary action in the very first part... 259 | elif [ -z "${_POPT}${_SOPT}${_TOPT}" ]; then 260 | break 261 | fi 262 | done 263 | 264 | [ -n "$_POPT" ] \ 265 | || _die "Usage: $0 # -h for help, -P list supported functions" 266 | 267 | _validate_operation "${_PACMAN}_${_POPT}${_SOPT}" \ 268 | || { 269 | _not_implemented 270 | exit 1 271 | } 272 | 273 | _translate_all || exit 274 | 275 | # pacman man page (examples) says: 276 | # "pacman -Syu gpm = Update package list, upgrade all packages, 277 | # and then install gpm if it wasn't already installed." 278 | # 279 | # Instead, just disallow specific packages, as (ex-)yum users likely 280 | # expect to just update/upgrade one package (and its dependencies) 281 | # and apt-get and pacman have no way to do this. 282 | # 283 | if [ -n "$*" ]; then 284 | case "${_POPT}${_SOPT}" in 285 | "Su"|"Sy"|"Suy") 286 | if ! echo "$*" | $GREP -Eq -e '(^|\s)-' -e '-+\w+\s+[^-]'; then 287 | echo 1>&2 "WARNING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 288 | echo 1>&2 " The -Sy/u options refresh and/or upgrade all packages." 289 | echo 1>&2 " To install packages as well, use separate commands:" 290 | echo 1>&2 291 | echo 1>&2 " $0 -S$_SOPT; $0 -S ${*:-}" 292 | echo 1>&2 "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 293 | fi; 294 | esac 295 | fi 296 | 297 | if [ -n "$PACAPT_DEBUG" ]; then 298 | echo "pacapt: $_PACMAN, p=$_POPT, s=$_SOPT, t=$_TOPT, e=$_EOPT" 299 | echo "pacapt: execute '${_PACMAN}_${_POPT}${_SOPT} $_EOPT ${*:-}'" 300 | if command -v declare >/dev/null; then 301 | # shellcheck disable=SC3044 302 | declare -f "${_PACMAN}_${_POPT}${_SOPT}" 303 | else 304 | _error "Attempted to print the definition of the method '${_PACMAN}_${_POPT}${_SOPT}'." 305 | _error "However, unable to find method ('declare'). Maybe your shell is purely POSIX?" 306 | fi 307 | else 308 | "_${_PACMAN}_init" || exit 309 | # shellcheck disable=SC2086 310 | "${_PACMAN}_${_POPT}${_SOPT}" $_EOPT "$@" 311 | fi 312 | -------------------------------------------------------------------------------- /tests/Dockerfile.alpine_bash4: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | RUN apk update && apk add bash 3 | -------------------------------------------------------------------------------- /tests/Dockerfile.debian_bash3: -------------------------------------------------------------------------------- 1 | # Purpose : dpkg + bash3 2 | FROM bash:3.2 as bash3 3 | 4 | FROM debian 5 | 6 | COPY --from=bash3 /usr/local/bin/bash /bin/bash 7 | COPY --from=bash3 /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 8 | COPY --from=bash3 /usr/lib/libncursesw.so.6 /usr/lib/libncursesw.so.6 9 | COPY --from=bash3 /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 10 | -------------------------------------------------------------------------------- /tests/Dockerfile.opkg_bash4: -------------------------------------------------------------------------------- 1 | FROM oofnik/openwrt:19.07.7-x86-64 2 | RUN opkg update && opkg install bash 3 | -------------------------------------------------------------------------------- /tests/Dockerfile.oraclelinux-8_dnf: -------------------------------------------------------------------------------- 1 | # Purpose : oraclelinux:8-slim + dnf 2 | FROM oraclelinux:8-slim 3 | 4 | RUN microdnf install dnf 5 | -------------------------------------------------------------------------------- /tests/Dockerfile.slitaz40_bash3: -------------------------------------------------------------------------------- 1 | FROM bash:3.2 as bash3 2 | 3 | FROM icymatter/slitaz40-minimal 4 | 5 | COPY --from=bash3 /usr/local/bin/bash /bin/bash 6 | COPY --from=bash3 /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 7 | COPY --from=bash3 /usr/lib/libncursesw.so.6 /usr/lib/libncursesw.so.6 8 | COPY --from=bash3 /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 9 | -------------------------------------------------------------------------------- /tests/Dockerfile.voidlinux: -------------------------------------------------------------------------------- 1 | FROM voidlinux/voidlinux:20201117RC01 2 | 3 | RUN SSL_NO_VERIFY_PEER=true xbps-install -S 4 | RUN SSL_NO_VERIFY_PEER=true xbps-install -uy xbps 5 | -------------------------------------------------------------------------------- /tests/Dockerfile.zypper_bash3: -------------------------------------------------------------------------------- 1 | # Purpose : dpkg + bash3 2 | FROM bash:3.2 as bash3 3 | 4 | FROM opensuse/leap:15.2 5 | 6 | COPY --from=bash3 /usr/local/bin/bash /bin/bash 7 | COPY --from=bash3 /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 8 | COPY --from=bash3 /usr/lib/libncursesw.so.6 /usr/lib/libncursesw.so.6 9 | COPY --from=bash3 /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1 10 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | TESTS = *.txt 2 | IMAGES = 3 | 4 | .PHONY: default 5 | default: 6 | @grep -E "^# [a-z].+:" Makefile 7 | 8 | # gen: 9 | # gen: Generating `pacapt.dev` 10 | tmp/pacapt.dev:: 11 | @( cd ../ && make -s pacapt.dev ; ) 12 | @mkdir -p ./tmp/ 13 | @cp -u ../pacapt.dev tmp/ 14 | @chmod 755 $(@) 15 | 16 | # all: 17 | # all: Execute all test scripts 18 | # all: To execute a subset of tests, list them with TESTS=... 19 | # all: for example, `make all TESTS="foo.txt bar.txt" 20 | .PHONY: all 21 | all: tmp/pacapt.dev 22 | @IMAGES=$(IMAGES) ./test.sh $(TESTS) 23 | 24 | # gen: 25 | # gen: Generate test scripts but don't execute them 26 | .PHONY: gen 27 | gen: tmp/pacapt.dev 28 | @TESTS_DO_NOT_RUN=1 ./test.sh *.txt 29 | 30 | # clean: 31 | # clean: Remove all temporary files under /tmp/ 32 | # clean: (but still keep all log files.) 33 | .PHONY: clean 34 | clean: 35 | @rm -fv tmp/*.sh tmp/pacapt.dev 36 | @echo Please remove tmp/*.log manually. 37 | 38 | # test_homebrew: 39 | # test_homebrew: Execute tests within MacOS provided by Github-actions 40 | .PHONY: test_homebrew 41 | test_homebrew: 42 | @set -u && echo $$CI >/dev/null 43 | @mkdir -pv tmp 44 | @sh ../bin/gen_tests.sh < homebrew.txt > tmp/homebrew.sh 45 | @cd tmp && MSG_PREFIX=":: [homebrew] " sh homebrew.sh 46 | 47 | # test_pkgng: 48 | # test_pkgng: Execute FreeBSD tests within MacOS provided by Github-actions 49 | .PHONY: test_pkgng 50 | test_pkgng: 51 | @set -u && echo $$CI >/dev/null 52 | @mkdir -pv tmp 53 | @sh ../bin/gen_tests.sh < pkgng.txt > tmp/pkgng.sh 54 | @pkg remove -y bash || true 55 | @cd tmp && MSG_PREFIX=":: [pkgng] " sh pkgng.sh 56 | 57 | # test_sun_tools: 58 | # test_sun_tools: Execute SunOS tests within MacOS provided by Github-actions 59 | .PHONY: test_sun_tools 60 | test_sun_tools: 61 | @set -u && echo $$CI >/dev/null 62 | cd tmp && MSG_PREFIX=":: [sun_tools] " sh sun_tools.sh 63 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://github.com/icy/pacapt/actions/workflows/ci.yaml/badge.svg)](https://github.com/icy/pacapt/actions) 2 | 3 | ## Table of contents 4 | 5 | See also https://github.com/icy/pacapt/actions. 6 | 7 | 1. [Preparing test environment](#preparing-test-environment) 8 | 1. [Invoking test scripts](#invoking-test-scripts) 9 | 1. [Writing test cases](#writing-test-cases) 10 | 1. [Notes](#notes-on-writing-test-cases) 11 | 12 | ## Preparing test environment 13 | 14 | We run `#sh` test scripts inside `Docker` container. We will need 15 | the following things 16 | 17 | 1. A fast network to download base images from http://hub.docker.com/, 18 | and to execute `pacman -Sy` command; 19 | 1. Our user environment can execute `docker run` command to create 20 | new container and mount some host volumes; 21 | 22 | Basically we execute the following command 23 | 24 | $ cd 25 | 26 | $ mkdir -p tests/tmp/ 27 | $ sh ./bin/gen_tests.sh \ 28 | < tests/dpkg.txt \ 29 | > tests/tmp/test.sh 30 | 31 | $ cd tests/tmp/ 32 | $ docker run --rm \ 33 | -v $PWD/test.sh:/tmp/test.sh \ 34 | -v $PWD/pacapt.dev:/usr/bin/pacman \ 35 | ubuntu:18.04 \ 36 | sh /tmp/test.sh 37 | 38 | This command will return 0 if all tests pass, or return 1 if any test fails. 39 | 40 | For more details, please see in `Makefile` and `test.sh`. 41 | 42 | ## Invoking test scripts 43 | 44 | There are `Makefile` and `test.sh` written and tested in an Arch/Ubuntu 45 | machine. It is expected to work in similar environment with `GNU Make`, 46 | `Bash` and `Docker`. 47 | 48 | $ make # List all sections 49 | $ make all # Execute all tests (WARNING: It's slow!) 50 | # or a subset of tests, as below 51 | $ make TESTS="foo.txt bar.txt" 52 | $ make TESTS="foo.txt" IMAGES="ubuntu:latest" 53 | 54 | This script will create a temporary directory `tests/tmp/` to store 55 | all logs and details. If there is any test script fails, the process 56 | is stopped for investigation. 57 | 58 | ## Writing test cases 59 | 60 | In short, the test file has the following format 61 | 62 | ``` 63 | im docker-image1 docker-image2 64 | im docker-image3 ... 65 | 66 | in pacman options 67 | in ! command to execute 68 | ou regular expression to match 69 | ``` 70 | 71 | The test file is heavily parsed by a custom `Ruby` script found in 72 | [`bin/gen_tests.sh`](bin/gen_tests.sh) and will be invoked 73 | by the executor [`tests/test.sh`](tests/test.sh). When there are 74 | multiple docker images are provided, the `parallel` command will know 75 | that and execute multiple containers in parallel. 76 | 77 | All tests in the test file are executed in the order provided. 78 | 79 | See examples in `tests/dpkg.txt`. Each test case combines of input command 80 | and output regular expressions used by `grep -E`. Input command is started 81 | by `in `, output regexp is started by `ou `. For example, 82 | 83 | in -Sy 84 | in -Qs htop 85 | ou ^htop 86 | 87 | the test is passed if the following group of commands returns successfully 88 | 89 | pacman -Sy 90 | pacman -Qs htop | grep -qE '^htop' 91 | 92 | If we want to execute some command other than `pacman` script, use `!` 93 | to write our original command. For example, 94 | 95 | in ! echo Y | pacman -S htop 96 | in ! echo Y | pacman -R htop 97 | in -Qi htop 98 | ou ^Status: deinstall 99 | 100 | On `Debian`/`Ubuntu` system, this test case is to ensure that the script 101 | can install `htop` package, then remove it. An alternative test is 102 | 103 | echo Y | pacman -S htop 104 | echo Y | pacman -R htop 105 | pacman -Qi htop | grep -E '^Status: deinstall' 106 | 107 | ## Notes on writing test cases 108 | 109 | 1. To specify a list of container images, use `im image [image]...`; 110 | 1. Each `im` instruction has its own temporary file to store all output; 111 | 1. Multiple uses of `test.in` is possible, and all results are appended 112 | to test's temporary file. If we want to clear the contents of this output 113 | please use `in clear`; 114 | 1. Multiple uses of `test.ou` is possible; any fail check will increase 115 | the total number of failed tests; 116 | 1. To make sure that test's temporary file is empty, use `ou empty`; 117 | 1. Tests are executed by orders provided in the source file. It's better 118 | to execute `pacman -Sy` to update package manager's database before 119 | any other tests, and it's also better to test `clean up` features 120 | (`pacman -Sc`, `pacman -Scc`, ...) at the very end of the source file. 121 | See `lib/dpkg.sh` for an example; 122 | 1. All tests are executed by `sh` shell. 123 | 1. In any input command, `$LOG` (if any) is replaced by the path to 124 | test's temporary file; 125 | 1. It's very easy to trick the test mechanism; it's our duty to make 126 | the tests as simple as possible. 127 | 1. All temporary files are stored under `tests/tmp` directory. As some files 128 | name are reused, new execution of tests may clear out any existing output logs. 129 | The log files are quite verbose and helpful to learn why some tests fail. 130 | -------------------------------------------------------------------------------- /tests/apk.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for apk support 4 | # Author : Álvaro Mondéjar 5 | # License : MIT 6 | 7 | im alpine:3.12 alpine:3.13 alpine:3.14 alpine:latest 8 | im alpine_bash4 9 | 10 | in -P 11 | ou available operations:.*( [Q][ ilos])+ 12 | 13 | # Get installed packages 14 | in -Qq 15 | ou ^busybox 16 | in -Q 17 | ou ^busybox.+\[installed\]$ 18 | 19 | # Get packages information 20 | in -Qi 21 | ou ^musl.+description:$ 22 | ou ^musl.+webpage:$ 23 | ou ^busybox.+description:$ 24 | ou ^busybox.+webpage:$ 25 | 26 | # Get package information 27 | in -Qi busybox 28 | ou ^busybox.+description:$ 29 | ou ^busybox.+webpage:$ 30 | 31 | # Get package files 32 | in -Ql busybox 33 | ou ^busybox bin/busybox$ 34 | in -Ql 35 | ou ^busybox bin/busybox$ 36 | ou ^ca-certificates-bundle etc/ssl/cert.pem$ 37 | in -Qlq 38 | ou ^bin/busybox$ 39 | ou ^etc/ssl/cert.pem$ 40 | 41 | # Get package which provides file 42 | in -Qo /bin/busybox 43 | ou ^/bin/busybox is owned by busybox.+ 44 | in -Qo busybox 45 | ou ^/bin/busybox is owned by busybox.+ 46 | 47 | # Search locally installed packages 48 | in -Qs busybox 49 | ou ^busybox.+\[installed\]$ 50 | 51 | # List packages with available updates 52 | in -Qu 53 | ou ^Installed:\s+Available:$ 54 | 55 | # Update 56 | in -Sy 57 | ou ^(fetch|OK) 58 | 59 | # Download package 60 | in -Swv nano 61 | ou Downloading nano 62 | 63 | in -Sw screen 64 | ou ^Downloading screen 65 | 66 | # Setup cache 67 | in -S alpine-conf 68 | ou Installing alpine-conf 69 | ou ^OK 70 | in ! setup-apkcache /var/cache/apk/ 71 | ou empty 72 | 73 | # Install package 74 | in -S screen 75 | ou Installing screen 76 | ou ^OK 77 | 78 | # Remove package 79 | in ! which screen 80 | ou /usr/bin/screen 81 | in -R screen 82 | ou Purging screen 83 | in ! command -v screen 84 | ou empty 85 | 86 | # Purge package 87 | in -Rn screen 88 | ou ^OK 89 | in clear 90 | in ! command -v screen 91 | ou empty 92 | 93 | # List explicitly installed packages 94 | in -Qe | grep -o wget 95 | ou empty 96 | 97 | in -S wget 98 | in -Qe 99 | ou ^wget$ 100 | ou ^alpine-conf$ 101 | ou ^alpine-baselayout$ 102 | 103 | in -R wget 104 | in clear 105 | in -Qe | grep -o wget 106 | ou empty 107 | 108 | in ! echo "wget" >> /etc/apk/world 109 | in -Qe | grep -o wget 110 | ou empty 111 | in ! sed -i '$ d' /etc/apk/world 112 | in ! grep -o wget /etc/apk/world 113 | ou empty 114 | 115 | # Clean cache 116 | in ! ls /var/cache/apk/ 117 | ou ^installed$ 118 | ou ^screen 119 | in -Sc 120 | ou empty 121 | in ! ls /var/cache/apk/ 122 | ou ^screen 123 | in -Scc 124 | ou empty 125 | in ! ls /var/cache/apk/ 126 | ou empty 127 | 128 | in -S screen 129 | ou Installing screen 130 | ou ^OK 131 | in ! ls /var/cache/apk/ 132 | ou ^screen 133 | in -Scc 134 | ou empty 135 | in ! ls /var/cache/apk/ 136 | ou empty 137 | 138 | # Display remote package information 139 | in -Si busybox 140 | ou ^busybox.+description:$ 141 | ou ^busybox.+webpage:$ 142 | 143 | in -Sii busybox 144 | ou ^busybox.* is required by:$ 145 | ou ^alpine-conf 146 | ou ^alpine-baselayout 147 | 148 | # Search packages 149 | in -Sl 150 | ou ^(WARNING|libxcb) 151 | in -Ss 152 | ou ^(WARNING|libxcb) 153 | in -Ss libxcb 154 | ou ^(WARNING|libxcb-dev) 155 | 156 | # Upgrade 157 | in -Su 158 | ou ^fetch 159 | ou ^OK 160 | in -Suy 161 | ou ^fetch 162 | ou ^OK 163 | -------------------------------------------------------------------------------- /tests/dnf.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for dnf support 4 | # Author : Álvaro Mondéjar 5 | # License : MIT 6 | 7 | im fedora:32 fedora:33 fedora:34 8 | im oraclelinux-8_dnf 9 | 10 | in -P 11 | ou available operations:.*( [Q][ ilos])+ 12 | 13 | # NOTE: in fedora:34 '/usr/bin/dnf' is not an executable 14 | # but in all machines the binary is a symlink 15 | in ! [ -L /usr/bin/dnf ] && echo "dnf binary is symlink" 16 | ou ^dnf binary is symlink$ 17 | 18 | # List packages with available updates 19 | # NOTE: Fedora | OracleLinux 20 | in -Qu 21 | ou ^(Available Upgrades|Oracle Linux) 22 | 23 | # Update and upgrade 24 | # NOTE: Fedora | OracleLinux 25 | in -Su --noconfirm 26 | ou ^(Upgrading:|Nothing to do.)$ 27 | ou ^(Upgraded:|Complete!)$ 28 | 29 | # Get installed packages 30 | in -Qq 31 | ou ^bash$ 32 | ou ^grep$ 33 | in -Q 34 | ou ^bash [0-9]+\.[0-9]+\.?[0-9]*$ 35 | 36 | # Get packages information (too slow) 37 | #in -Qi 38 | 39 | # Get package information 40 | in -Qi bash 41 | ou ^Name\s+: bash$ 42 | ou ^Version\s+: [0-9]+\.[0-9]+\.?[0-9]*$ 43 | 44 | # Get locally installed package 45 | in -Qs rpm 46 | ou ^rpm-.+\.x86_64$ 47 | ou ^rpm-libs-.+\.x86_64$ 48 | 49 | # Get package files 50 | in -Ql rpm 51 | ou ^/usr/bin/rpm$ 52 | 53 | # Get package from file 54 | in -Qo rpm 55 | ou ^rpm-.+\.x86_64$ 56 | in -Qo "$(command -v rpm)" 57 | ou ^rpm-.+\.x86_64$ 58 | 59 | # Show package changelog 60 | in -Qc rpm 61 | ou ^*\s.+[0-9]$ 62 | 63 | # Get installed packages unavailable in repos 64 | in -Qm 65 | ou ^Last metadata expiration check 66 | 67 | # Install package 68 | in ! command -v nano 69 | ou empty 70 | in -S --noconfirm nano 71 | ou ^Installing:$ 72 | ou ^ nano\s+x86_64 73 | ou ^Installed:$ 74 | in ! command -v nano 75 | ou /bin/nano 76 | 77 | # Remove package 78 | in -R --noconfirm nano 79 | ou ^Removing:$ 80 | ou ^ nano\s+x86_64 81 | ou ^Removed:$ 82 | 83 | # Search packages 84 | in -Ss wget 85 | ou ^wget\.x86_64 86 | in -Sl 87 | ou ^Available Packages$ 88 | 89 | # Get information from local package file 90 | in ! dnf repoquery --location nano 91 | ou ^http.+\.rpm$ 92 | in ! curl -sL "$(dnf repoquery --location nano 2>/dev/null | head -n 1)" -o /tmp/nano-package.rpm --connect-timeout 5 --max-time 30 --retry 5 --retry-delay 0 --retry-max-time 60 93 | ou empty 94 | in ! [ -f /tmp/nano-package.rpm ] || echo not found 95 | ou empty 96 | in -Qp /tmp/nano-package.rpm 97 | ou ^nano-.+\.x86_64$ 98 | 99 | # Install package using local file 100 | in ! command -v nano 101 | ou empty 102 | in -U --noconfirm /tmp/nano-package.rpm 103 | ou ^Installing:$ 104 | ou ^ nano\s+x86_64 105 | ou ^Installed:$ 106 | in ! command -v nano 107 | ou ^(/usr)?/bin/nano$ 108 | 109 | # Cache cleaning 110 | in -Sc 111 | ou ^[0-9]+ files removed$ 112 | in -Scc 113 | ou ^[0-9]+ files removed$ 114 | in -Sccc 115 | ou ^[0-9]+ files removed$ 116 | 117 | # Get dependencies 118 | in -Si dnf 119 | ou ^bash 120 | ou ^python3-dnf 121 | 122 | # Get reverse dependencies 123 | in -Sii rpm 124 | ou ^rpm-libs- 125 | 126 | # Package groups 127 | in -Sg 128 | ou ^ RPM Development Tools$ 129 | in -Sg "RPM Development Tools" 130 | ou ^ redhat-rpm-config$ 131 | ou ^ rpm-build$ 132 | -------------------------------------------------------------------------------- /tests/dpkg.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for dpkg support 4 | # Author : Ky-Anh Huynh 5 | # License : MIT 6 | 7 | # FIXME: debian:squeeze It's unable to run `pacman -Sy` 8 | im ubuntu:14.04 ubuntu:16.04 ubuntu:18.04 ubuntu:20.04 ubuntu 9 | im debian:jessie debian:stretch debian:buster debian:bullseye 10 | im debian_bash3 11 | 12 | # Remove `docker-clean` because we need *.deb files under /var/cache 13 | in ! rm -fv /etc/apt/apt.conf.d/docker-clean 14 | ou ^removed .*docker-clean 15 | 16 | in ! PACAPT_DEBUG=auto pacman 17 | in ! if bash --version | grep -qs 'version 3'; then echo "Bash3-no-switching"; fi 18 | ou (debug.*Switching to Bash shell)|(Bash3-no-switching) 19 | 20 | in -P 21 | ou available operations:.*( [Q][ ilos])+ 22 | 23 | # Update package databases 24 | in -Sy 25 | ou ^Get 26 | ou ^Fetched 27 | in -Sy --quiet --quiet 28 | ou empty 29 | in -Sy -qq 30 | ou empty 31 | 32 | # Simple query that lists all packages 33 | in -Qq 34 | ou ^apt$ 35 | 36 | # Listing with version and package name 37 | in -Q 38 | # ou ^ii +apt +.+ubuntu 39 | ou ^ii +apt + 40 | 41 | # List explicitly installed packages 42 | in ! if [ "$(cat /etc/*-release | grep -E ^VERSION_CODENAME= | cut -d'=' -f2)" = "bullseye" ]; then pacman -S --noconfirm iproute2; fi 43 | in -Qe 44 | ou ^(iproute2|adduser)$ 45 | 46 | # Information of `apt` 47 | in -Qi apt 48 | ou ^Package: apt$ 49 | ou ^Status: install ok installed$ 50 | ou ^Priority: (important|required)$ 51 | 52 | # File listing for `apt` 53 | in -Ql apt 54 | ou ^/usr/bin/apt-key 55 | 56 | # File listing (all packages) 57 | # FIXME: Debian-squeeze doesn't have /usr/bin/apt 58 | in -Ql 59 | ou ^apt /usr/bin/apt-key$ 60 | 61 | # File listing (all packages), files only 62 | in -Qql 63 | ou ^/usr/bin/apt-key$ 64 | 65 | # Look up package name 66 | in -Qo /bin/bash 67 | ou ^bash: /bin/bash$ 68 | 69 | # On ubuntu:20.04, /usr/bin/bash is not part of the `bash` package 70 | # (maybe it's a symlink/file created by installation process) 71 | # hence the looking up would fail 72 | in -Qo bash 73 | ou ^bash: /bin/bash$ 74 | 75 | # Search for pattern in installed package (names + descriptions) 76 | in -Qs bash 77 | ou ^bash.+Bourne 78 | 79 | in -Qs bourne 80 | ou ^bash.+Bourne 81 | 82 | in -Qs screen 83 | ou empty 84 | 85 | in -Qs 'Bourne Again' 86 | ou ^bash.+Bourne 87 | 88 | # Install and Deinstall a package 89 | 90 | # Download without installation 91 | in -Sw --noconfirm screen 92 | in ! command -v screen || echo 'command not found' 93 | ou command not found 94 | 95 | # Display remote package information 96 | in -Si screen 97 | ou ^Package: screen 98 | 99 | in -Sii screen 100 | ou ^Reverse Depends: 101 | 102 | # Get package changelog 103 | in -Qc apt 104 | ou ^(Get|Err).+ apt 105 | 106 | # Now installation 107 | # From ubuntu:20.04 it becomes /bin/screen =)) 108 | in -S --noconfirm screen 109 | in ! command -v screen 110 | ou ^(/usr)?/bin/screen 111 | 112 | # Now remove the package 113 | in -R --noconfirm screen 114 | in -Qi screen 115 | ou ^Status: deinstall 116 | 117 | # Verify package files 118 | in -Qk apt 119 | ou requires 'debsums' but the tool is not found\.$ 120 | in -S --noconfirm debsums 121 | in -Qk apt 122 | ou /usr/bin/apt.+OK 123 | ou /usr/bin/apt-get.+OK 124 | in -Qk 125 | ou /usr/bin/apt.+OK 126 | in -R --noconfirm debsums 127 | 128 | # Package groups 129 | in -Sg 130 | ou requires 'tasksel' but the tool is not found\.$ 131 | in -S --noconfirm tasksel 132 | in -Sg 133 | # debian*? -> web-server 134 | # ubuntu(:(18.04|20.04))? -> ubuntu-desktop 135 | # ubuntu:(14.04|16.04) -> manual 136 | ou ^u (web-server|ubuntu-desktop|manual) 137 | 138 | in ! if [ "$(cat /etc/*-release | grep -E ^ID= | cut -d'=' -f2)" = "ubuntu" ]; then pacman -Sg ubuntu-desktop; else pacman -Sg web-server; fi 139 | ou ^(task-web-server|ubuntu-desktop) 140 | in -R --noconfirm tasksel 141 | 142 | # Query information from a .deb package 143 | in ! export DEB_FILE=`find /var/cache/apt/ -type f -iname "screen*.deb"` 144 | in -Qp $DEB_FILE 145 | ou ^ Package: screen 146 | 147 | # Clean up package databases 148 | in -Sc 149 | in clear 150 | in -sS tmux 151 | ou package/tmux 152 | ou terminal multiplexer 153 | 154 | # Strong cleaning up 155 | in -Sccc 156 | in clear 157 | in -sS tmux 158 | ou empty 159 | -------------------------------------------------------------------------------- /tests/homebrew.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Purpose : testings pacapt+homebrew 4 | # Author : Ky-Anh Huynh 5 | # Date : 06.July.2021 6 | 7 | im macos 8 | 9 | # Ensure we are running Bash3 within Github-Action 10 | in ! bash --version 11 | ou version 3. 12 | 13 | in -Sy 14 | in -S nano 15 | in ! command -v nano 16 | ou bin/nano 17 | in ! nano --version 18 | ou GNU nano 19 | in -Qi 20 | ou kegs.*files 21 | in -Qi nano 22 | ou License: GPL 23 | ou replacement for the Pico 24 | 25 | # FIXME: This is very slow on Github # in -Ql 26 | # FIXME: This is very slow on Github # ou ^nano.* bin/nano 27 | # FIXME: This is very slow on Github # in -Qql 28 | # FIXME: This is very slow on Github # ou ^([^[:space:]])*bin/nano 29 | 30 | in -Ql nano 31 | ou bin/nano 32 | ou share/info/nano.info 33 | in -Qs 34 | ou ^nano 35 | #in -Qo -1 36 | #ou ^Date: 37 | #in -Qo nano -1 38 | #ou ^Date: 39 | in -Q 40 | ou nano [0-9].[0-9] 41 | in -Qq 42 | ou nano 43 | in -Qq nano 44 | ou nano 45 | -------------------------------------------------------------------------------- /tests/opkg.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for okpg support 4 | # Author : Ky-Anh Huynh 5 | # Date : June 19th, 2021 6 | # License : MIT 7 | 8 | im oofnik/openwrt:snapshot-x86-64 9 | im oofnik/openwrt:19.07.7-x86-64 10 | im oofnik/openwrt:19.07.6-x86-64 11 | im oofnik/openwrt:19.07.5-x86-64 12 | im opkg_bash4 13 | 14 | in -Sy 15 | ou Updated list of available packages in /var/opkg-lists/openwrt_core 16 | ou Downloading.*downloads.openwrt.org 17 | ou Signature check passed. 18 | 19 | in -Q 20 | ou busybox - .* 21 | ou libc - .* 22 | 23 | in -Q busybox 24 | ou busybox 25 | 26 | in -Qq 27 | ou ^busybox$ 28 | 29 | in -Qi 30 | ou busybox 31 | ou libc 32 | ou Status: install user installed 33 | 34 | in -Ql 35 | ou libc 36 | ou busybox 37 | 38 | in -Ql libc 39 | ou libc 40 | 41 | in -Ql ruby 42 | ou empty 43 | 44 | in -Qo 45 | ou empty 46 | 47 | in -Qo busybox 48 | ou busybox - .* 49 | 50 | in -Qo /bin/sh 51 | ou busybox - .* 52 | 53 | in -Qs sh 54 | ou base-files - .* 55 | ou busybox - .* 56 | 57 | in -Qqs sh 58 | ou ^busybox$ 59 | 60 | in -Sw htop 61 | in ! htop 62 | ou Downloading.*htop 63 | ou htop: not found 64 | 65 | in -S htop 66 | in ! command -v htop 67 | ou /usr/bin/htop 68 | 69 | in -R htop 70 | in ! htop -h 71 | ou Removing package htop from root 72 | ou htop: not found 73 | 74 | in -Sw htop 75 | in -U ./htop*.ipk 76 | in ! htop -h 77 | ou Hisham Muhammad 78 | 79 | in -Si ruby 80 | in ! ruby -e true 81 | ou ruby: not found 82 | ou Ruby is .* for quick and easy 83 | 84 | in -Sii librt 85 | ou e2fsprogs.*depends on.* 86 | 87 | in -Ss 88 | ou zoneinfo-core 89 | ou ^zsh 90 | 91 | in -Ss perl 92 | ou Perl is a stable.* programming language. 93 | -------------------------------------------------------------------------------- /tests/pkgng.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for pkgng support 4 | # Author : Álvaro Mondéjar 5 | # License : MIT 6 | 7 | # NOTE: Must be executed in a FreeBSD distribution 8 | 9 | im freebsd 10 | 11 | # Get installed packages 12 | in -Qq 13 | ou ^(pkg|git|ruby) 14 | in -Q 15 | ou ^(pkg|git|ruby) 16 | 17 | # Get packages information 18 | in -Qi 19 | ou ^pkg-[0-9]+\.[0-9]+\.?[0-9]*\s+Package manager$ 20 | 21 | # Get package information 22 | in -Qi pkg 23 | ou ^Name\s+: pkg$ 24 | ou ^Version\s+: [0-9]+\.[0-9]+\.?[0-9]*$ 25 | 26 | # Get package files 27 | in -Ql pkg 28 | ou ^pkg-[0-9]+\.[0-9]+\.?[0-9]*:$ 29 | ou ^\s+/usr/local/sbin/pkg$ 30 | 31 | # Get dependencies 32 | in -Si nginx 33 | ou ^Name\s+: nginx$ 34 | ou ^Version\s+: [0-9]+\.[0-9]+\.?[0-9]* 35 | ou ^Shared Libs required:$ 36 | 37 | # Search package 38 | in -Ss nano 39 | ou ^nano-[0-9]+\.[0-9]+\.?[0-9]* 40 | ou ^rubygem-nanoc-[0-9]+\.[0-9]+\.?[0-9]* 41 | 42 | # # Vm initialization installs this tool! 43 | # NOTE: This is already done in Makefile 44 | # in -Rs bash 45 | # in ! command -v bash 46 | # ou not found 47 | 48 | # Update 49 | in -Sy 50 | ou ^All repositories are up to date\.$ 51 | 52 | # Upgrade 53 | in -Su 54 | ou ^Your packages are up to date\.$ 55 | in -Syu 56 | ou ^All repositories are up to date\.$ 57 | ou ^Your packages are up to date\.$ 58 | 59 | # Install package 60 | in ! command -v nano 61 | ou empty 62 | in -S --noconfirm nano 63 | ou ^New packages to be INSTALLED:$ 64 | in ! command -v nano 65 | ou ^/usr/local/bin/nano$ 66 | 67 | # Remove package 68 | in -R --noconfirm nano 69 | ou ^Installed packages to be REMOVED:$ 70 | in ! nano 71 | ou not found 72 | 73 | in -S --noconfirm nano 74 | in clear 75 | in -Rs --noconfirm nano 76 | ou ^Installed packages to be REMOVED:$ 77 | 78 | # Fetch package 79 | in ! echo y | pacman -Sw nano 80 | ou ^No packages are required to be fetched.$ 81 | 82 | # Clean cache 83 | in -Sc --noconfirm 84 | ou ^(Nothing to do)|(The following package files will be deleted:)$ 85 | 86 | in -Scc 87 | ou ^(Nothing to do.)|(/var/cache/pkg/.+)$ 88 | -------------------------------------------------------------------------------- /tests/slitaz40.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for Slitaz support 4 | # Author : Ky-Anh Huynh 5 | # License : MIT 6 | 7 | im icymatter/slitaz40-minimal 8 | im slitaz40_bash3 9 | 10 | in -Sy 11 | ou (Connecting to)|(Recharging repository) 12 | ou (is ready to use)|(Main is up to date) 13 | 14 | in -Q 15 | ou ^busybox.+[[:digit:]]+ 16 | 17 | # FIXME: slitaz generates some special characters 18 | in -Qq 19 | ou ^busybox 20 | 21 | in -Qi busybox 22 | ou Package.+:.+busybox 23 | 24 | in -Ql busybox 25 | ou ^/bin/busybox 26 | 27 | in -sS htop 28 | ou ^htop((-)|( +))[[:digit:]]+ 29 | 30 | in -Qs htop 31 | ou not implemented 32 | 33 | in -Qo /bin/busybox 34 | ou ^busybox 35 | 36 | in -Qo busybox 37 | ou ^busybox 38 | 39 | in ! echo Y | pacman -S htop 40 | ou htop.+ is installed. 41 | 42 | in ! echo Y | pacman -S --forced htop 43 | ou Unknown option 44 | 45 | in ! echo Y | pacman -S -- --forced htop 46 | ou htop.+ is installed. 47 | 48 | # FIXME: Slitaz-4.0: test passed 49 | # FIXME: Slitaz-5.0: test failed. Possibly a tazpkg bug? 50 | in ! echo N | pacman -R htop 51 | ou Uninstallation of htop cancelled 52 | 53 | # FIXME: Weird, slitaz doesn't understand Y :) 54 | # FIXME: It's actually a timeout problem here...? 55 | in ! echo Y | pacman -R htop 56 | ou Uninstallation of htop cancelled 57 | 58 | in ! echo y | pacman -R htop 59 | ou Removing all files installed 60 | 61 | in ! export TAZPKG_FILE=`find /var/cache/tazpkg/ -type f -iname "htop*.tazpkg"` 62 | in -U $TAZPKG_FILE 63 | ou htop.+ is installed. 64 | 65 | in -Sccc 66 | ou not implemented 67 | 68 | in -Scc 69 | in clear 70 | 71 | # FIXME: Slitaz-4.0: passed 72 | # FIXME: Slitaz-5.0: failed; `-Ss` runs `-Sy` automatically. 73 | in -sS htop 74 | ou No 'packages.list' found to check 75 | -------------------------------------------------------------------------------- /tests/sun_tools.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for sun_tools support 4 | # Author : Álvaro Mondéjar 5 | # License : MIT 6 | 7 | # NOTE: Must be executed in a Solaris (SunOS) distribution 8 | 9 | im solaris 10 | 11 | # Get packages information 12 | in -Qi 13 | ou PKGINST:\s+CSWpkgutil 14 | ou PKGINST:\s+BRCMbnx 15 | 16 | # Get locally installed package 17 | in -Qs pkgutil 18 | ou ^application CSWpkgutil 19 | 20 | # Get installed packages 21 | in -Q 22 | ou ^application CSWpkgutil 23 | 24 | in -Q CSWpkgutil 25 | ou ^application CSWpkgutil pkgutil 26 | 27 | in -Qq 28 | ou ^application CSWpkgutil 29 | 30 | -------------------------------------------------------------------------------- /tests/swupd.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for swupd support 4 | # Author : Álvaro Mondéjar 5 | # License : MIT 6 | 7 | im clearlinux:base clearlinux:latest 8 | 9 | # Update 10 | in -Su 11 | ou ^Update (complete - System already up-to-date|started) 12 | in -Suy 13 | ou ^Update (complete - System already up-to-date|started) 14 | in -Sy 15 | ou ^Update (complete - System already up-to-date|started) 16 | 17 | # Install package (os-core-search needed for searching capabilities) 18 | in -S os-core-search 19 | ou ^ - os-core-search 20 | ou ^Installing files\.\.\.$ 21 | ou ^Successfully installed 1 bundle$ 22 | 23 | # Search package 24 | in -Ss os-core-search 25 | ou ^Bundle with the best search result:$ 26 | ou ^\s+os-core-search\s+- Provides swupd search capability\. \(installed\)$ 27 | 28 | # List installed packages 29 | in -Q 30 | Installed bundles: 31 | ou ^ - findutils$ 32 | ou ^ - os-core$ 33 | ou ^ - os-core-search$ 34 | 35 | # Query package files 36 | in -Qo swupd 37 | ou ^\s+os-core-update.+\(installed\)$ 38 | in -Qo /sbin/swupd 39 | ou ^\s+os-core-update.+\(installed\)$ 40 | 41 | # Get bundle information 42 | in -Qi os-core-search 43 | ou ^ Info for bundle: os-core-search$ 44 | ou ^Status: Explicitly installed$ 45 | 46 | # Remove bundle 47 | in -R os-core-search 48 | ou ^The following bundles are being removed:$ 49 | ou ^Deleting bundle files\.\.\.$ 50 | ou ^Successfully removed 1 bundle$ 51 | in -Ss os-core-search 52 | ou ^This bundle can be installed with:$ 53 | 54 | # Clean cache 55 | in -Sc 56 | ou files removed$ 57 | in -Scc 58 | ou files removed$ 59 | -------------------------------------------------------------------------------- /tests/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Purpose : Execute test using data from foobar.txt 4 | # Author : Ky-Anh Huynh 5 | # License : MIT 6 | # Date : July 2016 (initial version), 7 | # June 2021 (parallel support) 8 | 9 | __test_an_image_with_docker() { 10 | local_pacman="${1}" 11 | local_img="${2}" 12 | 13 | if [ "$local_img" = "im" ]; then 14 | return 0 15 | fi 16 | 17 | echo >&2 ":: INFO($local_pacman) Testing with $local_img" 18 | ( 19 | if [[ -f "Dockerfile.${local_img}" ]]; then 20 | >&2 echo ":: ... building docker file ${local_img}" 21 | docker build -t "$local_img" -f "Dockerfile.${local_img}" . 22 | fi 23 | 24 | cd tmp/ || return 1 25 | 26 | # Bash/shellcheck suggests to avoid `sed`, but we would port 27 | # this script to POSIX (which is impossible for now due to 28 | # the use of `export -f` as seen in the next part of the script). 29 | 30 | MSG_PREFIX="( $local_pacman vs. $local_img )" 31 | # shellcheck disable=SC2001 32 | docker run --rm \ 33 | -v "$PWD/pacapt.dev:/usr/bin/pacman" \ 34 | -v "$PWD/$local_pacman.sh:/tmp/test.sh" \ 35 | -e "MSG_PREFIX=:: INFO $MSG_PREFIX " \ 36 | "$local_img" \ 37 | /tmp/test.sh 2>"$local_pacman.$(echo "$local_img" | sed -e "s!/!-!g").log" 38 | ) 39 | if [ $? -ge 1 ]; then 40 | echo >&2 ":: FAIL $MSG_PREFIX" 41 | return 1 42 | fi 43 | } 44 | 45 | # $1: Input file 46 | _test() { 47 | local_file="${1:-}" 48 | local_pacman="$(basename "$local_file" .txt)" 49 | local_images= 50 | 51 | # See if input is provided with .txt extension 52 | if [ "$(basename "$local_file")" = "$local_pacman" ]; then 53 | local_file="$local_file.txt" 54 | fi 55 | 56 | if [ ! -f "$local_file" ]; then 57 | echo >&2 ":: ERRO($local_pacman): File not found '$local_file'. Return(1)." 58 | return 1 59 | fi 60 | 61 | echo >&2 ":: INFO($local_pacman) Generating 'tmp/$local_pacman.sh'..." 62 | sh ../bin/gen_tests.sh < "$local_file" > "tmp/$local_pacman.sh" 63 | chmod 755 "tmp/$local_pacman.sh" 64 | 65 | if ! sh -n "tmp/$local_pacman.sh"; then 66 | return 1 67 | fi 68 | 69 | if [ "${TESTS_DO_NOT_RUN:-}" = 1 ]; then 70 | return 0 71 | fi 72 | 73 | if [ -z "$IMAGES" ]; then 74 | local_images="$(grep -E '^im ' "$local_file" | sed -re 's/^ *im +//g')" 75 | else 76 | >&2 echo ":: INFO($local_pacman) Using image(s) from IMAGES (${IMAGES})" 77 | local_images="${IMAGES}" 78 | fi 79 | 80 | for img in $local_images; do 81 | local_pacmans="$local_pacmans $local_pacman" 82 | done 83 | 84 | # export -f is requiring `Bash` =)) 85 | local_plog="tmp/parallel.$local_pacman.log" 86 | export -f __test_an_image_with_docker 87 | # shellcheck disable=SC2086 88 | parallel \ 89 | --link \ 90 | --line-buffer \ 91 | --joblog "$local_plog" \ 92 | __test_an_image_with_docker \ 93 | ::: $local_pacmans \ 94 | ::: $local_images 95 | 96 | cat "$local_plog" 97 | 98 | tail -n+2 "$local_plog" \ 99 | | awk ' 100 | BEGIN { 101 | n_tests = 0 102 | exit_code = 0 103 | } 104 | /[0-9]/ { 105 | n_tests += 1 ; 106 | if ($7 > 0) { 107 | exit_code = 1; 108 | } 109 | } 110 | END { 111 | exit(exit_code) 112 | } 113 | ' 114 | 115 | if [ $? -eq 0 ]; then 116 | echo ":: INFO: All test(s) passed." 117 | else 118 | echo ":: ERRO: Some test(s) failed." 119 | return 1 120 | fi 121 | } 122 | 123 | while [ $# -gt 0 ]; do 124 | _test "$1" || exit 1 125 | shift 126 | done 127 | -------------------------------------------------------------------------------- /tests/xbps.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for xbps support 4 | # Author : Connor Sample 5 | # License : MIT 6 | 7 | im voidlinux 8 | 9 | # List packages 10 | in -Q 11 | ou ^ii.*$ 12 | 13 | in -Qe 14 | ou ^base-minimal.*$ 15 | 16 | in -Qi dash 17 | ou ^\[\*\]\sdash.* 18 | 19 | in -Ql tar 20 | ou ^/usr/bin/tar.* 21 | 22 | in -Qo /usr/bin/tar 23 | ou tar-[0-9_.]+: /usr/bin/tar \(regular file\) 24 | 25 | in -Qs tar 26 | ou \[\*\] tar-.* 27 | 28 | # Installing/removing packages 29 | # Older version of void is throwing a certificate error due to old certificate 30 | 31 | in ! SSL_NO_VERIFY_PEER=true pacman -Sy 32 | ou .*\[\*\]\sUpdating repository.* 33 | 34 | in -S --noconfirm nano 35 | ou .*[1-9]+\sinstalled.* 36 | 37 | in -Ss nano 38 | ou \[\-\]\snano.* 39 | 40 | in -R --noconfirm nano 41 | ou .*1 removed\.$ 42 | 43 | in -Scc 44 | ou 45 | -------------------------------------------------------------------------------- /tests/yum.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for yum support 4 | # Author : Álvaro Mondéjar 5 | # License : MIT 6 | 7 | im centos:7 centos:8 8 | im oraclelinux:7-slim 9 | 10 | in -P 11 | ou available operations:.*( [Q][ ilos])+ 12 | 13 | # Get installed packages 14 | in -Qq 15 | ou ^rpm$ 16 | in -Q 17 | ou ^rpm [0-9]+\.[0-9]+\.?[0-9]*$ 18 | 19 | # Get packages information 20 | in -Qi 21 | ou ^Name\s+: rpm$ 22 | ou ^Version\s+: [0-9]+\.[0-9]+\.?[0-9]*$ 23 | 24 | # Get package information 25 | in -Qi rpm 26 | ou ^Name\s+: rpm$ 27 | ou ^Version\s+: [0-9]+\.[0-9]+\.?[0-9]*$ 28 | 29 | # Get locally installed package 30 | in -Qs rpm 31 | ou ^rpm [0-9]+\.[0-9]+\.?[0-9]*$ 32 | in -Qqs rpm 33 | ou ^rpm$ 34 | 35 | # Get package files 36 | in -Ql rpm 37 | ou ^(/usr)?/bin/rpm$ 38 | 39 | # Get package from file 40 | in -Qo rpm 41 | ou ^rpm-.+\.x86_64$ 42 | in -Qo "$(command -v rpm)" 43 | ou ^rpm-.+\.x86_64$ 44 | 45 | # Show package changelog 46 | in -Qc rpm 47 | ou ^*\s.+[0-9]$ 48 | 49 | # List packages with available updates 50 | # oraclelinux/slim may doesn't show anything 51 | in -Qu 52 | ou ^(([a-z0-9\-]+\.x86_64.+(baseos|updates|ol7_latest))|(Loaded plugins: ovl))$ 53 | in -Sy 54 | ou ^(([a-z0-9\-]+\.x86_64.+(baseos|updates|ol7_latest))|(Loaded plugins: ovl))$ 55 | 56 | # Get installed packages unavailable in repos 57 | in -Qm 58 | ou ^(Last metadata expiration check|Loaded plugins) 59 | 60 | # Install package 61 | in ! command -v wget 62 | ou empty 63 | in -S --noconfirm wget 64 | ou ^Installing:$ 65 | ou ^ wget\s+x86_64 66 | ou ^Installed:$ 67 | in ! command -v wget 68 | ou ^(/usr)?/bin/wget$ 69 | 70 | # Remove package 71 | in -R --noconfirm wget 72 | ou ^Removing:$ 73 | ou ^ wget\s+x86_64 74 | ou ^Removed:$ 75 | in ! command -v wget 76 | ou empty 77 | 78 | in -S --noconfirm wget 79 | in ! command -v wget 80 | ou ^(/usr)?/bin/wget$ 81 | in -Rs --noconfirm wget 82 | ou ^Removing:$ 83 | ou ^ wget\s+x86_64 84 | ou ^Removed:$ 85 | in ! command -v wget 86 | ou empty 87 | 88 | # Update 89 | in -Su 90 | ou ^((Up(dat|grad)ing:)|((Loaded plugins: ovl)))$ 91 | in -Suy 92 | ou ^(([a-z0-9\-]+\.x86_64.+(baseos|updates|ol7_latest))|((Loaded plugins: ovl)))$ 93 | 94 | # Search packages 95 | in -Ss wget 96 | ou ^wget\.x86_64 97 | 98 | # NOTE: dependencies queries require repoquery (included in yum-utils) 99 | in -S --noconfirm yum-utils 100 | in clear 101 | in ! command -v repoquery 102 | ou ^(/usr)?/bin/repoquery$ 103 | 104 | # Get information from local package file 105 | in ! repoquery --location nano 106 | ou ^http.+\.rpm$ 107 | in ! curl -sL "$(repoquery --location nano 2>/dev/null | head -n 1)" -o /tmp/nano-package.rpm --connect-timeout 5 --max-time 30 --retry 5 --retry-delay 0 --retry-max-time 60 108 | ou empty 109 | in ! [ -f /tmp/nano-package.rpm ] || echo not found 110 | ou empty 111 | in -Qp /tmp/nano-package.rpm 112 | ou ^nano-.+\.x86_64$ 113 | 114 | # Install package using local file 115 | in ! command -v nano 116 | ou empty 117 | in -U --noconfirm /tmp/nano-package.rpm 118 | ou ^Installing:$ 119 | ou ^ nano\s+x86_64 120 | ou ^Installed:$ 121 | in ! command -v nano 122 | ou ^(/usr)?/bin/nano$ 123 | 124 | # List packages installed explicitly 125 | in -Qe 126 | ou ^nano$ 127 | ou ^yum-utils$ 128 | 129 | # Cache cleaning 130 | in -Sc 131 | ou ^[0-9]+( metadata)? files* removed$ 132 | in -Scc 133 | ou ^[0-9]+( package)? files* removed$ 134 | in -Sccc 135 | ou ^([0-9]+ files* removed|Cleaning repos:) 136 | 137 | # Get dependencies 138 | in -Si yum 139 | ou ^(dnf|rpm)- 140 | 141 | # Get reverse dependencies 142 | in -Sii rpm 143 | ou ^rpm-libs- 144 | 145 | # Package groups 146 | in -Sg 147 | ou ^ FTP Server$ 148 | in -Sg "FTP Server" 149 | ou ^ Mandatory Packages:$ 150 | ou ^ \+?vsftpd$ 151 | -------------------------------------------------------------------------------- /tests/zypper.txt: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Purpose : Testing script for zypper (opensuse) support 4 | # Author : Ky-Anh Huynh 5 | # License : MIT 6 | 7 | im opensuse/leap:15.2 8 | im opensuse/leap:42.3 9 | 10 | # FIXME: We disable this but also create a specific test from 11 | # FIXME: github/workflow (zypper-seccomp). We should re-enable 12 | # FIXME: this once the upstream issues are gone 13 | # im opensuse/tumbleweed:latest 14 | 15 | # im opensuse/clair:latest 16 | im zypper_bash3 17 | 18 | # On zypper_bash3, Bash is not available 19 | in ! PACAPT_DEBUG=auto pacman 20 | in ! if bash --version | grep -qs 'version 3'; then echo "Bash3-no-switching"; fi 21 | ou (debug.*Switching to Bash shell)|(Bash3-no-switching) 22 | 23 | in -P 24 | ou available operations:.*( [Q][ ilos])+ 25 | 26 | # Update package databases 27 | in -Sy 28 | 29 | # Simple query that lists all packages 30 | in -Qq 31 | ou ^glibc 32 | ou ^zypper 33 | 34 | # Listing with version and package name 35 | in -Q 36 | # ou ^ii +zypper +.+ubuntu 37 | ou ^i\+ +\| +zypper + 38 | 39 | # Information of `zypper` 40 | in -Qi zypper 41 | ou ^Name +: +zypper 42 | ou ^Source package : zypper-.*.src 43 | 44 | # File listing for `zypper` 45 | in -Ql zypper 46 | ou ^/usr/lib/zypper/commands 47 | 48 | # Look up package name 49 | in -Qo /bin/bash 50 | ou ^bash.* 51 | 52 | in -Qo bash 53 | ou ^bash.* 54 | 55 | # Search for pattern in installed package (names + descriptions) 56 | in -Qs bash 57 | ou Bourne-Again Shell 58 | 59 | in -Qsq bash 60 | ou ^bash 61 | 62 | in -Qs bourne 63 | ou Bourne-Again Shell 64 | 65 | in -Qs screen 66 | ou ncurses-utils 67 | 68 | # Install and Deinstall a package 69 | 70 | # Download without installation 71 | in ! pacman -Sw --noconfirm screen 72 | in ! command -v screen || echo 'command not found' 73 | ou command not found 74 | 75 | # Display remote package information 76 | in -Si screen 77 | ou ^Name +: +screen 78 | 79 | #in -Sii screen 80 | #ou ^Reverse Depends: 81 | 82 | # # Now installation 83 | in ! pacman -S --noconfirm screen 84 | in ! command -v screen 85 | ou ^(/usr)?/bin/screen 86 | 87 | # Now remove the package 88 | in ! pacman -R --noconfirm screen 89 | in -Qi screen 90 | ou ^Status +: +not installed 91 | 92 | in -Sc 93 | ou All repositories have been cleaned up. 94 | 95 | in -sS tmux 96 | ou tmux 97 | 98 | # Package groups 99 | in -Sg 100 | ou ^ | base 101 | ou ^ | console 102 | 103 | in -Sg console 104 | ou ^ | patterns-base-console 105 | ou ^ | tmux 106 | --------------------------------------------------------------------------------