Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor docs #91

Merged
merged 8 commits into from
May 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ install:
$(MKDIR) $(DESTDIR)$(PREFIX)/bin
$(INSTALL) -m755 bfs $(DESTDIR)$(PREFIX)/bin/bfs
$(MKDIR) $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -m644 bfs.1 $(DESTDIR)$(MANDIR)/man1/bfs.1
$(INSTALL) -m644 docs/bfs.1 $(DESTDIR)$(MANDIR)/man1/bfs.1
$(MKDIR) $(DESTDIR)$(PREFIX)/share/bash-completion/completions
$(INSTALL) -m644 completions/bfs.bash $(DESTDIR)$(PREFIX)/share/bash-completion/completions/bfs
$(MKDIR) $(DESTDIR)$(PREFIX)/share/zsh/site-functions
Expand Down
189 changes: 114 additions & 75 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
<div align="center">

`bfs`
=====

[![License](http://img.shields.io/badge/license-0BSD-blue.svg)](https://github.com/tavianator/bfs/blob/main/LICENSE)
[![Version](https://img.shields.io/github/v/tag/tavianator/bfs?label=version)](https://github.com/tavianator/bfs/releases)
[![CI Status](https://github.com/tavianator/bfs/actions/workflows/ci.yml/badge.svg)](https://github.com/tavianator/bfs/actions/workflows/ci.yml)
<a href="https://github.com/tavianator/bfs/releases"><img src="https://img.shields.io/github/v/tag/tavianator/bfs?label=version" alt="Version" align="left"></a>
<a href="/LICENSE"><img src="https://img.shields.io/badge/license-0BSD-blue.svg" alt="License" align="left"></a>
<a href="https://github.com/tavianator/bfs/actions/workflows/ci.yml"><img src="https://img.shields.io/github/workflow/status/tavianator/bfs/CI?label=CI" alt="CI Status" align="right"></a>
<a href="https://codecov.io/gh/tavianator/bfs"><img src="https://img.shields.io/codecov/c/github/tavianator/bfs?token=PpBVuozOVC" alt="Code coverage" align="right"/></a>

***Breadth-first search for your files.***

Breadth-first search for your files.
[ **[Features](#features)** ]&emsp;
[ **[Installation](#installation)** ]&emsp;
[ **[Usage](/docs/USAGE.md)** ]&emsp;
[ **[Building](/docs/BUILDING.md)** ]&emsp;
[ **[Hacking](/docs/HACKING.md)** ]&emsp;
[ **[Changelog](/docs/CHANGELOG.md)** ]

<img src="https://tavianator.github.io/bfs/animation.svg" alt="Screenshot" />
<img src="https://tavianator.github.io/bfs/animation.svg" alt="Screenshot">
<p></p>
</div>

`bfs` is a variant of the UNIX `find` command that operates [breadth-first](https://en.wikipedia.org/wiki/Breadth-first_search) rather than [depth-first](https://en.wikipedia.org/wiki/Depth-first_search).
`bfs` is a variant of the UNIX `find` command that operates [**breadth-first**](https://en.wikipedia.org/wiki/Breadth-first_search) rather than [**depth-first**](https://en.wikipedia.org/wiki/Depth-first_search).
It is otherwise compatible with many versions of `find`, including

- [POSIX `find`](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html)
- [GNU `find`](https://www.gnu.org/software/findutils/)
- {[Free](https://www.freebsd.org/cgi/man.cgi?find(1)),[Open](https://man.openbsd.org/find.1),[Net](https://man.netbsd.org/find.1)}BSD `find`
- [macOS `find`](https://ss64.com/osx/find.html)
<div align="center">

[ **[POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html)** ]&emsp;
[ **[GNU](https://www.gnu.org/software/findutils/)** ]&emsp;
[ **[FreeBSD](https://www.freebsd.org/cgi/man.cgi?find(1))** ]&emsp;
[ **[OpenBSD](https://man.openbsd.org/find.1)** ]&emsp;
[ **[NetBSD](https://man.netbsd.org/find.1)** ]&emsp;
[ **[macOS](https://ss64.com/osx/find.html)** ]

</div>

If you're not familiar with `find`, the [GNU find manual](https://www.gnu.org/software/findutils/manual/html_mono/find.html) provides a good introduction.

Expand All @@ -24,7 +42,10 @@ Features
--------

<details>
<summary><code>bfs</code> operates breadth-first, which typically finds the file(s) you're looking for faster.</summary>
<summary>
<code>bfs</code> operates breadth-first, which typically finds the file(s) you're looking for faster.
<p></p>
</summary>

Imagine the following directory tree:

Expand Down Expand Up @@ -72,24 +93,55 @@ haystack/deep/1/2/3/4
</details>

<details>
<summary><code>bfs</code> tries to be easier to use than <code>find</code>, while remaining compatible.</summary>
<summary>
<code>bfs</code> tries to be easier to use than <code>find</code>, while remaining compatible.
<p></p>
</summary>

For example, `bfs` is less picky about where you put its arguments:

<pre>
$ <strong>bfs</strong> -L -name 'needle' <em>haystack</em> │ $ <strong>find</strong> -L -name 'needle' <em>haystack</em>
<strong>haystack/needle</strong> │ find: paths must precede expression: haystack
$ <strong>bfs</strong> <em>haystack</em> -L -name 'needle' │ $ <strong>find</strong> <em>haystack</em> -L -name 'needle'
<strong>haystack/needle</strong> │ find: unknown predicate `-L'
$ <strong>bfs</strong> -L <em>haystack</em> -name 'needle' │ $ <strong>find</strong> -L <em>haystack</em> -name 'needle'
<strong>haystack/needle</strong> │ <strong>haystack/needle</strong>
</pre>
<table>
<tbody>
<tr></tr>
<tr>
<td width="506">

```console
$ bfs -L -name 'needle' haystack
haystack/needle

$ bfs haystack -L -name 'needle'
haystack/needle

$ bfs -L haystack -name 'needle'
haystack/needle
```

</td>
<td width="506">

```console
$ find -L -name 'needle' haystack
find: paths must precede expression: haystack

$ find haystack -L -name 'needle'
find: unknown predicate `-L'

$ find -L haystack -name 'needle'
haystack/needle
```

</td>
</tr>
</tbody>
</table>
</details>

<details>
<summary><code>bfs</code> gives helpful errors and warnings.</summary>
<summary>
<code>bfs</code> gives helpful errors and warnings.
<p></p>
</summary>

For example, `bfs` will detect and suggest corrections for typos:

Expand All @@ -100,7 +152,7 @@ $ bfs -nam needle
<strong>bfs: error:</strong> Unknown argument; did you mean <strong>-name</strong>?
</pre>

`bfs` also includes a powerful static analysis to identify likely mistakes:
`bfs` also includes a powerful static analysis to help catch mistakes:

<pre>
$ bfs -print -name 'needle'
Expand All @@ -111,63 +163,45 @@ $ bfs -print -name 'needle'
</details>

<details>
<summary><code>bfs</code> adds some options that make common tasks easier.</summary>
<summary>
<code>bfs</code> adds some options that make common tasks easier.
<p></p>
</summary>

### `-exclude`
For example, the `-exclude` operator skips over entire subtrees whenever an expression matches.
`-exclude` is both more powerful and easier to use than the standard `-prune` action; compare

The `-exclude` operator skips an entire subtree whenever an expression matches.
For example, `-exclude -name .git` will exclude any files or directories named `.git` from the search results.
`-exclude` is easier to use than the standard `-prune` action; compare

bfs -name config -exclude -name .git
<pre>
$ bfs -name config <strong>-exclude -name .git</strong>
</pre>

to the equivalent

find ! \( -name .git -prune \) -name config

Unlike `-prune`, `-exclude` even works in combination with `-depth`/`-delete`.

---

### `-hidden`/`-nohidden`

`-hidden` matches "hidden" files (dotfiles).
`bfs -hidden` is effectively shorthand for

find \( -name '.*' -not -name . -not -name .. \)

`-nohidden` is equivalent to `-exclude -hidden`.

---

### `-unique`

This option ensures that `bfs` only visits each file once, even if it's reachable through multiple hard or symbolic links.
It's particularly useful when following symbolic links (`-L`).

---

### `-color`/`-nocolor`

When printing to a terminal, `bfs` automatically colors paths like GNU `ls`, according to the `LS_COLORS` environment variable.
The `-color` and `-nocolor` options override the automatic behavior, which may be handy when you want to preserve colors through a pipe:

bfs -color | less -R
<pre>
$ find <strong>! \( -name .git -prune \)</strong> -name config
</pre>

If the [`NO_COLOR`](https://no-color.org/) environment variable is set, colors will be disabled by default.
As an additional shorthand, `-nohidden` skips over all hidden files and directories.
See the [usage documentation](/docs/USAGE.md#extensions) for more about the extensions provided by `bfs`.
</details>


Installation
------------

<details>
<summary><code>bfs</code> may already be packaged for your operating system.</summary>
<details open>
<summary>
<code>bfs</code> may already be packaged for your operating system.
<p></p>
</summary>

<pre>
<strong>Alpine Linux</strong>
# apk add bfs

<strong>Arch Linux</strong>
Available in the <a href="https://aur.archlinux.org/packages/bfs">AUR</a>

<strong>Debian/Ubuntu</strong>
# apt install bfs

Expand All @@ -189,22 +223,16 @@ $ brew install tavianator/tap/bfs
</details>

<details>
<summary>To build <code>bfs</code> from source, you may need to install some dependencies.</summary>
<summary>
To build <code>bfs</code> from source, you may need to install some dependencies.
<p></p>
</summary>

The only absolute requirements for building `bfs` are a C compiler, [GNU make](https://www.gnu.org/software/make/), and [Bash](https://www.gnu.org/software/bash/).
These are installed by default on many systems, and easy to install on most others.
Refer to your operating system's documentation on building software.

`bfs` also depends on some system libraries for some of its features.
These dependencies are optional, and can be turned off at build time if necessary by setting the appropriate variable to the empty string (e.g. `make WITH_ONIGURUMA=`).

| Dependency | Platforms | `make` flag |
|-------------------------------------------------------|------------|------------------|
| [acl](https://savannah.nongnu.org/projects/acl) | Linux only | `WITH_ACL` |
| [attr](https://savannah.nongnu.org/projects/attr) | Linux only | `WITH_ATTR` |
| [libcap](https://sites.google.com/site/fullycapable/) | Linux only | `WITH_LIBCAP` |
| [Oniguruma](https://github.com/kkos/oniguruma) | All | `WITH_ONIGURUMA` |

Here's how to install them on some common platforms:

<pre>
Expand Down Expand Up @@ -235,9 +263,18 @@ Here's how to install them on some common platforms:
<strong>Homebrew</strong>
$ brew install oniguruma
</pre>

These dependencies are technically optional, though strongly recommended.
See the [build documentation](/docs/BUILDING.md#dependencies) for how to disable them.
</details>

Once the dependencies are installed, download one of the [releases](https://github.com/tavianator/bfs/releases) or clone the [git repo](https://github.com/tavianator/bfs).
<details>
<summary>
Once you have the dependencies, you can build <code>bfs</code>.
<p></p>
</summary>

Download one of the [releases](https://github.com/tavianator/bfs/releases) or clone the [git repo](https://github.com/tavianator/bfs).
Then run

$ make
Expand All @@ -254,3 +291,5 @@ If you're interested in speed, you may want to build the release version instead
Finally, if you want to install it globally, run

# make install

</details>
74 changes: 26 additions & 48 deletions CONTRIBUTING.md → docs/BUILDING.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
Contributing
============

License
-------

`bfs` is licensed under the [Zero-Clause BSD License](https://opensource.org/licenses/0BSD), a maximally permissive license.
Contributions must use the same license.
Building `bfs`
==============


Building
--------
Compiling
---------

`bfs` uses [GNU Make](https://www.gnu.org/software/make/) as its build system.
A simple invocation of
Expand Down Expand Up @@ -63,15 +56,34 @@ Here are some of the common ones; check the [`Makefile`](/Makefile) for more.
| `CC` | The C compiler to use, e.g. `make CC=clang` |
| `CFLAGS`<br>`EXTRA_CFLAGS` | Override/add to the default compiler flags |
| `LDFLAGS`<br>`EXTRA_LDFLAGS` | Override/add to the linker flags |
| `WITH_ACL`<br>`WITH_ATTR`<br>... | Enable/disable optional dependencies |
| `WITH_ACL`<br>`WITH_ATTR`<br>... | Enable/disable [optional dependencies] |
| `TEST_FLAGS` | `tests.sh` flags for `make check` |
| `DESTDIR` | The root directory for `make install` |
| `PREFIX` | The installation prefix (default: `/usr`) |
| `MANDIR` | The man page installation directory |

[optional dependencies]: #dependencies

### Dependencies

`bfs` depends on some system libraries for some of its features.
These dependencies are optional, and can be turned off at build time if necessary by setting the appropriate variable to the empty string (e.g. `make WITH_ONIGURUMA=`).

| Dependency | Platforms | `make` flag |
|-------------|------------|------------------|
| [acl] | Linux only | `WITH_ACL` |
| [attr] | Linux only | `WITH_ATTR` |
| [libcap] | Linux only | `WITH_LIBCAP` |
| [Oniguruma] | All | `WITH_ONIGURUMA` |

[acl]: https://savannah.nongnu.org/projects/acl
[attr]: https://savannah.nongnu.org/projects/attr
[libcap]: https://sites.google.com/site/fullycapable/
[Oniguruma]: https://github.com/kkos/oniguruma

### Dependency tracking

The build system automatically tracks header dependencies with the `-M` family of compiler options (see `DEPFLAGS` in the `Makefile`).
The build system automatically tracks header dependencies with the `-M` family of compiler options (see `DEPFLAGS` in the [`Makefile`](/Makefile)).
So if you edit a header file, `make` will rebuild the necessary object files ensuring they don't go out of sync.

We go one step further than most build systems by tracking the flags that were used for the previous compilation.
Expand All @@ -90,7 +102,7 @@ To test a different configuration, you'll have to repeat it (e.g. `make release
Testing
-------

`bfs` comes with an extensive testsuite which can be run with
`bfs` comes with an extensive test suite which can be run with

$ make check

Expand Down Expand Up @@ -131,37 +143,3 @@ You can run it yourself with
$ make distcheck

Some of these tests require `sudo`, and will prompt for your password if necessary.


Hacking
-------

`bfs` is written in [C](https://en.wikipedia.org/wiki/C_(programming_language)), specifically [C11](https://en.wikipedia.org/wiki/C11_(C_standard_revision)).
You can get a feel for the coding style by skimming the source code.
[`main.c`](src/main.c) contains an overview of the rest of source files.
A quick summary:

- Tabs for indentation, spaces for alignment.
- Most types and functions should be namespaced with `bfs_`.
Exceptions are made for things that could be generally useful outside of `bfs`.
- Error handling follows the C standard library conventions: return a nonzero `int` or a `NULL` pointer, with the error code in `errno`.
All failure cases should be handled, including `malloc()` failures.
- `goto` is not harmful for cleaning up in error paths.

### Adding tests

Both new features and bug fixes should have associated tests.
To add a test, create a new function in `tests.sh` called `test_<something>`.
Snapshot tests use the `bfs_diff` function to automatically compare the generated and expected outputs.
For example,

```bash
function test_something() {
bfs_diff basic -name something
}
```

`basic` is one of the directory trees generated for test cases; others include `links`, `loops`, `deep`, and `rainbow`.

Run `./tests.sh test_something --update` to generate the reference snapshot (and don't forget to `git add` it).
Finally, add the test case to one of the arrays `posix_tests`, `bsd_tests`, `gnu_tests`, or `bfs_tests` depending on which `find` implementations it should be compatible with.
File renamed without changes.
Loading