
Привет!
Cargo — это хороший менеджер пакетов Rust, который берет на себя тяжелую работу по управлению зависимостями, сборке проекта, тестированию и многому другому.
Cargo
Cargo – это официальный менеджер пакетов и система сборки для Rust. Он был разработан для упрощения работы с кодом на Rust, обеспечивая единообразную сборку проектов, управление зависимостями, ну и плюсом тестирование. Как npm для Node.js или Maven для Java – Cargo играет аналогичную роль для Rust.
Основные команды Cargo:
-
cargo new-
Создает новый проект Rust.
-
Пример:
cargo new my_projectсоздает новый проект с именемmy_project.
-
-
cargo build-
Компилирует текущий проект и все его зависимости.
-
Варианты:
cargo build --releaseдля создания оптимизированной сборки.
-
-
cargo run-
Компилирует и запускает исполняемый файл проекта.
-
Можно передать аргументы:
cargo run -- arg1 arg2.
-
-
cargo test-
Запускает тесты, определенные в проекте.
-
Можно запускать определенные тесты:
cargo test test_name.
-
-
cargo check-
Быстро проверяет код проекта на наличие ошибок, не производя полной компиляции.
-
-
cargo clean-
Удаляет сгенерированные артефакты сборки.
-
-
cargo doc-
Генерирует документацию для текущего проекта и его зависимостей.
-
-
cargo update-
Обновляет зависимости проекта, указанные в
Cargo.lock, до последних версий, совместимых сCargo.toml.
-
-
cargo publish-
Публикует пакет в crates.io, официальном реестре пакетов Rust.
-
Итак, основные возможности:
Cargo автоматически скачивает нужные библиотеки (которые называются «crates» в Rust) и их зависимости. Cargo компилирует код, используя правильные версии зависимостей и параметры сборки.
Cargo позволяет публиковать свои crates на crates.io.
Установим и настроим
Cargo поставляется вместе с Rust, поэтому, если уже установлен Rust, то Cargo уже установлен:
rustc --version
Если видно версию Rust, значит, все ок
Настроим рабочее окружение:
Создадим каталог, в котором будем работать (папку). Переходим в рабочий каталог с помощью терминала и выполняем команду инициализации проекта:
[dependencies] my_library = "^1.2.3"
Это крейтит файл Cargo.toml и каталог src с файлом main.rs, где в будущем будем писать код. Через консоль можно создать каталог таким образом:
$ cargo new hello_world --bin
Открываем файл Cargo.toml в текстовом редакторе. В этом файле будем указывать зависимости и настройки проекта.
Файл Cargo.toml
Секция [dependencies] используется для определения основных зависимостей проекта. Эти зависимости будут установлены при сборке проекта для всех конфигураций:
[package] name = "my_project" version = "0.1.0" edition = "2018" [dependencies] my_library = "1.2.3"
Секция [dev-dependencies] используется для зависимостей, которые нужны только во время разработки, например, для юнит-тестирования. Они не будут включены в финальную сборку проекта:
[dev-dependencies] test_framework = "0.5.0"
Секция [build-dependencies] используется для зависимостей, которые нужны только во время сборки проекта:
[build-dependencies] codegen_tool = "0.1.0"
Можно так же определить зависимость как optional. Например:
[dependencies] serde = { version = "1.0", optional = true }
serde — это сериализационная библиотека, которую мы хотим использовать только в определенных условиях.
Features представляют собой именованный набор зависимостей и настроек. В Cargo.toml можно определить features следующим образом:
[features] json-support = ["serde"]
feature, названная json-support, включает в себя опциональную зависимость serde.
Когда определена feature, можно использовать атрибуты условной компиляции в коде, чтобы включать или исключать части кода.
#[cfg(feature = "json-support")] fn parse_json(data: &str) -> Result<MyStruct, serde_json::Error> { serde_json::from_str(data) } #[cfg(not(feature = "json-support"))] fn parse_json(_data: &str) -> Result<MyStruct, ()> { Err(()) }
Функция parse_json будет работать с сериализацией JSON только если включена feature json-support.
Можно создавать features, которые зависят от других features:
[features] better-logging = ["log", "json-support"]
better-logging включает себя зависимость log и feature json-support.
Иногда нужно, чтобы определенные features исключали друг друга:
#[cfg(all(feature = "use-mysql", not(feature = "use-postgres")))] fn setup_database() { // Настройка для MySQL } #[cfg(all(feature = "use-postgres", not(feature = "use-mysql")))] fn setup_database() { // Настройка для PostgreSQL }
Этот код обеспечивает, что будет использоваться только одна из баз данных.
Cargo с CI/CD
В CI основной акцент на автоматизацию тестирования и сборки. CD фокусируется на автоматизации процесса развертывания после тестирования.
Файл Cargo.lock должен быть включен репозиторий, особенно для исполняемых проектов, чтобы гарантировать согласованность зависимостей на всех этапах CI/CD.
Настройка .gitlab-ci.yml для GitLab CI:
stages: - build - test build_job: stage: build script: - cargo build --release test_job: stage: test script: - cargo test
Настройка GitHub Actions
name: Rust CI on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Build run: cargo build --verbose - name: Run tests run: cargo test --verbose
Интеграция с Docker в GitLab CI
deploy_job: stage: deploy script: - cargo build --release - docker build -t my-rust-app . - docker push my-rust-app
Можно настроить автоматические проверки кода с использованием cargo clippy и cargo fmt, например файл будет определять процесс CI, который запускается при каждом push и pull request в master ветку:
name: Rust CI on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build-and-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install Rust uses: actions-rs/toolchain@v1 with: toolchain: stable profile: minimal override: true - name: Cache Cargo dependencies uses: actions/cache@v2 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Check Code Style with cargo fmt uses: actions-rs/cargo@v1 with: command: fmt args: -- --check - name: Lint with cargo clippy uses: actions-rs/cargo@v1 with: command: clippy args: -- -D warnings - name: Build uses: actions-rs/cargo@v1 with: command: build args: --verbose - name: Run tests uses: actions-rs/cargo@v1 with: command: test args: --verbose
actions/checkout@v2позволяет workflow использовать код. actions-rs/toolchain@v1: устанавливает определенную версию Rust toolchain. actions-rs/cargo@v1 шаги используют cargo для выполнения различных команд: cargo fmt -- --checkпроверяет стиль кода. cargo clippy -- -D warningsзапускает linter clippy для выявления предупреждений и ошибок в коде. cargo build и cargo test собирают проект и выполняют тесты соответственно.
Ограничения на версии
Ограничения на версии позволяют указать диапазон версий, которые хотим использовать. Примеры ограничений:
-
=: Использовать только конкретную версию.-
Пример:
my_library = "1.2.3"
-
-
>=: Использовать версии, равные или новее указанной.-
Пример:
my_library >= "1.2.3"
-
-
<=:Использовать версии, равные или старше указанной.-
Пример:
my_library <= "2.0.0"
-
-
~: Использовать версии, которые совместимы с указанной версией, но не изменяют MAJOR версию.-
Пример:
my_library = "~1.2.0"
-
-
^: Использовать версии, которые совместимы с указанной версией, но не изменяют MAJOR и MINOR версии.-
Пример:
my_library = "^1.2.0"
-
-
!=: Исключить определенные версии.-
Пример:
my_library != "1.0.0"
-
SemVer — это соглашение о формате версий библиотек и зависимостей, которое позволяет определить, какие изменения были внесены в новой версии и какие возможности могут быть нарушены для разработчиков, использующих эту зависимость. SemVer включает в себя три компонента версии: MAJOR, MINOR и PATCH.
MAJOR (главный номер): увеличивается, когда вносятся обратно несовместимые изменения API.
MINOR (минорный номер): увеличивается, когда добавляются новые функциональные возможности, но с сохранением обратной совместимости. Новые функции могут быть добавлены, но существующий код должен продолжать работать.
PATCH (патч-номер): увеличивается, когда вносятся исправления ошибок или изменения, которые сохраняют обратную совместимость, означает, что внесенные изменения исправляют ошибки, но не меняют функциональность.
Предположим, у нас есть зависимость в файле Cargo.toml следующего вида:
[dependencies] my_library = "1.2.3"
MAJOR (главный номер) равен 1. Это означает, что мы используем главную версию этой библиотеки.
MINOR (минорный номер) равен 2. Это указывает на минорные обновления с новыми функциональными возможностями, но с обратной совместимостью.
PATCH (патч-номер) равен 3. Это обновление исправлений и изменений с обратной совместимостью.
Примеры ограничений:
Использовать версии от 1.2.3 до 2.0.0 (включительно):
my_library >= "1.2.3, <= 2.0.0"
Использовать версии совместимые с 1.2.0, но не изменяющие MAJOR версию:
my_library = "~1.2.0"
Использовать версии совместимые с 1.2.0, но не изменяющие MAJOR и MINOR версии:
my_library = "^1.2.0"
После указания зависимостей и их ограничений в Cargo.toml, можно выпнолить команду cargo update в командной строке в корневой директории проекта. Cargo обновит зависимости в соответствии с указанными ограничениями и загрузит подходящие версии.
В продолжение темы хочу напомнить про бесплатные вебинары от экспертов рынка про безопасный unsafe Rust и про то, как Rust побуждает использовать композицию.
А больше курсов от экспертов OTUS можно найти в полном каталоге.
ссылка на оригинал статьи https://habr.com/ru/articles/788642/
Добавить комментарий