|
|
|
📌 изучить доступные инструменты cargo
|
Например, поиск по запросу cargo-<something> «инструменты» выдает десятки результатов
|
|
|
просканируйте свой crate на предмет нарушений семантического версионирования Semver при подготовке к выпуску новой версии.
По сути, он проверяет, не содержит ли новая версия вашего публичного API изменений, которые должны были бы повлечь за собой повышение старшего (major) или среднего (minor) номера версии, но были ошибочно выпущены как патч (patch) или минорное обновление.
|
|
|
предупреждает вас, когда ваш Cargo.toml включает неиспользуемую зависимость
можно добавить в CI
|
|
|
Анализирует ваш граф зависимостей для обнаружения различных потенциальных проблем во всем наборе транзитивных зависимостей:
- Зависимости, имеющие известные проблемы безопасности во включенной версии
- Зависимости, которые покрываются неприемлемой лицензиней
- Зависимости, которые просто неприемлемы
- Зависимости, включенные в несколько различных версий в дереве зависимостей
можно добавить в CI
|
|
cargo-audit
проверка зависимостей на уязвимости безопасности
advisories
cargo generate-lockfile
|
Cargo-audit - это утилита командной строки, которая проверяет Cargo.lock файлы и сравнивает их с RustSec Advisory Database, базой данных сообщества уязвимостей безопасности, поддерживаемой рабочей группой Rust Secure Code
$ cargo install cargo-audit
$ cargo audit --json
$ cargo generate-lockfile
Чем больше ваш график зависимостей, тем больше вероятность того, что вы столкнетесь с такого рода проблемами. Экосистема крейтов Rust так же уязвима для случайных проблем с зависимостями, как и другие экосистемы пакетов, где история показала, что удаление пакета одним разработчиком или исправление лицензирования для своего пакета командой может иметь широкомасштабные цепные эффекты.
Еще более тревожными являются Атаки на цепочки поставок, когда злоумышленник намеренно пытается подорвать часто используемые зависимости, используя типосквоттинг , захват учетной записи сопровождающего или другие более сложные атаки.
Этот тип атаки влияет не только на ваш скомпилированный код — имейте в виду, что зависимость может запустить произвольный код во время сборки , через build.rs скрипты или процедурные макросы. Это означает, что скомпрометированная зависимость может привести к запуску майнера криптовалюты как части вашей системы CI!
|
|
|
Crate cargo-crev — это инструмент для системы ревизий кода в экосистеме Rust.
Его основная цель — повысить доверие к коду, используемому в зависимости, и помочь разработчикам выбирать безопасные и качественные библиотеки.
|
|
|
Это расширение для Vs code показывает актуальные версии пакетов
|
|
rustc - компилирует исполняемый файл
command-line-arguments
|
# Версия компилятра
rustc --version
# компиляция завершение процесса программы при panic! (нужна OC abort)
rustc --cfg 'panic="abort"' src/main.rs
# запуск
./main
# или компиляция и запуск
rustc src/parse_sound.rs && ./parse_sound
|
|
|
Пакетный менеджер выполняет rustc.
Cargo, менеджер пакетов Rust, позволяет автоматически выбирать зависимости для кода Rust в соответствии с семантическое версионирование (semver)
Позволяет "package" объявлять свои различные зависимости и гарантировать, что вы всегда получите повторяемую сборку.
Три задачи: сборка кода, загрузка библиотек, от которых зависит ваш код, и сборка этих библиотек
Cargo.lock - содержит точную информацию о том, какую версию всех зависимостей мы использовали.
Install:
curl https://sh.rustup.rs -sSf | sh
PATH=$PATH:/home/jeka/.cargo/bin
|
|
Установить Cargo
other-installers
|
$ curl -s https://static.rust-lang.org/rustup.sh | sh -s -- --channel=nightly
curl https://sh.rustup.rs -sSf | sh -s -- -y
# sudo mount -o remount,exec /tmp # если папка смонтирована как noexec
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
export PATH="$PATH:$HOME/.cargo/bin"
sudo apt-get install build-essential # доп. пакеты
sudo apt-get install libc6-dev
sudo apt-get install libssl-dev
|
|
|
rustup self uninstall
sudo apt remove --auto-remove --purge rust-gdb rustc libstd-rust-1.24 libstd-rust-1.28 libstd-rust-dev
|
|
Создание пустого проекта (bin по умолчанию)
|
$ cargo new --bin hello_world (или $ cargo new hello_world)
$ cargo build // смотри $ ./target/debug/hello_world
$ cargo run
$ cargo build --release // смотри $ ./target/release/hello_world
$ cargo new --lib mylib # создаст lib.rs и папку .git
$ cargo new --vcs none --lib mylib # создаст lib.rs без папки .git
или из clon
$ git clone https://github.com/rust-lang-nursery/rand.git
$ cd rand
$ cargo build
$ cargo +nightly new hello-world --edition 2018
|
|
Обновить определенный пакет
|
Ошибка
error[E0282]: type annotations needed for Box<_>
--> /home/jeka/.cargo/registry/src/index.crates.io-6f17d22bba15001f/time-0.3.34/src/format_description/parse/mod.rs:83:9
|
83 | let items = format_items
| ^^^^^
...
86 | Ok(items.into())
| ---- type must be known at this point
|
= note: this is an inference error on crate time caused by an API change in Rust 1.80.0; update time to version >=0.3.35 by calling cargo update
Поскольку в вашем проекте используется версия библиотеки time 0.3.34, которая несовместима с последней версией компилятора Rust, вам необходимо обновить зависимость библиотеки time до версии 0.3.35 или выше, где эта проблема уже исправлена.
cargo update -p time
cargo build
|
|
указывает, cargo какие диапазоны версий semver приемлемы для этой зависимости
specifying-dependencies
effective-rust/semver
code-security/dependabot
|
Избегайте указания полностью Wildcard-зависимость, например "*" или "0.*"
Полностью wildcard-зависимость говорит, что любая версия зависимости с любым API может использоваться вашим контейнером, что вряд ли будет тем, что вам нужно.
"1.2.3": Указывает, что приемлема любая версия, совместимая с semver 1.2.3
"^1.2.3": Это еще один способ более явно указать то же самое
"=1.2.3": Прикрепляет к одной конкретной версии, замены не допускаются
"~1.2.3": Разрешает версии, совместимые с semver 1.2.3, но только в тех случаях, когда изменяется последний указанный компонент (поэтому 1.2.4 приемлема, а 1.3.0 — нет)
"1.2.*": Принимает любую версию, соответствующую подстановочному знаку
Версия "1" эквивалентна "^1", которая допускает все версии 1.x (и поэтому также эквивалентна "1.*")
Версия "1.4.23" эквивалентна "^1.4.23", что допускает любые версии 1.x, превышающие 1.4.23
Учитывая номер версии MAJOR.MINOR.PATCH, увеличьте:
MAJOR версия при внесении несовместимых изменений в API
MINOR версия, когда вы добавляете функциональность с обратной совместимостью
PATCH версия, когда вы делаете исправления ошибок с обратной совместимостью
После выпуска версии пакета содержимое этой версии НЕ ДОЛЖНО быть изменено. Любые изменения ДОЛЖНЫ быть выпущены как новая версия.
Такие инструменты, как cargo update или Dependabot может информировать вас о доступности обновлений; затем вы можете запланировать обновление на удобное для вас время.
| Спецификация | " 1.2.2 " | " 1.2.3 " | " 1.2.4 " | " 1.3.0 " | " 2.0.0 " |
"1.2.3" | Нет | Да | Да | Да | Нет |
"^1.2.3" | Нет | Да | Да | Да | Нет |
"=1.2.3" | Нет | Да | Нет | Нет | Нет |
"~1.2.3" | Нет | Да | Да | Нет | Нет |
"1.2.*" | Да | Да | Да | Нет | Нет |
"1.*" | Да | Да | Да | Да | Нет |
"*" | Да | Да | Да | Да | Да |
|
|
Поймите, что добавление зависимостей экономит время на написание кода, но это не бесплатно.
dep-graph.html#what-to-depend-on
|
Однако каждая новая зависимость имеет свою цену, частично из-за более длительных сборок и больших двоичных файлов, но в основном из-за усилий разработчиков, затрачиваемых на устранение проблем с зависимостями по мере их возникновения.
|
|
Используйте Re-export для зависимостей вашей библиотеки
повторно экспортируйте зависимости, типы которых появляются в вашем API
effective-rust/re-export
|
Кстати, подумайте хорошенько, прежде чем использовать типы другого ящика в вашем API : это тесно связывает ваш ящик с ящиком зависимости. Например, повышение основной версии для зависимости автоматически потребует повышения основной версии и для вашего ящика.
т.е. если ваш публичный API метод явно требует зависимости от внешней библиотеки pub fn foo(item: some_extern_lib::ExternStruct){} то другой код использующий вашу библиотеку и crate some_extern_lib с более новой версией не смогут сосуществовать. Думаю можно спрятать зависимость за своей обверткой и не выдавать зависимость наружу, создав ее самостоятельно
С точки зрения автора бинарного файла, проблему можно обойти, добавив промежуточный контейнер-обертку, который скрывает открытое использование rand типов v0.7. Контейнер-обертка отличается от бинарного контейнера и поэтому может зависеть от rand v0.7 отдельно от зависимости бинарного контейнера от rand v0.8
Лучший подход доступен автору библиотечного ящика. Он может облегчить жизнь своим пользователям, явно реэкспорт одного из следующих:
- Типы, задействованные в API
- Весь ящик зависимостей
// Re-export the version of `rand` used in this crate's API.
pub use rand;
т.е. если в используемой внешней библиотеке есть Re-export то эти зависимости с другой версией будет возможно использовать через имя библиотеки
some_lib::rand и при этом свою зависимость rand можно будет использовать другой версии напрямую в своей библиотеке/бинарном файле
|
|
избегать импорта подстановочных знаков ::* из контейнеров
effective-rust/wildcard
|
избегать импорта подстановочных знаков из контейнеров, которые вы не контролируете
use somecrate::module::* говорит о том, что каждый публичный символ из этого модуля должен быть добавлен в локальное пространство имен.
зависимость добавит новый символ, который будет конфликтовать с именем, которое вы уже используете?
Если какие-либо имена методов из нового типажа конфликтуют с существующими именами методов, которые применяются к типу, то компилятор больше не может однозначно определить, какой метод имеется в виду
|
|
Глобальные зависимости
cargo-home
|
|
|
|
.cargo/ - Конфигурация груза локального проекта , может содержать . config.toml
/projects/foo/.cargo/config.toml
/projects/.cargo/config.toml
$HOME/.cargo/config.toml
# быстрая компиляция
[registries.crates-io]
protocol = "sparse"
[doc]
browser = "chromium" # browser to use with `cargo doc --open`
[env]
# Set ENV_VAR_NAME=value for any process run by Cargo
ENV_VAR_NAME = "value"
# Set even if already present in environment
ENV_VAR_NAME_2 = { value = "value", force = true }
|
|
|
Cargo также можно настроить с помощью переменных среды в дополнение к файлам конфигурации TOML
|
|
|
Некоторые пакеты требуют компиляции стороннего кода, отличного от Rust, например библиотеки C.
Cargo скомпилирует build.rs скрипт и выполнит его непосредственно перед сборкой пакета.
Некоторые примеры использования скриптов сборки:
- Создание связанной библиотеки
C.
- Поиск библиотеки
C в хост-системе.
- Создание модуля
Rust из спецификации.
- Выполнение любой конфигурации для конкретной платформы, необходимой для ящика.
Cargo.toml:
[package]
name = "secure_code"
version = "0.1.0"
edition = "2021"
build = "build.rs"
File /build.rs:
use std::env;
use std::process::Stdio;
fn main() -> Result<(), Box> {
let mut child = std::process::Command::new("sh")
.arg("db/setup_db.sh")
.stderr(Stdio::piped())
.spawn()
.unwrap();
child.wait().unwrap();
Ok(())
}
build.rs для gRPC:
use std::env;
use std::path::PathBuf;
fn main() -> Result<(), Box> {
let proto_file = "./proto/store.proto";
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
tonic_build::configure()
.protoc_arg("--experimental_allow_proto3_optional") // for older systems
.build_client(true)
.build_server(true)
.file_descriptor_set_path(out_dir.join("store_descriptor.bin"))
.out_dir("./src")
.compile(&[proto_file], &["proto"])?;
Ok(())
}
|
|
Версия компилятора при запуске
|
В корень проекта файл, который будет управлять версией компилятора:
$ cat rust-toolchain.toml
[toolchain]
channel = "nightly-2022-06-09"
Если такой версии компилятора на компе нет, то cargo вызовет rustup, чтобы тот поставил нужную версию. Если такой компилятор есть, то любые действия с cargo по компиляции будут использовать указанную в конфиге версию.
|
|
Формат манифеста
Cargo.toml
the-manifest-format
|
[package]
name = "social_backend"
version = "0.1.0-dev"
edition = "2018"
description = "Backend part of social platform project."
authors = ["Instrumentisto Team <developer@instrumentisto.com>"]
readme = "README.md"
repository = "https://git.instrumentisto.com/social/backend"
publish = false
[dependencies]
postgres_macros = "0.1" // из ветки master залитой на crates.io
postgres_macros = { path = "../postgres_macros-0.1.13"} // из своей папки
postgres_macros = { git = "https://github.com/sfackler/rust-postgres-macros.git", rev = "7d4cc509e5c96e062ba494ecd7fde020a5e91a21" } // из ветки master определенного commit
[dependencies.postgres_macros] // из ветки release определенного commit
git="https://github.com/sfackler/rust-postgres-macros.git"
branch = "release"
version = "0.1.12"
rev = "fbe8fb80cb5e5873b611b6203c56a2d8279f6296"
[dev-dependencies]
# Dev-зависимости не используются при компиляции пакета для сборки, но используются для компиляции тестов, примеров и тестов производительности.
|
|
|
[dev-dependencies] - Зависимости для примеров, тестов и бенчмарков.
Dev-зависимости не используются при компиляции пакета для сборки cargo build, но используются для компиляции тестов, примеров и тестов.
Эти зависимости не распространяются на другие пакеты, зависящие от этого пакета.
[dev-dependencies]
tempdir = "0.3"
|
|
|
Рабочая область — это набор из одного или нескольких пакетов, называемых членами рабочей области, которые управляются вместе.
|
|
|
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3 // opt-level - это количество оптимизаций с диапазоном от 0 до 3
[profile.dev]
opt-level = 0
debug = true
rpath = false
lto = false
debug-assertions = true
codegen-units = 16
panic = 'unwind'
incremental = true
overflow-checks = true
[profile.release]
opt-level = 3
debug = false
rpath = false
lto = true
debug-assertions = false
codegen-units = 1
panic = 'abort'
incremental = false
overflow-checks = false
[profile.test]
opt-level = 0
debug = 2
rpath = false
lto = false
debug-assertions = true
codegen-units = 16
incremental = true
overflow-checks = true
[profile.bench]
opt-level = 3
debug = false
rpath = false
lto = true
debug-assertions = false
codegen-units = 16
incremental = false
overflow-checks = false
|
|
Профили [profile.dev]
cargo build --profile=dev
profiles
|
Cargo имеет 4 встроенных профиля: dev, release, test, и bench . Профиль выбирается автоматически на основе выполняемой команды, если профиль не указан в командной строке.
Дефолтный cargo build:
[profile.dev]
opt-level = 0
debug = true
split-debuginfo = '...' # Platform-specific.
debug-assertions = true
overflow-checks = true
lto = false
panic = 'unwind'
incremental = true
codegen-units = 256
rpath = false
Дефолтный cargo build --release:
[profile.release]
opt-level = 3
debug = false
split-debuginfo = '...' # Platform-specific.
debug-assertions = false
overflow-checks = false
lto = false
panic = 'unwind'
incremental = false
codegen-units = 16
rpath = false
|
|
сколько времени заняла компиляция каждого контейнера
cargo build --timings
|
cargo build --timings (или cargo run --timings)
сгенерирует удобный отчет в формате HTML, который покажет вам, сколько времени заняла компиляция каждого контейнера.
|
|
|
.
├── Cargo.lock
├── Cargo.toml
├── src/
│ ├── lib.rs
│ ├── main.rs
│ └── bin/
│ ├── named-executable.rs
│ ├── another-executable.rs
│ └── multi-file-executable/
│ ├── main.rs
│ └── some_module.rs
├── benches/
│ ├── large-input.rs
│ └── multi-file-bench/
│ ├── main.rs
│ └── bench_module.rs
├── examples/
│ ├── simple.rs
│ └── multi-file-example/
│ ├── main.rs
│ └── ex_module.rs
└── tests/
├── some-integration-tests.rs
└── multi-file-test/
├── main.rs
└── test_module.rs
Cargo.toml и Cargo.lock размещается в корневой директории вашего проекта.
- Исходный код отправляется в директорию
src.
- Стандартный файл библиотеки расположен по адресу
src/lib.rs.
- Стандартный исполняемый файл находится по адресу
src/main.rs.
- Другие исполняемые файлы могут быть расположены в
src/bin/*.rs.
- Интеграционные тесты находятся в директории tests (юнит тесты в том файле, который они тестируют).
- Исполняемые примеры располагаются в директории
examples.
- Бенчмарки хранятся в директории
benches
- Скомпилированный исполняемый файл в
target/debug/<name project> или target/release/<name project>
|
|
Замена для extern crate foo as bar;
|
[dependencies.baz]
version = "0.1"
package = "foo"
[dependencies]
baz = { version = "0.1", package = "foo" }
|
|
Избегайте необходимости use foo as bar в Rust source.
Зависит от нескольких версий ящика.
Зависит от ящиков с одинаковым названием из разных реестров.
renaming-dependencies-in-cargotoml
|
Все три библиотеки одно и тоже из разных источников
Для поддержки этого Cargo поддерживает package ключ в [dependencies] разделе, от которого должен зависеть пакет:
т.е. явно с помощью package ключа указать как называется библиотека который мы хотим получить, а то как мы ее назовем тут baz = {...
[package]
name = "mypackage"
version = "0.0.1"
[dependencies]
foo = "0.1"
bar = { git = "https://github.com/example/project", package = "foo" }
baz = { version = "0.1", registry = "custom", package = "foo" }
В этом примере три ящика теперь доступны в вашем коде Rust:
extern crate foo; // crates.io
extern crate bar; // git repository
extern crate baz; // registry `custom`
Все три из этих ящиков имеют название пакета foo в своем собственном Cargo.toml, так что мы явно с помощью package ключа , чтобы сообщить Cargo , что мы хотим , чтобы foo пакет , даже если мы называем это что-то еще на месте.
Если package ключ не указан, по умолчанию используется имя запрашиваемой зависимости.
Обратите внимание, что если у вас есть необязательная зависимость, например:
[dependencies]
foo = { version = "0.1", package = 'bar', optional = true }
Вы bar зависите от ящика от crates.io, но у вашего ящика есть foo функция вместо bar функции. То есть имена функций принимают после имени зависимости, а не имени пакета, при переименовании.
|
|
Создает графы зависимостей
cargo-deps
cargo-depgraph
cargo-depgraph
cargo-deps
graphviz
|
Создавайте диаграммы зависимостей для ваших проектов
cargo install cargo-deps
sudo apt install graphviz
cargo deps | dot -Tpng > graph.png
cargo deps --all-deps | dot -Tpng > graph.png
cargo install cargo-depgraph
cargo depgraph [options] | dot -Tpng > graph.png
|
|
|
$ cargo metadata > /home/jeka/file.json
Output:
{
// Версия формата сообщений .
"version": integer,
// Список пакетов для проекта, включая зависимости.
"packages": [
{
// Уникальный идентификатор пакета.
"id": PackageId,
"name": string,
"version": string,
"source": SourceId,
// Список объявленных зависимостей. Используемые зависимости описаны в пол `resolve`.
"dependencies": [ Dependency ],
"targets: [ Target ],
// Путь до Cargo.toml
"manifest_path": string,
}
],
"workspace_members": [ PackageId ],
// Граф зависимостей.
"resolve": {
"nodes": [
{
"id": PackageId,
"dependencies": [ PackageId ]
}
]
}
}
|
|
Реальные зависимости проекта
Cargo.toml
Cargo.lock
cargo tree --format "{p} {f}"
cargo tree -f '{p} {f}'
cargo build -v
cargo update
Указание синтаксиса зависимостей:
|
.gitignore cargo.lock:
Если вы создаете не конечный продукт, например библиотеку rust, от которой будут зависеть другие пакеты rust, вставьте Cargo.lock свой .gitignore. Если вы создаете конечный продукт, исполняемый как инструмент командной строки или приложение, или системную библиотеку с типом ящика staticlib или cdylib, отметьте Cargo.lock в git
Cargo.toml:
[dependencies]
regex = "0.1.41" # пожелание по умолчанию ^0.1.41 Для точной версии "=0.1.41"
Cargo.lock содержит точную информацию о том, какую версию всех зависимостей мы использовали, чтобы сборка была стабильной и не требовала новых загрузок
Передавать файлы Cargo.lock в .gitignore систему контроля версий или нет?
То, что производит конечный продукт, а именно приложения и двоичные файлы, должно передаваться с Cargo.lock для обеспечения детерминированной сборки.
Библиотечные контейнеры не должны передавать файл Cargo.lock, поскольку он не имеет значения для последующих потребителей библиотеки — у них будет свой собственный файл Cargo.lock имейте в виду, что файл Cargo.lock для библиотечного контейнера игнорируется пользователями библиотеки
Однако, если вы контролируете версии Cargo.lock, настройте процесс для обработки обновлений (например, GitHub's Dependabot)
[[package]]
name = "regex"
version = "0.1.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
dependencies = ["aho-corasick", "memchr", "regex-syntax", "thread_local","utf8-ranges",]
$ cargo tree
temp v0.1.0 (/home/jeka/projects/project_rust/temp)
└── regex v0.1.80
├── aho-corasick v0.5.3
│ └── memchr v0.1.11
│ └── libc v0.2.97
├── memchr v0.1.11 (*)
├── regex-syntax v0.3.9
├── thread_local v0.2.7
│ └── thread-id v2.0.0
│ ├── kernel32-sys v0.2.2
│ │ └── winapi v0.2.8
│ │ [build-dependencies]
│ │ └── winapi-build v0.1.1
│ └── libc v0.2.97
└── utf8-ranges v0.1.3
просил regex 0.1.4 но cargo дал 0.1.8 так как это минимальная разрешимая версия используемая другими пакетами т.е по факту в проекте версия 0.1.8 хотя Cargo.toml написано 0.1.4
cargo build -v покажет версии пакетов в сборке
...Compiling regex v0.1.80
Теперь, если regex будет обновлено, мы по-прежнему будем строить с той же ревизией, пока не выберем cargo update
|
|
cargo tree Распечатайте дерево зависимостей
|
Распечатайте дерево зависимостей:
--invert: показывает, что зависит от конкретного пакета, помогая вам сосредоточиться на конкретной проблемной зависимости
--edges features: показывает, какие функции ящика активируются ссылкой зависимости, что помогает вам понять, что происходит с унификацией функций
--duplicates: Показывает ящики, имеющие несколько версий, представленных в графике зависимостей.
cargo tree -e features
cargo tree --format "{p} {f}"
|
|
crate cargo-tree
Дубликаты зависимостей
|
помогает найти все места, в которые вставляются дубликаты зависимостей
cargo install cargo-tree
$ cargo tree --features serde_json -p libc -i
$ cargo tree -d
$ tree -d -L 1 target/doc/
cargo tree также может работать в «обратном» режиме, когда дерево зависимостей идет назад. Это чаще всего полезно при попытке определить, откуда поступает определенный ящик. --package или -p флаг выбирает ящик, чтобы использовать в качестве корня дерева и --invert или -i флаг инвертирует граф зависимостей обхода
|
|
Cargo.lock
помощь с версией пакета через git (rev, tag, branch)
specifying-dependencies-from-git-repositories
|
Для точной версии указывается его commit
[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand.git", rev = "9f35b8e" }
но это накладно следить за SHA-1 каждый раз, когда мы хотим обновить нашу библиотеку. Это утомительно и чревато ошибками.
Как это решает cargo.lock за нас, когда у нас есть:
[package]
name = "hello_world"
version = "0.1.0"
[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand.git" }
Cargo возьмет последний коммит и запишет эту информацию в наш, Cargo.lock:
[[package]]
name = "hello_world"
version = "0.1.0"
dependencies = [
"rand 0.1.0 (git+https://github.com/rust-lang-nursery/rand.git#9f35b8e439eeedd60b9414c58f389bdc6a3284f9)",
]
[[package]]
name = "rand"
version = "0.1.0"
source = "git+https://github.com/rust-lang-nursery/rand.git#9f35b8e439eeedd60b941
Теперь, когда вы передаете свой пакет кому-то другому, он будет использовать тот же самый SHA, даже если мы не указали его в нашем Cargo.toml
|
|
|
// Обновление только одного пакета
$ cargo update -p rand --precise $version
// Обновление всех пакетов
$ cargo update
|
|
Переопределение зависимостей
[replace] -> [path]
Устарел синтаксис replace вместо него path
specifying-dependencies
overriding-dependencies
|
Допустим, вы работаете над проектом, используя контейнер uuid, который зависит от rand. Вы обнаружили ошибку в rand, и она уже исправлена, по пока не опубликована.
[dependencies]
uuid = "0.2"
Чтобы переопределить зависимость rand контейнера uuid, мы будем использовать [секцию [replace]] replace-section в Cargo.toml, добавив это в конце:
[replace]
"rand:0.3.14" = { git = 'https://github.com/rust-lang-nursery/rand' }
Посмотреть в Cargo.lock какую конкретно версию использует uuid библиотеке rand:0.3.14
Это означает, что rand версии 0.3.14, которую мы сейчас используем, будет заменена веткой master репозитория rand на GitHub.
Устарел синтаксис replace вместо него path
[patch.crates-io]
rustc-serialize = {path="../rustc-serialize", version="0.3.24"}
|
|
feature
позволят включать функционал библиотеки
reference/features
|
Файл библиотеки lib.rs:
//#[cfg(feature = "mydefault")]
//pub use def::*;
pub fn qwerty(){ println!("qwerty");}
#[cfg(feature = "ex_1")]
pub mod bla{
pub fn boo(){ println!("boo"); }
}
pub mod lala{
pub fn foo(){ println!("foo");}
}
#[cfg(feature = "mydefault")]
pub mod def{
pub fn ggg(){ println!("ggg"); }
}
Cargo.toml:
[package]
name = "mylib"
version = "0.1.0"
edition = "2018"
[dependencies]
[features]
default = ['mydefault']
ex_1=[]
mydefault = []
Для использования различных функций библиотеки mylib в своем проекте:
Cargo.toml:
[dependencies]
mylib = {default-features = false,path="mylib",features=["mydefault","ex_1"]}
Файл main.rs:
use mylib::*;
fn main(){
qwerty();
def::ggg();
lala::foo();
bla::boo();
}
|
|
Взаимоисключающие функции
|
В редких случаях функции могут быть несовместимы друг с другом.
Добавления ошибки компиляции для обнаружения этого сценария.
#[cfg(all(feature = "foo", feature = "bar"))]
compile_error!("feature \"foo\" and feature \"bar\" cannot be enabled at the same time");
|
|
|
Когда сборка долгая, можно проверить компилируется ли проект
cargo check
cargo check -p <pkgid>
|
|
cargo install --list
cargo install mdbook-mermaid
cargo uninstall mdbook-mermaid
cargo-install-for-easy-installation-of-tools
|
Эта команда управляет локальным набором установленных бинарных крейтов Cargo.
Могут быть установлены только пакеты, у которых есть исполняемый файл [[bin]] или [[example]] цели, и все исполняемые файлы устанавливаются в корневую bin папку установки.
По умолчанию устанавливаются только двоичные файлы, а не примеры.
Короче устанавливает в систему исполняемые crates
$ cargo install ripgrep
|
|
|
Команда cargo install позволяет устанавливать и использовать бинарные crate локально. Это не предназначено для замены системных пакетов; он должен быть удобным способом для разработчиков Rust, чтобы установить инструменты, которые другие поделили на crates.io
Все установленные бинарные файлы cargo install хранятся в папке bin корневого каталога установки .
Если вы установили Rust с помощью rustup.rs и не имеете каких-либо пользовательских конфигураций,
этот каталог будет $HOME/.cargo/bin. Убедитесь, что в вашем каталоге есть $PATH программа для запуска программ,
с которыми вы установили cargo install.
Существует реализация Rust grep инструмента, предназначенного ripgrep для поиска файлов.
Если мы хотим установить ripgrep, мы можем запустить следующее:
$ cargo install ripgrep
... Installing ~/.cargo/bin/rg
Пока каталог установки находится в вашем $PATH, как упоминалось ранее, вы можете запустить rg --help
и начать использовать более быстрый, более простой инструмент для поиска файлов!
Если имя бинарного файла в вашем $PATH имени cargo-something, вы можете запустить его, как если бы это была подкоманда Cargo, запустив ее cargo something
|
|
|
предоставляет некоторую информацию о том, сколько времени занимает каждая компиляция
target/cargo-timings/cargo-timing.html
|
|
Проверка сборки для определенной цели
cargo build --target wasm32-unknown-unknown
cargo check --target wasm32-unknown-unknown
add-wasm-support-to-crate
|
|
|
|
сборка dev (developer), исполняемый файл в target/debug/<NAME PROJECT>
|
|
|
сборка release, для пользователей финальная версия с оптимизацией, исполняемый файл в target/release/<NAME PROJECT>
|
|
cargo build --bin my_other_bin
|
два двоичных файла src/bin/my_other_bin.rs
foo
├── Cargo.toml
└── src
└── main.rs
Предположим, что мы хотим иметь два двоичных файла в одном проекте. Что тогда?
Оказывается, cargo это поддерживает. Двоичный файл по умолчанию называется main.rs, это мы видели раньше, но вы можете добавить дополнительные файлы, поместив их в bin/ каталог:
foo
├── Cargo.toml
└── src
├── main.rs
└── bin
└── my_other_bin.rs
Чтобы сказать cargo скомпилировать или запустить этот двоичный файл, мы просто передаём cargo флаг --bin my_other_bin, где my_other_bin это имя двоичного файла, с которым мы хотим работать.
|
|
sudo cargo build --verbose > cargo.log 2>&1
|
-
> Это оператор перенаправления вывода. Он отправляет стандартный вывод (STDOUT) команды в файл.
-
cargo.log Имя файла, в который будет записан стандартный вывод (STDOUT).
-
2>&1 Это оператор перенаправления потока ошибок (STDERR). Он перенаправляет поток ошибок в то же место, куда перенаправлен стандартный вывод (то есть в файл cargo.log).
|
|
|
Тихий запуск, без лишнего вывода в консоль
|
|
|
Полный список вызываемых команд rustc
|
|
cargo run --bin example_bin
|
Если надо запустить main.rs то в опции --bin указать имя проекта (из Cargo.toml)
Для проверки работы библиотеки:
- создать папку
src/bin/example_bin.rs
- импортировать свою библиотеку
use self::your_lib_name::*;
- запуск
cargo run --bin example_bin
|
|
Запуск одного приложения из разных источников
cargo run
|
Запуск одного приложения из разных источников
Cargo.toml:
[package]
....
default-run = "main"
[[bin]]
name = "main"
path = "src/main.rs"
[[bin]]
name = "websocket-server"
path = "src/main.rs"
[[bin]]
name = "websocket-client"
path = "src/client.rs"
Запуск:
cargo run // запуститься по дефолту main.rs
cargo run --bin websocket-server
cargo run --bin websocket-client
|
|
cargo run --example parse_select
|
Должна быть папка examples/parse_select.rs на уровне с Cargo.toml
cargo run --example parse_select
или
Псевдоним можно указать в Cargo.toml:
[[example]]
name = "parse"
path ="examples/parse_select.rs"
Запуск
cargo run --example parse
|
|
cargo run --example parse_select
crate-type
reference/examples
|
Вы можете запустить отдельные исполняемые примеры с помощью команды cargo run --example <example-name>
По умолчанию примеры - это исполняемые двоичные файлы (с main() функцией).
Вы можете указать crate-type поле, чтобы пример был скомпилирован как библиотека:
Укажите, crate-type чтобы пример был скомпилирован в виде библиотеки (дополнительная информация о типах ящиков доступна в Справочнике по Rust ):
[[example]]
name = "foo"
crate-type = ["staticlib"]
Вы можете создавать отдельные примеры библиотек с помощью команды cargo build --example <example-name>
|
|
cargo run --example image-fractal
cargo run --example image-next
|
File examples/fractal.rs
Cargo.toml:
[[example]]
name = "image-fractal"
path ="examples/image/fractal.rs"
[[example]]
name = "image-next"
path ="examples/image/next.rs"
|
|
Запуск библиотеки на выполнение из папки bin/ как входной файл
|
Запуск библиотеки на выполнение из папки bin/ как входной файл
Cargo.toml:
[package]
name = "HELLO"
src/lib.rs:
pub mod foo;
src/foo.rs:
pub const VAR:i32 = 9;
src/bin/backend.rs:
fn main() {
println!("{}",HELLO::foo::VAR);
}
Запуск:
$ cargo run --bin backend
Второй вариант через [[bin]]
Cargo.toml:
[[bin]]
name = "name_run"
path = "src/bin/backend.rs"
Запуск:
$ cargo run --bin name_run
|
|
Запуск библиотеки на выполнение из workspace
cargo run -- --workspace ./byte_sized
|
File test_lib/Cargo.toml:
[workspace]
members = [
"bin_world",
"hello_world",
]
test_lib/bin_world (это бинарный проект)
File test_lib/bin_world/src/main.rs :
use hello_world;
fn main() {
println!("Hello, world! {}",hello_world::foo::Var);
}
File test_lib/bin_world/Cargo.toml (подключает библиотеку hello_world из workspace)
[dependencies]
hello_world = { path = "../hello_world" }
test_lib/hello_world (это библиотека)
File test_lib/hello_world/src/lib.rs:
pub mod foo;
File test_lib/hello_world/src/foo.rs:
pub const Var:i32 = 9;
Сборка и запуск:
../test_lib $ cargo build
../test_lib $ cargo run -p bin_world // запуск бинарного проекта
|
|
cargo +nightly rustc --profile=check -- -Zunpretty=expanded
cargo-expand
|
выводит текст кода на экран
use quux::{quux_1, quux_2};
use set_example::check_value;
fn main() {
let mut y = 2;
{
let x = || { 7 + y };
let retval = quux_1(&x);
{ ::std::io::_print(format_args!("retval: {0:?}\n", retval)); };
let retval = quux_2(x());
{ ::std::io::_print(format_args!("retval: {0:?}\n", retval)); };
}
y = 5;
{ ::std::io::_print(format_args!("y : {0:?}\n", y)); };
let mut loop_count = 0;
let p1 = 1;
loop {
let p2 = "hello";
check_value(p1, p2);
loop_count += 1;
if loop_count > 2 { break; }
}
}
cargo +nightly rustc --profile=check -- -Zunpretty=expanded
|
|
|
Использование rust-toolchain.toml позволяет стандартизировать и упрощать процесс управления версиями Rust и связанных инструментов в проекте, что способствует стабильности и предсказуемости разработки.
[toolchain]
channel = "stable" # Можно указать также "nightly" или конкретную версию, например, "1.56.0"
components = ["rustfmt", "rust-analyzer", "clippy"] # Дополнительные компоненты для установки
targets = ["wasm32-unknown-unknown"] # Дополнительные цели компиляции
profile = "minimal" # Профиль установки, может быть "default", "minimal", или "complete"
-
channel:
Указывает версию Rust, которую следует использовать. Это может быть stable, beta, nightly или конкретная версия, например, 1.56.0.
-
components:
Список дополнительных компонентов, которые будут установлены вместе с компилятором Rust. Примеры: rustfmt (для форматирования кода), clippy (для анализа кода), rust-src (исходный код стандартной библиотеки).
-
targets:
Список дополнительных целей компиляции, которые будут установлены. Например, wasm32-unknown-unknown для компиляции в WebAssembly.
-
profile:
Профиль установки Rust. Возможные значения: default (включает большинство компонентов), minimal (только компилятор и Cargo), complete (все доступные компоненты).
Версия компилятора при запуске
В корень проекта файл, который будет управлять версией компилятора:
File rust-toolchain.toml:
[toolchain]
channel = "nightly-2022-06-09"
Если такой версии компилятора на компе нет, то cargo вызовет rustup, чтобы тот поставил нужную версию. Если такой компилятор есть, то любые действия с cargo по компиляции будут использовать указанную в конфиге версию.
|
|
|
|
|
|
Код Rust использует змеиный регистр (snake case) как основной стиль для имён функций и переменных, в котором все буквы строчные, а символ подчёркивания разделяет слова.
|
|
📌 Заюзать пример шаблона чистого кода
cucumber/clippy
|
|
|
vscode settings.json
Настройка форматирования IDE vscode
gist
|
home/jeka/.config/Code/User/settings.json
settings.json
{
"workbench.colorTheme": "Default Dark+",
"editor.minimap.enabled": false,
"scm.inputFontSize": 10,
"screencastMode.fontSize": 48,
"debug.console.fontSize": 10,
"markdown.preview.fontSize": 10,
"cmake.configureOnOpen": true,
"idf.flashType": "UART",
"window.menuBarVisibility": "toggle",
"workbench.statusBar.visible": false,
"workbench.tree.indent": 6,
"workbench.view.alwaysShowHeaderActions": true,
//"editor.mouseWheelZoom": true ,
//"files.autoSave": "afterDelay",
//"editor.fontSize": 8,
//"terminal.integrated.fontSize": 10,
// Определяет семейство шрифтов.
"editor.fontFamily": "Consolas, 'Courier New', monospace",
// Управляет насыщенностью шрифта.
"editor.fontWeight": "normal",
// Управляет размером шрифта в пикселях.
"editor.fontSize": 8,
// Управляет высотой строк. Укажите 0 для вычисления высоты строки по размеру шрифта.
"editor.lineHeight": 0,
// Управляет видимостью номеров строк.
"editor.lineNumbers": "on",
// Столбцы, в которых должны отображаться вертикальные линейки
"editor.rulers": [],
// Символы, которые будут использоваться как разделители слов при выполнении навигации или других операций, связанных со словами.
"editor.wordSeparators": "`~!@#$%^&*()-=+[{]}\\|;:'\",.<>/?",
// Число пробелов в табуляции. Эта настройка переопределяется на основании содержимого файла, когда включен параметр "editor.detectIndentation".
"editor.tabSize": 4,
// Вставлять пробелы при нажатии клавиши TAB. Эта настройка переопределяется на основании содержимого файла, когда включен параметр "editor.detectIndentation".
"editor.insertSpaces": true,
// При открытии файла editor.tabSize и editor.insertSpaces будут определяться на основе содержимого файла.
"editor.detectIndentation": true,
// Определяет, будут ли выделения иметь скругленные углы.
"editor.roundedSelection": true,
// Определяет, будет ли содержимое редактора прокручиваться за последнюю строку.
"editor.scrollBeyondLastLine": true,
// Определяет число символов, после которых текст будет перенесен на следующую строку. Если этот параметр имеет значение 0, используется перенос по ширине окна просмотра (перенос по словам). Если задать значение –1, то в редакторе не будет выполняться перенос по словам.
"editor.wrappingColumn": 300,
// Определяет, должны ли строки переноситься. Строки будут переноситься по значению min(editor.wrappingColumn, viewportWidthInColumns).
"editor.wordWrap": false,
// Управляет отступом строк с переносом по словам. Допустимые значения: "none", "same" или "indent".
"editor.wrappingIndent": "same",
// Множитель, используемый для параметров deltaX и deltaY событий прокрутки колесика мыши.
"editor.mouseWheelScrollSensitivity": 1,
// Определяет, должны ли при вводе текста отображаться краткие предложения.
"editor.quickSuggestions": true,
// Управляет длительностью задержки (в мс), перед отображением кратких предложений.
"editor.quickSuggestionsDelay": 10,
// Включение подсказок для параметров
"editor.parameterHints": true,
// Определяет, должен ли редактор автоматически закрывать скобки после открытия.
"editor.autoClosingBrackets": true,
// Управляет параметром, определяющим, должен ли редактор автоматически форматировать строку после ввода.
"editor.formatOnType": false,
// Определяет, должны ли при вводе триггерных символов автоматически отображаться предложения.
"editor.suggestOnTriggerCharacters": true,
// Определяет, можно ли принимать предложения клавишей ВВОД в дополнение к клавише TAB. Это помогает избежать неоднозначности между вставкой новых строк или принятием предложений.
"editor.acceptSuggestionOnEnter": true,
// Управляет отображением фрагментов вместе с другими предложениями и их сортировкой.
"editor.snippetSuggestions": "bottom",
// Включите предложения на основе слов.
"editor.wordBasedSuggestions": true,
// Вставка фрагментов при совпадении их префиксов. Функция работает оптимально, если параметр "quickSuggestions" отключен.
"editor.tabCompletion": false,
// Определяет, будет ли редактор выделять фрагменты, совпадающие с выделенным текстом.
"editor.selectionHighlight": true,
// Определяет, сколько украшений могут отображаться на одном месте в обзорной линейке.
"editor.overviewRulerLanes": 3,
// Управляет стилем анимации курсора. Допустимые значения: "blink", "smooth", "phase", "expand" и "solid"
"editor.cursorBlinking": "blink",
// Изменение размера шрифта в редакторе при нажатой клавише CTRL и движении колесика мыши
"editor.mouseWheelZoom": true,
// Определяет стиль курсора. Допустимые значения: "block", "line" и "underline"
"editor.cursorStyle": "line",
// Включает лигатуры шрифта.
"editor.fontLigatures": false,
// Управляет скрытием курсора в обзорной линейке.
"editor.hideCursorInOverviewRuler": false,
// Определяет, должен ли редактор обрабатывать символы пробела; возможные значения: "none", "boundary" и "all". Параметр "boundary" не обрабатывает единичные пробелы между словами.
"editor.renderWhitespace": "none",
// Определяет, должны ли в редакторе отображаться управляющие символы.
"editor.renderControlCharacters": false,
// Определяет, должны ли в редакторе отображаться направляющие отступа.
"editor.renderIndentGuides": false,
// Определяет, должен ли редактор отображать текущее выделение строки
"editor.renderLineHighlight": true,
// Управляет показом групп связанных элементов кода в редакторе
"editor.codeLens": true,
// Определяет, включено ли сворачивание кода в редакторе.
"editor.folding": true,
// Вставка и удаление пробелов после позиции табуляции
"editor.useTabStops": true,
// Удалить автоматически вставляемый конечный пробел
"editor.trimAutoWhitespace": true,
// Оставлять просматривающие редакторы открытыми, даже если дважды щелкнуто их содержимое или нажата клавиша ESC.
"editor.stablePeek": false,
// Определяет, как редактор несовпадений отображает отличия: рядом или в тексте.
"diffEditor.renderSideBySide": true,
// Определяет, должен ли редактор несовпадений трактовать несовпадения символов-разделителей как различия.
"diffEditor.ignoreTrimWhitespace": true,
// Emmet
// Если включено, сокращения Emmet разворачиваются при нажатии клавиши TAB.
"emmet.triggerExpansionOnTab": true,
// Настройки, которые используются для изменения поведения некоторых действий и сопоставителей Emmet.
"emmet.preferences": {},
// Задайте профиль для указанного синтаксиса или используйте свой собственный профиль с определенными правилами.
"emmet.syntaxProfiles": {},
// Массив языков, в которых не должны развертываться сокращения Emmet.
"emmet.excludeLanguages": [],
// Workbench
// Определяет, должны ли открытые редакторы отображаться на вкладках или нет.
"workbench.editor.showTabs": true,
// Определяет, должны ли открытые редакторы отображаться со значком. Требует включить тему значков.
"workbench.editor.showIcons": true,
// Определяет, отображаются ли открытые редакторы в режиме предварительного просмотра. Редакторы с предварительным просмотром повторно используются до сохранения (например, с помощью двойного щелчка или изменения).
"workbench.editor.enablePreview": true,
// Определяет, отображаются ли редакторы из Quick Open в режиме предварительного просмотра. Редакторы в режиме предварительного просмотра повторно используются до сохранения (например, с помощью двойного щелчка или изменения).
"workbench.editor.enablePreviewFromQuickOpen": true,
// Определяет место открытия редакторов. Выберите "Слева" или "Справа", чтобы открывать редакторы слева или справа от активного сейчас редактора. Выберите "Первый" или "Последний", чтобы открывать редакторы независимо от активного сейчас редактора.
"workbench.editor.openPositioning": "right",
// Управляет автоматическим закрытием Quick Open при потере фокуса.
"workbench.quickOpen.closeOnFocusLost": true,
// Управляет открытием редактора с отображением всех настроек по умолчанию при открытии настроек.
"workbench.settings.openDefaultSettings": true,
// Окно
// Если этот параметр включен, файлы будут открываться в новом окне, а не в существующем экземпляре.
"window.openFilesInNewWindow": true,
// Управляет повторным открытием папок после перезапуска. Выберите значение "none", чтобы не открывать папку повторно, "one", чтобы открывалась последняя папка, с которой вы работали, или "all", чтобы открывались все папки последнего сеанса.
"window.reopenFolders": "one",
// Определяет, должно ли окно восстанавливаться в полноэкранном режиме, если оно было закрыто в полноэкранном режиме.
"window.restoreFullscreen": false,
// Настройте масштаб окна. Исходный размер равен 0. Увеличение или уменьшение значения на 1 означает увеличение или уменьшение окна на 20 %. Чтобы более точно задать масштаб, можно также ввести десятичное число.
"window.zoomLevel": 0,
// Файлы
// Настройка стандартных масок для исключения файлов и папок.
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/.DS_Store": true
},
// Настройте сопоставления файлов с языками (например, "*.extension": "html"). У них будет приоритет перед заданными по умолчанию сопоставлениями установленных языков.
"files.associations": {},
// Кодировка набора символов по умолчанию, используемая при чтении и записи файлов
"files.encoding": "utf8",
// Символ конца строки по умолчанию.
"files.eol": "\r\n",
// Если этот параметр включен, при сохранении файла будут удалены завершающие символы-разделители.
"files.trimTrailingWhitespace": false,
// Управляет автоматическим сохранением измененных файлов. Допустимые значения: "off", "afterDelay", "onFocusChange" (редактор теряет фокус) и "onWindowChange" (окно теряет фокус). Если задано значение "afterDelay", можно настроить задержку в "files.autoSaveDelay".
"files.autoSave": "afterDelay",
// Определяет задержку в мс, после которой измененный файл сохраняется автоматически. Действует, только если параметр files.autoSave имеет значение "afterDelay".
"files.autoSaveDelay": 1000,
// Настройте стандартные маски путей файлов, чтобы исключить их из списка отслеживаемых файлов. После изменения этого параметра потребуется перезагрузка. При отображении сообщения "Код потребляет большое количество процессорного времени при запуске" вы можете исключить большие папки, чтобы уменьшить первоначальную загрузку.
"files.watcherExclude": {
"**/.git/objects/**": true
},
// Форматирование файла при сохранении. Модуль форматирования должен быть доступен, файл не должен сохраняться автоматически, а работа редактора не должна завершаться.
"editor.formatOnSave": false,
// Проводник
// Число редакторов, отображаемых на панели открытых редакторов. Задайте значение 0, чтобы скрыть панель.
"explorer.openEditors.visible": 9,
// Определяет, будет ли высота раздела открытых редакторов динамически адаптироваться к количеству элементов.
"explorer.openEditors.dynamicHeight": true,
// Определяет, следует ли обозревателю автоматически отображать файлы при их открытии.
"explorer.autoReveal": true,
// Определяет, разрешено ли перемещение файлов и папок перетаскиванием в проводнике.
"explorer.enableDragAndDrop": true,
// Поиск
// Настройте стандартные маски для исключения файлов и папок при поиске. Все стандартные маски наследуются от параметра file.exclude.
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true
},
// Настройте для включения результатов поиска глобальных символов в файлы по запросу для Quick Open.
"search.quickOpen.includeSymbols": false,
// Обновить
// Настройте канал обновления, по которому вы будете получать обновления. После изменения значения необходим перезапуск.
"update.channel": "default",
// Git
// С поддержкой GIT
"git.enabled": true,
// Путь к исполняемому файлу GIT
"git.path": null,
// Включено ли автоматическое обновление
"git.autorefresh": true,
// Включено ли автоматическое получение.
"git.autofetch": true,
// Следует ли предупреждать о длинных сообщениях о фиксации.
"git.enableLongCommitWarning": true,
// Всегда разрешать Code управлять большими репозиториями.
"git.allowLargeRepositories": false,
// Подтвердите синхронизацию репозиториев Git.
"git.confirmSync": false,
// Управляет счетчиком эмблем Git.
"git.countBadge": "all",
// HTTP
// Используемый параметр прокси. Если он не задан, он будет взят из переменных среды http_proxy и https_proxy.
"http.proxy": "",
// Должен ли сертификат прокси-сервера проверяться по списку предоставленных ЦС.
"http.proxyStrictSSL": true,
// Значение, отправляемое как заголовок "Proxy-Authorization" для каждого сетевого запроса.
"http.proxyAuthorization": null,
// CSS
// Controls CSS validation and problem severities.
// Enables or disables all validations
"css.validate": true,
// When using a vendor-specific prefix make sure to also include all other vendor-specific properties
"css.lint.compatibleVendorPrefixes": "ignore",
// When using a vendor-specific prefix also include the standard property
"css.lint.vendorPrefix": "warning",
// Do not use duplicate style definitions
"css.lint.duplicateProperties": "ignore",
// Do not use empty rulesets
"css.lint.emptyRules": "warning",
// Import statements do not load in parallel
"css.lint.importStatement": "ignore",
// Do not use width or height when using padding or border
"css.lint.boxModel": "ignore",
// The universal selector (*) is known to be slow
"css.lint.universalSelector": "ignore",
// No unit for zero needed
"css.lint.zeroUnits": "ignore",
// @font-face rule must define 'src' and 'font-family' properties
"css.lint.fontFaceProperties": "warning",
// Hex colors must consist of three or six hex numbers
"css.lint.hexColorLength": "error",
// Invalid number of parameters
"css.lint.argumentsInColorFunction": "error",
// Unknown property.
"css.lint.unknownProperties": "warning",
// IE hacks are only necessary when supporting IE7 and older
"css.lint.ieHack": "ignore",
// Unknown vendor specific property.
"css.lint.unknownVendorSpecificProperties": "ignore",
// Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect
"css.lint.propertyIgnoredDueToDisplay": "warning",
// Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.
"css.lint.important": "ignore",
// Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.
"css.lint.float": "ignore",
// Selectors should not contain IDs because these rules are too tightly coupled with the HTML.
"css.lint.idSelector": "ignore",
// SCSS (Sass)
// Controls SCSS validation and problem severities.
// Enables or disables all validations
"scss.validate": true,
// When using a vendor-specific prefix make sure to also include all other vendor-specific properties
"scss.lint.compatibleVendorPrefixes": "ignore",
// When using a vendor-specific prefix also include the standard property
"scss.lint.vendorPrefix": "warning",
// Do not use duplicate style definitions
"scss.lint.duplicateProperties": "ignore",
// Do not use empty rulesets
"scss.lint.emptyRules": "warning",
// Import statements do not load in parallel
"scss.lint.importStatement": "ignore",
// Do not use width or height when using padding or border
"scss.lint.boxModel": "ignore",
// The universal selector (*) is known to be slow
"scss.lint.universalSelector": "ignore",
// No unit for zero needed
"scss.lint.zeroUnits": "ignore",
// @font-face rule must define 'src' and 'font-family' properties
"scss.lint.fontFaceProperties": "warning",
// Hex colors must consist of three or six hex numbers
"scss.lint.hexColorLength": "error",
// Invalid number of parameters
"scss.lint.argumentsInColorFunction": "error",
// Unknown property.
"scss.lint.unknownProperties": "warning",
// IE hacks are only necessary when supporting IE7 and older
"scss.lint.ieHack": "ignore",
// Unknown vendor specific property.
"scss.lint.unknownVendorSpecificProperties": "ignore",
// Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect
"scss.lint.propertyIgnoredDueToDisplay": "warning",
// Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.
"scss.lint.important": "ignore",
// Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.
"scss.lint.float": "ignore",
// Selectors should not contain IDs because these rules are too tightly coupled with the HTML.
"scss.lint.idSelector": "ignore",
// LESS
// Controls LESS validation and problem severities.
// Enables or disables all validations
"less.validate": true,
// When using a vendor-specific prefix make sure to also include all other vendor-specific properties
"less.lint.compatibleVendorPrefixes": "ignore",
// When using a vendor-specific prefix also include the standard property
"less.lint.vendorPrefix": "warning",
// Do not use duplicate style definitions
"less.lint.duplicateProperties": "ignore",
// Do not use empty rulesets
"less.lint.emptyRules": "warning",
// Import statements do not load in parallel
"less.lint.importStatement": "ignore",
// Do not use width or height when using padding or border
"less.lint.boxModel": "ignore",
// The universal selector (*) is known to be slow
"less.lint.universalSelector": "ignore",
// No unit for zero needed
"less.lint.zeroUnits": "ignore",
// @font-face rule must define 'src' and 'font-family' properties
"less.lint.fontFaceProperties": "warning",
// Hex colors must consist of three or six hex numbers
"less.lint.hexColorLength": "error",
// Invalid number of parameters
"less.lint.argumentsInColorFunction": "error",
// Unknown property.
"less.lint.unknownProperties": "warning",
// IE hacks are only necessary when supporting IE7 and older
"less.lint.ieHack": "ignore",
// Unknown vendor specific property.
"less.lint.unknownVendorSpecificProperties": "ignore",
// Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect
"less.lint.propertyIgnoredDueToDisplay": "warning",
// Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.
"less.lint.important": "ignore",
// Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.
"less.lint.float": "ignore",
// Selectors should not contain IDs because these rules are too tightly coupled with the HTML.
"less.lint.idSelector": "ignore",
// HTML
// Maximum amount of characters per line (0 = disable).
"html.format.wrapLineLength": 120,
// List of tags, comma separated, that shouldn't be reformatted. 'null' defaults to all tags listed at https://www.w3.org/TR/html5/dom.html#phrasing-content.
"html.format.unformatted": "a, abbr, acronym, b, bdo, big, br, button, cite, code, dfn, em, i, img, input, kbd, label, map, object, q, samp, script, select, small, span, strong, sub, sup, textarea, tt, var",
// Indent and sections.
"html.format.indentInnerHtml": false,
// Whether existing line breaks before elements should be preserved. Only works before elements, not inside tags or for text.
"html.format.preserveNewLines": true,
// Maximum number of line breaks to be preserved in one chunk. Use 'null' for unlimited.
"html.format.maxPreserveNewLines": null,
// Format and indent {{#foo}} and {{/foo}}.
"html.format.indentHandlebars": false,
// End with a newline.
"html.format.endWithNewline": false,
// List of tags, comma separated, that should have an extra newline before them. 'null' defaults to "head, body, /html".
"html.format.extraLiners": "head, body, /html",
// Configures if the built-in HTML language support suggests Angular V1 tags and properties.
"html.suggest.angular1": true,
// Configures if the built-in HTML language support suggests Ionic tags, properties and values.
"html.suggest.ionic": true,
// Configures if the built-in HTML language support suggests HTML5 tags, properties and values.
"html.suggest.html5": true,
// JSON
// Associate schemas to JSON files in the current project
"json.schemas": [],
// Markdown
// A list of URLs or local paths to CSS style sheets to use from the markdown preview. Relative paths are interpreted relative to the folder open in the explorer. If there is no open folder, they are interpreted relative to the location of the markdown file. All '\' need to be written as '\\'.
"markdown.styles": [],
// PHP
// Включена ли проверка PHP.
"php.validate.enable": true,
// Указывает на исполняемый файл PHP.
"php.validate.executablePath": null,
// Запускается ли Linter при сохранении или в типе.
"php.validate.run": "onSave",
// TypeScript
// Указывает путь к папке, содержащей файлы tsserver и lib*.d.ts, которые необходимо использовать.
"typescript.tsdk": null,
// Проверка наличия версии TypeScript в рабочей области
"typescript.check.workspaceVersion": true,
// Проверка отличия компилятора TypeScript глобальной установки (например, tsc) от используемой языковой службы TypeScript.
"typescript.check.tscVersion": true,
// Включение трассировки сообщений, отправленных на сервер TS
"typescript.tsserver.trace": "off",
// Дополните функции сигнатурами их параметров.
"typescript.useCodeSnippetsOnMethodSuggest": false,
// Включить или отключить проверку TypeScript
"typescript.validate.enable": true,
// Определяет метод обработки пробелов после разделителя-запятой
"typescript.format.insertSpaceAfterCommaDelimiter": true,
// Определяет метод обработки пробелов после точки с запятой в операторе for
"typescript.format.insertSpaceAfterSemicolonInForStatements": true,
// Определяет метод обработки пробелов после двоичного оператора
"typescript.format.insertSpaceBeforeAndAfterBinaryOperators": true,
// Определяет метод обработки пробелов после ключевых слов в операторе потока управления
"typescript.format.insertSpaceAfterKeywordsInControlFlowStatements": true,
// Определяет метод обработки пробелов после ключевого слова анонимной функции
"typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true,
// Определяет метод обработки пробелов после открытия и до закрытия непустых круглых скобок
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false,
// Определяет метод обработки пробелов после открытия и до закрытия непустых квадратных скобок
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
// Определяет, помещается ли открывающая фигурная скобка в новую строку для функций
"typescript.format.placeOpenBraceOnNewLineForFunctions": false,
// Определяет, помещается ли открывающая фигурная скобка в новую строку для управляющих блоков
"typescript.format.placeOpenBraceOnNewLineForControlBlocks": false,
// Включить или отключить проверку JavaScript
"javascript.validate.enable": true,
// Определяет метод обработки пробелов после разделителя-запятой
"javascript.format.insertSpaceAfterCommaDelimiter": true,
// Определяет метод обработки пробелов после точки с запятой в операторе for
"javascript.format.insertSpaceAfterSemicolonInForStatements": true,
// Определяет метод обработки пробелов после двоичного оператора
"javascript.format.insertSpaceBeforeAndAfterBinaryOperators": true,
// Определяет метод обработки пробелов после ключевых слов в операторе потока управления
"javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": true,
// Определяет метод обработки пробелов после ключевого слова анонимной функции
"javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true,
// Определяет метод обработки пробелов после открытия и до закрытия непустых круглых скобок
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false,
// Определяет метод обработки пробелов после открытия и до закрытия непустых квадратных скобок
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
// Определяет, помещается ли открывающая фигурная скобка в новую строку для функций
"javascript.format.placeOpenBraceOnNewLineForFunctions": false,
// Определяет, помещается ли открывающая фигурная скобка в новую строку для управляющих блоков
"javascript.format.placeOpenBraceOnNewLineForControlBlocks": false,
// Расширения
// Автоматически обновлять расширения
"extensions.autoUpdate": false,
// Внешний терминал
// Настройка терминала, который будет запущен в Windows.
"terminal.external.windowsExec": "%COMSPEC%",
// Настройка приложения терминала для запуска в OS X.
"terminal.external.osxExec": "Terminal.app",
// Настройка терминала для запуска в Linux.
"terminal.external.linuxExec": "xterm",
// Интегрированный терминал
// Путь оболочки, который используется терминалом в Linux.
"terminal.integrated.shell.linux": "bash",
// Аргументы командной строки, которые следует использовать в терминале Linux.
"terminal.integrated.shellArgs.linux": [],
// Путь оболочки, который используется терминалом в OS X.
"terminal.integrated.shell.osx": "sh",
// Аргументы командной строки, которые следует использовать в терминале OS X.
"terminal.integrated.shellArgs.osx": [],
// Путь оболочки, который используется терминалом в Windows. При работе с оболочкой, поставляемой с Windows (cmd, PowerShell или Bash на Ubuntu), укажите C:Windowssysnative вместо C:WindowsSystem32 для использования 64-разрядных версий.
"terminal.integrated.shell.windows": "C:\\WINDOWS\\system32\\cmd.exe",
// Определяет семейство шрифтов терминала, значение по умолчанию — editor.fontFamily.
"terminal.integrated.fontFamily": "",
// Определяет, будут ли включены лигатуры шрифтов для терминала.
"terminal.integrated.fontLigatures": false,
// Определяет размер шрифта (в пикселях) для терминала; значение по умолчанию — editor.fontSize.
"terminal.integrated.fontSize": 10,
// Определяет высоту строки терминала; это число умножается на размер шрифта терминала, что дает фактическую высоту строки в пикселях.
"terminal.integrated.lineHeight": 1.2,
// Управляет миганием курсора терминала.
"terminal.integrated.cursorBlinking": false,
// Управляет заданием переменных при запуске терминала, значение по умолчанию: "True" для OS X и "False" для других платформ.
"terminal.integrated.setLocaleVariables": false,
// Набор идентификаторов команд, настраиваемые сочетания клавиш которых не будут передаваться в оболочку, а вместо этого будут всегда обрабатываться Code. Это позволяет использовать настраиваемые сочетания клавиш, которые при обычных условиях были бы использованы оболочкой и работали бы так же, как если бы терминал не имел фокуса, например клавиши CTRL+P запускали бы Quick Open.
"terminal.integrated.commandsToSkipShell": [
"editor.action.toggleTabFocusMode",
"workbench.action.quickOpen",
"workbench.action.showCommands",
"workbench.action.terminal.clear",
"workbench.action.terminal.copySelection",
"workbench.action.terminal.focus",
"workbench.action.terminal.focusNext",
"workbench.action.terminal.focusPrevious",
"workbench.action.terminal.kill",
"workbench.action.terminal.new",
"workbench.action.terminal.paste",
"workbench.action.terminal.runSelectedText",
"workbench.action.terminal.scrollDown",
"workbench.action.terminal.scrollDownPage",
"workbench.action.terminal.scrollUp",
"workbench.action.terminal.scrollUpPage",
"workbench.action.terminal.toggleTerminal"
],
// Представление "Проблемы"
// Определяет, следует ли представлению "Проблемы" отображать файлы при их открытии
"problems.autoReveal": true,
// Телеметрия
// Разрешить отправку сведений об использовании и ошибках в корпорацию Майкрософт.
"telemetry.enableTelemetry": true,
// Разрешить отправку отчетов о сбоях в корпорацию Майкрософт.
// Чтобы этот параметр вступил в силу, требуется перезагрузка.
"telemetry.enableCrashReporter": true
}
|
|
Проверка кода перед отправкой
|
cargo fmt --all -- --check
cargo +nightly fmt --all -- --check --unstable-features
cargo clippy -- -D warnings
cargo test --features runtime-benchmarks -p node-minterest-runtime benchmarking
cargo check
cargo audit --json
|
|
Проверка кода перед git push
|
Проверка кода перед отправкой
cargo fmt --all -- --check
cargo fmt --all -- --check --color always 2>&1 | grep Diff -A 20| head -20
|
|
Пропустить форматирования кода
|
// skip auto formatting
#[rustfmt::skip]
|
|
|
//! Докуметация уровня модуля и линтер не будет "ругаться".
#![deny(
missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
unused_qualifications
)]
fn main(){
print!("hi");
}
|
|
|
Коллекция линтов для выявления распространенных ошибок и улучшения кода
Clippy выводит предупреждения и советы, но сам код не изменяет.
Вы можете использовать Clippy для обнаружения потенциальных проблем в вашем коде, таких как неэффективные конструкции, ошибки производительности или стиль кода, но исправления нужно вносить вручную на основе полученных рекомендаций.
Запуск
$ cargo clippy -- -D warnings
Запуск в папке example
$ cargo clippy -p example
|
|
Clippy выдает предупреждения об использовании Rust по различным категориям:
|
- Correctness (Корректность): предупреждает о распространенных ошибках программирования.
- Idiom: Предупреждает о конструкциях кода, которые не совсем соответствуют стандартному стилю Rust.
- Concision (Краткость): указывает на более компактные варианты кода.
- Performance (Производительность): предлагает альтернативы, позволяющие избежать ненужной обработки или распределения.
- Readability (Удобочитаемость): описывает изменения в коде, которые облегчат его чтение и понимание людьми.
|
|
clippy Lints in file lib.rs
rtc-stats-native/src/lib.rs
|
clippy Lints
#![doc = include_str!("../README.md")]
#![deny(
macro_use_extern_crate,
nonstandard_style,
rust_2018_idioms,
rustdoc::all,
trivial_numeric_casts
)]
#![forbid(non_ascii_idents)]
#![warn(
clippy::absolute_paths,
clippy::as_conversions,
clippy::as_ptr_cast_mut,
clippy::assertions_on_result_states,
clippy::branches_sharing_code,
clippy::clear_with_drain,
clippy::clone_on_ref_ptr,
clippy::collection_is_never_read,
clippy::create_dir,
clippy::dbg_macro,
clippy::debug_assert_with_mut_call,
clippy::decimal_literal_representation,
clippy::default_union_representation,
clippy::derive_partial_eq_without_eq,
clippy::else_if_without_else,
clippy::empty_drop,
clippy::empty_line_after_outer_attr,
clippy::empty_structs_with_brackets,
clippy::equatable_if_let,
clippy::empty_enum_variants_with_brackets,
clippy::exit,
clippy::expect_used,
clippy::fallible_impl_from,
clippy::filetype_is_file,
clippy::float_cmp_const,
clippy::fn_to_numeric_cast,
clippy::fn_to_numeric_cast_any,
clippy::format_push_string,
clippy::get_unwrap,
clippy::if_then_some_else_none,
clippy::imprecise_flops,
clippy::index_refutable_slice,
clippy::infinite_loop,
clippy::iter_on_empty_collections,
clippy::iter_on_single_items,
clippy::iter_over_hash_type,
clippy::iter_with_drain,
clippy::large_include_file,
clippy::large_stack_frames,
clippy::let_underscore_untyped,
clippy::lossy_float_literal,
clippy::manual_c_str_literals,
clippy::manual_clamp,
clippy::map_err_ignore,
clippy::mem_forget,
clippy::missing_assert_message,
clippy::missing_asserts_for_indexing,
clippy::missing_const_for_fn,
clippy::missing_docs_in_private_items,
clippy::multiple_inherent_impl,
clippy::multiple_unsafe_ops_per_block,
clippy::mutex_atomic,
clippy::mutex_integer,
clippy::needless_collect,
clippy::needless_pass_by_ref_mut,
clippy::needless_raw_strings,
clippy::nonstandard_macro_braces,
clippy::option_if_let_else,
clippy::or_fun_call,
clippy::panic_in_result_fn,
clippy::partial_pub_fields,
clippy::pedantic,
clippy::print_stderr,
clippy::print_stdout,
clippy::pub_without_shorthand,
clippy::ref_as_ptr,
clippy::rc_buffer,
clippy::rc_mutex,
clippy::read_zero_byte_vec,
clippy::readonly_write_lock,
clippy::redundant_clone,
clippy::redundant_type_annotations,
clippy::ref_patterns,
clippy::rest_pat_in_fully_bound_structs,
clippy::same_name_method,
clippy::semicolon_inside_block,
clippy::shadow_unrelated,
clippy::significant_drop_in_scrutinee,
clippy::significant_drop_tightening,
clippy::str_to_string,
clippy::string_add,
clippy::string_lit_as_bytes,
clippy::string_lit_chars_any,
clippy::string_slice,
clippy::string_to_string,
clippy::suboptimal_flops,
clippy::suspicious_operation_groupings,
clippy::suspicious_xor_used_as_pow,
clippy::tests_outside_test_module,
clippy::todo,
clippy::trailing_empty_array,
clippy::transmute_undefined_repr,
clippy::trivial_regex,
clippy::try_err,
clippy::undocumented_unsafe_blocks,
clippy::unimplemented,
clippy::uninhabited_references,
clippy::unnecessary_safety_comment,
clippy::unnecessary_safety_doc,
clippy::unnecessary_self_imports,
clippy::unnecessary_struct_initialization,
clippy::unneeded_field_pattern,
clippy::unused_peekable,
clippy::unwrap_in_result,
clippy::unwrap_used,
clippy::use_debug,
clippy::use_self,
clippy::useless_let_if_seq,
clippy::verbose_file_reads,
clippy::wildcard_enum_match_arm,
explicit_outlives_requirements,
future_incompatible,
let_underscore_drop,
meta_variable_misuse,
missing_abi,
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
semicolon_in_expressions_from_macros,
single_use_lifetimes,
unit_bindings,
unreachable_pub,
unsafe_op_in_unsafe_fn,
unstable_features,
unused_crate_dependencies,
unused_extern_crates,
unused_import_braces,
unused_lifetimes,
unused_macro_rules,
unused_qualifications,
unused_results,
variant_size_differences
)]
#![cfg_attr(feature = "mockable", allow(missing_docs))]
#![allow(
clippy::module_name_repetitions,
clippy::unimplemented,
clippy::unnecessary_safety_comment,
clippy::unnecessary_safety_doc,
unreachable_pub
)]
|
|
|
File .clippy.toml
# See full lints list at:
# https://rust-lang.github.io/rust-clippy/master/index.html
absolute-paths-allowed-crates = [
"backoff",
"fantoccini",
"log",
"proto",
"reqwest",
"syn",
"time",
"tonic",
"web_sys",
]
doc-valid-idents = [
"KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
"DirectX", "ECMAScript",
"GPLv2", "GPLv3", "GitHub", "GitLab",
"IPv4", "IPv6", "JavaScript", "NaN", "NaNs",
"OAuth", "OpenGL", "OpenSSH", "OpenSSL", "OpenStreetMap", "TrueType",
"iOS", "macOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW",
"BigInt64Array", "BigUint64Array",
"ConstrainDOMString", "ConstrainULong",
"DisplayMediaStreamConstraints",
"DOMHighResTimeStamp",
"getDisplayMedia", "getUserMedia", "gRPC",
"MediaDevices", "MediaDeviceKind", "MediaDeviceInfo",
"MediaStream", "MediaStreamConstraints",
"MediaStreamTrack", "MediaStreamTrackState",
"MediaTrackConstraints",
"MessageEvent",
"RESTful",
"RTCAudioSenderStats", "RTCSenderAudioTrackAttachmentStats",
"RTCConfiguration",
"RTCDataChannel",
"RTCDtlsTransport",
"RTCIceCandidate", "RTCIceCandidateInit", "RTCIceCandidateType",
"RTCIceServer", "RTCIceTransport",
"RTCPeerConnection", "RTCPeerConnectionIceEvent",
"RTCRtpCodecCapability",
"RTCRtpParameters",
"RTCRtpSender", "RTCSenderVideoTrackAttachmentStats",
"RTCRtpTransceiver", "RTCRtpTransceiverDirection",
"RTCSctpTransport",
"RTCSdpType",
"RTCStats", "RTCStatsReport",
"RTCTrackEvent",
"RTCVideoSenderStats",
"VideoFacingModeEnum",
"WebAPI", "WebDriver", "WebRTC", "WebSocket",
]
standard-macro-braces = [
{ name = "assert", brace = "(" },
{ name = "assert_eq", brace = "(" },
{ name = "assert_ne", brace = "(" },
{ name = "debug_assert", brace = "(" },
{ name = "debug_assert_eq", brace = "(" },
{ name = "debug_assert_ne", brace = "(" },
{ name = "format", brace = "(" },
{ name = "format_args", brace = "(" },
{ name = "format_ident", brace = "(" },
{ name = "json", brace = "(" },
{ name = "matches", brace = "(" },
{ name = "panic", brace = "(" },
{ name = "parse_quote", brace = "{" },
{ name = "print", brace = "(" },
{ name = "println", brace = "(" },
{ name = "quote", brace = "{" },
{ name = "quote_spanned", brace = "{" },
{ name = "Token", brace = "[" },
{ name = "vec", brace = "[" },
{ name = "write", brace = "(" },
{ name = "writeln", brace = "(" },
]
|
|
|
File Cargo.toml:
[package.metadata.clippy]
config-file = "clippy.toml"
forbid = ["non_ascii_idents"]
warn = ["future_incompatible", "unused_crate_dependencies"]
File Makefile:
##################
# Cargo commands #
##################
# Resolve Cargo project dependencies.
#
# Usage:
# make cargo [cmd=(<cargo-cmd>)]
all: cargo.fmt cargo.clippy
# Format Rust sources with rustfmt.
#
# Usage:
# make cargo.fmt [check=(no|yes)]
cargo.fmt:
cargo +nightly fmt --all $(if $(call eq,$(check),yes),-- --check,)
# Perform static code analysis with Clippy.
# Usage:
# make cargo.clippy
cargo.clippy:
cargo clippy --all-targets --all-features -- -D warnings
File src/_clippy_lints.rs:
#![deny(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications
)]
//#![doc = include_str!("../README.md")]
#![deny(
macro_use_extern_crate,
nonstandard_style,
rustdoc::all,
trivial_numeric_casts
)]
#![warn(
clippy::absolute_paths,
.....
variant_size_differences
)]
#![cfg_attr(feature = "mockable", allow(missing_docs))]
#![allow(
clippy::module_name_repetitions,
clippy::unimplemented,
clippy::unnecessary_safety_comment,
clippy::unnecessary_safety_doc,
unreachable_pub
)]
// TODO: Remove on next `derive_more` major version.
#![allow(clippy::uninlined_format_args, clippy::use_debug)]
File .clippy.toml:
# See full lints list at:
# https://rust-lang.github.io/rust-clippy/master/index.html
standard-macro-braces = [
{ name = "assert", brace = "(" },
{ name = "assert_eq", brace = "(" },
{ name = "assert_ne", brace = "(" },
{ name = "debug_assert", brace = "(" },
{ name = "debug_assert_eq", brace = "(" },
{ name = "debug_assert_ne", brace = "(" },
{ name = "format", brace = "(" },
{ name = "format_args", brace = "(" },
{ name = "format_ident", brace = "(" },
{ name = "json", brace = "(" },
{ name = "matches", brace = "(" },
{ name = "panic", brace = "(" },
{ name = "parse_quote", brace = "{" },
{ name = "print", brace = "(" },
{ name = "println", brace = "(" },
{ name = "quote", brace = "{" },
{ name = "quote_spanned", brace = "{" },
{ name = "Token", brace = "[" },
{ name = "vec", brace = "[" },
{ name = "write", brace = "(" },
{ name = "writeln", brace = "(" },
]
File src/main.rs*:
//! Documentstion
/// linting module for clean code
mod _clippy_lints;
fn main() {
println!("Hello, world!");
}
Add clippy lints to file src/_clippy_lints.rs
#![deny(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications
)]
//#![doc = include_str!("../README.md")]
#![deny(
macro_use_extern_crate,
nonstandard_style,
rustdoc::all,
trivial_numeric_casts
)]
#![warn(
clippy::absolute_paths,
clippy::as_conversions,
clippy::as_ptr_cast_mut,
clippy::assertions_on_result_states,
clippy::branches_sharing_code,
clippy::clear_with_drain,
clippy::clone_on_ref_ptr,
clippy::collection_is_never_read,
clippy::create_dir,
clippy::dbg_macro,
clippy::debug_assert_with_mut_call,
clippy::decimal_literal_representation,
clippy::default_union_representation,
clippy::derive_partial_eq_without_eq,
clippy::else_if_without_else,
clippy::empty_drop,
clippy::empty_line_after_outer_attr,
clippy::empty_structs_with_brackets,
clippy::equatable_if_let,
clippy::empty_enum_variants_with_brackets,
clippy::exit,
clippy::expect_used,
clippy::fallible_impl_from,
clippy::filetype_is_file,
clippy::float_cmp_const,
clippy::fn_to_numeric_cast,
clippy::fn_to_numeric_cast_any,
clippy::format_push_string,
clippy::get_unwrap,
clippy::if_then_some_else_none,
clippy::imprecise_flops,
clippy::index_refutable_slice,
clippy::infinite_loop,
clippy::iter_on_empty_collections,
clippy::iter_on_single_items,
clippy::iter_over_hash_type,
clippy::iter_with_drain,
clippy::large_include_file,
clippy::large_stack_frames,
clippy::let_underscore_untyped,
clippy::lossy_float_literal,
clippy::manual_str_repeat,
clippy::manual_clamp,
clippy::map_err_ignore,
clippy::mem_forget,
clippy::missing_assert_message,
clippy::missing_asserts_for_indexing,
clippy::missing_const_for_fn,
clippy::missing_docs_in_private_items,
clippy::multiple_inherent_impl,
clippy::multiple_unsafe_ops_per_block,
clippy::mutex_atomic,
clippy::mutex_integer,
clippy::needless_collect,
clippy::needless_pass_by_ref_mut,
clippy::needless_raw_strings,
clippy::nonstandard_macro_braces,
clippy::option_if_let_else,
clippy::or_fun_call,
clippy::panic_in_result_fn,
clippy::partial_pub_fields,
clippy::pedantic,
clippy::print_stderr,
clippy::print_stdout,
clippy::pub_without_shorthand,
clippy::ptr_as_ptr,
clippy::rc_buffer,
clippy::rc_mutex,
clippy::read_zero_byte_vec,
clippy::readonly_write_lock,
clippy::redundant_clone,
clippy::redundant_type_annotations,
clippy::ref_patterns,
clippy::rest_pat_in_fully_bound_structs,
clippy::same_name_method,
clippy::semicolon_inside_block,
clippy::shadow_unrelated,
clippy::significant_drop_in_scrutinee,
clippy::significant_drop_tightening,
clippy::str_to_string,
clippy::string_add,
clippy::string_lit_as_bytes,
clippy::string_lit_chars_any,
clippy::string_slice,
clippy::string_to_string,
clippy::suboptimal_flops,
clippy::suspicious_operation_groupings,
clippy::suspicious_xor_used_as_pow,
clippy::tests_outside_test_module,
clippy::todo,
clippy::trailing_empty_array,
clippy::transmute_undefined_repr,
clippy::trivial_regex,
clippy::try_err,
clippy::undocumented_unsafe_blocks,
clippy::unimplemented,
clippy::uninhabited_references,
clippy::unnecessary_safety_comment,
clippy::unnecessary_safety_doc,
clippy::unnecessary_self_imports,
clippy::unnecessary_struct_initialization,
clippy::unneeded_field_pattern,
clippy::unused_peekable,
clippy::unwrap_in_result,
clippy::unwrap_used,
clippy::use_debug,
clippy::use_self,
clippy::useless_let_if_seq,
clippy::verbose_file_reads,
clippy::wildcard_enum_match_arm,
explicit_outlives_requirements,
let_underscore_drop,
meta_variable_misuse,
missing_abi,
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
semicolon_in_expressions_from_macros,
single_use_lifetimes,
unit_bindings,
unreachable_pub,
unsafe_op_in_unsafe_fn,
unstable_features,
unused_extern_crates,
unused_import_braces,
unused_lifetimes,
unused_macro_rules,
unused_qualifications,
unused_results,
variant_size_differences
)]
#![cfg_attr(feature = "mockable", allow(missing_docs))]
#![allow(
clippy::module_name_repetitions,
clippy::unimplemented,
clippy::unnecessary_safety_comment,
clippy::unnecessary_safety_doc,
unreachable_pub
)]
// TODO: Remove on next `derive_more` major version.
#![allow(clippy::uninlined_format_args, clippy::use_debug)]
|
|
|
Установка
$ rustup component add clippy
$ rustup component add clippy-preview
|
|
Настроить поведение некоторых линтов
Файл .clippy.toml
|
Файл .clippy.toml:
avoid-breaking-exported-api = false
disallowed-names = ["toto", "tata", "titi"]
cyclomatic-complexity-threshold = 30
|
|
|
#![deny(clippy::single_match, clippy::box_vec)]
#![allow(clippy::single_match, clippy::box_vec)]
#![warn(clippy::single_match, clippy::box_vec)]
#![forbid(clippy::single_match, clippy::box_vec)]
clippy::all(все , что по умолчанию: все категории ниже , за исключением nursery, pedanticи cargo)
clippy::correctness (код, который является просто неправильным или очень очень бесполезным, по умолчанию вызывает серьезные ошибки)
clippy::style (код, который должен быть написан более идиоматическим способом)
clippy::complexity (код, который делает что-то простое, но сложным образом)
clippy::perf (код, который можно написать быстрее)
clippy::pedantic (строчки довольно строгие, по умолчанию отключены)
clippy::nursery (новые линты, которые еще не совсем готовы, по умолчанию отключены)
clippy::cargo (проверка по грузовому манифесту, по умолчанию отключена)
|
|
|
Запустите Clippy
$ cargo run --bin cargo-clippy --manifest-path=path_to_clippys_Cargo.toml
$ cargo clippy
# если вы хотите, чтобы при сборке предупреждений задание на сборку не выполнялось, используйте
$ cargo clippy -- -D warnings
# для того, чтобы также проверить тесты и функции ящиков не по умолчанию, используйте
$ cargo clippy --all-targets --all-features -- -D warnings
$ cargo test
# автоматическое исправление
$ cargo clippy --fix
# запуск в папке example
$ cargo clippy -p example
# запуск в папке example без учета проверки зависимостей
$ cargo clippy -p example -- --no-deps
Умалчивания Clippy линтов:
fn test(unix_millis:u64)->i64{
i64::from(unix_millis)
}
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
fn test(unix_millis:u64)->i64{
unix_millis as i64
}
|
|
|
# Установка
$ rustup component add rustfmt
$ rustup component add rustfmt --toolchain nightly
# Форматирование всех файлов
$ cargo fmt --all
$ cargo fmt --all -- --check --color always 2>&1 | grep Diff -A 20| head -20
$ cargo +nightly fmt --all -- --check --unstable-features
# Вывод в stdout для предварительного просмотра
$ cargo +nightly fmt -- --emit stdout
# Форматирование отдельных файлов
$ cargo install rustfmt
$ rustfmt src/main.rs --check
$ rustfmt src/main.rs src/lib.rs
$ rustfmt --edition 2021 -- */*.rs
# Проверка вывода форматирования
$ echo "fn main() {}" | rustfmt
--check покажет что будет форматировать
--all отформатируйте все пакеты, а также их локальные зависимости на основе пути
|
|
|
# See full list at:
# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md
max_width = 80
format_strings = false
imports_granularity = "Crate"
normalize_comments = true
wrap_comments = true
reorder_impl_items = true
use_try_shorthand = true
error_on_line_overflow = true
error_on_unformatted = true
unstable_features = true
|
|
rust-lang.github.io/rustfmt
Переопределить настройки по умолчанию в файле .rustfmt.toml
|
Файл .rustfmt.toml
Параметры по умолчанию вывести в файл rustfmt.toml
$ rustfmt --print-config default rustfmt.toml
Список всех параметров
$ rustfmt --help=config
max_width = 100 # Максимальная ширина каждой строки
hard_tabs = false # Использовать символы табуляции для отступа, пробелы для выравнивания
tab_spaces = 4 # Количество пробелов на вкладке
newline_style = 'Auto' # [Auto|Windows|Unix|Native] Окончания строк Unix или Windows
use_small_heuristics = 'Default' # [Off | Max | Default] Использовать ли другое форматирование для элементов и выражений, если они удовлетворяют эвристическому понятию 'small'
reorder_imports = true # Изменение порядка импорта и извлечения ящиков в алфавитном порядке
reorder_modules = true # Изменить порядок операторов в алфавитном порядке в группе
remove_nested_parens = true # Удалить вложенные парены
edition = '2015' # [2015 | 2018] Редакция парсера (RFC 2052)
merge_derives = true # Объединить несколько `#[derive(...)]` в один
use_try_shorthand = false # Заменить использование попытки! макрос по? стенография
use_field_init_shorthand = false # Использовать сокращение поля инициализации, если это возможно
force_explicit_abi = true # Всегда печатать abi для внешних элементов
|
|
Запрет форматирования rustfmt
#[rustfmt::skip]
|
Чтобы запретить rustfmt форматировать макрос или атрибут, используйте:
#[rustfmt::skip::macros(target_macro_name)] или
#[rustfmt::skip::attributes(target_attribute_name)]
#![rustfmt::skip::attributes(custom_attribute)]
#[custom_attribute(formatting , here , should , be , Skipped)]
#[rustfmt::skip::macros(html)]
fn main() {
let macro_result1 = html! { <div>Hello</div>}.to_string();
}
|
|
|
# Project configuration for rustfmt Rust code formatter.
# See full list of configurations at:
# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md
max_width = 80
format_strings = false
imports_granularity = "Crate"
format_code_in_doc_comments = true
format_macro_matchers = true
use_try_shorthand = true
error_on_line_overflow = true
error_on_unformatted = true
unstable_features = true
|
|
|
rust-analyzer — это библиотека для семантического анализа кода Rust по мере его изменения во времени.
Функции IntelliSense предоставляются языковым сервером Rust, rust-analyzer, предоставляющий подсказки для отображения предполагаемых типов, возвращаемых значений, описания, автозавершения, исправления ...
Возможно, вам потребуется установить набор инструментов GCC через build-essential
$ sudo apt-get install build-essential
|
|
|
rust-analyzer постоянно анализирует код и показывает лампочку 💡 в vscode, если может предложить исправление.
rust-analyzer — это “мозг” Rust для IDE.
Он не компилятор, а языковой сервер (Language Server Protocol, LSP),
который анализирует твой код в фоне, строит AST, типы, зависимости, референсы
и предоставляет IDE функции вроде:
- автодополнение (completion)
- переход к определению
- быстрые исправления (quick fix)
- автоматические рефакторинги
- подсказки по типам, doc, usages, и т.п.
|
|
|
Вот некоторые вещи, rust-analyzer которые являются просто тестами:
- Форматирование кода (самое распространённое — не нужна лишняя куча YAML в CI, можно раскошелиться на форматер из теста).
- Проверка отсутствия в истории коммитов слияний и обучение новых участников навыкам выживания в git.
- Сбор руководства из специально отформатированных комментариев к документации по базе кода.
- Проверка того, что база кода действительно достаточно хорошо документирована.
- Обеспечение совместимости лицензий зависимостей.
- Обеспечение линейности операций высокого уровня по размеру входных данных. Синтаксис — выделите синтетический файл размером 1, 2, 4, 8, 16 килобайт, запустите линейную регрессию, проверьте, чтобы результат выглядел как линия, а не парабола.
|
|
Настройки расширения
@ext:rust-lang.rust-analyzer
|
Глобальный файл ~/.config/Code/User/settings.json
Локальный файл .vscode/settings.json
{
"editor.minimap.enabled": false,
"window.zoomLevel": -1,
"files.autoSave": "afterDelay",
"rust-analyzer.cargo.allFeatures": true,
"tabnine.experimentalAutoImports": true,
"editor.codeActionsOnSave": {
},
"rust-analyzer.procMacro.ignored": {
},
"rust-analyzer.procMacro.enable": true, # поддержка derive-макросов (serde, async_trait, и др.)
"rust-analyzer.procMacro.server": null,
"debug.allowBreakpointsEverywhere": true,
"rust-analyzer.inlayHints.bindingModeHints.enable": true,
"editor.inlayHints.enabled": "on", # это показывает типы прямо в коде
"rust-analyzer.inlayHints.typeHints": true,
"rust-analyzer.checkOnSave.command": "clippy", # анализирует код Clippy при сохранении
"rust-analyzer.check.command": "check", # будет запускаться cargo clippy при сохранении файла
"window.enableMenuBarMnemonics": false
}
${userHome} - путь к домашней папке пользователя
${workspaceFolder} - путь к папке, открытой в VS Code
${workspaceFolderBasename} — имя папки, открытой в VS Code, без косых черт (/)
${file} - текущий открытый файл
${fileWorkspaceFolder} - рабочая папка текущего открытого файла
${relativeFile} - текущий открытый файл относительноworkspaceFolder
${relativeFileDirname} - имя каталога текущего открытого файла относительноworkspaceFolder
${fileBasename} - базовое имя текущего открытого файла
${fileBasenameNoExtension} - базовое имя текущего открытого файла без расширения.
${fileExtname} - расширение текущего открытого файла
${fileDirname} - путь к папке с текущим открытым файлом
${fileDirnameBasename} - имя папки текущего открытого файла
${cwd} — текущий рабочий каталог исполнителя задач при запуске VS Code.
${lineNumber} - номер текущей выделенной строки в активном файле
${selectedText} - текущий выделенный текст в активном файле
${execPath} — путь к исполняемому файлу VS Code.
${defaultBuildTask} — имя задачи сборки по умолчанию.
${pathSeparator} — символ, используемый операционной системой для разделения компонентов в путях к файлам.
|
|
|
Функции навигации по коду доступны в контекстном меню редактора.
- Перейти к определению
F12 — перейти к исходному коду определения типа.
- Peek Definition
Ctrl+Shift+F10 — открыть окно Peek с определением типа.
- Перейти к ссылкам
Shift+F12 — показать все ссылки для типа.
- Показать иерархию вызовов
Shift+Alt+H — показать все вызовы от функции или к ней.
|
|
интеграция clippy в rust-analyzer
|
Линтер rustc, включенный по умолчанию, обнаруживает основные ошибки Rust, но вы можете использовать clippy, чтобы получить больше линтов.
Чтобы включить интеграцию clippy в rust-analyzer, измените параметр Rust-analyzer > Check: Command ( rust-analyzer.check.command) на значение clippy по умолчанию check.
Расширение rust-analyzer теперь будет запускаться cargo clippy при сохранении файла и отображать обрезанные предупреждения и ошибки непосредственно в редакторе и представлении «Проблемы»
Глобальный файл ~/.config/Code/User/settings.json:
{
"rust-analyzer.check.command": "check",
}
|
|
|
|
|
cargo clone <crate> получить исходный код crate
cargo-clone
|
cargo install cargo-clone
|
|
cargo bloat что занимает большую часть места в вашем исполняемом файле.
cargo-bloat
|
cargo install cargo-bloat
% cargo bloat --release -n 10
Compiling ...
Analyzing target/release/cargo-bloat
File .text Size Crate Name
0.9% 7.1% 27.0KiB cargo_bloat cargo_bloat::main
0.8% 5.7% 21.4KiB cargo_bloat cargo_bloat::process_crate
0.3% 2.3% 8.6KiB [Unknown] read_line_info
0.3% 2.1% 7.9KiB std std::sys::unix::process::process_common::Command::capture_env
0.3% 2.1% 7.8KiB json json::parser::Parser::parse
0.2% 1.7% 6.5KiB [Unknown] elf_add
0.2% 1.7% 6.3KiB std __rdos_backtrace_dwarf_add
0.2% 1.3% 5.0KiB std <rustc_demangle::legacy::Demangle as core::fmt::Display>::fmt
0.2% 1.3% 4.9KiB std std::sys_common::backtrace::_print
0.2% 1.3% 4.8KiB std core::num::flt2dec::strategy::dragon::format_shortest
9.8% 73.5% 278.0KiB And 932 smaller methods. Use -n N to show more.
13.3% 100.0% 378.0KiB .text section size, the file size is 2.8MiB
|
|
cargo profiler callgrind
подкоманда cargo для профилирования ваших приложений.
cargo-profiler
|
cargo install cargo-profiler
|
|
|
|
|
|
|
|
|
Дополнительные правила, не обрабатываемые Rustfmt и Clippy, описаны ниже.
Декларации импорта, реэкспорта и модулей
Их следует разделить на следующие упорядоченные разделы:
-
объявления модулей (mod и pub mode ключевые слова);
-
импортирует разделы ( use ключевое слово):
- std/core импорт;
- импорт внешних ящиков;
- этот ящик импортирует (начинается с
crate::);
- импорт из родительских модулей (начинается с
super::);
- импорт из подмодулей (начинается с
self::).
- реэкспорт разделов ( pub use ключевое слово):
std/core реэкспорт;
-
реэкспорт внешних ящиков;
- этот ящик реэкспортируется (начинается с
crate::);
- реэкспорт из родительских модулей (начинается с
super::);
- реэкспорт из подмодулей (начинается с
self::).
-
Пустая строка между этими разделами до и после обязательна.
Внутри каждого раздела и внутри каждого утверждения элементы должны быть отсортированы в алфавитном порядке.
Если импортированная черта не используется напрямую , ее необходимо подчеркнуть импортированную ( as _), чтобы не загрязнять пространство имен текущего модуля.
Импортируйте несколько элементов в одном операторе из одного места вместо использования нескольких операторов (обычно это контролируется merge_imports опцией Rustfmt ).
|
|
|
✅
//! Some module.
mod private_stuff;
pub mod public_stuff;
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc};
use futures::Future as _;
use serde::{Deserialize, Serialize};
use crate::core::{DynFuture, DynStream};
use super::event;
use self::private_stuff::util;
pub use postgres::Type;
pub use crate::core::util::UnfoldingStream;
pub use super::props::Error;
pub use self::public_stuff::*;
const LIMIT: u8 = 100;
|
|
Неправильные примеры
Нет пустых строк:
|
❌
//! Some module.
mod private_stuff;
pub mod public_stuff;
❌
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc};
use futures::Future as _;
use serde::{Deserialize, Serialize};
use crate::core::{DynFuture, DynStream};
use super::event;
use self::private_stuff::util;
pub use postgres::Type;
pub use crate::core::util::UnfoldingStream;
pub use super::props::Error;
pub use self::public_stuff::*;
❌
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc};
use futures::Future as _;
use serde::{Deserialize, Serialize};
use crate::core::{DynFuture, DynStream};
use super::event;
use self::private_stuff::util;
pub use postgres::Type;
pub use crate::core::util::UnfoldingStream;
pub use super::props::Error;
pub use self::public_stuff::*;
|
|
|
Атрибуты объявлений должны быть отсортированы в алфавитном порядке. Элементы внутри атрибута также должны быть отсортированы в алфавитном порядке (так же, как они сортируются с помощью оператора Rustfmt Inside use).
✅ Правильный пример
#[allow(clippy::mut_mut)]
#[derive(smart_default::SmartDefault, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
struct User {
#[serde(default)]
id: u64,
}
```>
❌ Неправильные примеры
#[serde(deny_unknown_fields)]
#[derive(smart_default::SmartDefault, Debug, Deserialize, Serialize)]
#[allow(clippy::mut_mut)]
struct User {
id: u64,
}
</div></td>
<td id="cargo_c20cc58fde0417b9_other"><div class="cell-content" contenteditable="true"></div></td>
</tr>
<tr id="cargo_a639db11c2b3eca3">
<td id="cargo_a639db11c2b3eca3_topic"><div class="cell-content" contenteditable="true">
#### Утилита cargo-make
</div></td>
<td id="cargo_a639db11c2b3eca3_content"><div class="cell-content" contenteditable="true">
cargo-make — это утилита для автоматизации задач в экосистеме Rust.
Она расширяет возможности стандартного Cargo, позволяя описывать и запускать сложные сценарии сборки, тестирования, деплоя и любых других действий через конфигурацию.
</div></td>
<td id="cargo_a639db11c2b3eca3_other"><div class="cell-content" contenteditable="true"></div></td>
</tr>
<tr id="cargo_65ef4111493fed9b">
<td id="cargo_65ef4111493fed9b_topic"><div class="cell-content" contenteditable="true"></div></td>
<td id="cargo_65ef4111493fed9b_content"><div class="cell-content" contenteditable="true">
`cargo-make` — это **утилита для автоматизации задач** в экосистеме Rust.
Она расширяет возможности стандартного Cargo, позволяя описывать и запускать сложные сценарии сборки, тестирования, деплоя и любых других действий через конфигурацию.
**Основные моменты**
* **Аналог Makefile**, но для Rust и в экосистеме Cargo.
* Работает через файл `Makefile.toml`, где ты описываешь задачи (tasks).
* Позволяет:
* запускать последовательность команд (pipelines),
* использовать условные шаги,
* переопределять стандартные команды Cargo (`cargo build`, `cargo test` и т.д.),
* интегрироваться с другими инструментами (docker, npm, bash-скрипты и пр.).
---
**Пример**
`Makefile.toml`:
```toml
[tasks.build-release]
command = "cargo"
args = ["build", "--release"]
[tasks.test-all]
command = "cargo"
args = ["test", "--all"]
[tasks.ci-flow]
dependencies = ["build-release", "test-all"]
Теперь можно вызвать:
cargo make ci-flow
и он выполнит сначала build-release, потом test-all.
Когда полезен
- Если стандартного
cargo build/test/run недостаточно.
- Для CI/CD пайплайнов.
- Для локальной автоматизации (генерация кода, линтинг, запуск бенчмарков и т.д.).
- Чтобы не плодить bash-скрипты и Makefile, а держать всё в экосистеме Rust.
|
|
|
|
|
|
|
|
|
|
|
|
|
|