Class: Loom::Shell::Core

Inherits:
Object
  • Object
show all
Defined in:
lib/loom/shell/core.rb

Direct Known Subclasses

LocalShell

Defined Under Namespace

Classes: LocalShell

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mod_loader, sshkit_backend, dry_run = false) ⇒ Core

Returns a new instance of Core.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/loom/shell/core.rb', line 9

def initialize(mod_loader, sshkit_backend, dry_run=false)
  @dry_run = dry_run
  @mod_loader = mod_loader
  @sshkit_backend = sshkit_backend

  @session = Session.new
  @shell_api = Api.new self

  @cmd_wrappers = []
  @sudo_users = []

  # TODO: @sudo_dirs is a smelly workaround for not having a better
  # understanding of sudo security policies and inheriting environments.
  @sudo_dirs = []
end

Instance Attribute Details

#dry_runObject (readonly)

Returns the value of attribute dry_run.



25
26
27
# File 'lib/loom/shell/core.rb', line 25

def dry_run
  @dry_run
end

#mod_loaderObject (readonly)

Returns the value of attribute mod_loader.



25
26
27
# File 'lib/loom/shell/core.rb', line 25

def mod_loader
  @mod_loader
end

#sessionObject (readonly)

Returns the value of attribute session.



25
26
27
# File 'lib/loom/shell/core.rb', line 25

def session
  @session
end

#shell_apiObject (readonly)

Returns the value of attribute shell_api.



25
26
27
# File 'lib/loom/shell/core.rb', line 25

def shell_api
  @shell_api
end

Instance Method Details

#capture(*cmd_parts) ⇒ Object



146
147
148
149
150
151
152
153
# File 'lib/loom/shell/core.rb', line 146

def capture(*cmd_parts)
  if @dry_run
    # TODO: I'm not sure what to do about this.
    Loom.log.warn "`capture` during dry run won't do what you want"
  end
  execute *cmd_parts
  @session.last.stdout.strip
end

#cd(path, &block) ⇒ Object

Loom.log.debug3(self) { “sudo legacy… the other way” }

  sudo_stack_and_wrap(user, *sudo_cmd, &block)
else
  Loom.log.debug3(self) { "sudo legacy" }
  sudo_stack_and_wrap(user, *sudo_cmd)
end

end



132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/loom/shell/core.rb', line 132

def cd(path, &block)
  Loom.log.debug1(self) { "cd => #{path} #{block}" }

  # TODO: this might creates problems with relative paths, e.g.
  # loom.cd foo => cd ./foo
  # loom.sudo user => cd ./foo; sudo user
  @sudo_dirs.push path
  begin
    @sshkit_backend.within path, &block
  ensure
    @sudo_dirs.pop
  end
end

#execute(*cmd_parts, is_test: false, **cmd_opts) ⇒ Object Also known as: exec



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/loom/shell/core.rb', line 164

def execute(*cmd_parts, is_test: false, **cmd_opts)
  cmd_parts.compact!
  raise "empty command passed to execute" if cmd_parts.empty?

  result = if @dry_run
             wrap :printf, :first => true do
               cmd_result = execute_internal *cmd_parts, **cmd_opts
               Loom.log.info do
                 "\t%s" % prompt_fmt(cmd_result.full_stdout.strip)
               end
               cmd_result
             end
           else
             execute_internal *cmd_parts, **cmd_opts
           end
  @session << CmdResult.create_from_sshkit_command(result, is_test, self)

  Loom.log.debug @session.last.stdout unless @session.last.stdout.empty?
  Loom.log.debug @session.last.stderr unless @session.last.stderr.empty?
  @session.last
end

#is_sudo?Boolean

Returns:

  • (Boolean)


27
28
29
# File 'lib/loom/shell/core.rb', line 27

def is_sudo?
  !@sudo_users.empty?
end

#localObject



31
32
33
# File 'lib/loom/shell/core.rb', line 31

def local
  @local ||= LocalShell.new @mod_loader, @session, @dry_run
end

#pipe(*cmds) ⇒ Object



155
156
157
158
# File 'lib/loom/shell/core.rb', line 155

def pipe(*cmds)
  cmd = CmdWrapper.pipe *cmds.map { |*cmd| CmdWrapper.new *cmd }
  execute cmd
end

#sudo(user = nil, *sudo_cmd, &block) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/loom/shell/core.rb', line 81

def sudo(user=nil, *sudo_cmd, &block)
  user ||= :root
  Loom.log.debug1(self) { "sudo => #{user} #{sudo_cmd} #{block}" }

  is_new_sudoer = @sudo_users.last.to_sym != user.to_sym rescue true

  @sudo_dirs.push(capture :pwd)
  @sudo_users.push << user if is_new_sudoer

  sudo_wrapper = [:sudo, "-u", user, "--", "/bin/sh", "-c"]
  sudo_cmd.compact!
  begin
    wrap *sudo_wrapper, :should_quote => true do
      execute *sudo_cmd unless sudo_cmd.empty?
      yield if block_given?
    end
  ensure
    @sudo_users.pop if is_new_sudoer
    @sudo_dirs.pop
  end
end

#test(*cmd, check: :exit_status, **cmd_opts) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/loom/shell/core.rb', line 35

def test(*cmd, check: :exit_status, **cmd_opts)
  # TODO: is_test smells like a hack. I can't rely on Command#is_success?
  # here (returned from execute) because I'm overriding it with :is_test =>
  # true. Fix Command#is_success? to not be a lie.. that is a lazy hack for
  # result reporting (I think the fix & feature) is to define Command
  # objects and declare style of reporting & error code handling it
  # has. Commands can be defined to ignore errors and just return their
  # results.
  execute *cmd, :is_test => true, **cmd_opts

  case check
  when :exit_status
    @session.last.exit_status == 0
  when :stderr
    @session.last.stderr.empty?
  else
    raise "unknown test check => #{check}"
  end
end

#upload(local_path, remote_path) ⇒ Object



160
161
162
# File 'lib/loom/shell/core.rb', line 160

def upload(local_path, remote_path)
  @sshkit_backend.upload! local_path, remote_path
end

#verify(*check) ⇒ Object

Raises:



55
56
57
# File 'lib/loom/shell/core.rb', line 55

def verify(*check)
  raise VerifyError, check unless test *check
end

#verify_which(command) ⇒ Object



59
60
61
# File 'lib/loom/shell/core.rb', line 59

def verify_which(command)
  verify :which, command
end

#wrap(*wrapper, first: false, should_quote: true, &block) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/loom/shell/core.rb', line 63

def wrap(*wrapper, first: false, should_quote: true, &block)
  raise "missing block for +wrap+" unless block_given?

  cmd_wrapper = CmdWrapper.new(*wrapper, should_quote: should_quote)

  if first
    @cmd_wrappers.unshift(cmd_wrapper)
  else
    @cmd_wrappers.push(cmd_wrapper)
  end

  begin
    yield
  ensure
    first ? @cmd_wrappers.shift : @cmd_wrappers.pop
  end
end