sq-asset_sync 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +42 -0
  5. data/Appraisals +15 -0
  6. data/CHANGELOG.md +738 -0
  7. data/Gemfile +7 -0
  8. data/README.md +466 -0
  9. data/Rakefile +44 -0
  10. data/asset_sync.gemspec +38 -0
  11. data/docs/heroku.md +36 -0
  12. data/gemfiles/rails_3.1.gemfile +10 -0
  13. data/gemfiles/rails_3.2.gemfile +10 -0
  14. data/gemfiles/rails_4.0.gemfile +10 -0
  15. data/gemfiles/rails_4.1.gemfile +10 -0
  16. data/kochiku.yml +7 -0
  17. data/lib/asset_sync.rb +15 -0
  18. data/lib/asset_sync/asset_sync.rb +73 -0
  19. data/lib/asset_sync/config.rb +226 -0
  20. data/lib/asset_sync/engine.rb +53 -0
  21. data/lib/asset_sync/multi_mime.rb +16 -0
  22. data/lib/asset_sync/railtie.rb +5 -0
  23. data/lib/asset_sync/storage.rb +291 -0
  24. data/lib/asset_sync/version.rb +3 -0
  25. data/lib/generators/asset_sync/install_generator.rb +67 -0
  26. data/lib/generators/asset_sync/templates/asset_sync.rb +41 -0
  27. data/lib/generators/asset_sync/templates/asset_sync.yml +43 -0
  28. data/lib/tasks/asset_sync.rake +30 -0
  29. data/script/ci +31 -0
  30. data/spec/dummy_app/Rakefile +30 -0
  31. data/spec/dummy_app/app/assets/javascripts/application.js +1 -0
  32. data/spec/fixtures/aws_with_yml/config/asset_sync.yml +25 -0
  33. data/spec/fixtures/google_with_yml/config/asset_sync.yml +19 -0
  34. data/spec/fixtures/rackspace_with_yml/config/asset_sync.yml +20 -0
  35. data/spec/fixtures/with_invalid_yml/config/asset_sync.yml +24 -0
  36. data/spec/integration/aws_integration_spec.rb +77 -0
  37. data/spec/spec_helper.rb +64 -0
  38. data/spec/unit/asset_sync_spec.rb +257 -0
  39. data/spec/unit/google_spec.rb +142 -0
  40. data/spec/unit/multi_mime_spec.rb +48 -0
  41. data/spec/unit/rackspace_spec.rb +90 -0
  42. data/spec/unit/railsless_spec.rb +72 -0
  43. data/spec/unit/storage_spec.rb +244 -0
  44. metadata +248 -0
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+ gem 'rcov', :platforms => :mri_18, :group => [:development, :test]
4
+ gem 'simplecov', :platforms => [:jruby, :mri_19, :ruby_19, :mri_20, :rbx], :group => [:development, :test], :require => false
5
+ gem 'jruby-openssl', :platform => :jruby
6
+ gem 'rails', '4.1.5'
7
+ gem 'sq-gem_tasks'
@@ -0,0 +1,466 @@
1
+ [![Build Status](https://secure.travis-ci.org/rumblelabs/asset_sync.png)](http://travis-ci.org/rumblelabs/asset_sync)
2
+ [![Code Climate](https://codeclimate.com/github/rumblelabs/asset_sync/badges/gpa.svg)](https://codeclimate.com/github/rumblelabs/asset_sync)
3
+
4
+ # Asset Sync
5
+
6
+ Synchronises Assets between Rails and S3.
7
+
8
+ Asset Sync is built to run with the new Rails Asset Pipeline feature introduced in **Rails 3.1**. After you run __bundle exec rake assets:precompile__ your assets will be synchronised to your S3
9
+ bucket, optionally deleting unused files and only uploading the files it needs to.
10
+
11
+ This was initially built and is intended to work on [Heroku](http://heroku.com) but can work on any platform.
12
+
13
+ ## Upgrading?
14
+
15
+ If you are upgrading from a version of asset_sync **< 0.2.0** (i.e. 0.1.x). All of the references to config variables have changed to reference those used in **Fog**. Ensure to backup your `asset_sync.rb` or `asset_sync.yml` files and re-run the generator. You may also then need to update your ENV configuration variables (or you can change the ones that are referenced).
16
+
17
+ ## Installation
18
+
19
+ Add the gem to your Gemfile
20
+
21
+ ``` ruby
22
+ gem 'asset_sync'
23
+ ```
24
+
25
+ ### Optimized Fog loading
26
+
27
+ Since AssetSync doesn't know which parts of Fog you intend to use, it will just load the fog-core library.
28
+ In order to use aws or other providers, add those in your Gemfile accordingly, like:
29
+ ```ruby
30
+ gem "fog-aws"
31
+ gem "asset_sync"
32
+ ```
33
+
34
+ ### Extended Installation (Faster sync with turbosprockets)
35
+
36
+ It's possible to improve **asset:precompile** time if you are using Rails 3.2.x
37
+ the main source of which being compilation of **non-digest** assets.
38
+
39
+ [turbo-sprockets-rails3](https://github.com/ndbroadbent/turbo-sprockets-rails3)
40
+ solves this by only compiling **digest** assets. Thus cutting compile time in half.
41
+
42
+ > NOTE: It will be **deprecated in Rails 4** as sprockets-rails has been extracted
43
+ out of Rails and will only compile **digest** assets by default.
44
+
45
+ ## Configuration
46
+
47
+ ### Rails
48
+
49
+ Configure __config/environments/production.rb__ to use Amazon
50
+ S3 as the asset host and ensure precompiling is enabled.
51
+
52
+
53
+ ``` ruby
54
+ #config/environments/production.rb
55
+ config.action_controller.asset_host = "//#{ENV['FOG_DIRECTORY']}.s3.amazonaws.com"
56
+ ```
57
+
58
+ Or, to use Google Storage Cloud, configure as this.
59
+
60
+ ``` ruby
61
+ #config/environments/production.rb
62
+ config.action_controller.asset_host = "//#{ENV['FOG_DIRECTORY']}.storage.googleapis.com"
63
+ ```
64
+
65
+
66
+
67
+ On **HTTPS**: the exclusion of any protocol in the asset host declaration above will allow browsers to choose the transport mechanism on the fly. So if your application is available under both HTTP and HTTPS the assets will be served to match.
68
+
69
+ > The only caveat with this is that your S3 bucket name **must not contain any periods** so, mydomain.com.s3.amazonaws.com for example would not work under HTTPS as SSL certificates from Amazon would interpret our bucket name as **not** a subdomain of s3.amazonaws.com, but a multi level subdomain. To avoid this don't use a period in your subdomain or switch to the other style of S3 URL.
70
+
71
+ ``` ruby
72
+ config.action_controller.asset_host = "//s3.amazonaws.com/#{ENV['FOG_DIRECTORY']}"
73
+ ```
74
+ Or
75
+
76
+ ``` ruby
77
+ config.action_controller.asset_host = "//storage.googleapis.com/#{ENV['FOG_DIRECTORY']}"
78
+ ```
79
+ On **non default S3 bucket region**: If your bucket is set to a region that is not the default US Standard (us-east-1) you must use the first style of url ``//#{ENV['FOG_DIRECTORY']}.s3.amazonaws.com`` or amazon will return a 301 permanently moved when assets are requested. Note the caveat above about bucket names and periods.
80
+
81
+ If you wish to have your assets sync to a sub-folder of your bucket instead of into the root add the following to your ``production.rb`` file
82
+
83
+ ```ruby
84
+ # store assets in a 'folder' instead of bucket root
85
+ config.assets.prefix = "/production/assets"
86
+ ````
87
+
88
+ Also, ensure the following are defined (in production.rb or application.rb)
89
+
90
+ * **config.assets.digest** is set to **true**.
91
+ * **config.assets.enabled** is set to **true**.
92
+
93
+ Additionally, if you depend on any configuration that is setup in your `initializers` you will need to ensure that
94
+
95
+ * **config.assets.initialize\_on\_precompile** is set to **true**
96
+
97
+ ### AssetSync
98
+
99
+ **AssetSync** supports the following methods of configuration.
100
+
101
+ * [Built-in Initializer](https://github.com/rumblelabs/asset_sync/blob/master/lib/asset_sync/engine.rb) (configured through environment variables)
102
+ * Rails Initializer
103
+ * A YAML config file
104
+
105
+
106
+ Using the **Built-in Initializer** is the default method and is supposed to be used with **environment** variables. It's the recommended approach for deployments on Heroku.
107
+
108
+ If you need more control over configuration you will want to use a **custom rails initializer**.
109
+
110
+ Configuration using a **YAML** file (a common strategy for Capistrano deployments) is also supported.
111
+
112
+ The recommend way to configure **asset_sync** is by using **environment variables** however it's up to you, it will work fine if you hard code them too. The main reason why using environment variables is recommended is so your access keys are not checked into version control.
113
+
114
+
115
+ ### Built-in Initializer (Environment Variables)
116
+
117
+ The Built-in Initializer will configure **AssetSync** based on the contents of your environment variables.
118
+
119
+ Add your configuration details to **heroku**
120
+
121
+ ``` bash
122
+ heroku config:add AWS_ACCESS_KEY_ID=xxxx
123
+ heroku config:add AWS_SECRET_ACCESS_KEY=xxxx
124
+ heroku config:add FOG_DIRECTORY=xxxx
125
+ heroku config:add FOG_PROVIDER=AWS
126
+ # and optionally:
127
+ heroku config:add FOG_REGION=eu-west-1
128
+ heroku config:add ASSET_SYNC_GZIP_COMPRESSION=true
129
+ heroku config:add ASSET_SYNC_MANIFEST=true
130
+ heroku config:add ASSET_SYNC_EXISTING_REMOTE_FILES=keep
131
+ ```
132
+
133
+ Or add to a traditional unix system
134
+
135
+ ``` bash
136
+ export AWS_ACCESS_KEY_ID=xxxx
137
+ export AWS_SECRET_ACCESS_KEY=xxxx
138
+ export FOG_DIRECTORY=xxxx
139
+ ```
140
+
141
+ Rackspace configuration is also supported
142
+
143
+ ``` bash
144
+ heroku config:add RACKSPACE_USERNAME=xxxx
145
+ heroku config:add RACKSPACE_API_KEY=xxxx
146
+ heroku config:add FOG_DIRECTORY=xxxx
147
+ heroku config:add FOG_PROVIDER=Rackspace
148
+ ```
149
+
150
+ Google Storage Cloud configuration is supported as well
151
+ ``` bash
152
+ heroku config:add FOG_PROVIDER=Google
153
+ heroku config:add GOOGLE_STORAGE_ACCESS_KEY_ID=xxxx
154
+ heroku config:add GOOGLE_STORAGE_SECRET_ACCESS_KEY=xxxx
155
+ heroku config:add FOG_DIRECTORY=xxxx
156
+ ```
157
+
158
+ The Built-in Initializer also sets the AssetSync default for **existing_remote_files** to **keep**.
159
+
160
+ ### Custom Rails Initializer (config/initializers/asset_sync.rb)
161
+
162
+ If you want to enable some of the advanced configuration options you will want to create your own initializer.
163
+
164
+ Run the included Rake task to generate a starting point.
165
+
166
+ rails g asset_sync:install --provider=Rackspace
167
+ rails g asset_sync:install --provider=AWS
168
+
169
+ The generator will create a Rails initializer at `config/initializers/asset_sync.rb`.
170
+
171
+ ``` ruby
172
+ AssetSync.configure do |config|
173
+ config.fog_provider = 'AWS'
174
+ config.fog_directory = ENV['FOG_DIRECTORY']
175
+ config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
176
+ config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
177
+
178
+ # Don't delete files from the store
179
+ # config.existing_remote_files = 'keep'
180
+ #
181
+ # Increase upload performance by configuring your region
182
+ # config.fog_region = 'eu-west-1'
183
+ #
184
+ # Automatically replace files with their equivalent gzip compressed version
185
+ # config.gzip_compression = true
186
+ #
187
+ # Use the Rails generated 'manifest.yml' file to produce the list of files to
188
+ # upload instead of searching the assets directory.
189
+ # config.manifest = true
190
+ #
191
+ # Fail silently. Useful for environments such as Heroku
192
+ # config.fail_silently = true
193
+ end
194
+ ```
195
+
196
+ ### YAML (config/asset_sync.yml)
197
+
198
+ Run the included Rake task to generate a starting point.
199
+
200
+ rails g asset_sync:install --use-yml --provider=Rackspace
201
+ rails g asset_sync:install --use-yml --provider=AWS
202
+
203
+ The generator will create a YAML file at `config/asset_sync.yml`.
204
+
205
+ ``` yaml
206
+ defaults: &defaults
207
+ fog_provider: "AWS"
208
+ fog_directory: "rails-app-assets"
209
+ aws_access_key_id: "<%= ENV['AWS_ACCESS_KEY_ID'] %>"
210
+ aws_secret_access_key: "<%= ENV['AWS_SECRET_ACCESS_KEY'] %>"
211
+ # You may need to specify what region your storage bucket is in
212
+ # fog_region: "eu-west-1"
213
+ existing_remote_files: keep # Existing pre-compiled assets on S3 will be kept
214
+ # To delete existing remote files.
215
+ # existing_remote_files: delete
216
+ # To ignore existing remote files and overwrite.
217
+ # existing_remote_files: ignore
218
+ # Automatically replace files with their equivalent gzip compressed version
219
+ # gzip_compression: true
220
+ # Fail silently. Useful for environments such as Heroku
221
+ # fail_silently: true
222
+ # Always upload. Useful if you want to overwrite specific remote assets regardless of their existence
223
+ # eg: Static files in public often reference non-fingerprinted application.css
224
+ # note: You will still need to expire them from the CDN's edge cache locations
225
+ # always_upload: ['application.js', 'application.css']
226
+ # Ignored files. Useful if there are some files that are created dynamically on the server and you don't want to upload on deploy.
227
+ # ignored_files: ['ignore_me.js', !ruby/regexp '/ignore_some/\d{32}\.css/']
228
+
229
+ development:
230
+ <<: *defaults
231
+
232
+ test:
233
+ <<: *defaults
234
+
235
+ production:
236
+ <<: *defaults
237
+ ```
238
+
239
+ ### Available Configuration Options
240
+
241
+ All AssetSync configuration can be modified directly using environment variables with the **Built-in initializer**. e.g.
242
+
243
+ ```ruby
244
+ AssetSync.config.fog_provider == ENV['FOG_PROVIDER']
245
+ ```
246
+
247
+ Simply **upcase** the ruby attribute names to get the equivalent environment variable to set. The only exception to that rule are the internal **AssetSync** config variables, they must be prepended with `ASSET_SYNC_*` e.g.
248
+
249
+ ```ruby
250
+ AssetSync.config.gzip_compression == ENV['ASSET_SYNC_GZIP_COMPRESSION']
251
+ ```
252
+
253
+ #### AssetSync (optional)
254
+
255
+ * **existing_remote_files**: (`'keep', 'delete', 'ignore'`) what to do with previously precompiled files. **default:** `'keep'`
256
+ * **gzip\_compression**: (`true, false`) when enabled, will automatically replace files that have a gzip compressed equivalent with the compressed version. **default:** `'false'`
257
+ * **manifest**: (`true, false`) when enabled, will use the `manifest.yml` generated by Rails to get the list of local files to upload. **experimental**. **default:** `'false'`
258
+ * **enabled**: (`true, false`) when false, will disable asset sync. **default:** `'true'` (enabled)
259
+ * **ignored\_files**: an array of files to ignore e.g. `['ignore_me.js', %r(ignore_some/\d{32}\.css)]` Useful if there are some files that are created dynamically on the server and you don't want to upload on deploy **default**: `[]`
260
+
261
+
262
+ #### Fog (Required)
263
+ * **fog\_provider**: your storage provider *AWS* (S3) or *Rackspace* (Cloud Files) or *Google* (Google Storage)
264
+ * **fog\_directory**: your bucket name
265
+
266
+ #### Fog (Optional)
267
+
268
+ * **fog\_region**: the region your storage bucket is in e.g. *eu-west-1*
269
+
270
+ #### AWS
271
+
272
+ * **aws\_access\_key\_id**: your Amazon S3 access key
273
+ * **aws\_secret\_access\_key**: your Amazon S3 access secret
274
+
275
+ #### Rackspace
276
+
277
+ * **rackspace\_username**: your Rackspace username
278
+ * **rackspace\_api\_key**: your Rackspace API Key.
279
+
280
+ #### Google Storage
281
+ * **google\_storage\_access\_key\_id**: your Google Storage access key
282
+ * **google\_storage\_secret\_access\_key**: your Google Storage access secret
283
+
284
+ #### Rackspace (Optional)
285
+
286
+ * **rackspace\_auth\_url**: Rackspace auth URL, for Rackspace London use: `https://lon.identity.api.rackspacecloud.com/v2.0`
287
+
288
+ ## Amazon S3 Multiple Region Support
289
+
290
+ If you are using anything other than the US buckets with S3 then you'll want to set the **region**. For example with an EU bucket you could set the following environment variable.
291
+
292
+ ``` bash
293
+ heroku config:add FOG_REGION=eu-west-1
294
+ ```
295
+
296
+ Or via a custom initializer
297
+
298
+ ``` ruby
299
+ AssetSync.configure do |config|
300
+ # ...
301
+ config.fog_region = 'eu-west-1'
302
+ end
303
+ ```
304
+
305
+ Or via YAML
306
+
307
+ ``` yaml
308
+ production:
309
+ # ...
310
+ fog_region: 'eu-west-1'
311
+ ```
312
+
313
+ ### Amazon (AWS) IAM Users
314
+
315
+ Amazon has switched to the more secure IAM User security policy model. When generating a user & policy for asset_sync you will need to ensure the policy has the following permissions.
316
+ You __must__ give the user permission to **s3:ListAllMyBuckets** as well as give permission to both the bucket, as well as the bucket's contents (/*). If not given all these permissions you'll see the error ```Expected(200) <=> Actual(403 Forbidden) ```
317
+
318
+ IAM User Policy Example (replace "bucket_name" with your bucket):
319
+ ``` json
320
+ {
321
+ "Statement": [
322
+ {
323
+ "Action": [
324
+ "s3:ListAllMyBuckets"
325
+ ],
326
+ "Effect": "Allow",
327
+ "Resource": "arn:aws:s3:::*"
328
+ },
329
+ {
330
+ "Action": "s3:*",
331
+ "Effect": "Allow",
332
+ "Resource": "arn:aws:s3:::bucket_name"
333
+ },
334
+ {
335
+ "Action": "s3:*",
336
+ "Effect": "Allow",
337
+ "Resource": "arn:aws:s3:::bucket_name/*"
338
+ }
339
+ ]
340
+ }
341
+ ```
342
+
343
+ If you want to use IAM roles you must set ```config.aws_iam_roles = true``` in your initializers.
344
+ ```
345
+ AssetSync.configure do |config|
346
+ # ...
347
+ config.aws_iam_roles = true
348
+ end
349
+ ```
350
+
351
+
352
+ ## Automatic gzip compression
353
+
354
+ With the `gzip_compression` option enabled, when uploading your assets. If a file has a gzip compressed equivalent we will replace that asset with the compressed version and sets the correct headers for S3 to serve it. For example, if you have a file **master.css** and it was compressed to **master.css.gz** we will upload the **.gz** file to S3 in place of the uncompressed file.
355
+
356
+ If the compressed file is actually larger than the uncompressed file we will ignore this rule and upload the standard uncompressed version.
357
+
358
+ ## Fail Silently
359
+
360
+ With the `fail_silently` option enabled, when running `rake assets:precompile` AssetSync will never throw an error due to missing configuration variables.
361
+
362
+ With the new **user_env_compile** feature of Heroku (see above), this is no longer required or recommended. Yet was added for the following reasons:
363
+
364
+ > With Rails 3.1 on the Heroku cedar stack, the deployment process automatically runs `rake assets:precompile`. If you are using **ENV** variable style configuration. Due to the methods with which Heroku compile slugs, there will be an error raised by asset\_sync as the environment is not available. This causes heroku to install the `rails31_enable_runtime_asset_compilation` plugin which is not necessary when using **asset_sync** and also massively slows down the first incoming requests to your app.
365
+
366
+ > To prevent this part of the deploy from failing (asset_sync raising a config error), but carry on as normal set `fail_silently` to true in your configuration and ensure to run `heroku run rake assets:precompile` after deploy.
367
+
368
+ ## Rake Task
369
+
370
+ A rake task is included within the **asset_sync** gem to perform the sync:
371
+
372
+ ``` ruby
373
+ namespace :assets do
374
+ desc "Synchronize assets to S3"
375
+ task :sync => :environment do
376
+ AssetSync.sync
377
+ end
378
+ end
379
+ ```
380
+
381
+ If `AssetSync.config.run_on_precompile` is `true` (default), then assets will be uploaded to S3 automatically after the `assets:precompile` rake task is invoked:
382
+
383
+ ``` ruby
384
+ if Rake::Task.task_defined?("assets:precompile:nondigest")
385
+ Rake::Task["assets:precompile:nondigest"].enhance do
386
+ Rake::Task["assets:sync"].invoke if defined?(AssetSync) && AssetSync.config.run_on_precompile
387
+ end
388
+ else
389
+ Rake::Task["assets:precompile"].enhance do
390
+ Rake::Task["assets:sync"].invoke if defined?(AssetSync) && AssetSync.config.run_on_precompile
391
+ end
392
+ end
393
+ ```
394
+
395
+ You can disable this behavior by setting `AssetSync.config.run_on_precompile = false`.
396
+
397
+ ## Sinatra/Rack Support
398
+
399
+ You can use the gem with any Rack application, but you must specify two
400
+ additional options; `prefix` and `public_path`.
401
+
402
+ ```ruby
403
+ AssetSync.configure do |config|
404
+ config.fog_provider = 'AWS'
405
+ config.fog_directory = ENV['FOG_DIRECTORY']
406
+ config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
407
+ config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
408
+ config.prefix = 'assets'
409
+ config.public_path = Pathname('./public')
410
+ end
411
+ ```
412
+
413
+ Then manually call `AssetSync.sync` at the end of your asset precompilation
414
+ task.
415
+
416
+ ```ruby
417
+ namespace :assets do
418
+ desc 'Precompile assets'
419
+ task :precompile do
420
+ target = Pathname('./public/assets')
421
+ manifest = Sprockets::Manifest.new(sprockets, './public/assets/manifest.json')
422
+
423
+ sprockets.each_logical_path do |logical_path|
424
+ if (!File.extname(logical_path).in?(['.js', '.css']) || logical_path =~ /application\.(css|js)$/) && asset = sprockets.find_asset(logical_path)
425
+ filename = target.join(logical_path)
426
+ FileUtils.mkpath(filename.dirname)
427
+ puts "Write asset: #{filename}"
428
+ asset.write_to(filename)
429
+ manifest.compile(logical_path)
430
+ end
431
+ end
432
+
433
+ AssetSync.sync
434
+ end
435
+ end
436
+ ```
437
+
438
+ ## Running the specs
439
+
440
+ Make sure you have a .env file with these details:-
441
+
442
+ AWS_ACCESS_KEY_ID=<yourkeyid>
443
+ AWS_SECRET_ACCESS_KEY=<yoursecretkey>
444
+ FOG_DIRECTORY=<yourbucket>
445
+
446
+ Make sure the bucket has read/write permissions. Then to run the tests:-
447
+
448
+ foreman run rake
449
+
450
+ ## Todo
451
+
452
+ 1. Add some before and after filters for deleting and uploading
453
+ 2. Support more cloud storage providers
454
+ 3. Better test coverage
455
+ 4. Add rake tasks to clean old assets from a bucket
456
+
457
+ ## Credits
458
+
459
+ Inspired by:
460
+
461
+ - [https://github.com/moocode/asset_id](https://github.com/moocode/asset_id)
462
+ - [https://gist.github.com/1053855](https://gist.github.com/1053855)
463
+
464
+ ## License
465
+
466
+ MIT License. Copyright 2011-2013 Rumble Labs Ltd. [rumblelabs.com](http://rumblelabs.com)