Freshen Makefile and update README.md (#31)

Details:

* Freshen Makefile and update README.md

- [x] Add `sudo` to revelvant commands
- [x] Use named languages (bash) in fenced codeblocks
- [x] Use `console` in fenced codeblocks for command output

- [x] Use `install` with permission mode

The permissions on `has` were 777 from `git clone`.

- [x] Add option to use $PREFIX

What if I don't want to install to /usr/local/bin?

`make PREFIX=$HOME/.local install` now works.

- [x] Add `update` target for `git pull`
- [x] Include .PHONY targets

* Freshen Makefile and update README.md

- [x] Add `sudo` to revelvant commands
- [x] Use named languages (bash) in fenced codeblocks
- [x] Use `console` in fenced codeblocks for command output

- [x] Use `install` with permissions set

The permissions on `has` were 777 from `git clone`.

- [x] Add option to use $PREFIX

What if I don't want to install to /usr/local/bin?

`make PREFIX=$HOME/.local install` now works.

- [x] Add `update` target for `git pull`
- [x] Include .PHONY targets

- [x] Add tests for Makefile changes
- [x] Uses `bats` variables for directories

- ✓ make install creates a valid installation
- ✓ ..even if has is missing from directory
- ✓ make update runs git pull

* Update .hastest.bats

temp remove "git pull" check.

* Update travis to use bats-core 1.10

Do not be concerned about dirty working tree when running make update.

* Change version output to non-blinking.

* Update travis to use bats-core 1.10

Do not be concerned about dirty working tree when running make update.

* Working makefile

* Use `[[` and `@` for the $lines match.

* `make install` MacOS friendly again
This commit is contained in:
Virgil 2019-04-04 20:39:17 +10:00 committed by Kunal Dabir
parent 3b26771c8a
commit 36e11e238f
5 changed files with 168 additions and 84 deletions

View File

@ -1,19 +1,64 @@
#!/usr/bin/env bats
INSTALL_DIR=
BATS_TMPDIR=${BATS_TMPDIR:-/tmp}
## We need to create a new directory to that .hasrc file in the root does not get read by the `has` instance under test
## 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() {
mkdir -p ./tmp-for-test
cp -f has ./tmp-for-test/
cd tmp-for-test
export BATS_TEST_TMPDIR="$BATS_TMPDIR/tmp-for-test"
mkdir -p "$BATS_TEST_TMPDIR"
cp -f has "$BATS_TEST_TMPDIR"
cd "$BATS_TEST_TMPDIR"
}
teardown() {
cd ..
rm -rf ./tmp-for-test
if [[ -n "$BATS_TEST_TMPDIR" ]]; then
rm -rf "$BATS_TEST_TMPDIR"
fi
}
@test "make install creates a valid installation" {
INSTALL_DIR="${BATS_TEST_TMPDIR}/.local"
cd "${BATS_TEST_DIRNAME}"
run make PREFIX="${INSTALL_DIR}" install
[ "$status" -eq 0 ]
[ -x "${INSTALL_DIR}/bin/has" ]
# has reads .hasrc from $PWD, so change anywhere else.
cd "${INSTALL_DIR}"
run "${INSTALL_DIR}/bin/has"
[ "$status" -eq 0 ]
[ "${lines[0]%% *}" == 'has' ]
[ "${lines[1]%% *}" == 'USAGE:' ]
rm -rf ${INSTALL_DIR}
}
@test "..even if has is missing from directory" {
INSTALL_DIR="${BATS_TEST_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
rm -rf ${INSTALL_DIR}
}
@test "make update runs git fetch" {
cd "${BATS_TEST_DIRNAME}"
run make update
[[ "$status" -eq 0 ]]
[[ "${lines[@]}" =~ "git fetch --verbose" ]]
}
@test "has prints help" {
run bash has
[[ "$(echo "${output}" | grep "has")" ]]
[[ "$(echo "${output}" | grep "USAGE:")" ]]
[[ "$(echo "${output}" | grep "EXAMPLE:")" ]]
}
@test "works with single command check" {
run bash has git
@ -73,12 +118,3 @@ teardown() {
[[ "$(echo "${output}" | grep "✔" | grep "git")" ]]
[[ "$(echo "${output}" | grep "✔" | grep "bc")" ]]
}
@test "has prints help" {
run bash has
[[ "$(echo "${output}" | grep "has")" ]]
[[ "$(echo "${output}" | grep "USAGE:")" ]]
[[ "$(echo "${output}" | grep "EXAMPLE:")" ]]
}

View File

@ -1,9 +1,10 @@
language: bash
before_install:
- sudo add-apt-repository ppa:duggan/bats --yes
- sudo apt-get update -qq
- sudo apt-get install -qq bats
- git clone https://github.com/bats-core/bats-core.git /tmp/bats-core
- mkdir -p /tmp/local
- bash /tmp/bats-core/install.sh /tmp/local
- export PATH=$PATH:/tmp/local/bin
install:
- sudo apt-get install -qq bc
script:

View File

@ -1,8 +1,38 @@
test:
# Makefile for has
# https://github.com/kdabir/has
# 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
# install 'has' in specified directory
chmod 755 has && \
mkdir --verbose --parents $(DESTDIR)$(PREFIX)/bin && \
cp --verbose --update 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 --force has
uninstall :
rm --force /usr/local/bin/has
.PHONY: test install uninstall update
uninstall:
rm -f /usr/local/bin/has

136
README.md
View File

@ -1,93 +1,115 @@
# has
`has` checks presence of various command line tools on the PATH and reports their installed version.
`has` checks presence of various command line tools on the PATH and reports their installed version.
[![Build Status](https://travis-ci.org/kdabir/has.svg?branch=master)](https://travis-ci.org/kdabir/has)
[![Open Source Helpers](https://www.codetriage.com/kdabir/has/badges/users.svg)](https://www.codetriage.com/kdabir/has)
[![demo](demo.svg)](demo.svg)
## How ?
[Install](#installing) the `has` script. There is no dependency apart from `bash` itself
[Install](#installing) the `has` script. There is no dependency apart from `bash` itself.
$ 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
```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 status code
reflects number of commands **not found** on your path.
If everything is good `has` exits with status code `0`. The status code reflects number of commands **not found** on your path.
$ has node go javac
✔ node 8.2.1
✔ go 1.8.3
✘ javac
```console
$ has node go javac
✔ node 8.2.1
✔ go 1.8.3
✘ javac
```
And echo the status:
$ echo $?
1
```console
$ echo $?
1
```
## Installing
`has` is a single bash script that does it all. Just [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.
### Cloning the Repo
Just execute the following command in terminal, it clones has repo and install it in your path
Just execute the following command in a terminal: it clones `has` repo and installs it into your path.
git clone https://github.com/kdabir/has.git && cd has && make install
```bash
git clone https://github.com/kdabir/has.git && cd has && sudo make install
```
To update just do a `git pull` and `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
curl -sL https://git.io/_has > /usr/local/bin/has
```bash
curl -sL https://git.io/_has > /usr/local/bin/has
```
This command is safe to be called multiple times as well. (to update `has`)
```bash
curl -sL https://git.io/_has | sudo tee /usr/local/bin/has >/dev/null
```
### Running directly off the internet
These commands are safe to be called multiple times as well (to update `has`)
If you are lazy, you can run `has` directly off the internet as well:
### Running directly off the Internet
curl -sL https://git.io/_has | bash -s git node npm
✔ git 2.14.1
✔ node 8.2.1
✔ npm 5.3.0
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 of typing every time, setup an alias in your `.bashrc`/`.zshrc` file:
alias has="curl -sL https://git.io/_has | bash -s"
**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?
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 existance of `foobar` and tries to detect version as well.
## The `.hasrc` file
`has` looks for `.hasrc` file in the directory from where `has` command is issued. This file can contain commands that `has`
`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
@ -95,22 +117,22 @@ curl
# interpreters
ruby
node
```
When `has` is run in dir containing this file, it produces:
```
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.
`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
@ -119,31 +141,27 @@ $ has java
✔ 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:
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 of this repo
`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
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 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 [Travis-CI](https://travis-ci.org/kdabir/has).
#### ♥
Raise the PR and **make sure the tests pass** on [Travis-CI](https://travis-ci.org/kdabir/has).
### ♥

3
has
View File

@ -19,7 +19,6 @@ REGEX_SIMPLE_VERSION="([[:digit:]]+\.?){2,3}"
## RC file can contain commands to be tested
RC_FILE=".hasrc"
# try to extract version by executing $1 with $2 arg
__dynamic_detect(){
cmd=$1
@ -77,7 +76,7 @@ __detect(){
vim|emacs|nano|subl) __dynamic_detect--version ${command} ;;
bats|tree|ack|autojump) __dynamic_detect--version ${command} ;;
jq|ag|brew) __dynamic_detect--version ${command} ;;
R) __dynamic_detect--version ${command} ;;
node|npm|yarn) __dynamic_detect--version ${command} ;;
grunt|brunch) __dynamic_detect--version ${command} ;;