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 #!/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() { setup() {
mkdir -p ./tmp-for-test export BATS_TEST_TMPDIR="$BATS_TMPDIR/tmp-for-test"
cp -f has ./tmp-for-test/ mkdir -p "$BATS_TEST_TMPDIR"
cd tmp-for-test cp -f has "$BATS_TEST_TMPDIR"
cd "$BATS_TEST_TMPDIR"
} }
teardown() { teardown() {
cd .. if [[ -n "$BATS_TEST_TMPDIR" ]]; then
rm -rf ./tmp-for-test 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" { @test "works with single command check" {
run bash has git run bash has git
@ -73,12 +118,3 @@ teardown() {
[[ "$(echo "${output}" | grep "✔" | grep "git")" ]] [[ "$(echo "${output}" | grep "✔" | grep "git")" ]]
[[ "$(echo "${output}" | grep "✔" | grep "bc")" ]] [[ "$(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 language: bash
before_install: before_install:
- sudo add-apt-repository ppa:duggan/bats --yes - git clone https://github.com/bats-core/bats-core.git /tmp/bats-core
- sudo apt-get update -qq - mkdir -p /tmp/local
- sudo apt-get install -qq bats - bash /tmp/bats-core/install.sh /tmp/local
- export PATH=$PATH:/tmp/local/bin
install: install:
- sudo apt-get install -qq bc - sudo apt-get install -qq bc
script: 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 bats .hastest.bats
install: has :
cp has /usr/local/bin/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
`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) [![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) [![Open Source Helpers](https://www.codetriage.com/kdabir/has/badges/users.svg)](https://www.codetriage.com/kdabir/has)
[![demo](demo.svg)](demo.svg) [![demo](demo.svg)](demo.svg)
## How ? ## 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 ```console
✔ node 8.2.1 $ has node npm java git gradle
✔ npm 5.3.0 ✔ node 8.2.1
✔ java 1.8.0 ✔ npm 5.3.0
✔ git 2.14.1 ✔ java 1.8.0
✔ gradle 4.0.1 ✔ git 2.14.1
✔ gradle 4.0.1
```
If everything is good `has` exits with status code `0`. The status code If everything is good `has` exits with status code `0`. The status code reflects number of commands **not found** on your path.
reflects number of commands **not found** on your path.
$ has node go javac ```console
✔ node 8.2.1 $ has node go javac
✔ go 1.8.3 ✔ node 8.2.1
✘ javac ✔ go 1.8.3
✘ javac
```
And echo the status: And echo the status:
$ echo $? ```console
1 $ echo $?
1
```
## Installing ## 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. `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 ### 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 ### 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 If you are lazy, you can run `has` directly off the Internet as well:
✔ git 2.14.1
✔ node 8.2.1
✔ npm 5.3.0
```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: **ProTip**: if that's too much typing every time, setup an alias in your `.bashrc`/`.zshrc` file:
alias has="curl -sL https://git.io/_has | bash -s" ```.bashrc
alias has="curl -sL https://git.io/_has | bash -s"
```
And use it And use it
$ has git ```console
✔ git 2.14.1 $ 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`. 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 ## 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. will check for. List one command per line. Lines starting with `#` are treated as comments.
Following is example of `.hasrc` file: Following is example of `.hasrc` file:
``` ```hs
# tools # tools
git git
curl curl
@ -95,22 +117,22 @@ curl
# interpreters # interpreters
ruby ruby
node 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 $ has
✔ git 2.19.1 ✔ git 2.19.1
✔ curl 7.54.0 ✔ curl 7.54.0
✔ ruby 2.3.1 ✔ ruby 2.3.1
✔ node 10.7.0 ✔ 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, 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 $ has java
✔ java 11.0.1 ✔ java 11.0.1
✔ git 2.19.1 ✔ git 2.19.1
@ -119,31 +141,27 @@ $ has java
✔ node 10.7.0 ✔ 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 **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. 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` `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
> take a look at [.hasrc](https://github.com/kdabir/has/blob/master/.hasrc) file for this repo.
## Contributing ## 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) 2. Update the documentation (i.e. the README file)
3. Adding support for more commands 3. Adding support for more commands
4. Adding more features to `has` 4. Adding more features to `has`
## Adding Features ## Adding Features
If you are contributing a feature, please ensure to check current tests. Add test cases for your feature. Tests are 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` 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 can contain commands to be tested
RC_FILE=".hasrc" RC_FILE=".hasrc"
# try to extract version by executing $1 with $2 arg # try to extract version by executing $1 with $2 arg
__dynamic_detect(){ __dynamic_detect(){
cmd=$1 cmd=$1
@ -77,7 +76,7 @@ __detect(){
vim|emacs|nano|subl) __dynamic_detect--version ${command} ;; vim|emacs|nano|subl) __dynamic_detect--version ${command} ;;
bats|tree|ack|autojump) __dynamic_detect--version ${command} ;; bats|tree|ack|autojump) __dynamic_detect--version ${command} ;;
jq|ag|brew) __dynamic_detect--version ${command} ;; jq|ag|brew) __dynamic_detect--version ${command} ;;
R) __dynamic_detect--version ${command} ;; R) __dynamic_detect--version ${command} ;;
node|npm|yarn) __dynamic_detect--version ${command} ;; node|npm|yarn) __dynamic_detect--version ${command} ;;
grunt|brunch) __dynamic_detect--version ${command} ;; grunt|brunch) __dynamic_detect--version ${command} ;;