Управление зависимостями в Rust с Cargo

от автора

Привет!

Cargo — это хороший менеджер пакетов Rust, который берет на себя тяжелую работу по управлению зависимостями, сборке проекта, тестированию и многому другому.

Cargo

Cargo – это официальный менеджер пакетов и система сборки для Rust. Он был разработан для упрощения работы с кодом на Rust, обеспечивая единообразную сборку проектов, управление зависимостями, ну и плюсом тестирование. Как npm для Node.js или Maven для Java – Cargo играет аналогичную роль для Rust.

Основные команды Cargo:

  1. cargo new

    • Создает новый проект Rust.

    • Пример: cargo new my_project создает новый проект с именем my_project.

  2. cargo build

    • Компилирует текущий проект и все его зависимости.

    • Варианты: cargo build --release для создания оптимизированной сборки.

  3. cargo run

    • Компилирует и запускает исполняемый файл проекта.

    • Можно передать аргументы: cargo run -- arg1 arg2.

  4. cargo test

    • Запускает тесты, определенные в проекте.

    • Можно запускать определенные тесты: cargo test test_name.

  5. cargo check

    • Быстро проверяет код проекта на наличие ошибок, не производя полной компиляции.

  6. cargo clean

    • Удаляет сгенерированные артефакты сборки.

  7. cargo doc

    • Генерирует документацию для текущего проекта и его зависимостей.

  8. cargo update

    • Обновляет зависимости проекта, указанные в Cargo.lock, до последних версий, совместимых с Cargo.toml.

  9. 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *