ki-repo 0.1.1 → 0.1.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.
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- # Copyright 2012 Mikko Apo
3
+ # Copyright 2012-2013 Mikko Apo
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -82,14 +82,6 @@ end
82
82
 
83
83
  class Array
84
84
  include Ki::KiEnumerable
85
-
86
- def Array.wrap(maybe_arr)
87
- if maybe_arr.kind_of?(Array)
88
- maybe_arr
89
- else
90
- [maybe_arr]
91
- end
92
- end
93
85
  end
94
86
 
95
87
  module Enumerable
@@ -109,7 +101,7 @@ class File
109
101
  end
110
102
  end
111
103
  FileUtils.mv(tmp, dest)
112
- rescue Exception => e
104
+ rescue Exception
113
105
  FileUtils.remove_entry_secure(tmp)
114
106
  raise
115
107
  end
@@ -117,17 +109,6 @@ class File
117
109
  end
118
110
 
119
111
  class Hash
120
- original_get = self.instance_method(:[])
121
-
122
- define_method(:[]) do |key, default=nil|
123
- value = original_get.bind(self).call(key)
124
- if value || include?(key)
125
- value
126
- else
127
- default
128
- end
129
- end
130
-
131
112
  def require(key)
132
113
  if !include?(key)
133
114
  raise "'#{key}' is not defined!"
@@ -135,3 +116,59 @@ class Hash
135
116
  self[key]
136
117
  end
137
118
  end
119
+
120
+ class Object
121
+ # if block raises an exception outputs the error message. returns block's exit value or reraises the exception
122
+ def show_errors(&block)
123
+ begin
124
+ block.call
125
+ rescue Exception => e
126
+ puts "Exception '#{e.message}':\n#{e.backtrace.join("\n")}"
127
+ raise
128
+ end
129
+ end
130
+
131
+ # Resolves fully qualified class named including modules: Ki::KiCommand
132
+ def Object.const_get_full(full_class_name)
133
+ class_or_module = self
134
+ full_class_name.split("::").each do |name|
135
+ class_or_module = class_or_module.const_get(name)
136
+ end
137
+ class_or_module
138
+ end
139
+
140
+ def try(retries, retry_sleep, &block)
141
+ c = 0
142
+ start = Time.now
143
+ while c < retries
144
+ begin
145
+ return block.call(c+1)
146
+ rescue Exception => e
147
+ c += 1
148
+ if c < retries
149
+ sleep retry_sleep
150
+ else
151
+ raise e.class, e.message + " (tried #{c} times, waited #{sprintf("%.2f", Time.now - start)} seconds)", e.backtrace
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ class String
159
+ def split_strip(separator=",")
160
+ split(separator).map{|s| s.strip}
161
+ end
162
+ end
163
+
164
+ module ObjectSpace
165
+ def ObjectSpace.all_classes
166
+ arr = []
167
+ each_object do |o|
168
+ if o.kind_of?(Class)
169
+ arr << o
170
+ end
171
+ end
172
+ arr
173
+ end
174
+ end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- # Copyright 2012 Mikko Apo
3
+ # Copyright 2012-2013 Mikko Apo
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
data/lib/util/shell.rb ADDED
@@ -0,0 +1,96 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012-2013 Mikko Apo
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Ki
18
+ # Executes a command and logs using HashLog
19
+ class ShellCommandExecution
20
+ attr_chain :cmd, :require
21
+ attr_chain :exitstatus, :require
22
+ attr_chain :pid, :require
23
+ attr_chain :env, :require
24
+ attr_chain :options, :require
25
+ attr_chain :out, :require
26
+ attr_chain :err, :require
27
+ end
28
+ class DummyHashLog
29
+ def log(*arr, &block)
30
+ block.call
31
+ end
32
+ end
33
+ class HashLogShell
34
+ attr_chain :env
35
+ attr_chain :chdir
36
+ attr_chain :ignore_error
37
+ attr_reader :previous
38
+ attr_chain :root_log, -> { DummyHashLog.new }
39
+
40
+ def spawn(*arr)
41
+ run_env = {}
42
+ run_options = {}
43
+ if (env)
44
+ run_env.merge!(env)
45
+ end
46
+ if (arr.first.kind_of?(Hash))
47
+ run_env.merge!(arr.delete_at(0))
48
+ end
49
+ if (arr.last.kind_of?(Hash))
50
+ run_options.merge!(arr.delete_at(-1))
51
+ end
52
+ if (chdir && !run_options[:chdir])
53
+ run_options[:chdir] = chdir
54
+ end
55
+ rout = wout = rerr = werr = nil
56
+ if (!run_options[:out])
57
+ rout, wout = IO.pipe
58
+ run_options[:out]=wout
59
+ end
60
+ if (!run_options[:err])
61
+ rerr, werr = IO.pipe
62
+ run_options[:err]=werr
63
+ end
64
+ cmd = arr.first
65
+ root_log.log("Shell command '#{cmd}'") do
66
+ pid = system_spawn(run_env, cmd, run_options)
67
+ pid, status = Process.waitpid2(pid)
68
+ exitstatus = status.exitstatus
69
+ @previous = ShellCommandExecution.new.
70
+ cmd(cmd).
71
+ exitstatus(exitstatus).
72
+ pid(pid).
73
+ env(run_env).
74
+ options(run_options)
75
+ if rout
76
+ wout.close
77
+ @previous.out(rout.readlines.join("\n"))
78
+ rout.close
79
+ end
80
+ if rerr
81
+ werr.close
82
+ @previous.err(rerr.readlines.join("\n"))
83
+ rerr.close
84
+ end
85
+ if (exitstatus != 0 && !ignore_error)
86
+ raise "Shell command '#{cmd}' failed with exit code #{exitstatus}"
87
+ end
88
+ @previous
89
+ end
90
+ end
91
+
92
+ def system_spawn(run_env, cmd, run_options)
93
+ Process.spawn(run_env, cmd, run_options)
94
+ end
95
+ end
96
+ end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- # Copyright 2012 Mikko Apo
3
+ # Copyright 2012-2013 Mikko Apo
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -36,12 +36,14 @@ module Ki
36
36
  if block.nil?
