unix_commander 0.0.2 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -34,6 +34,17 @@ comm = UnixCommander::Command.new
34
34
  comm.cat("file").tail("-n10").grep("'something'").run
35
35
  ```
36
36
 
37
+ <<<<<<< HEAD
38
+ =======
39
+ You can use redirection too
40
+ ```
41
+ require 'unix_commander'
42
+
43
+ comm = UnixCommander::Command.new
44
+ comm.cat("file").tail("-n10").grep("'something'").out_to("my_file").err_to("/dev/null")
45
+ ```
46
+
47
+ >>>>>>> development
37
48
  You don't have to run the commands right away, we can create a command and run it whe we see fit:
38
49
 
39
50
  ```
@@ -56,7 +67,21 @@ require 'unix_commander'
56
67
  comm = UnixCommander::Command.new
57
68
  comm.cat("file").tail("-n10").grep("'something'").run_ssh("Batou99","secret","remote_server")
58
69
  ```
70
+ <<<<<<< HEAD
71
+ =======
59
72
 
73
+ After running a command you can access it output using **out**, **err** or **both**
74
+ ```
75
+ require 'unix_commander'
76
+ >>>>>>> development
77
+
78
+ comm = UnixCommander::Command.new
79
+ comm.cat("file").tail("-n10").grep("'something'").run_ssh("Batou99","secret","remote_server").out
80
+ # Or
81
+ comm.cat("file").tail("-n10").grep("'something'").run_ssh("Batou99","secret","remote_server").err
82
+ # Or
83
+ comm.cat("file").tail("-n10").grep("'something'").run_ssh("Batou99","secret","remote_server").both
84
+ ```
60
85
  ## Contributing
61
86
 
62
87
  1. Fork it
@@ -1,3 +1,3 @@
1
1
  module UnixCommander
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -5,32 +5,69 @@ require 'net/ssh'
5
5
 
6
6
  module UnixCommander
7
7
 
8
- class Command
8
+ # This class encapsulates the output of a command. It also has the logic to run a command locally or remotely
9
+ class Runner
9
10
 
10
- attr :cmd
11
+ # @return [Command]
12
+ attr :command
11
13
 
12
- def initialize(_cmd = "")
13
- @cmd = _cmd
14
+
15
+ # Creates a new Runner
16
+ # @param _command The command to be run by the runner
17
+ def initialize(_command)
18
+ @command = _command
14
19
  end
15
20
 
16
- def method_missing(m, *args, &block)
17
- if cmd == ""
18
- Command.new("#{m} #{args.join(' ')}".strip)
19
- else
20
- Command.new("#{cmd} | #{m} #{args.join(' ')}".strip)
21
- end
21
+ # Return a string with the output of the command
22
+ # If the command has not been run yet it returns an empty string
23
+ # @return [String] *stdout* and *stderr* of the command (*stdout* \\n *stderr*)
24
+ def to_s
25
+ both.join("\n")
22
26
  end
23
27
 
24
- def run
25
- @in, @out, @err = Open3.popen3("#{cmd}")
28
+ # Returns the output (stdout) of the command
29
+ # If the command has not been run yet it returns an empty string
30
+ # @return [String] *stdout* of the command
31
+ def out
32
+ return "" if @out==nil
33
+ return @out if @out.class==String
26
34
  @out.read
27
35
  end
28
36
 
37
+ # Returns the output (stderr) of the command
38
+ # If the command has not been run yet it returns an empty string
39
+ # @return [String] *stderr* of the command
40
+ def err
41
+ return "" if @err==nil
42
+ return @err if @err.class==String
43
+ @err.read
44
+ end
45
+
46
+ # Return a string with the output of the command
47
+ # If the command has not been run yet it returns ["",""]
48
+ # @return [Array] *stdout* and *stderr* of the command
49
+ def both
50
+ [out, err]
51
+ end
52
+
53
+ # Runs the stored command locally
54
+ # @return [Runner] Returns itself
55
+ def run
56
+ @in, @out, @err = Open3.popen3("#{@command.cmd}")
57
+ self
58
+ end
59
+
60
+ # Runs the stored command remotely
61
+ # @param _username The ssh username to access the remote server
62
+ # @param _password The ssh password to access the remote server
63
+ # @param _address The ssh server address to access the remote server. It defaults to localhost.
64
+ # @return [Runner] Returns itself
29
65
  def run_ssh(_username, _password = "", _address = "127.0.0.1")
30
66
  stdout_data = ""
67
+ stderr_data = ""
31
68
  Net::SSH.start(_address,_username,:password => _password) do |ssh|
32
69
  channel = ssh.open_channel do |ch|
33
- ch.exec(@cmd) do |ch,success|
70
+ ch.exec(@command.cmd) do |ch,success|
34
71
  # "on_data" is called when the process writes something to stdout
35
72
  ch.on_data do |c, data|
36
73
  stdout_data += data
@@ -38,13 +75,98 @@ module UnixCommander
38
75
 
39
76
  # "on_extended_data" is called when the process writes something to stderr
40
77
  ch.on_extended_data do |c, type, data|
41
- raise "Error on command: #{data}"
78
+ stderr_data += data
42
79
  end
43
80
  end
44
81
  end
45
82
  end
46
- # We have to strip the extra linefeed
47
- stdout_data
83
+ @out = stdout_data
84
+ @err = stderr_data
85
+ self
86
+ end
87
+ end
88
+
89
+ # This class encapsulates a command that will run in a unix machine locally or remotely
90
+ class Command
91
+
92
+ # @return [String]
93
+ attr :cmd
94
+
95
+ # Creates a new command
96
+ # @param [String] create a command with some unix code inside (defaults to "")
97
+ def initialize(_cmd = "")
98
+ @cmd = _cmd
99
+ end
100
+ # Shows the string representation of the command being run in unix
101
+ # @return [String]
102
+ def to_s
103
+ cmd
104
+ end
105
+
106
+ # This is the main method of the library. Every unknown method you call on a Command object
107
+ # is interpreted as a unix command and its args are used as the args of the unix command.
108
+ # When the command already has some unix command inside, it pipes them together (|)
109
+ # @param [String] m name of the unix command you want to execute
110
+ # @param [Array] *args args for the aforementioned command
111
+ # @return [Command] new command with internal unix commands piped together
112
+ def method_missing(m, *args, &block)
113
+ if cmd == ""
114
+ Command.new("#{m} #{args.join(' ')}".strip)
115
+ else
116
+ Command.new("#{cmd} | #{m} #{args.join(' ')}".strip)
117
+ end
118
+ end
119
+
120
+ # Redirects *stdout* to someplace (Using >). By default it uses destructive redirection.
121
+ # @param [String] place to redirect the output (e.g. /dev/null)
122
+ # @param [true,false] append if true uses append redirection (>>) it defaults to false.
123
+ # @return [Command] New command with *stdout* redirected to _str
124
+ def out_to(_str,_append=false)
125
+ if cmd == ""
126
+ raise ArgumentError, "Cannot redirect with an empty command"
127
+ else
128
+ _append ? Command.new("#{cmd} >> #{_str}") : Command.new("#{cmd} > #{_str}")
129
+ end
130
+ end
131
+
132
+ # Redirects *stderr* to someplace (Using >). By default it uses destructive redirection.
133
+ # @param [String] place to redirect the output (e.g. /dev/null)
134
+ # @param [true,false] append if true uses append redirection (>>) it defaults to false.
135
+ # @return [Command] New command with *stderr* redirected to _str
136
+ def err_to(_str,_append=false)
137
+ if cmd == ""
138
+ raise ArgumentError, "Cannot redirect with an empty command"
139
+ else
140
+ _append ? Command.new("#{cmd} 2>> #{_str}") : Command.new("#{cmd} 2> #{_str}")
141
+ end
142
+ end
143
+
144
+ # Redirects *stdout* and *stderr* to someplace (Using >). By default it uses destructive redirection.
145
+ # @param [String] place to redirect the output (e.g. /dev/null)
146
+ # @param [true,false] append if true uses append redirection (>>) it defaults to false.
147
+ # @return [Command] New command with *stdout and stderr* redirected to _str
148
+ def both_to(_str,_append=false)
149
+ if cmd == ""
150
+ raise ArgumentError, "Cannot redirect with an empty command"
151
+ else
152
+ _append ? Command.new("#{cmd} >> #{_str} 2>&1") : Command.new("#{cmd} > #{_str} 2>&1")
153
+ end
154
+ end
155
+
156
+ # Run the Command locally. The output is encapsulated in a Runner object
157
+ # @return [Runner] runner object with the output inside
158
+ def run
159
+ Runner.new(self).run
160
+ end
161
+
162
+ # Run the Command remotely via ssh. The output is encapsulated in a Runner object
163
+ # @param _username The ssh username to access the remote server
164
+ # @param _password The ssh password to access the remote server
165
+ # @param _address The ssh server address to access the remote server. It defaults to localhost.
166
+ # @return [Runner] runner object with the output inside
167
+ def run_ssh(_username, _password = "", _address = "127.0.0.1")
168
+ Runner.new(self).run_ssh(_username,_password,_address)
48
169
  end
49
170
  end
171
+
50
172
  end
@@ -0,0 +1,83 @@
1
+ require 'pry'
2
+ require './lib/unix_commander'
3
+
4
+ describe "Commands without chaining" do
5
+ before do
6
+ @command = UnixCommander::Command.new
7
+ end
8
+
9
+ it "should accept commands with no args" do
10
+ version = %x[uname]
11
+ @command.uname.to_s.should == "uname"
12
+ end
13
+
14
+ it "should accept commands with one arg" do
15
+ @command.uname("-a").to_s.should == "uname -a"
16
+ end
17
+
18
+ end
19
+
20
+ describe "Commands with chaining" do
21
+ before do
22
+ @command = UnixCommander::Command.new
23
+ end
24
+
25
+ it "can chain 2 commands" do
26
+ @command.uname("-a").cut("-d'#' -f1").to_s.should == "uname -a | cut -d'#' -f1"
27
+ end
28
+
29
+ it "can chain 3 commands" do
30
+ @command.cat("/proc/cpuinfo").awk("'{ print $1 }'").head("-n1").to_s.should == "cat /proc/cpuinfo | awk '{ print $1 }' | head -n1"
31
+ end
32
+ end
33
+
34
+ describe "Running" do
35
+ before do
36
+ @command = UnixCommander::Command.new.uname
37
+ end
38
+
39
+ it "should call a runner" do
40
+ UnixCommander::Runner.any_instance.should_receive(:run).and_return(%x[uname -a])
41
+ @command.run.should == %x[uname -a]
42
+ end
43
+
44
+ it "should call a runner over ssh" do
45
+ UnixCommander::Runner.any_instance.should_receive(:run_ssh).with('dev','devpass','localhost').and_return(%x[uname -a])
46
+ @command.run_ssh('dev','devpass','localhost').should == %x[uname -a]
47
+ end
48
+ end
49
+
50
+ describe "Redirection" do
51
+ before do
52
+ @command = UnixCommander::Command.new.uname("-a").cut("-d' ' -f1")
53
+ end
54
+
55
+ it "should translate to_s correctly" do
56
+ @command.to_s.should == "uname -a | cut -d' ' -f1"
57
+ end
58
+
59
+ it "should redirect stdout" do
60
+ @command.out_to('/dev/null').to_s.should == "uname -a | cut -d' ' -f1 > /dev/null"
61
+ end
62
+
63
+ it "should redirect stderr" do
64
+ @command.err_to('/dev/null').to_s.should == "uname -a | cut -d' ' -f1 2> /dev/null"
65
+ end
66
+
67
+ it "should redirect both" do
68
+ @command.both_to('/dev/null').to_s.should == "uname -a | cut -d' ' -f1 > /dev/null 2>&1"
69
+ end
70
+
71
+ it "should append stdout" do
72
+ @command.out_to('/dev/null',true).to_s.should == "uname -a | cut -d' ' -f1 >> /dev/null"
73
+ end
74
+
75
+ it "should append stderr" do
76
+ @command.err_to('/dev/null',true).to_s.should == "uname -a | cut -d' ' -f1 2>> /dev/null"
77
+ end
78
+
79
+ it "should append both" do
80
+ @command.both_to('/dev/null',true).to_s.should == "uname -a | cut -d' ' -f1 >> /dev/null 2>&1"
81
+ end
82
+ end
83
+
@@ -0,0 +1,73 @@
1
+ require 'pry'
2
+ require './lib/unix_commander'
3
+
4
+ describe "Runner local" do
5
+ before do
6
+ @command = UnixCommander::Command.new("uname")
7
+ end
8
+
9
+ it "can access out after run command" do
10
+ UnixCommander::Runner.new(@command).run.out.should == %x[uname]
11
+ end
12
+
13
+ it "can access err after run command with no errors" do
14
+ UnixCommander::Runner.new(@command).run.err.should == ""
15
+ end
16
+
17
+ it "can access err after run command with errors" do
18
+ @command = UnixCommander::Command.new("cat /etc/shadow")
19
+ UnixCommander::Runner.new(@command).run.err.should_not == ""
20
+ end
21
+
22
+ it "can access out and err after run command with errors" do
23
+ @command = UnixCommander::Command.new("grep abc /etc/*")
24
+ UnixCommander::Runner.new(@command).run.err.should_not == ""
25
+ UnixCommander::Runner.new(@command).run.out.should == %x[grep abc /etc/* 2> /dev/null]
26
+ end
27
+
28
+ it "should have empty data before run" do
29
+ UnixCommander::Runner.new(@command).out == ""
30
+ UnixCommander::Runner.new(@command).err == ""
31
+ end
32
+
33
+ it "can access out and err with an array" do
34
+ @command = UnixCommander::Command.new("grep abc /etc/*")
35
+ out_err = UnixCommander::Runner.new(@command).run.both
36
+ out_err[0].should_not == ""
37
+ out_err[1].should_not == ""
38
+ end
39
+
40
+ end
41
+
42
+ describe "Runner ssh" do
43
+ before do
44
+ @command = UnixCommander::Command.new("uname")
45
+ end
46
+
47
+ it "can access out after run command" do
48
+ UnixCommander::Runner.new(@command).run_ssh('dev','dev').out.should == %x[uname]
49
+ end
50
+
51
+ it "can access err after run command with no errors" do
52
+ UnixCommander::Runner.new(@command).run_ssh('dev','dev').err.should == ""
53
+ end
54
+
55
+ it "can access err after run command with errors" do
56
+ @command = UnixCommander::Command.new("cat /etc/shadow")
57
+ UnixCommander::Runner.new(@command).run_ssh('dev','dev').err.should_not == ""
58
+ end
59
+
60
+ it "can access out and err after run command with errors" do
61
+ @command = UnixCommander::Command.new("grep abc /etc/*")
62
+ UnixCommander::Runner.new(@command).run_ssh('dev','dev').err.should_not == ""
63
+ UnixCommander::Runner.new(@command).run_ssh('dev','dev').out.should == %x[grep abc /etc/* 2> /dev/null]
64
+ end
65
+
66
+ it "can access out and err with an array" do
67
+ @command = UnixCommander::Command.new("grep abc /etc/*")
68
+ out_err = UnixCommander::Runner.new(@command).run_ssh('dev','dev').both
69
+ out_err[0].should_not == ""
70
+ out_err[1].should_not == ""
71
+ end
72
+
73
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unix_commander
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-30 00:00:00.000000000 Z
12
+ date: 2012-12-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: net-ssh
@@ -139,8 +139,9 @@ files:
139
139
  - Rakefile
140
140
  - lib/unix_commander.rb
141
141
  - lib/unix_commander/version.rb
142
+ - spec/command_spec.rb
142
143
  - spec/fixtures/ps_list.txt
143
- - spec/single_commands_spec.rb
144
+ - spec/runner_spec.rb
144
145
  - unix_commander.gemspec
145
146
  homepage: https://github.com/Batou99/unix_commander
146
147
  licenses: []
@@ -167,5 +168,7 @@ signing_key:
167
168
  specification_version: 3
168
169
  summary: A gem to run unix commands on a more ruby-esque way
169
170
  test_files:
171
+ - spec/command_spec.rb
170
172
  - spec/fixtures/ps_list.txt
171
- - spec/single_commands_spec.rb
173
+ - spec/runner_spec.rb
174
+ has_rdoc:
@@ -1,46 +0,0 @@
1
- require 'pry'
2
- require './lib/unix_commander'
3
-
4
- describe "Commands without chaining" do
5
- before do
6
- @command = UnixCommander::Command.new
7
- end
8
-
9
- it "should run commands with no args" do
10
- version = %x[uname]
11
- @command.uname.run.should == version
12
- end
13
-
14
- it "should run commands with one arg" do
15
- long_version = %x[uname -a]
16
- @command.uname("-a").run.should == long_version
17
- end
18
-
19
- end
20
-
21
- describe "Commands with chaining" do
22
- before do
23
- @command = UnixCommander::Command.new
24
- end
25
-
26
- it "can chain 2 commands" do
27
- uname_cut = %x[uname -a | cut -d'#' -f1]
28
- @command.uname("-a").cut("-d'#' -f1").run.should == uname_cut
29
- end
30
-
31
- it "can chain 3 commands" do
32
- cpuinfo = %x[ cat /proc/cpuinfo | awk '{ print $1 }' | head -n1]
33
- @command.cat("/proc/cpuinfo").awk("'{ print $1 }'").head("-n1").run.should == cpuinfo
34
- end
35
- end
36
-
37
- describe "Run via ssh" do
38
- before do
39
- @command = UnixCommander::Command.new
40
- end
41
-
42
- it "can chain 2 commands" do
43
- uname_cut = %x[uname -a | cut -d'#' -f1]
44
- @command.uname("-a").cut("-d'#' -f1").run_ssh('dev','dev').should == uname_cut
45
- end
46
- end