LIMB
Вход Регистрация

тема

Как я аналог neofetch делал

sukidat · · 0 ответов · 502 просмотров

Сап.Думаю, все слышали, что разработку Neofetch свернули. Да и честно говоря, он всегда меня бесил своей скоростью. Это же Bash, он под капотом спамит кучей процессов типа grep, awk и cut, чтобы просто узнать версию ядра или загрузку памяти. На старом железе это заметно тупит.Есть Fastfetch на C, он летает, но тащить бинарники и компилировать под каждую машину мне лень. Мне хотелось чего-то гибкого, скриптового, но чтобы работало так же быстро, как C.В итоге я выбрал LuaJIT. Многие забывают, что это не просто скрипты для игр. У него есть киллер-фича — FFI. По сути, я могу прямо из скрипта дергать функции ядра Linux и читать структуры памяти, минуя всякие медленные парсеры текста.Короче, написал свою утилиту. Работает моментально, весит копейки, выглядит как классика.Чтобы было красиво и поддерживаемо, завернул всё в нормальный OOP. Никакой лапши, всё по классам.Стек:* LuaJIT (для скорости и FFI)* Linux Kernel API (sysinfo, uname)Собственно, код (сохранять как luafetch.lua):
Спойлер: Исходный код (LuaJIT)
Code:
#!/usr/bin/env luajitlocal ffi = require("ffi")ffi.cdef[[    struct utsname {        char sysname[65]; char nodename[65];        char release[65]; char version[65];        char machine[65]; char domainname[65];    };    int uname(struct utsname *buf);    struct sysinfo {        long uptime; unsigned long loads[3];        unsigned long totalram; unsigned long freeram;        unsigned long sharedram; unsigned long bufferram;        unsigned long totalswap; unsigned long freeswap;        unsigned short procs; unsigned long totalhigh;        unsigned long freehigh; unsigned int mem_unit;        char _f[20-2*sizeof(long)-sizeof(int)];    };    int sysinfo(struct sysinfo *info);    char *getlogin(void);]]local System = {}System.__index = Systemfunction System.new()    local self = setmetatable({}, System)    self.uts = ffi.new("struct utsname")    self.info = ffi.new("struct sysinfo")    ffi.C.uname(self.uts)    ffi.C.sysinfo(self.info)    return selfendfunction System:get_user_host()    local user = "root"    local u_ptr = ffi.C.getlogin()    if u_ptr ~= nil then user = ffi.string(u_ptr) end    local host = ffi.string(self.uts.nodename)    return user, hostendfunction System:get_os_arch()    local distro = "Linux"    local f = io.open("/etc/os-release", "r")    if f then        local c = f:read("*a")        f:close()        distro = c:match('PRETTY_NAME="(.-)"') or "Linux"    end    return distro .. " " .. ffi.string(self.uts.machine)endfunction System:get_kernel()    return ffi.string(self.uts.release)endfunction System:get_uptime()    local up = tonumber(self.info.uptime)    local h = math.floor(up / 3600)    local m = math.floor((up % 3600) / 60)    return string.format("%d hours, %d mins", h, m)endfunction System:get_ram()    local function to_mb(b, u)        return math.floor((tonumber(b) * tonumber(u)) / 1048576)    end    local total = to_mb(self.info.totalram, self.info.mem_unit)    local free = to_mb(self.info.freeram, self.info.mem_unit)    return string.format("%dMiB / %dMiB", total - free, total)endfunction System:get_pkgs()    local f = io.open("/var/lib/dpkg/status", "r")    if not f then return "0 (nix)" end    local count = 0    while true do        local chunk = f:read(1048576)        if not chunk then break end        local _, n = chunk:gsub("Package: ", "")        count = count + n    end    f:close()    return count .. " (dpkg)"endfunction System:get_cpu()    local f = io.open("/proc/cpuinfo", "r")    if not f then return "Unknown" end    for line in f:lines() do        if line:match("^model name") then            f:close()            local name = line:match(": (.+)")            return name:gsub("Intel%(R%) Core%(TM%) ", ""):gsub("CPU ", ""):gsub("AMD Ryzen ", "Ryzen ")        end    end    f:close()    return "Unknown"endfunction System:get_shell()    local s = os.getenv("SHELL") or "/bin/sh"    return s:match("^.+/(.+)$")endfunction System:get_wm()    local wm = os.getenv("XDG_CURRENT_DESKTOP") or os.getenv("DESKTOP_SESSION")    return wm and wm:upper() or "TTY"endlocal Display = {}Display.__index = Displayfunction Display.new(sys)    local self = setmetatable({}, Display)    self.sys = sys    self.colors = {        reset = "\27[0m",        bold = "\27[1m",        blue = "\27[34m",        white = "\27[37m"    }    self.art = {        [[.                                ]],        [[                          /  , / ]],        [[                        ,/' /`'  ]],        [[                       /(/`'   _ ]],        [[                      f'/)  ,-'  ]],        [[                     /    ,' itz ]],        [[                    f,/  /       ]],        [[                    /"  7        ]],        [[                   / ,f /        ]],        [[              )   / / |J         ]],        [[                 7,( ;|j         ]],        [[      ,       (. "`/ ('          ]],        [[          `    )`-'/ l `         ]],        [[    (  (    ) '   ' (_,'  )      ]],        [[ (     ,)  7`  /  /,  (, (       ]],        [[  ,  ) (,- `-'  /  (,   -') (    ]],        [[ (_ ( `-_(,_,'_(_(__ )_, _`-_, _ ]],        [[                                 ]],        [[          KALI LINUX             ]]    }    return selfendfunction Display:render()    local user, host = self.sys:get_user_host()    local c = self.colors        local header = string.format("%s%s@%s%s", user, c.reset, c.blue, host)    local sep = string.rep("-", #user + #host + 1)    local info = {        string.format("%s%s%s%s%s", c.bold, c.blue, header, c.reset, c.bold),        sep,        self:fmt("OS", self.sys:get_os_arch()),        self:fmt("Host", host),        self:fmt("Kernel", self.sys:get_kernel()),        self:fmt("Uptime", self.sys:get_uptime()),        self:fmt("Packages", self.sys:get_pkgs()),        self:fmt("Shell", self.sys:get_shell()),        self:fmt("WM", self.sys:get_wm()),        self:fmt("CPU", self.sys:get_cpu()),        self:fmt("Memory", self.sys:get_ram())    }    print("")    for i = 1, math.max(#self.art, #info) do        local a = self.art[i] or ""        local pad = string.rep(" ", math.max(0, 38 - #a))        local l = info[i] or ""        io.write(string.format("  %s%s%s%s%s %s\n", c.bold, c.blue, a, pad, c.reset, l))    end    print("")    self:draw_palette()endfunction Display:fmt(k, v)    local c = self.colors    return string.format("%s%s%s%s: %s%s", c.blue, c.bold, k, c.reset, c.white, v)endfunction Display:draw_palette()    local function row(base)        io.write(string.rep(" ", 42))        for i = 0, 7 do io.write(string.format("\27[%dm   ", base + i)) end        io.write(self.colors.reset .. "\n")    end    row(40)    row(100)    print("")endlocal sys = System.new()local app = Display.new(sys)app:render()
Установка:Всё тривиально. Ставим LuaJIT (он есть везде), кидаем скрипт в bin и даем права.
Code:
sudo apt install luajitsudo mv luafetch.lua /usr/local/bin/luafetchsudo chmod +x /usr/local/bin/luafetch
Теперь просто пишем luafetch в терминале.Для тех, кто сидит на Kali или любом другом Debian-based, подсчет пакетов будет моментальным, потому что я читаю напрямую файл базы dpkg, а не вызываю команду.Как вам такой подход? Если есть идеи, что еще можно вытащить через FFI — пишите.
👍41 ❤️7 🔥6 🤔7 😢9

Гостевой просмотр. Чтобы отвечать и ставить реакции, войдите или зарегистрируйтесь.