Last active
March 15, 2018 15:10
-
-
Save jorgemorgado/b49c79340a3c2191eb2a066798c16f5e to your computer and use it in GitHub Desktop.
Given a list of servers, spawns a matrix of iTerm terminals
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* | |
Given a list of servers, spawns a matrix of iTerm terminals. | |
Then, it connects (via SSH) to each server on the list. | |
If you need to connect a lots of servers at the same time and | |
then run the same command(s) on all of them, this is a time saver. | |
Bonus: after connecting, type Cmd + Option + I to broadcast input | |
to all panes in the current tab. | |
Author: Jorge Morgado <jorge@morgado.ch> | |
Copyright (c)2018. All rights reserved. | |
TODO: | |
* Reduce the font size on every terminal based on the length of the server's list | |
*) | |
(* | |
Function: __split | |
Splits theString by theDelimiter and returns an array with the result. | |
*) | |
on __split(theString, theDelimiter) | |
-- save delimiters to restore old settings | |
set oldDelimiters to AppleScript's text item delimiters | |
-- set delimiters to delimiter to be used | |
set AppleScript's text item delimiters to theDelimiter | |
-- create the array | |
set theArray to every text item of theString | |
-- restore the old setting | |
set AppleScript's text item delimiters to oldDelimiters | |
-- return the result | |
return theArray | |
end __split | |
(* | |
Function: __matrix_size | |
Calculate the matrix size based on the number of terminals to open. | |
The maximum number of rows and columns is also provided | |
to guarantee the calculation does not exceed that size. | |
*) | |
on __matrix_size(nrTerminals, maxRows, maxCols) | |
set c to 1 | |
repeat until c is maxCols + 1 | |
set r to 1 | |
repeat until r is maxRows + 1 | |
if c * r ≥ nrTerminals then | |
return {r, c} | |
end if | |
set r to r + 1 | |
end repeat | |
set c to c + 1 | |
end repeat | |
return {0, 0} | |
end __matrix_size | |
-- Ask for the list of servers to connect | |
set questionServers to display dialog ¬ | |
"Enter the list of machines to connect (one per line):" default answer linefeed & linefeed | |
set answerServers to text returned of questionServers | |
(* | |
# For testing, comment the previous dialog section and set the max_servers below | |
#set max_servers to 42 | |
set max_servers to 42 | |
set answerServers to {"server1"} | |
repeat with i from 2 to max_servers | |
copy "server" & i to the end of answerServers | |
end repeat | |
*) | |
-- Split the list of servers into an array | |
set listServers to my __split(answerServers, linefeed) | |
-- Get the size of the servers list | |
set sizeListServers to count of listServers | |
-- Pre-define some iTerm matrix sizes based on the amount of servers | |
if sizeListServers ≤ 2 then | |
set MAX_COLS to 2 | |
set MAX_ROWS to 1 | |
else if sizeListServers ≤ 6 then | |
set MAX_COLS to 2 | |
set MAX_ROWS to 3 | |
else if sizeListServers ≤ 9 then | |
set MAX_COLS to 3 | |
set MAX_ROWS to 3 | |
else if sizeListServers ≤ 16 then | |
set MAX_COLS to 4 | |
set MAX_ROWS to 4 | |
else if sizeListServers ≤ 25 then | |
set MAX_COLS to 5 | |
set MAX_ROWS to 5 | |
else | |
# It doesn't support more than 42 terminals | |
# Because I don't have a really BIG screen :-( | |
set MAX_COLS to 6 | |
set MAX_ROWS to 7 | |
end if | |
-- Calculate the matrix dimensions | |
set {rowsMatrix, colsMatrix} to my __matrix_size(sizeListServers, MAX_ROWS, MAX_COLS) | |
if rowsMatrix = 0 or colsMatrix = 0 then | |
display dialog "Your list is too big for me! I only support up to " & (MAX_ROWS * MAX_COLS) & " servers. Exiting..." buttons ["OK"] default button 1 | |
error number -128 | |
end if | |
-- Correct the number of terminals on the last column if needed | |
if rowsMatrix * colsMatrix > sizeListServers then | |
set rowsLast to rowsMatrix - ((rowsMatrix * colsMatrix) - sizeListServers) | |
else | |
set rowsLast to rowsMatrix | |
end if | |
-- The base position for the iTerm window. This is postion (X,Y) of the canvas. | |
set basePosX to 0 | |
set basePosY to 0 | |
set bottomPosX to (675 * colsMatrix) * 0.6 | |
set bottomPosY to (440 * rowsMatrix) | |
-- Open an iTerm window (if running) or start the application (if not yet running) | |
if application "iTerm" is running then | |
tell application "iTerm" | |
create window with default profile | |
end tell | |
else | |
activate application "iTerm" | |
end if | |
tell application "iTerm" | |
set current_window to current window | |
# Resize the main window for the iTerm matrix | |
tell current_window | |
set bounds to {basePosX, basePosY, bottomPosX, bottomPosY} | |
end tell | |
set sessionID to 1 | |
# Split the main window into the calculated nr of columns | |
repeat with c from 1 to colsMatrix - 1 | |
tell session sessionID of current tab of current_window | |
split vertically with default profile | |
end tell | |
# Then, for each column, split it into the calculated nr or rows | |
repeat with r from 1 to rowsMatrix - 1 | |
tell session sessionID of current tab of current_window | |
split horizontally with default profile | |
end tell | |
set sessionID to sessionID + 1 | |
end repeat | |
set sessionID to sessionID + 1 | |
end repeat | |
# Split the last column (this is a special case because the last | |
# column might not have the same amount of rows; it can also be that | |
# the last column is simultaneously the first and only column). | |
repeat with r from 1 to rowsLast - 1 | |
tell session sessionID of current tab of current_window | |
split horizontally with default profile | |
end tell | |
set sessionID to sessionID + 1 | |
end repeat | |
(* | |
log "-- <DEBUG> --------------------" | |
log "=> total servers = " & sizeListServers | |
log "MAX_ROWS = " & MAX_ROWS | |
log "MAX_COLS = " & MAX_COLS | |
log "rowsMatrix = " & rowsMatrix | |
log "colsMatrix = " & colsMatrix | |
log "rowsLast = " & rowsLast | |
log "-- </DEBUG> -------------------" | |
*) | |
(* | |
# This is the simple case where it just opens a connection to each | |
# server in order of the sessions. No glamour... | |
repeat with n from 1 to (count of listServers) | |
tell session n of current tab of current_window | |
set serverName to item n of listServers | |
-- write text "echo " & serverName | |
write text "ssh " & serverName | |
-- delay 1 | |
end tell | |
end repeat | |
*) | |
# The calibration value is used for edge cases where the first sessionID1 | |
# computes to 0 (zero). For example, the case with 4 terminals. | |
set calibration_value to 0 | |
# In this case, opens the connections "in pairs" (side-by-side). | |
# It makes more sense for cases where the list of servers contains | |
# pairs of servers (e.g., a cluster) in the right order. In this case, | |
# connections are opened next to each other which it's easier to | |
# compare both terminals (except on the last column which might have | |
# less rows). | |
set n to 1 | |
repeat with nrCol from 1 to colsMatrix by 2 | |
repeat with nrRow from 1 to rowsMatrix | |
set sessionID1 to (nrCol * rowsMatrix) + nrRow - MAX_ROWS | |
# Can't have sessionID zero. Correct that to +1 | |
if sessionID1 = 0 then | |
set calibration_value to 1 | |
end if | |
set sessionID1 to sessionID1 + calibration_value | |
set sessionID2 to sessionID1 + rowsMatrix | |
if sessionID1 ≤ sizeListServers then | |
tell session sessionID1 of current tab of current_window | |
set serverName to item n of listServers | |
-- write text "echo " & serverName | |
-- log "echo " & serverName | |
write text "ssh " & serverName | |
end tell | |
set n to n + 1 | |
end if | |
if sessionID2 ≤ sizeListServers then | |
tell session sessionID2 of current tab of current_window | |
set serverName to item n of listServers | |
-- write text "echo " & serverName | |
-- log "echo " & serverName | |
write text "ssh " & serverName | |
end tell | |
set n to n + 1 | |
end if | |
end repeat | |
delay 1 | |
end repeat | |
end tell |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment