naksh 0.2.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.
Files changed (137) hide show
  1. data/AUTHORS +1 -0
  2. data/COPYING +674 -0
  3. data/COPYING-DOCS +15 -0
  4. data/README.md +45 -0
  5. data/Rakefile +129 -0
  6. data/TODO +19 -0
  7. data/bin/naksh +2 -0
  8. data/data/default.mo +0 -0
  9. data/data/default.po +16 -0
  10. data/data/default2.mo +0 -0
  11. data/data/default2.po +27 -0
  12. data/data/starter.pot +29 -0
  13. data/docs/bash_flow.dia +0 -0
  14. data/docs/gtk_manual.txt +13 -0
  15. data/docs/master_plan.dia +0 -0
  16. data/docs/master_plan.png +0 -0
  17. data/docs/master_plan.svg +74 -0
  18. data/docs/master_plan.svgz +0 -0
  19. data/docs/userguide/en/about.xml +42 -0
  20. data/docs/userguide/en/gnu-fdl-1.2.xml +543 -0
  21. data/docs/userguide/en/naksh.xml +881 -0
  22. data/docs/userguide/en/naksh_start_window.png +0 -0
  23. data/docs/userguide/en/old_naksh.xml +180 -0
  24. data/docs/userguide/en/userguide-en.omf +37 -0
  25. data/lib/naksh.rb +165 -0
  26. data/lib/naksh/buffer.rb +153 -0
  27. data/lib/naksh/command_handling.rb +117 -0
  28. data/lib/naksh/commands/bash/README +2 -0
  29. data/lib/naksh/commands/bash/echo.nkc.rb +50 -0
  30. data/lib/naksh/commands/bsd.rb +25 -0
  31. data/lib/naksh/commands/dos.rb +25 -0
  32. data/lib/naksh/commands/fuse.rb +25 -0
  33. data/lib/naksh/commands/gnu.rb +30 -0
  34. data/lib/naksh/commands/gnu/README +2 -0
  35. data/lib/naksh/commands/gnu/cat.nkc.rb +50 -0
  36. data/lib/naksh/commands/gnu/cd.nkc.rb +11 -0
  37. data/lib/naksh/commands/gnu/echo.documentation.json +57 -0
  38. data/lib/naksh/commands/gnu/echo.documentation.rb +60 -0
  39. data/lib/naksh/commands/gnu/echo.nkc.rb +52 -0
  40. data/lib/naksh/commands/gnu/ls.nkc.rb +11 -0
  41. data/lib/naksh/commands/gnu/mv.nkc.rb +15 -0
  42. data/lib/naksh/commands/gnu/pwd.nkc.rb +11 -0
  43. data/lib/naksh/commands/naksh/addpath.nkc.rb +15 -0
  44. data/lib/naksh/commands/naksh/broken.nkc.rb +10 -0
  45. data/lib/naksh/commands/naksh/empty.nkc.rb +4 -0
  46. data/lib/naksh/commands/naksh/exit.nkc.rb +10 -0
  47. data/lib/naksh/commands/naksh/help.nkc.rb +21 -0
  48. data/lib/naksh/commands/naksh/man.nkc.rb +8 -0
  49. data/lib/naksh/commands/ruby.rb +31 -0
  50. data/lib/naksh/commands/unix.rb +131 -0
  51. data/lib/naksh/configuration/gconf.rb +51 -0
  52. data/lib/naksh/configuration/hash.rb +38 -0
  53. data/lib/naksh/defaults.rb +40 -0
  54. data/lib/naksh/history.rb +85 -0
  55. data/lib/naksh/interfaces.rb +59 -0
  56. data/lib/naksh/interfaces/fox.rb +49 -0
  57. data/lib/naksh/interfaces/gtk.rb +103 -0
  58. data/lib/naksh/interfaces/gtk/abtwin.rb +53 -0
  59. data/lib/naksh/interfaces/gtk/gnomeapp.rb +31 -0
  60. data/lib/naksh/interfaces/gtk/helpwin.rb +70 -0
  61. data/lib/naksh/interfaces/gtk/io.rb +94 -0
  62. data/lib/naksh/interfaces/gtk/mainwin.rb +56 -0
  63. data/lib/naksh/interfaces/gtk/mainwin/console.rb +121 -0
  64. data/lib/naksh/interfaces/gtk/mainwin/main_menu.rb +143 -0
  65. data/lib/naksh/interfaces/gtk/optwin.rb +78 -0
  66. data/lib/naksh/interfaces/tab.rb +58 -0
  67. data/lib/naksh/interfaces/wxw.rb +75 -0
  68. data/lib/naksh/interfaces/wxw/abtwin.rb +38 -0
  69. data/lib/naksh/interfaces/wxw/helpwin.rb +40 -0
  70. data/lib/naksh/interfaces/wxw/io.rb +61 -0
  71. data/lib/naksh/interfaces/wxw/mainwin.rb +42 -0
  72. data/lib/naksh/interfaces/wxw/mainwin/main_menu.rb +126 -0
  73. data/lib/naksh/interfaces/wxw/mainwin/sessions.rb +49 -0
  74. data/lib/naksh/interfaces/wxw/optwin.rb +37 -0
  75. data/lib/naksh/path_entry.rb +101 -0
  76. data/lib/naksh/regexp.rb +31 -0
  77. data/lib/naksh/session.rb +72 -0
  78. data/lib/naksh/stdlibext.rb +48 -0
  79. data/lib/naksh/syntax.rb +57 -0
  80. data/lib/naksh/syntax/bash.rb +219 -0
  81. data/lib/naksh/syntax/bash/antlr/bottomup.g +24 -0
  82. data/lib/naksh/syntax/bash/antlr/topdown.g +52 -0
  83. data/lib/naksh/syntax/bash/dhaka/evaluator.rb +353 -0
  84. data/lib/naksh/syntax/bash/dhaka/grammar.rb +71 -0
  85. data/lib/naksh/syntax/bash/dhaka/lexer.rb +52 -0
  86. data/lib/naksh/syntax/bash/treetop/bash.treetop +17 -0
  87. data/lib/old/abbr_call.rb +39 -0
  88. data/lib/old/autocomplete.rb +29 -0
  89. data/lib/old/command.rb +106 -0
  90. data/lib/old/command_holder.rb +75 -0
  91. data/lib/old/commands.rb +24 -0
  92. data/lib/old/old_executor.rb +95 -0
  93. data/lib/old/options.rb +31 -0
  94. data/lib/old/rush.rb +113 -0
  95. data/lib/old/sortissimo.rb +205 -0
  96. data/lib/old/systems.rb +25 -0
  97. data/lib/old/systems/ruby.rb +26 -0
  98. data/lib/old/un.rb +240 -0
  99. data/lib/rust/Rakefile +6 -0
  100. data/lib/rust/commands/builtins.rb +46 -0
  101. data/lib/rust/commands/builtins/cd.rb +17 -0
  102. data/lib/rust/commands/builtins/exit.rb +13 -0
  103. data/lib/rust/commands/builtins/help.rb +14 -0
  104. data/lib/rust/commands/builtins/parser.rb +13 -0
  105. data/lib/rust/commands/builtins/pwd.rb +13 -0
  106. data/lib/rust/commands/builtins/type.rb +13 -0
  107. data/lib/rust/commands/commands/ls.rb +13 -0
  108. data/lib/rust/commands/commands/read.rb +13 -0
  109. data/lib/rust/commands/commands/rm.rb +14 -0
  110. data/lib/rust/commands/commands/test.rb +20 -0
  111. data/lib/rust/helpers/array.rb +10 -0
  112. data/lib/rust/helpers/command_center.rb +78 -0
  113. data/lib/rust/helpers/constants.rb +58 -0
  114. data/lib/rust/helpers/io.rb +132 -0
  115. data/lib/rust/helpers/parser.rb +45 -0
  116. data/lib/rust/helpers/rush_control.rb +40 -0
  117. data/lib/rust/helpers/string.rb +50 -0
  118. data/lib/rust/helpers/trollop.rb +475 -0
  119. data/lib/rust/parsers/bash.rb +220 -0
  120. data/lib/rust/parsers/bash/stdlibext.rb +32 -0
  121. data/lib/rust/parsers/ren.rb +57 -0
  122. data/lib/rust/rust.rb +75 -0
  123. data/lib/rust/syntax/command.rb +23 -0
  124. data/lib/rust/syntax/paths.rb +31 -0
  125. data/lib/rust/syntax/pipes.rb +148 -0
  126. data/naksh.gemspec +55 -0
  127. data/test/naksh/arg_parser.rspec.rb +27 -0
  128. data/test/naksh/commands/bash/echo.rspec.rb +32 -0
  129. data/test/naksh/commands/sortlist +127 -0
  130. data/test/naksh/external_command.rspec.rb +46 -0
  131. data/test/naksh/send_error.rspec.rb +60 -0
  132. data/test/naksh/suggest.rspec.rb +38 -0
  133. data/test/naksh/syntax/bash.rspec.rb +69 -0
  134. data/test/naksh/syntax/bash/execute.rspec.rb +51 -0
  135. data/test/naksh/syntax/rspec.rb +63 -0
  136. data/test/run_rspecs.rb +20 -0
  137. metadata +217 -0
