strobe 0.1.4 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
File without changes
@@ -1,7 +1,7 @@
1
1
  require 'thor'
2
2
  require 'pathname'
3
3
  require 'fileutils'
4
- require 'highline'
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
- @highline = HighLine.new
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
- @highline.agree(msg, *args) do |q|
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 = @highline.ask msg do |q|
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
- @highline.ask msg do |q|
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
- @highline.choose do |menu|
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
@@ -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
- save do
124
- say "The application is now running at #{resource[:url]}"
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
- resource get_application
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 `sc-build -c`? [Yn] "
206
+ return unless agree "Run `#{cmd}`? [Yn] "
181
207
  end
182
208
 
183
- unless CLI::Ticker.tick("Running `sc-build -c`", 2) { system "sc-build", "-c" }
184
- error! "Something went wrong while running `sc-build -c`"
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
@@ -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
- host = self[:url] || "http://api.strobeapp.com/"
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
@@ -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
- cell = obj [ col[:key] ] unless col[:key] == Index
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
 
@@ -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.resource_name].map do |hash|
21
+ resp.body[klass.pluralized_root].map do |hash|
18
22
  klass.new(hash)
19
23
  end
20
24
  else
@@ -3,12 +3,19 @@ require 'net/http'
3
3
 
4
4
  module Strobe
5
5
  class Connection
6
- attr_reader :url
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
- @url = URI(url)
10
- @user = nil
11
- @password = nil
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 @url.host, @url.port || 80
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
- queue = run_request(env, host, ( port || 80 ).to_i, $2 || '/')
58
+ msg = queue.pop
59
+ status = msg[0].to_i
34
60
 
35
- msg = queue.pop
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
@@ -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.singular_resource_name
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.singular_resource_name => params.except(*filter) }
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.singular_resource_name]
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
- Dir["static/*"].each do |appdir|
68
- next if File.file?(appdir)
62
+ if opts[:sproutcore]
63
+ Dir["static/*"].each do |appdir|
64
+ next if File.file?(appdir)
69
65
 
70
- app_name = File.basename(appdir)
71
- index = Dir["#{appdir}/*/*/index.html"].first
66
+ app_name = File.basename(appdir)
67
+ index = Dir["#{appdir}/*/*/index.html"].first
72
68
 
73
- next unless index && File.file?(index)
69
+ next unless index && File.file?(index)
74
70
 
75
- manifest = "#{File.dirname(index)}/app.manifest"
76
- manifest = read(manifest) if File.file?(manifest)
77
- content = read(index)
71
+ manifest = "#{File.dirname(index)}/app.manifest"
72
+ manifest = read(manifest) if File.file?(manifest)
73
+ content = read(index)
78
74
 
79
- m.file "#{app_name}/index.html", "text/html", content
80
- m.file "#{app_name}/app.manifest", "text/cache-manifest", manifest if manifest
75
+ m.file "#{app_name}/index.html", content
76
+ m.file "#{app_name}/app.manifest", manifest if manifest
81
77
 
82
- next if picked_root_app
78
+ next if picked_root_app
83
79
 
84
- m.file "index.html", "text/html", content
85
- m.file "app.manifest", "text/cache-manifest", manifest
80
+ m.file "index.html", content
81
+ m.file "app.manifest", manifest
86
82
 
87
- picked_root_app = true
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, content_type, body)
111
- @files << [path, content_type, body]
107
+ def file(path, body)
108
+ @files << [path, body]
112
109
  end
113
110
 
114
111
  def headers
115
- { 'Content-Type' => 'application/x-strobe-deploy',
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, type, data|
169
+ @files.each do |path, data|
170
170
  size = data.respond_to?(:bytesize) ? data.bytesize : data.size
171
- head << "#{Digest::SHA1.hexdigest(data)} #{size} #{path} #{type}\n"
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: false
5
- segments:
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-01-11 00:00:00 -08:00
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: highline
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
- segments:
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: mime-types
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
- segments:
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: rack
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
- segments:
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: thor
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
- segments:
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.3.7
139
+ rubygems_version: 1.6.2
169
140
  signing_key:
170
141
  specification_version: 3
171
142
  summary: A deployment tool for HTML5 applications