ruboty-exec_command 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6f31fbeb824f00f5843ea7a7168363a33539b82f
4
- data.tar.gz: d7fabdad9e511f00165e8096e828e83f1af70023
3
+ metadata.gz: ed267f398d5e36b654ce35cece09794eec585a8b
4
+ data.tar.gz: 36b55cda29a3336492150319973786b11805eab7
5
5
  SHA512:
6
- metadata.gz: 45bc5f831cdc072533200b0ce52c2a4dadc83cb9808c7620c407de2fbf4e64a30b7de6660c5c5b651b0c03693d32c9abab394577d1967b53891b30a3a186b3ce
7
- data.tar.gz: 6c91c79b5694c3017427aeea2f804395f662ff8bc949aa51a72fc1bf99436faa9fb43f3495162eeba4fc76cd174211d57466420764a83f6de57584360ea0cc6a
6
+ metadata.gz: d3616c0a4b014f983cf81f8838b5404ac654e391fa63dc984409b602adcff3809d9235ebbc58db2e2fba0a1a07a6fdf30ca5a189c2b6c361200fe9cce9fec6bf
7
+ data.tar.gz: 203d2ece0eefb17fd223a6740957ba576725a03c6acca090b3c5682d00efb0b08d5b69bc688563c1952d0e30edbdce0f422f67c1bab737a8145f07af2f0d2f52
data/README.md CHANGED
@@ -9,8 +9,9 @@ When you say '@bot: example hello', ruboty runs the command
9
9
  $PWD/commands/example/hello or $RUBOTY_ROOT/commands/example/hello
10
10
  if RUBOTY_ROOT is defined.
11
11
 
12
- For your convinience, please implement -h option into the
13
- command. The usage will be used for help message of ruboty.
12
+ All of commands under `commands/` directory are executed with `-h`
13
+ option once to gather their usage information used for help message
14
+ of ruboty. Please implement `-h` option into the commands.
14
15
 
15
16
  ## Command Controll
16
17
 
@@ -38,9 +39,26 @@ Or install it yourself as:
38
39
 
39
40
  $ gem install ruboty-exec_command
40
41
 
42
+ ## Environment Variables
43
+
44
+ | Name | Description | Default |
45
+ |--------------------------|------------------------------|-------------------|
46
+ | LOG_LEVEL | log level | 1 (Logger::INFO) |
47
+ | EXEC_COMMAND_OUTPUT_ROOT | The command output root | logs/exec_command |
48
+ | EXEC_COMMAND_OUTPUT_DIR | The command output directory | "#{root}/%Y-%m |
49
+
41
50
  ## History
42
51
 
43
- - 0.0.4:
52
+ - 0.1.2:
53
+ - fix: not to match with shorter name commands
54
+ - add: symlink to output files to tail -F easily
55
+ - add: Bundler.with_clean_env to run a ruby script with bundler inside ruboty
56
+ - add: logging to see what's going on with ruboty
57
+
58
+ - 0.1.1:
59
+ - each message contains PID
60
+
61
+ - 0.1.0:
44
62
  - command runs as a back ground thread
45
63
  - command accepts option arguments
46
64
 
@@ -1,7 +1,7 @@
1
1
  #!/bin/bash
2
2
 
3
3
  if [ "$1" == "-h" ]; then
4
- echo "sleep"
4
+ echo "sleep <seconds>"
5
5
  else
6
6
  echo "Have a good sleep." 1>&2
7
7
  sleep $*
@@ -19,16 +19,16 @@ module Ruboty
19
19
  def kill_command
20
20
  # TODO: command list lock
21
21
  # kill running process, command is "kill command <index>"
22
- killed = command_slot.kill(message.body.split.last.to_i)
23
-
24
- if killed.nil?
22
+ if command_slot.kill(message.body.split.last.to_i).nil?
25
23
  message.reply("Command [#{message.body.split.last}] not found.")
26
24
  end
27
25
  end
28
26
 
29
27
  def run_and_monitor(comm)
30
28
  pid = command_slot.run(comm)
