tmux-persistence icon indicating copy to clipboard operation
tmux-persistence copied to clipboard

OSX Compatibility

Open beeftornado opened this issue 10 years ago • 4 comments

I don't have the time right now to submit a pull request because this probably no longer works in linux so I would need to add some OS detection and switches. Here is a version that runs in OSX 10.9.2 with ruby 1.9.2-p180.

Issues resolved:

  • Home directory expansion was not happening, causing the created folder to be in the current directory and literally be named with a tilde.
  • Directory creation was sort of broken, so changed Dir in one place to FileUtils.
  • Renamed .sessions to .tmux-sessions because it was too generic.
  • Most recent tmux version has slightly different argument names for its commands.
    • list-sessions command fixed
    • list-panes command fixed
  • ps command in OSX has different arguments, the current ones caused error.
  • The restore script was misformatted and wouldn't execute.
  • The restore script didn't have execute permissions.
#!/usr/bin/env ruby

require 'fileutils.rb'

# Start - Configuration Variables
sessionDir = ENV['HOME']+"/.tmux-sessions"
maxStoredSessions = 5
filesToRoll = 3
# End - Configuration Variables

FileUtils::makedirs(sessionDir) unless File.exists?(sessionDir)

files = []
Dir.entries(sessionDir).each do |e|
  if e !~ /^\./
    files << e
  end
end
files.sort! unless files.length == 0

if files.length > maxStoredSessions
  0.upto(filesToRoll - 1) do |index|
    File.delete( sessionDir+ "/" + files[index] )
  end
  puts "Rotated stored sessions"
end

#%x[rm #{sessionDir}/*-restore]

sessions = %x[tmux list-sessions -F "\#{session_name}"].split("\n")

sessions.each do |sessionName|
  rawPaneList = %x[tmux list-panes -t #{sessionName} -s -F "\#{window_index} \#{pane_index} \#{window_width} \#{window_height} \#{pane_width} \#{pane_height} \#{window_name} \#{pane_current_path} \#{pane_pid}"].split("\n")

  panes = []
  rawPaneList.each do |pane_line|
    temp_pane = pane_line.split(" ")
    panes.push({
      windowIndex: Integer(temp_pane[0]),
      paneIndex: Integer(temp_pane[1]),
      windowWidth: Integer(temp_pane[2]),
      windowHeight: Integer(temp_pane[3]),
      paneWidth: Integer(temp_pane[4]),
      paneHeight: Integer(temp_pane[5]),
      window_name: temp_pane[6],
      cwd: temp_pane[7],
      pid: temp_pane[8]
    })
  end

  sessionScript = ""
  panes.each do |pane|
    pane[:cmd] = %x[ps -o command -p #{pane[:pid]} | awk 'NR>1'].delete("\n")
    pane[:cmd] = %x[ps -o command #{pane[:pid]} | awk 'NR>1'].delete("\n").gsub(/^-/,"") unless pane[:cmd] != ""

    sessionScript += "tmux new-window -t $SESSION -a -n #{pane[:window_name]} \"cd #{pane[:cwd]} && #{pane[:cmd]}\"\n"

    if pane[:paneIndex] > 0
      if pane[:paneWidth] < pane[:windowWidth]
        sessionScript += "tmux join-pane -h -l #{pane[:paneWidth]} -s $SESSION:#{pane[:windowIndex] +1}.0 -t $SESSION:#{pane[:windowIndex]}\n"
      else
        sessionScript += "tmux join-pane -v -l #{pane[:paneHeight]} -s $SESSION:#{pane[:windowIndex] +1}.0 -t $SESSION:#{pane[:windowIndex]}\n"
      end
    end
  end

  restore_file = sessionDir + "/" + sessionName + "-restore"

  File.open(restore_file, "w") {
    |f| f.write(%Q[#!/usr/bin/env bash
SESSION=#{sessionName}

if [ -z $TMUX ]; then

  # if session already exists, attach
  tmux has-session -t $SESSION 
  if [ $? -eq 0 ]; then
    echo \"Session $SESSION already exists. Attaching...\"
    tmux attach -t $SESSION
    exit 0;
  fi

  # make new session
  tmux new-session -d -s $SESSION

  #{sessionScript}

  # attach to new session
  tmux select-window -t $SESSION:1
  tmux attach-session -t $SESSION

fi
  ])

    # make script executable
    f.chmod( 0744 )
  }
end

beeftornado avatar May 01 '14 22:05 beeftornado

A slightly modified version of this to work with byobu: https://gist.github.com/beeftornado/d98a9b9feed83b7ab2de

beeftornado avatar May 02 '14 19:05 beeftornado

@beeftornado thanks! This looks great. I'd like to maintain both Linux and Mac compatibility, but would definitely like to take advantage of the improvements you've made.

As soon as I've got a chance to do that (or if you do end up having time to submit that PR), I'll merge them. In the meantime, if you wouldn't mind I'll take this version and make an OSX branch of the project.

Also, is the byobu gist compatible with your osx changes and vanilla tmux?

geebee avatar May 02 '14 19:05 geebee

@geebee Feel free to do whatever you'd like with my changes.

For the byobu changes, I took my OSX version you see above and

  1. Renamed the destination session folder
  2. Changed the restoration commands in the restore script to call byobu instead of tmux. Using tmux to retrieve the window data is fine, but restoration has to go through byobu.

Other than those changes, it is exactly the same. So inherently, it does run on OSX, but the restore script won't run because, obviously, it no longer calls tmux. I uploaded the gist separately because I didn't know if byobu is in the scope of the project or not because even though it is just a wrapper around tmux, it is still different. You can add it to your project if you'd like as a separate script, or if you have an abundance of time, you can add detection in the backup script to see if the user is using byobu and switch the output accordingly.

Running byobu on my osx machine runs this process:

tmux -2 -f /usr/local/share/byobu/profiles/tmuxrc new-session -n - /usr/local/bin/byobu-shell

beeftornado avatar May 02 '14 23:05 beeftornado

Updated my byobu version to not create that first bogus window that is spawned from your current terminal. If your first window to be restored had panes, then the first pane was getting thrown into the first bogus window and the second pane was getting its own window at the end, which made no sense.

At least on my computer, this now reproduces the window structure exactly as I had it.

https://gist.github.com/beeftornado/d98a9b9feed83b7ab2de

beeftornado avatar May 30 '14 19:05 beeftornado