Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 3 additions & 52 deletions .github/workflows/rust-ci.yml → .github/workflows/linux.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (c) 2026 l5yth
# SPDX-License-Identifier: Apache-2.0

name: Rust CI
name: Linux

on:
push:
Expand All @@ -10,56 +10,7 @@ on:
branches: [main]

jobs:
ci:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt

- name: Cargo check
run: cargo check --all --all-features

- name: Check formatting
run: cargo fmt --all -- --check

- name: Cargo test
run: cargo test --all --all-features --verbose

- name: Cargo clippy
run: cargo clippy --all-targets --all-features -- -D warnings

coverage:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview

- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov

- name: Generate lcov coverage
run: cargo llvm-cov --workspace --lcov --output-path lcov.info

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov.info
fail_ci_if_error: false

archlinux-package:
pkgbuild:
runs-on: ubuntu-latest
container:
image: archlinux:latest
Expand All @@ -78,7 +29,7 @@ jobs:
chown -R builder:builder "${GITHUB_WORKSPACE}"
su - builder -c "cd '${GITHUB_WORKSPACE}/packaging/archlinux' && sed -i \"s|^source=.*$|source=(\\\"lsu::git+https://github.com/${GITHUB_REPOSITORY}.git#commit=${GITHUB_SHA}\\\")|\" PKGBUILD && makepkg --syncdeps --noconfirm --cleanbuild --clean --install"

gentoo-ebuild:
ebuild:
runs-on: ubuntu-latest
container:
image: gentoo/stage3:latest
Expand Down
60 changes: 60 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright (c) 2026 l5yth
# SPDX-License-Identifier: Apache-2.0

name: Rust

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt

- name: Cargo check
run: cargo check --all --all-features

- name: Check formatting
run: cargo fmt --all -- --check

- name: Cargo test
run: cargo test --all --all-features --verbose

- name: Cargo clippy
run: cargo clippy --all-targets --all-features -- -D warnings

coverage:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview

- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov

- name: Generate lcov coverage
run: cargo llvm-cov --workspace --lcov --output-path lcov.info

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov.info
fail_ci_if_error: false
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ name = "lsu"
version = "0.1.0"
edition = "2024"
license = "Apache-2.0"
description = "Terminal UI for systemd services and their journal"
readme = "README.md"
repository = "https://github.com/l5yth/lsu"
homepage = "https://github.com/l5yth/lsu"
keywords = ["systemd", "tui", "linux"]
categories = ["command-line-utilities"]

[dependencies]
anyhow = "1"
Expand Down
27 changes: 25 additions & 2 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
Object form, made available under the Licen2se, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).

Expand Down Expand Up @@ -175,4 +175,27 @@

END OF TERMS AND CONDITIONS

Copyright 2026 l5yth
APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright (C) 2026 l5yth

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
42 changes: 34 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,43 @@

# lsu

`lsu` is a Rust terminal UI for viewing `systemd` service units and their latest log line.
`lsu` is a Rust terminal UI for viewing `systemd` service units and their journal.

![lsu terminal UI screenshot](assets/images/lsu-tui-overview.png)

## Dependencies

- Linux system with `systemd`
- `systemctl` and `journalctl` available in `PATH`
- Rust toolchain (Rust 2021 edition, Cargo)
- any GNU/Linux system with `systemd`
- `systemctl` and `journalctl` available in `$PATH` obviosly
- Some current Rust stable toolchain (Rust 2024 edition, Cargo)

Core crates: `ratatui`, `crossterm`, `serde`, `serde_json`, `anyhow`.

## Installation

Helpers exist for Arch and Gentoo-based systems but you can install also
via crates.io or from source directly.

### Archlinux

See [PKGBUILD](./packaging/archlinux/PKGBUILD)

### Gentoo

See [lsu-9999.ebuild](./packaging/gentoo/app-misc/lsu/lsu-9999.ebuild)

### Cargo Crates

```bash
cargo install lsu
```

### From Source

Build from source:

```bash
git clone <repo-url>
git clone https://github.com/l5yth/lsu.git
cd lsu
cargo build --release
```
Expand All @@ -34,7 +53,7 @@ Run the built binary:
Or run directly in development:

```bash
cargo run --
cargo run --release --
```

## Usage
Expand All @@ -43,6 +62,7 @@ cargo run --
Usage: lsu [OPTIONS]

Show systemd services in a terminal UI.
By default only loaded and active units are shown.

Options:
-a, --all Shorthand for --load all --active all --sub all
Expand All @@ -59,19 +79,25 @@ Examples:
lsu
lsu --all
lsu --all --refresh 5
lsu -r 0
lsu --load failed
lsu --active inactive
lsu --sub exited
lsu --load loaded --active inactive --sub dead
```

In-app keys:

- `q`: quit
- `r`: refresh now
- `↑` / `↓`: move selection in service unit list
- `l` or `enter`: open detailed logs for selected service
- Log view: `↑` / `↓` scroll logs, `b` or `esc` return to list

## Development

```bash
cargo check
cargo test
cargo test --all --all-features --verbose
cargo fmt --all
cargo clippy --all-targets --all-features -D warnings
```
40 changes: 40 additions & 0 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright (C) 2026 l5yth

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

//! App entry module.
//!
//! In test builds we expose a lightweight stub to keep unit-test coverage
//! focused on deterministic logic modules rather than terminal runtime I/O.

#[cfg(not(test))]
pub mod tui;

#[cfg(not(test))]
pub use self::tui::run;

#[cfg(test)]
/// Test-only runner stub.
pub fn run() -> anyhow::Result<()> {
Ok(())
}

#[cfg(test)]
mod tests {
#[test]
fn test_run_stub_is_ok() {
assert!(super::run().is_ok());
}
}
Loading