---
title: TUI の Feed Viewer を自宅の Raspbery Pi で 公開するまで
tags:  #rust #nix  
author: [ymgyt](https://www.docswell.com/user/ymgyt)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/DEYGY8NYEM.jpg?width=480
description: Nix で Rust の開発環境から CI,Deploy まで管理する
published: October 10, 24
canonical: https://www.docswell.com/s/ymgyt/Z1RY8R-syndicationd
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/DEYGY8NYEM.jpg)

TUI の Feed Viewer を自宅の Raspbery Pi で
公開するまで
Nix で Rust の開発環境から CI,Deploy まで管理する
山口 裕太
· 2024‑03‑05


# Page. 2

![Page Image](https://bcdn.docswell.com/page/VJNGPQXR78.jpg)

自己紹介
[speaker]
name
= &quot;Yamaguchi Yuta&quot;
github = &quot;https://github.com/ymgyt&quot;
blog
= &quot;https://blog.ymgyt.io/&quot;


# Page. 3

![Page Image](https://bcdn.docswell.com/page/YE9W3D8ZE3.jpg)

会社紹介
[company]
name
tech_blog
= &quot;FRAIM Inc.&quot;
= &quot;https://zenn.dev/p/fraim&quot;


# Page. 4

![Page Image](https://bcdn.docswell.com/page/GE8NM3ZY7D.jpg)

作成したツールのライフサイクルについて
話すこと
• TUI の Feed Viewer を作った
• Nix で開発環境,CI,Deploy を管理した
• Release では cargo‑release と cargo‑dist を利
用した
• Trace,Metrics,Logs は OpenTelemetry を利用し
た


# Page. 5

![Page Image](https://bcdn.docswell.com/page/LELP3VD97R.jpg)

Rust で TUI
Feed の Entry 一覧


# Page. 6

![Page Image](https://bcdn.docswell.com/page/4JM4DGPV7W.jpg)

Rust で TUI
Feed の一覧


# Page. 7

![Page Image](https://bcdn.docswell.com/page/PJRW4Z1W79.jpg)

Rust の TUI
library
1. crossterm(cross platform terminal library)
2. ratatui(tui widgets library)


# Page. 8

![Page Image](https://bcdn.docswell.com/page/PEXP29YV7X.jpg)

Rust の TUI
library
Netﬂix が公開した eBPF の tui tool でも ratatui
が使われている


# Page. 9

![Page Image](https://bcdn.docswell.com/page/3EKDMP35JD.jpg)

let (header, widths, rows) = self.entry_rows(cx);
ratatui
let entries = Table::new(rows, widths)
.header(header.style(cx.theme.entries.header))
.column_spacing(2)
.style(cx.theme.entries.background)
.highlight_symbol(ui::TABLE_HIGHLIGHT_SYMBOL)
.highlight_style(cx.theme.entries.selected_entry)
.highlight_spacing(HighlightSpacing::WhenSelected);
Table や List 等の基本的な widget が用意されている


# Page. 10

![Page Image](https://bcdn.docswell.com/page/L73RYXG1J5.jpg)

crossterm
async fn event_loop&lt;S&gt;(&amp;mut self, input: &amp;mut S)
where
S: Stream&lt;Item = io::Result&lt;CrosstermEvent&gt;&gt; +
Unpin,
{
loop {
tokio::select! {
biased;
Some(event) = input.next() =&gt; { }
_ = self.background_jobs =&gt; { }
};
}
複数の入力も async で書ける


# Page. 11

![Page Image](https://bcdn.docswell.com/page/87DY521K7G.jpg)

crossterm
fn handle_terminal_event(&amp;mut self, event:
std::io::Result&lt;CrosstermEvent&gt;) {
match event.unwrap() {
CrosstermEvent::Resize(columns, rows) =&gt; { }
CrosstermEvent::Key(key) =&gt; match key.code {
KeyCode::Tab =&gt; { },
KeyCode::Char(&#039;j&#039;) =&gt; { },
}
}
}
Key 入力の処理も簡単


# Page. 12

![Page Image](https://bcdn.docswell.com/page/VJP6G1Q3E8.jpg)

Nix による開発
環境の管理
この Rust の project を Nix で管理しました


# Page. 13

![Page Image](https://bcdn.docswell.com/page/2EV36Y5N7Q.jpg)

そもそも Nix とは
Nix による開発
環境の管理
&gt; A build tool, package manager, and
programming language
https://zero‑to‑nix.com/concepts/nix


# Page. 14

![Page Image](https://bcdn.docswell.com/page/57G3N965JL.jpg)

Nix で管理する
と何がうれし
いのか
• 開発環境を Nix で管理できる


# Page. 15

![Page Image](https://bcdn.docswell.com/page/4EQ5QW4LJP.jpg)

{
Nix による開発
環境の管理
inputs.nixpkgs.url = &quot;github:NixOS/nixpkgs/
release-23.11&quot;;
outputs = { self, nixpkgs, ... }:
let dev_packages = with pkgs; [
graphql-client
git-cliff
cargo-release
cargo-dist
oranda
];
in { devShells.default = craneLib.devShell {
packages = dev_packages;
};
});
}
project root の ﬂake.nix で開発時の依存を宣言


# Page. 16

![Page Image](https://bcdn.docswell.com/page/KJ49NKQ571.jpg)

nix develop
nix develop を実行すると宣言した package が
PATH に入った状態で開発環境(shell)が立ち上が
る


# Page. 17

![Page Image](https://bcdn.docswell.com/page/LE1K5XP2JG.jpg)

Nix で管理する
と何がうれし
いのか
• 開発環境を Nix で管理できる
• CI を Nix で管理できる


# Page. 18

![Page Image](https://bcdn.docswell.com/page/GEWD5N22J2.jpg)

CI でも nix
develop
name: CI
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: nix develop .#ci --acceptflake-config --command just check
• install action が不要
• 開発環境と同一 version


# Page. 19

![Page Image](https://bcdn.docswell.com/page/47ZGN3D4E3.jpg)

Nix で管理する
と何がうれし
いのか
• 開発環境を Nix で管理できる
• CI を Nix で管理できる
• Cache を Nix で管理できる


# Page. 20

![Page Image](https://bcdn.docswell.com/page/YJ6Y8X1G7V.jpg)

Nix で管理する
と何がうれし
いのか
/nix/store/3sn5pij1hjvdlnq468c0m8vz8nibhrdccargo-release-0.25.0/bin/cargo-release の
3sn5pij1hjvdlnq468c0m8vz8nibhrdc が入力に対
応する hash となっており、cache があれば
build せずに binary を取得できる


# Page. 21

![Page Image](https://bcdn.docswell.com/page/GJ5G9X4XJ4.jpg)

Nix で管理する
と何がうれし
いのか
cache から取得


# Page. 22

![Page Image](https://bcdn.docswell.com/page/9E2Y2XVQER.jpg)

Nix で管理する
と何がうれし
いのか
name: CI
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v25
with:
github_access_token:
${{ secrets.GITHUB_TOKEN }}
- uses: cachix/cachix-action@v14
with:
name: syndicationd
authToken: &#039;${{ secrets.CACHIX_AUTH_TOKEN }}&#039;
- run: nix develop .#ci --accept-flake-config -command just check
cache を設定した最終的な CI の workﬂow
local と CI で同じ cache の仕組みを利用できる


# Page. 23

![Page Image](https://bcdn.docswell.com/page/D7YGY83Y7M.jpg)

Nix で管理する
と何がうれし
いのか
• 開発環境を Nix で管理できる
• CI を Nix で管理できる
• Cache を Nix で管理できる
• Install を Nix で管理できる


# Page. 24

![Page Image](https://bcdn.docswell.com/page/VENGPQVRJ8.jpg)

Nix で管理する
と何がうれし
いのか
nix run で一時的に実行したり
nix proﬁle で install もできる
Mac と Linux で同じ package 管理ができる


# Page. 25

![Page Image](https://bcdn.docswell.com/page/Y79W3D6Z73.jpg)

Nix で管理する
と何がうれし
いのか
• 開発環境を Nix で管理できる
• CI を Nix で管理できる
• Cache を Nix で管理できる
• Install を Nix で管理できる
• Deploy を Nix で管理できる


# Page. 26

![Page Image](https://bcdn.docswell.com/page/G78NM3PYJD.jpg)

Nix で systemd
service を宣言
{ config, pkgs, syndicationd, ... }:
let
syndPkg = syndicationd.packages.&quot;${pkgs.system}&quot;.syndapi;
in {
config = {
systemd.services.synd-api = {
description = &quot;Syndicationd api&quot;;
wantedBy = [ &quot;multi-user.target&quot; ];
environment = {
SYND_LOG = &quot;INFO&quot;;
};
serviceConfig = {
ExecStart = &quot;${syndPkg}/bin/synd-api&quot;
};
};
};
}
https://github.com/ymgyt/mynix/blob/main/homeserver/
modules/syndicationd/default.nix


# Page. 27

![Page Image](https://bcdn.docswell.com/page/L7LP3V19JR.jpg)

Nix で Deploy
deploy‑rs で NixOS が入った RaspberryPi に
deploy


# Page. 28

![Page Image](https://bcdn.docswell.com/page/4EM4DGWVJW.jpg)

Nix で管理する
と何がうれし
いのか
• 開発環境を Nix で管理できる
• CI を Nix で管理できる
• Cache を Nix で管理できる
• Install を Nix で管理できる
• Deploy を Nix で管理できる


# Page. 29

![Page Image](https://bcdn.docswell.com/page/PERW4ZYWJ9.jpg)

cargo でも公開
したい
とはいえ、cargo install もしたい


# Page. 30

![Page Image](https://bcdn.docswell.com/page/P7XP29GVJX.jpg)

cargo publish するには以下が必要
cargo でも公開
したい
• Cargo.toml の package.version の bump
• Workspace 内に依存 package がある場合は合
わせて bump
• CHANGELOG の生成
• git の tagging
これを workspace の member crate ごとに実施
する必要がある


# Page. 31

![Page Image](https://bcdn.docswell.com/page/37KDMP45ED.jpg)

cargo でも公開
したい
cargo‑release が全て面倒をみてくれる


# Page. 32

![Page Image](https://bcdn.docswell.com/page/LJ3RYXL1E5.jpg)

cargo release --package foo patch を実行する
cargo でも公開
したい
と
• foo package の Cargo.toml package.version を
bump(v0.1.2 ‑&gt; v0.1.3)
• foo に依存している workspace 内の package
の dependencies.foo.version を bump
• 設定に定義した replace 処理を実施
(CHANGELOG の[unreleased] ‑&gt; [v0.1.3])
• git の commit, tagging, push
• cargo publish


# Page. 33

![Page Image](https://bcdn.docswell.com/page/8JDY52NKJG.jpg)

homebrew で
も公開したい
brew install もしたい


# Page. 34

![Page Image](https://bcdn.docswell.com/page/VEP6G15378.jpg)

専用の repository(homebrew-syndicationd)に以下
のような記述が必要
homebrew で
も公開したい
class Synd &lt; Formula
desc &quot;terminal feed viewer&quot;
version &quot;0.1.6&quot;
on_macos do
on_arm do
url &quot;https://github.com/ymgyt/syndicationd/releases/download/syndterm-v0.1.6/synd-term-aarch64-apple-darwin.tar.gz&quot;
sha256
&quot;c02751ba979720a2a24be09e82d6647a6283f28290bbe9c2fb79c03cb6dbb979&quot;
end
on_intel do
url &quot;https://github.com/ymgyt/syndicationd/releases/download/syndterm-v0.1.6/synd-term-x86_64-apple-darwin.tar.gz&quot;
sha256
&quot;3be81f95c68bde17ead0972df258c1094b28fd3d2a96c1a05261dba2326f31d8&quot;
end
end


# Page. 35

![Page Image](https://bcdn.docswell.com/page/27V36YPNJQ.jpg)

homebrew で
も公開したい
cargo‑dist が全て面倒をみてくれる


# Page. 36

![Page Image](https://bcdn.docswell.com/page/5JG3N9P5EL.jpg)

cargo dist init を実行して質問に答えると
cargo‑dist が
やってくれる
• Cargo.toml の[workspace.metadata.dist]に設
定が追加
• .github/workflows/release.yml を生成


# Page. 37

![Page Image](https://bcdn.docswell.com/page/47Q5QW2LEP.jpg)

cargo dist init を実行して質問に答えると
cargo‑dist が
やってくれる
• Cargo.toml の[workspace.metadata.dist]に設
定が追加
• .github/workflows/release.yml を生成
この状態で cargo‑release で git tag を push する
と


# Page. 38

![Page Image](https://bcdn.docswell.com/page/KE49NKL5J1.jpg)

cargo‑dist が
やってくれる
Github release と各種 installer が作成される


# Page. 39

![Page Image](https://bcdn.docswell.com/page/L71K5XL2EG.jpg)

cargo‑dist が
やってくれる
cargo‑dist が以下をやってくれる(設定次第)
• 各種 platform(aarch64,x86 の darwin,windows,
linux gnu,musl)向けの binary 生成
• shell,powershell の install script 作成
• homebrew 用 repository の更新(push 権限を渡
す必要あり)


# Page. 40

![Page Image](https://bcdn.docswell.com/page/G7WD5NV2E2.jpg)

cargo‑dist が
やってくれる
cargo dist plan を実行すると CI で実行される
内容を確認できる
workﬂow yaml にベタ書きされているのではな
く、cargo dist plan の出力を参照するように
なっている


# Page. 41

![Page Image](https://bcdn.docswell.com/page/4JZGN34473.jpg)

cargo‑dist が
やってくれる
cargo‑release と一緒に使うことが想定されてお
り
cargo publish と git の tag push までが cargo‑
release
それ以降の配布処理が cargo‑dist という役割分
担がよかったので使ってみた


# Page. 42

![Page Image](https://bcdn.docswell.com/page/YE6Y8X3GJV.jpg)

監視もしたい
Deploy と Release ができたので次に監視がした
い


# Page. 43

![Page Image](https://bcdn.docswell.com/page/GE5G9XLXE4.jpg)

監視もしたい
Deploy と Release ができたので次に監視がした
い
OpenTelemetry を使う


# Page. 44

![Page Image](https://bcdn.docswell.com/page/972Y2XLQ7R.jpg)

Rust で
OpenTelemetry
Rust で tracing を使っている場合
tracing-opentelemetry と opentelemetry_sdk を
使うと
Logs, Traces, Metrics を取得できる


# Page. 45

![Page Image](https://bcdn.docswell.com/page/DJYGY8QYJM.jpg)

Rust で
OpenTelemetry
公開している Grafana dashboard


# Page. 46

![Page Image](https://bcdn.docswell.com/page/V7NGPQKRE8.jpg)

Rust で
OpenTelemetry
Entry 取得時の Trace


# Page. 47

![Page Image](https://bcdn.docswell.com/page/YJ9W3DVZJ3.jpg)

まとめ
Nix,cargo‑{release,dist},OpenTelemetry で
楽しいツール開発


# Page. 48

![Page Image](https://bcdn.docswell.com/page/GJ8NM34YED.jpg)

各種 link
• cargo‑release
• cargo‑dist
• deploy‑rs
• syndicationd
• raspi nix conﬁguration


