Class: Beaker::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/beaker/command.rb

Overview

An object that represents a “command” on a remote host. Is responsible for munging the environment correctly. Probably poorly named.

Direct Known Subclasses

HostCommand, PuppetCommand, SedCommand

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command, args = [], options = {}) ⇒ Command

Note:

For backwards compatability we must support any number of strings or symbols (or arrays of strings an symbols) and essentially ensure they are in a flattened array, coerced to strings, and call #join(‘ ’) on it. We have options for the command line invocation that must be turned into ‘–key=value’ and similarly joined as well as a hash of environment key value pairs, and finally we need a hash of options to control the default envs that are included.

Returns a new instance of Command.

Examples:

Recommended usage programmatically:

Command.new('git add', files, :patch => true, 'ENV' => {'PATH' => '/opt/csw/bin'})

My favorite example of a signature that we must maintain

Command.new('puppet', :resource, 'scheduled_task', name,
            [ 'ensure=present',
              'command=c:\\\\windows\\\\system32\\\\notepad2.exe',
              "arguments=args-#{name}" ] )


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/beaker/command.rb', line 47

def initialize command, args = [], options = {}
  @command = command
  @options = options
  @args    = args
  @environment = {}
  @cmdexe = @options.delete(:cmdexe) || false
  @prepend_cmds = @options.delete(:prepend_cmds) || nil

  # this is deprecated and will not allow you to use a command line
  # option of `--environment`, please use ENV instead.
  [:ENV, :environment, 'environment', 'ENV'].each do |k|
     if @options[k].is_a?(Hash)
       @environment = @environment.merge(@options.delete(k))
     end
  end

end

Instance Attribute Details

#argsObject

An array of additional arguments to be supplied to the command



18
19
20
# File 'lib/beaker/command.rb', line 18

def args
  @args
end

#commandObject

A string representing the (possibly) incomplete command



9
10
11
# File 'lib/beaker/command.rb', line 9

def command
  @command
end

#environmentObject

A hash key-values where the keys are environment variables to be set



12
13
14
# File 'lib/beaker/command.rb', line 12

def environment
  @environment
end

#optionsObject

A hash of options. Keys with values of nil are considered flags



15
16
17
# File 'lib/beaker/command.rb', line 15

def options
  @options
end

Instance Method Details

#args_string(args = @args) ⇒ String

Returns String of the arguments for command.



119
120
121
# File 'lib/beaker/command.rb', line 119

def args_string args = @args
  args.flatten.compact.join(' ')
end

#cmd_line(host, cmd = @command, env = @environment, pc = @prepend_cmds) ⇒ String

Returns This returns the fully formed command line invocation.



72
73
74
75
76
77
78
79
# File 'lib/beaker/command.rb', line 72

def cmd_line host, cmd = @command, env = @environment, pc = @prepend_cmds
  env_string = env.nil? ? '' : environment_string_for( host, env )

  cygwin = ((host['platform'] =~ /windows/) and host.is_cygwin? and @cmdexe) ? 'cmd.exe /c' : nil

  # This will cause things like `puppet -t -v agent` which is maybe bad.
  [env_string, cygwin, pc, cmd, options_string, args_string].compact.reject(&:empty?).join(' ')
end

#environment_string_for(host, env) ⇒ String

Note:

I dislike the principle of this method. There is host specific knowledge contained here. Really the relationship should be reversed where a host is asked for an appropriate Command when given a generic Command.

Construct the environment string for this command



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/beaker/command.rb', line 140

def environment_string_for host, env
  return '' if env.empty?
  env_array = []
  env.each_key do |key|
    val = env[key]
    if val.is_a?(Array)
      val = val.join(':')
    else
      val = val.to_s
    end
    env_array << "#{key.to_s.upcase}=\"#{val}\""
  end

  if not host.is_powershell?
    environment_string = env_array.join(' ')
    "env #{environment_string}"
  else
    environment_string = ''
    env_array.each_with_index do |env|
      environment_string += "set #{env} && "
    end
    environment_string
  end

end

#options_string(opts = @options) ⇒ String

Note:

Why no. Not the least bit Unixy, why do you ask?

Returns String of the options and flags for command.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/beaker/command.rb', line 86

def options_string opts = @options
  flags = []
  options = opts.dup
  options.each_key do |key|
    if options[key] == nil
      flags << key
      options.delete(key)
    end
  end

  short_flags, long_flags = flags.partition {|flag| flag.to_s.length == 1 }
  parsed_short_flags = short_flags.map {|f| "-#{f}" }
  parsed_long_flags = long_flags.map {|f| "--#{f}" }

  short_opts, long_opts = {}, {}
  options.each_key do |key|
    if key.to_s.length == 1
      short_opts[key] = options[key]
    else
      long_opts[key] = options[key]
    end
  end
  parsed_short_opts = short_opts.map {|k,v| "-#{k}=#{v}" }
  parsed_long_opts = long_opts.map {|k,v| "--#{k}=#{v}" }

  return (parsed_short_flags +
          parsed_long_flags +
          parsed_short_opts + parsed_long_opts).join(' ')
end