Всем привет.

В первой части мы сделали простейший прототип, работающий с PostgreSQL.

При этом мы прописали все параметры соединения с базой прямо в коде. Давайте теперь вынесем их в конфигурационный файл.

В качестве формата конфигурации я выбрал INI — достаточно простой и известный формат.



Первым делом нам нужно найти библиотеку для работы с INI-файлами.

Тут нам поможет crates.io — централизованное хранилище контейнеров Rust. Идём туда, вбиваем в поиске «ini», и первая же ссылка ведёт на нужную нам библиотеку: rust-ini.

Использовать её, судя по примеру на главной, достаточно просто. Попробуем:
Код
extern crate ini;
...
use ini::Ini;

fn params() -> (ConnectParams, SslMode) {
    let conf = Ini::load_from_file(".phonebookrc").unwrap();
    let general = conf.general_section();

    let host = general.get("host").unwrap();
    let port = general.get("port").unwrap();
    let sslmode = general.get("sslmode").unwrap();
    let dbname = general.get("dbname").unwrap();
    let user = general.get("user").unwrap();
    let pass = general.get("pass").unwrap();

    let sslmode_ = match sslmode.as_ref() {
        "disable" => SslMode::None,
        "enable" => unimplemented!(),
        _ => panic!("Wrong sslmode"),
    };

    let params = ConnectParams {
        target: ConnectTarget::Tcp(host.to_owned()),
        port: Some(FromStr::from_str(port).unwrap()),
        user: Some(UserInfo {
            user: user.to_owned(),
            password: Some(pass.to_owned()),
        }),
        database: Some(dbname.to_owned()),
        options: vec![],
    };
    (params, sslmode_)
}

