scripts

Utilitity scripts
git clone git://gtms.dev:scripts
Log | Files | Refs

tmux-dev (8707B)


      1 #!/bin/lua
      2 
      3 -----------------------------
      4 ------ CONFIGURATION  -------
      5 -----------------------------
      6 local session = 'medoro' -- name for tmux session
      7 local workdir = '~/dev/medoro' -- your root dir for projects
      8 local pub = '~/.dswitch/channels/stable/versions/2.10.4/dart-sdk/bin/pub'
      9 
     10 local cmd = {
     11   ui = string.format(
     12     '%s get && %s run build_runner serve --delete-conflicting-outputs web:8081 >&1  > >(trun angulardart ui)', pub, pub),
     13   dw = string.format(
     14     '%s get && %s run build_runner serve --delete-conflicting-outputs web:8082 >&1 > >(trun angulardart dw)', pub, pub),
     15   digi = string.format(
     16     '%s get && %s run build_runner serve --delete-conflicting-outputs web:8083 >&1 > >(trun angulardart digi)', pub, pub),
     17   dpgw = 'mvn compile && mvn exec:java -Dexec.mainClass=org.medoro.dpgw.DPGWMain',
     18   r_dpgw = 'mvn exec:java -Dexec.mainClass=org.medoro.dpgw.DPGWMain',
     19 }
     20 ------ APP DEFINITION  -------
     21 -- cwd:   working directory
     22 -- cmd:   command to start/restart
     23 local dpgw = {key = 'dpgw', cwd = workdir .. '/dpgw', cmd = cmd.dpgw, r_cmd = cmd.r_dpgw}
     24 local ui = {key = 'ui', cwd = workdir .. '/ui/branches/devel', cmd = cmd.ui}
     25 local dw = {key = 'dw', cwd = workdir .. '/dw/branches/devel', cmd = cmd.dw}
     26 local digi = {key = 'digi', cwd = workdir .. '/digi/branches/devel', cmd = cmd.digi}
     27 -- COUPLES
     28 -- apps:  list of app to make action on
     29 local stack = {key = 'stack', apps = {dpgw, ui, dw}}
     30 ------------------------------
     31 
     32 ------- ENABLED APPS  -------
     33 local enabled_apps = {ui, dw, dpgw, digi, stack}
     34 -----------------------------
     35 
     36 ------- USAGE  -------
     37 local usage = [[
     38 usage: mdev <action> [<app>]
     39 
     40 action
     41   s <app>     -- [s]tart   | Start app in tmux session
     42   r <app>     -- [r]estart | Cancel command and rerun app cmd
     43   t [<app>]   -- [t]erm    | Stop app or whole session if app not provided
     44   o [<app>]   -- [o]pen    | Open tmux, if <app> is provided open app pane
     45                              (Only first app is taken)
     46   j <app>...  -- [j]oin    | Join multiple app to single tmux window
     47 
     48 start
     49   app separated by space will start each one in new tmux window
     50   > "app1 app2 app3"
     51 
     52   to start multple apps in one tmux window, connect them with '+' 
     53   > "app1+app2 app3"
     54 ]]
     55 -----------------------------
     56 
     57 -- provide at least one argument or catch help for usage
     58 if #arg == 0 or arg[1] == '-h' or arg[1] == '--help' then
     59   io.write(usage, '\n')
     60   os.exit(0)
     61 end
     62 
     63 local actions = {start = 's', restart = 'r', stop = 't', open = 'o', join = 'j'} -- command mapping
     64 local action_set = {['s'] = true, ['r'] = true, ['t'] = true, ['o'] = true, ['j'] = true}
     65 local action = string.sub(table.remove(arg, 1), 1, 1); -- get first char of command
     66 -- check for valid command
     67 if not action_set[action] then
     68   io.write(usage, '\n')
     69   os.exit(1)
     70 end
     71 
     72 -- make action
     73 if #arg == 0 and action == actions.stop then
     74   local _, _, code = os.execute(string.format('tmux kill-session -t %s', session))
     75   if code < 1 then io.write('Stopped session', '\n') end
     76   os.exit(0)
     77 elseif #arg == 0 then
     78   os.exit(0)
     79 end
     80 
     81 -----------------------------
     82 ------ PROCESS UTILS  -------
     83 -----------------------------
     84 local function started()
     85   local _, _, code = os.execute(string.format('tmux has -t %s 2>> /dev/null', session))
     86   return code < 1
     87 end
     88 local function run(cmd, ...) return os.execute(string.format(cmd, ...)) end
     89 
     90 --------------------------
     91 ------ TMUX UTILS  -------
     92 --------------------------
     93 local function tlocation(pane)
     94   local list = io.popen(string.format(
     95                           'tmux lsp -s -t %s -F "#{pane_title} #{window_index} #{pane_index}" 2>> /dev/null', session))
     96   local location
     97   for line in list:lines() do
     98     local p, wi, pi = string.match(line, '^(%a+) (%d+) (%d+)$')
     99     if p == pane then location = string.format('%s:%s.%s', session, wi, pi) end
    100   end
    101   return location
    102 end
    103 local function tattach(pane)
    104   local location = tlocation(pane)
    105   if location then run('tmux a -t %s', location) end
    106 end
    107 local function tkillp(pane)
    108   local location = tlocation(pane)
    109   if location then run('tmux killp -t %s', location) end
    110 end
    111 local function tnew(key, cwd)
    112   run('tmux neww -c %s -t %s -n %s', cwd, session, key)
    113   run('tmux selectp -t %s:%s.0 -T %s', session, key, key)
    114 end
    115 local function tsend(pane, cmds)
    116   local location = tlocation(pane)
    117   if location then
    118     if type(cmds) == 'table' then
    119       for _, c in ipairs(cmds) do run('tmux send -t %s "%s" enter', location, c) end
    120     else
    121       run('tmux send -t %s "%s" enter', location, cmds)
    122     end
    123     return true
    124   end
    125 end
    126 local function tjoin(target, source)
    127   local spane = tlocation(source)
    128   local tpane = tlocation(target)
    129   run('tmux joinp -s %s -t %s', spane, tpane)
    130 end
    131 
    132 ------------------
    133 ------ APP -------
    134 ------------------
    135 local App = {}
    136 
    137 ------ METATABLE -------
    138 function App:new(app)
    139   self.__index = self
    140   setmetatable(app, self)
    141   app.run = {}
    142   return app
    143 end
    144 ------------------------
    145 
    146 function App:start()
    147   tnew(self.key, self.cwd)
    148   tsend(self.key, self.cmd)
    149   io.write(string.format('Started %s', self.key), '\n')
    150 end
    151 
    152 function App:restart()
    153   tsend(self.key, {'^c', self.r_cmd or self.cmd})
    154   io.write(string.format('Restarted %s', self.key), '\n')
    155 end
    156 
    157 function App:stop()
    158   tkillp(self.key)
    159   io.write(string.format('Stopped %s', self.key), '\n')
    160   -- TODO: check if window is not empty and close it.. maybe
    161 end
    162 
    163 function App:open()
    164   local location = tlocation(self.key)
    165   if location then tattach(self.key) end
    166 end
    167 
    168 --- if pane exists
    169 function App:started()
    170   return tlocation(self.key)
    171   -- TODO: maybe check if command is running, is that possible?
    172 end
    173 
    174 ------ CREATE APPS -------
    175 local apps = {}
    176 for _, app in ipairs(enabled_apps) do apps[app.key] = App:new(app) end
    177 --------------------------
    178 
    179 ------ SESSION STARTED CHECK -------
    180 local fwin = 'initialize' -- name of first pane created alongside session
    181 -- on START action - if session is not started, create new
    182 if action == actions.start and not started() then
    183   local ok = run('tmux new -s %s -n %s -d', session, fwin)
    184   if not ok then
    185     io.stderr.write('Could not run session.')
    186     os.exit(1)
    187   end
    188   io.write(string.format('Started session "%s"', session), '\n')
    189 end
    190 -- on NON-START action - if session is not started, exit
    191 if action ~= actions.start and not started() then
    192   io.stderr:write('Session not running! Start session first.\n')
    193   os.exit(1)
    194 end
    195 ------------------------------------
    196 
    197 ------ PARSE ARGS -------
    198 local curr_apps = {}
    199 for _, a in ipairs(arg) do
    200   local key_sequence = {}
    201   for k, _ in string.gmatch(a, '(%a+)%+?') do
    202     local app = apps[k]
    203     if app then
    204       -- COUPLES CHECK
    205       -- expand couples
    206       if app.apps then
    207         for _, couple_apps in ipairs(app.apps) do table.insert(curr_apps, couple_apps) end
    208       else
    209         table.insert(key_sequence, app)
    210       end
    211     else
    212       io.stderr:write('App with key "', k, '" not exists, ignoring.', '\n')
    213     end
    214   end
    215   table.insert(curr_apps, key_sequence)
    216 end
    217 
    218 ------ MAIN LOGIC -------
    219 for _, capp in ipairs(curr_apps) do
    220   local slaves = {} -- apps to join
    221   if not capp.key then
    222     for _, ca in ipairs(capp) do table.insert(slaves, ca) end
    223   else
    224     table.insert(slaves, capp)
    225   end
    226 
    227   for _, app in ipairs(slaves) do
    228     if action == actions.start then
    229       if app:started() then
    230         io.stderr:write(string.format('App \'%s\' is already running.\n', app.key))
    231       else
    232         app:start()
    233       end
    234 
    235     elseif action == actions.restart then
    236       if not app:started() then
    237         io.stderr:write(string.format('App \'%s\' not running.\n', app.key))
    238       else
    239         app:restart()
    240       end
    241 
    242     elseif action == actions.stop then
    243       if not app:started() then
    244         io.stderr:write(string.format('App \'%s\' not running.\n', app.key))
    245       else
    246         app:stop()
    247       end
    248 
    249     elseif action == actions.open then
    250       if not app:started() then
    251         io.stderr:write(string.format('App \'%s\' not running.\n', app.key))
    252       else
    253         app:open()
    254       end
    255     end
    256   end
    257 
    258   -- join slaves to master
    259   if action == actions.start or action == actions.join then
    260     local master = table.remove(slaves, 1)
    261     for _, app in ipairs(slaves) do tjoin(master.key, app.key) end
    262   end
    263 end
    264 ------------------------
    265 
    266 ----------------------
    267 ------ CLEANUP -------
    268 ----------------------
    269 local anything_running = false
    270 for _, app in pairs(apps) do
    271   if app:started() then
    272     anything_running = true
    273     break
    274   end
    275 end
    276 if anything_running then
    277   -- kill initial pane when tmux is created
    278   run('tmux killw -t %s:%s 2>> /dev/null', session, fwin)
    279 else
    280   -- kill whole session if nothing is running
    281   run('tmux kill-session -t %s 2>> /dev/null', session)
    282   io.write(string.format('killing session "%s"', session), '\n')
    283 end