37
37
  raise "Option without parser block: " + args.join(", ")
38
38
  end
39
- if args.size == 3
40
- short = args.delete_at(0)
39
+ if args.size == 2 || args.size == 3
40
+ short = args.size == 3 ? args.delete_at(0) : nil
41
41
  long, *params = args.delete_at(0).split(" ")
42
42
  comment = args.delete_at(0)
43
43
  options_for_to_s << {short: short, long: long, comment: comment, params: params, block: block }
44
- options << {opt: short, comment: comment, params: params, block: block }
44
+ if short
45
+ options << {opt: short, comment: comment, params: params, block: block }
46
+ end
45
47
  options << {opt: long, comment: comment, params: params, block: block }
46
48
  else
47
49
  raise "unsupported option configuration size: " + args.join(", ")
data/lib/util/test.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- # Copyright 2012 Mikko Apo
3
+ # Copyright 2012-2013 Mikko Apo
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -318,6 +318,18 @@ module Ki
318
318
  def write(s)
319
319
  self.<< s
320
320
  end
321
+ def flush
322
+
323
+ end
324
+ end
325
+
326
+ def restore_extensions
327
+ original_commands = KiCommand::KiExtensions.dup
328
+ cleaners << lambda do
329
+ KiCommand::KiExtensions.clear
330
+ KiCommand::KiExtensions.register(original_commands)
331
+ end
321
332
  end
333
+
322
334
  end
323
335
  end
