rash-command-shell 0.2.0 → 0.2.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6769401d090279e0c3f7b3a2e26a52c59af013196c84e9b42ec09e5d9e5b5a42
4
- data.tar.gz: 9a93bc36eb0316ba762cefa301457b9537df4009ee8127ae8c8691bdb18eecaa
3
+ metadata.gz: 8d2870af889b41fda5f16c62f4f181c09ae843cc61ef4391596078c723c13269
4
+ data.tar.gz: 0e4e282af5b0940e63478b62985238e427969f2d95e7fccb6e25afc7f18f7c3b
5
5
  SHA512:
6
- metadata.gz: 1462afc1e5767594c11f45104046618a3c5158cab07ad1315fe2e46b7ed64cea0c2972516338086cbb5e6ae2ba3f99e7e442873bc7213d72830697f36adf3cdd
7
- data.tar.gz: c296445d776d3dcde932617030279866961e1f77126e9551d08a5e31835dc0d583b710ba34a8382b245b6c142b1d51ab02081ef0a744b29556d4aef06a830933
6
+ metadata.gz: ca2658254fe315de5c6902a301d1a5d7f210e68630f9ac0677d811af697a2b334e6f185882d4ac8e725e56ee3e8dad777f8b09e7a5db9159914fb2dbecf9a589
7
+ data.tar.gz: 2820b7e820e1a28fdf87e898cc284b8c8a9be53193fd72047b61cc6036ba51eb2fa92e2b0dc687e73f258a8af7854a89320230bf349b71cc8d5d3e09ee46ca62
data/bin/rash CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  if ARGV.empty?
4
4
  exec("irb", "-r", "rash", *ARGV)
5
+ elsif ARGV[0] =~ /(-)?-v(ersion)?/
6
+ puts "Rash (c) 2020 Kellen Watt"
7
+ puts "Version 0.2.2" # I may forget to update this
5
8
  elsif File.exists?(ARGV[0]) && !File.directory?(ARGV[0])
6
9
  require "rash"
7
10
  file = ARGV.shift
@@ -1,7 +1,6 @@
1
1
  class Environment
2
2
 
3
3
  attr_reader :aliasing_disabled
4
- attr_reader :superuser_mode
5
4
  attr_reader :umask
6
5
 
7
6
  def initialize
@@ -56,6 +55,14 @@ class Environment
56
55
  limits.each {|resource, limit| Process.setrlimit(resource, *limit)}
57
56
  end
58
57
  end
58
+
59
+ def dispatch(m, *args)
60
+ if @in_pipeline
61
+ add_pipeline(m, *args)
62
+ else
63
+ system_command(m, *args)
64
+ end
65
+ end
59
66
 
60
67
  private
61
68
 
@@ -75,6 +82,23 @@ class Environment
75
82
  }
76
83
  ENV["RASHDIR"] = File.dirname(__FILE__)
77
84
  end
85
+
86
+ def resolve_command(m, *args, literal: false)
87
+ (literal ? [m.to_s] : resolve_alias(m)) + args.flatten.map{|a| a.to_s}
88
+ end
89
+
90
+ def system_command(m, *args, except: false, literal: false, out: nil, input: nil, err: nil)
91
+ command = resolve_command(m, *args, literal: literal)
92
+ command.unshift("sudo") if @superuser_mode
93
+ opts = {out: out || $stdout,
94
+ err: err || $stderr,
95
+ in: input || $stdin,
96
+ exception: except || @superuser_mode,
97
+ umask: @umask}
98
+
99
+ system(*command, opts)
100
+ end
101
+
78
102
  end
79
103
 
80
104
  require_relative "rash/redirection"
@@ -103,13 +127,16 @@ def run(file, *args)
103
127
  unless File.executable?(exe)
104
128
  raise SystemCallError.new("No such executable file - #{exe}", Errno::ENOENT::Errno)
105
129
  end
106
- system(exe, *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin, umask: $env.umask})
130
+ $env.dispatch(exe, *args, literal: true)
131
+ # system(exe, *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin, umask: $env.umask})
107
132
  end
108
133
 
109
134
  alias cmd __send__
110
135
 
111
136
  # Defines `bash` psuedo-compatibility. Filesystem effects happen like normal
112
137
  # and environmental variable changes are copied
138
+ #
139
+ # This is an artifact of an old design and is deprecated until further notice.
113
140
  def sourcesh(file)
