up 0.18.0

up is a tool to help you keep your machine up to date.
Documentation
# Contributing Guide

## Building & Testing

### macOS

The simplest way to develop this app is to build the dynamically-linked Darwin (macOS) target.

#### macOS Install

First you need to install Rust. The easiest way is to use [rustup][].

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

If you don't want to install to the default locations, just set the variables correctly.

```bash
# You need to set $RUSTUP_HOME and $CARGO_HOME in your rc file and add $CARGO_HOME/bin to your path.
RUSTUP_HOME="$XDG_DATA_HOME"/rustup CARGO_HOME="$XDG_DATA_HOME"/cargo \
  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs           \
  | sh -s -- -y --no-modify-path
```

#### macOS Build

You can then build and run this project with:

```bash
cargo build                          # Debug   binary in target/debug/up
cargo build --release                # Release binary in target/release/up

cargo run --release -- <args>        # Build the release binary and run it with <args>.

./target/release/up --help # Run release binary directly.
```

The compiled binary can be copied anywhere.

#### macOS Test

```bash
cargo test                    # Run tests in debug mode.
cargo test --release          # Run tests in release mode.
cargo test --release          # Run all tests in release mode (what CI runs).
cargo test --no-fail-fast     # Don't stop at first error.

cargo test --test test_module # Only run tests in <test_module> (e.g. file in tests/).
cargo test -- test_name       # Only test functions containing <test_name>.
```

### Linux

The binary that is used in Rio is a statically-linked Linux binary.

#### Docker Linux Build

The easiest way to build is with docker.

Run this script to build and test locally.

```bash
meta/cargo-docker
```

#### Cross-Compiled Linux Build

See [this blog post][Rust Barebones] for more info.

```bash
brew install FiloSottile/musl-cross/musl-cross
rustup target install x86_64-unknown-linux-musl
grep -q 'linker = "x86_64-linux-musl-gcc"' "${CARGO_HOME}"/config \
  || echo -e '[target.x87_64-unknown-linux-musl]
  linker = "x86_64-linux-musl-gcc"' >> "${CARGO_HOME:-~/.cargo}"/config
TARGET_CC=x86_64-linux-musl-gcc cargo build --release --target=x86_64-unknown-linux-musl
```

## Development

### Helpful tools:

You probably want to install some extra rust components to make life easier:

- [`rls`][]: the Rust Language Server. Provides IDE capabilities for anything with
  [Language Server Protocol][] support.
- [`clippy`][]: warns about unidiomatic or dangerous code.
- [`rustfmt`][]: use `cargo fmt` to auto-format code in this repo
- `rust-docs`: offline rust docs, open with `rustup doc`.
- [`cargo-edit`]: Provides `cargo add`, `cargo rm`, and `cargo upgrade` for dependency management.
- [`cargo-watch`]: Run commands when files change (are saved).

```bash
# Use the latest stable rust by default.
cargo default stable

# Add useful rust components.
rustup component add rls rust-analysis rust-src clippy rustfmt rust-docs

cargo install cargo-edit cargo-watch
```

### Updating

You can keep your build tools up to date with:

```bash
# Updates rustup and installed toolchains + components.
rustup update

# Updates everything installed globally with `cargo install`.
cargo install-update --all
```

### Debugging

Rust code can be debugged with either [`gdb`][] or [`lldb`][]. VS Code or CLion
should both work.

See these links for more info:
- [StackOverflow][SO rust debugging]
- [Some blog post][Blog rust debugging]

[Blog rust debugging]: https://bryce.fisher-fleig.org/blog/debugging-rust-programs-with-lldb/index.html
[SO rust debugging]: https://stackoverflow.com/questions/37586216/step-by-step-interactive-debugger-for-rust
[`gdb`]: https://www.gnu.org/software/gdb/
[`lldb`]: https://lldb.llvm.org/

### Show docs

You can show the Rust documentation for the current version of Rust with:

```bash
rustup doc
```

You can show the docs for the current versions of this tool and all its dependencies with:

```bash
# Use --document-private-items to see doc comments for private functions/items/modules.
cargo doc --open --document-private-items
```

### Run on save

```bash
cargo watch -x test                # Run `cargo test` when files change.
cargo watch -x 'run -- --some-arg' # Run `cargo run -- --some-arg` when files change.
```

You can also run arbitrary commands on your own system as you develop, for example with:

```shell
# Run on file change.
fd | entr -s 'cargo +nightly fmt && RUST_BACKTRACE=1 cargo +nightly r -- --log-level=trace'

# In another window, replace with your command logging output.
less ~/tmp/dot-tmp.log
```

### Command Aliases

You can also define command aliases as in git, for an example see [my dotfiles][cargo config].

## Managing Dependencies

To add a prod dependency (compiled into the final binary) use:

```bash
# `cargo add --help` for more info.
cargo add <dependency>    # Add a dependency (compiled into the binary).
cargo add -D <dependency> # Add a dev dependency (only used in tests).
```

To update the ranges in the `Cargo.toml`:

```bash
cargo upgrade
```

Update pinned versions in `Cargo.lock` to the latest versions matching the ranges in `Cargo.toml`:

```bash
cargo update
```

## Writing doc comments

Useful links:
- [Rust By Example][Documentation - Rust By Example]
- [The Book][Documentation - The Book]
- [The API Reference][Documentation - API Reference]
- [RFC 1574: API Documentation Conventions][]
- [RFC 1946: intra-rustdoc links][]
- [Documentation - Reddit][]

## Commit Messages

This project uses [Conventional Commit messages][], with the following categories:

- build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
- chore: (updating grunt tasks etc; no production code change)
- ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
- docs: Documentation only changes
- feat: A new feature
- fix: A bug fix
- perf: A code change that improves performance
- refactor: A code change that neither fixes a bug nor adds a feature
- revert: revert of a previous commit
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- test: Adding missing tests or correcting existing tests

[CONTRIBUTING.md]: /docs/CONTRIBUTING.md
[Conventional Commit messages]: https://www.conventionalcommits.org/en/v1.0.0-beta.4/
[Documentation - API Reference]: https://doc.rust-lang.org/stable/reference/comments.html#doc-comments
[Documentation - Reddit]: https://www.reddit.com/r/rust/comments/ahb50s/is_there_any_documentation_style_guide_for/
[Documentation - Rust By Example]: https://doc.rust-lang.org/rust-by-example/meta/doc.html
[Documentation - The Book]: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments
[Language Server Protocol]: https://langserver.org/
[RFC 1574: API Documentation Conventions]: https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text
[RFC 1946: intra-rustdoc links]: https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html
[Rust Barebones]: https://anderspitman.net/blog/rust-docker-barebones/
[`cargo-edit`]: https://github.com/killercup/cargo-edit
[`cargo-watch`]: https://github.com/passcod/cargo-watch
[`clippy`]: https://github.com/rust-lang/rust-clippy
[`rls`]: https://github.com/rust-lang/rls
[`rustfmt`]: https://github.com/rust-lang/rustfmt
[cargo config]: https://github.com/gibfahn/dot/blob/master/dotfiles/.local/share/cargo/config
[rustup]: https://rustup.rs/