31
- message.reply("[#{comm.command_name}] invoked.")
29
+ msg = "[#{comm.command_name}] invoked. PID: #{comm.pid}"
30
+ Ruboty.logger.info { "[EXEC_COMMAND] #{msg}" }
31
+ message.reply(msg)
32
32
 
33
33
  # Waiter thread
34
34
  thread = Thread.new do
@@ -36,15 +36,19 @@ module Ruboty
36
36
  command_slot.forget(pid)
37
37
 
38
38
  if status.exitstatus == 0
39
- message.reply("[#{comm.command_name}] completed successfully.")
39
+ msg = "[#{comm.command_name}] completed successfully. PID: #{comm.pid}"
40
+ Ruboty.logger.info { "[EXEC_COMMAND] #{msg}" }
41
+ message.reply(msg)
40
42
  message.reply(comm.stdout_log.chomp)
41
43
  elsif status.signaled?
42
- message.reply("[#{comm.command_name}] killed by signal #{status.termsig}")
44
+ msg = "[#{comm.command_name}] killed by signal #{status.termsig} PID: #{comm.pid}"
45
+ Ruboty.logger.info { "[EXEC_COMMAND] #{msg}" }
46
+ message.reply(msg)
43
47
  else
44
- message.reply("[#{comm.command_name}] exit status with #{status}\n" +
45
- comm.stdout_log +
46
- "stderr: " + comm.stderr_log.chomp
47
- )
48
+ msg = "[#{comm.command_name}] exit status with #{status} PID: #{comm.pid}\n" +
49
+ comm.stdout_log + "stderr: " + comm.stderr_log.chomp
50
+ Ruboty.logger.info { "[EXEC_COMMAND] #{msg}" }
51
+ message.reply(msg)
48
52
  end
49
53
  end
50
54
 
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+
1
3
  module Ruboty
2
4
  module ExecCommand
3
5
  class Command
@@ -11,8 +13,8 @@ module Ruboty
11
13
  "#{ruboty_root}/commands"
12
14
  end
13
15
 
14
- def log_root
15
- "#{ruboty_root}/logs/exec_command"
16
+ def output_root
17
+ ENV['EXEC_COMMAND_OUTPUT_ROOT'] || "#{ruboty_root}/logs/exec_command"
16
18
  end
17
19
 
18
20
  def command?(path)
@@ -86,28 +88,38 @@ module Ruboty
86
88
  Time.now.strftime "%Y-%m-%d_%H:%M:%S"
87
89
  end
88
90
 
89
- def log_dir
90
- d = "#{self.class.log_root}/#{this_month}"
91
+ def output_dir
92
+ d = ENV['EXEC_COMMAND_OUTPUT_DIR'] || "#{self.class.output_root}/#{this_month}"
91
93
  FileUtils.mkdir_p(d) if not Dir.exists?(d)
92
94
  d
93
95
  end
94
96
 