114
141
  bash_env = lambda do |cmd = nil|
115
142
  tmpenv = `#{cmd + ';' if cmd} printenv`
@@ -141,17 +168,10 @@ end
141
168
 
142
169
  # Note that I defy convention and don't define `respond_to_missing?`. This
143
170
  # is because doing so screws with irb.
144
- # This code is a nightmarish monstrosity. I need some kind of "dispatch" method on Environment
145
171
  def self.method_missing(m, *args, &block)
146
172
  exe = which(m.to_s)
147
173
  if exe || ($env.alias?(m) && !$env.aliasing_disabled)
148
- if $env.superuser_mode
149
- system("sudo", *$env.resolve_alias(m), *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin, exception: true, umask: $env.umask})
150
- elsif $env.pipelined? # implicitly disallowing superuser_mode for now. Need to refactor to allow
151
- $env.add_pipeline(m, *args)
152
- else
153
- system(*$env.resolve_alias(m), *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin, umask: $env.umask})
154
- end
174
+ $env.dispatch(m, *args)
155
175
  else
156
176
  super
157
177
  end
@@ -7,26 +7,12 @@ class Environment
7
7
  @aliases.delete(func.to_sym)
8
8
  end
9
9
 
10
- # recursive aliases not currently possible. In the works
11
- def resolve_alias(f)
12
- result = [f.to_s]
13
- aliases = @aliases.dup
14
- found_alias = true
15
- while found_alias
16
- found_alias = false
17
- if aliases.has_key?(result[0].to_sym)
18
- found_alias = true
19
- match = result[0].to_sym
20
- result[0] = aliases[match]
21
- aliases.delete(match)
22
- result.flatten!
23
- end
24
- end
25
- result
26
- end
27
-
28
10
  def alias?(f)
29
- @aliases.has_key?(f.to_sym)
11
+ @aliases.key?(f.to_sym)
12
+ end
13
+
14
+ def aliases
15
+ @aliases.dup
30
16
  end
31
17
 
32
18
  def without_aliasing
@@ -52,4 +38,25 @@ class Environment
52
38
  end
53
39
  end
54
40
  end
41
+
42
+ private
43
+
44
+ # Unless given a compelling reason, this doesn't need to be public. For most
45
+ # purposes, some combination of `alias?` and `aliases` should be sufficient.
46
+ def resolve_alias(f)
47
+ result = [f.to_s]
48
+ aliases = @aliases.dup
49
+ found_alias = true
50
+ while found_alias
51
+ found_alias = false
52
+ if aliases.has_key?(result[0].to_sym)
53
+ found_alias = true
54
+ match = result[0].to_sym
55
+ result[0] = aliases[match]
56
+ aliases.delete(match)
57
+ result.flatten!
58
+ end
59
+ end
60
+ result
61
+ end
55
62
  end
@@ -2,6 +2,7 @@ class Environment
2
2
 
3
3
  RASH_LOCAL_FILE = ".rashrc.local"
4
4
 
5
+ # Has to be a better way of adding extensions and dynamically loading them
5
6
  def initialize
6
7
  common_init
7
8
  @working_directory = Directory.root("/")
@@ -33,8 +34,6 @@ class Environment
33
34
 
34
35
  private
35
36
 
36
- LOCAL_FUNCTIONS_ENABLED = true
37
-
38
37
  # from and to are strings
39
38
  def traverse_filetree(from, to)
40
39
  abs_from = File.expand_path(from)
@@ -120,16 +119,13 @@ class Environment
120
119
  end
121
120
  end
122
121
 
122
+ # still could absolutely be more cleaned up, but it works
123
123
  def self.method_missing(m, *args, &block)
124
124
  exe = which(m.to_s)
125
125
  if $env.local_method?(m)
126
126
  $env.local_call(m, *args, &block)
127
127
  elsif exe || ($env.alias?(m) && !$env.aliasing_disabled)
128
- if $env.superuser_mode
129
- system("sudo", *$env.resolve_alias(m), *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin, exception: true, umask: $env.umask})
130
- else
131
- system(*$env.resolve_alias(m), *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin, umask: $env.umask})
132
- end
128
+ $env.dispatch(m, *args)
133
129
  else
134
130
  super
135
131
  end
@@ -17,5 +17,3 @@ end
17
17
  def as_background(&block)
18
18
  $env.async(&block)
19
19
  end
20
-
21
-
@@ -4,11 +4,48 @@ class Environment
4
4
  @in_pipeline
