Skip to content

Instantly share code, notes, and snippets.

@sue445
Last active December 9, 2015 11:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sue445/4b8013ad19a3f5917aee to your computer and use it in GitHub Desktop.
Save sue445/4b8013ad19a3f5917aee to your computer and use it in GitHub Desktop.
specinfra-plain_sudoの一部
# lib/specinfra/plain_sudo.rb
require "specinfra/plain_sudo/version"
require "specinfra"
require "active_support/all"
module Specinfra
module PlainSudo
# Your code goes here...
end
end
Specinfra::Backend::Ssh.class_eval do
require "specinfra/plain_sudo/build_command_with_plain_sudo"
alias_method_chain :build_command, :plain_sudo
end
# lib/specinfra/plain_sudo/build_command_with_plain_sudo.rb
module Specinfra
module PlainSudo
# sudoできないコマンドを列挙
CAN_NOT_SUDO_COMMANDS = %w(cd export umask)
# 引数のcommandにsudoをつけていいかどうかのチェック
def self.can_sudo?(command)
# 誤爆防止の為後ろに空白をいれたものでチェックする
if CAN_NOT_SUDO_COMMANDS.map{ |c| "#{c} " }.any?{ |c| command.start_with?(c) }
# sudoできないコマンドに1つでもマッチしてたらsudoできないようにする
false
else
true
end
end
end
end
def build_command_with_plain_sudo(original_command)
return build_command_without_plain_sudo(original_command) unless sudo?
return original_command if original_command.include?("sudo ")
# 環境変数とコマンドで分割する
# 例) KEY1='VALUE1' KEY2="VALUE2" ls /tmp だと
# environment: KEY1='VALUE1' KEY2="VALUE2"
# commands : ls /tmp
matched_data = %r(
^(?<environment>(\w+=["']?\w+["']?\s*)+)
(?<commands>.+)$
)x.match(original_command)
if matched_data
environment = matched_data[:environment].strip
commands = matched_data[:commands]
else
environment = nil
commands = original_command
end
formatted_command =
commands.split("&&").map do |command|
command.strip!
if Specinfra::PlainSudo.can_sudo?(command)
"sudo #{command}"
else
# sudo cd 〜 などができないため
command
end
end.join(" && ")
[environment, formatted_command].compact.join(" ")
end
# spec/specinfra/plain_sudo_spec.rb
describe Specinfra::Backend::Ssh do
let(:backend){ Specinfra::Backend::Ssh.instance }
describe "#build_command" do
subject{ backend.build_command(command) }
before do
# sudoじゃない場合はオリジナルのメソッドが呼ばれるはずなのでテスト不要
allow(backend).to receive(:sudo?){ true }
end
context "コマンドにsudoが含まれていない時" do
context "コマンドにcdが含まれていない時" do
let(:command){ "sl -l ." }
it { should eq "sudo sl -l ." }
end
context "コマンドにcdが含まれている時" do
let(:command){ "cd /usr/local/rbenv && git ls-remote origin HEAD | cut -f1" }
it { should eq "cd /usr/local/rbenv && sudo git ls-remote origin HEAD | cut -f1" }
end
context "コマンドにumaskが含まれている時" do
let(:command){ "umask 002 && mkdir /tmp/hoge" }
it { should eq "umask 002 && sudo mkdir /tmp/hoge" }
end
context "コマンドに環境変数が含まれている時" do
let(:command){ %q(KEY1='VALUE1' KEY2="VALUE2" ls /tmp) }
it { should eq %q(KEY1='VALUE1' KEY2="VALUE2" sudo ls /tmp) }
end
end
context "コマンドにsudoが含まれている時" do
let(:command){ "sudo sl -l ." }
it { should eq "sudo sl -l ." }
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment