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



149
150
151
152
153
154
155
156
# File 'lib/loom/shell/core.rb', line 149

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



135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/loom/shell/core.rb', line 135

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



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

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

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

  @session << result
  Loom.log.debug result.stdout unless result.stdout.empty?
  Loom.log.debug result.stderr unless result.stderr.empty?
  result
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



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

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

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



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

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
54
# 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.
  # @see the TODO at Loom::Runner+execute_pattern+
  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



163
164
165
# File 'lib/loom/shell/core.rb', line 163

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

#verify(*check) ⇒ Object

Raises:



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

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

#verify_which(command) ⇒ Object



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

def verify_which(command)
  verify :which, command
end

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



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

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