waxx 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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/LICENSE +201 -0
  4. data/README.md +879 -0
  5. data/bin/waxx +120 -0
  6. data/lib/waxx/app.rb +173 -0
  7. data/lib/waxx/conf.rb +54 -0
  8. data/lib/waxx/console.rb +204 -0
  9. data/lib/waxx/csrf.rb +14 -0
  10. data/lib/waxx/database.rb +80 -0
  11. data/lib/waxx/encrypt.rb +38 -0
  12. data/lib/waxx/error.rb +60 -0
  13. data/lib/waxx/html.rb +33 -0
  14. data/lib/waxx/http.rb +268 -0
  15. data/lib/waxx/init.rb +273 -0
  16. data/lib/waxx/irb.rb +44 -0
  17. data/lib/waxx/irb_env.rb +18 -0
  18. data/lib/waxx/json.rb +23 -0
  19. data/lib/waxx/mongodb.rb +221 -0
  20. data/lib/waxx/mysql2.rb +234 -0
  21. data/lib/waxx/object.rb +115 -0
  22. data/lib/waxx/patch.rb +138 -0
  23. data/lib/waxx/pdf.rb +69 -0
  24. data/lib/waxx/pg.rb +246 -0
  25. data/lib/waxx/process.rb +270 -0
  26. data/lib/waxx/req.rb +116 -0
  27. data/lib/waxx/res.rb +98 -0
  28. data/lib/waxx/server.rb +304 -0
  29. data/lib/waxx/sqlite3.rb +237 -0
  30. data/lib/waxx/supervisor.rb +47 -0
  31. data/lib/waxx/test.rb +162 -0
  32. data/lib/waxx/util.rb +57 -0
  33. data/lib/waxx/version.rb +3 -0
  34. data/lib/waxx/view.rb +389 -0
  35. data/lib/waxx/waxx.rb +73 -0
  36. data/lib/waxx/x.rb +103 -0
  37. data/lib/waxx.rb +50 -0
  38. data/skel/README.md +11 -0
  39. data/skel/app/app/app.rb +39 -0
  40. data/skel/app/app/error/app_error.rb +16 -0
  41. data/skel/app/app/error/dhtml.rb +9 -0
  42. data/skel/app/app/error/html.rb +8 -0
  43. data/skel/app/app/error/json.rb +8 -0
  44. data/skel/app/app/error/pdf.rb +13 -0
  45. data/skel/app/app/log/app_log.rb +13 -0
  46. data/skel/app/app.rb +20 -0
  47. data/skel/app/home/home.rb +16 -0
  48. data/skel/app/home/html.rb +145 -0
  49. data/skel/app/html.rb +192 -0
  50. data/skel/app/usr/email.rb +66 -0
  51. data/skel/app/usr/html.rb +115 -0
  52. data/skel/app/usr/list.rb +51 -0
  53. data/skel/app/usr/password.rb +54 -0
  54. data/skel/app/usr/record.rb +98 -0
  55. data/skel/app/usr/usr.js +67 -0
  56. data/skel/app/usr/usr.rb +277 -0
  57. data/skel/app/waxx/waxx.rb +109 -0
  58. data/skel/bin/README.md +1 -0
  59. data/skel/db/README.md +11 -0
  60. data/skel/db/app/0-init.sql +88 -0
  61. data/skel/lib/README.md +1 -0
  62. data/skel/log/README.md +1 -0
  63. data/skel/opt/dev/config.yaml +1 -0
  64. data/skel/opt/prod/config.yaml +1 -0
  65. data/skel/opt/stage/config.yaml +1 -0
  66. data/skel/opt/test/config.yaml +1 -0
  67. data/skel/private/README.md +1 -0
  68. data/skel/public/lib/site.css +202 -0
  69. data/skel/public/lib/waxx/w.ico +0 -0
  70. data/skel/public/lib/waxx/w.png +0 -0
  71. data/skel/public/lib/waxx/waxx.js +111 -0
  72. data/skel/tmp/pids/README.md +1 -0
  73. data.tar.gz.sig +0 -0
  74. metadata +140 -0
  75. metadata.gz.sig +3 -0
