Как стать автором
Обновить
720.8
OTUS
Цифровые навыки от ведущих экспертов

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

Уровень сложностиПростой
Время на прочтение6 мин
Количество просмотров3.4K

Привет!

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 можно найти в полном каталоге.

Теги:
Хабы:
Всего голосов 15: ↑9 и ↓6+4
Комментарии4

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS