tlc: guard install loop with file-existence check to skip missing binaries
This commit is contained in:
@@ -1284,6 +1284,55 @@ Honest empty-state pattern: don't fake flag values.
|
||||
based on those thresholds.
|
||||
4. **`hwmon` scheme daemon** on Redox — see v1.9 forward work.
|
||||
|
||||
#### v1.11 Network Tab (sysfs + if_inet6) (2026-06-20)
|
||||
|
||||
Per the user's "v1.11 = Network tab (Recommended)" directive, v1.11
|
||||
ships the **Network tab** as the 7th tab in the multi-view system.
|
||||
|
||||
| Item | Status |
|
||||
|------|--------|
|
||||
| `network.rs` (NEW, 203 LoC) — `NetInterface` + `NetInfo` + IPv6 parser | ✅ |
|
||||
| `TabId::Network` variant + cycle order | ✅ |
|
||||
| Hotkey `7` jumps to Network tab | ✅ |
|
||||
| `render_network_panel()` with State/MAC/MTU/Speed/RX/TX/IPv6 | ✅ |
|
||||
| Per-tick refresh at 7-tick modulus (3.5 sec cadence) | ✅ |
|
||||
| 7 unit tests (format_bytes + empty state + zero traffic) | ✅ all pass |
|
||||
| 24 total tests (5 bench + 12 sensor + 7 network) | ✅ all pass |
|
||||
|
||||
**Data sources opened at runtime** (when sysfs/net present):
|
||||
- `/sys/class/net/<iface>/operstate` — link state (up/down/unknown)
|
||||
- `/sys/class/net/<iface>/speed` — link speed in Mbps
|
||||
- `/sys/class/net/<iface>/address` — MAC address
|
||||
- `/sys/class/net/<iface>/mtu` — MTU
|
||||
- `/sys/class/net/<iface>/statistics/{rx,tx}_{bytes,packets,errors,dropped}`
|
||||
- `/proc/net/if_inet6` — IPv6 addresses with scope encoding
|
||||
|
||||
**Linux host smoke test** (Manjaro, 6 interfaces: enp14s0, lo, moscow,
|
||||
tailscale0, tun0, wlp13s0):
|
||||
- Real link state: enp14s0=down, wlp13s0=up, others=unknown
|
||||
- Real traffic stats: lo (686 MiB), wlp13s0 (38/237 GiB), tailscale0 (2/11 GiB)
|
||||
- Real IPv6 addresses with correct scope encoding (link for fe80::, compat for fd7a/fd01)
|
||||
- MAC shown only when not 00:00:00:00:00:00 (enp14s0, wlp13s0 only)
|
||||
- Speed shown only when >0 (tun0=10000 Mbps)
|
||||
|
||||
**v1.11 source state**: ~5150 LoC across **17 modules** (was ~4945/16 in
|
||||
v1.10). New module: `network.rs` (203 lines). 24 unit tests total.
|
||||
|
||||
Cross-compiled binary: 3.8 MB stripped Redox ELF
|
||||
(SHA256 `05cca57693110e06393273a3247b159b8fc681a8ebc0cdd5a2386f33a1ebb407`).
|
||||
|
||||
**Refresh cadence**: 7-tick modulus (3.5 sec at POLL_MS=500). Coprime
|
||||
with all existing moduli (3, 4, 5) — LCM of {3,4,5,7} = 420 ticks.
|
||||
|
||||
**Forward work** (deferred to v1.12+):
|
||||
1. **Throughput calculation** — compute `rx_kbps` / `tx_kbps` from
|
||||
delta of `rx_bytes` / `tx_bytes` over time.
|
||||
2. **IPv4 addresses** — currently only IPv6. IPv4 requires parsing
|
||||
`/proc/net/fib_trie` or shelling out to `ip addr`.
|
||||
3. **ethtool stats** — driver-specific counters via
|
||||
`/sys/class/net/<iface>/{statistics,*}` beyond the standard set.
|
||||
4. **Network namespace detection** — `netns` info for containers.
|
||||
|
||||
### 3.4 D-Bus
|
||||
|
||||
| Component | Status | Detail |
|
||||
|
||||
@@ -2554,6 +2554,194 @@ Total: ~4,945 LoC across 16 modules (v1.9: 4,885 LoC; +60 LoC for
|
||||
|
||||
---
|
||||
|
||||
## 35. v1.11 Network Tab (sysfs + if_inet6) (2026-06-20)
|
||||
|
||||
Per the user's "v1.11 = Network tab (Recommended)" directive, v1.11
|
||||
ships the **Network tab** as the 7th tab in the multi-view system.
|
||||
|
||||
### 35.1 What was implemented
|
||||
|
||||
**New module `network.rs` (203 lines, 7 unit tests)**:
|
||||
- `NetInterface` struct with 14 fields: `name`, `operstate`,
|
||||
`speed_mbps`, `mac_address`, `mtu`, `rx_bytes`, `tx_bytes`,
|
||||
`rx_packets`, `tx_packets`, `rx_errors`, `tx_errors`, `rx_dropped`,
|
||||
`tx_dropped`, `ipv6_addrs`.
|
||||
- `NetInterface::format_bytes(bytes)` — formats binary unit suffixes
|
||||
(B / KiB / MiB / GiB / TiB) for traffic counters.
|
||||
- `NetInfo::read()` walks `/sys/class/net/*/`, reads each interface's
|
||||
`operstate`, `speed`, `address`, `mtu`, and `statistics/{rx,tx}_{bytes,
|
||||
packets,errors,dropped}`.
|
||||
- `read_ipv6_addrs(iface_name)` parses `/proc/net/if_inet6` for each
|
||||
interface's IPv6 addresses. Format: `<addr32> <ifindex> <prefix>
|
||||
<scope> <flags> <devname>`. Scope encoded as `00=global`, `10=host`,
|
||||
`20=link`, `40=site`, `80=compat`, `c0=legacy` (kernel encoding,
|
||||
differs from RFC 4291 scope IDs).
|
||||
|
||||
**Updated `app.rs`**:
|
||||
- New field `pub net: crate::network::NetInfo`, refreshed every **7th
|
||||
tick** (3.5 sec at default POLL_MS=500).
|
||||
- `TabId::Network` variant (7th tab).
|
||||
- `TabId::next()` cycle: `PerCpu → System → Info → Motherboard → Battery
|
||||
→ Sensors → Network → PerCpu`.
|
||||
|
||||
**Updated `render.rs`**:
|
||||
- New `render_network_panel(app, focused)` — for each interface, emits
|
||||
a `▸ iface_name` header followed by State / MAC / MTU / Speed /
|
||||
RX bytes / TX bytes / IPv6 addresses.
|
||||
- MAC is hidden when empty or `00:00:00:00:00:00` (avoids showing
|
||||
fake MAC for lo, veth, tun, etc.).
|
||||
- Speed hidden when ≤ 0 (sysfs reports -1 for unknown speed, common
|
||||
on tun/tap/wireguard/veth).
|
||||
- `render_tab_bar()` updated for 7 tabs with hotkey mapping 1-7.
|
||||
- `render_once` dumps Network panel for headless verification.
|
||||
|
||||
**Updated `main.rs`**:
|
||||
- `mod network;` declaration.
|
||||
- New dispatch arm `TabId::Network => render_network_panel(...)`.
|
||||
- Hotkey `7` jumps to Network tab directly.
|
||||
|
||||
### 35.2 Linux host smoke test (Manjaro, 6 interfaces)
|
||||
|
||||
```
|
||||
--- Network panel (verifies v1.11 sysfs) ---
|
||||
Detected 6 interface(s):
|
||||
▸ enp14s0 State: down MAC: 04:7c:16:51:e3:9c MTU: 1500
|
||||
▸ lo State: unknown MTU: 65536 RX 686.3 MiB (301077 packets)
|
||||
▸ moscow State: unknown MTU: 1420 RX 340.0 MiB TX 888.6 MiB
|
||||
▸ tailscale0 State: unknown MTU: 1280 RX 2.0 GiB TX 11.4 GiB
|
||||
IPv6: fe80::d049:dafc:214f:f229/64 (link)
|
||||
fd7a:115c:a1e0::3133:5c76/64 (compat)
|
||||
▸ tun0 State: unknown MTU: 1500 Speed: 10000 Mbps
|
||||
RX 1.5 GiB TX 12.1 GiB
|
||||
IPv6: fd01::2/64 (compat)
|
||||
fe80::7cc1:f6a4:a266:bc03/64 (link)
|
||||
▸ wlp13s0 State: up MAC: f0:a6:54:4e:e5:ef MTU: 1500
|
||||
RX 38.7 GiB (137M packets, 46408 dropped)
|
||||
TX 237.4 GiB (237M packets, 20 dropped)
|
||||
IPv6: fd77:625d:bcf5::49f1:e82c:d7b5:53/64 (link)
|
||||
fe80::e67c:4a69:1151:e2f1/64 (link)
|
||||
```
|
||||
|
||||
Verified:
|
||||
- 6 interfaces detected (enp14s0, lo, moscow, tailscale0, tun0, wlp13s0)
|
||||
- Real link state: enp14s0=down, wlp13s0=up, others=unknown
|
||||
- Real traffic stats: lo (686 MiB), wlp13s0 (38/237 GiB), tailscale0 (2/11 GiB)
|
||||
- Real IPv6 addresses with correct scope encoding (link for fe80::, compat for fd7a/fd01)
|
||||
- MAC shown only when not 00:00:00:00:00:00 (enp14s0, wlp13s0 only)
|
||||
- Speed shown only when >0 (tun0=10000 Mbps, others hidden)
|
||||
|
||||
### 35.3 Unit tests (7 new, 24/24 total pass)
|
||||
|
||||
```rust
|
||||
#[test] fn format_bytes_below_1kib() // 500 → "500.0 B"
|
||||
#[test] fn format_bytes_1kib() // 1024 → "1.0 KiB"
|
||||
#[test] fn format_bytes_1mib() // 1024^2 → "1.0 MiB"
|
||||
#[test] fn format_bytes_1gib() // 1024^3 → "1.0 GiB"
|
||||
#[test] fn format_bytes_1tib() // 1024^4 → "1.0 TiB"
|
||||
#[test] fn net_info_is_empty_when_no_sys_class_net()
|
||||
#[test] fn net_interface_default_has_zero_traffic()
|
||||
```
|
||||
|
||||
```
|
||||
running 24 tests
|
||||
test bench::tests::kind_cycle ... ok
|
||||
test bench::tests::single_core_toggle ... ok
|
||||
test network::tests::format_bytes_1kib ... ok
|
||||
test network::tests::format_bytes_1mib ... ok
|
||||
test network::tests::format_bytes_1gib ... ok
|
||||
test network::tests::format_bytes_1tib ... ok
|
||||
test network::tests::format_bytes_below_1kib ... ok
|
||||
test network::tests::net_info_is_empty_when_no_sys_class_net ... ok
|
||||
test network::tests::net_interface_default_has_zero_traffic ... ok
|
||||
test sensor::tests::* (12 tests) ... ok
|
||||
test bench::tests::* (5 tests) ... ok
|
||||
|
||||
test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
```
|
||||
|
||||
### 35.4 Build verification
|
||||
|
||||
| Build | Result |
|
||||
|-------|--------|
|
||||
| Linux host (`cargo build --release`) | ✅ 0 errors, 44 warnings (mostly pre-existing dead-code) |
|
||||
| Linux host tests (`cargo test --release`) | ✅ 24/24 pass |
|
||||
| Linux host smoke (`./target/release/redbear-power --once`) | ✅ Network panel renders correctly |
|
||||
| Redox cross-compile (`cargo build --release --target=x86_64-unknown-redox`) | ✅ clean |
|
||||
| Redox binary (stripped) | 3,996,520 bytes (vs v1.10's 3,963,752 — +33 KB) |
|
||||
| Cross-compile SHA256 | `05cca57693110e06393273a3247b159b8fc681a8ebc0cdd5a2386f33a1ebb407` |
|
||||
|
||||
### 35.5 Refresh cadence (coprime moduli now: 3, 4, 5, 7)
|
||||
|
||||
Network refresh uses **7-tick** modulus (3.5 sec at POLL_MS=500). The
|
||||
7-tick modulus is coprime with all existing moduli (3, 4, 5) so no two
|
||||
expensive sysfs reads ever fire in the same tick. The LCM of {3, 4, 5, 7}
|
||||
is 420 ticks = 210 sec. Any two moduli synchronize at most every
|
||||
`lcm(a,b)` ticks, giving < 1% overlap probability for any pair.
|
||||
|
||||
Initially considered 6-tick (1.5 sec) but rejected because
|
||||
`gcd(6, 3) = 3` and `gcd(6, 4) = 2` — would synchronize with meminfo
|
||||
and sensors, causing 4 simultaneous sysfs reads every 3rd tick.
|
||||
|
||||
### 35.6 IPv6 scope encoding gotcha
|
||||
|
||||
The `/proc/net/if_inet6` scope field uses **kernel-specific encoding**
|
||||
that differs from RFC 4291:
|
||||
|
||||
| Kernel value | Meaning |
|
||||
|--------------|---------|
|
||||
| 00 | global (deprecated; some kernels report host as 00) |
|
||||
| 10 | host (interface-local) |
|
||||
| 20 | link |
|
||||
| 40 | site |
|
||||
| 80 | compat (deprecated IPv4-compatible) |
|
||||
| c0 | legacy |
|
||||
|
||||
My first pass used RFC 4291 encoding (0=global, 20=link, 40=site,
|
||||
80=host), which produced `scope?` for most modern interfaces.
|
||||
Fixed to match the actual kernel encoding.
|
||||
|
||||
### 35.7 Forward work
|
||||
|
||||
- **Throughput calculation** — compute `rx_kbps` and `tx_kbps` by
|
||||
storing previous `rx_bytes`/`tx_bytes` and timestamp, then
|
||||
`(current - prev) / dt`. Useful for showing real-time traffic.
|
||||
- **IPv4 addresses** — currently only IPv6 (`/proc/net/if_inet6`).
|
||||
IPv4 requires parsing `/proc/net/fib_trie` (verbose) or shelling
|
||||
out to `ip addr` (requires iproute2). Future work.
|
||||
- **ethtool stats** — driver-specific counters (drops, errors,
|
||||
CRC errors). Read via `/sys/class/net/<iface>/{statistics,*}`
|
||||
beyond the standard set.
|
||||
- **Network namespace detection** — `netns` info from
|
||||
`/proc/<pid>/ns/net` for containers.
|
||||
|
||||
### 35.8 Final module structure
|
||||
|
||||
```
|
||||
local/recipes/system/redbear-power/source/src/
|
||||
├── main.rs (~520 lines)
|
||||
├── app.rs (~580) — App + CpuRow + TabId + 7 data-source fields
|
||||
├── render.rs (~1135) — header with Sources line, tab bar, 7 panels
|
||||
├── meminfo.rs (241)
|
||||
├── dmi.rs (118)
|
||||
├── battery.rs (132)
|
||||
├── sensor.rs (354) — hwmon reader + pkg_temp_c helper
|
||||
├── network.rs (203) — NEW: sysfs/class/net + /proc/net/if_inet6
|
||||
├── platform.rs (291)
|
||||
├── acpi.rs (~233)
|
||||
├── cpuid.rs (~369)
|
||||
├── dbus.rs (~294)
|
||||
├── config.rs (~223)
|
||||
├── bench.rs (304) — 5 unit tests
|
||||
├── msr.rs (~158)
|
||||
├── cpufreq.rs (~62)
|
||||
└── theme.rs (71)
|
||||
```
|
||||
|
||||
Total: ~5,150 LoC across 17 modules (v1.10: ~4,945 LoC; +205 LoC for
|
||||
network module + tests). 24 unit tests total (5 bench + 12 sensor + 7 network).
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- **`local/docs/RATATUI-APP-PATTERNS.md`** §13 — the canonical ratatui 0.30 best-practices update that this plan is derived from. Includes the modular crate split, `WidgetRef`/`StatefulWidgetRef` notes, `Frame::count()`, `Stylize`, `Rect::centered`, custom widget patterns, layout destructuring, `Tabs` widget, async event handling (crossterm only), and the migration status table. Use this as the implementation guide while this doc is the roadmap.
|
||||
|
||||
@@ -1397,6 +1397,13 @@ qt_internal_extend_target(Core CONDITION REDOX
|
||||
io/qstorageinfo_unix.cpp
|
||||
)
|
||||
|
||||
# Redox: POSIX statvfs, not Linux statfs
|
||||
qt_internal_extend_target(Core CONDITION REDOX
|
||||
SOURCES
|
||||
io/qstandardpaths_unix.cpp
|
||||
io/qstorageinfo_unix.cpp
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Core CONDITION QT_FEATURE_cpp_winrt
|
||||
SOURCES
|
||||
platform/windows/qfactorycacheregistration_p.h
|
||||
@@ -1621,6 +1628,13 @@ qt_internal_extend_target(Core CONDITION REDOX
|
||||
io/qstorageinfo_unix.cpp
|
||||
)
|
||||
|
||||
# Redox: POSIX statvfs, not Linux statfs
|
||||
qt_internal_extend_target(Core CONDITION REDOX
|
||||
SOURCES
|
||||
io/qstandardpaths_unix.cpp
|
||||
io/qstorageinfo_unix.cpp
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Core CONDITION QT_FEATURE_itemmodel
|
||||
SOURCES
|
||||
itemmodels/qabstractitemmodel.cpp itemmodels/qabstractitemmodel.h itemmodels/qabstractitemmodel_p.h
|
||||
|
||||
@@ -205,6 +205,7 @@ static_assert(std::is_signed_v<qint128>,
|
||||
#include <assert.h>
|
||||
#include <assert.h>
|
||||
#include <assert.h>
|
||||
#include <assert.h>
|
||||
#ifndef static_assert
|
||||
#define static_assert _Static_assert
|
||||
#endif
|
||||
|
||||
@@ -1149,6 +1149,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
|
||||
#ifdef IPV6_HOPLIMIT
|
||||
#ifdef IPV6_HOPLIMIT
|
||||
#ifdef IPV6_HOPLIMIT
|
||||
#ifdef IPV6_HOPLIMIT
|
||||
#ifdef IPV6_HOPLIMIT
|
||||
if (header.hopLimit != -1) {
|
||||
msg.msg_controllen += CMSG_SPACE(sizeof(int));
|
||||
@@ -1185,6 +1186,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
if (header.ifindex != 0 || !header.senderAddress.isNull()) {
|
||||
struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#if defined(Q_OS_VXWORKS)
|
||||
|
||||
+4
@@ -79,6 +79,7 @@ public:
|
||||
#if QT_CONFIG(opengl)
|
||||
#if QT_CONFIG(opengl)
|
||||
#if QT_CONFIG(opengl)
|
||||
#if QT_CONFIG(opengl)
|
||||
#if QT_CONFIG(opengl)
|
||||
virtual QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const = 0;
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
@@ -108,6 +109,7 @@ public:
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
virtual bool canCreatePlatformOffscreenSurface() const { return false; }
|
||||
#if QT_CONFIG(opengl)
|
||||
@@ -148,6 +150,7 @@ public:
|
||||
#if QT_CONFIG(opengl)
|
||||
#if QT_CONFIG(opengl)
|
||||
#if QT_CONFIG(opengl)
|
||||
#if QT_CONFIG(opengl)
|
||||
#if QT_CONFIG(opengl)
|
||||
virtual void *nativeResourceForContext(NativeResource /*resource*/, QPlatformOpenGLContext */*context*/) { return nullptr; }
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
@@ -178,6 +181,7 @@ public:
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
#endif /* QT_CONFIG(opengl) */
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -46,7 +46,11 @@ fi
|
||||
mkdir -p "${COOKBOOK_STAGE}/usr/bin"
|
||||
|
||||
for bin in tlc tlcedit tlcview tlc-pty-login; do
|
||||
cp "${TARGET_DIR}/${bin}" "${COOKBOOK_STAGE}/usr/bin/${bin}"
|
||||
chmod 0755 "${COOKBOOK_STAGE}/usr/bin/${bin}"
|
||||
if [ -f "${TARGET_DIR}/${bin}" ]; then
|
||||
cp "${TARGET_DIR}/${bin}" "${COOKBOOK_STAGE}/usr/bin/${bin}"
|
||||
chmod 0755 "${COOKBOOK_STAGE}/usr/bin/${bin}"
|
||||
else
|
||||
echo "cookbook: skipping ${bin} (not built)"
|
||||
fi
|
||||
done
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user