@@ -0,0 +1,220 @@
1
+ #!/usr/local/bin/ruby
2
+ # 2011 Mahmut Bulut, thefed, and Antonio Salazar
3
+
4
+ # This file is part of Naksh.
5
+ #
6
+ # Naksh is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Naksh is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Naksh. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ # this is bash.rb with piping removed
20
+
21
+ require "rubygems"
22
+ require 'gettext'
23
+ #require "../helpers/parser.rb"
24
+ #require "bash/stdlibext.rb"
25
+ #require "../commands/builtins.rb"
26
+ Dir[File.join(File.dirname(__FILE__), "bash/*")].each {|l| require l }
27
+
28
+ module Naksh
29
+ module Syntax
30
+ module Bash
31
+
32
+ extend ::Parser
33
+ #executes a script
34
+ #entrance point
35
+ def Bash.execute(script_str)
36
+ end_res = []
37
+ styles = []
38
+ #splits at ';'
39
+ Bash.split_script(Bash.clean_script(script_str)).each do |pipeline|
40
+
41
+ result=[]
42
+
43
+ #splits at '|'
44
+ pipeline=Bash.split_pipeline(Bash.clean_pipeline(pipeline))
45
+ pipeline.each_index do |i|
46
+
47
+ #split into [command_name,['array','of','space',"separated arguments"]]
48
+ d=Bash.split_command(Bash.clean_command(pipeline[i]))
49
+
50
+ result<<[d[0],d[1]]
51
+
52
+ #if an error gets thrown by a command, just quit
53
+ # return nil if Naksh.stopped?
54
+
55
+ end
56
+
57
+ styles = result.map do |part|
58
+ if builtin_commands.include? part[0].strip.to_sym
59
+ :builtin
60
+ else
61
+ :cmd
62
+ end
63
+ end
64
+
65
+ end_res.concat result
66
+
67
+ end
68
+ end_res << styles
69
+ print run(*end_res)
70
+ end
71
+
72
+ #should call any tidying methods helpful to other steps
73
+ #currently just removes comments
74
+ def Bash.clean_script(script_str)
75
+ Bash.remove_comments(script_str)
76
+ end
77
+
78
+
79
+ #should remove all comments from script
80
+ def Bash.remove_comments(script_str)
81
+ loop do
82
+ start=Bash.find_unescaped_nonstring(script_str,'#')
83
+ return script_str unless start
84
+ close=Bash.find_unescaped_nonstring(script_str,"\n",start)
85
+ return script_str[0..start-1] unless close
86
+ script_str=script_str[0..start-1]<<script_str[close+1..script_str.length]
87
+ end
88
+ end
89
+
90
+
91
+ #splits a script into wholly independant segments
92
+ def Bash.split_script(str)
93
+ Bash.split_unescaped(str,';')
94
+ end
95
+
96
+
97
+ #should call any tidying methods helpful to other steps
98
+ #currently returns input
99
+ def Bash.clean_pipeline(pipe_str)
100
+ pipe_str
101
+ end
102
+
103
+
104
+ #separate commands in a pipeline
105
+ def Bash.split_pipeline(str)
106
+ Bash.split_unescaped(str,'|')
107
+ end
108
+
109
+
110
+ #prepares for Bash.split_command
111
+ #by unifying syntax variations
112
+ #removing excess whitespace, etc
113
+
114
+ #it wraps the actual command in single quotes
115
+ def Bash.clean_command(com_str)
116
+
117
+ #remove leading whitespace
118
+ com_str.sub!(/\A\s+/,'')
119
+
120
+ #need to evaluate variables before this
121
+ com_str.sub!(/\A'([^']+)'(\S*)/,'\'\1\2\'')
122
+ com_str.sub!(/\A"([^"]+)"(\S*)/,'\'\1\2\'')
123
+ com_str.sub!(/\A(\S+)/,'\'\1\'')
124
+
125
+ #I think this section may be useless, not belong here, etc.
126
+ invalid_starting_characters=%w[; | #]
127
+ invalid_starting_characters.each do |chr|
128
+ if (/^/+chr).match(com_str)
129
+ err _('commands cannot begin with the following character')<<' '<<chr
130
+ end
131
+ end
132
+
133
+ com_str
134
+ end
135
+
136
+
137
+ #I couldn't make a good regexp version, but THIS WORKS
138
+ #takes into account escaping (\) and quotation ("')
139
+ def Bash.find_unescaped_nonstring(str,search_char,starting_index=0)
140
+ search_char=search_char.chr if search_char.kind_of? Integer
141
+ raise ArgumentError,"Naksh::Syntax::Bash.find_unescaped_nonstring(#{re.inspect},#{str.inspect})" unless search_char.kind_of? String and str.kind_of? String and search_char.length==1 and starting_index.kind_of? Integer
142
+ return nil if str.length<=starting_index
143
+ escaped=false
144
+ string_open=false
145
+ starting_index.upto str.length-1 do |i|
146
+ next if i<starting_index
147
+ if str[i].chr==search_char
148
+ return i unless escaped or string_open
149
+ elsif str[i].chr=="\\"
150
+ escaped=!escaped
151
+ elsif not escaped and str[i].chr=='\''
152
+ case string_open
153
+ when false
154
+ string_open='\''
155
+ when '\''
156
+ string_open=false
157
+ end
158
+ elsif not escaped and str[i].chr=='"'
159
+ case string_open
160
+ when false
161
+ string_open='"'
162
+ when '"'
163
+ string_open=false
164
+ end
165
+ else
166
+ escaped=false
167
+ end
168
+ end
169
+ #Regexp requires zero-width negative lookbehind
170
+ #/\A(([^\\](\\\\)*)(("[^"]*")|('[^']*'))*/<<re
171
+ nil
172
+ end
173
+
174
+
175
+ def Bash.split_command(com_str)
176
+ com_arr=Bash.split_unescaped(com_str,' ')
177
+ com_arr=[com_str,[]] unless com_arr
178
+ raise RuntimeError,'single quotes should have been added around command earlier in processing'<<"\ncommand as recieved = #{com_str.inspect}" unless /\A'.*'\z/.match(com_arr[0])
179
+ com_arr[0].replace(com_arr[0][1,com_arr[0].length-2])
180
+ [com_arr[0],com_arr[1,com_arr.length]]
181
+ end
182
+
183
+
184
+
185
+ #returns an Array of Strings,
186
+ #made of str split at every unescaped instance of char
187
+ #not enclosed in an unescaped string delimiter ('")
188
+ def Bash.split_unescaped(str,char)
189
+ result=[]
190
+ split_index=0
191
+ loop do
192
+ split_index=Bash.find_unescaped_nonstring(str,char)
193
+ return result<<str unless split_index
194
+ result<<str[0,split_index] unless split_index.zero?
195
+ str=str[split_index+1,str.length]
196
+ return result if str.empty?
197
+ end
198
+ end
199
+
200
+
201
+
202
+ def Bash.complete(command)
203
+ possible = []
204
+ builtin_commands.each do |com|
205
+ possible << com if com.to_s.match command # only if it matches
206
+ break if com[0] > command[0] # break if we're after it
207
+ end
208
+ if possible.length > 1 # if we found multiple matches
209
+ raise Hell, "Too ambiguous of a command" # raise Hell
210
+ else # else its size = 1
211
+ return possible[0] # return the chosen one
212
+ end
213
+ end
214
+
215
+
216
+ end
217
+ end
218
+ end
219
+
220
+ #Naksh::Syntax::Bash.execute('ls | wc -l')
@@ -0,0 +1,32 @@
1
+ #!/usr/local/bin/ruby
2
+ # 2011 Mahmut Bulut
3
+
4
+ # This file is part of Naksh.
5
+ #
6
+ # Naksh is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Naksh is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Naksh. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ def Regexp.join(re_list,preserve_options=true)
20
+ raise ArgumentError,"Regexp.join: 1st argument should be an array #{re_list}" unless re_list.respond_to? :collect and re_list.respond_to? :join
21
+ re_list.collect! do |re|
22
+ re= Regexp.new(Regexp.escape(re)) if re.kind_of? String
23
+ re= Regexp.new(re) unless re.kind_of? Regexp
24
+ preserve_options ? re.to_s : '(?:'<<re.source<<')'
25
+ end
26
+ Regexp.compile(re_list.join('').gsub(/\(\?[\w\-]*\:\)/,''))
27
+ end
28
+ class Regexp
29
+ def +(other)
30
+ Regexp.join([self,other],false)
31
+ end
32
+ end
@@ -0,0 +1,57 @@
1
+ #!/usr/local/bin/ruby
2
+ #
3
+ # Created by me on 2011-12-15.
4
+ # Copyright (c) 2011. All pwnage reserved.
5
+
6
+ #
7
+ # run_as_ruby is not allowed in Ren
8
+
9
+ module Ren
10
+ class << self
11
+ include Parser
12
+
13
+ def execute(line)
14
+ (eval(line); return) if line.strip.slice(0).chr =~ /!/
15
+
16
+ package = check_for_pipes(line)
17
+ p package
18
+ print run_standard(package[0], package[1])
19
+
20
+ # Gotta catch 'em all
21
+ # rescue NameError => e
22
+ # err "Internal Command Unknown"
23
+ rescue ArgumentError => e
24
+ err "Improper use of command syntax"
25
+ rescue SyntaxError => e
26
+ err "Incorrect Ruby Grammar"
27
+ rescue Errno::ENOENT => e
28
+ err "Command not found"
29
+ rescue => e
30
+ raise e
31
+ end
32
+
33
+ def check_for_pipes(line)
34
+ cmd_parts = (line.match('|') ? line.split('|') : [line] ) # check for pipelining
35
+ # because between the pipes,
36
+ # it's nothing but commands
37
+
38
+ clean_whitespace!(cmd_parts)
39
+
40
+ styles = cmd_parts.map do |cmd_part|
41
+ parts = cmd_part.split(' ')
42
+ cmd = parts[0]
43
+ if builtin_commands.include? cmd.strip.to_sym
44
+ :builtin
45
+ else
46
+ :cmd
47
+ end
48
+ end
49
+ [cmd_parts, styles]
50
+ end
51
+
52
+ def clean_whitespace!(parts)
53
+ parts.map! {|p| p.strip }
54
+ end
55
+
56
+ end
57
+ end
data/lib/rust/rust.rb ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/local/bin/ruby
2
+ #
3
+ # Created by me on 2011-12-07.
4
+ # Copyright (c) 2011. All pwnage reserved.
5
+
6
+ require "rubygems"
7
+ require "highline/system_extensions"
8
+ require "shellwords"
9
+
10
+ require "helpers/trollop.rb"
11
+
12
+
13
+ require "commands/builtins.rb"
14
+ require "syntax/paths.rb"
15
+ require "syntax/pipes.rb"
16
+ require "helpers/array.rb"
17
+ require "helpers/command_center.rb"
18
+ require "helpers/constants.rb"
19
+ require "helpers/io.rb"
20
+ require "helpers/parser.rb"
21
+ require "helpers/string.rb"
22
+
23
+ Dir['parsers/*'].each {|l| require l }
24
+ require "helpers/rush_control.rb" # needs to be loaded AFTER the parsers
25
+
26
+ include HighLine::SystemExtensions
27
+
28
+ class Rust
29
+
30
+ ###
31
+ # Used by the parser
32
+ def self.io
33
+ @@io
34
+ end
35
+
36
+ def initialize(stdin=$stdin, stdout=$stdout, stderr=$stderr)
37
+ $stdin, $stdout, $stderr = stdin, stdout, stderr
38
+
39
+ $keys ||= {}
40
+ @history = []
41
+ @io = InOut.new(stdin, stdout, stderr, $keys)
42
+ @@io = @io # a nice hack for parser compatiblity
43
+
44
+ run
45
+ end
46
+
47
+ def run
48
+ ######
49
+ ## Read the user's .rustrc file
50
+ if File.exist? "#{ENV['HOME']}/.rustrc"
51
+ CommandCenter.instance_eval(File.read("#{ENV['HOME']}/.rustrc"))
52
+ else
53
+ File.open("#{ENV['HOME']}/.rustrc", 'w')
54
+ end
55
+
56
+ prompt
57
+ end
58
+
59
+
60
+ def prompt
61
+ line = ''
62
+ loop {
63
+ line += ask($prompt)
64
+ # unless line.slice(-1) =~ /\\/
65
+ @history << line
66
+ $parser.execute line.strip unless line.strip =~ /^$/ # $parser.execute line
67
+ line = ''
68
+ # end
69
+ }
70
+ end
71
+
72
+ end
73
+
74
+
75
+ Rust.new
@@ -0,0 +1,23 @@
1
+ #!/usr/local/bin/ruby
2
+ #
3
+ # Created by me on 2011-12-07.
4
+ # Copyright (c) 2011. All pwnage reserved.
5
+
6
+ # NO LONGER IN USE
7
+ # BUT USED TO BE USED BY CommandCenter
8
+
9
+ class Command
10
+
11
+ attr_reader :command, :arguments
12
+
13
+ def initialize(name, args, str={:stdin => STDIN, :stdout => STDOUT, :stderr => STDERR})
14
+ @command = name
15
+ @arguments = args
16
+ @streams = { :stdin => str[:in], :stdout => str[:out], :stderr => str[:err] }
17
+ end
18
+
19
+ def run
20
+ exec(@command, @arguments)
21
+ end
22
+
23
+ end
@@ -0,0 +1,31 @@
1
+ #!/usr/local/bin/ruby
2
+ #
3
+ # Created by me on 2011-12-07.
4
+ # Copyright (c) 2011. All pwnage reserved.
5
+ #$path = ['/bin', '/usr/bin', '/usr/local/bin']
6
+
7
+ module Paths
8
+ class << self
9
+
10
+ ############
11
+ public
12
+ ############
13
+
14
+ # linear search
15
+ # checks if file if on path
16
+ def on_path? file
17
+ $path.each do |f|
18
+ return f if Dir[File.join(f, file)]
19
+ end
20
+ false
21
+ end
22
+
23
+ def find_path(file)
24
+ return Dir.pwd + file unless on_path? file
25
+ return File.join(on_path?(file), file)
26
+ end
27
+
28
+ end
29
+ end
30
+
31
+ #p Paths.find_path('ls')
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # Created by me on 2011-12-07.
5
+ # Copyright (c) 2011. All pwnage reserved.
6
+
7
+ #require File.join(File.dirname(__FILE__), "../commands/builtins.rb")
8
+ #require File.join(File.dirname(__FILE__), "../helpers/command_center.rb")
9
+
10
+ module Pipes
11
+
12
+ #################
13
+ # Shamelessly borrowed from RS, written by kittensoft
14
+ # This totally rocks, despite it being pretty much popen3/4
15
+ #################
16
+ def self.pipe_to(*args)
17
+ error = nil
18
+ # Custom streams?
19
+ args, ios = if args.last.kind_of? Hash
20
+ [args[0...-1], args.last]
21
+ else
22
+ [args, {}]
23
+ end
24
+ style = ios[:style]
25
+ ios.reject! {|key, i| key == :style }
26
+
27
+ # pipe.first is read, pipe.last is write
28
+ in_pipe, out_pipe, err_pipe = IO.pipe, IO.pipe, IO.pipe
29
+
30
+ # Adjust the pipes if we have custom streams
31
+ ios.each {|n, stream| raise ArgumentError.new("#{n} must be an IO!") unless stream.kind_of? IO}
32
+
33
+ in_pipe[0] = ios[:stdin] if ios[:stdin]
34
+ out_pipe[1] = ios[:stdout] if ios[:stdout]
35
+ err_pipe[1] = ios[:stderr] if ios[:stderr]
36
+
37
+ child = fork do
38
+ # Reconfigure the standard I/O
39
+ in_pipe.last.close # Cannot write to STDIN
40
+ (IO.open(0)).reopen in_pipe.first # Input comes from reading in_pipe
41
+ in_pipe.first.close # Unnecessary, replaced above
42
+
43
+ out_pipe.first.close # Cannot read from STDOUT
44
+ (IO.open(1)).reopen out_pipe.last # Output goes to writing side of out_pipe
45
+ out_pipe.last.close # Close old read
46
+
47
+ err_pipe.first.close # Cannot read from STDERR
48
+ (IO.open(2)).reopen err_pipe.last # Error output goes to writing side of err_pipe
49
+ err_pipe.last.close # Close old read
50
+
51
+ # Run the command with the new environment
52
+
53
+ case style
54
+ when :standard
55
+ ::CommandCenter.run_standard(args.join(' '))
56
+ when :ruby
57
+ ::CommandCenter.run_as_ruby(args.join(' '))
58
+ when :builtin
59
+ ::CommandCenter.run_as_builtin(args.join(' '))
60
+ when :cmd
61
+ arr = ::Shellwords.shellwords(args.join(''))
62
+ cmd = arr.shift
63
+ exec(::Paths.find_path(cmd), *arr)
64
+ end
65
+ end # fork
66
+
67
+
68
+ # Close unnecessary sides
69
+ # in_pipe.first.close # Cannot read from other program's STDIN
70
+ out_pipe.last.close # Cannot write to other program's STDOUT
71
+ err_pipe.last.close # Cannot write to other program's STDERR
72
+
73
+ # Do not wait for child
74
+ res = [child, in_pipe.last, out_pipe.first, err_pipe.first]
75
+
76
+ # Block-form
77
+ if block_given?
78
+ begin
79
+ value = yield(*res)
80
+ ensure
81
+ Process.waitpid child
82
+ res[1..-1].each {|pipe| pipe.close unless pipe.closed?}
83
+ value
84
+ end
85
+ # Raw
86
+ else
87
+ res
88
+ end # if block_given?
89
+ end # self.pipe_to
90
+
91
+ end
92
+
93
+
94
+ __END__
95
+ run(["ls", []], ["wc", ["-l"]], [:builtin, :cmd])
96
+ run_standard(["ls", "wc"], [:builtin, :cmd])
97
+ run_standard(["echo foo", "cat", "cat"], [:cmd, :cmd, :cmd])
98
+
99
+ Pipes.pipe_to('ls') {|pid, i, o, e|
100
+ Pipes.pipe_to('wc -l', :stdin => o) {|ppid, ii, oo, ee| oo.read.should.equal res}
101
+ }
102
+
103
+ def |(other)
104
+ Pipes.pipe_to(self.to_s) {|p, i, o, e|
105
+ Pipes.pipe_to(other.to_s, :stdin => o) {|pid, in, out, err| say out.read}
106
+ }
107
+ end
108
+
109
+ def run_standard(parts, styles)
110
+ # Please note that this will
111
+ # work for even single commands!
112
+ # :stding is STDIN and :stdout is STDOUT
113
+
114
+ # this is the actual pipage
115
+ inp = STDIN
116
+ res = []
117
+ parts.each_with_index do |part, i|
118
+ # pipe_to returns the pid, in, out, and err
119
+ pipes = ::Pipes.pipe_to(part, :stdin => inp, :style => styles[i])
120
+ inp = pipes[2]
121
+ res.concat pipes[1..-1]
122
+ end
123
+ # p res
124
+ puts res[-2].read
125
+ # close them all off
126
+ res.each {|pipe| pipe.close unless pipe.closed? }
127
+ end
128
+
129
+
130
+ def line(args)
131
+ pipes = []
132
+ pipes << ::Pipes.pipe_to(args[0])
133
+ # pipes << ::Pipes.pipe_to(args[1],:stdin => pipes[0][2])
134
+ ::Pipes.pipe_to(args[1], :stdin => pipes[0][2]) {|pid, inp, out, err| puts out.read}
135
+ pipes.each{|p| p[1..-1].each{|l| l.close unless l.closed? } }
136
+ end
137
+
138
+
139
+ case style
140
+ when :standard
141
+ CommandCenter.run_standard(args.join(' '))
142
+ when :ruby
143
+ CommandCenter.run_as_ruby(args.join(' '))
144
+ when :builtin
145
+ CommandCenter.run_as_builtin(args.join(' '))
146
+ when :cmd
147
+ exec(*args)
148
+ end