1
0
Fork 0
mirror of https://github.com/capistrano/capistrano synced 2023-03-27 23:21:18 -04:00

Monkey patch SSHKit to expose current backend

Eventually this will be part of SSHKit itself, but for flexibility in using
Capistrano with older SSHKit versions, I'm including this here as a monkey
patch.

The point of SSHKit::Backend.current is to give code access to the current
Backend without having to pass around a reference to it. For example, consider
a `git` helper that executes a git command:

def git(*args)
  SSHKit::Backend.current.execute(:git, *args)
end

Thanks to `current`, we can use this git method wherever we are in an `on`
block, without having to pass a reference to `self`:

on release_roles(:all) do
  git "status"
end

Without the thread local, the same task would be much more awkward due to the
necessary passing of `self`:

def git(backend, *args)
  backend.execute(:git, *args)
end

on release_roles(:all) do
  git self, "status"
end

To someone not intimately familiar with SSHKit, what `self` in this context is
confusing and not obvious at all. It is because SSHKit uses `instance_exec`
within the `on` block that `self` magically transforms.

Better to avoid using `self` altogether and prefer the thread local.
This commit is contained in:
Matt Brictson 2016-01-17 16:01:21 -08:00
parent 9168947002
commit 3b9c90327b
2 changed files with 55 additions and 0 deletions

View file

@ -0,0 +1,25 @@
require "sshkit/backends/abstract"
# Monkey patch older versions of SSHKit to make the currently-executing Backend
# available via a thread local value.
#
# TODO: Remove this code once capistrano.gemspec requires newer SSHKit version.
unless SSHKit::Backend.respond_to?(:current)
module SSHKit
module Backend
def self.current
Thread.current["sshkit_backend"]
end
class Abstract
def run
Thread.current["sshkit_backend"] = self
instance_exec(@host, &@block)
ensure
Thread.current["sshkit_backend"] = nil
end
end
end
end
end

View file

@ -0,0 +1,30 @@
require "spec_helper"
require "capistrano/ext/sshkit/backend/thread_local"
module SSHKit
module Backend
describe "#current" do
require "sshkit/dsl"
it "refers to the currently executing backend" do
backend = nil
current = nil
on(:local) do
backend = self
current = SSHKit::Backend.current
end
expect(current).to eq(backend)
end
it "is nil outside of an on block" do
on(:local) do
# nothing
end
expect(SSHKit::Backend.current).to be_nil
end
end
end
end