5
5
  end
6
6
 
7
+ def make_pipeline(&block)
8
+ raise IOError.new("pipelining already enabled") if @in_pipeline
9
+ start_pipeline
10
+ begin
11
+ block.call
12
+ ensure
13
+ end_pipeline
14
+ end
15
+ nil
16
+ end
17
+
18
+ def as_pipe_command(&block)
19
+ raise IOError.new("pipelining not enabled") unless @in_pipeline
20
+
21
+ input = (@active_pipelines.empty? ? $stdin : @active_pipelines.last.reader)
22
+ @active_pipelines << Pipeline.new
23
+ output = @active_pipelines.last.writer
24
+ error = ($stderr == $stdout ? output : $stderr)
25
+
26
+ pid = fork do
27
+ @in_pipeline = false
28
+ $stdin = input
29
+ $stdout = output
30
+ $stderr = error
31
+ block.call
32
+ output.close
33
+ exit!(true)
34
+ end
35
+ output.close
36
+
37
+ @active_pipelines.last.link_process(pid)
38
+ nil
39
+ end
40
+
41
+ private
42
+
7
43
  def start_pipeline
8
44
  @in_pipeline = true
9
45
  end
10
46
 
11
47
  def end_pipeline
48
+ raise IOError.new("pipelining not enabled") unless @in_pipeline
12
49
  @in_pipeline = false
13
50
  if @active_pipelines.size > 0
14
51
  Process.wait(@active_pipelines.last.pid)
@@ -20,13 +57,15 @@ class Environment
20
57
  end
21
58
  end
22
59
 
60
+ # special method to be referenced from Environment#dispatch. Do not use directly
23
61
  def add_pipeline(m, *args)
62
+ raise IOError.new("pipelining not enabled") unless @in_pipeline
24
63
  input = (@active_pipelines.empty? ? $stdin : @active_pipelines.last.reader)
25
64
  @active_pipelines << Pipeline.new
26
65
  output = @active_pipelines.last.writer
27
66
  error = ($stderr == $stdout ? output : $stderr)
28
67
  pid = fork do # might not be necessary, spawn might cover it. Not risking it before testing
29
- system(*$env.resolve_alias(m), *args.flatten.map{|a| a.to_s}, {out: output, in: input, err: error, exception: true, umask: @umask})
68
+ system_command(m, *args, out: output, input: input, err: error, except: true)
30
69
  output.close
31
70
  exit!(true)
32
71
  end
@@ -34,26 +73,6 @@ class Environment
34
73
  @active_pipelines.last.link_process(pid)
35
74
  end
36
75
 
37
- def as_pipe(&block)
38
- input = (@active_pipelines.empty? ? $stdin : @active_pipelines.last.reader)
39
- @active_pipelines << Pipeline.new
40
- output = @active_pipelines.last.writer
41
- error = ($stderr == $stdout ? output : $stderr)
42
- pid = fork do
43
- @in_pipeline = false
44
- $stdin = input
45
- $stdout = output
46
- $stderr = error
47
- block.call
48
- output.close
49
- exit!(true)
50
- end
51
- output.close
52
- @active_pipelines.last.link_process(pid)
53
- end
54
-
55
- private
56
-
57
76
  class Pipeline
58
77
  attr_reader :writer, :reader, :pid
59
78
 
@@ -85,11 +104,5 @@ end
85
104
 
86
105
 
87
106
  def in_pipeline(&block)
88
- raise IOError.new("pipelining already enabled") if $env.pipelined?
89
- $env.start_pipeline
90
- begin
91
- block.call
92
- ensure
93
- $env.end_pipeline
94
- end
107
+ $env.make_pipeline(&block)
95
108
  end
@@ -1,7 +1,5 @@
1
1
  class Environment
2
2
 
3
- DEFAULT_IO = {in: STDIN, out: STDOUT, err: STDERR}
4
-
5
3
  def reset_io
6
4
  reset_stdout
7
5
  reset_stderr
@@ -78,6 +76,10 @@ class Environment
78
76
  def standard_stream?(f)
79
77
  DEFAULT_IO.values.include?(f)
80
78
  end
79
+
80
+ private
81
+
82
+ DEFAULT_IO = {in: STDIN, out: STDOUT, err: STDERR}
81
83
  end
82
84
 
83
85
  # If you want to append, you need to get the file object yourself.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rash-command-shell
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kellen Watt