-
Notifications
You must be signed in to change notification settings - Fork 0
/
luafetch.lua
288 lines (270 loc) · 9.31 KB
/
luafetch.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
-- Luafetch
-- Created by: Phate6660
-- Runs an external command in bash and returns the output.
local function cmd(command)
local handle = io.popen(command)
local result = handle:read("*a")
handle:close()
return result
end
-- Reads an environmental variable and returns the contents if possible,
-- otherwise it returns a dynamic error message stating which variable failed.
local function env(var)
local data = os.getenv(var)
if not data then
return 'N/A (could not read "$' .. var .. '", are you sure it is set?)'
else
return data
end
end
-- Returns a bool based on whether or not the file exists.
local function file_exists(name)
local f=io.open(name,"r")
if f~=nil then
io.close(f)
return true
else
return false
end
end
-- Takes a string, creates a table delimited by newlines,
-- counts the number of elements, then returns the number.
local function linecount(string)
local lines = {}
for line in string.gmatch(string, '([^\n]+)') do
table.insert(lines, line)
end
local count = {}
for i, _ in ipairs(lines) do
table.insert(count, i)
end
return count[#count+1-1]
end
-- An Android specific function for matching the processor ID (obtained from `/proc/cpuinfo`),
-- with the processor name and returns said name.
local function match_processor(id)
local hardware = {
['0xd46'] = "Cortex-A510",
}
return hardware[id]
end
-- Takes a string, the character to find, and what to replace it with.
-- Returns the string with all instances of the character replaced.
local function replace(arg, char, rep)
if string.match(arg, char) then
return arg:gsub(char, rep)
else
return arg -- Just return arg without doing anything if char wasn't found.
end
end
-- A function to return output, and optionally strip newlines from it.
local function return_output(output, strip)
strip = strip or false
if strip == true then
return replace(output, '\n', '')
else
return output
end
end
-- Takes a file path, optionally a line number, and optionally to strip newlines.
-- With just the file path, it'll return the contents of the file.
-- Specifying a line number will return only that line.
local function read(file_path, line_number, strip)
line_number = line_number or 'nil'
strip = strip or false
local file = io.open(file_path, 'r')
if not file then
return 'N/A (could not read "' .. file_path .. '")'
else
local contents = file:read '*a'
file:close()
if line_number == 'nil' then
return return_output(contents, strip)
else
local contents_table = {}
local delim = '\n'
for line in string.gmatch(contents, '([^' .. delim .. ']+)') do
table.insert(contents_table, line)
end
return return_output(contents_table[line_number], strip)
end
end
end
-- Split a string based on a delimiter, return a table.
local function split(string, delim)
local string_table = {}
for entry in string.gmatch(string, '([^' .. delim .. ']+)') do
table.insert(string_table, entry)
end
return string_table
end
-- Checks if the OS is Android, currently by parsing the kernel
-- name and checking if it contains 'android', since it seems that
-- most of not all android versions will contain 'android'
-- in the kernel version.
local function android()
local s = return_output(cmd('uname -r'))
if string.match(s, "android") then
return true
else
return false
end
end
local function return_cpu()
if android() then
line = read('/proc/cpuinfo', 7, true)
else
line = read('/proc/cpuinfo', 5, true)
end
local line_table = split(line, ':')
local result = line_table[2]:sub(2) -- Remove leading space from using ':' as delimiter.
if android() then
return match_processor(result)
else
return result
end
end
local function return_distro()
local line = read('/etc/os-release', 3, true)
if android() then
local av = cmd("getprop ro.build.version.release")
av = return_output(av, true)
local android = "Android " .. av
local kv = cmd("uname -r")
kv = return_output(kv, true)
local device = cmd("getprop ro.vendor.product.display")
device = return_output(device, true)
return android, kv, device
end
local line_table = split(line, '=')
return replace(line_table[2], '"', '')
end
-- TODO: Gather more info, such as total and used memory.
local function return_memory()
local line = read('/proc/meminfo', 1, true)
local line_table = split(line, ' ')
local kb = tonumber(line_table[2])
if kb > 1024 then
local mb = kb / 1024
local mb_table = split(tostring(mb), '.')
return mb_table[1] .. ' MB'
end
return kb
end
local function return_packages(mngr)
mngr = mngr or 'nil'
if mngr == "portage" then
-- '/var/db/pkg/*/*' is a list of all packages.
-- TODO: Get the list of dirs in pure lua.
local dirs = cmd('find "/var/db/pkg/" -mindepth 2 -maxdepth 2 -type d -printf "%f\n"')
local dirs_list = dirs:read('*a')
dirs:close()
local total = linecount(dirs_list)
local explicit_list = read('/var/lib/portage/world', nil, false)
local explicit = linecount(explicit_list)
return explicit .. ' (explicit), ' .. total .. ' (total) ' .. '| Portage'
elseif mngr == "pacman" then
local total = cmd('pacman -Qq | wc -l')
return replace(total .. ' (total) | Pacman', '\n', '')
-- `pkg` is also a BSD package manager, but we'll get to that later
-- if this reaches a stage where it expands to BSD.
-- For now, this is in reference to the `pkg`
-- package manager built in to Termux
elseif mngr == 'pkg' or 'apt' or 'dpkg' then
local output = cmd("dpkg -l --no-pager")
output = linecount(output) - 4
return output .. " (total) | " .. mngr
elseif mngr == 'nil' then
return 'N/A (no package manager was passed to the function)'
else
return 'N/A (' .. mngr .. ' is unsupported right now)'
end
end
local function return_music(player)
player = player or 'nil'
if player == 'mpd' then
local line = cmd('mpc -f "%artist% - %album% - %title%" | head -n1')
return replace(usable_line, '\n', '')
elseif player == 'spotify' then
local line = cmd('playerctl -p spotify metadata -f "{{ artist }} - {{ album }} - {{ title }}"')
return replace(usable_line, '\n', '')
elseif player == 'nil' then
return 'N/A (no player selected)'
else
return 'N/A (' .. player .. ' is unsupported right now)'
end
end
local function return_uptime()
local uptime = tonumber(split(read('/proc/uptime'), '.')[1])
if android() then
-- TODO: Find a better method than running a command,
-- though unfortunately `/proc/uptime` is either missing or inaccessible on Android.
local output = cmd("uptime -p")
local usable_output = return_output(output, true)
-- TODO: Clean up and format output before returning it.
return usable_output
end
if uptime > 86400 then
local days_pre = uptime / 60 / 60 / 24
days_pre = split(tostring(days_pre), '.')[1]
Days = days_pre .. 'd'
else
Days = ''
end
if uptime > 3600 then
local hours_pre = (uptime / 60 / 60) % 24
hours_pre = split(tostring(hours_pre), '.')[1]
Hours = hours_pre .. 'h'
else
Hours = ''
end
if uptime > 60 then
local minutes_pre = (uptime / 60) % 60
minutes_pre = split(tostring(minutes_pre), '.')[1]
Minutes = minutes_pre .. 'm'
else
Minutes = ''
end
if Days == '' then
return (Days .. ' ' .. Hours .. ' ' .. Minutes):sub(2)
else
return Days .. ' ' .. Hours .. ' ' .. Minutes
end
end
-- Gather Information
-- Notes:
-- * the first arg passed to the script is the packaga manager
-- * the second arg the music player if music info is wanted
-- TODO: hide info behind options, this will require more robust arg parsing.
local cpu = return_cpu()
if android() then
distro, kernel, device = return_distro()
else
device = read(
'/sys/devices/virtual/dmi/id/product_name',
nil, true
)
distro = return_distro()
kernel = read('/proc/sys/kernel/osrelease', nil, true)
end
local editor = env('EDITOR')
local hostname = read('/etc/hostname', nil, true)
local memory = return_memory()
local packages = return_packages(arg[1])
local shell = env('SHELL')
local uptime = return_uptime()
local user = env('USER')
local music = return_music(arg[2])
print('cpu = ' .. cpu .. '\n'
.. 'device = ' .. device .. '\n'
.. 'distro = ' .. distro .. '\n'
.. 'editor = ' .. editor .. '\n'
.. 'hostname = ' .. hostname .. '\n'
.. 'kernel = ' .. kernel .. '\n'
.. 'memory = ' .. memory .. '\n'
.. 'packages = ' .. packages .. '\n'
.. 'shell = ' .. shell .. '\n'
.. 'uptime = ' .. uptime .. '\n'
.. 'user = ' .. user .. '\n'
.. 'music = ' .. music
)