strobe 0.1.4 → 0.1.6

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.
@@ -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