session 2.4.0 → 3.1.0

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/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