Igor Dobryn
about IT

ITerm2 script to start processes

Working with a current project it was not a big deal to start 2-3 services to develop until recently. The last requested change required to run 11 different processes. Each process is either running application server (like rails server or express.js server) or assets server (i.e. webpack dev server). Starting the project became annoying and I took a thought about a more convenient way to start all the services. ITerm2 scripting seemed to be a good fit.

I made myself the following requirements:

  1. Separate ITerm2 windows - one window for running services and another one for the rest of the needs
  2. Every service should run in a separate tab
  3. Tab should have a reasonable name to quickly identify the microservice
  4. The script should not be rigid for the number of services

After reviewing the docs I found the following useful commands:

  1. Open new ITerm2 window: Window.async_create()
  2. Open new ITerm2 tab: window.async_create_tab()
  3. Set tab title: tab.async_set_title
  4. Run command in the tab: tab.current_session.async_send_text()

Let’s create new ITerm2 script by choosing Scripts -> Manage -> New Python Script in Basic python environment of a Simple template with a name my-script:

#!/usr/bin/env python3.7

import iterm2

# This script was created with the "basic" environment which does not support adding dependencies
# with pip.
async def main(connection):
  # Your code goes here. Here's a bit of example code that adds a tab to the current window:
  app = await iterm2.async_get_app(connection)
  window = app.current_terminal_window
  if window is not None:
    await window.async_create_tab()
  else:
    # You can view this message in the script console.
    print("No current window")

iterm2.run_until_complete(main)

 
Define a function to start a service in the given tab. Where service consists of title and commands to run:

async def run_service_in_tab(tab, service):
  await tab.async_set_title(service['title'])

  for command in service['commands']:
    await tab.current_session.async_send_text(f'{command}\n')  

 
Now we have to define a list of services and run them in a loop. The full script will have the following shape:

#!/usr/bin/env python3

import iterm2

services = [

  {
    'title': 'My 1st Service',
    'commands': [
      'echo "cd to-proper-dir"',
      'echo "command to start the service"'     
    ]
  },
  {
    'title': 'My 2nd Service',
    'commands': [
      'echo "cd to-proper-dir"',
      'echo "command to start the service"'     
    ]
  },
];

async def run_service_in_tab(tab, service):
  await tab.async_set_title(service['title'])

  for command in service['commands']:
    await tab.current_session.async_send_text(f'{command}\n')  

async def main(connection):
  app = await iterm2.async_get_app(connection)
  window = await iterm2.Window.async_create(connection)

  for index, service in enumerate(services):
    tab = window.current_tab if index == 0 else await window.async_create_tab()
    await run_service_in_tab(window.current_tab, service)

iterm2.run_until_complete(main)

 
Remark, we don’t need to window.async_create_tab() for the first service as the window is created with a default tab

That’s it.

ITerm2 Python Scripting