ztp/docs/01-installing-rust.md

48 lines
1.4 KiB
Markdown
Raw Normal View History

+++
title = "Installing Rust"
date = 2023-03-20T17:37:40Z
weight = 1
+++
Since this book is about learning Rust, primarily in a microservices
environment, this chapter focuses on installing Rust and describing the tools
available to the developer.
The easiest way to install Rust is to install the [Rustup](https://rustup.rs/)
tool. It is one of those blind-trust-in-the-safety-of-the-toolchain things. For
Linux and Mac users, the command is a shell script that installs to a user's
local account:
Pre-commit checks and test refactorings. Re-reading the text, I made a number of changes. The first is that, while it is nice that Rust allows us to have unit tests in the file whose functionality we're testing, it's also nice to have the tests somewhere separate, and to have the tests be a little more modular. In the `./tests` folder, you can now see the same `health_check` test as the original, but in an isolated and cleaned-up form. Most importantly, the server startup code is now in its own function, with a correct return type that includes a handle to the spawned thread and the address on which that server is listening; tests can be run in parallel on many different ports and a lot of code duplication is eliminated. ``` rust type NullHandle = JoinHandle<()>; async fn spawn_server() -> (SocketAddr, NullHandle) { let listener = TcpListener::bind("127.0.0.1:0".parse::<SocketAddr>().unwrap()).unwrap(); let addr = listener.local_addr().unwrap(); let handle: NullHandle = tokio::spawn(async move { axum::Server::from_tcp(listener) .unwrap() .serve(app().into_make_service()) .await .unwrap(); }); (addr, handle) } ``` It is also possible now to add new tests in a straightforward manner. The Hyper API is not that much different from the Actix request API, and the Axum extractors seem to be straightforward. I suspect that what I'm looking at here with the handle is the idea that, when it goes out of scope, it calls a d In the introduction I said I was going to be neglecting CI/CD, since I'm a solo developer. That's true, but I do like my guardrails. I like not being able to commit garbage to the repository. So I'm going to add some checks, using [Pre-Commit](https://pre-commit.com/). Pre-Commit is a Python program, so we'll start by installing it. I'm using a local Python environment kickstarted with [Pyenv](https://github.com/pyenv/pyenv). ``` sh $ pip install pre-commit ``` And inside your project, in the project root, you hook it up with the following commands: ``` sh $ pre-commit install $ pre-commit sample-config > .pre-commit-config.yaml ``` I'm going with the default from the rust pre-commit collection, so my `.pre-commit-config.yaml` file looks like this: ``` yaml repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.1.0 hooks: - id: check-byte-order-marker - id: check-case-conflict - id: check-merge-conflict - id: check-symlinks - id: check-yaml - id: end-of-file-fixer - id: mixed-line-ending - id: trailing-whitespace - repo: https://github.com/pre-commit/pre-commit rev: v2.5.1 hooks: - id: validate_manifest - repo: https://github.com/doublify/pre-commit-rust rev: master hooks: - id: fmt - id: cargo-check - id: clippy ``` ... and with that, every time I try to commit my code, it will not let me until these tests pass. And I *like* that level of discipline. This is low-level validation; it won't catch if I put addition where I meant subtraction, or if I have a comparison going in the wrong direction, but at least the basics are handled and, more importantly, the formatting and styling is consistent throughout all of my code.
2023-03-22 00:52:44 +00:00
``` sh
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
Once installed, you can install Rust itself:
Pre-commit checks and test refactorings. Re-reading the text, I made a number of changes. The first is that, while it is nice that Rust allows us to have unit tests in the file whose functionality we're testing, it's also nice to have the tests somewhere separate, and to have the tests be a little more modular. In the `./tests` folder, you can now see the same `health_check` test as the original, but in an isolated and cleaned-up form. Most importantly, the server startup code is now in its own function, with a correct return type that includes a handle to the spawned thread and the address on which that server is listening; tests can be run in parallel on many different ports and a lot of code duplication is eliminated. ``` rust type NullHandle = JoinHandle<()>; async fn spawn_server() -> (SocketAddr, NullHandle) { let listener = TcpListener::bind("127.0.0.1:0".parse::<SocketAddr>().unwrap()).unwrap(); let addr = listener.local_addr().unwrap(); let handle: NullHandle = tokio::spawn(async move { axum::Server::from_tcp(listener) .unwrap() .serve(app().into_make_service()) .await .unwrap(); }); (addr, handle) } ``` It is also possible now to add new tests in a straightforward manner. The Hyper API is not that much different from the Actix request API, and the Axum extractors seem to be straightforward. I suspect that what I'm looking at here with the handle is the idea that, when it goes out of scope, it calls a d In the introduction I said I was going to be neglecting CI/CD, since I'm a solo developer. That's true, but I do like my guardrails. I like not being able to commit garbage to the repository. So I'm going to add some checks, using [Pre-Commit](https://pre-commit.com/). Pre-Commit is a Python program, so we'll start by installing it. I'm using a local Python environment kickstarted with [Pyenv](https://github.com/pyenv/pyenv). ``` sh $ pip install pre-commit ``` And inside your project, in the project root, you hook it up with the following commands: ``` sh $ pre-commit install $ pre-commit sample-config > .pre-commit-config.yaml ``` I'm going with the default from the rust pre-commit collection, so my `.pre-commit-config.yaml` file looks like this: ``` yaml repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.1.0 hooks: - id: check-byte-order-marker - id: check-case-conflict - id: check-merge-conflict - id: check-symlinks - id: check-yaml - id: end-of-file-fixer - id: mixed-line-ending - id: trailing-whitespace - repo: https://github.com/pre-commit/pre-commit rev: v2.5.1 hooks: - id: validate_manifest - repo: https://github.com/doublify/pre-commit-rust rev: master hooks: - id: fmt - id: cargo-check - id: clippy ``` ... and with that, every time I try to commit my code, it will not let me until these tests pass. And I *like* that level of discipline. This is low-level validation; it won't catch if I put addition where I meant subtraction, or if I have a comparison going in the wrong direction, but at least the basics are handled and, more importantly, the formatting and styling is consistent throughout all of my code.
2023-03-22 00:52:44 +00:00
``` sh
$ rustup install toolchain stable
```
You should now have Rust compiler and the Rust build and packaging tool, known
as Cargo:
Pre-commit checks and test refactorings. Re-reading the text, I made a number of changes. The first is that, while it is nice that Rust allows us to have unit tests in the file whose functionality we're testing, it's also nice to have the tests somewhere separate, and to have the tests be a little more modular. In the `./tests` folder, you can now see the same `health_check` test as the original, but in an isolated and cleaned-up form. Most importantly, the server startup code is now in its own function, with a correct return type that includes a handle to the spawned thread and the address on which that server is listening; tests can be run in parallel on many different ports and a lot of code duplication is eliminated. ``` rust type NullHandle = JoinHandle<()>; async fn spawn_server() -> (SocketAddr, NullHandle) { let listener = TcpListener::bind("127.0.0.1:0".parse::<SocketAddr>().unwrap()).unwrap(); let addr = listener.local_addr().unwrap(); let handle: NullHandle = tokio::spawn(async move { axum::Server::from_tcp(listener) .unwrap() .serve(app().into_make_service()) .await .unwrap(); }); (addr, handle) } ``` It is also possible now to add new tests in a straightforward manner. The Hyper API is not that much different from the Actix request API, and the Axum extractors seem to be straightforward. I suspect that what I'm looking at here with the handle is the idea that, when it goes out of scope, it calls a d In the introduction I said I was going to be neglecting CI/CD, since I'm a solo developer. That's true, but I do like my guardrails. I like not being able to commit garbage to the repository. So I'm going to add some checks, using [Pre-Commit](https://pre-commit.com/). Pre-Commit is a Python program, so we'll start by installing it. I'm using a local Python environment kickstarted with [Pyenv](https://github.com/pyenv/pyenv). ``` sh $ pip install pre-commit ``` And inside your project, in the project root, you hook it up with the following commands: ``` sh $ pre-commit install $ pre-commit sample-config > .pre-commit-config.yaml ``` I'm going with the default from the rust pre-commit collection, so my `.pre-commit-config.yaml` file looks like this: ``` yaml repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.1.0 hooks: - id: check-byte-order-marker - id: check-case-conflict - id: check-merge-conflict - id: check-symlinks - id: check-yaml - id: end-of-file-fixer - id: mixed-line-ending - id: trailing-whitespace - repo: https://github.com/pre-commit/pre-commit rev: v2.5.1 hooks: - id: validate_manifest - repo: https://github.com/doublify/pre-commit-rust rev: master hooks: - id: fmt - id: cargo-check - id: clippy ``` ... and with that, every time I try to commit my code, it will not let me until these tests pass. And I *like* that level of discipline. This is low-level validation; it won't catch if I put addition where I meant subtraction, or if I have a comparison going in the wrong direction, but at least the basics are handled and, more importantly, the formatting and styling is consistent throughout all of my code.
2023-03-22 00:52:44 +00:00
``` sh
$ rustc --version
rustc 1.68.0 (2c8cc3432 2023-03-06)
$ cargo --version
cargo 1.68.0 (115f34552 2023-02-26)
```
I also installed the following tools:
Pre-commit checks and test refactorings. Re-reading the text, I made a number of changes. The first is that, while it is nice that Rust allows us to have unit tests in the file whose functionality we're testing, it's also nice to have the tests somewhere separate, and to have the tests be a little more modular. In the `./tests` folder, you can now see the same `health_check` test as the original, but in an isolated and cleaned-up form. Most importantly, the server startup code is now in its own function, with a correct return type that includes a handle to the spawned thread and the address on which that server is listening; tests can be run in parallel on many different ports and a lot of code duplication is eliminated. ``` rust type NullHandle = JoinHandle<()>; async fn spawn_server() -> (SocketAddr, NullHandle) { let listener = TcpListener::bind("127.0.0.1:0".parse::<SocketAddr>().unwrap()).unwrap(); let addr = listener.local_addr().unwrap(); let handle: NullHandle = tokio::spawn(async move { axum::Server::from_tcp(listener) .unwrap() .serve(app().into_make_service()) .await .unwrap(); }); (addr, handle) } ``` It is also possible now to add new tests in a straightforward manner. The Hyper API is not that much different from the Actix request API, and the Axum extractors seem to be straightforward. I suspect that what I'm looking at here with the handle is the idea that, when it goes out of scope, it calls a d In the introduction I said I was going to be neglecting CI/CD, since I'm a solo developer. That's true, but I do like my guardrails. I like not being able to commit garbage to the repository. So I'm going to add some checks, using [Pre-Commit](https://pre-commit.com/). Pre-Commit is a Python program, so we'll start by installing it. I'm using a local Python environment kickstarted with [Pyenv](https://github.com/pyenv/pyenv). ``` sh $ pip install pre-commit ``` And inside your project, in the project root, you hook it up with the following commands: ``` sh $ pre-commit install $ pre-commit sample-config > .pre-commit-config.yaml ``` I'm going with the default from the rust pre-commit collection, so my `.pre-commit-config.yaml` file looks like this: ``` yaml repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.1.0 hooks: - id: check-byte-order-marker - id: check-case-conflict - id: check-merge-conflict - id: check-symlinks - id: check-yaml - id: end-of-file-fixer - id: mixed-line-ending - id: trailing-whitespace - repo: https://github.com/pre-commit/pre-commit rev: v2.5.1 hooks: - id: validate_manifest - repo: https://github.com/doublify/pre-commit-rust rev: master hooks: - id: fmt - id: cargo-check - id: clippy ``` ... and with that, every time I try to commit my code, it will not let me until these tests pass. And I *like* that level of discipline. This is low-level validation; it won't catch if I put addition where I meant subtraction, or if I have a comparison going in the wrong direction, but at least the basics are handled and, more importantly, the formatting and styling is consistent throughout all of my code.
2023-03-22 00:52:44 +00:00
``` sh
$ rustup component add clippy rust-src rust-docs
$ cargo install rustfmt rust-analyzer
```
- clippy: A powerful linter that provides useful advice above and beyond the
compiler's basic error checking.
- rustfmt: A formatting tool that provides a common format for most developers
- rust-analyzer: For your IDE, rust-analyzer provides the LSP (Language Server
Protocol) for Rust, giving you code completion, on-the-fly error definition,
and other luxuries.