mirror of https://github.com/kdabir/has.git
Compare commits
80 Commits
Author | SHA1 | Date |
---|---|---|
Peter Dave Hello | 430d0854f2 | |
Peter Dave Hello | 43a6c97bcd | |
Arkoprabho Chakraborti | 61032d63f1 | |
Kunal Dabir | a2d7c083c7 | |
Kunal Dabir | abb3decba7 | |
Maksym Bilyk | 54c334962c | |
wzy | 8b43040ce2 | |
Alex Meyer | c12a38bbdd | |
Kunal Dabir | 49444b3179 | |
Christian Clauss | 81a613a80c | |
Sylvain METAYER | 0f965b7713 | |
Christian Clauss | b6869f3f8d | |
Christian Clauss | fc3505077a | |
Talas | 7446f451dd | |
Kunal Dabir | 45fd56f557 | |
Megumin | 559e885f22 | |
Saager Mhatre | 3ce21c9b2c | |
ptt-homme | 868bc1aff6 | |
ptt-homme | 1f28a53597 | |
ptt-homme | 41149c3474 | |
John-Michael Faircloth | 45c4126659 | |
Abhishek Anand Amralkar | 99595431ff | |
Stephen Dolenc | e8bdf2278c | |
Kunal Dabir | 90d1817ab9 | |
johan-ejstrud | 3dd103126e | |
Stephen Dolenc | 4ccd0177d4 | |
Jordi Sola | 31828ec6bf | |
Cody Hiar | 28484822d6 | |
Kunal Dabir | bdf7c2ffe6 | |
Ashish Mohite | 197dce1d03 | |
Kunal Dabir | b82d650df0 | |
Kunal Dabir | e9b78acff2 | |
Kunal Dabir | a788fdf6b8 | |
Kunal Dabir | 754a4e444c | |
Kunal Dabir | e8028b18ad | |
Virgil | c25ce0eea4 | |
Virgil | 1f7dd61324 | |
Virgil | f5981b9145 | |
Kunal Dabir | 53ab06dd03 | |
Virgil | 36e11e238f | |
Kunal Dabir | 3b26771c8a | |
Kunal Dabir | 33b0623497 | |
Kunal Dabir | 29e5c412d2 | |
Kunal Dabir | 10c906e7f8 | |
Kunal Dabir | ef55e62fd0 | |
Kunal Dabir | b1f41e786c | |
Kunal Dabir | 7dc6946d36 | |
Kunal Dabir | d07a65596d | |
Kunal Dabir | 33cbc13738 | |
Kunal Dabir | 44a71cf023 | |
Kunal Dabir | 1702c991ce | |
Kunal Dabir | b60c239bc4 | |
Kunal Dabir | 79f3eb8bba | |
Kunal Dabir | 27a6b24b1c | |
Kunal Dabir | 722a5495d6 | |
Kunal Dabir | 4e91758c00 | |
Kunal Dabir | 1ad2f05548 | |
Jason Phan | 4d1035e241 | |
Kunal Dabir | 8674525059 | |
Kunal Dabir | 87959c9b70 | |
Dan Stewart | 86e7a8c4d6 | |
Kunal Dabir | 75ccc96171 | |
Layik Hama | 621616fe56 | |
Kunal Dabir | 0f23f2606d | |
Kunal Dabir | d18ace12fd | |
Kunal Dabir | 5443d4cb9e | |
Kunal Dabir | c85422d5d4 | |
Kunal Dabir | a3223b2a8e | |
codetriage-readme-bot | 90e3dfdd68 | |
Kunal Dabir | 4de4abba1e | |
Kunal Dabir | 3136085c75 | |
Kunal Dabir | f6fe16c659 | |
Kunal Dabir | f5101803f4 | |
vimist | dfe466c7bf | |
vimist | d61a4bb457 | |
vimist | cf9ea4ce23 | |
vimist | f3b243a531 | |
vimist | 1382244c94 | |
Kunal Dabir | 0816c04c67 | |
Kunal Dabir | 8f0ffe8698 |
|
@ -1,19 +1,23 @@
|
|||
# http://editorconfig.org/
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{sh,bash,bats}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
# Markdown
|
||||
[*.md]
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Makefiles always use tabs for indentation
|
||||
[{Makefile, makefile}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
|
|
@ -1 +1,9 @@
|
|||
* text=auto
|
||||
# Auto detect text files and perform LF normalization
|
||||
# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
|
||||
* text=auto eol=lf
|
||||
#
|
||||
# The above will handle all files NOT found below
|
||||
#
|
||||
*.sh text diff=sh eol=lf
|
||||
*.bash text diff=sh eol=lf
|
||||
*.md text eol=lf
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
name: CI
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
shellcheck:
|
||||
name: shellcheck
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Clone Repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run Shellcheck
|
||||
uses: ludeeus/action-shellcheck@1.1.0
|
||||
|
||||
test:
|
||||
name: test
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
container:
|
||||
- debian # uses debian:buster-20200327-slim which is debian 10.3
|
||||
- ubuntu16 # uses ubuntu:xenial-20200212 which is ubuntu 16.04
|
||||
|
||||
container: kdabir/has-test-containers:${{ matrix.container }}
|
||||
|
||||
steps:
|
||||
- name: Clone Repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: test
|
||||
run: make test
|
||||
shell: bash
|
||||
|
||||
test_all:
|
||||
name: test_all
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
container:
|
||||
- ubuntu # uses ubuntu:bionic-20200311 which is ubuntu 18.04
|
||||
- alpine # uses bash:5.0.16 which is alpine 3.11
|
||||
|
||||
container: kdabir/has-test-containers:${{ matrix.container }}
|
||||
|
||||
steps:
|
||||
- name: Clone Repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: test_all
|
||||
run: bats -t ./tests/test_all_packages.bats
|
||||
shell: bash
|
|
@ -1,3 +1,4 @@
|
|||
*~
|
||||
.DS_Store
|
||||
.idea
|
||||
tmp-for-test/
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# make to install/test the project
|
||||
make
|
||||
curl
|
||||
git
|
||||
# bats for testing
|
||||
bats
|
220
.hastest.bats
220
.hastest.bats
|
@ -1,30 +1,224 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
@test "works with single command check" {
|
||||
run bash has git
|
||||
INSTALL_DIR=
|
||||
BATS_TMPDIR="${BATS_TMPDIR:-/tmp}"
|
||||
fancyx='✗'
|
||||
checkmark='✓'
|
||||
## We need to create a new directory so that .hasrc file in the root does not get read by the `has` instance under test
|
||||
setup() {
|
||||
export HAS_TMPDIR="${BATS_TMPDIR}/tmp-for-test"
|
||||
mkdir -p "${HAS_TMPDIR}"
|
||||
cp -f "${BATS_TEST_DIRNAME}"/has "${HAS_TMPDIR}"
|
||||
cd "${HAS_TMPDIR}" || return
|
||||
export has="${HAS_TMPDIR}/has"
|
||||
}
|
||||
|
||||
teardown() {
|
||||
if [[ -d "${HAS_TMPDIR}" ]]; then
|
||||
rm -rf "${HAS_TMPDIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
@test "invoking 'has' without arguments prints usage" {
|
||||
run $has
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ $output == *"✔ git"* ]]
|
||||
[ "${lines[0]}" = 'Usage: has [OPTION] <command-names>...' ]
|
||||
[ "${lines[1]}" = 'Has checks the presence of various command line tools on the PATH and reports their installed version.' ]
|
||||
[ "${lines[2]}" = 'Options:' ]
|
||||
[ "${lines[3]}" = ' -q Silent mode' ]
|
||||
[ "${lines[4]}" = ' -h, --help Display this help text and quit' ]
|
||||
[ "${lines[5]}" = ' -V, --version Show version number and quit' ]
|
||||
[ "${lines[6]}" = 'Examples: has git curl node' ]
|
||||
}
|
||||
|
||||
@test "safely tells about tools not configured" {
|
||||
run bash has foobar
|
||||
@test "make install creates a valid installation" {
|
||||
INSTALL_DIR="${HAS_TMPDIR}/.local"
|
||||
cd "${BATS_TEST_DIRNAME}"
|
||||
run make PREFIX="${INSTALL_DIR}" install
|
||||
[ "$status" -eq 0 ]
|
||||
[ -x "${INSTALL_DIR}/bin/has" ]
|
||||
|
||||
[ "$status" -eq 1 ]
|
||||
[[ $output == *"✘ foobar not understood"* ]]
|
||||
# has reads .hasrc from $PWD, so change anywhere else.
|
||||
cd "${INSTALL_DIR}"
|
||||
run "${INSTALL_DIR}/bin/has"
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${lines[0]}" = 'Usage: has [OPTION] <command-names>...' ]
|
||||
[ "${lines[1]}" = 'Has checks the presence of various command line tools on the PATH and reports their installed version.' ]
|
||||
[ "${lines[2]}" = 'Options:' ]
|
||||
[ "${lines[3]}" = ' -q Silent mode' ]
|
||||
[ "${lines[4]}" = ' -h, --help Display this help text and quit' ]
|
||||
[ "${lines[5]}" = ' -V, --version Show version number and quit' ]
|
||||
[ "${lines[6]}" = 'Examples: has git curl node' ]
|
||||
}
|
||||
|
||||
@test "env var lets override safety check" {
|
||||
HAS_ALLOW_UNSAFE=y run bash has foobar
|
||||
@test "..even if 'has' is missing from directory" {
|
||||
if [[ -n $GITHUB_ACTION ]] || [[ -n $GITHUB_ACTIONS ]]; then
|
||||
if grep -iq "ubuntu" /etc/issue; then
|
||||
skip "todo: this test fails on ubuntu in CI"
|
||||
fi
|
||||
fi
|
||||
|
||||
INSTALL_DIR="${HAS_TMPDIR}/system_local"
|
||||
cd "${BATS_TEST_DIRNAME}"
|
||||
mv has has-been
|
||||
run make PREFIX="${INSTALL_DIR}" install
|
||||
[ "$status" -eq 0 ]
|
||||
[ -x "${INSTALL_DIR}/bin/has" ]
|
||||
cd "${BATS_TEST_DIRNAME}"
|
||||
mv has-been has
|
||||
}
|
||||
|
||||
@test "make update runs git fetch" {
|
||||
cd "${BATS_TEST_DIRNAME}"
|
||||
if [[ -z $GITHUB_ACTION ]] && [[ -z $GITHUB_ACTIONS ]]; then
|
||||
skip "make update overwrites my git working tree"
|
||||
elif grep -iq "ubuntu" /etc/issue; then
|
||||
skip "todo: this test fails on ubuntu in CI"
|
||||
fi
|
||||
|
||||
run make update
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(echo "${output}" | grep "git fetch --verbose")" ]
|
||||
}
|
||||
|
||||
@test "works with single command check" {
|
||||
run $has git
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(echo "${lines[0]}" | grep "git")" ]
|
||||
}
|
||||
|
||||
@test "'has' warns about tools not configured" {
|
||||
run $has foobar
|
||||
|
||||
[ "$status" -eq 1 ]
|
||||
[[ $output == *"✘ foobar"* ]]
|
||||
[ "$(echo "${output}" | grep ${fancyx} | grep "foobar not understood")" ]
|
||||
}
|
||||
|
||||
@test "env var 'HAS_ALLOW_UNSAFE' overrides safety check" {
|
||||
HAS_ALLOW_UNSAFE=y run $has foobar
|
||||
|
||||
[ "$status" -eq 1 ]
|
||||
[ "$(echo "${output}" | grep ${fancyx} | grep "foobar")" ]
|
||||
}
|
||||
|
||||
@test "status code reflects number of failed commands" {
|
||||
HAS_ALLOW_UNSAFE=y run bash has foobar make git barbaz
|
||||
HAS_ALLOW_UNSAFE=y run $has foobar bc git barbaz
|
||||
|
||||
[ "$status" -eq 2 ]
|
||||
[[ $output == *"✘ foobar"* ]]
|
||||
[[ $output == *"✘ barbaz"* ]]
|
||||
[ "$(echo "${output}" | grep ${fancyx} | grep "foobar")" ]
|
||||
[ "$(echo "${output}" | grep ${fancyx} | grep "barbaz")" ]
|
||||
}
|
||||
|
||||
@test "status code reflects number of failed commands up to 126" {
|
||||
run $has $(for i in {1..256}; do echo foo; done)
|
||||
|
||||
[ "$status" -eq 126 ]
|
||||
}
|
||||
|
||||
@test "loads commands from .hasrc file and excludes comments" {
|
||||
printf "bash\n#comment\nmake\n" >> .hasrc
|
||||
|
||||
run $has
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(echo "${output}" | grep ${checkmark} | grep "bash")" ]
|
||||
[ "$(echo "${output}" | grep ${checkmark} | grep "make")" ]
|
||||
}
|
||||
|
||||
@test "loads commands from .hasrc file and honors CLI args as well" {
|
||||
printf "bash\nmake\ngit" >> .hasrc
|
||||
HAS_ALLOW_UNSAFE=y run $has git bc
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(echo "${output}" | grep ${checkmark} | grep "bash")" ]
|
||||
[ "$(echo "${output}" | grep ${checkmark} | grep "make")" ]
|
||||
[ "$(echo "${output}" | grep ${checkmark} | grep "git")" ]
|
||||
[ "$(echo "${output}" | grep ${checkmark} | grep "bc")" ]
|
||||
}
|
||||
|
||||
@test "testing PASS output with unicode" {
|
||||
run $has git
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "printf '%b\n' ${lines[0]}" =~ '✓' ]]
|
||||
}
|
||||
|
||||
@test "testing FAIL output with unicode" {
|
||||
run $has foobar
|
||||
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "printf '%b\n' ${lines[0]}" =~ '✗' ]]
|
||||
}
|
||||
|
||||
@test "fail count 3: testing output with and without unicode" {
|
||||
run $has git foobar barbaz barfoo
|
||||
|
||||
[ "$status" -eq 3 ]
|
||||
[[ "printf '%b\n' ${lines[0]}" =~ "${checkmark}" ]]
|
||||
[[ "printf '%b\n' ${lines[2]}" =~ '✗' ]]
|
||||
}
|
||||
|
||||
@test "testing archiving commands" {
|
||||
run $has tar unzip gzip xz unar pv zip
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(echo "${lines[0]}" | grep "tar")" ]
|
||||
[ "$(echo "${lines[1]}" | grep "unzip")" ]
|
||||
[ "$(echo "${lines[2]}" | grep "gzip")" ]
|
||||
[ "$(echo "${lines[3]}" | grep "xz")" ]
|
||||
[ "$(echo "${lines[4]}" | grep "unar")" ]
|
||||
[ "$(echo "${lines[5]}" | grep "pv")" ]
|
||||
[ "$(echo "${lines[6]}" | grep "zip")" ]
|
||||
}
|
||||
|
||||
@test "testing coreutils commands" {
|
||||
run $has coreutils sed awk grep sudo file linuxutils
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(echo "${lines[0]}" | grep "gnu_coreutils")" ]
|
||||
[ "$(echo "${lines[5]}" | grep "file")" ]
|
||||
[ "$(echo "${lines[6]}" | grep "gnu_coreutils")" ]
|
||||
}
|
||||
|
||||
@test "testing hub version is different to git version" {
|
||||
if ! command -v hub; then
|
||||
skip "'hub' command not found. Installation command can be found at the bottom of ./tests/containers/debian.Dockerfile"
|
||||
fi
|
||||
run $has hub git
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(echo "${lines[0]}" | grep "hub")" ]
|
||||
[ "$(echo "${lines[1]}" | grep "git")" ]
|
||||
[ ! "${lines[0]##*\ }" = "${lines[1]##*\ }" ]
|
||||
}
|
||||
|
||||
@test "quiet mode" {
|
||||
run $has -q git
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ -z "${output}" ]
|
||||
}
|
||||
|
||||
@test "quiet mode should print usage when no commands or .hasrc file" {
|
||||
run $has -q
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${lines[0]}" = 'Usage: has [OPTION] <command-names>...' ]
|
||||
[ "${lines[1]}" = 'Has checks the presence of various command line tools on the PATH and reports their installed version.' ]
|
||||
[ "${lines[2]}" = 'Options:' ]
|
||||
[ "${lines[3]}" = ' -q Silent mode' ]
|
||||
[ "${lines[4]}" = ' -h, --help Display this help text and quit' ]
|
||||
[ "${lines[5]}" = ' -V, --version Show version number and quit' ]
|
||||
[ "${lines[6]}" = 'Examples: has git curl node' ]
|
||||
}
|
||||
|
||||
@test "status code in quiet mode still equal to number of failed commands" {
|
||||
HAS_ALLOW_UNSAFE=y run $has -q foobar bc git barbaz
|
||||
|
||||
[ "$status" -eq 2 ]
|
||||
[ -z "${output}" ]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
enabled: true
|
||||
auto: false
|
||||
remote_files: []
|
||||
comments: true
|
||||
statuses: true
|
||||
request_review: null
|
||||
labels: [linting]
|
||||
restylers:
|
||||
- shfmt:
|
||||
# -ln str language variant to parse (bash/posix/mksh, default "bash")
|
||||
# -i uint indent: 0 for tabs (default), >0 for number of spaces
|
||||
# -bn binary ops like && and | may start a line
|
||||
# -ci switch cases will be indented
|
||||
# -sr redirect operators will be followed by a space
|
||||
# -kp keep column alignment paddings
|
||||
# -mn minify program to reduce its size (implies -s)
|
||||
arguments:
|
||||
- -ln bash
|
||||
- -i 2
|
||||
- -ci
|
||||
- -bn
|
||||
- -kp
|
||||
- -sr
|
10
.travis.yml
10
.travis.yml
|
@ -1,10 +0,0 @@
|
|||
language: bash
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository ppa:duggan/bats --yes
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq bats
|
||||
install:
|
||||
- sudo apt-get install -qq bc
|
||||
script:
|
||||
- make test
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2017 Kunal Dabir, Saager Mhatre
|
||||
Copyright (c) 2014-2018 Kunal Dabir, Saager Mhatre and various contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
|
42
Makefile
42
Makefile
|
@ -1,8 +1,40 @@
|
|||
test:
|
||||
# Makefile for has
|
||||
# https://github.com/kdabir/has
|
||||
# Sadly, longopts like --verbose are not working on MacOS for cp, mkdir and rm
|
||||
|
||||
|
||||
# PREFIX is an environment variable.
|
||||
# Use default value if not set.
|
||||
ifeq ($(PREFIX),)
|
||||
PREFIX := /usr/local
|
||||
endif
|
||||
|
||||
test : has
|
||||
bats .hastest.bats
|
||||
|
||||
install:
|
||||
cp has /usr/local/bin/has
|
||||
has :
|
||||
# ensure 'has' in repo
|
||||
git checkout --force -- has
|
||||
|
||||
# install 'has' in specified directory
|
||||
install : has
|
||||
chmod 755 has && \
|
||||
mkdir -v -p $(DESTDIR)$(PREFIX)/bin && \
|
||||
cp -v has $(DESTDIR)$(PREFIX)/bin/has
|
||||
|
||||
# update: has
|
||||
update : update-fetch has
|
||||
|
||||
update-fetch : update-force
|
||||
# update repo from upstream
|
||||
git fetch --verbose --force
|
||||
|
||||
update-force :
|
||||
# remove local repo 'has' to force update
|
||||
rm -f has
|
||||
|
||||
uninstall :
|
||||
rm -f $(DESTDIR)$(PREFIX)/bin/has
|
||||
|
||||
.PHONY: test install uninstall update
|
||||
|
||||
uninstall:
|
||||
rm -f /usr/local/bin/has
|
||||
|
|
212
README.md
212
README.md
|
@ -1,76 +1,210 @@
|
|||
# has
|
||||
|
||||
`has` checks presence of various command line tools on the path and also reports their installed version
|
||||
`has` checks presence of various command line tools on the PATH and reports their installed version.
|
||||
|
||||
## How ?
|
||||
[![Build Status](https://github.com/kdabir/has/actions/workflows/main.yml/badge.svg)](https://github.com/kdabir/has/actions/workflows/main.yml)
|
||||
[![Open Source Helpers](https://www.codetriage.com/kdabir/has/badges/users.svg)](https://www.codetriage.com/kdabir/has)
|
||||
|
||||
Download the `has` file. There is no dependency apart from `bash` itself
|
||||
[![demo](demo.svg)](demo.svg)
|
||||
|
||||
$ has node npm java git gradle
|
||||
✔ node 8.2.1
|
||||
✔ npm 5.3.0
|
||||
✔ java 1.8.0
|
||||
✔ git 2.14.1
|
||||
✔ gradle 4.0.1
|
||||
## Quick Start 🚴
|
||||
|
||||
If everything is good `has` exits with status code `0`. The status code
|
||||
reflects number of commands **not found** on your path.
|
||||
Just [install](#installing) the `has` script, (there is no dependency apart from `bash` itself). From the command line, pass the list of commands you want to check as arguments to `has`, for example:
|
||||
|
||||
$ has node go javac
|
||||
✔ node 8.2.1
|
||||
✔ go 1.8.3
|
||||
✘ javac
|
||||
```console
|
||||
$ has node npm java git gradle
|
||||
✔ node 8.2.1
|
||||
✔ npm 5.3.0
|
||||
✔ java 1.8.0
|
||||
✔ git 2.14.1
|
||||
✔ gradle 4.0.1
|
||||
```
|
||||
|
||||
If everything is good `has` exits with status code `0`. The exit status code reflects number of commands **not found** on your path.
|
||||
|
||||
```console
|
||||
$ has node go javac
|
||||
✔ node 8.2.1
|
||||
✔ go 1.8.3
|
||||
✘ javac
|
||||
```
|
||||
|
||||
And echo the status:
|
||||
|
||||
$ echo $?
|
||||
1
|
||||
```console
|
||||
$ echo $?
|
||||
1
|
||||
```
|
||||
|
||||
## Use `has` in scripts
|
||||
|
||||
`has` can be used in shell scripts to check presence of tool in very readable way
|
||||
|
||||
```bash
|
||||
if has node
|
||||
then echo you have what it takes 🎉
|
||||
fi
|
||||
```
|
||||
|
||||
**Pro Tip**: the `has` in above command can be replaced with the entire curl command for to ensure portability of script → `if curl -sL https://git.io/_has | bash -s node then ...`
|
||||
|
||||
|
||||
## Installing
|
||||
## Installing 🚀
|
||||
|
||||
Just download the `has` script in your path.
|
||||
`has` is a single bash script that does it all. You can [download](https://raw.githubusercontent.com/kdabir/has/master/has) the script and make it available on your `$PATH`. However, to make it even simpler, just follow *one* of these methods.
|
||||
|
||||
git clone https://github.com/kdabir/has.git && cd has && make install
|
||||
### Homebrew (MacOS) 🍺
|
||||
|
||||
Just run the following:
|
||||
|
||||
If you are lazy, you can run `has` directly off the internet as well:
|
||||
```bash
|
||||
brew install kdabir/tap/has
|
||||
```
|
||||
|
||||
curl -sL https://git.io/_has | bash -s git node npm
|
||||
✔ git 2.14.1
|
||||
✔ node 8.2.1
|
||||
✔ npm 5.3.0
|
||||
### Cloning the Repo
|
||||
|
||||
Just execute the following command in a terminal: it clones `has` repo and installs it into your path.
|
||||
|
||||
And if that's too much of typing every time, setup an alias
|
||||
|
||||
alias has="curl -sL https://git.io/_has | bash -s"
|
||||
```bash
|
||||
git clone https://github.com/kdabir/has.git && cd has && sudo make install
|
||||
```
|
||||
|
||||
For a non-root installation:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/kdabir/has.git
|
||||
cd has
|
||||
make PREFIX=$HOME/.local install
|
||||
```
|
||||
|
||||
To update just do a `git fetch` or `make update` followed by the appropriate `make install` command.
|
||||
|
||||
### Downloading to a file
|
||||
|
||||
```bash
|
||||
curl -sL https://git.io/_has > /usr/local/bin/has
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -sL https://git.io/_has | sudo tee /usr/local/bin/has >/dev/null
|
||||
```
|
||||
|
||||
These commands are safe to be called multiple times as well (to update `has`)
|
||||
|
||||
### asdf users
|
||||
|
||||
```
|
||||
asdf plugin add has https://github.com/sylvainmetayer/asdf-has
|
||||
asdf install has 1.4.0
|
||||
```
|
||||
|
||||
### Running directly off the Internet
|
||||
|
||||
If you are lazy, you can run `has` directly off the Internet as well:
|
||||
|
||||
```console
|
||||
curl -sL https://git.io/_has | bash -s git node npm
|
||||
✔ git 2.17.1
|
||||
✔ node 11.11.0
|
||||
✔ npm 6.7.0
|
||||
```
|
||||
|
||||
**ProTip**: if that's too much typing every time, setup an alias in your `.bashrc`/`.zshrc` file:
|
||||
|
||||
```.bashrc
|
||||
alias has="curl -sL https://git.io/_has | bash -s"
|
||||
```
|
||||
|
||||
And use it
|
||||
|
||||
$ has git
|
||||
✔ git 2.14.1
|
||||
```console
|
||||
$ has git
|
||||
✔ git 2.17.1
|
||||
$ type has
|
||||
has is aliased to `curl -sL https://git.io/_has | bash -s'
|
||||
```
|
||||
|
||||
## command not understood by has?
|
||||
## Command not understood by has?
|
||||
|
||||
Let's say `$ has foobar` returns `foobar not understood`, because `has` may not have whitelisted `foobar`.
|
||||
|
||||
In such cases, pass `HAS_ALLOW_UNSAFE=y has foobar`. This is should still check for existance of `foobar` and tries to detect version as well.
|
||||
In such cases, pass `HAS_ALLOW_UNSAFE=y has foobar`. This should still check for existence of `foobar` and tries to detect version as well.
|
||||
|
||||
> the value must exactly be `y` for it to work.
|
||||
|
||||
## Demo
|
||||
## The `.hasrc` file
|
||||
|
||||
[![asciicast](https://asciinema.org/a/135790.png)](https://asciinema.org/a/135790)
|
||||
`has` looks for `.hasrc` file in the directory from where `has` command is issued. This file can contain commands that `has`
|
||||
will check for. List one command per line. Lines starting with `#` are treated as comments.
|
||||
|
||||
Following is example of `.hasrc` file:
|
||||
|
||||
```hs
|
||||
# tools
|
||||
git
|
||||
curl
|
||||
|
||||
# interpreters
|
||||
ruby
|
||||
node
|
||||
```
|
||||
|
||||
When `has` is run in directory containing this file, it produces:
|
||||
|
||||
```console
|
||||
$ has
|
||||
✔ git 2.19.1
|
||||
✔ curl 7.54.0
|
||||
✔ ruby 2.3.1
|
||||
✔ node 10.7.0
|
||||
```
|
||||
|
||||
Also, CLI arguments passed to `has` are additive to `.hasrc` file. For example, in the same dir, if the following command is fired,
|
||||
`has` checks for both commands passed from cli args and provided in `.hasrc` file.
|
||||
|
||||
```bash
|
||||
$ has java
|
||||
✔ java 11.0.1
|
||||
✔ git 2.19.1
|
||||
✔ curl 7.54.0
|
||||
✔ ruby 2.3.1
|
||||
✔ node 10.7.0
|
||||
```
|
||||
|
||||
**Pro Tip**: commit `.hasrc` file in root of your project. This can work as a quick check for confirming presence all command
|
||||
line tools required to build and run your project.
|
||||
|
||||
On machines that don't even have `has` installed, your project's `.hasrc` is honored by this command:
|
||||
|
||||
`curl -sL https://git.io/_has | bash -s`
|
||||
|
||||
> take a look at [.hasrc](https://github.com/kdabir/has/blob/master/.hasrc) file for this repo.
|
||||
|
||||
## Contributing
|
||||
|
||||
[![Build Status](https://travis-ci.org/kdabir/has.svg?branch=has)](https://travis-ci.org/kdabir/has)
|
||||
|
||||
|
||||
1. Star the repo, tweet about it, spread the word
|
||||
1. Star the repo, tweet about it, spread the word
|
||||
2. Update the documentation (i.e. the README file)
|
||||
3. Adding support for more commands
|
||||
4. Adding more features to `has`
|
||||
|
||||
## Adding more tools
|
||||
|
||||
#### ♥
|
||||
The current list of supported packages can be viewed with `bash tests/packages_all.sh`
|
||||
|
||||
If the command you wish to include supports any of `-v`, `--version`, `-version`, `version`, `-V` then you can find
|
||||
corresponding function which can be called to check presence and extract version. However, for many tools version
|
||||
extraction may not work and you will need to add custom parsing of command's output. The `has` script is commented
|
||||
to guide developers about what needs to be done to add more tools.
|
||||
|
||||
`/tests/test_all_packages.bats` will test every package has supports. This includes newly added commands so please add new packages to
|
||||
- `alpine.Dockerfile` and `ubuntu.Dockerfile` to install the tool OR
|
||||
- `packages_alpine_skip.txt` and `packages_ubuntu_skip.txt` to exclude the package from the tests
|
||||
|
||||
## Adding Features
|
||||
|
||||
If you are contributing a feature, please ensure to check current tests. Add test cases for your feature. Tests are
|
||||
executed using the excellent [bats](https://github.com/bats-core/bats-core) testing framework. Add tests and run `make test`
|
||||
|
||||
Raise the PR and **make sure the tests pass** on [GitHub Actions](https://github.com/kdabir/has/actions).
|
||||
|
||||
### ♥
|
||||
|
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 31 KiB |
432
has
432
has
|
@ -1,11 +1,52 @@
|
|||
#!/usr/bin/env bash
|
||||
## source: https://github.com/kdabir/has
|
||||
|
||||
## To add more tools, search for "__detect" function in this file
|
||||
|
||||
## Important so that version is not extracted for failed commands (not found)
|
||||
set -o pipefail
|
||||
|
||||
## constant - symbols for success failure
|
||||
PASS='✔'
|
||||
FAIL='✘'
|
||||
readonly BINARY_NAME="has"
|
||||
readonly VERSION="v1.5.0"
|
||||
|
||||
## constants - symbols for success failure
|
||||
if [[ ! -t 1 ]]; then
|
||||
TERM="dumb"
|
||||
elif [[ -z $TERM ]]; then
|
||||
TERM="xterm"
|
||||
fi
|
||||
|
||||
txtreset="$(tput -T "$TERM" sgr0)"
|
||||
readonly txtreset
|
||||
|
||||
txtbold="$(tput -T "$TERM" bold)"
|
||||
readonly txtbold
|
||||
|
||||
txtred="$(tput -T "$TERM" setaf 1)"
|
||||
readonly txtred
|
||||
|
||||
txtgreen="$(tput -T "$TERM" setaf 2)"
|
||||
readonly txtgreen
|
||||
|
||||
txtyellow="$(tput -T "$TERM" setaf 3)"
|
||||
readonly txtyellow
|
||||
|
||||
# unicode "✗"
|
||||
readonly fancyx='\342\234\227'
|
||||
# unicode "✓"
|
||||
readonly checkmark='\342\234\223'
|
||||
# PASS="\e[1m\e[38;5;2m✔\e[m"
|
||||
# FAIL="\e[1m\e[38;5;1m✘\e[m"
|
||||
readonly PASS="${txtbold}${txtgreen}${checkmark}${txtreset}"
|
||||
readonly FAIL="${txtbold}${txtred}${fancyx}${txtreset}"
|
||||
|
||||
## These variables are used to control decoration of output
|
||||
COLOR_AUTO="auto"
|
||||
COLOR_NEVER="never"
|
||||
COLOR_ALWAYS="always"
|
||||
COLOR_OPTS=("${COLOR_AUTO} ${COLOR_NEVER} ${COLOR_ALWAYS}")
|
||||
COLOR="${COLOR_AUTO}"
|
||||
COLOR_PREFIX="--color"
|
||||
|
||||
## These variables are used to keep track of passed and failed commands
|
||||
OK=0
|
||||
|
@ -14,97 +55,253 @@ KO=0
|
|||
## Regex to extract simple version - extracts numeric sem-ver style versions
|
||||
REGEX_SIMPLE_VERSION="([[:digit:]]+\.?){2,3}"
|
||||
|
||||
## name of RC file that can contain list of tools to be checked
|
||||
RC_FILE=".hasrc"
|
||||
|
||||
## try to extract version by executing $1 with $2 arg
|
||||
_usage() {
|
||||
cat <<EOF
|
||||
Usage: ${BINARY_NAME} [OPTION] <command-names>...
|
||||
Has checks the presence of various command line tools on the PATH and reports their installed version.
|
||||
|
||||
Options:
|
||||
-q Silent mode
|
||||
-h, --help Display this help text and quit
|
||||
-V, --version Show version number and quit
|
||||
|
||||
Examples: ${BINARY_NAME} git curl node
|
||||
EOF
|
||||
}
|
||||
|
||||
_version() {
|
||||
printf '%s\n' "${VERSION}"
|
||||
}
|
||||
|
||||
# function to parse color option
|
||||
_set_color() {
|
||||
local found=0;
|
||||
for opt in "${COLOR_OPTS[@]}"; do
|
||||
[ "${1}" == "${COLOR_PREFIX}-${opt}" ] && COLOR="${opt}" && found=1 && break
|
||||
done
|
||||
[ ${found} -eq 1 ] || >&2 echo "Error: wrong flag ${1}"
|
||||
}
|
||||
|
||||
# try to extract version by executing "${1}" with "${2}" arg
|
||||
# command name to be executed is dynamically passed to this function as ${1}
|
||||
# arg to ${1} is passed in ${2}
|
||||
__dynamic_detect(){
|
||||
cmd=$1
|
||||
params=$2
|
||||
version=$(eval ${cmd} ${params} "2>&1" | egrep -o "$REGEX_SIMPLE_VERSION" | head -1)
|
||||
cmd="${1}"
|
||||
params="${2}"
|
||||
version=$( eval "${cmd}" "${params}" "2>&1" | grep -Eo "${REGEX_SIMPLE_VERSION}" | head -1)
|
||||
status=$?
|
||||
}
|
||||
|
||||
# commands that use `--version` flag
|
||||
__dynamic_detect--version(){
|
||||
__dynamic_detect $1 "--version"
|
||||
__dynamic_detect "${1}" "--version"
|
||||
}
|
||||
|
||||
## commands that use `-version` flag
|
||||
# commands that use `-version` flag
|
||||
__dynamic_detect-version(){
|
||||
__dynamic_detect $1 "-version"
|
||||
__dynamic_detect "${1}" "-version"
|
||||
}
|
||||
|
||||
# commands that use `-v` flag
|
||||
__dynamic_detect-v(){
|
||||
__dynamic_detect $1 "-v"
|
||||
__dynamic_detect "${1}" "-v"
|
||||
}
|
||||
|
||||
# commands that use `-V` flag
|
||||
__dynamic_detect-V(){
|
||||
__dynamic_detect "${1}" "-V"
|
||||
}
|
||||
|
||||
# commands that use `version` argument
|
||||
__dynamic_detect-arg_version(){
|
||||
__dynamic_detect $1 "version"
|
||||
__dynamic_detect "${1}" "version"
|
||||
}
|
||||
|
||||
|
||||
## the main function
|
||||
__detect(){
|
||||
name=$1
|
||||
name="${1}"
|
||||
|
||||
# setup aliases maps commonly used name to exact command name
|
||||
# default values (for case when decoration applied)
|
||||
fail=${FAIL}
|
||||
pass=${PASS}
|
||||
wrapper_beg="${txtbold}${txtyellow}"
|
||||
wrapper_end="${txtreset}"
|
||||
|
||||
# setup aliases - maps commonly used name to exact command name
|
||||
case ${name} in
|
||||
golang) command="go" ;;
|
||||
jre) command="java" ;;
|
||||
jdk) command="javac" ;;
|
||||
nodejs) command="node" ;;
|
||||
goreplay) command="gor";;
|
||||
httpie) command="http";;
|
||||
*) command=${name} ;;
|
||||
rust ) command="rustc" ;;
|
||||
ssl ) command="openssl" ;;
|
||||
openssh ) command="ssh" ;;
|
||||
golang ) command="go" ;;
|
||||
jre ) command="java" ;;
|
||||
jdk ) command="javac" ;;
|
||||
nodejs ) command="node" ;;
|
||||
goreplay ) command="gor" ;;
|
||||
httpie ) command="http" ;;
|
||||
homebrew ) command="brew" ;;
|
||||
awsebcli ) command="eb" ;;
|
||||
awscli ) command="aws" ;;
|
||||
postgresql ) command="psql" ;;
|
||||
*coreutils|linux*utils) command="gnu_coreutils" ;;
|
||||
* ) command=${name} ;;
|
||||
esac
|
||||
|
||||
case ${command} in
|
||||
case "${command}" in
|
||||
|
||||
# commands that need --version flag
|
||||
bash|zsh) __dynamic_detect--version ${command} ;;
|
||||
git|hg|svn|bzr) __dynamic_detect--version ${command} ;;
|
||||
gcc|make) __dynamic_detect--version ${command} ;;
|
||||
curl|wget|http) __dynamic_detect--version ${command} ;;
|
||||
vim|emacs|nano|subl) __dynamic_detect--version ${command} ;;
|
||||
bats|tree|ack|autojump) __dynamic_detect--version ${command} ;;
|
||||
jq|ag|brew) __dynamic_detect--version ${command} ;;
|
||||
|
||||
node|npm|yarn) __dynamic_detect--version ${command} ;;
|
||||
ruby|gem|rake|bundle) __dynamic_detect--version ${command} ;;
|
||||
python|python3) __dynamic_detect--version ${command} ;;
|
||||
perl|php) __dynamic_detect--version ${command} ;;
|
||||
groovy|gradle|mvn) __dynamic_detect--version ${command} ;;
|
||||
## Shells
|
||||
bash|zsh|fish) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## VCS
|
||||
git|hg|svn|bzr) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## Http
|
||||
curl|wget|http) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## Editors
|
||||
vim|emacs|nano) __dynamic_detect--version "${command}" ;;
|
||||
subl|code|codium) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## File system search and navigation
|
||||
jq) __dynamic_detect--version "${command}" ;;
|
||||
ag|ack|rg) __dynamic_detect--version "${command}" ;;
|
||||
tree|autojump) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## OS Package managers
|
||||
apt|apt-get|aptitude) __dynamic_detect--version "${command}" ;;
|
||||
brew) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## System tools
|
||||
sed|awk|grep|file|sudo) __dynamic_detect--version "${command}" ;;
|
||||
gzip|xz|unar|bzip2) __dynamic_detect--version "${command}" ;;
|
||||
tar|pv) __dynamic_detect--version "${command}" ;;
|
||||
gunzip) __dynamic_detect--version "${command}" ;;
|
||||
tee) __dynamic_detect--version "${command}" ;;
|
||||
screen) __dynamic_detect-v "${command}" ;;
|
||||
|
||||
# Container runtimes
|
||||
docker|podman) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## Database CLI
|
||||
psql) __dynamic_detect--version "${command}" ;;
|
||||
sqlite3) __dynamic_detect-version "${command}" ;;
|
||||
|
||||
|
||||
########### Programming languages Build tools & Package managers ###########
|
||||
|
||||
|
||||
## Build and Compile
|
||||
gcc|make|cmake|bats) __dynamic_detect--version "${command}" ;;
|
||||
g++|clang|ccache) __dynamic_detect--version "${command}" ;;
|
||||
ninja) __dynamic_detect--version "${command}" ;;
|
||||
composer) __dynamic_detect-V "${command}" ;;
|
||||
pip|pip3|conda) __dynamic_detect-V "${command}" ;;
|
||||
lein|gradle|mvn) __dynamic_detect--version "${command}" ;;
|
||||
grunt|brunch) __dynamic_detect--version "${command}" ;;
|
||||
gem|rake|bundle) __dynamic_detect--version "${command}" ;;
|
||||
npm|yarn|pnpm) __dynamic_detect--version "${command}" ;;
|
||||
act) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## Scripting Language / runtime
|
||||
ruby|R|python|python3) __dynamic_detect--version "${command}" ;;
|
||||
perl|perl6|php|php5) __dynamic_detect--version "${command}" ;;
|
||||
groovy|node) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
# JVM tools that need -version flag
|
||||
ant) __dynamic_detect-version "${command}" ;;
|
||||
java|javac|scala|kotlin) __dynamic_detect-version "${command}" ;;
|
||||
|
||||
## Rust
|
||||
rustc|cargo) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## Cloud Tools
|
||||
aws|eb|sls|gcloud) __dynamic_detect--version "${command}" ;;
|
||||
heroku) __dynamic_detect--version "${command}" ;;
|
||||
netlify) __dynamic_detect--version "${command}" ;;
|
||||
netlifyctl) __dynamic_detect-arg_version "${command}" ;;
|
||||
|
||||
## GPG Tools
|
||||
gpg|gpgconf|gpg-agent) __dynamic_detect--version "${command}" ;;
|
||||
gpg-connect-agent) __dynamic_detect--version "${command}" ;;
|
||||
gpgsm) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## Hashicorp Tools
|
||||
terraform|packer) __dynamic_detect--version "${command}" ;;
|
||||
vagrant|consul) __dynamic_detect--version "${command}" ;;
|
||||
nomad) __dynamic_detect--version "${command}" ;;
|
||||
|
||||
## Browsers
|
||||
firefox) __dynamic_detect-v "${command}" ;;
|
||||
|
||||
# commands that need -v flag
|
||||
unzip) __dynamic_detect-v "${command}" ;;
|
||||
|
||||
# commands that need -V flag
|
||||
ab) __dynamic_detect-V "${command}" ;;
|
||||
|
||||
# commands that need -version flag
|
||||
ant|java|javac) __dynamic_detect-version ${command} ;;
|
||||
|
||||
# commands that need version arg
|
||||
hugo) __dynamic_detect-arg_version ${command} ;;
|
||||
go|hugo) __dynamic_detect-arg_version "${command}" ;;
|
||||
|
||||
## Example of commands that need custom processing
|
||||
## go needs version arg
|
||||
go)
|
||||
version=$(go version 2>&1| egrep -o "$REGEX_SIMPLE_VERSION" | head -1)
|
||||
status=$?
|
||||
;;
|
||||
|
||||
## ab uses -V flag
|
||||
ab)
|
||||
version=$(ab -V 2>&1 | egrep -o "$REGEX_SIMPLE_VERSION" | head -1)
|
||||
gulp)
|
||||
version=$( gulp --version 2>&1| grep -Eo "${REGEX_SIMPLE_VERSION}" | head -1)
|
||||
status=$?
|
||||
;;
|
||||
|
||||
## gor returns version but does not return normal status code, hence needs custom processing
|
||||
gor)
|
||||
version=$(gor version 2>&1 | egrep -o "$REGEX_SIMPLE_VERSION" | head -1)
|
||||
if [ $? -eq 1 ]; then status=0; else status=1; fi
|
||||
version=$( gor version 2>&1 | grep -Eo "${REGEX_SIMPLE_VERSION}" | head -1)
|
||||
if [ $? -eq 1 ]; then status=0; else status=127; fi
|
||||
;;
|
||||
|
||||
sbt)
|
||||
version=$( sbt about 2>&1 | grep -Eo "([[:digit:]]{1,4}\.){2}[[:digit:]]{1,4}" | head -1)
|
||||
status=$?
|
||||
;;
|
||||
|
||||
# openssl can have a letter at the end of the version number (eg. "1.1.1j")
|
||||
openssl)
|
||||
version=$( openssl version 2>&1 | grep -Eo "${REGEX_SIMPLE_VERSION}[[:alnum:]]*" |head -1)
|
||||
status=$?
|
||||
;;
|
||||
|
||||
# openssh version output has a lot going on
|
||||
ssh)
|
||||
version=$(ssh -V 2>&1 |grep -Eo "OpenSSH_${REGEX_SIMPLE_VERSION}[[:alnum:]]*" |cut -d'_' -f2)
|
||||
status=$?
|
||||
;;
|
||||
|
||||
## use 'readlink' to test for GNU coreutils
|
||||
# readlink (GNU coreutils) 8.28
|
||||
gnu_coreutils) __dynamic_detect--version readlink ;;
|
||||
|
||||
## hub uses --version but version string is on second line, or third if HUB_VERBOSE set
|
||||
hub)
|
||||
version=$( HUB_VERBOSE='' hub --version 2>&1 | sed -n 2p | grep -Eo "${REGEX_SIMPLE_VERSION}" | head -1)
|
||||
status=$?
|
||||
;;
|
||||
|
||||
## zip uses -v but version string is on second line
|
||||
zip)
|
||||
version=$( zip -v 2>&1 | sed -n 2p | grep -Eo "${REGEX_SIMPLE_VERSION}" | head -1)
|
||||
status=$?
|
||||
;;
|
||||
|
||||
has)
|
||||
version=$( has -v 2>&1 | grep -Eo "${REGEX_SIMPLE_VERSION}" | head -1)
|
||||
status=$?
|
||||
;;
|
||||
|
||||
*)
|
||||
## Can allow dynamic checking here, i.e. checking commands that are not listed above
|
||||
if [[ "${HAS_ALLOW_UNSAFE}" == "y" ]]; then
|
||||
__dynamic_detect--version ${command}
|
||||
__dynamic_detect--version "${command}"
|
||||
## fallback checking based on status!=127 (127 means command not found)
|
||||
## TODO can check other type of supported version-checks if status was not 127
|
||||
else
|
||||
|
@ -114,49 +311,114 @@ __detect(){
|
|||
;;
|
||||
esac
|
||||
|
||||
|
||||
if [ "$status" -eq "-1" ]; then ## When unsafe processing is not allowed, the -1 signifies
|
||||
|
||||
echo ${FAIL} ${command} "not understood"
|
||||
KO=$(($KO+1))
|
||||
|
||||
elif [ ${status} -eq 127 ]; then ## command not installed
|
||||
|
||||
echo ${FAIL} ${command}
|
||||
KO=$(($KO+1))
|
||||
|
||||
elif [ ${status} -eq 0 ]; then ## successfully executed
|
||||
|
||||
echo ${PASS} ${command} ${version}
|
||||
OK=$(($OK+1))
|
||||
|
||||
else ## as long as its not 127, command is there, but we might not have been able to extract version
|
||||
|
||||
echo ${PASS} ${command}
|
||||
OK=$(($OK+1))
|
||||
if [ "${COLOR}" == "${COLOR_NEVER}" ] || [[ ! -t 1 && "${COLOR}" == "${COLOR_AUTO}" ]]; then
|
||||
pass=${checkmark}
|
||||
fail=${fancyx}
|
||||
wrapper_beg=""
|
||||
wrapper_end=""
|
||||
fi
|
||||
|
||||
}
|
||||
if [ "$status" -eq "-1" ]; then ## When unsafe processing is not allowed, the -1 signifies
|
||||
printf '%b %s not understood\n' "${fail}" "${command}" > "$OUTPUT"
|
||||
KO=$(( KO+1 ))
|
||||
|
||||
elif [ ${status} -eq 127 ]; then ## command not installed
|
||||
printf '%b %s\n' "${fail}" "${command}" > "$OUTPUT"
|
||||
KO=$(( KO+1 ))
|
||||
|
||||
# if no arguments passed to script
|
||||
if [ "$#" -eq 0 ]; then
|
||||
# print help
|
||||
BINARY_NAME="has"
|
||||
VERSION="v1.1.0"
|
||||
echo "${BINARY_NAME} ${VERSION}"
|
||||
echo "USAGE: ${BINARY_NAME} <command-names>.."
|
||||
echo "EXAMPLE: ${BINARY_NAME} git curl node"
|
||||
elif [ ${status} -eq 0 ] || [ ${status} -eq 141 ]; then ## successfully executed
|
||||
printf "%b %s %b\n" "${pass}" "${command}" "${wrapper_beg}${version}${wrapper_end}" > "$OUTPUT"
|
||||
OK=$(( OK+1 ))
|
||||
|
||||
else
|
||||
else ## as long as its not 127, command is there, but we might not have been able to extract version
|
||||
printf '%b %s\n' "${pass}" "${command}" > "$OUTPUT"
|
||||
OK=$(( OK+1 ))
|
||||
fi
|
||||
} #end __detect
|
||||
|
||||
# for each arg
|
||||
for cmd in "$@"; do
|
||||
__detect $cmd
|
||||
done
|
||||
OPTIND=1
|
||||
OUTPUT=/dev/stdout
|
||||
|
||||
# echo ${OK} / $(($OK+$KO))
|
||||
exit ${KO}
|
||||
while getopts ":qhv-" OPTION; do
|
||||
case "$OPTION" in
|
||||
q)
|
||||
OUTPUT=/dev/null
|
||||
;;
|
||||
h)
|
||||
_usage
|
||||
exit 0
|
||||
;;
|
||||
v)
|
||||
_version
|
||||
exit 0
|
||||
;;
|
||||
-)
|
||||
[ $OPTIND -ge 1 ] && optind=$((OPTIND - 1)) || optind=$OPTIND
|
||||
eval OPTION="\$$optind"
|
||||
OPTARG=$(echo "$OPTION" | cut -d'=' -f2)
|
||||
OPTION=$(echo "$OPTION" | cut -d'=' -f1)
|
||||
case $OPTION in
|
||||
--version)
|
||||
_version
|
||||
exit 0
|
||||
;;
|
||||
--help)
|
||||
_usage
|
||||
exit 0
|
||||
;;
|
||||
${COLOR_PREFIX}*)
|
||||
_set_color "${OPTION}"
|
||||
;;
|
||||
*)
|
||||
printf '%s: unrecognized option '%s'\n' "${BINARY_NAME}" "${OPTARG}"
|
||||
_usage
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
OPTIND=1
|
||||
shift
|
||||
;;
|
||||
?)
|
||||
printf '%s: unrecognized option '%s'\n' "${BINARY_NAME}" "${OPTARG}"
|
||||
_usage
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
if [ -s "${RC_FILE}" ]; then
|
||||
HASRC="true"
|
||||
fi
|
||||
|
||||
# if HASRC is not set AND no arguments passed to script
|
||||
if [[ -z "${HASRC}" ]] && [ "$#" -eq 0 ]; then
|
||||
_usage
|
||||
else
|
||||
# for each cli-arg
|
||||
for cmd in "$@"; do
|
||||
__detect "${cmd}"
|
||||
done
|
||||
|
||||
## display found / total
|
||||
# echo ${OK} / $(($OK+$KO))
|
||||
|
||||
## if HASRC has been set
|
||||
if [[ -n "${HASRC}" ]]; then
|
||||
## for all
|
||||
while read -r line; do
|
||||
__detect "${line}"
|
||||
done <<<"$( grep -Ev "^\s*(#|$)" "${RC_FILE}" )"
|
||||
fi
|
||||
|
||||
## max status code that can be returned
|
||||
MAX_STATUS_CODE=126
|
||||
|
||||
if [[ "${KO}" -gt "${MAX_STATUS_CODE}" ]]; then
|
||||
exit "${MAX_STATUS_CODE}"
|
||||
else
|
||||
exit "${KO}"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# has containers
|
||||
|
||||
Custom containers used for testing https://github.com/kdabir/has
|
||||
|
||||
| container image | status |
|
||||
|------------------------------|--------|
|
||||
| kdabir/has-test-containers:alpine | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/kdabir/has-test-containers/alpine) |
|
||||
| kdabir/has-test-containers:ubuntu | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/kdabir/has-test-containers/ubuntu) |
|
||||
| kdabir/has-test-containers:debian | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/kdabir/has-test-containers/debian) |
|
||||
| kdabir/has-test-containers:ubuntu16 | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/kdabir/has-test-containers/ubuntu16) |
|
|
@ -0,0 +1,142 @@
|
|||
FROM bash:5.0.16
|
||||
|
||||
# already contains
|
||||
# awk
|
||||
# bash=5.0.16
|
||||
# bzip2
|
||||
# grep
|
||||
# gzip=1.31.1
|
||||
# sed=4.0
|
||||
# tar=1.31.1
|
||||
# unzip=6.00
|
||||
# wget
|
||||
# xz
|
||||
RUN apk add --no-cache \
|
||||
ack~=3.2.0 \
|
||||
apache2-utils~=2.4 `# ab=2.3` \
|
||||
apache-ant~=1.10.8 `# ant=1.10.8` \
|
||||
build-base libffi-dev openssl-dev `# required for eb` \
|
||||
curl~=7.67.0 \
|
||||
bzr~=2.7.0 \
|
||||
docker~=19.03.5 \
|
||||
emacs~=26.3 \
|
||||
file~=5.37 \
|
||||
gcc~=9.2.0 \
|
||||
git~=2.24.3 \
|
||||
go~=1.13.10 \
|
||||
gradle~=5.6.4 \
|
||||
hugo~=0.61.0 \
|
||||
jq=~1.6 \
|
||||
make~=4.2.1 \
|
||||
maven~=3.6.3 `# mvn=3.6.3` \
|
||||
mercurial~=5.3.2 `# hg=5.3.2` \
|
||||
nano~=4.6 \
|
||||
ncurses~=6.1_p20200118 `#tput:todo` \
|
||||
npm~=12.15.0 `# npm=6.13.4 # node=12.15.0` \
|
||||
openjdk11~=11.0.5 `# java=11.0.5` \
|
||||
perl~=5.30 ` # perl=30` \
|
||||
php7~=7.3.18 `# php=7.3.18 ` \
|
||||
postgresql~=12.2 `# psql=12.2` \
|
||||
pv~=1.6.6 \
|
||||
python~=2.7.18 \
|
||||
python3-dev~=3.8.2 `#python3=3.8.2` \
|
||||
R~=3.6.2 \
|
||||
ruby~=2.6.6 `# gem=3.0.3` \
|
||||
ruby-bundler~=2.0.2 `# bundle=2.0.2` \
|
||||
ruby-bigdecimal ruby-json `# required for brew` \
|
||||
ruby-rake~=2.6.6 `# rake=12.3.3` \
|
||||
subversion~=1.12.2 `# svn=1.12.2` \
|
||||
sudo~=1.8.31 \
|
||||
tree~=1.8.0 \
|
||||
vim~=8.2 \
|
||||
yarn~=1.19.2 \
|
||||
zip~=3.0 \
|
||||
zsh~=5.7.1 && \
|
||||
\
|
||||
# required for brew and lein
|
||||
ln -s $(which bash) /bin/bash && \
|
||||
\
|
||||
npm install --global --no-optional \
|
||||
brunch@"=3.0.0" \
|
||||
grunt-cli@"=1.3.2" \
|
||||
gulp-cli@"=2.2.0" \
|
||||
heroku@"=7.39.3" \
|
||||
netlify-cli@"=2.33.0" \
|
||||
serverless@"=1.67.3" `# sls=1.67.3` && \
|
||||
\
|
||||
autojump=22.5.3 && \
|
||||
curl -L "https://github.com/wting/autojump/archive/release-v${autojump}.tar.gz" | tar xz && \
|
||||
cd "autojump-release-v${autojump}" && \
|
||||
SHELL=bash ./install.py && \
|
||||
cd / && \
|
||||
ln -s ~/.autojump/bin/autojump /usr/local/bin/autojump && \
|
||||
\
|
||||
commit="87b16eb" `# bats=1.2.0` && \
|
||||
curl -L "https://github.com/bats-core/bats-core/tarball/${commit}" | tar xz && \
|
||||
"bats-core-bats-core-${commit}/install.sh" /usr/local && \
|
||||
\
|
||||
brew=2.2.13 && \
|
||||
git clone --depth=1 --branch ${brew} https://github.com/Homebrew/brew && \
|
||||
eval $(brew/bin/brew shellenv) && \
|
||||
ln -s /brew/bin/brew /usr/local/bin/brew && \
|
||||
brew --version && \
|
||||
\
|
||||
eb=3.18.0-1 && \
|
||||
curl -L "https://github.com/sdolenc/aws-elastic-beanstalk-cli/archive/${eb}.tar.gz" | tar xz && \
|
||||
pip3 install ./aws-elastic-beanstalk-cli-${eb} && \
|
||||
\
|
||||
gcloud=289.0.0 && \
|
||||
curl -L "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${gcloud}-linux-x86_64.tar.gz" | tar xz && \
|
||||
ln -s /google-cloud-sdk/bin/gcloud /usr/local/bin/gcloud && \
|
||||
\
|
||||
gor=1.0.0 && \
|
||||
curl -L "https://github.com/buger/goreplay/releases/download/v${gor}/gor_${gor}_x64.tar.gz" | tar xz --directory /usr/local/bin && \
|
||||
\
|
||||
groovy=3.0.3 && \
|
||||
curl -L "https://dl.bintray.com/groovy/maven/apache-groovy-binary-${groovy}.zip" -o /groovy.zip && \
|
||||
unzip groovy.zip && rm groovy.zip && \
|
||||
ln -s "/groovy-3.0.3/bin/groovy" /usr/local/bin/groovy && \
|
||||
\
|
||||
pip3 install \
|
||||
awscli==1.18.43 `# aws=1.18.43` \
|
||||
httpie==2.1.0 `# http=2.1.0` && \
|
||||
\
|
||||
hub=2.14.2 && \
|
||||
curl -L "https://github.com/github/hub/releases/download/v${hub}/hub-linux-386-${hub}.tgz" | tar xz && \
|
||||
ln -s "/hub-linux-386-${hub}/bin/hub" /usr/local/bin/hub && \
|
||||
\
|
||||
`# javac=11.0.5` && \
|
||||
ln -s "/usr/lib/jvm/java-11-openjdk/bin/javac" /usr/local/bin/javac && \
|
||||
\
|
||||
kotlin=1.3.72 && \
|
||||
curl -L "https://github.com/JetBrains/kotlin/releases/download/v${kotlin}/kotlin-compiler-${kotlin}.zip" -o /kotlin.zip && \
|
||||
unzip kotlin.zip && rm kotlin.zip && \
|
||||
ln -s /kotlinc/bin/kotlin /usr/local/bin/kotlin && \
|
||||
ln -s /kotlinc/bin/kotlinc /usr/local/bin/kotlinc && \
|
||||
\
|
||||
netlifyctl=0.4.0 && \
|
||||
curl -L "https://github.com/netlify/netlifyctl/releases/download/v${netlifyctl}/netlifyctl-linux-amd64-${netlifyctl}.tar.gz" | tar xz --directory /usr/local/bin && \
|
||||
\
|
||||
perl6=2020.02.1-04 && \
|
||||
curl -L "https://github.com/nxadm/rakudo-pkg/releases/download/v${perl6}/rakudo-pkg-Alpine3.11_${perl6}_x86_64.apk" --output perl6.apk && \
|
||||
apk add --allow-untrusted perl6.apk && rm perl6.apk && \
|
||||
ln -s /opt/rakudo-pkg/bin/perl6 /usr/local/bin/perl6 && \
|
||||
\
|
||||
rg=12.0.1 && \
|
||||
curl -L "https://github.com/BurntSushi/ripgrep/releases/download/${rg}/ripgrep-${rg}-x86_64-unknown-linux-musl.tar.gz" | tar xz && \
|
||||
ln -s "/ripgrep-${rg}-x86_64-unknown-linux-musl/rg" /usr/local/bin/rg && \
|
||||
\
|
||||
sbt=1.3.4 && \
|
||||
curl -L "https://piccolo.link/sbt-${sbt}.tgz" | tar xz && \
|
||||
ln -s /sbt/bin/sbt /usr/local/bin/sbt && \
|
||||
sbt --version && sbt --version && \
|
||||
\
|
||||
scala=2.12.11 && \
|
||||
curl -L "https://downloads.lightbend.com/scala/${scala}/scala-${scala}.tgz" | tar xz && \
|
||||
ln -s "/scala-${scala}/bin/scala" /usr/local/bin/scala && \
|
||||
\
|
||||
echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||
echo "http://dl-cdn.alpinelinux.org/alpine/v3.12/community" >> /etc/apk/repositories `# podman requires crun` && \
|
||||
apk add --no-cache \
|
||||
leiningen~=2.9.3 `# lein=2.9.3` \
|
||||
podman~=1.9.3
|
|
@ -0,0 +1,32 @@
|
|||
FROM debian:buster-20200327-slim
|
||||
|
||||
# already contains
|
||||
# apt
|
||||
# apt-get
|
||||
# bash
|
||||
# grep
|
||||
# gzip
|
||||
# tar
|
||||
RUN apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y -qq \
|
||||
bc \
|
||||
pv \
|
||||
unar \
|
||||
make \
|
||||
curl \
|
||||
git \
|
||||
unzip \
|
||||
xz-utils `#xz` \
|
||||
unar \
|
||||
pv \
|
||||
zip \
|
||||
sudo \
|
||||
file \
|
||||
&& apt-get -y autoremove && apt-get -y clean && rm -rf /var/lib/apt/lists/*; \
|
||||
\
|
||||
#bats
|
||||
commit="87b16eb"; \
|
||||
curl -L "https://github.com/bats-core/bats-core/tarball/${commit}" | tar xz; \
|
||||
"bats-core-bats-core-${commit}/install.sh" /usr/local; \
|
||||
\
|
||||
#hub
|
||||
curl -fsSL https://github.com/github/hub/raw/master/script/get | bash -s 2.14.2
|
|
@ -0,0 +1,147 @@
|
|||
FROM ubuntu:bionic-20200311
|
||||
|
||||
# Updates path with node, npm, npx, and globally installed npm packages
|
||||
ENV node=12.18.1
|
||||
ENV PATH="${PATH}:/node-v${node}-linux-x64/bin"
|
||||
|
||||
# already contains
|
||||
# apt=1.6.12
|
||||
# apt-get=1.6.12
|
||||
# awk
|
||||
# bash=4.4.20
|
||||
# bzip2=1.0.6
|
||||
# gnu_coreutils=8.28
|
||||
# grep=3.1
|
||||
# gzip=1.6
|
||||
# perl=26
|
||||
# sed=4.4
|
||||
# tar=1.29
|
||||
# tput #todo
|
||||
RUN apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y -qq \
|
||||
ack=2.22* \
|
||||
ant=1.10.5* \
|
||||
apache2-utils=2.4* `# ab=2.3` \
|
||||
apt-utils `# todo` \
|
||||
aptitude=0.8.10* \
|
||||
autojump=22.5.0* \
|
||||
awscli=1.14.44* `# aws=1.14.44` \
|
||||
build-essential zlib1g-dev libssl-dev libncurses-dev libffi-dev libsqlite3-dev libreadline-dev libbz2-dev `# required for eb` \
|
||||
bzr=2.7.0+bzr6622-10 `# bzr=2.8.0` \
|
||||
curl=7.58.0* \
|
||||
docker.io=19.03.6* `# docker=19.03.6` \
|
||||
emacs=47.0 `# emacs=25.2.2` \
|
||||
file=1:5.32* \
|
||||
gcc=4:7.4.0-1ubuntu2.3 `# gcc=7.5.0` \
|
||||
git=1:2.17.1* \
|
||||
gpg-agent `# todo:apt-key` \
|
||||
gradle=4.4.1* \
|
||||
groovy=2.4.16* \
|
||||
httpie=0.9.8* `# http=0.9.8` \
|
||||
hugo=0.40.1* \
|
||||
jq=1.5* \
|
||||
leiningen=2.8.1* `# lein=2.8.1` \
|
||||
locales `# required for brew` \
|
||||
make=4.1* \
|
||||
maven=3.6.0* `# mvn=3.6.0` \
|
||||
mercurial=4.5.3* `# hg=4.5.3` \
|
||||
nano=2.9.3* \
|
||||
openjdk-11-jdk-headless=11.0.7* `# java=11.0.7 # javac=11.0.7` \
|
||||
perl6=6.c-1 `# perl6=2018.03` \
|
||||
php=1:7.2+60ubuntu1 `# php=7.2.24` \
|
||||
postgresql-client=10+190* `# psql=10.12` \
|
||||
pv=1.6.6* \
|
||||
python=2.7.15~rc1-1 `# python=2.7.17` \
|
||||
python3=3.6.7-1~18.04 `# python3=3.6.9` \
|
||||
r-cran-littler=0.3.3* `# R=3.4.4` \
|
||||
rake=12.3.1* \
|
||||
ruby=1:2.5.1 \
|
||||
ruby-bundler=1.16.1* `# bundle=1.16.1` \
|
||||
rubygems `# gem=2.7.6` \
|
||||
scala=2.11.12* \
|
||||
silversearcher-ag=2.1.0* `# ag=2.1.0` \
|
||||
software-properties-common `# todo:add-apt-repository` \
|
||||
subversion=1.9.7* `# svn=1.9.7` \
|
||||
sudo=1.8.21* \
|
||||
tree=1.7.0* \
|
||||
unar=1.10.1* \
|
||||
unzip=6.0-21ubuntu1 `# unzip=6.00` \
|
||||
vim=2:8.0* \
|
||||
wget=1.19.4* \
|
||||
xz-utils=5.2.2* `# xz=5.2.2` \
|
||||
yarn `# yarn=0.32` \
|
||||
zip=3.0* \
|
||||
zsh=5.4.2* && \
|
||||
\
|
||||
commit="87b16eb" `# bats=1.2.0` && \
|
||||
curl -L "https://github.com/bats-core/bats-core/tarball/${commit}" | tar xz && \
|
||||
"bats-core-bats-core-${commit}/install.sh" /usr/local && \
|
||||
\
|
||||
brew=2.2.13 && \
|
||||
git clone --depth=1 --branch ${brew} https://github.com/Homebrew/brew && \
|
||||
locale-gen en_US en_US.UTF-8 && \
|
||||
eval $(brew/bin/brew shellenv) && \
|
||||
ln -s /brew/bin/brew /usr/local/bin/brew && \
|
||||
brew --version && \
|
||||
\
|
||||
code=1.44.2 && \
|
||||
curl -L "https://az764295.vo.msecnd.net/stable/ff915844119ce9485abfe8aa9076ec76b5300ddd/code_${code}-1587059832_amd64.deb" --output code_${code}.deb && \
|
||||
`# installing missing dependencies requires apt update which is the first done above` \
|
||||
dpkg -i code_${code}.deb || apt-get install -f -y && \
|
||||
rm -f code_${code}.deb && \
|
||||
\
|
||||
commit="102025c" `# eb=3.18.1` && \
|
||||
curl -L "https://github.com/aws/aws-elastic-beanstalk-cli-setup/tarball/${commit}" | tar xz && \
|
||||
"aws-aws-elastic-beanstalk-cli-setup-${commit}/scripts/bundled_installer" && \
|
||||
ln -s /root/.ebcli-virtual-env/executables/eb /usr/local/bin/eb && \
|
||||
\
|
||||
gcloud=289.0.0 && \
|
||||
curl -L "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${gcloud}-linux-x86_64.tar.gz" | tar xz && \
|
||||
ln -s /google-cloud-sdk/bin/gcloud /usr/local/bin/gcloud && \
|
||||
\
|
||||
gor=1.0.0 && \
|
||||
curl -L "https://github.com/buger/goreplay/releases/download/v${gor}/gor_${gor}_x64.tar.gz" | tar xz --directory /usr/local/bin && \
|
||||
\
|
||||
hub=2.14.2 && \
|
||||
curl -fsSL "https://github.com/github/hub/raw/master/script/get" | bash -s ${hub} && \
|
||||
\
|
||||
kotlin=1.3.72 && \
|
||||
curl -L "https://github.com/JetBrains/kotlin/releases/download/v${kotlin}/kotlin-compiler-${kotlin}.zip" -o /kotlin.zip && \
|
||||
unzip kotlin.zip && rm kotlin.zip && \
|
||||
ln -s /kotlinc/bin/kotlin /usr/local/bin/kotlin && \
|
||||
ln -s /kotlinc/bin/kotlinc /usr/local/bin/kotlinc && \
|
||||
\
|
||||
netlifyctl=0.4.0 && \
|
||||
curl -L "https://github.com/netlify/netlifyctl/releases/download/v${netlifyctl}/netlifyctl-linux-amd64-${netlifyctl}.tar.gz" | tar xz --directory /usr/local/bin && \
|
||||
\
|
||||
rg=12.0.1 && \
|
||||
curl -L "https://github.com/BurntSushi/ripgrep/releases/download/${rg}/ripgrep-${rg}-x86_64-unknown-linux-musl.tar.gz" | tar xz && \
|
||||
ln -s "/ripgrep-${rg}-x86_64-unknown-linux-musl/rg" /usr/local/bin/rg && \
|
||||
\
|
||||
sbt=1.3.4 && \
|
||||
curl -L "https://piccolo.link/sbt-${sbt}.tgz" | tar xz && \
|
||||
ln -s /sbt/bin/sbt /usr/local/bin/sbt && \
|
||||
sbt --version && sbt --version && \
|
||||
\
|
||||
add-apt-repository -y ppa:longsleep/golang-backports `#go` && \
|
||||
add-apt-repository -y ppa:ondrej/php `#php5` && \
|
||||
add-apt-repository -y ppa:projectatomic/ppa `#podman` && \
|
||||
wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add - `#subl` && \
|
||||
add-apt-repository -y "deb https://download.sublimetext.com/ apt/stable/" `#subl` && \
|
||||
apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y -qq \
|
||||
golang-go=2:1.14* `# go=1.14.2` \
|
||||
php5.6=5.6.40* `# php5=5.6.40` \
|
||||
podman=1.6.2* \
|
||||
sublime-text=3211 `# subl=3211` && \
|
||||
ln -s /usr/bin/php5.6 /usr/bin/php5 && \
|
||||
\
|
||||
curl -L "https://nodejs.org/dist/v${node}/node-v${node}-linux-x64.tar.gz" | tar xz && \
|
||||
\
|
||||
npm install --global --no-optional `# npm=6.14.5` \
|
||||
brunch@"=3.0.0" \
|
||||
grunt-cli@"=1.3.2" \
|
||||
gulp-cli@"=2.2.0" \
|
||||
heroku@"=7.39.3" \
|
||||
netlify-cli@"=2.33.0" \
|
||||
serverless@"=1.67.3" `# sls=1.67.3` && \
|
||||
\
|
||||
apt-get -y autoremove && apt-get -y clean && rm -rf /var/lib/apt/lists/*
|
|
@ -0,0 +1,32 @@
|
|||
FROM ubuntu:xenial-20200212
|
||||
|
||||
# already contains
|
||||
# apt
|
||||
# apt-get
|
||||
# bash
|
||||
# grep
|
||||
# gzip
|
||||
# tar
|
||||
RUN apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y -qq \
|
||||
bc \
|
||||
pv \
|
||||
unar \
|
||||
make \
|
||||
curl \
|
||||
git \
|
||||
unzip \
|
||||
xz-utils `#xz` \
|
||||
unar \
|
||||
pv \
|
||||
zip \
|
||||
sudo \
|
||||
file \
|
||||
&& apt-get -y autoremove && apt-get -y clean && rm -rf /var/lib/apt/lists/*; \
|
||||
\
|
||||
#bats
|
||||
commit="87b16eb"; \
|
||||
curl -L "https://github.com/bats-core/bats-core/tarball/${commit}" | tar xz; \
|
||||
"bats-core-bats-core-${commit}/install.sh" /usr/local; \
|
||||
\
|
||||
#hub
|
||||
curl -fsSL https://github.com/github/hub/raw/master/script/get | bash -s 2.14.2
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
## This script outputs all of the packages that has explicitly supports.
|
||||
set -euo pipefail
|
||||
|
||||
pushd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null
|
||||
|
||||
grep -o "^ \\+[a-zA-Z0-9_|-]\\+)" ../has | grep -o "[a-zA-Z0-9_|-]\\+" | tr "|" "\\n" | sort -f
|
||||
|
||||
popd >/dev/null
|
|
@ -0,0 +1,55 @@
|
|||
# Not pre-installed to container, but repository cloned during CI
|
||||
has
|
||||
|
||||
# non-alpine packages
|
||||
apt
|
||||
apt-get
|
||||
aptitude
|
||||
code
|
||||
subl
|
||||
|
||||
# gnu_coreutils shows as installed, but is not on alpine.
|
||||
# todo: We should change the command we use for this to
|
||||
# something busybox doesn't also implement. Examples:
|
||||
# chcon, csplit, dir, dircolors, fmt, join, logname, pathchk,
|
||||
# pinky, pr, ptx, runcon, stdbuf, tsort, users, vdir, who
|
||||
# Then we can move this to the "non-alpine packages" list above.
|
||||
gnu_coreutils
|
||||
|
||||
# installed on container (and has confirms), but
|
||||
# todo: has shows EMPTY version string on container
|
||||
awk
|
||||
bzip2
|
||||
grep
|
||||
gzip
|
||||
wget
|
||||
xz
|
||||
|
||||
# installed on container (and has confirms), but
|
||||
# todo: has grabs INCORRECT version string on container
|
||||
jq
|
||||
perl
|
||||
|
||||
# installed on container, but
|
||||
# todo: has reports command not found
|
||||
gor
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# tools below have not be added to the alpine test container image.
|
||||
# todo: we may need to compile executable binaries that run on alpine 3.11
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# todo: compile binary with help from:
|
||||
# https://github.com/ggreer/the_silver_searcher
|
||||
# https://github.com/Ketouem/ag-alpine
|
||||
ag
|
||||
|
||||
# apk available for alpine 3.8
|
||||
# todo: compile binary with help from:
|
||||
# https://github.com/sgerrand/alpine-pkg-php5
|
||||
php5
|
||||
|
||||
# todo: compile binary with help from:
|
||||
# https://theunarchiver.com/command-line
|
||||
# https://github.com/ashang/unar
|
||||
unar
|
|
@ -0,0 +1,16 @@
|
|||
# Not pre-installed to container, but repository cloned during CI
|
||||
has
|
||||
|
||||
# Tests are run as admin in CI. Code requires an extra parameter to get version as admin.
|
||||
# todo: add --user-data-dir=/tmp for code when has is run as admin
|
||||
code
|
||||
|
||||
# installed on container (and has confirms), but
|
||||
# todo: has shows EMPTY version string on container
|
||||
awk
|
||||
groovy
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# tools below have not be added to the ubuntu test container image.
|
||||
# --------------------------------------------------------------------------
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
cd $BATS_TEST_DIRNAME
|
||||
|
||||
distro="alpine"
|
||||
if grep -iq "ubuntu" /etc/issue; then
|
||||
distro="ubuntu"
|
||||
fi
|
||||
SKIP_FILE=packages_${distro}_skip.txt
|
||||
DOCKER_FILE=./containers/${distro}.Dockerfile
|
||||
|
||||
expected_version() {
|
||||
grep -Eo "( |#)${1}(|-cli)(|@\"|~)=[^\`\"; *-]+" $DOCKER_FILE | tr "=" "\n" | tr ":" "\n" | tail -1
|
||||
}
|
||||
|
||||
@test "test each package individually and verify version" {
|
||||
packages_count=0
|
||||
final_status=0
|
||||
for package in $(bash packages_all.sh); do
|
||||
if [ -n $package ] && ! grep -q "^$package$" $SKIP_FILE; then
|
||||
run expected_version $package
|
||||
[ "$status" -eq 0 ]
|
||||
[ -n "$output" ]
|
||||
|
||||
package="$package" expected_ver="$output" run bats -t test_package.bats
|
||||
echo "# $output" >&3
|
||||
echo "#" >&3
|
||||
packages_count=$(($packages_count + 1))
|
||||
final_status=$(($final_status + $status))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "# tested ${packages_count} commands individually" >&3
|
||||
echo "#" >&3
|
||||
|
||||
echo "# status code=$final_status" >&3
|
||||
[ "$final_status" -eq 0 ]
|
||||
echo "#" >&3
|
||||
}
|
||||
|
||||
@test "test all packages at once" {
|
||||
# subtract skips from full list
|
||||
packages_to_skip="$(grep -Ev "^\s*(#|$)" $SKIP_FILE | xargs | tr " " "|")"
|
||||
packages=$(bash packages_all.sh | egrep -Ev "^($packages_to_skip)$" | xargs)
|
||||
|
||||
run ../has $packages
|
||||
echo "$output" >&3
|
||||
echo "#" >&3
|
||||
|
||||
packages_count=$(echo "${packages}" | wc -w)
|
||||
echo "# tested ${packages_count} commands simultaneously" >&3
|
||||
actual_packages_count=$(echo "${output}" | wc -l)
|
||||
echo "# received output from ${actual_packages_count} commands" >&3
|
||||
[ "$packages_count" -eq "$actual_packages_count" ]
|
||||
echo "#" >&3
|
||||
|
||||
echo "# status code=$status" >&3
|
||||
[ "$status" -eq 0 ]
|
||||
echo "#" >&3
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
cd $BATS_TEST_DIRNAME
|
||||
|
||||
get_version_from_has() {
|
||||
echo "$1" | tr " " "\n" | tail -1
|
||||
}
|
||||
|
||||
@test "test $package" {
|
||||
# Ensure inputs
|
||||
[ "$(echo "${package}" | wc -w)" -eq 1 ]
|
||||
[ "$(echo "${expected_ver}" | wc -w)" -eq 1 ]
|
||||
|
||||
# Confirm package is installed
|
||||
run ../has $package
|
||||
echo "$output" >&3
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Get actual version (reported from has)
|
||||
actual_ver=""
|
||||
run get_version_from_has "$output"
|
||||
if [ "$status" -eq 0 ]; then
|
||||
actual_ver="$output"
|
||||
[ "$(echo "${actual_ver}" | wc -w)" -eq 1 ]
|
||||
fi
|
||||
|
||||
# Compare expected with actual
|
||||
# We grep instead of direct compare because has adds ansi colors with tput
|
||||
[ "$(echo "${actual_ver}" | grep "$expected_ver")" ]
|
||||
}
|
Loading…
Reference in New Issue