@@ -0,0 +1,43 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012-2013 Mikko Apo
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Ki
18
+
19
+ # Tries to launch Rack handlers in default order
20
+ # @see RackCommand
21
+ class DefaultRackHandler
22
+ def run(rack_app, config={})
23
+ detect_rack_handler.run(rack_app, config) do |server|
24
+ @server = server
25
+ end
26
+ end
27
+
28
+ def stop
29
+ @server.stop
30
+ end
31
+
32
+ def detect_rack_handler
33
+ servers = %W(thin mongrel webrick)
34
+ servers.each do |server_name|
35
+ begin
36
+ return Rack::Handler.get(server_name.to_s)
37
+ rescue Exception
38
+ end
39
+ end
40
+ fail "Could not resolve server handlers for any of '#{servers.join(', ')}'."
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,161 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012-2013 Mikko Apo
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'socket'
18
+ require 'net/http'
19
+
20
+ require 'sinatra/base'
21
+ require 'sass'
22
+ require 'coffee-script'
23
+
24
+ module Ki
25
+
26
+ class WebContext
27
+ attr_accessor :ki_home
28
+ attr_accessor :development
29
+ attr_chain :started, -> { Time.now.to_i }
30
+ attr_chain :resource_hash, -> { started.to_s(16) }
31
+ end
32
+
33
+ module KiWebBase
34
+ def web_ctx
35
+ RackCommand.web_ctx
36
+ end
37
+
38
+ def ki_home
39
+ web_ctx.ki_home
40
+ end
41
+
42
+ def res_url(path)
43
+ if path.include?("..")
44
+ raise "File '#{path}' cannot reference parent directories with '..'!"
45
+ end
46
+ "/file/web/#{ RackCommand.web_ctx.resource_hash}/#{self.class.name}:#{path}"
47
+ end
48
+ end
49
+
50
+ # When starting up, looks for /web extension classes loaded from ki-scripts and starts up a web site
51
+ # class MyApp2 < Sinatra::Base
52
+ # get '/' do
53
+ # "MyApp2"
54
+ # end
55
+ # end
56
+ # KiCommand.register("/web/test", MyApp2)
57
+ #
58
+ # @see DefaultRackHandler
59
+ class RackCommand
60
+ @@web_ctx = WebContext.new
61
+
62
+ attr_chain :shell_command, :require
63
+ attr_chain :handler, -> { DefaultRackHandler }
64
+
65
+ def ki_app
66
+ extensions = KiCommand::KiExtensions.by_parent["/web"]
67
+ if extensions.nil? || extensions.empty?
68
+ raise "No /web extensions defined!"
69
+ end
70
+ RackCommand.build_app(extensions.map{|p,c| [p[4..-1], c]})
71
+ end
72
+
73
+ def RackCommand.build_app(path_class_list)
74
+ Rack::Builder.new do
75
+ path_class_list.each do |path, clazz|
76
+ map(path) do
77
+ run(clazz)
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ def RackCommand.find_free_tcp_port
84
+ socket = Socket.new(:INET, :STREAM, 0)
85
+ socket.bind(Addrinfo.tcp("127.0.0.1", 0))
86
+ begin
87
+ socket.local_address.ip_port
88
+ ensure
89
+ socket.close
90
+ end
91
+ end
92
+
93
+ def RackCommand.wait_until_url_responds(url, &block)
94
+ try(20, 0.1) do
95
+ response = Net::HTTP.get_response(URI(url))
96
+ if block
97
+ block.call(response)
98
+ else
99
+ if (code = response.code) == "200"
100
+ return response
101
+ else
102
+ raise "Response code from #{url} was #{code}"
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ def start_server
109
+ @server = handler.new
110
+ [:INT, :TERM].each { |sig| trap(sig) { stop_server } }
111
+ @server.run(ki_app, :Port => (@port || 8290))
112
+ end
113
+
114
+ def stop_server
115
+ @server.stop
116
+ end
117
+
118
+ def execute(ctx, args)
119
+ RackCommand.web_ctx.ki_home=ctx.ki_home
120
+ @port = nil
121
+ opts.parse(args)
122
+ start_server
123
+ end
124
+
125
+ def opts
126
+ OptionParser.new do |opts|
127
+ opts.banner = ""
128
+ opts.on("--handler HANDLER", "Use specified Rack Handler") do |v|
129
+ handler(Object.const_get_full(v))
130
+ end
131
+ opts.on("--development", "Development mode, resource urls are reloaded") do |v|
132
+ RackCommand.web_ctx.development=true
133
+ end
134
+ opts.on("-p", "--port PORT", "Use specified port") do |v|
135
+ @port = Integer(v)
136
+ end
137
+ end
138
+ end
139
+
140
+ def self.web_ctx
141
+ @@web_ctx
142
+ end
143
+
144
+ attr_chain :summary, -> { "Starts Ki web server and uses code from Ki packages" }
145
+
146
+ def help
147
+ <<EOF
148
+ ki-repo has a built in web server.
149
+
150
+ ### Usage
151
+
152
+ #{shell_command} - Starts Ki web server
153
+
154
+ ### Parameters
155
+ #{opts}
156
+ EOF
157
+ end
158
+ end
159
+
160
+ KiCommand.register_cmd("web", RackCommand)
161
+ end