strobe 0.1.4 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +41 -0
- data/README.md +0 -0
- data/lib/strobe/cli.rb +14 -16
- data/lib/strobe/cli/input.rb +125 -0
- data/lib/strobe/cli/main.rb +43 -11
- data/lib/strobe/cli/settings.rb +48 -10
- data/lib/strobe/cli/table.rb +9 -4
- data/lib/strobe/collection.rb +5 -1
- data/lib/strobe/connection.rb +20 -24
- data/lib/strobe/middleware/proxy.rb +44 -6
- data/lib/strobe/resource/base.rb +9 -2
- data/lib/strobe/resource/collection.rb +9 -1
- data/lib/strobe/resources/application.rb +26 -26
- metadata +16 -45
data/CHANGELOG.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
## 0.1.6 (March, 23rd, 2011)
|
2
|
+
|
3
|
+
Bugfixes:
|
4
|
+
|
5
|
+
- Fix `strobe open` so that it actually opens stuff.
|
6
|
+
|
7
|
+
## 0.1.5 - yanked (March, 22nd, 2011)
|
8
|
+
|
9
|
+
Features:
|
10
|
+
|
11
|
+
- `strobe open` will open the application that was just deployed
|
12
|
+
- Pass the -r flag to sc-build
|
13
|
+
- The CLI tool will use a default value if none is provided when
|
14
|
+
requesting for input.
|
15
|
+
- You may now specify custom 404 pages by providing a 404.html page
|
16
|
+
at the root of the project.
|
17
|
+
- Add the ability to delete arbitrary applications by passing
|
18
|
+
--application-id=X to `strobe delete`.
|
19
|
+
- `strobe delete` when not in an application root and no application
|
20
|
+
is specified will become interactive.
|
21
|
+
- Speed up `strobe deploy` in certain cases.
|
22
|
+
- `strobe applications` will show the local path to the application if
|
23
|
+
it is known.
|
24
|
+
|
25
|
+
Bugfixes:
|
26
|
+
|
27
|
+
- `strobe set` without any options will no longer set the
|
28
|
+
application URL to a random value.
|
29
|
+
- Pressing CTRL-C when the strobe CLI tool is requesting input
|
30
|
+
will now exit.
|
31
|
+
- Fix redirects in the `strobe preview` proxy.
|
32
|
+
|
33
|
+
## 0.1.4 (January 11th, 2011)
|
34
|
+
|
35
|
+
Features:
|
36
|
+
|
37
|
+
- Deploy applications to Strobe Platform w/ `strobe deploy`
|
38
|
+
- Basic account management
|
39
|
+
- Basic user management
|
40
|
+
- Basic application management
|
41
|
+
- `strobe preview` provides the proxy
|
data/README.md
ADDED
File without changes
|
data/lib/strobe/cli.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'pathname'
|
3
3
|
require 'fileutils'
|
4
|
-
require '
|
4
|
+
require 'launchy'
|
5
5
|
|
6
6
|
module Strobe
|
7
7
|
class CLI < Thor
|
@@ -12,6 +12,7 @@ module Strobe
|
|
12
12
|
autoload :Table, 'strobe/cli/table'
|
13
13
|
autoload :Ticker, 'strobe/cli/ticker'
|
14
14
|
autoload :Users, 'strobe/cli/users'
|
15
|
+
autoload :Input, 'strobe/cli/input'
|
15
16
|
|
16
17
|
include Resources
|
17
18
|
|
@@ -26,6 +27,8 @@ module Strobe
|
|
26
27
|
rescue Strobe::StrobeError => e
|
27
28
|
raise if $ARGV.include?('--backtrace')
|
28
29
|
abort "[ERROR] #{e.message}"
|
30
|
+
rescue Interrupt
|
31
|
+
abort "\nQuitting..."
|
29
32
|
end
|
30
33
|
|
31
34
|
def self.action(name, *args, &blk)
|
@@ -57,7 +60,7 @@ module Strobe
|
|
57
60
|
super
|
58
61
|
|
59
62
|
@resource = nil
|
60
|
-
@
|
63
|
+
@input = Input.new
|
61
64
|
|
62
65
|
# State
|
63
66
|
@in_group = false
|
@@ -72,7 +75,11 @@ module Strobe
|
|
72
75
|
options[:path] || Dir.pwd
|
73
76
|
end
|
74
77
|
|
75
|
-
def config
|
78
|
+
def config(app = nil)
|
79
|
+
if app
|
80
|
+
@config = settings.configs.find { |c| c[:application_id] = app[:id] }
|
81
|
+
end
|
82
|
+
|
76
83
|
@config ||= Settings.application(path)
|
77
84
|
end
|
78
85
|
|
@@ -130,32 +137,23 @@ module Strobe
|
|
130
137
|
|
131
138
|
def agree(msg, *args)
|
132
139
|
return true if options[:yes]
|
133
|
-
@
|
134
|
-
next unless STDIN.tty? # For testing
|
135
|
-
q.readline = true
|
136
|
-
end
|
140
|
+
@input.agree(msg, *args)
|
137
141
|
end
|
138
142
|
|
139
143
|
def ask(key, options = {})
|
140
144
|
input key, options do |msg|
|
141
|
-
resp = @
|
142
|
-
next unless STDIN.tty? # For testing
|
143
|
-
q.readline = true
|
144
|
-
end
|
145
|
+
resp = @input.ask msg
|
145
146
|
end
|
146
147
|
end
|
147
148
|
|
148
149
|
def password(key, options = {})
|
149
150
|
input key, options do |msg|
|
150
|
-
@
|
151
|
-
next unless STDIN.tty? # For testing
|
152
|
-
q.echo = '*'
|
153
|
-
end
|
151
|
+
@input.ask_for_password msg
|
154
152
|
end
|
155
153
|
end
|
156
154
|
|
157
155
|
def choose
|
158
|
-
@
|
156
|
+
@input.choose do |menu|
|
159
157
|
yield menu
|
160
158
|
end
|
161
159
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Strobe
|
2
|
+
class CLI::Input
|
3
|
+
|
4
|
+
class Menu
|
5
|
+
class NoSuchOptionError < StandardError; end
|
6
|
+
|
7
|
+
attr_reader :choices, :actions, :input
|
8
|
+
|
9
|
+
def initialize(input)
|
10
|
+
@input = input
|
11
|
+
@choices = []
|
12
|
+
@actions = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def choice(name, &block)
|
16
|
+
choices << name
|
17
|
+
actions[name] = block
|
18
|
+
end
|
19
|
+
|
20
|
+
def display
|
21
|
+
choices.each_with_index do |choice, i|
|
22
|
+
input.puts "#{i+1}. #{choice}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def ask
|
27
|
+
display
|
28
|
+
|
29
|
+
begin
|
30
|
+
input.print "? "
|
31
|
+
|
32
|
+
option = input.gets.strip.to_i
|
33
|
+
if option < 1 || option > choices.length
|
34
|
+
input.puts "Please enter a number between 1 and #{choices.length}"
|
35
|
+
raise NoSuchOptionError
|
36
|
+
end
|
37
|
+
|
38
|
+
actions[choices[option - 1]].call
|
39
|
+
rescue NoSuchOptionError
|
40
|
+
retry
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_reader :stdin, :stdout
|
46
|
+
|
47
|
+
def initialize(stdin = STDIN, stdout = STDOUT)
|
48
|
+
@stdin, @stdout = stdin, stdout
|
49
|
+
end
|
50
|
+
|
51
|
+
def ask(msg = nil)
|
52
|
+
print msg if msg
|
53
|
+
gets.strip
|
54
|
+
end
|
55
|
+
|
56
|
+
def agree(msg = nil)
|
57
|
+
print msg if msg
|
58
|
+
c = gets.strip.downcase
|
59
|
+
c == "y" || c.strip.blank?
|
60
|
+
end
|
61
|
+
|
62
|
+
def choose(&block)
|
63
|
+
m = Menu.new(self)
|
64
|
+
yield m
|
65
|
+
m.ask
|
66
|
+
end
|
67
|
+
|
68
|
+
def ask_for_password(msg = nil)
|
69
|
+
print msg if msg
|
70
|
+
running_on_windows? ? ask_for_password_on_windows : ask_for_password_on_others
|
71
|
+
end
|
72
|
+
|
73
|
+
def puts(*args)
|
74
|
+
stdout.puts(*args)
|
75
|
+
end
|
76
|
+
|
77
|
+
def print(*args)
|
78
|
+
stdout.print(*args)
|
79
|
+
end
|
80
|
+
|
81
|
+
def gets(*args)
|
82
|
+
stdin.gets(*args)
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
def running_on_windows?
|
87
|
+
RUBY_PLATFORM =~ /mswin32|mingw32/
|
88
|
+
end
|
89
|
+
|
90
|
+
def echo_off
|
91
|
+
system "stty -echo"
|
92
|
+
end
|
93
|
+
|
94
|
+
def echo_on
|
95
|
+
system "stty echo"
|
96
|
+
end
|
97
|
+
|
98
|
+
def ask_for_password_on_windows
|
99
|
+
require "Win32API"
|
100
|
+
char = nil
|
101
|
+
password = ''
|
102
|
+
|
103
|
+
while char = Win32API.new("crtdll", "_getch", [ ], "L").Call do
|
104
|
+
break if char == 10 || char == 13 # received carriage return or newline
|
105
|
+
if char == 127 || char == 8 # backspace and delete
|
106
|
+
password.slice!(-1, 1)
|
107
|
+
else
|
108
|
+
# windows might throw a -1 at us so make sure to handle RangeError
|
109
|
+
(password << char.chr) rescue RangeError
|
110
|
+
end
|
111
|
+
end
|
112
|
+
puts
|
113
|
+
return password
|
114
|
+
end
|
115
|
+
|
116
|
+
def ask_for_password_on_others
|
117
|
+
echo_off if stdin.tty?
|
118
|
+
password = ask
|
119
|
+
puts if stdin.tty?
|
120
|
+
password
|
121
|
+
ensure
|
122
|
+
echo_on if stdin.tty?
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/lib/strobe/cli/main.rb
CHANGED
@@ -16,6 +16,13 @@ module Strobe
|
|
16
16
|
CLI::Users.start(argv)
|
17
17
|
end
|
18
18
|
|
19
|
+
action "open", "opens application in browser" do
|
20
|
+
resource get_application
|
21
|
+
url = resource['url']
|
22
|
+
|
23
|
+
Launchy.open("http://#{url}")
|
24
|
+
end
|
25
|
+
|
19
26
|
action "signup", "signup for a new Strobe account" do
|
20
27
|
resource Signup.new :account => { :name => 'default' }
|
21
28
|
|
@@ -71,12 +78,18 @@ module Strobe
|
|
71
78
|
method_option "staging", :type => :boolean, :banner => "deploy to a staging environment"
|
72
79
|
method_option "sc-build", :type => :boolean, :banner => "run `sc-build -c` before deploying"
|
73
80
|
method_option "no-sc-build", :type => :boolean, :banner => "skip the `sc-build -c` step"
|
81
|
+
method_option "url", :banner => "set application's url"
|
74
82
|
action "deploy", "deploy your application to Strobe" do
|
75
83
|
ensure_computer_is_registered
|
76
84
|
|
77
85
|
if application_id = config[:application_id]
|
78
86
|
resource Application.get! application_id, :lazy => true
|
79
87
|
|
88
|
+
if options[:url]
|
89
|
+
resource[:url] = options[:url]
|
90
|
+
save {}
|
91
|
+
end
|
92
|
+
|
80
93
|
host = resource[:url]
|
81
94
|
host = "staging.#{host}" if options[:staging]
|
82
95
|
|
@@ -85,7 +98,7 @@ module Strobe
|
|
85
98
|
exit
|
86
99
|
end
|
87
100
|
else
|
88
|
-
resource Account.first.applications.new
|
101
|
+
resource Account.first.applications.new(:url => options[:url])
|
89
102
|
end
|
90
103
|
|
91
104
|
resource[:path] = determine_application_root
|
@@ -97,13 +110,15 @@ module Strobe
|
|
97
110
|
|
98
111
|
save do
|
99
112
|
config[:application_id] ||= resource[:id]
|
113
|
+
settings.register_app_path(config.filename)
|
100
114
|
end
|
101
115
|
end
|
102
116
|
|
103
117
|
run_sc_build
|
104
118
|
|
105
119
|
host = resource.deploy! :environment => options[:staging] && 'staging',
|
106
|
-
:callback => CLI::DeployProgress.new
|
120
|
+
:callback => CLI::DeployProgress.new,
|
121
|
+
:sproutcore => is_sproutcore?
|
107
122
|
|
108
123
|
say "The application has successfully been deployed and is available at #{host}"
|
109
124
|
end
|
@@ -118,16 +133,23 @@ module Strobe
|
|
118
133
|
application_path_option
|
119
134
|
action "set", "update the settings for the application" do
|
120
135
|
resource get_application
|
121
|
-
resource['url'] = options['url']
|
122
136
|
|
123
|
-
|
124
|
-
say "
|
137
|
+
if options['url'].blank?
|
138
|
+
say "[ERROR] You need to specify what to set"
|
139
|
+
else
|
140
|
+
resource['url'] = options['url']
|
141
|
+
|
142
|
+
save do
|
143
|
+
say "The application is now running at #{resource[:url]}"
|
144
|
+
end
|
125
145
|
end
|
126
146
|
end
|
127
147
|
|
128
148
|
application_path_option
|
149
|
+
method_option "application-id", :type => :numeric, :banner => "Delete application with given id"
|
129
150
|
action "delete", "delete a specific application" do
|
130
|
-
|
151
|
+
id = options['application-id'] || config[:application_id]
|
152
|
+
resource(id ? Application.get!(id) : pick_application)
|
131
153
|
|
132
154
|
say "Deleting application '#{resource[:name]}'"
|
133
155
|
|
@@ -137,7 +159,7 @@ module Strobe
|
|
137
159
|
end
|
138
160
|
|
139
161
|
delete do
|
140
|
-
config.delete
|
162
|
+
config(resource).delete
|
141
163
|
say "The application has been deleted"
|
142
164
|
end
|
143
165
|
end
|
@@ -156,6 +178,7 @@ module Strobe
|
|
156
178
|
application = options['application-id'] ? Application.get!(options['application-id']) : pick_application
|
157
179
|
|
158
180
|
config[:application_id] = application[:id]
|
181
|
+
settings.register_app_path(config.filename)
|
159
182
|
|
160
183
|
say "You can now deploy to #{application[:name]} (http://#{application[:url]})"
|
161
184
|
end
|
@@ -174,14 +197,17 @@ module Strobe
|
|
174
197
|
# then just skip it
|
175
198
|
return if options["no-sc-build"]
|
176
199
|
|
200
|
+
apps = Dir['apps/*'].map{|d| d.split('/')[1] }
|
201
|
+
cmd = "sc-build -cr #{apps.join(' ')}".strip
|
202
|
+
|
177
203
|
# If the user doesn't ask either way, confirm first
|
178
204
|
unless options["sc-build"]
|
179
205
|
say "This appears to be a SproutCore application."
|
180
|
-
return unless agree "Run
|
206
|
+
return unless agree "Run `#{cmd}`? [Yn] "
|
181
207
|
end
|
182
208
|
|
183
|
-
unless CLI::Ticker.tick("Running `
|
184
|
-
error! "Something went wrong while running `
|
209
|
+
unless CLI::Ticker.tick("Running `#{cmd}`", 2) { system cmd }
|
210
|
+
error! "Something went wrong while running `#{cmd}`"
|
185
211
|
end
|
186
212
|
end
|
187
213
|
|
@@ -205,6 +231,12 @@ module Strobe
|
|
205
231
|
t.column :id
|
206
232
|
t.column :name
|
207
233
|
t.column :url
|
234
|
+
t.column :path do |app|
|
235
|
+
config = settings.configs.find do |c|
|
236
|
+
c[:application_id] == app[:id]
|
237
|
+
end
|
238
|
+
config.application_path if config
|
239
|
+
end
|
208
240
|
end
|
209
241
|
end
|
210
242
|
|
@@ -240,7 +272,7 @@ module Strobe
|
|
240
272
|
end
|
241
273
|
|
242
274
|
def get_application(opts = {})
|
243
|
-
unless id = config[:application_id]
|
275
|
+
unless id = opts.delete(:application_id) || config[:application_id]
|
244
276
|
error "No application found. Are you currently in the correct directory?"
|
245
277
|
exit 1
|
246
278
|
end
|
data/lib/strobe/cli/settings.rb
CHANGED
@@ -16,8 +16,10 @@ module Strobe
|
|
16
16
|
new application_config_file(root)
|
17
17
|
end
|
18
18
|
|
19
|
+
attr_reader :filename
|
20
|
+
|
19
21
|
def initialize(filename = self.class.global_config_file)
|
20
|
-
@filename = filename
|
22
|
+
@filename = Pathname.new(filename)
|
21
23
|
|
22
24
|
if @filename.exist?
|
23
25
|
@hash = YAML.load_file(@filename)
|
@@ -26,26 +28,24 @@ module Strobe
|
|
26
28
|
@hash = {} unless Hash === @hash
|
27
29
|
end
|
28
30
|
|
31
|
+
def application_path
|
32
|
+
filename.sub %r[/.strobe/config(\.[a-z]+)?$]i, ''
|
33
|
+
end
|
34
|
+
|
29
35
|
def [](k)
|
30
36
|
ENV[key(k)] || @hash[key(k)]
|
31
37
|
end
|
32
38
|
|
33
39
|
def []=(k, val)
|
34
40
|
@hash[key(k)] = val
|
35
|
-
|
36
|
-
# Persist the setting
|
37
|
-
FileUtils.mkdir_p(@filename.dirname)
|
38
|
-
File.open(@filename, "wb") do |file|
|
39
|
-
file.puts @hash.to_yaml
|
40
|
-
end
|
41
|
-
|
41
|
+
persist!
|
42
42
|
val
|
43
43
|
end
|
44
44
|
|
45
45
|
def connection
|
46
46
|
return @connection if @connection
|
47
|
-
|
48
|
-
@connection = Connection.new(host)
|
47
|
+
url = self[:url] || "http://api.strobeapp.com/"
|
48
|
+
@connection = Connection.new(url, 'host' => self[:host])
|
49
49
|
end
|
50
50
|
|
51
51
|
def connect!
|
@@ -63,10 +63,48 @@ module Strobe
|
|
63
63
|
FileUtils.rm_f(@filename)
|
64
64
|
end
|
65
65
|
|
66
|
+
def configs
|
67
|
+
@configs ||= begin
|
68
|
+
self[:applications] ||= []
|
69
|
+
self[:applications].map do |path|
|
70
|
+
next unless File.file?(path)
|
71
|
+
self.class.new(path)
|
72
|
+
end.compact
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def register_app_path(path)
|
77
|
+
self[:applications] ||= []
|
78
|
+
self[:applications] |= [File.expand_path(path.to_s)]
|
79
|
+
self[:applications] = self[:applications].select do |path|
|
80
|
+
File.file?(path)
|
81
|
+
end
|
82
|
+
|
83
|
+
persist!
|
84
|
+
end
|
85
|
+
|
86
|
+
def unregister_app_path(path)
|
87
|
+
self[:applications] ||= []
|
88
|
+
self[:applications].delete File.expand_path(path.to_s)
|
89
|
+
self[:applications] = self[:applications].select do |path|
|
90
|
+
File.file?(path)
|
91
|
+
end
|
92
|
+
|
93
|
+
persist!
|
94
|
+
end
|
95
|
+
|
66
96
|
private
|
67
97
|
|
68
98
|
def key(key)
|
69
99
|
"STROBE_#{key}".upcase
|
70
100
|
end
|
101
|
+
|
102
|
+
def persist!
|
103
|
+
# Persist the setting
|
104
|
+
FileUtils.mkdir_p(@filename.dirname)
|
105
|
+
File.open(@filename, "wb") do |file|
|
106
|
+
file.puts @hash.to_yaml
|
107
|
+
end
|
108
|
+
end
|
71
109
|
end
|
72
110
|
end
|
data/lib/strobe/cli/table.rb
CHANGED
@@ -13,14 +13,19 @@ module Strobe
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
def column(key)
|
17
|
-
@columns << { :key => key, :max => 0 }
|
16
|
+
def column(key, opts = {}, &blk)
|
17
|
+
@columns << { :key => key, :max => 0, :blk => blk }.merge(opts)
|
18
18
|
end
|
19
19
|
|
20
20
|
def to_s
|
21
21
|
@collection.each do |obj|
|
22
22
|
@computed << @columns.map do |col|
|
23
|
-
|
23
|
+
if col[:blk]
|
24
|
+
cell = col[:blk].call(obj)
|
25
|
+
elsif col[:key] != Index
|
26
|
+
cell = obj[ col[:key] ]
|
27
|
+
end
|
28
|
+
|
24
29
|
cell = cell.to_s
|
25
30
|
col[:max] = [ cell.length, col[:max] ].max
|
26
31
|
cell
|
@@ -34,7 +39,7 @@ module Strobe
|
|
34
39
|
str = ""
|
35
40
|
|
36
41
|
@columns.each do |col|
|
37
|
-
cell = col[:key].to_s.upcase unless col[:key] == Index
|
42
|
+
cell = (col[:header] || col[:key]).to_s.upcase unless col[:key] == Index
|
38
43
|
str << cell_to_s(col, cell)
|
39
44
|
end
|
40
45
|
|
data/lib/strobe/collection.rb
CHANGED
@@ -8,13 +8,17 @@ module Strobe
|
|
8
8
|
@klass, @params = klass, params
|
9
9
|
end
|
10
10
|
|
11
|
+
def where(params)
|
12
|
+
Strobe::Collection.new(klass, params)
|
13
|
+
end
|
14
|
+
|
11
15
|
def to_a
|
12
16
|
@to_a ||= begin
|
13
17
|
resp = Strobe.connection.get klass.resource_uri, params
|
14
18
|
resp.validate!
|
15
19
|
|
16
20
|
if resp.status == 200
|
17
|
-
resp.body[klass.
|
21
|
+
resp.body[klass.pluralized_root].map do |hash|
|
18
22
|
klass.new(hash)
|
19
23
|
end
|
20
24
|
else
|
data/lib/strobe/connection.rb
CHANGED
@@ -3,12 +3,19 @@ require 'net/http'
|
|
3
3
|
|
4
4
|
module Strobe
|
5
5
|
class Connection
|
6
|
-
|
6
|
+
def self.host_and_port(uri)
|
7
|
+
uri = "http://#{uri}" unless uri =~ %r[^https?://]
|
8
|
+
uri = URI(uri)
|
9
|
+
[ uri.host, uri.port ]
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :host, :port
|
7
13
|
|
8
|
-
def initialize(url)
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@
|
14
|
+
def initialize(url, headers = {})
|
15
|
+
@host, @port = self.class.host_and_port(url)
|
16
|
+
@headers = headers
|
17
|
+
@user = nil
|
18
|
+
@password = nil
|
12
19
|
end
|
13
20
|
|
14
21
|
def authenticate_with_token(token)
|
@@ -98,7 +105,13 @@ module Strobe
|
|
98
105
|
|
99
106
|
def request(method, path, body = nil, headers = {})
|
100
107
|
headers.keys.each do |key|
|
101
|
-
headers[key.downcase] = headers.delete(key)
|
108
|
+
headers[key.to_s.downcase] = headers.delete(key)
|
109
|
+
end
|
110
|
+
|
111
|
+
# add connection-global headers, which will be
|
112
|
+
# overwritten by request-specific headers
|
113
|
+
@headers.each do |k, v|
|
114
|
+
headers[k.to_s.downcase] ||= v if v
|
102
115
|
end
|
103
116
|
|
104
117
|
headers['authorization'] ||= authorization_header
|
@@ -126,7 +139,7 @@ module Strobe
|
|
126
139
|
private
|
127
140
|
|
128
141
|
def build_http
|
129
|
-
http = Net::HTTP.new
|
142
|
+
http = Net::HTTP.new host, port || 80
|
130
143
|
http.read_timeout = 60
|
131
144
|
http.open_timeout = 10
|
132
145
|
http
|
@@ -142,22 +155,5 @@ module Strobe
|
|
142
155
|
def authorize?
|
143
156
|
@user
|
144
157
|
end
|
145
|
-
|
146
|
-
def json_connection
|
147
|
-
@json_connection ||= Faraday::Connection.new(:url => @url) do |b|
|
148
|
-
b.use Faraday::Request::ActiveSupportJson
|
149
|
-
b.use Faraday::Adapter::NetHttp
|
150
|
-
b.use Faraday::Response::ActiveSupportJson
|
151
|
-
b.headers['authorization'] = authorization_header if authorize?
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def reg_connection
|
156
|
-
@reg_connection ||= Faraday::Connection.new(:url => @url) do |b|
|
157
|
-
b.use Faraday::Adapter::NetHttp
|
158
|
-
b.use Faraday::Response::ActiveSupportJson
|
159
|
-
b.headers['authorization'] = authorization_header if authorize?
|
160
|
-
end
|
161
|
-
end
|
162
158
|
end
|
163
159
|
end
|
@@ -7,8 +7,9 @@ module Strobe
|
|
7
7
|
# A wrapper around the Net/HTTP response body
|
8
8
|
# that allows rack to stream the result down
|
9
9
|
class Body
|
10
|
-
def initialize(queue)
|
10
|
+
def initialize(queue, options = {})
|
11
11
|
@queue = queue
|
12
|
+
@options = options
|
12
13
|
end
|
13
14
|
|
14
15
|
def each
|
@@ -16,9 +17,24 @@ module Strobe
|
|
16
17
|
if Exception === chunk
|
17
18
|
raise chunk
|
18
19
|
else
|
19
|
-
yield chunk
|
20
|
+
yield prepare_chunk(chunk)
|
20
21
|
end
|
21
22
|
end
|
23
|
+
|
24
|
+
yield "0\r\n\r\n" if chunked?
|
25
|
+
end
|
26
|
+
|
27
|
+
def prepare_chunk(chunk)
|
28
|
+
if chunked?
|
29
|
+
size = chunk.respond_to?(:bytesize) ? chunk.bytesize : chunk.length
|
30
|
+
"#{size.to_s(16)}\r\n#{chunk}\r\n"
|
31
|
+
else
|
32
|
+
chunk
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def chunked?
|
37
|
+
@options[:chunked]
|
22
38
|
end
|
23
39
|
end
|
24
40
|
|
@@ -26,18 +42,34 @@ module Strobe
|
|
26
42
|
@app = app
|
27
43
|
end
|
28
44
|
|
45
|
+
def redirect?(status)
|
46
|
+
status >= 300 && status < 400
|
47
|
+
end
|
48
|
+
|
29
49
|
def call(env)
|
30
50
|
if env['PATH_INFO'] =~ proxy_path
|
31
51
|
host, port = $1.split(':')
|
52
|
+
path = $2 || '/'
|
53
|
+
|
54
|
+
running = true
|
55
|
+
while running
|
56
|
+
queue = run_request(env, host, ( port || 80 ).to_i, path)
|
32
57
|
|
33
|
-
|
58
|
+
msg = queue.pop
|
59
|
+
status = msg[0].to_i
|
34
60
|
|
35
|
-
|
61
|
+
if redirect?(status) && location = msg[1]['location']
|
62
|
+
uri = URI.parse(location)
|
63
|
+
host, port, path = uri.host, uri.port, uri.path
|
64
|
+
else
|
65
|
+
running = false
|
66
|
+
end
|
67
|
+
end
|
36
68
|
|
37
69
|
if Exception === msg
|
38
70
|
raise msg
|
39
71
|
else
|
40
|
-
[ msg[0], msg[1], Body.new(queue) ]
|
72
|
+
[ msg[0], msg[1], Body.new(queue, :chunked => chunked?(msg[1])) ]
|
41
73
|
end
|
42
74
|
else
|
43
75
|
@app.call(env)
|
@@ -46,11 +78,15 @@ module Strobe
|
|
46
78
|
|
47
79
|
private
|
48
80
|
|
81
|
+
def chunked?(headers)
|
82
|
+
headers["transfer-encoding"] == "chunked"
|
83
|
+
end
|
84
|
+
|
49
85
|
def proxy_path
|
50
86
|
%r[/_strobe/proxy/([^/]+)(/.*)?$]
|
51
87
|
end
|
52
88
|
|
53
|
-
KEEP = [ 'CONTENT_LENGTH', 'CONTENT_TYPE' ]
|
89
|
+
KEEP = [ 'CONTENT_LENGTH', 'CONTENT_TYPE', 'Connection' ]
|
54
90
|
|
55
91
|
def run_request(env, host, port, path)
|
56
92
|
queue = Queue.new
|
@@ -59,6 +95,8 @@ module Strobe
|
|
59
95
|
body = env['rack.input']
|
60
96
|
end
|
61
97
|
|
98
|
+
env["Connection"] = "keep-alive"
|
99
|
+
|
62
100
|
unless env['QUERY_STRING'].blank?
|
63
101
|
path += "?#{env['QUERY_STRING']}"
|
64
102
|
end
|
data/lib/strobe/resource/base.rb
CHANGED
@@ -65,6 +65,12 @@ module Strobe
|
|
65
65
|
def uri_prefix
|
66
66
|
@uri_prefix ||= "/#{resource_name}"
|
67
67
|
end
|
68
|
+
|
69
|
+
def root(root = nil)
|
70
|
+
@root ||= singular_resource_name
|
71
|
+
@root = root if root
|
72
|
+
@root
|
73
|
+
end
|
68
74
|
end
|
69
75
|
|
70
76
|
attr_reader :response
|
@@ -112,6 +118,7 @@ module Strobe
|
|
112
118
|
inst[parts[1..-1]]
|
113
119
|
else
|
114
120
|
parts.inject(params) do |param, key|
|
121
|
+
return unless param
|
115
122
|
param[key]
|
116
123
|
end
|
117
124
|
end
|
@@ -178,7 +185,7 @@ module Strobe
|
|
178
185
|
|
179
186
|
def request
|
180
187
|
@response = yield
|
181
|
-
root = self.class.
|
188
|
+
root = self.class.root
|
182
189
|
|
183
190
|
@response.validate!
|
184
191
|
|
@@ -209,7 +216,7 @@ module Strobe
|
|
209
216
|
|
210
217
|
def request_params
|
211
218
|
filter = self.class.filter
|
212
|
-
{ self.class.
|
219
|
+
{ self.class.root => params.except(*filter) }
|
213
220
|
end
|
214
221
|
|
215
222
|
def create
|
@@ -27,6 +27,10 @@ module Strobe
|
|
27
27
|
singular_resource_name.pluralize
|
28
28
|
end
|
29
29
|
|
30
|
+
def pluralized_root
|
31
|
+
root.pluralize
|
32
|
+
end
|
33
|
+
|
30
34
|
def resource_uri
|
31
35
|
uri_prefix
|
32
36
|
end
|
@@ -37,6 +41,10 @@ module Strobe
|
|
37
41
|
|
38
42
|
alias all collection
|
39
43
|
|
44
|
+
def where(params)
|
45
|
+
Strobe::Collection.new(self, params)
|
46
|
+
end
|
47
|
+
|
40
48
|
def new(params = {})
|
41
49
|
inst = IdentityMap.identify(self, key.key_for(params)) do
|
42
50
|
super({})
|
@@ -91,7 +99,7 @@ module Strobe
|
|
91
99
|
resp.validate! if opts[:validate]
|
92
100
|
|
93
101
|
if resp.success?
|
94
|
-
self.params = resp.body[self.class.
|
102
|
+
self.params = resp.body[self.class.root]
|
95
103
|
self
|
96
104
|
end
|
97
105
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'zlib'
|
2
2
|
require 'digest/sha1'
|
3
|
-
require 'mime/types'
|
4
3
|
|
5
4
|
module Strobe
|
6
5
|
module Resources
|
@@ -55,36 +54,34 @@ module Strobe
|
|
55
54
|
PackFile.build(opts) do |m|
|
56
55
|
Dir["**/*"].each do |filename|
|
57
56
|
next unless File.file?(filename)
|
58
|
-
|
59
|
-
mime_type = MIME::Types.type_for(filename).first
|
60
|
-
mime_type ||= "application/octet-stream"
|
61
|
-
|
62
|
-
m.file filename, mime_type.to_s, read(filename)
|
57
|
+
m.file filename, read(filename)
|
63
58
|
end
|
64
59
|
|
65
60
|
picked_root_app = false
|
66
61
|
|
67
|
-
|
68
|
-
|
62
|
+
if opts[:sproutcore]
|
63
|
+
Dir["static/*"].each do |appdir|
|
64
|
+
next if File.file?(appdir)
|
69
65
|
|
70
|
-
|
71
|
-
|
66
|
+
app_name = File.basename(appdir)
|
67
|
+
index = Dir["#{appdir}/*/*/index.html"].first
|
72
68
|
|
73
|
-
|
69
|
+
next unless index && File.file?(index)
|
74
70
|
|
75
|
-
|
76
|
-
|
77
|
-
|
71
|
+
manifest = "#{File.dirname(index)}/app.manifest"
|
72
|
+
manifest = read(manifest) if File.file?(manifest)
|
73
|
+
content = read(index)
|
78
74
|
|
79
|
-
|
80
|
-
|
75
|
+
m.file "#{app_name}/index.html", content
|
76
|
+
m.file "#{app_name}/app.manifest", manifest if manifest
|
81
77
|
|
82
|
-
|
78
|
+
next if picked_root_app
|
83
79
|
|
84
|
-
|
85
|
-
|
80
|
+
m.file "index.html", content
|
81
|
+
m.file "app.manifest", manifest
|
86
82
|
|
87
|
-
|
83
|
+
picked_root_app = true
|
84
|
+
end
|
88
85
|
end
|
89
86
|
end
|
90
87
|
end
|
@@ -107,14 +104,17 @@ module Strobe
|
|
107
104
|
@callback = opts[:callback]
|
108
105
|
end
|
109
106
|
|
110
|
-
def file(path,
|
111
|
-
@files << [path,
|
107
|
+
def file(path, body)
|
108
|
+
@files << [path, body]
|
112
109
|
end
|
113
110
|
|
114
111
|
def headers
|
115
|
-
{
|
112
|
+
{
|
113
|
+
'Content-Type' => 'application/x-strobe-deploy',
|
116
114
|
'Content-Length' => size.to_s,
|
117
|
-
'Content-Encoding' => 'deflate'
|
115
|
+
'Content-Encoding' => 'deflate',
|
116
|
+
'X-Strobe-Deploy-Protocol-Version' => '2'
|
117
|
+
}
|
118
118
|
end
|
119
119
|
|
120
120
|
def each(*args, &blk)
|
@@ -166,9 +166,9 @@ module Strobe
|
|
166
166
|
head = ""
|
167
167
|
body = ""
|
168
168
|
|
169
|
-
@files.each do |path,
|
169
|
+
@files.each do |path, data|
|
170
170
|
size = data.respond_to?(:bytesize) ? data.bytesize : data.size
|
171
|
-
head << "#{Digest::SHA1.hexdigest(
|
171
|
+
head << "#{Digest::SHA1.hexdigest("blob #{size}\0#{data}")}\0#{size}\0#{path}\n"
|
172
172
|
body << data
|
173
173
|
end
|
174
174
|
|
metadata
CHANGED
@@ -1,21 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: strobe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 1
|
8
|
-
- 4
|
9
|
-
version: 0.1.4
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.6
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
|
-
- Yehuda Katz
|
13
8
|
- Carl Lerche
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date: 2011-
|
13
|
+
date: 2011-03-23 00:00:00 -07:00
|
19
14
|
default_executable:
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
@@ -26,76 +21,55 @@ dependencies:
|
|
26
21
|
requirements:
|
27
22
|
- - ~>
|
28
23
|
- !ruby/object:Gem::Version
|
29
|
-
segments:
|
30
|
-
- 3
|
31
|
-
- 0
|
32
|
-
- 0
|
33
24
|
version: 3.0.0
|
34
25
|
type: :runtime
|
35
26
|
version_requirements: *id001
|
36
27
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
28
|
+
name: mime-types
|
38
29
|
prerelease: false
|
39
30
|
requirement: &id002 !ruby/object:Gem::Requirement
|
40
31
|
none: false
|
41
32
|
requirements:
|
42
33
|
- - ~>
|
43
34
|
- !ruby/object:Gem::Version
|
44
|
-
|
45
|
-
- 1
|
46
|
-
- 6
|
47
|
-
- 0
|
48
|
-
version: 1.6.0
|
35
|
+
version: 1.16.0
|
49
36
|
type: :runtime
|
50
37
|
version_requirements: *id002
|
51
38
|
- !ruby/object:Gem::Dependency
|
52
|
-
name:
|
39
|
+
name: rack
|
53
40
|
prerelease: false
|
54
41
|
requirement: &id003 !ruby/object:Gem::Requirement
|
55
42
|
none: false
|
56
43
|
requirements:
|
57
44
|
- - ~>
|
58
45
|
- !ruby/object:Gem::Version
|
59
|
-
|
60
|
-
- 1
|
61
|
-
- 16
|
62
|
-
- 0
|
63
|
-
version: 1.16.0
|
46
|
+
version: 1.2.0
|
64
47
|
type: :runtime
|
65
48
|
version_requirements: *id003
|
66
49
|
- !ruby/object:Gem::Dependency
|
67
|
-
name:
|
50
|
+
name: thor
|
68
51
|
prerelease: false
|
69
52
|
requirement: &id004 !ruby/object:Gem::Requirement
|
70
53
|
none: false
|
71
54
|
requirements:
|
72
55
|
- - ~>
|
73
56
|
- !ruby/object:Gem::Version
|
74
|
-
|
75
|
-
- 1
|
76
|
-
- 2
|
77
|
-
- 0
|
78
|
-
version: 1.2.0
|
57
|
+
version: 0.14.0
|
79
58
|
type: :runtime
|
80
59
|
version_requirements: *id004
|
81
60
|
- !ruby/object:Gem::Dependency
|
82
|
-
name:
|
61
|
+
name: launchy
|
83
62
|
prerelease: false
|
84
63
|
requirement: &id005 !ruby/object:Gem::Requirement
|
85
64
|
none: false
|
86
65
|
requirements:
|
87
|
-
- -
|
66
|
+
- - ">="
|
88
67
|
- !ruby/object:Gem::Version
|
89
|
-
|
90
|
-
- 0
|
91
|
-
- 14
|
92
|
-
- 0
|
93
|
-
version: 0.14.0
|
68
|
+
version: "0"
|
94
69
|
type: :runtime
|
95
70
|
version_requirements: *id005
|
96
71
|
description: The client library for deploying applications to Strobe's HTML5 deployment platform
|
97
72
|
email:
|
98
|
-
- wycats@strobecorp.com
|
99
73
|
- carl@strobecorp.com
|
100
74
|
executables:
|
101
75
|
- strobe
|
@@ -106,6 +80,7 @@ extra_rdoc_files: []
|
|
106
80
|
files:
|
107
81
|
- lib/strobe/association.rb
|
108
82
|
- lib/strobe/cli/deploy_progress.rb
|
83
|
+
- lib/strobe/cli/input.rb
|
109
84
|
- lib/strobe/cli/main.rb
|
110
85
|
- lib/strobe/cli/preview.rb
|
111
86
|
- lib/strobe/cli/settings.rb
|
@@ -134,6 +109,8 @@ files:
|
|
134
109
|
- lib/strobe/sproutcore.rb
|
135
110
|
- lib/strobe/validations.rb
|
136
111
|
- lib/strobe.rb
|
112
|
+
- CHANGELOG.md
|
113
|
+
- README.md
|
137
114
|
- bin/strobe
|
138
115
|
has_rdoc: true
|
139
116
|
homepage: http://rubygems.org/gems/strobe
|
@@ -149,23 +126,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
149
126
|
requirements:
|
150
127
|
- - ">="
|
151
128
|
- !ruby/object:Gem::Version
|
152
|
-
segments:
|
153
|
-
- 0
|
154
129
|
version: "0"
|
155
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
131
|
none: false
|
157
132
|
requirements:
|
158
133
|
- - ">="
|
159
134
|
- !ruby/object:Gem::Version
|
160
|
-
segments:
|
161
|
-
- 1
|
162
|
-
- 3
|
163
|
-
- 6
|
164
135
|
version: 1.3.6
|
165
136
|
requirements: []
|
166
137
|
|
167
138
|
rubyforge_project: strobe
|
168
|
-
rubygems_version: 1.
|
139
|
+
rubygems_version: 1.6.2
|
169
140
|
signing_key:
|
170
141
|
specification_version: 3
|
171
142
|
summary: A deployment tool for HTML5 applications
|