10 Commits

Author SHA1 Message Date
murat 497a800ecb updated README 2026-06-01 22:19:50 +03:00
murat 64827aa86d chore(shell): showing only the executable name instead of full path 2026-06-01 22:09:39 +03:00
murat f90137b4c0 chore(ram): showing 2 digit after (.) instead of 4 2026-06-01 21:54:42 +03:00
murat 5bbe703ec1 update for manually running workflow for old releases 2026-05-26 18:52:02 +03:00
murat d8bc65e0d6 ability to generate releases by manually running workflows 2026-05-26 18:46:52 +03:00
murat 7abb846a81 fixed github actions build
i hate llms so much
2026-05-26 18:38:51 +03:00
murat 58bcb147e4 init github actions for builds 2026-05-26 18:32:17 +03:00
murat ecf066dcb3 init Makefile
i used chatgpt for it please don't take my life i still don't know make
2026-05-26 18:28:46 +03:00
murat e6e5648a2d updated gitignore 2026-05-26 18:21:35 +03:00
murat e47dc4f7d8 updated readme 2026-05-25 21:36:10 +03:00
5 changed files with 274 additions and 78 deletions
+80
View File
@@ -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
View File
@@ -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 directories
build/ build/
Build/ 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/
+50
View File
@@ -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
+126 -1
View File
@@ -1,2 +1,127 @@
# fetchit # 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
```
+17 -13
View File
@@ -6,6 +6,7 @@
#include <array> #include <array>
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <iomanip>
#include <unordered_map> #include <unordered_map>
#include <cctype> #include <cctype>
#include <sys/utsname.h> #include <sys/utsname.h>
@@ -14,13 +15,13 @@
#include <clocale> #include <clocale>
#include <cwchar> #include <cwchar>
using std::string, std::cout; using std::string, std::cout, std::vector;
namespace fs = std::filesystem; namespace fs = std::filesystem;
string getUser(); string getUser();
string getHost(); string getHost();
string getDistro(); string getDistro();
std::vector<string> distroArt(); vector<string> distroArt();
string getKernel(); string getKernel();
string getUptime(); string getUptime();
string getShell(); string getShell();
@@ -67,8 +68,8 @@ struct gpuId {
string device; string device;
}; };
std::vector<gpuId> getGpuIds() { vector<gpuId> getGpuIds() {
std::vector<gpuId> gpus; vector<gpuId> gpus;
std::string pciPath = "/sys/bus/pci/devices/"; std::string pciPath = "/sys/bus/pci/devices/";
for (const auto& entry : fs::directory_iterator(pciPath)) { for (const auto& entry : fs::directory_iterator(pciPath)) {
@@ -122,7 +123,7 @@ int main () {
return color(c) + padded + color(Color::Reset) + value; return color(c) + padded + color(Color::Reset) + value;
}; };
std::vector<string> infoLines = { vector<string> infoLines = {
formatLine(Color::Green, " distro:", getDistro()), formatLine(Color::Green, " distro:", getDistro()),
formatLine(Color::Magenta, " kernel:", getKernel()), formatLine(Color::Magenta, " kernel:", getKernel()),
formatLine(Color::Blue, " uptime:", getUptime()), formatLine(Color::Blue, " uptime:", getUptime()),
@@ -133,7 +134,7 @@ int main () {
formatLine(Color::Blue, " OS Date:", getOsDate()) formatLine(Color::Blue, " OS Date:", getOsDate())
}; };
std::vector<string> logoLines = distroArt(); vector<string> logoLines = distroArt();
size_t logoWidth = 0; size_t logoWidth = 0;
for (const auto& line : logoLines) { for (const auto& line : logoLines) {
if (line.size() > logoWidth) logoWidth = line.size(); if (line.size() > logoWidth) logoWidth = line.size();
@@ -262,7 +263,7 @@ string color(Color c) {
return "\033[0m"; return "\033[0m";
} }
std::vector<string> distroArt() { vector<string> distroArt() {
std::ifstream readOsRelease("/etc/os-release"); std::ifstream readOsRelease("/etc/os-release");
if(!readOsRelease.is_open()) { if(!readOsRelease.is_open()) {
@@ -287,7 +288,7 @@ std::vector<string> distroArt() {
readOsRelease.close(); readOsRelease.close();
const std::vector<DistroLogo> logos = { const vector<DistroLogo> logos = {
{ {
"arch", "arch",
Color::Blue, Color::Blue,
@@ -451,7 +452,7 @@ std::vector<string> distroArt() {
}, },
}; };
std::vector<string> out; vector<string> out;
for (const auto& logo : logos) { for (const auto& logo : logos) {
if (logo.id == distroID) { if (logo.id == distroID) {
const string prefix = color(logo.color); const string prefix = color(logo.color);
@@ -508,6 +509,9 @@ string getUptime() {
string getShell() { string getShell() {
string shell; string shell;
shell = std::getenv("SHELL"); shell = std::getenv("SHELL");
while(shell.find('/') < shell.length()) shell.erase(0, shell.find('/') + 1);
if (!shell.empty()) return shell; if (!shell.empty()) return shell;
return ""; return "";
@@ -581,7 +585,7 @@ string getGPU() {
return hex; return hex;
}; };
auto joinWith = [](const std::vector<string>& items, const string& sep) { auto joinWith = [](const vector<string>& items, const string& sep) {
string out; string out;
for (const auto& item : items) { for (const auto& item : items) {
if (item.empty()) continue; if (item.empty()) continue;
@@ -595,7 +599,7 @@ string getGPU() {
if(!readPciIds.is_open()) { if(!readPciIds.is_open()) {
std::cerr << "Error: Couldn't read /usr/share/hwdata/pci.ids\n"; std::cerr << "Error: Couldn't read /usr/share/hwdata/pci.ids\n";
std::vector<string> ids; vector<string> ids;
for (const auto& gpu : gpus) { for (const auto& gpu : gpus) {
string vendor = normalizeHex(gpu.vendor); string vendor = normalizeHex(gpu.vendor);
string device = normalizeHex(gpu.device); string device = normalizeHex(gpu.device);
@@ -643,7 +647,7 @@ string getGPU() {
readPciIds.close(); readPciIds.close();
std::vector<string> gpuNames; vector<string> gpuNames;
for (const auto& gpu : gpus) { for (const auto& gpu : gpus) {
string vendor = normalizeHex(gpu.vendor); string vendor = normalizeHex(gpu.vendor);
string device = normalizeHex(gpu.device); string device = normalizeHex(gpu.device);
@@ -700,7 +704,7 @@ string getRAM() {
memkbs /= 1024; memkbs /= 1024;
float memory = memkbs / 1024.0f; float memory = memkbs / 1024.0f;
std::stringstream ss; std::stringstream ss;
ss << memory << " GB"; ss << std::fixed << std::setprecision(2) << memory << " GB";
string memGigs = ss.str(); string memGigs = ss.str();
if (!memGigs.empty()) return memGigs; if (!memGigs.empty()) return memGigs;