File: statusd_exec.lua

package info (click to toggle)
notion 4.0.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,656 kB
  • sloc: ansic: 47,365; sh: 2,093; makefile: 594; perl: 270
file content (212 lines) | stat: -rw-r--r-- 6,708 bytes parent folder | download | duplicates (4)
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
-- Authors: Antti Vähäkotamäki
-- License: LGPL, version 2.1 or later
-- Last Changed: 2006
--
-- statusd_exec.lua
--
--
-- -- What is this?
--
-- This is a simple "general" statusd Lua script which
-- lets you show output of external programs in ion
-- statusbar. This is convenient if you are not familiar
-- with Lua but can handle yourself with some other
-- language enough to output what you would want the
-- statusbar to show.
--
-- After this script is loaded it starts executing all
-- the provided programs (wether a placeholder exists in
-- template or not) and updates the statusbar every time
-- one of them prints (and flushes) a line.
--
-- -- How to use it?
--
-- 1 ) update statusbar template to include %exec_something
-- 2 ) specify parameters in cfg_statusbar.lua like this:
--
-- mod_statusbar.launch_statusd{
--
--     [ ... some other config here ... ],
--
--     exec = {
--
--         -- show date each second in %exec_date with.. date!
--
--         date = {
--             program = 'date',
--             retry_delay = 1 * 1000,
--         },
--
--         -- show percentage of hda1 every 30 seconds in
--         -- %exec_hda1u with df, grep and sed.
--         -- also highlights entry if usage is high.
--
--         hda1u = {
--             program = 'df|grep hda1|sed "s/.*\\(..%\\).*/\\1/"',
--             retry_delay = 30 * 1000,
--             meter_length = 4,
--             hint_regexp = {
--                 important = '9[456].',
--                 critical = {
--                     '9[789].',
--                     '1...',
--                 },
--             },
--         },
--
--         -- keep continous track of a remote machine in
--         -- %exec_remote with ssh, bash and uptime.
--         -- if the connection breaks, wait 60 seconds and retry
--
--         remote = {
--             program = 'ssh -tt myhost.com "while (uptime);' ..
--                       'do sleep 1; done"',
--             retry_delay = 60 * 1000,
--         },
--     }
-- }
--
-- -- Description of variables:
--
-- * program
--  The program to execute. The last line of each
--  flushed output this program writes to stdout is
--  inserted as the content of the meter.
--
-- * retry_delay (optional)
--  The delay to wait (ms) before running the program again
--  once it stops sending data. Some programs just
--  send the data and exit while others continue
--  sending data periodically. This value can be used
--  to control the update rate for the first type of
--  programs. You can also specify a value for the other
--  type of programs to retry if the program stops for
--  some reason.
--
-- * meter_length (optional)
--  The space reserved for this meter in characters.
--  If the value is not specified or is less than 1
--  then the space is determined by the length of the
--  data being shown but some people do not want their
--  statusbar width to change randomly.
--
-- * hint_regexp (optional)
--  These regular expressions (in Lua syntax) are
--  matched with the data and in case of a match the
--  named hint is set to the meter. The value can be
--  either a string containing the regexp or a table
--  containing several possible regexps (Lua regexp
--  doesn't have an 'or'). By default the themes define
--  a color for 'important' and 'critical' hints.
--
--

local settings = table.join( statusd.get_config("exec"), {} )
local start_execution = nil
local timers = {}

-- Function for starting and restarting execution of a process

start_execution = function ( key )

    -- Set up a function for receiving the data
    -- and informing the statusbar

    local process_input = function ( new_data )

        local received_data = ""

        -- When we get new data, output the last complete line

        while new_data do
            received_data = received_data .. new_data

            -- Erase old data which we do not need anymore

            received_data = string.gsub( received_data,
                                         ".*\n(.*\n.*)", "%1" )

            -- Set the last complete line as the current line

            local current_line = string.gsub( received_data,
                                              "(.*)\n.*", "%1" )

            local t_key = "exec_" .. key
            local t_length = settings[key].meter_length
            local h_regexp = settings[key].hint_regexp

            if not tlength or t_length < 1 then
                t_length = string.len( current_line )
            end

            statusd.inform( t_key .. "_hint", '' )
            statusd.inform( t_key .. "_template",
                            string.rep( 'x', t_length ) )
            statusd.inform( t_key, current_line )

            if not h_regexp then h_regexp = {} end

            for hint, re in pairs( h_regexp ) do
                if ( type( re ) == 'string' ) then
                    re = { re }
                end

                for _, r in ipairs( re ) do
                    if ( string.find( current_line, r ) ) then
                       statusd.inform(t_key .. "_hint", hint)
                    end
                end
            end

            -- Wait for bgread to signal that more data
            -- is available or the program has exited

            new_data = coroutine.yield()
        end

        -- Program has exited.
        -- Start a timer for a new execution if set.

        if settings[key].retry_delay then
            timers[key]:set( settings[key].retry_delay,
                             function()
                                 start_execution(key)
                             end )
        end
    end

    -- Set up a simple function for printing errors

    local process_error = function( new_data )
        while new_data do
            io.stderr:write( "ion-statusd [statusd_exec, key='"
                .. key .. "']: " .. new_data )
            io.stderr:flush()
            new_data = coroutine.yield()
        end
    end

    -- Execute the program in the background and create
    -- coroutine functions to handle input and error data

    statusd.popen_bgread( settings[key].program,
                          coroutine.wrap( process_input ),
                          coroutine.wrap( process_error ) )

end

-- Now start execution of all defined processes

for key in pairs(settings) do
    timers[key] = statusd.create_timer()
    start_execution(key)
end

--
-- Copyright (c) Antti Vähäkotamäki 2006.
--
-- Ion is free software; you can redistribute it and/or modify it under
-- the terms of the GNU Lesser General Public License as published by
-- the Free Software Foundation; either version 2.1 of the License, or
-- (at your option) any later version.
--