fn main() {
    let (params, sslmode) = params();
...


Стоит пояснить несколько моментов.

Мы делаем

    let s = match sslmode.as_ref() {

чтобы sslmode не было перемещено внутрь match. В противном случае, мы не смогли бы использовать его дальше.

unimplemented!() — это макрос, который используют, чтобы показать, что определённая функциональность не реализована. Он вызывает панику при достижении данной строки.

panic!() — макрос, непосредственно вызывающий панику текущего потока. Его можно вызвать с форматной строкой и аргументами, чтобы напечатать своё сообщение.

В конце мы создаём структуру с параметрами соединения

    let params = ConnectParams {

Все поля инициализируются, как обычно, кроме двух:
        port: Some(FromStr::from_str(port).unwrap()),

Тут мы используем метод from_str типажа FromStr, чтобы разобрать целое число из строки. Эта операция возвращает Result.

        options: vec![],

Здесь же мы используем макрос инициализации вектора: он создаёт вектор, а затем делает несколько раз v.push(...).

В конце функции мы просто пишем

    (params, sslmode_)

чтобы вернуть из неё кортеж из 2 элементов. Обратите внимание на отсутствие точки с запятой.

Однако, если сейчас мы попробуем собрать программу, нас постигнет неудача:

$ cargo build
   Compiling bufstream v0.1.1
   Compiling debug-builders v0.1.0
   Compiling gcc v0.3.6
   Compiling rustc-serialize v0.3.14
   Compiling phf_shared v0.7.3
   Compiling libc v0.1.8
   Compiling byteorder v0.3.10
   Compiling phf v0.7.3
   Compiling log v0.3.1
   Compiling rand v0.3.8
   Compiling rust-ini v0.6.0 (https://github.com/zonyitoo/rust-ini/#0b3a3894)
   Compiling time v0.1.26
/home/mkpankov/.multirust/toolchains/stable/cargo/git/checkouts/rust-ini-4a9e7dbb298b5764/master/src/lib.rs:48:1: 48:16 error: #[feature] may not be used on the stable release channel
/home/mkpankov/.multirust/toolchains/stable/cargo/git/checkouts/rust-ini-4a9e7dbb298b5764/master/src/lib.rs:48 #![feature(io)]
                                                                                                               ^~~~~~~~~~~~~~~
error: aborting due to previous error
   Compiling rust-crypto v0.2.31
Build failed, waiting for other jobs to finish...
Could not compile `rust-ini`.

Компилятор говорит о том, что возможность «io» не может быть использована в стабильном компиляторе. Хм.

Как можно видеть, «feature(io)» используем не мы, а сам rust-ini. И в каком же компиляторе она тогда может быть использована? Ответ, конечно же — в нестабильном Rust.

Стоит заметить, что в подобные моменты проще сходить в чат (хотя бы в наш русскоязычный) и спросить, что происходит и что делать. Документация по отключаемым возможностям есть, но она не совсем поспевает за реальным положением дел.

Ладно, и что теперь? Нужно переустанавливать компилятор только ради этого? К сожалению, да, но, к счастью, делать это нужно сделать только один раз.

Познакомьтесь с multirust.

Этот инструмент управляет версиями компилятора и позволяет мгновенно переключаться между ними, а также упрощает обновление.

Устанавливаем его (предварительно стоит удалить уже установленный Rust):

$ curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh

Теперь мы можем установить сами компиляторы и сказать, что нашему проекту нужен ночной компилятор:

$ multirust update
...
$ cd rust-phonebook
$ multirust override nightly
multirust: using existing install for 'nightly'
multirust: override toolchain for '/home/mkpankov/rust-phonebook.finished' set to 'nightly'

Теперь попробуем пересобрать наш проект:

$ cargo build
...
   Compiling rust-phonebook v0.1.0 (file:///home/mkpankov/rust-phonebook.finished)
src/main.rs:10:5: 10:12 warning: struct field is never used: `id`, #[warn(dead_code)] on by default
src/main.rs:10     id: i32,
                   ^~~~~~~
$

Всё собралось!

multirust делает работу гораздо удобнее. Новые проекты всё же лучше начинать на стабильном компиляторе, и переключаться только по необходимости — ситуация с нестабильными возможностями такова, что они нужны далеко не всем проектам. А обновление всех сборок делается с ним всего одной командой «multirust update».

Ложка дёгтя здесь в том, что multirust на данный момент не работает на Windows. Но установить несколько компиляторов на Windows вам ничего не помешает — они по-умолчанию ставятся в разные места.

На сегодня всё. Теперь вы знаете, где искать библиотеки, и что делать, если им требуются нестабильные возможности.

Комментарии (9)


  1. voidnugget
    24.09.2015 19:02

    Кусок сорцов на картинке под катом… доставил.


  1. grossws
    24.09.2015 19:51

    curl -sf raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh
    Как всегда, способ установки прекрасен.

    Ложка дёгтя здесь в том, что multirust на данный момент работает только на Windows. Но установить несколько компиляторов на Windows вам ничего не помешает — они по-умолчанию ставятся в разные места.
    Не распарсил. Так работает только на win или не работает только на win? Особенно, в контексте использования sh.


    1. mkpankov
      24.09.2015 23:06

      Как всегда, способ установки прекрасен.
      Не могу сказать, что разделяю ваши опасения по поводу его небезопасности. Тут даже sudo на весь скрипт не запрашивается — оно используется внутри, если нужно, и скрипт об этом предупреждает. Можно передать --prefix и тогда оно вообще не понадобится, просто придётся окружение трогать тогда.

      Не распарсил. Так работает только на win или не работает только на win? Особенно, в контексте использования sh.
      Спасибо, поправил.


    1. Googolplex
      25.09.2015 20:09

      В некоторых дистрибутивах линукса есть пакеты multirust, например, в арче это multirust из AUR. В Homebrew на маках, насколько я помню, формула для multirust тоже есть.


      1. grossws
        25.09.2015 20:15

        Ну, это некоторое лукавство. AUR — это user repository и пакеты из него не являются сколь-нибудь доверенными. Поэтому при установке из AUR обычно, как минимум, просматривается PKGBUILD и install-скрипт. Оно принципиально не отличается от того, чтобы сделать curl/wget в файл, посмотреть и после запускать.

        Кто ментейнит базу brew и какая там модель доверия — не знаю.


        1. Googolplex
          25.09.2015 21:19

          Ну да, в этом вы правы. Тем не менее, это не curl | sh, который к тому же ставит файлы без ведома менеджера пакетов (хотя конкретно в случае multirust всё достаточно неплохо, и там есть унинсталлер).


  1. mkpankov
    24.09.2015 23:11
    +3

    Пара обновлений, произошедших буквально за несколько последних часов:

    • В multirust добавили поддержку Windows через MinGW
    • Автор rust-ini выпилил единственную используемую нестабильную возможность, так что теперь данная библиотека работает на stable


  1. Googolplex
    25.09.2015 20:08
    +1

    Вместо FromStr::from_str(x) лучше использовать x.parse(). А вообще — спасибо за статьи, здорово, что подобные туториалы появляются и на русском тоже.

    Кстати, а почему INI а не TOML, в общем-то, практически общепринятый в коммьюнити Rust?


    1. mkpankov
      26.09.2015 13:09

      Спасибо.

      INI — наверное, потому, что лично мне он более знаком и кажется менее навороченным, чем TOML.