data/lib/waxx/error.rb ADDED
@@ -0,0 +1,60 @@
1
+ # Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
2
+ # Released under the Apache Version 2 License. See LICENSE.txt.
3
+
4
+ module Waxx::Error
5
+ def error(x, status:200, type:nil, title:"An error occurred", message:"", args: [])
6
+ x.res.status = status
7
+ App[:app_error][type.to_sym][:get].call(x, title, message, *args)
8
+ end
9
+
10
+ def fatal(x, e)
11
+ App::AppLog.log(x, cat: "Error", name:"#{x.req.uri}", value: "#{e}\n#{e.backtrace}")
12
+ x.res.status = 503
13
+ er = [
14
+ "ERROR:\n#{e}\n#{e.backtrace.join("\n")}",
15
+ "USR:\n\n#{x.usr.map{|n,v| "#{n}: #{v}"}.join("\n")}",
16
+ "GET:\n#{x.req.get.map{|n,v| "#{n}: #{v}"}.join("\n")}",
17
+ "POST:\n#{req.post.map{|n,v| "#{n}: #{v}"}.join("\n")}",
18
+ "ENV:\n\n#{x.req.env.map{|n,v| "#{n}: #{v}"}.join("\n")}"
19
+ ].join("\n\n")
20
+
21
+ if Waxx['debug']['on_screen']
22
+ x << "<pre>#{er}</pre>"
23
+ else
24
+ get_const(App, x.ext).get(x,
25
+ title: "System Error",
26
+ content: "<h4><span class='glyphicon glyphicon-thumbs-down'></span> Sorry! Something went wrong on our end.</h4>
27
+ <h4><span class='glyphicon glyphicon-thumbs-up'></span> The tech support team has been notified.</h4>
28
+ <p>We will contact you if we need addition information. </p>
29
+ <p>Sorry for the inconvenience.</p>"
30
+ )
31
+ end
32
+ if Waxx['debug']['send_email'] and Waxx['debug']['email']
33
+ to_email = Waxx['debug']['email']
34
+ from_email = Waxx['site']['support_email']
35
+ subject = "[Bug] #{App['site']['name']} #{x.meth}:#{x.uri}"
36
+ body = er
37
+ begin
38
+ # Send email via DB.email table
39
+ App::Email.post(x,{
40
+ to_email: to_email,
41
+ from_email: from_email,
42
+ subject: subject,
43
+ body: body
44
+ })
45
+ rescue => e2
46
+ begin
47
+ # Only send email
48
+ Mail.deliver do
49
+ from from_email
50
+ to to_email
51
+ subject subject
52
+ body body
53
+ end
54
+ rescue => e3
55
+ puts "FATAL ERROR: Could not send bug report email: #{e2}\n#{e2.backtrace} AND #{e3}\n#{e3.backtrace}"
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
data/lib/waxx/html.rb ADDED
@@ -0,0 +1,33 @@
1
+ # Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
2
+ # Released under the Apache Version 2 License. See LICENSE.txt.
3
+
4
+ module Waxx::Html
5
+ extend self
6
+ attr :view
7
+
8
+ def view
9
+ @view ||= name.split("::").slice(1,2).inject(App){|c, n| c.const_get(n)}
10
+ end
11
+
12
+ def f v, *fmt
13
+ v.f *fmt
14
+ end
15
+
16
+ def h v
17
+ begin
18
+ v.h
19
+ rescue
20
+ v.to_s.h
21
+ end
22
+ end
23
+
24
+ def qs v
25
+ Waxx::Http.qs(v)
26
+ end
27
+
28
+ def debug(str, level=3)
29
+ Waxx.debug(str, level)
30
+ end
31
+
32
+ end
33
+
data/lib/waxx/http.rb ADDED
@@ -0,0 +1,268 @@
1
+ # Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
2
+ # Released under the Apache Version 2 License. See LICENSE.txt.
3
+
4
+ module Waxx::Http
5
+ extend self
6
+
7
+ def content_types
8
+ ContentTypes
9
+ end
10
+
11
+ def ctype(t, default="application/octet-stream")
12
+ ContentTypes[t.to_sym] || default
13
+ end
14
+
15
+ def time(t=Time.new.utc)
16
+ t.strftime('%a, %d %b %Y %H:%M:%S UTC')
17
+ end
18
+
19
+ def escape(str)
20
+ str.to_s.gsub(/([^a-zA-Z0-9_.-]+)/) do |m|
21
+ '%' + m.unpack('H2' * m.bytesize).join('%').upcase
22
+ end
23
+ end
24
+ alias qs escape
25
+
26
+ def unescape(str)
27
+ str.to_s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do |m|
28
+ [m.delete('%')].pack('H*')
29
+ end
30
+ end
31
+
32
+ def parse_head(io)
33
+ Waxx.debug("parse_head: #{io.class}", 9)
34
+ env = {}
35
+ head = ""
36
+ while(e = io.gets)
37
+ break if e.strip == ""
38
+ head << e
39
+ n, v = e.split(":", 2)
40
+ env[n] = v.strip
41
+ end
42
+ Waxx.debug "env.size: #{env.size}", 9
43
+ [env, head]
44
+ end
45
+
46
+ def query_string_to_hash(str, base={})
47
+ return base if str.nil? or str.strip == ""
48
+ str.strip.split(/[;&]/).each{|nv|
49
+ n, v = nv.split("=",2).map{|s| unescape(s)}
50
+ if n =~ /\[\]$/
51
+ n = n.sub(/\[\]$/,"")
52
+ base[n] ||= []
53
+ base[n] << v
54
+ else
55
+ base[n] = v
56
+ end
57
+ }
58
+ base
59
+ end
60
+
61
+ def parse_multipart(env, data)
62
+ boundary = env['Content-Type'].match(/boundary=(.*)$/)[1]
63
+ parts = data.split("--"+boundary+"\r\n")
64
+ post = {}
65
+ parts.each{|part|
66
+ next if part.strip == ""
67
+ begin
68
+ head, body = part.split("\r\n\r\n",2)
69
+ headers = Hash[*(head.split("\r\n").map{|hp| hp.split(":",2).map{|i| i.strip}}.flatten)]
70
+ cd = Hash[*("_=#{headers['Content-Disposition']}".split(";").map{|da| da.strip.gsub('"',"").split("=",2)}.flatten)]
71
+ if cd['filename']
72
+ post[cd['name']] = {
73
+ filename: cd['filename'],
74
+ data: body.sub(/\r\n--#{boundary}--\r\n$/,"").sub(/\r\n$/,""),
75
+ content_type: headers['Content-Type'],
76
+ headers: headers
77
+ }
78
+ else
79
+ post[cd['name']] = body.sub(/\r\n--#{boundary}--\r\n$/,"").sub(/\r\n$/,"")
80
+ end
81
+ rescue => e
82
+ Waxx.debug "Error parse_multipart: #{e}"
83
+ post["Error in parse_multipart (uid-#{rand})"] = e
84
+ end
85
+ }
86
+ post
87
+ end
88
+
89
+ def parse_cookie(str)
90
+ Waxx.debug "parse_cookie"
91
+ re = {}
92
+ return re if str.nil? or str == ""
93
+ str.split(/[;,]\s?/).each do |pairs|
94
+ name, values = pairs.split('=',2)
95
+ next unless name and values
96
+ name = unescape(name)
97
+ vals = values.split('&').collect{|v| unescape(v) }
98
+ if re.has_key?(name)
99
+ Waxx.debug "re has key"
100
+ if Array === re[name]
101
+ re[name].push vals
102
+ else
103
+ re[name] = [re[name], vals]
104
+ end
105
+ else
106
+ re[name] = vals
107
+ end
108
+ re[name].flatten!
109
+ end
110
+ re.freeze
111
+ re
112
+ end
113
+
114
+ def parse_data(env, meth, io, head)
115
+ Waxx.debug "parse_data"
116
+ if %w(PUT POST PATCH).include? meth
117
+ data = io.read(env['Content-Length'].to_i)
118
+ Waxx.debug "data.size: #{data.size} #{env['Content-Type']}"
119
+ case env['Content-Type']
120
+ when /x-www-form-urlencoded/
121
+ post = query_string_to_hash(data).freeze
122
+ when /multipart/
123
+ post = parse_multipart(env, data).freeze
124
+ when /json/
125
+ post = (JSON.parse(data)).freeze
126
+ else
127
+ post = data.freeze
128
+ end
129
+ else
130
+ post = {}.freeze
131
+ data = nil
132
+ end
133
+ [post, data]
134
+ end
135
+
136
+ Status = {
137
+ "200"=>"OK",
138
+ "206"=>"Partial Content",
139
+ "300"=>"Multiple Choices",
140
+ "301"=>"Moved Permanently",
141
+ "302"=>"Found",
142
+ "304"=>"Not Modified",
143
+ "400"=>"Bad Request",
144
+ "401"=>"Authorization Required",
145
+ "403"=>"Forbidden",
146
+ "404"=>"Not Found",
147
+ "405"=>"Method Not Allowed",
148
+ "406"=>"Not Acceptable",
149
+ "411"=>"Length Required",
150
+ "412"=>"Precondition Failed",
151
+ "500"=>"Internal Server Error",
152
+ "501"=>"Method Not Implemented",
153
+ "502"=>"Bad Gateway",
154
+ "506"=>"Variant Also Negotiates"
155
+ }
156
+
157
+ ContentTypes = {
158
+ css: "text/css; charset=utf-8",
159
+ csv: "text/csv; charset=utf-8",
160
+ htm: "text/html; charset=utf-8",
161
+ html: "text/html; charset=utf-8",
162
+ jpg: "image/jpeg",
163
+ js: "application/javascript; charset=utf-8",
164
+ json: "application/json; charset=utf-8",
165
+ tab: "text/tab-separated-values; charset=utf-8",
166
+ txt: "text/plain; charset=utf-8",
167
+ xml: "text/xml",
168
+ gif: "image/gif",
169
+ jpeg: "image/jpeg",
170
+ atom: "application/atom+xml",
171
+ rss: "application/rss+xml",
172
+
173
+ mml: "text/mathml",
174
+ jad: "text/vnd.sun.j2me.app-descriptor",
175
+ wml: "text/vnd.wap.wml",
176
+ htc: "text/x-component",
177
+
178
+ png: "image/png",
179
+ tif: "image/tiff",
180
+ tiff: "image/tiff",
181
+ wbmp: "image/vnd.wap.wbmp",
182
+ ico: "image/x-icon",
183
+ jng: "image/x-jng",
184
+ bmp: "image/x-ms-bmp",
185
+ svg: "image/svg+xml",
186
+ svgz: "image/svg+xml",
187
+ webp: "image/webp",
188
+
189
+ woff: "application/font-woff",
190
+ jar: "application/java-archive",
191
+ war: "application/java-archive",
192
+ ear: "application/java-archive",
193
+ hqx: "application/mac-binhex40",
194
+ doc: "application/msword",
195
+ pdf: "application/pdf",
196
+ ps: "application/postscript",
197
+ eps: "application/postscript",
198
+ ai: "application/postscript",
199
+ rtf: "application/rtf",
200
+ m3u8: "application/vnd.apple.mpegurl",
201
+ xls: "application/vnd.ms-excel",
202
+ eot: "application/vnd.ms-fontobject",
203
+ ppt: "application/vnd.ms-powerpoint",
204
+ wmlc: "application/vnd.wap.wmlc",
205
+ kml: "application/vnd.google-earth.kml+xml",
206
+ kmz: "application/vnd.google-earth.kmz",
207
+ cco: "application/x-cocoa",
208
+ jardiff: "application/x-java-archive-diff",
209
+ jnlp: "application/x-java-jnlp-file",
210
+ run: "application/x-makeself",
211
+ pl: "application/x-perl",
212
+ pm: "application/x-perl",
213
+ prc: "application/x-pilot",
214
+ pdb: "application/x-pilot",
215
+ rar: "application/x-rar-compressed",
216
+ rpm: "application/x-redhat-package-manager",
217
+ sea: "application/x-sea",
218
+ swf: "application/x-shockwave-flash",
219
+ sit: "application/x-stuffit",
220
+ tcl: "application/x-tcl",
221
+ tk: "application/x-tcl",
222
+ der: "application/x-x509-ca-cert",
223
+ pem: "application/x-x509-ca-cert",
224
+ crt: "application/x-x509-ca-cert",
225
+ xpi: "application/x-xpinstall",
226
+ xhtml: "application/xhtml+xml",
227
+ xspf: "application/xspf+xml",
228
+ zip: "application/zip",
229
+
230
+ bin: "application/octet-stream",
231
+ exe: "application/octet-stream",
232
+ dll: "application/octet-stream",
233
+ deb: "application/octet-stream",
234
+ dmg: "application/octet-stream",
235
+ iso: "application/octet-stream",
236
+ img: "application/octet-stream",
237
+ msi: "application/octet-stream",
238
+ msp: "application/octet-stream",
239
+ msm: "application/octet-stream",
240
+
241
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
242
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
243
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
244
+
245
+ mid: "audio/midi",
246
+ midi: "audio/midi",
247
+ kar: "audio/midi",
248
+ mp3: "audio/mpeg",
249
+ ogg: "audio/ogg",
250
+ m4a: "audio/x-m4a",
251
+ ra: "audio/x-realaudio",
252
+
253
+ ts: "video/mp2t",
254
+ mp4: "video/mp4",
255
+ mpeg: "video/mpeg",
256
+ mpg: "video/mpeg",
257
+ mov: "video/quicktime",
258
+ webm: "video/webm",
259
+ flv: "video/x-flv",
260
+ m4v: "video/x-m4v",
261
+ mng: "video/x-mng",
262
+ asx: "video/x-ms-asf",
263
+ asf: "video/x-ms-asf",
264
+ wmv: "video/x-ms-wmv",
265
+ avi: "video/x-msvideo",
266
+
267
+ }
268
+ end
data/lib/waxx/init.rb ADDED
@@ -0,0 +1,273 @@
1
+ require 'securerandom'
2
+
3
+ # Trap ^C
4
+ Signal.trap("INT") {
5
+ puts "\n\nInstallation terminated by INT (^C)\n"
6
+ exit
7
+ }
8
+
9
+ # Trap `Kill `
10
+ Signal.trap("TERM") {
11
+ puts "\n\nInstallation terminated by TERM\n"
12
+ exit
13
+ }
14
+
15
+ # Command line init script to create a Waxx app
16
+ module Waxx::Init
17
+ extend self
18
+
19
+ # Defines the default YAML config file
20
+ def default_input(x, opts)
21
+ %(---
22
+ server:
23
+ host: localhost
24
+ port: 7777
25
+ processes: 1
26
+ min_threads: 4
27
+ max_threads: 4
28
+ log_dir: log
29
+ pid_dir: tmp/pids
30
+
31
+ site:
32
+ name: #{`whoami`.chomp.capitalize}'s Website
33
+ support_email: #{`whoami`.chomp}@#{`hostname`.chomp}
34
+ url: http://localhost:7777
35
+
36
+ encryption:
37
+ cipher: AES-256-CBC
38
+ key: #{SecureRandom.base64(32)[0,32]}
39
+ iv: #{SecureRandom.base64(16)[0,16]}
40
+
41
+ cookie:
42
+ user:
43
+ name: wxu
44
+ expires_after_login_mins: 1440
45
+ expires_after_activity_mins: 480
46
+ secure: true
47
+ agent:
48
+ name: wxa
49
+ expires_years: 30
50
+ secure: true
51
+
52
+ debug:
53
+ level: 9
54
+ on_screen: true
55
+ send_email: false
56
+ email: #{`whoami`.chomp}@#{`hostname`.chomp}
57
+ auto_reload_code: true
58
+
59
+ databases:
60
+ app:
61
+
62
+ default:
63
+ app: website
64
+ act: index
65
+ ext: html
66
+
67
+ file:
68
+ serve: true
69
+ path: public
70
+
71
+ init:
72
+ website: true
73
+ html: true
74
+ )
75
+ end
76
+
77
+ # Some nice ASCII Art to get people excited
78
+ def ascii_art
79
+ # http://www.patorjk.com/software/taag/
80
+ %(
81
+ `8.`888b ,8' .8. `8.`8888. ,8' `8.`8888. ,8'
82
+ `8.`888b ,8' .888. `8.`8888. ,8' `8.`8888. ,8'
83
+ `8.`888b ,8' :88888. `8.`8888. ,8' `8.`8888. ,8'
84
+ `8.`888b .b ,8' . `88888. `8.`8888.,8' `8.`8888.,8'
85
+ `8.`888b 88b ,8' .8. `88888. `8.`88888' `8.`88888'
86
+ `8.`888b .`888b,8' .8`8. `88888. .88.`8888. .88.`8888.
87
+ `8.`888b8.`8888' .8' `8. `88888. .8'`8.`8888. .8'`8.`8888.
88
+ `8.`888`8.`88' .8' `8. `88888. .8' `8.`8888. .8' `8.`8888.
89
+ `8.`8' `8,`' .888888888. `88888. .8' `8.`8888. .8' `8.`8888.
90
+ `8.` `8' .8' `8. `88888. .8' `8.`8888. .8' `8.`8888.
91
+
92
+ Version #{Waxx::Version}
93
+ )
94
+ end
95
+
96
+ # Start the init process. Fired when `waxx init folder` is called
97
+ def init(x, opts, input=nil)
98
+ puts ""
99
+ puts ascii_art
100
+ puts ""
101
+ # Set defaults
102
+ input ||= YAML.load(default_input(x, opts))
103
+ make_dir(x, opts/:sub_command)
104
+ # Ask a few questions
105
+ input = ask(x, input)
106
+ puts ""
107
+ puts "Here is your config..."
108
+ puts ""
109
+ puts input.to_yaml
110
+ puts ""
111
+ puts ""
112
+ puts "Does this look right? You can edit this YAML file later in #{opts/:sub_command}/opt/dev/config.yaml."
113
+ print "Install? (y|n) [y]: "
114
+ proceed = $stdin.gets.chomp
115
+ if proceed == '' or (proceed =~ /[yY]/) == 0
116
+ install_waxx(x, input, opts)
117
+ else
118
+ init(x, opts, input)
119
+ end
120
+ end
121
+
122
+ # Make the Waxx::Root / app folder
123
+ def make_dir(x, name)
124
+ puts ""
125
+ if File.exist? name
126
+ if not Dir.empty?(name)
127
+ puts "Error. The directory '#{name}' already exists and is not empty."
128
+ puts "I don't want to destroy anything. Bailing out."
129
+ exit 4
130
+ end
131
+ puts "Installing into existing directory: #{name}"
132
+ Dir.unlink name
133
+ else
134
+ puts "Make directory: #{name}"
135
+ end
136
+ end
137
+
138
+ # Ask questions about the config
139
+ def ask(x, input)
140
+ get_site(x, input)
141
+ get_key_iv(x, input)
142
+ get_db(x, input)
143
+ input
144
+ end
145
+
146
+ # Get config options about the site
147
+ def get_site(x, input)
148
+ puts ""
149
+ puts "Website/App options:"
150
+ print " Name [#{input/:site/:name}]: "
151
+ name = $stdin.gets.chomp
152
+ print " Support Email [#{input/:site/:support_email}]: "
153
+ support_email = $stdin.gets.chomp
154
+ print " Liston on IP/Host [#{input/:server/:host}]: "
155
+ host = $stdin.gets.chomp
156
+ print " Listen on Port [#{input/:server/:port}]: "
157
+ port = $stdin.gets.chomp
158
+ input['site']['name'] = name unless name == ''
159
+ input['site']['support_email'] = support_email unless support_email == ''
160
+ input['server']['host'] = host unless host == ''
161
+ input['server']['port'] = port unless port == ''
162
+ input['site']['url'] = "http://#{input['server']['host']}:#{input['server']['port']}"
163
+ input
164
+ end
165
+
166
+ # Get config options about the db
167
+ def get_db(x, input)
168
+ default_db = "postgresql://#{`whoami`.chomp}@localhost/#{`whoami`.chomp}"
169
+ puts ""
170
+ puts "Enter your database connection string (type://user:pass@host:port/db)"
171
+ puts "Types include: postgresql, mysql2, sqlite3, mongodb"
172
+ puts "You can edit or add more database connections by editing opt/dev/config.yaml"
173
+ puts "Enter 'none' if you do not want to connect to a database now"
174
+ puts "[#{input['databases']['app'] || default_db}] "
175
+ print " db: "
176
+ db = $stdin.gets.chomp
177
+ if db.downcase == "none"
178
+ input['databases'] = {}
179
+ else
180
+ input['databases']['app'] = db == '' ? (input['databases']['app'] || default_db) : db
181
+ puts "Create the standard waxx table? (The waxx table is used for migration management.)"
182
+ puts "The databse must already exist and the user must have create table privileges."
183
+ print " Create waxx table (y|n) [y]:"
184
+ initdb = $stdin.gets.chomp
185
+ initdb = initdb == '' or not (initdb =~ /[Yy]/).nil?
186
+ input['init']['db'] = initdb
187
+ end
188
+ input
189
+ end
190
+
191
+ # Get config options about the encryption
192
+ def get_key_iv(x, input)
193
+ puts ""
194
+ puts "The AES key and initiation vector for encryption."
195
+ puts "The default was generated with SecureRandom.base64()."
196
+ puts "Accept the default or enter 48 (or more) random characters."
197
+ puts "Can not start with an ampersand: &"
198
+ puts "See https://www.grc.com/passwords.htm for inspiration."
199
+ puts "[#{input['encryption']['key']}#{input['encryption']['iv']}] "
200
+ print " Random string: "
201
+ random = $stdin.gets.chomp
202
+ if random.size >= 48
203
+ input['encryption']['key'] = random[0,32]
204
+ input['encryption']['iv'] = random[33,16]
205
+ end
206
+ input
207
+ end
208
+
209
+ # Install Waxx in the target folder. Copy skel and update the config file
210
+ def install_waxx(x, input, opts)
211
+ skel_folder = "#{File.dirname(__FILE__)}/../../skel/"
212
+ install_folder = opts/:sub_command
213
+ puts ""
214
+ puts "Copying files from #{skel_folder} to #{install_folder}"
215
+ FileUtils.cp_r(skel_folder, install_folder, verbose: false)
216
+ if input/:init/:db
217
+ puts ""
218
+ puts "Setup Database"
219
+ create_waxx_table(x, input)
220
+ end
221
+ if not (input/:databases).empty?
222
+ # Require the correct db lib in app/app.rb
223
+ db_libs = {pg: 'pg', postgresql: 'pg', mysql: 'mysql2', mysql2: 'mysql2', sqlite: 'sqlite3', sqlite3: 'sqlite3', mongo: 'mongodb', mongodb: 'mongodb'}
224
+ db_lib = db_libs[(input/:databases/:app).split(":").first.to_sym]
225
+ puts "Requiring lib '#{db_lib}' in app/app.rb"
226
+ app_rb = File.read("#{install_folder}/app/app.rb")
227
+ File.open("#{install_folder}/app/app.rb","w"){|f|
228
+ f.puts app_rb.sub("# require '#{db_lib}'","require '#{db_lib}'")
229
+ }
230
+ end
231
+ puts ""
232
+ puts "Installing dev config"
233
+ input.delete "init"
234
+ File.open("#{install_folder}/opt/dev/config.yaml","w"){|f| f << input.to_yaml}
235
+ puts ""
236
+ puts "Waxx installed successfully."
237
+ puts "cd into #{install_folder} and run `waxx on` to get your waxx on"
238
+ end
239
+
240
+ def create_waxx_table(x, input)
241
+ # Require the db lib
242
+ case (input/:databases/:app).split(":").first.downcase
243
+ when 'postgresql'
244
+ require 'pg'
245
+ when 'mysql2'
246
+ require 'mysql2'
247
+ when 'sqlite3'
248
+ require 'sqlite3'
249
+ end
250
+ create_sql = %(
251
+ CREATE TABLE waxx (
252
+ name character varying(254) NOT NULL PRIMARY KEY,
253
+ value character varying(254) NOT NULL,
254
+ CONSTRAINT waxx_uniq UNIQUE(name)
255
+ )
256
+ )
257
+ insert_sql = %(INSERT INTO waxx (name, value) VALUES ('db.app.migration.last', '0'))
258
+ puts " Connecting to: #{input/:databases/:app}"
259
+ begin
260
+ db = Waxx::Database.connect(input/:databases/:app)
261
+ db.exec(create_sql)
262
+ db.exec(insert_sql)
263
+ puts " Waxx table created successfully."
264
+ rescue => e
265
+ puts %(
266
+ \nERROR: Could not create waxx table. Please create manually:
267
+ \n#{create_sql}
268
+ \n#{insert_sql}
269
+ \nError Detail: #{e}
270
+ )
271
+ end
272
+ end
273
+ end
data/lib/waxx/irb.rb ADDED
@@ -0,0 +1,44 @@
1
+ # Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
2
+ # Released under the Apache Version 2 License. See LICENSE.txt.
3
+
4
+ # Thanks to http://jasonroelofs.com/2009/04/02/embedding-irb-into-your-ruby-application/
5
+
6
+ require 'irb'
7
+
8
+ # Jump into an IRB session with `waxx console`
9
+ module IRB
10
+ ##
11
+ # Start an IRB session for Ruby < 2.4
12
+ def self.start_session_old(binding)
13
+ unless @__initialized
14
+ args = ARGV
15
+ ARGV.replace(ARGV.dup)
16
+ IRB.setup(nil)
17
+ ARGV.replace(args)
18
+ @__initialized = true
19
+ end
20
+
21
+ workspace = WorkSpace.new(binding)
22
+
23
+ irb = Irb.new(workspace)
24
+
25
+ @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
26
+ @CONF[:MAIN_CONTEXT] = irb.context
27
+
28
+ catch(:IRB_EXIT) do
29
+ irb.eval_input
30
+ end
31
+ end
32
+
33
+ ##
34
+ # Start an IRB session
35
+ # `waxx console`
36
+ def self.start_session(context)
37
+ return self.start_session_old(context) if RUBY_VERSION.to_f < 2.4
38
+ IRB.setup(nil)
39
+ workspace = IRB::WorkSpace.new(context)
40
+ irb = IRB::Irb.new(workspace)
41
+ IRB.conf[:MAIN_CONTEXT] = irb.context
42
+ irb.eval_input
43
+ end
44
+ end
@@ -0,0 +1,18 @@
1
+ # Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
2
+ # Released under the Apache Version 2 License. See LICENSE.txt.
3
+
4
+ extend Waxx::Console
5
+
6
+ puts "Welcome to Waxx"
7
+ puts "See waxx.io for more info"
8
+ puts ""
9
+ puts "HTTP Methods with URI: "
10
+ puts " get '/app/env'"
11
+ puts " post '/person/record/1?first_name=Jane;last_name=Lee'"
12
+ puts " (This will set the first & last name of person 1.)"
13
+ puts ""
14
+ puts "Pass 'x' to all data methods: "
15
+ puts " App::Person::Record.get(x, id: 1)"
16
+ puts " App::Person::Record.post(x, {first_name:'Jane', last_name: 'Lee'})"
17
+ puts " App::Person::Record.put(x, 1, {first_name:'Joe', last_name: 'Bar'})"
18
+ puts ""