Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 497a800ecb | |||
| 64827aa86d | |||
| f90137b4c0 | |||
| 5bbe703ec1 | |||
| d8bc65e0d6 | |||
| 7abb846a81 | |||
| 58bcb147e4 | |||
| ecf066dcb3 | |||
| e6e5648a2d | |||
| e47dc4f7d8 |
@@ -0,0 +1,80 @@
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- "v*"
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: "Optional tag to release (e.g. v1.1)"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: ubuntu-latest
|
||||
container: debian:11
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install build dependencies
|
||||
run: apt-get update && apt-get install -y --no-install-recommends make g++ git tar ca-certificates
|
||||
|
||||
- name: Build
|
||||
run: make clean build
|
||||
|
||||
release:
|
||||
if: (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) || (github.event_name == 'workflow_dispatch' && inputs.release_tag != '')
|
||||
runs-on: ubuntu-latest
|
||||
container: debian:11
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout (tag push)
|
||||
uses: actions/checkout@v4
|
||||
if: github.event_name == 'push'
|
||||
|
||||
- name: Checkout (manual tag)
|
||||
uses: actions/checkout@v4
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
|
||||
- name: Install build dependencies
|
||||
run: apt-get update && apt-get install -y --no-install-recommends make g++ git tar ca-certificates
|
||||
|
||||
- name: Build release tarball
|
||||
env:
|
||||
VERSION: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref_name }}
|
||||
run: |
|
||||
if make -n release >/dev/null 2>&1; then
|
||||
make release VERSION="$VERSION"
|
||||
else
|
||||
make clean build
|
||||
mkdir -p dist
|
||||
tar -C build -czf "dist/fetchit-${VERSION}-linux-x86_64-gnu.tar.gz" fetchit
|
||||
fi
|
||||
|
||||
- name: Upload workflow artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fetchit-${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref_name }}-linux-x86_64-gnu
|
||||
path: dist/*.tar.gz
|
||||
|
||||
- name: Publish GitHub release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref_name }}
|
||||
files: dist/*.tar.gz
|
||||
overwrite_files: true
|
||||
generate_release_notes: true
|
||||
+1
-64
@@ -1,69 +1,6 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Linker files
|
||||
*.ilk
|
||||
|
||||
# Debugger Files
|
||||
*.pdb
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
*.so.*
|
||||
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Build directories
|
||||
build/
|
||||
Build/
|
||||
build-*/
|
||||
dist/
|
||||
|
||||
# CMake generated files
|
||||
CMakeFiles/
|
||||
CMakeCache.txt
|
||||
cmake_install.cmake
|
||||
Makefile
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.log
|
||||
*.bak
|
||||
*.swp
|
||||
|
||||
# vcpkg
|
||||
vcpkg_installed/
|
||||
|
||||
# debug information files
|
||||
*.dwo
|
||||
|
||||
# test output & cache
|
||||
Testing/
|
||||
.cache/
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
APP := fetchit
|
||||
SRC := main.cpp
|
||||
BUILD_DIR := build
|
||||
DIST_DIR := dist
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
DESTDIR ?=
|
||||
|
||||
CXX ?= g++
|
||||
CXXFLAGS ?= -O2 -Wall -Wextra -std=c++17 -pipe
|
||||
LDFLAGS ?= -static-libstdc++ -static-libgcc
|
||||
|
||||
VERSION ?= $(shell git describe --tags --dirty --always 2>/dev/null)
|
||||
|
||||
.PHONY: all build run install uninstall clean dist release
|
||||
|
||||
all: build
|
||||
|
||||
build: $(BUILD_DIR)/$(APP)
|
||||
|
||||
$(BUILD_DIR)/$(APP): $(SRC) | $(BUILD_DIR)/.dir
|
||||
$(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS)
|
||||
|
||||
|
||||
$(BUILD_DIR)/.dir:
|
||||
mkdir -p $(BUILD_DIR)
|
||||
touch $@
|
||||
|
||||
run: build
|
||||
./$(BUILD_DIR)/$(APP)
|
||||
|
||||
install: build
|
||||
install -d "$(DESTDIR)$(BINDIR)"
|
||||
install -m 0755 $(BUILD_DIR)/$(APP) "$(DESTDIR)$(BINDIR)/$(APP)"
|
||||
|
||||
uninstall:
|
||||
rm -f "$(DESTDIR)$(BINDIR)/$(APP)"
|
||||
|
||||
clean:
|
||||
rm -f $(BUILD_DIR)/$(APP)
|
||||
|
||||
dist: build | $(DIST_DIR)/.dir
|
||||
tar -C $(BUILD_DIR) -czf $(DIST_DIR)/$(APP)-$(VERSION)-linux-x86_64-gnu.tar.gz $(APP)
|
||||
|
||||
$(DIST_DIR)/.dir:
|
||||
mkdir -p $(DIST_DIR)
|
||||
touch $@
|
||||
|
||||
release: clean build dist
|
||||
@@ -1,2 +1,127 @@
|
||||
# fetchit
|
||||
Works on my machine
|
||||
|
||||
`fetchit` is a Linux terminal system information viewer written in C++. It's a single-file program (`main.cpp`) that prints a colored distro logo (when available) alongside system and hardware info, similar to neofetch/fastfetch.
|
||||
|
||||
## Features
|
||||
|
||||
- Shows: distro, kernel, uptime, shell, CPU, GPU, RAM, and "OS Date".
|
||||
- Distro detection via `/etc/os-release` (`PRETTY_NAME` for display, `ID` for logo matching).
|
||||
- Colored ASCII distro logos for supported distros.
|
||||
- GPU detection by scanning PCI devices (`/sys/bus/pci/devices/`) for class `0x03*`.
|
||||
- GPU name resolution via `/usr/share/hwdata/pci.ids` (falls back to hex IDs if missing).
|
||||
- Accounts for Unicode character width for better alignment in terminals.
|
||||
|
||||
## Supported Distro Logos
|
||||
|
||||
Logos are matched against `/etc/os-release` `ID`:
|
||||
|
||||
`arch`, `cachyos`, `debian`, `ubuntu`, `fedora`, `manjaro`, `opensuse`, `pop`, `linuxmint`, `endeavouros`, `void`, `alpine`
|
||||
|
||||
## Requirements
|
||||
|
||||
- Linux
|
||||
- A C++17-capable compiler (default: `g++`)
|
||||
- UTF-8 locale + ANSI color support (recommended for icons/colors)
|
||||
- Reads the following files/paths:
|
||||
- `/etc/os-release`
|
||||
- `/etc/hostname`
|
||||
- `/proc/uptime`
|
||||
- `/proc/cpuinfo`
|
||||
- `/proc/meminfo`
|
||||
- `/sys/bus/pci/devices/`
|
||||
- `/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq`
|
||||
- `/usr/share/hwdata/pci.ids` (optional)
|
||||
|
||||
## Build
|
||||
|
||||
### Using the Makefile (recommended)
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
Binary output: `build/fetchit`
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
make run
|
||||
```
|
||||
|
||||
### Manual build
|
||||
|
||||
```bash
|
||||
g++ -O2 -Wall -Wextra -std=c++17 -pipe -o fetchit main.cpp
|
||||
```
|
||||
|
||||
## Install / Uninstall
|
||||
|
||||
Install:
|
||||
|
||||
```bash
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Defaults:
|
||||
|
||||
- `PREFIX=/usr/local`
|
||||
- `BINDIR=$(PREFIX)/bin`
|
||||
- Installs to: `/usr/local/bin/fetchit`
|
||||
|
||||
Uninstall:
|
||||
|
||||
```bash
|
||||
sudo make uninstall
|
||||
```
|
||||
|
||||
Packaging-friendly variables:
|
||||
|
||||
- `DESTDIR` (staging root)
|
||||
- `PREFIX`, `BINDIR`
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
make install PREFIX=/usr BINDIR=/usr/bin DESTDIR=/tmp/pkgroot
|
||||
```
|
||||
|
||||
## Distribution Archive
|
||||
|
||||
Create a tar.gz containing the built binary:
|
||||
|
||||
```bash
|
||||
make dist
|
||||
```
|
||||
|
||||
Output: `dist/fetchit-<version>-linux-x86_64-gnu.tar.gz`
|
||||
|
||||
`<version>` is derived from:
|
||||
`git describe --tags --dirty --always` (when available)
|
||||
|
||||
Full release pipeline:
|
||||
|
||||
```bash
|
||||
make release
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `shell` is taken from `$SHELL` and printed as the basename (e.g. `bash`, not `/usr/bin/bash`).
|
||||
- `OS Date` is computed from `/etc/hostname` file metadata (`ctime`) as an elapsed duration; it may not equal the OS install date.
|
||||
- If `pci.ids` is unavailable, GPU(s) are printed as hex IDs like `0xVVVV:0xDDDD`.
|
||||
- If no distro logo matches, the logo section will be empty and only info lines are shown.
|
||||
|
||||
## Sample Output
|
||||
|
||||
```text
|
||||
--- user@host ---
|
||||
|
||||
/\ distro: Arch Linux
|
||||
/ \ kernel: 7.0.10-arch1-1
|
||||
/ \ uptime: 12 minutes
|
||||
/ \ shell: bash
|
||||
/ ,, \ CPU: ... (N) @ X.XX GHz
|
||||
/ | | \ GPU: ...
|
||||
/_-'' ''-_\ RAM: 15.25 GB
|
||||
OS Date: 6 months 17 days 3 hours 40 minutes
|
||||
```
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <unordered_map>
|
||||
#include <cctype>
|
||||
#include <sys/utsname.h>
|
||||
@@ -14,13 +15,13 @@
|
||||
#include <clocale>
|
||||
#include <cwchar>
|
||||
|
||||
using std::string, std::cout;
|
||||
using std::string, std::cout, std::vector;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
string getUser();
|
||||
string getHost();
|
||||
string getDistro();
|
||||
std::vector<string> distroArt();
|
||||
vector<string> distroArt();
|
||||
string getKernel();
|
||||
string getUptime();
|
||||
string getShell();
|
||||
@@ -67,8 +68,8 @@ struct gpuId {
|
||||
string device;
|
||||
};
|
||||
|
||||
std::vector<gpuId> getGpuIds() {
|
||||
std::vector<gpuId> gpus;
|
||||
vector<gpuId> getGpuIds() {
|
||||
vector<gpuId> gpus;
|
||||
std::string pciPath = "/sys/bus/pci/devices/";
|
||||
|
||||
for (const auto& entry : fs::directory_iterator(pciPath)) {
|
||||
@@ -122,7 +123,7 @@ int main () {
|
||||
return color(c) + padded + color(Color::Reset) + value;
|
||||
};
|
||||
|
||||
std::vector<string> infoLines = {
|
||||
vector<string> infoLines = {
|
||||
formatLine(Color::Green, " distro:", getDistro()),
|
||||
formatLine(Color::Magenta, " kernel:", getKernel()),
|
||||
formatLine(Color::Blue, " uptime:", getUptime()),
|
||||
@@ -133,7 +134,7 @@ int main () {
|
||||
formatLine(Color::Blue, " OS Date:", getOsDate())
|
||||
};
|
||||
|
||||
std::vector<string> logoLines = distroArt();
|
||||
vector<string> logoLines = distroArt();
|
||||
size_t logoWidth = 0;
|
||||
for (const auto& line : logoLines) {
|
||||
if (line.size() > logoWidth) logoWidth = line.size();
|
||||
@@ -262,7 +263,7 @@ string color(Color c) {
|
||||
return "\033[0m";
|
||||
}
|
||||
|
||||
std::vector<string> distroArt() {
|
||||
vector<string> distroArt() {
|
||||
std::ifstream readOsRelease("/etc/os-release");
|
||||
|
||||
if(!readOsRelease.is_open()) {
|
||||
@@ -287,7 +288,7 @@ std::vector<string> distroArt() {
|
||||
|
||||
readOsRelease.close();
|
||||
|
||||
const std::vector<DistroLogo> logos = {
|
||||
const vector<DistroLogo> logos = {
|
||||
{
|
||||
"arch",
|
||||
Color::Blue,
|
||||
@@ -451,7 +452,7 @@ std::vector<string> distroArt() {
|
||||
},
|
||||
};
|
||||
|
||||
std::vector<string> out;
|
||||
vector<string> out;
|
||||
for (const auto& logo : logos) {
|
||||
if (logo.id == distroID) {
|
||||
const string prefix = color(logo.color);
|
||||
@@ -508,6 +509,9 @@ string getUptime() {
|
||||
string getShell() {
|
||||
string shell;
|
||||
shell = std::getenv("SHELL");
|
||||
|
||||
while(shell.find('/') < shell.length()) shell.erase(0, shell.find('/') + 1);
|
||||
|
||||
if (!shell.empty()) return shell;
|
||||
|
||||
return "";
|
||||
@@ -581,7 +585,7 @@ string getGPU() {
|
||||
return hex;
|
||||
};
|
||||
|
||||
auto joinWith = [](const std::vector<string>& items, const string& sep) {
|
||||
auto joinWith = [](const vector<string>& items, const string& sep) {
|
||||
string out;
|
||||
for (const auto& item : items) {
|
||||
if (item.empty()) continue;
|
||||
@@ -595,7 +599,7 @@ string getGPU() {
|
||||
|
||||
if(!readPciIds.is_open()) {
|
||||
std::cerr << "Error: Couldn't read /usr/share/hwdata/pci.ids\n";
|
||||
std::vector<string> ids;
|
||||
vector<string> ids;
|
||||
for (const auto& gpu : gpus) {
|
||||
string vendor = normalizeHex(gpu.vendor);
|
||||
string device = normalizeHex(gpu.device);
|
||||
@@ -643,7 +647,7 @@ string getGPU() {
|
||||
|
||||
readPciIds.close();
|
||||
|
||||
std::vector<string> gpuNames;
|
||||
vector<string> gpuNames;
|
||||
for (const auto& gpu : gpus) {
|
||||
string vendor = normalizeHex(gpu.vendor);
|
||||
string device = normalizeHex(gpu.device);
|
||||
@@ -700,7 +704,7 @@ string getRAM() {
|
||||
memkbs /= 1024;
|
||||
float memory = memkbs / 1024.0f;
|
||||
std::stringstream ss;
|
||||
ss << memory << " GB";
|
||||
ss << std::fixed << std::setprecision(2) << memory << " GB";
|
||||
string memGigs = ss.str();
|
||||
|
||||
if (!memGigs.empty()) return memGigs;
|
||||
|
||||
Reference in New Issue
Block a user