chitin 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README +4 -0
- data/TODO +6 -1
- data/bin/chitin +5 -2
- data/lib/chitin/commands/builtins.rb +51 -3
- data/lib/chitin/commands/executable.rb +27 -6
- data/lib/chitin/commands/ruby.rb +25 -2
- data/lib/chitin/core_ext/array.rb +7 -0
- data/lib/chitin/core_ext/coolline.rb +10 -1
- data/lib/chitin/core_ext/kernel.rb +21 -0
- data/lib/chitin/file.rb +0 -17
- data/lib/chitin/manifests/manifest.rb +36 -0
- data/lib/chitin/session.rb +11 -5
- data/lib/chitin/version.rb +1 -1
- metadata +5 -2
data/README
CHANGED
data/TODO
CHANGED
@@ -12,6 +12,9 @@ FUTURE:
|
|
12
12
|
* tab complete ruby/shell things
|
13
13
|
* post_processing for shell commands
|
14
14
|
-> make it asynchronous and use pipes
|
15
|
+
* ability to 'neuter' a command, so that it won't automatically be run
|
16
|
+
-> i think i just did this in a commit (6/11/13)
|
17
|
+
* grep through history
|
15
18
|
|
16
19
|
QUIRKS:
|
17
20
|
* menu doesn't erase itself sometimes
|
@@ -19,9 +22,11 @@ QUIRKS:
|
|
19
22
|
* does not play nice with GDB if it is called within the bash profile file
|
20
23
|
|
21
24
|
FAILURES:
|
22
|
-
* ^C on running ruby programs kills the whole interpreter... womp.
|
23
25
|
* slashes in filenames
|
24
26
|
* `include Math; sin(5)` fails
|
27
|
+
* too many open pipes
|
28
|
+
-> don't close them in the first place
|
29
|
+
* unable to do "STDIN > ls > NULLOUT ^ NULLERR"
|
25
30
|
|
26
31
|
Questions:
|
27
32
|
* Why do you have to do @line = '' in Coolline in order to not affect the
|
data/bin/chitin
CHANGED
@@ -12,9 +12,12 @@ end
|
|
12
12
|
require File.join(File.dirname(follow_link(__FILE__)), "..", "lib", "chitin")
|
13
13
|
|
14
14
|
rc = ARGV[0] || File.expand_path('~/.chitinrc')
|
15
|
-
FileUtils.touch rc
|
16
15
|
|
17
|
-
Chitin::Builtins.class_eval File.read(rc)
|
16
|
+
Chitin::Builtins.class_eval File.read(rc) if rc
|
17
|
+
|
18
|
+
if rc && File.exists?(rc)
|
19
|
+
Chitin::Builtins.class_eval File.read(rc)
|
20
|
+
end
|
18
21
|
|
19
22
|
SESSION = Chitin::Session.new Chitin::Builtins
|
20
23
|
SESSION.start
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# Things are contained in modules or functions so that they play well with
|
2
2
|
# code folding.
|
3
|
+
# Picked up that trick from Sinatra
|
3
4
|
|
4
5
|
require 'etc'
|
5
6
|
ENV['USER'] ||= Etc.getlogin
|
@@ -47,7 +48,17 @@ module Chitin
|
|
47
48
|
|
48
49
|
# ruby's backtick doesn't chomp off the newline, which makes it more
|
49
50
|
# or less useless for piping into other commands
|
50
|
-
def `(args)
|
51
|
+
def `(*args)
|
52
|
+
res = eval args.join
|
53
|
+
|
54
|
+
if Runnable === res
|
55
|
+
composed = res | L {|str| str }
|
56
|
+
res = composed[:raw_run].chomp
|
57
|
+
composed[:wait]
|
58
|
+
end
|
59
|
+
|
60
|
+
res.to_s
|
61
|
+
end
|
51
62
|
|
52
63
|
# Place the last argument on the line
|
53
64
|
# This is a total hack. It would need proper parsing to accomodate for
|
@@ -109,6 +120,41 @@ module Chitin
|
|
109
120
|
def prompt
|
110
121
|
"#{ENV['USER']}: #{short_pwd} % "
|
111
122
|
end
|
123
|
+
|
124
|
+
# Get the elapsed time of the last command.
|
125
|
+
def last_elapsed
|
126
|
+
SESSION.last_elapsed || 0.0
|
127
|
+
end
|
128
|
+
|
129
|
+
def last_elapsed_formatted
|
130
|
+
hours = (last_elapsed / 3600).floor
|
131
|
+
min = ((last_elapsed - 3600 * hours) / 60).floor
|
132
|
+
sec = last_elapsed - 3600 * hours - 60 * min
|
133
|
+
|
134
|
+
if hours > 0
|
135
|
+
"%02d:%02d:%f" % [hours, min, sec]
|
136
|
+
elsif min > 0
|
137
|
+
"%02d:%f" % [min, sec]
|
138
|
+
else
|
139
|
+
"%f" % sec
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# My personal fancy shell.
|
144
|
+
# On the first line it has the time, elapsed time of the last
|
145
|
+
# run command, and the shortened working directory.
|
146
|
+
# On the second line, it has three colored dots.
|
147
|
+
def time_elapsed_working_multiline_prompt
|
148
|
+
"(".purple + Time.now.to_s + ") ".purple +
|
149
|
+
"(".purple + "last => " + "#{last_elapsed_formatted}".cyan + ") ".purple +
|
150
|
+
"(".purple + short_pwd.yellow + ")\n".purple +
|
151
|
+
'.'.red + '.'.yellow + '.'.cyan + ' '
|
152
|
+
end
|
153
|
+
|
154
|
+
# Minimalist.
|
155
|
+
def minimalist_prompt
|
156
|
+
'.'.red + '.'.yellow + '.'.cyan + ' '
|
157
|
+
end
|
112
158
|
end
|
113
159
|
include Prompts
|
114
160
|
|
@@ -141,14 +187,16 @@ module Chitin
|
|
141
187
|
end
|
142
188
|
end
|
143
189
|
|
144
|
-
# i know puts returns nil, but this is to
|
145
|
-
# the fact that we want it to return nil
|
190
|
+
# i know puts returns nil and p returns the object, but this is to
|
191
|
+
# emphasize the fact that we want it to return nil. also, so that
|
192
|
+
# we don't accidentally run a Runnable while inspecting it
|
146
193
|
nil
|
147
194
|
end
|
148
195
|
end
|
149
196
|
include Aliases
|
150
197
|
|
151
198
|
# Fixnum math is now floating-point math
|
199
|
+
# hashtag gitonmahlevel
|
152
200
|
class ::Fixnum
|
153
201
|
alias_method :old_div, :/
|
154
202
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Chitin
|
2
2
|
class Executable
|
3
|
+
# this is needed to work in tandem with #method_missing.
|
4
|
+
# this will sweep all inherited methods BUT #[] under the rug.
|
3
5
|
__sweep__ :[]
|
4
6
|
|
5
7
|
include Runnable
|
@@ -9,12 +11,17 @@ module Chitin
|
|
9
11
|
|
10
12
|
@path = path
|
11
13
|
@args = process_args(args)
|
14
|
+
@suspended = false
|
12
15
|
end
|
13
16
|
|
14
17
|
# EVERYTHING will be sent to the command. ERRTHANG!!!!
|
15
18
|
def method_missing(name, *arr, &blk)
|
16
|
-
|
17
|
-
|
19
|
+
if @suspended
|
20
|
+
super(name, *arr, &blk)
|
21
|
+
else
|
22
|
+
setup name.to_s, *process_args(arr)
|
23
|
+
self
|
24
|
+
end
|
18
25
|
end
|
19
26
|
|
20
27
|
private
|
@@ -39,9 +46,9 @@ module Chitin
|
|
39
46
|
end
|
40
47
|
else
|
41
48
|
# I'm leaving this here so that I know what went down in this
|
42
|
-
# battlefield. I tried automatically expanding globs, but
|
43
|
-
# in conjunction with * means things get expanded twice,
|
44
|
-
# in a lot of duplicates.
|
49
|
+
# battlefield. I tried automatically expanding FileObject globs, but
|
50
|
+
# that in conjunction with * means things get expanded twice,
|
51
|
+
# resulting in a lot of duplicates.
|
45
52
|
#
|
46
53
|
# Maybe an answer is to get rid of * and only do automatic expansion
|
47
54
|
# for executables.
|
@@ -137,6 +144,21 @@ module Chitin
|
|
137
144
|
end
|
138
145
|
end
|
139
146
|
|
147
|
+
# Make it so you can treat it like a normal object.
|
148
|
+
# This stops method forwarding
|
149
|
+
def suspend
|
150
|
+
@suspended_methods = private_methods.dup
|
151
|
+
@suspended_methods.each {|m| public m }
|
152
|
+
|
153
|
+
@suspended = true
|
154
|
+
end
|
155
|
+
|
156
|
+
def unsuspend
|
157
|
+
@suspended_methods.each {|m| private m }
|
158
|
+
@suspended_methods = []
|
159
|
+
@suspended = false
|
160
|
+
end
|
161
|
+
|
140
162
|
def inspect
|
141
163
|
"#<Chitin::Executable #{super}>"
|
142
164
|
end
|
@@ -146,7 +168,6 @@ module Chitin
|
|
146
168
|
|
147
169
|
[path, *arr.flatten].join ' '
|
148
170
|
end
|
149
|
-
|
150
171
|
end
|
151
172
|
end
|
152
173
|
|
data/lib/chitin/commands/ruby.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Chitin
|
2
|
-
class
|
2
|
+
class PVC
|
3
3
|
__sweep__ :[]
|
4
4
|
|
5
5
|
include Runnable
|
@@ -26,8 +26,13 @@ module Chitin
|
|
26
26
|
|
27
27
|
private
|
28
28
|
|
29
|
+
# prepare the initial input to be sent down through `@chains`
|
30
|
+
def prepare
|
31
|
+
self[:in]
|
32
|
+
end
|
33
|
+
|
29
34
|
def result
|
30
|
-
val =
|
35
|
+
val = prepare
|
31
36
|
@chains.each do |arr|
|
32
37
|
val = if Proc === arr.last
|
33
38
|
val.send *arr[0..-2], &arr[-1]
|
@@ -87,12 +92,30 @@ module Chitin
|
|
87
92
|
end.join '.'
|
88
93
|
end
|
89
94
|
|
95
|
+
def inspect
|
96
|
+
"#<PVC #{to_s}>"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class StringMethod < PVC
|
101
|
+
private
|
102
|
+
|
103
|
+
# the only difference is that we have `self[:in]`
|
104
|
+
# instead of just `self[:in].read`
|
105
|
+
def prepare
|
106
|
+
self[:in].read
|
107
|
+
end
|
108
|
+
|
90
109
|
def inspect
|
91
110
|
"#<StringMethod #{to_s}>"
|
92
111
|
end
|
93
112
|
end
|
94
113
|
end
|
95
114
|
|
115
|
+
# I'm leaving this all here because it's important in understanding the
|
116
|
+
# motivation for the above classes (PVC and StringMethod).
|
117
|
+
# But the Proc stuff below was replaced by PVC above.
|
118
|
+
|
96
119
|
# class Proc
|
97
120
|
# # So let's quick chat about what including Runnable to a proc means.
|
98
121
|
# # It means that it can be chained with pipes.
|
@@ -49,6 +49,8 @@ class Coolline
|
|
49
49
|
# In tests, this reads the first character of buffered input.
|
50
50
|
# In practice, this does not do anything differently than `@input.getch`
|
51
51
|
# C'est la vie.
|
52
|
+
# Notice how I went back to `@input.getch`, since Roger Pack was saying
|
53
|
+
# that `@input.raw { @input.getc }` wasn't working on Windows.
|
52
54
|
def read_char
|
53
55
|
#@input.raw { @input.getc }
|
54
56
|
@input.getch
|
@@ -68,7 +70,14 @@ class Coolline
|
|
68
70
|
#
|
69
71
|
# Also, @history_moved appears to be a useless variable.
|
70
72
|
def readline(prompt = ">> ")
|
71
|
-
|
73
|
+
lines = prompt.split("\n")
|
74
|
+
|
75
|
+
if lines.size == 1
|
76
|
+
@prompt = prompt
|
77
|
+
else
|
78
|
+
puts lines[0..-2]
|
79
|
+
@prompt = lines.last
|
80
|
+
end
|
72
81
|
|
73
82
|
@history.delete_empty
|
74
83
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Kernel
|
2
|
+
def D(path); Chitin::Directory.new path; end
|
3
|
+
def F(path); Chitin::FileObject.new path; end
|
4
|
+
def S(path); Chitin::Symlink.new path; end
|
5
|
+
|
6
|
+
alias_method :d, :D
|
7
|
+
alias_method :f, :F
|
8
|
+
alias_method :s, :S
|
9
|
+
|
10
|
+
# L for Lambda. Creates a proc as a RubyMethod
|
11
|
+
def L(&block)
|
12
|
+
Chitin::StringMethod.new :bottle, &block
|
13
|
+
end
|
14
|
+
|
15
|
+
def P(&block)
|
16
|
+
Chitin::PVC.new :bottle, &block
|
17
|
+
end
|
18
|
+
|
19
|
+
NULLIN = NULLOUT = NULLERR = File.open(File::NULL, 'w+')
|
20
|
+
end
|
21
|
+
|
data/lib/chitin/file.rb
CHANGED
@@ -143,20 +143,3 @@ module Chitin
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
-
module Kernel
|
147
|
-
def D(path); Chitin::Directory.new path; end
|
148
|
-
def F(path); Chitin::FileObject.new path; end
|
149
|
-
def S(path); Chitin::Symlink.new path; end
|
150
|
-
|
151
|
-
alias_method :d, :D
|
152
|
-
alias_method :f, :F
|
153
|
-
alias_method :s, :S
|
154
|
-
|
155
|
-
# L for Lambda. Creates a proc as a RubyMethod
|
156
|
-
def L(&block)
|
157
|
-
Chitin::StringMethod.new :bottle, &block
|
158
|
-
end
|
159
|
-
|
160
|
-
NULLIN = NULLOUT = NULLERR = File.open(File::NULL, 'w+')
|
161
|
-
end
|
162
|
-
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module Chitin
|
4
|
+
class Manifest
|
5
|
+
|
6
|
+
def self.register(hash)
|
7
|
+
@@password_hash = hash
|
8
|
+
end
|
9
|
+
|
10
|
+
# retrieve the manifest entry for the name
|
11
|
+
def self.find(name)
|
12
|
+
manifest_path = File.expand_path '.chitin_manifest'
|
13
|
+
manifest = File.read manifest_path
|
14
|
+
manifest_hmac = manifest_data[0..511]
|
15
|
+
manifest_data = manifest_data[512..-1]
|
16
|
+
|
17
|
+
# verify the authenticity of the file
|
18
|
+
computed_hmac = OpenSSL::HMAC.hexdigest('sha256',
|
19
|
+
@@password_hash,
|
20
|
+
manifest_data)
|
21
|
+
|
22
|
+
unless computed_hmac == manifest_hmac
|
23
|
+
puts "MANIFEST FILE HAS BEEN TAMPERED WITH"
|
24
|
+
return {}
|
25
|
+
end
|
26
|
+
|
27
|
+
@@data ||= {}
|
28
|
+
@@data[manifest_path] ||= YAML.load manifest_data
|
29
|
+
@@data[manifest_path][name]
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
data/lib/chitin/session.rb
CHANGED
@@ -7,17 +7,21 @@ module Chitin
|
|
7
7
|
|
8
8
|
attr_reader :config
|
9
9
|
attr_reader :editor
|
10
|
+
attr_reader :last_elapsed
|
10
11
|
|
11
12
|
def initialize(config=nil)
|
12
13
|
@config = config
|
13
14
|
@out = STDOUT
|
14
15
|
@sandbox = Sandbox.new # give it its own private space to work
|
15
|
-
|
16
|
+
|
17
|
+
# include the config and builtins
|
18
|
+
(class << @sandbox; self; end).send :include, @config
|
16
19
|
|
17
20
|
@editor = Coolline.new do |c|
|
18
21
|
# Remove the default of '-' and add support for strings
|
19
22
|
# starting after parentheses.
|
20
|
-
c.word_boundaries = [' ', "\t", "(", ")", '[', ']'
|
23
|
+
c.word_boundaries = [' ', "\t", "(", ")", '[', ']', '`', '@', '$', '>',
|
24
|
+
'<', '=', ';', '|', '&', '{', '}']
|
21
25
|
c.history_file = File.join ENV['HOME'], '.chitin_history'
|
22
26
|
|
23
27
|
# Make sure we don't kill the shell accidentally when we're trying to
|
@@ -40,9 +44,6 @@ module Chitin
|
|
40
44
|
# if there's a quote, remove it. we'll add it back in later, but it ruins
|
41
45
|
# searching so we need it removed for now.
|
42
46
|
unquoted_line = ['"', '\''].include?(line[0, 1]) ? line[1..-1] : line
|
43
|
-
|
44
|
-
#options = Dir[unquoted_line + '*']
|
45
|
-
#options +=
|
46
47
|
|
47
48
|
Dir[unquoted_line + '*'].map do |w|
|
48
49
|
slash_it = File.directory?(w) and line[-1] != '/' and w[-1] != '/'
|
@@ -65,6 +66,9 @@ module Chitin
|
|
65
66
|
while (val = read)
|
66
67
|
next if val.empty?
|
67
68
|
|
69
|
+
# a little bit of infrastructure for timing purposes
|
70
|
+
timing = Time.now
|
71
|
+
|
68
72
|
begin
|
69
73
|
res = evaluate val
|
70
74
|
display res unless val.lstrip[0, 1] == '#'
|
@@ -75,6 +79,8 @@ module Chitin
|
|
75
79
|
puts "#{e.message} (#{e.class})"
|
76
80
|
e.backtrace[1..-1].each {|l| puts "\t#{l}" }
|
77
81
|
nil
|
82
|
+
ensure
|
83
|
+
@last_elapsed = Time.now - timing
|
78
84
|
end
|
79
85
|
|
80
86
|
end
|
data/lib/chitin/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chitin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
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: 2013-
|
12
|
+
date: 2013-07-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: wirble
|
@@ -85,13 +85,16 @@ files:
|
|
85
85
|
- lib/chitin/commands/pipe.rb
|
86
86
|
- lib/chitin/commands/ruby.rb
|
87
87
|
- lib/chitin/commands/runnable.rb
|
88
|
+
- lib/chitin/core_ext/array.rb
|
88
89
|
- lib/chitin/core_ext/class.rb
|
89
90
|
- lib/chitin/core_ext/coolline.rb
|
90
91
|
- lib/chitin/core_ext/io.rb
|
92
|
+
- lib/chitin/core_ext/kernel.rb
|
91
93
|
- lib/chitin/core_ext/object.rb
|
92
94
|
- lib/chitin/core_ext/string.rb
|
93
95
|
- lib/chitin/core_ext/symbol.rb
|
94
96
|
- lib/chitin/file.rb
|
97
|
+
- lib/chitin/manifests/manifest.rb
|
95
98
|
- lib/chitin/sandbox.rb
|
96
99
|
- lib/chitin/session.rb
|
97
100
|
- lib/chitin/support.rb
|