97
+ # symlink to output_file_name so that we can easily tail -F
98
+ def symlink_file_name
99
+ %Q(#{output_dir}/#{command_name.gsub(" ", "_")})
100
+ end
101
+
95
102
  def output_file_name
96
- %Q(#{log_dir}/#{command_name.gsub(" ", "_")}-#{this_time})
103
+ %Q(#{output_dir}/#{command_name.gsub(" ", "_")}-#{this_time})
104
+ end
105
+
106
+ # return symlink output file name [stdout, stderr]
107
+ def symlink_files
108
+ ["#{symlink_file_name}.out", "#{symlink_file_name}.err"]
97
109
  end
98
110
 
111
+ # return temporary output file name [stdout, stderr]
99
112
  def output_files
100
- # return temporary output file IO objects [stdout, stderr]
101
113
  ["#{output_file_name}.out", "#{output_file_name}.err"]
102
114
  end
103
115
 
116
+ # return contents of stdout
104
117
  def stdout_log
105
- # return contents of stdout
106
118
  File.open(output_files[0]).read
107
119
  end
108
120
 
121
+ # return contents of stderr
109
122
  def stderr_log
110
- # return contents of stderr
111
123
  File.open(output_files[1]).read
112
124
  end
113
125
 
@@ -118,14 +130,30 @@ module Ruboty
118
130
  def run_bg(args=[])
119
131
  stdout, stderr = output_files
120
132
  @start_at = this_time
121
- @pid = Process.spawn(%Q(#{absolute_path} #{args.join(" ")}),
122
- pgroup: true, out: stdout, err: stderr)
133
+ stdout_link, stderr_link = symlink_files
134
+ FileUtils.ln_sf(stdout, stdout_link)
135
+ FileUtils.ln_sf(stderr, stderr_link)
136
+ cmd = %Q(#{absolute_path} #{args.join(" ")})
137
+ with_clean_env do
138
+ @pid = Process.spawn(cmd, pgroup: true, out: stdout, err: stderr)
139
+ end
140
+ Ruboty.logger.debug { "[EXEC_COMMAND] Invoked `#{cmd}`. PID: #{@pid}" }
141
+ @pid
123
142
  end
124
143
 
125
144
  def help
126
145
  run(args=['-h']).chomp
127
146
  end
128
147
 
148
+ def with_clean_env(&block)
149
+ if defined?(Bundler)
150
+ Bundler.with_clean_env do
151
+ yield
152
+ end
153
+ else
154
+ yield
155
+ end
156
+ end
129
157
  end
130
158
  end
131
159
  end
@@ -28,9 +28,9 @@ module Ruboty
28
28
  found = @commands.index { |c| c.pid == idx_or_pid }
29
29
 
30
30
  if found.nil?
31
+ # look for the command with index
31
32
  i = idx_or_pid.to_i
32
- num_commands = @commands.size
33
- if i <= 0 or i > num_commands
33
+ if i <= 0 or i > @commands.size
34
34
  nil
35
35
  else
36
36
  @commands[i-1]
@@ -49,10 +49,8 @@ module Ruboty
49
49
  if @commands.size == 0
50
50
  "No command running."
51
51
  else
52
- number = 0
53
- @commands.map do |c|
54
- number += 1
55
- "#{number}: #{c.command_name} (PID[#{c.pid}], started at #{c.start_at})\n"
52
+ @commands.map.with_index do |c, number|
53
+ "#{number+1}: #{c.command_name} (PID[#{c.pid}], started at #{c.start_at})\n"
56
54
  end.join.chomp
57
55
  end
58
56
  end
@@ -62,8 +60,9 @@ module Ruboty
62
60
  unless command.nil?
63
61
  Process.kill(-9, command.pid) # kill process group
64
62
  forget(command.pid)
63
+ else
64
+ false
65
65
  end
66
- command
67
66
  end
68
67
  end
69
68
  end
@@ -1,5 +1,5 @@
1
1
  module Ruboty
2
2
  module ExecCommand
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
@@ -14,10 +14,11 @@ module Ruboty
14
14
  # under "commands" directory. The path name to the
15
15
  # executable command is gonna be a command name.
16
16
  # i.e. commands/server/monitor => /server monitor/
17
+ # All of commands are called with -h option on the startup.
17
18
  # The command should return a usage with -h option
18
19
  def self.register_commands
19
20
  Ruboty::ExecCommand::Command.all.each do |e|
20
- on /#{e.command_name}/i, name: "command_handler", description: e.help
21
+ on /#{e.command_name}(?:\z|\s+)/i, name: "command_handler", description: e.help
21
22
  end
22
23
  end
23
24
 
@@ -19,7 +19,7 @@ describe Ruboty::Handlers::Command do
19
19
  end
20
20
 
21
21
  let(:said_to_sleep) do
22
- "@ruboty example sleep 1"
22
+ "@ruboty example sleep 5"
23
23
  end
24
24
 
25
25
  let(:said_to_kill) do
@@ -31,15 +31,15 @@ describe Ruboty::Handlers::Command do
31
31
  end
32
32
 
33
33
  let(:replied) do
34
- "[example hello] invoked."
34
+ /\[example hello\] invoked. PID: \d+/
35
35
  end
36
36
 
37
37
  let(:replied_sleep) do
38
- "[example sleep] invoked."
38
+ /\[example sleep\] invoked. PID: \d+/
39
39
  end
40
40
 
41
41
  let(:replied_success) do
42
- "[example hello] completed successfully."
42
+ /\[example hello\] completed successfully. PID: \d+/
43
43
  end
44
44
 
45
45
  let(:replied_stdout) do
@@ -47,7 +47,7 @@ describe Ruboty::Handlers::Command do
47
47
  end
48
48
 
49
49
  let(:replied_after_kill) do
50
- "[example sleep] killed by signal 9"
50
+ /\[example sleep\] killed by signal 9 PID: \d+/
51
51
  end
52
52
 
53
53
  def reply_data(body, original_body)
@@ -64,6 +64,13 @@ describe Ruboty::Handlers::Command do
64
64
  }
65
65
  end
66
66
 
67
+
68
+ def should_receive_body(reply)
69
+ robot.should_receive(:say) do |args, options|
70
+ args[:body].should match(reply)
71
+ end
72
+ end
73
+
67
74
  before do
68
75
  ENV['RUBOTY_ROOT'] = Dir.pwd
69
76
  end
@@ -75,8 +82,9 @@ describe Ruboty::Handlers::Command do
75
82
  end
76
83
 
77
84
  it "run example command" do
78
- robot.should_receive(:say).with(reply_data(replied, said))
79
- robot.should_receive(:say).with(reply_data(replied_success, said))
85
+ #robot.should_receive(:say).with(reply_data(replied, said))
86
+ should_receive_body(replied)
87
+ should_receive_body(replied_success)
80
88
  robot.should_receive(:say).with(reply_data(replied_stdout, said))
81
89
  robot.receive(body: said, from: from, to: to)
82
90
  end
@@ -90,8 +98,8 @@ describe Ruboty::Handlers::Command do
90
98
  it "run kill command" do
91
99
  thread = Thread.new do
92
100
  ENV['RUBOTY_ENV'] = "blocked_test"
93
- robot.should_receive(:say).with(reply_data(replied_sleep, said_to_sleep))
94
- robot.should_receive(:say).with(reply_data(replied_after_kill, said_to_sleep))
101
+ should_receive_body(replied_sleep)
102
+ should_receive_body(replied_after_kill)
95
103
  robot.receive(body: said_to_sleep, from: from, to: to)
96
104
  end
97
105
 
@@ -103,7 +111,7 @@ describe Ruboty::Handlers::Command do
103
111
  # Wait killed message
104
112
  thread.join
105
113
  end
106
-
114
+
107
115
  after do
108
116
  ENV['RUBOTY_ENV'] = "test"
109
117
  end
metadata CHANGED
@@ -1,55 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruboty-exec_command
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nakai Tooru
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-04 00:00:00.000000000 Z
11
+ date: 2015-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruboty
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.7'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.7'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '10.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '10.0'
55
55
  - !ruby/object:Gem::Dependency
@@ -70,42 +70,42 @@ dependencies:
70
70
  name: guard-rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: growl
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: simplecov
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '>='
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  description: ''
@@ -115,7 +115,7 @@ executables: []
115
115
  extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
- - .gitignore
118
+ - ".gitignore"
119
119
  - Gemfile
120
120
  - Guardfile
121
121
  - LICENSE.txt
@@ -144,17 +144,17 @@ require_paths:
144
144
  - lib
145
145
  required_ruby_version: !ruby/object:Gem::Requirement
146
146
  requirements:
147
- - - '>='
147
+ - - ">="
148
148
  - !ruby/object:Gem::Version
149
149
  version: '0'
150
150
  required_rubygems_version: !ruby/object:Gem::Requirement
151
151
  requirements:
152
- - - '>='
152
+ - - ">="
153
153
  - !ruby/object:Gem::Version
154
154
  version: '0'
155
155
  requirements: []
156
156
  rubyforge_project:
157
- rubygems_version: 2.0.14
157
+ rubygems_version: 2.4.5
158
158
  signing_key:
159
159
  specification_version: 4
160
160
  summary: Add command to ruboty as a handler