unix_commander 0.0.2 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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