session 2.4.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,3 @@
1
+ same as Ruby's
2
+
3
+ http://www.ruby-lang.org/en/LICENSE.txt
data/README ADDED
@@ -0,0 +1,168 @@
1
+ URLS: |
2
+
3
+ http://raa.ruby-lang.org/project/session/
4
+ http://www.codeforpeople.com/lib/ruby/session/
5
+
6
+
7
+ NAME: |
8
+
9
+ Session
10
+ ::Sh
11
+ ::Bash
12
+ ::Shell
13
+ ::IDL
14
+
15
+ SYNOPSIS: |
16
+
17
+ Session::* offers a set of classes built upon Open3::popen3 for driving
18
+ external progams via pipes. It offers a significant abstraction over
19
+ Open3::popen in that the stdout/stderr of each command sent can be deliniated:
20
+
21
+ open3:
22
+
23
+ i,o,e = Open3::popen3 '/bin/sh'
24
+
25
+ i.puts 'ls'
26
+ i.puts 'echo 42'
27
+
28
+ now, how to determine the boundry between the output from 'ls' and 'echo'?
29
+ the only (simple) way is start a process for each command
30
+
31
+ i,o,e = Open3::popen3 '/bin/sh'
32
+ i.puts 'ls'
33
+ i.close
34
+ stdout, stderr = o.read, e.read
35
+
36
+ i,o,e = Open3::popen3 '/bin/sh'
37
+ i.puts 'echo 42'
38
+ i.close
39
+ stdout, stderr = o.read, e.read
40
+
41
+ session:
42
+
43
+ sh = Session::new
44
+
45
+ stdout, stderr = sh.execute 'ls'
46
+ stdout, stderr = sh.execute 'echo 42'
47
+
48
+ Both stderr and stdout can be redirected, and the exit_status of each command
49
+ is made available:
50
+
51
+ bash = Session::Bash.new
52
+ stdout, stderr = StringIO::new, StringIO::new
53
+
54
+ bash.execute 'ls', :stdout => stdout, :stderr => stderr
55
+ # bash.execute 'ls', 1 => stdout, 2 => stderr # same thing
56
+ # bash.execute 'ls', :o => stdout, :e => stderr # same thing
57
+
58
+ exit_status = bash.exit_status
59
+
60
+ A block form can be used to specify a callback to be invoked whenever output
61
+ has become availible:
62
+
63
+ bash = Session::Bash.new
64
+
65
+ bash.execute( 'long_running_command.exe' ) do |out, err|
66
+ logger << out if out
67
+ elogger << err if err
68
+ end
69
+
70
+ Sessions are Thread safe (in the sense that they do not block on io
71
+ operations) allowing commands spawned from guis to update widgets with output
72
+ while running in the background.
73
+
74
+ button.configure 'action' => lambda do
75
+ sh = Session::new
76
+ sh.execute(cmd) do |o,e|
77
+ out_widget.update o if o
78
+ err_widget.update e if e
79
+ end
80
+ end
81
+
82
+ SAMPLES: |
83
+
84
+ see samples/*
85
+
86
+ HISTORY: |
87
+ 3.1.0:
88
+ - patches from @headius
89
+
90
+ 3.0.0
91
+ - move to github
92
+
93
+ 2.4.0:
94
+ - added ability to specify stdin for Session::Bash and Session::Sh
95
+
96
+ sh = Session::new
97
+
98
+ sh.execute 'cat', :stdin => io
99
+ sh.execute 'cat', :stdin => string
100
+ sh.execute 'cat', :stdin => stringio
101
+
102
+ 2.3.0:
103
+ - fixed warning of @debug being un-initialized
104
+
105
+ 2.2.0:
106
+ - added a private munged version of Open3::open3. the builtin one causes
107
+ the child process to become a child of init, this was very inconvenient
108
+ because it was sometimes hard to crawl proces trees - the parent was lost.
109
+ now the seesion is a child process that has been detached using
110
+ Process::detach. this results in less suprising behaviour; for instance
111
+ sending signal TERM to a process results in any sessions it had open dying
112
+ as well. you can use Session::use_open3=true or
113
+ ENV['SESSION_USE_OPEN3']='1' for the old behaviour if you need it.
114
+ - added Session::Bash::Login class. this class opens a session which has
115
+ all the normal settings of a bash loging shell (.bashrc is sourced). this
116
+ if often convenient as paths, aliases, etc. are set as normal.
117
+ - moved the Spawn module inside the Session module. now the Session module
118
+ is the namespace for everything so using session pollutes namespace less.
119
+
120
+ 2.1.9:
121
+ - fixed bug where setting track history after creation caused later failure in
122
+ execute (@history =[] only in ctor). thanks leon breedt
123
+ <bitserf@gmail.com>!
124
+ - updates to README
125
+ - included session-x.x.x.rpa file - thanks batsman <batsman.geo@yahoo.com>
126
+ - to_str/to_s/to_yaml for History/Command is now valid yaml (updated samples
127
+ to reflect this)
128
+ - inspect for History/Command is now ruby's default
129
+
130
+ 2.1.8:
131
+ - greatly simplified read loop using two reader threads, one for stderr and
132
+ one for stdout alongside a mutex to protect data. this streamlined the code
133
+ alot vs. the old select method including allowing removal of the linbuffer
134
+ class. the interface remains exactly as before however.
135
+
136
+ 2.1.7:
137
+ - improved thread safe non-blocking read method
138
+ - gemspec
139
+
140
+ 2.1.6:
141
+ - wrapped send_command in a Thread (send async) so output processing can
142
+ commend immeadiately. this was o.k. before, but had strange behaviour when
143
+ using popen3 from threads. thanks to tanaka akira for this suggestion.
144
+ - iff ENV['SESSION_USE_SPAWN'] is set Session uses Spawn::spawn instead of
145
+ Open3::popen3. also noted that spawn seems to be a bit faster.
146
+ - added tests for threads.
147
+ - run 'sh SESSION_USE_SPAWN=1 ruby test/session.rb' to test using spawn
148
+ - added test for idl so it's test is not run if system doesn't have it, all
149
+ that should be required for 'ruby test/session.rb' is should be sh'
150
+ - removed sample/tcsh and note about Tcsh and Csh in README - stderr
151
+ redirection/separation is flaky in those shells
152
+
153
+ 2.1.5:
154
+ - added Session.use_spawn=, AbstractSession.use_spawn=, and an :use_session=>
155
+ option to AbstractSession#initialize. if any of them are set the code uses
156
+ Spawn::spawn to create external processes instead of Open3::popen3.
157
+ Spawn::spawn uses named pipes (fifos) for IPC instead of forking and pipes.
158
+ the fork used in popen3 can cause strange behaviour with multi-threaded apps
159
+ (like a tk app). see source for details
160
+
161
+ 2.1.4:
162
+ - added Thread.exclusive{} wrapper when io is read to works in multi
163
+ threaded apps
164
+
165
+
166
+ AUTHOR: |
167
+
168
+ ara.t.howard@noaa.gov
data/Rakefile ADDED
@@ -0,0 +1,233 @@
1
+
2
+ This.rubyforge_project = 'codeforpeople'
3
+ This.author = "Ara T. Howard"
4
+ This.email = "ara.t.howard@gmail.com"
5
+ This.homepage = "http://github.com/ahoward/#{ This.lib }/tree/master"
6
+
7
+
8
+ task :default do
9
+ puts(Rake::Task.tasks.map{|task| task.name} - ['default'])
10
+ end
11
+
12
+
13
+ task :gemspec do
14
+ ignore_extensions = 'git', 'svn', 'tmp', /sw./, 'bak', 'gem'
15
+ ignore_directories = 'pkg'
16
+ ignore_files = 'test/log'
17
+
18
+ shiteless =
19
+ lambda do |list|
20
+ list.delete_if do |entry|
21
+ next unless test(?e, entry)
22
+ extension = File.basename(entry).split(%r/[.]/).last
23
+ ignore_extensions.any?{|ext| ext === extension}
24
+ end
25
+ list.delete_if do |entry|
26
+ next unless test(?d, entry)
27
+ dirname = File.expand_path(entry)
28
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
29
+ end
30
+ list.delete_if do |entry|
31
+ next unless test(?f, entry)
32
+ filename = File.expand_path(entry)
33
+ ignore_files.any?{|file| File.expand_path(file) == filename}
34
+ end
35
+ end
36
+
37
+ lib = This.lib
38
+ object = This.object
39
+ version = This.version
40
+ files = shiteless[Dir::glob("**/**")]
41
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
42
+ has_rdoc = true #File.exist?('doc')
43
+ test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
44
+ summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
45
+ description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
46
+
47
+ extensions = This.extensions
48
+ if extensions.nil?
49
+ %w( Makefile configure extconf.rb ).each do |ext|
50
+ extensions << ext if File.exists?(ext)
51
+ end
52
+ end
53
+ extensions = [extensions].flatten.compact
54
+
55
+ template =
56
+ if test(?e, 'gemspec.erb')
57
+ Template{ IO.read('gemspec.erb') }
58
+ else
59
+ Template {
60
+ <<-__
61
+ ## #{ lib }.gemspec
62
+ #
63
+
64
+ Gem::Specification::new do |spec|
65
+ spec.name = #{ lib.inspect }
66
+ spec.version = #{ version.inspect }
67
+ spec.platform = Gem::Platform::RUBY
68
+ spec.summary = #{ lib.inspect }
69
+ spec.description = #{ description.inspect }
70
+
71
+ spec.files = #{ files.inspect }
72
+ spec.executables = #{ executables.inspect }
73
+
74
+ spec.require_path = "lib"
75
+
76
+ spec.has_rdoc = #{ has_rdoc.inspect }
77
+ spec.test_files = #{ test_files.inspect }
78
+ #spec.add_dependency 'lib', '>= version'
79
+ spec.add_dependency 'fattr'
80
+
81
+ spec.extensions.push(*#{ extensions.inspect })
82
+
83
+ spec.rubyforge_project = #{ This.rubyforge_project.inspect }
84
+ spec.author = #{ This.author.inspect }
85
+ spec.email = #{ This.email.inspect }
86
+ spec.homepage = #{ This.homepage.inspect }
87
+ end
88
+ __
89
+ }
90
+ end
91
+
92
+ open("#{ lib }.gemspec", "w"){|fd| fd.puts template}
93
+ This.gemspec = "#{ lib }.gemspec"
94
+ end
95
+
96
+ task :gem => [:clean, :gemspec] do
97
+ Fu.mkdir_p This.pkgdir
98
+ before = Dir['*.gem']
99
+ cmd = "gem build #{ This.gemspec }"
100
+ `#{ cmd }`
101
+ after = Dir['*.gem']
102
+ gem = ((after - before).first || after.first) or abort('no gem!')
103
+ Fu.mv gem, This.pkgdir
104
+ This.gem = File.basename(gem)
105
+ end
106
+
107
+ task :readme do
108
+ samples = ''
109
+ prompt = '~ > '
110
+ lib = This.lib
111
+ version = This.version
112
+
113
+ Dir['sample*/*'].sort.each do |sample|
114
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
115
+
116
+ cmd = "cat #{ sample }"
117
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
118
+ samples << Util.indent(`#{ cmd }`, 4) << "\n"
119
+
120
+ cmd = "ruby #{ sample }"
121
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
122
+
123
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
124
+ samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
125
+ end
126
+
127
+ template =
128
+ if test(?e, 'readme.erb')
129
+ Template{ IO.read('readme.erb') }
130
+ else
131
+ Template {
132
+ <<-__
133
+ NAME
134
+ #{ lib }
135
+
136
+ DESCRIPTION
137
+
138
+ INSTALL
139
+ gem install #{ lib }
140
+
141
+ SAMPLES
142
+ #{ samples }
143
+ __
144
+ }
145
+ end
146
+
147
+ open("README", "w"){|fd| fd.puts template}
148
+ end
149
+
150
+
151
+ task :clean do
152
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
153
+ end
154
+
155
+
156
+ task :release => [:clean, :gemspec, :gem] do
157
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
158
+ raise "which one? : #{ gems.inspect }" if gems.size > 1
159
+ raise "no gems?" if gems.size < 1
160
+ cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.pkgdir }/#{ This.gem }"
161
+ puts cmd
162
+ system cmd
163
+ end
164
+
165
+
166
+
167
+
168
+
169
+ BEGIN {
170
+ $VERBOSE = nil
171
+
172
+ require 'ostruct'
173
+ require 'erb'
174
+ require 'fileutils'
175
+
176
+ Fu = FileUtils
177
+
178
+ This = OpenStruct.new
179
+
180
+ This.file = File.expand_path(__FILE__)
181
+ This.dir = File.dirname(This.file)
182
+ This.pkgdir = File.join(This.dir, 'pkg')
183
+
184
+ lib = ENV['LIB']
185
+ unless lib
186
+ lib = File.basename(Dir.pwd)
187
+ end
188
+ This.lib = lib
189
+
190
+ version = ENV['VERSION']
191
+ unless version
192
+ require "./lib/#{ This.lib }"
193
+ This.name = lib.capitalize
194
+ This.object = eval(This.name)
195
+ version = This.object.send(:version)
196
+ end
197
+ This.version = version
198
+
199
+ abort('no lib') unless This.lib
200
+ abort('no version') unless This.version
201
+
202
+ module Util
203
+ def indent(s, n = 2)
204
+ s = unindent(s)
205
+ ws = ' ' * n
206
+ s.gsub(%r/^/, ws)
207
+ end
208
+
209
+ def unindent(s)
210
+ indent = nil
211
+ s.each do |line|
212
+ next if line =~ %r/^\s*$/
213
+ indent = line[%r/^\s*/] and break
214
+ end
215
+ indent ? s.gsub(%r/^#{ indent }/, "") : s
216
+ end
217
+ extend self
218
+ end
219
+
220
+ class Template
221
+ def initialize(&block)
222
+ @block = block
223
+ @template = block.call.to_s
224
+ end
225
+ def expand(b=nil)
226
+ ERB.new(Util.unindent(@template)).result(b||@block)
227
+ end
228
+ alias_method 'to_s', 'expand'
229
+ end
230
+ def Template(*args, &block) Template.new(*args, &block) end
231
+
232
+ Dir.chdir(This.dir)
233
+ }
data/gemspec.rb ADDED
@@ -0,0 +1,62 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ lib, version, *ignored = ARGV
4
+
5
+ unless lib
6
+ lib = File.basename(Dir.pwd)
7
+ end
8
+
9
+ unless version
10
+ mod = lib.capitalize
11
+ require "./lib/#{ lib }"
12
+ version = eval(mod).send(:version)
13
+ end
14
+
15
+ abort('no lib') unless lib
16
+ abort('no version') unless version
17
+
18
+ puts "### gemspec: #{ lib }-#{ version }"
19
+
20
+ $VERBOSE = nil
21
+
22
+ shiteless = lambda{|list| list.delete_if{|file| file =~ %r/\.(git|svn|tmp|sw.|bak)$/}}
23
+
24
+ files = shiteless[Dir::glob("**/**")]
25
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
26
+ has_rdoc = true #File.exist?('doc')
27
+ test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
28
+
29
+ extensions = []
30
+ %w( Makefile configure extconf.rb rakefile Rakefile mkrf_conf ).each do |ext|
31
+ extensions << ext if File.exists?(ext)
32
+ end
33
+
34
+ template = <<-__
35
+
36
+ Gem::Specification::new do |spec|
37
+ spec.name = #{ lib.inspect }
38
+ spec.version = #{ version.inspect }
39
+ spec.platform = Gem::Platform::RUBY
40
+ spec.summary = #{ lib.inspect }
41
+
42
+ spec.files = #{ files.inspect }
43
+ spec.executables = #{ executables.inspect }
44
+
45
+ spec.require_path = "lib"
46
+
47
+ spec.has_rdoc = #{ has_rdoc.inspect }
48
+ spec.test_files = #{ test_files.inspect }
49
+ #spec.add_dependency 'lib', '>= version'
50
+ #spec.add_dependency 'fattr'
51
+
52
+ spec.extensions.push(*#{ extensions.inspect })
53
+
54
+ spec.rubyforge_project = 'codeforpeople'
55
+ spec.author = "Ara T. Howard"
56
+ spec.email = "ara.t.howard@gmail.com"
57
+ spec.homepage = "http://github.com/ahoward/#{ lib }/tree/master"
58
+ end
59
+
60
+ __
61
+
62
+ puts template