asset_sync 2.6.0 → 2.12.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 51ba6147cc39550e51d1eb1bc98420b53b0ca14fe96d90d34e7de36c8a9511b5
4
- data.tar.gz: 701e692e95ed4c8ad41a8a5d14e7356ee8c013221e675d7396a8b07816f7a226
3
+ metadata.gz: 1fbb82cb5023ce3d6e1f088aa62fa32718f8e743977c31b773e3f2a324a0a397
4
+ data.tar.gz: 504e104e3dfe839bb19b0794a7af8f4bb932fd7f7500347374c14b8862e5ae43
5
5
  SHA512:
6
- metadata.gz: f03b66ce2292d21a3e1a514307a3bf737c0ea856b46ee6e36aef40b93a2604b544e708f97f7b1e9fbfa81483545929cfb9e7714c4bf4172e6311e22f4cc7ffe2
7
- data.tar.gz: e228c684a414b1a9859ea8df91f76b1b6c5ad4234863b46307dd76b705aa8a71f18cba5ab8c959a33ac089ca9d5c355dc26391bb16441a8c802fc0f44f97c087
6
+ metadata.gz: 2945ac417bfcc350068b1c9ce3c59781f0cd7bb50bd606919803e55602a81b06d6d6fed24de0c7e62ca695a83901481d296a9ae20031b5ab1e9edfc61a69823a
7
+ data.tar.gz: b96f8274e66d1d7ec2ab182fdcb3833edd7c24b9dc9d9fd9d038a3db8608dc1102a23b2998ec5c9749e89fe6d12212488dc9733ec927328fcc0f388bf84df357
@@ -5,21 +5,24 @@ language: ruby
5
5
  cache:
6
6
  bundler: true
7
7
  rvm:
8
- - 2.2
9
8
  - 2.3
10
9
  - 2.4
11
10
  - 2.5
12
11
  - 2.6
12
+ - 2.7
13
13
  - ruby-head
14
14
  - jruby
15
15
  - jruby-head
16
16
  gemfile:
17
- - gemfiles/rails_4_2.gemfile
18
17
  - gemfiles/rails_5_0.gemfile
19
18
  - gemfiles/rails_5_1.gemfile
20
19
  - gemfiles/rails_5_2.gemfile
20
+ - gemfiles/rails_6_0.gemfile
21
21
  before_install:
22
- - gem install bundler
22
+ # Cannot use bundler 2.x due to dependency (mainly rails 4.2)
23
+ # Solution from https://github.com/rails/rails/blob/4-2-stable/.travis.yml
24
+ - "travis_retry gem update --system --no-doc || travis_retry gem update --system --no-rdoc --no-ri"
25
+ - "travis_retry gem install bundler -v '<2'"
23
26
  env:
24
27
  global:
25
28
  - FOG_DIRECTORY=asset-sync-travis
@@ -29,9 +32,13 @@ env:
29
32
  matrix:
30
33
  fast_finish: true
31
34
  allow_failures:
32
- - rvm: 2.6
33
35
  - rvm: ruby-head
34
36
  - rvm: jruby-head
37
+ exclude:
38
+ - rvm: 2.3
39
+ gemfile: gemfiles/rails_6_0.gemfile
40
+ - rvm: 2.4
41
+ gemfile: gemfiles/rails_6_0.gemfile
35
42
  notifications:
36
43
  webhooks:
37
44
  urls:
data/Appraisals CHANGED
@@ -1,8 +1,4 @@
1
1
 
2
- appraise "rails_4_2" do
3
- gem "rails", "~> 4.2.0"
4
- end
5
-
6
2
  appraise "rails_5_0" do
7
3
  gem "rails", "~> 5.0.0"
8
4
  end
@@ -14,3 +10,7 @@ end
14
10
  appraise "rails_5_2" do
15
11
  gem "rails", "~> 5.2.0"
16
12
  end
13
+
14
+ appraise "rails_6_0" do
15
+ gem "rails", "~> 6.0.0"
16
+ end
@@ -18,6 +18,96 @@ This project adheres to [Semantic Versioning](http://semver.org/).
18
18
  - Nothing
19
19
 
20
20
 
21
+ ## [2.12.1] - 2020-06-17
22
+
23
+ ### Fixed
24
+
25
+ - Fix initializer template in generator
26
+ (https://github.com/AssetSync/asset_sync/pull/404)
27
+
28
+
29
+ ## [2.12.0] - 2020-06-11
30
+
31
+ ### Added
32
+
33
+ - Add option `aws_session_token` to support AWS Temporary Security Credentials
34
+ (https://github.com/AssetSync/asset_sync/pull/403)
35
+
36
+
37
+ ## [2.11.0] - 2020-03-13
38
+
39
+ ### Added
40
+
41
+ - Add option `remote_file_list_cache_file_path` to skip scanning remote
42
+ (https://github.com/AssetSync/asset_sync/pull/400)
43
+
44
+
45
+ ## [2.10.0] - 2020-02-26
46
+
47
+ ### Added
48
+
49
+ - Add option `concurrent_uploads_max_threads` to limit number of threads for uploading files
50
+ (https://github.com/AssetSync/asset_sync/pull/398)
51
+
52
+
53
+ ## [2.9.1] - 2020-02-20
54
+
55
+ ### Fixed
56
+
57
+ - Fix uploading of sprockets manifest file
58
+ (https://github.com/AssetSync/asset_sync/pull/397)
59
+
60
+
61
+ ## [2.9.0] - 2020-01-15
62
+
63
+ ### Added
64
+
65
+ - Add option `concurrent_uploads` to improve speed of uploading
66
+ (https://github.com/AssetSync/asset_sync/pull/393)
67
+
68
+
69
+ ## [2.8.2] - 2019-12-27
70
+
71
+ ### Changed
72
+
73
+ - Use `delete_multiple_objects` when storage is `aws`
74
+ (https://github.com/AssetSync/asset_sync/pull/392)
75
+
76
+
77
+ ## [2.8.1] - 2019-07-25
78
+
79
+ ### Changed
80
+
81
+ - Removed `rubyforge_project` from gemspec
82
+ (https://github.com/AssetSync/asset_sync/pull/386)
83
+
84
+ ### Fixed
85
+
86
+ - Fixed when `fog_public` set to `false`, file were still set to be public
87
+ (https://github.com/AssetSync/asset_sync/pull/387)
88
+
89
+
90
+ ## [2.8.0] - 2019-06-17
91
+
92
+ ### Added
93
+
94
+ - Add option `fog_port`
95
+ (https://github.com/AssetSync/asset_sync/pull/385)
96
+
97
+
98
+ ## [2.7.0] - 2019-03-15
99
+
100
+ ### Added
101
+
102
+ - Adds JSON API support when using Google Storage
103
+ (https://github.com/AssetSync/asset_sync/pull/381)
104
+
105
+ ### Changed
106
+
107
+ - Update `AssetSync::MultiMime.lookup` to always return strings (kind of internal change)
108
+ (https://github.com/AssetSync/asset_sync/pull/380)
109
+
110
+
21
111
  ## [2.6.0] - 2018-12-07
22
112
 
23
113
  ### Added
@@ -105,7 +195,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
105
195
 
106
196
  - Only support mime-type >= 2.99,
107
197
  which is released at the end of 2015
108
- - Only support mactivemodel >= 4.1,
198
+ - Only support activemodel >= 4.1,
109
199
  which is released in 2014
110
200
 
111
201
 
@@ -888,7 +978,17 @@ Changes:
888
978
  * Merge branch 'sinatra'
889
979
 
890
980
 
891
- [Unreleased]: https://github.com/AssetSync/asset_sync/compare/v2.6.0...HEAD
981
+ [Unreleased]: https://github.com/AssetSync/asset_sync/compare/v2.12.1...HEAD
982
+ [2.12.1]: https://github.com/AssetSync/asset_sync/compare/v2.12.0...v2.12.1
983
+ [2.12.0]: https://github.com/AssetSync/asset_sync/compare/v2.11.0...v2.12.0
984
+ [2.11.0]: https://github.com/AssetSync/asset_sync/compare/v2.10.0...v2.11.0
985
+ [2.10.0]: https://github.com/AssetSync/asset_sync/compare/v2.9.1...v2.10.0
986
+ [2.9.1]: https://github.com/AssetSync/asset_sync/compare/v2.9.0...v2.9.1
987
+ [2.9.0]: https://github.com/AssetSync/asset_sync/compare/v2.8.2...v2.9.0
988
+ [2.8.2]: https://github.com/AssetSync/asset_sync/compare/v2.8.1...v2.8.2
989
+ [2.8.1]: https://github.com/AssetSync/asset_sync/compare/v2.8.0...v2.8.1
990
+ [2.8.0]: https://github.com/AssetSync/asset_sync/compare/v2.7.0...v2.8.0
991
+ [2.7.0]: https://github.com/AssetSync/asset_sync/compare/v2.6.0...v2.7.0
892
992
  [2.6.0]: https://github.com/AssetSync/asset_sync/compare/v2.5.0...v2.6.0
893
993
  [2.5.0]: https://github.com/AssetSync/asset_sync/compare/v2.4.0...v2.5.0
894
994
  [2.4.0]: https://github.com/AssetSync/asset_sync/compare/v2.3.0...v2.4.0
data/README.md CHANGED
@@ -103,10 +103,10 @@ On **non default S3 bucket region**: If your bucket is set to a region that is n
103
103
 
104
104
  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
105
105
 
106
- ```ruby
106
+ ``` ruby
107
107
  # store assets in a 'folder' instead of bucket root
108
108
  config.assets.prefix = "/production/assets"
109
- ````
109
+ ```
110
110
 
111
111
  Also, ensure the following are defined (in production.rb or application.rb)
112
112
 
@@ -170,7 +170,17 @@ heroku config:add FOG_DIRECTORY=xxxx
170
170
  heroku config:add FOG_PROVIDER=Rackspace
171
171
  ```
172
172
 
173
- Google Storage Cloud configuration is supported as well
173
+ Google Storage Cloud configuration is supported as well. The preferred option is using the [GCS JSON API](https://github.com/fog/fog-google#storage) which requires that you create an appropriate service account, generate the signatures and make them accessible to asset sync at the prescribed location
174
+
175
+ ```bash
176
+ heroku config:add FOG_PROVIDER=Google
177
+ heroku config:add GOOGLE_PROJECT=xxxx
178
+ heroku config:add GOOGLE_JSON_KEY_LOCATION=xxxx
179
+ heroku config:add FOG_DIRECTORY=xxxx
180
+ ```
181
+
182
+ If using the S3 API the following config is required
183
+
174
184
  ``` bash
175
185
  heroku config:add FOG_PROVIDER=Google
176
186
  heroku config:add GOOGLE_STORAGE_ACCESS_KEY_ID=xxxx
@@ -198,6 +208,7 @@ AssetSync.configure do |config|
198
208
  config.fog_directory = ENV['FOG_DIRECTORY']
199
209
  config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
200
210
  config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
211
+ config.aws_session_token = ENV['AWS_SESSION_TOKEN'] if ENV.key?('AWS_SESSION_TOKEN')
201
212
 
202
213
  # Don't delete files from the store
203
214
  # config.existing_remote_files = 'keep'
@@ -216,6 +227,9 @@ AssetSync.configure do |config|
216
227
  # Change host option in fog (only if you need to)
217
228
  # config.fog_host = 's3.amazonaws.com'
218
229
  #
230
+ # Change port option in fog (only if you need to)
231
+ # config.fog_port = "9000"
232
+ #
219
233
  # Use http instead of https.
220
234
  # config.fog_scheme = 'http'
221
235
  #
@@ -229,6 +243,15 @@ AssetSync.configure do |config|
229
243
  # Upload the manifest file also.
230
244
  # config.include_manifest = false
231
245
  #
246
+ # Upload files concurrently
247
+ # config.concurrent_uploads = false
248
+ #
249
+ # Number of threads when concurrent_uploads is enabled
250
+ # config.concurrent_uploads_max_threads = 10
251
+ #
252
+ # Path to cache file to skip scanning remote
253
+ # config.remote_file_list_cache_file_path = './.asset_sync_remote_file_list_cache.json'
254
+ #
232
255
  # Fail silently. Useful for environments such as Heroku
233
256
  # config.fail_silently = true
234
257
  #
@@ -325,6 +348,9 @@ AssetSync.config.gzip_compression == ENV['ASSET_SYNC_GZIP_COMPRESSION']
325
348
  * **gzip\_compression**: (`true, false`) when enabled, will automatically replace files that have a gzip compressed equivalent with the compressed version. **default:** `'false'`
326
349
  * **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'`
327
350
  * **include_manifest**: (`true, false`) when enabled, will upload the `manifest.yml` generated by Rails. **default:** `'false'`
351
+ * **concurrent_uploads**: (`true, false`) when enabled, will upload the files in different Threads, this greatly improves the upload speed. **default:** `'false'`
352
+ * **concurrent_uploads_max_threads**: when concurrent_uploads is enabled, this determines the number of threads that will be created. **default:** `10`
353
+ * **remote_file_list_cache_file_path**: if present, use this path to cache remote file list to skip scanning remote **default:** `nil`
328
354
  * **enabled**: (`true, false`) when false, will disable asset sync. **default:** `'true'` (enabled)
329
355
  * **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**: `[]`
330
356
  * **cache\_asset\_regexps**: an array of files to add cache headers e.g. `['cache_me.js', %r(cache_some\.\d{8}\.css)]` Useful if there are some files that are added to sprockets assets list and need to be set as 'Cacheable' on uploaded server. Only rails compiled regexp is matched internally **default**: `[]`
@@ -385,6 +411,14 @@ The blocks are run when local files are being scanned and uploaded
385
411
  * **rackspace\_api\_key**: your Rackspace API Key.
386
412
 
387
413
  #### Google Storage
414
+
415
+ When using the JSON API
416
+
417
+ - **google\_project**: your Google Cloud Project name where the Google Cloud Storage bucket resides
418
+ - **google\_json\_key\_location**: path to the location of the service account key. The service account key must be a JSON type key
419
+
420
+ When using the S3 API
421
+
388
422
  * **google\_storage\_access\_key\_id**: your Google Storage access key
389
423
  * **google\_storage\_secret\_access\_key**: your Google Storage access secret
390
424
 
@@ -515,6 +549,10 @@ AssetSync.configure do |config|
515
549
  config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
516
550
  config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
517
551
  config.prefix = 'assets'
552
+ # Can be a `Pathname` or `String`
553
+ # Will be converted into an `Pathname`
554
+ # If relative, will be converted into an absolute path
555
+ # via `::Rails.root` or `::Dir.pwd`
518
556
  config.public_path = Pathname('./public')
519
557
  end
520
558
  ```
@@ -584,7 +622,7 @@ Make sure you have a .env file with these details:-
584
622
  AWS_SECRET_ACCESS_KEY=<yoursecretkey>
585
623
  FOG_DIRECTORY=<yourbucket>
586
624
  FOG_REGION=<youbucketregion>
587
-
625
+
588
626
  # for AzureRM provider
589
627
  AZURE_STORAGE_ACCOUNT_NAME=<youraccountname>
590
628
  AZURE_STORAGE_ACCESS_KEY=<youraccesskey>
@@ -15,8 +15,6 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.license = 'MIT'
17
17
 
18
- s.rubyforge_project = "asset_sync"
19
-
20
18
  s.add_dependency("fog-core")
21
19
  s.add_dependency('unf')
22
20
  s.add_dependency('activemodel', ">= 4.1.0")
@@ -5,6 +5,6 @@ source "https://rubygems.org"
5
5
  gem "rcov", platforms: :mri_18, group: [:development, :test]
6
6
  gem "simplecov", platforms: [:jruby, :mri_19, :ruby_19, :mri_20, :rbx], group: [:development, :test], require: false
7
7
  gem "jruby-openssl", platform: :jruby
8
- gem "rails", "~> 4.2.0"
8
+ gem "rails", "~> 6.0.0"
9
9
 
10
10
  gemspec path: "../"
@@ -26,7 +26,9 @@ module AssetSync
26
26
  attr_accessor :cdn_distribution_id
27
27
  attr_accessor :cache_asset_regexps
28
28
  attr_accessor :include_manifest
29
- attr_writer :public_path
29
+ attr_accessor :concurrent_uploads
30
+ attr_accessor :concurrent_uploads_max_threads
31
+ attr_accessor :remote_file_list_cache_file_path
30
32
 
31
33
  # FOG configuration
32
34
  attr_accessor :fog_provider # Currently Supported ['AWS', 'Rackspace']
@@ -35,8 +37,9 @@ module AssetSync
35
37
  attr_reader :fog_public # e.g. true, false, "default"
36
38
 
37
39
  # Amazon AWS
38
- attr_accessor :aws_access_key_id, :aws_secret_access_key, :aws_reduced_redundancy, :aws_iam_roles, :aws_signature_version
40
+ attr_accessor :aws_access_key_id, :aws_secret_access_key, :aws_session_token, :aws_reduced_redundancy, :aws_iam_roles, :aws_signature_version
39
41
  attr_accessor :fog_host # e.g. 's3.amazonaws.com'
42
+ attr_accessor :fog_port # e.g. '9000'
40
43
  attr_accessor :fog_path_style # e.g. true
41
44
  attr_accessor :fog_scheme # e.g. 'http'
42
45
 
@@ -44,7 +47,9 @@ module AssetSync
44
47
  attr_accessor :rackspace_username, :rackspace_api_key, :rackspace_auth_url
45
48
 
46
49
  # Google Storage
47
- attr_accessor :google_storage_secret_access_key, :google_storage_access_key_id
50
+ attr_accessor :google_storage_secret_access_key, :google_storage_access_key_id # when using S3 interop
51
+ attr_accessor :google_json_key_location # when using service accounts
52
+ attr_accessor :google_project # when using service accounts
48
53
 
49
54
  # Azure Blob with Fog::AzureRM
50
55
  attr_accessor :azure_storage_account_name
@@ -59,8 +64,11 @@ module AssetSync
59
64
  validates :aws_secret_access_key, :presence => true, :if => proc {aws? && !aws_iam?}
60
65
  validates :rackspace_username, :presence => true, :if => :rackspace?
61
66
  validates :rackspace_api_key, :presence => true, :if => :rackspace?
62
- validates :google_storage_secret_access_key, :presence => true, :if => :google?
63
- validates :google_storage_access_key_id, :presence => true, :if => :google?
67
+ validates :google_storage_secret_access_key, :presence => true, :if => :google_interop?
68
+ validates :google_storage_access_key_id, :presence => true, :if => :google_interop?
69
+ validates :google_json_key_location, :presence => true, :if => :google_service_account?
70
+ validates :google_project, :presence => true, :if => :google_service_account?
71
+ validates :concurrent_uploads, :inclusion => { :in => [true, false] }
64
72
 
65
73
  def initialize
66
74
  self.fog_region = nil
@@ -79,6 +87,9 @@ module AssetSync
79
87
  self.invalidate = []
80
88
  self.cache_asset_regexps = []
81
89
  self.include_manifest = false
90
+ self.concurrent_uploads = false
91
+ self.concurrent_uploads_max_threads = 10
92
+ self.remote_file_list_cache_file_path = nil
82
93
  @additional_local_file_paths_procs = []
83
94
 
84
95
  load_yml! if defined?(::Rails) && yml_exists?
@@ -130,6 +141,14 @@ module AssetSync
130
141
  fog_provider =~ /google/i
131
142
  end
132
143
 
144
+ def google_interop?
145
+ google? && google_json_key_location.nil?
146
+ end
147
+
148
+ def google_service_account?
149
+ google? && google_json_key_location
150
+ end
151
+
133
152
  def azure_rm?
134
153
  fog_provider =~ /azurerm/i
135
154
  end
@@ -159,10 +178,24 @@ module AssetSync
159
178
  @public_path || ::Rails.public_path
160
179
  end
161
180
 
181
+ def public_path=(path)
182
+ # Generate absolute path even when relative path passed in
183
+ # Required for generating relative sprockets manifest path
184
+ pathname = Pathname(path)
185
+ @public_path = if pathname.absolute?
186
+ pathname
187
+ elsif defined?(::Rails.root)
188
+ ::Rails.root.join(pathname)
189
+ else
190
+ Pathname(::Dir.pwd).join(pathname)
191
+ end
192
+ end
193
+
162
194
  def load_yml!
163
195
  self.enabled = yml["enabled"] if yml.has_key?('enabled')
164
196
  self.fog_provider = yml["fog_provider"]
165
197
  self.fog_host = yml["fog_host"]
198
+ self.fog_port = yml["fog_port"]
166
199
  self.fog_directory = yml["fog_directory"]
167
200
  self.fog_region = yml["fog_region"]
168
201
  self.fog_public = yml["fog_public"] if yml.has_key?("fog_public")
@@ -170,14 +203,17 @@ module AssetSync
170
203
  self.fog_scheme = yml["fog_scheme"]
171
204
  self.aws_access_key_id = yml["aws_access_key_id"]
172
205
  self.aws_secret_access_key = yml["aws_secret_access_key"]
206
+ self.aws_session_token = yml["aws_session_token"] if yml.has_key?("aws_session_token")
173
207
  self.aws_reduced_redundancy = yml["aws_reduced_redundancy"]
174
208
  self.aws_iam_roles = yml["aws_iam_roles"]
175
209
  self.aws_signature_version = yml["aws_signature_version"]
176
210
  self.rackspace_username = yml["rackspace_username"]
177
211
  self.rackspace_auth_url = yml["rackspace_auth_url"] if yml.has_key?("rackspace_auth_url")
178
212
  self.rackspace_api_key = yml["rackspace_api_key"]
179
- self.google_storage_secret_access_key = yml["google_storage_secret_access_key"]
180
- self.google_storage_access_key_id = yml["google_storage_access_key_id"]
213
+ self.google_json_key_location = yml["google_json_key_location"] if yml.has_key?("google_json_key_location")
214
+ self.google_project = yml["google_project"] if yml.has_key?("google_project")
215
+ self.google_storage_secret_access_key = yml["google_storage_secret_access_key"] if yml.has_key?("google_storage_secret_access_key")
216
+ self.google_storage_access_key_id = yml["google_storage_access_key_id"] if yml.has_key?("google_storage_access_key_id")
181
217
  self.existing_remote_files = yml["existing_remote_files"] if yml.has_key?("existing_remote_files")
182
218
  self.gzip_compression = yml["gzip_compression"] if yml.has_key?("gzip_compression")
183
219
  self.manifest = yml["manifest"] if yml.has_key?("manifest")
@@ -190,6 +226,9 @@ module AssetSync
190
226
  self.cdn_distribution_id = yml['cdn_distribution_id'] if yml.has_key?("cdn_distribution_id")
191
227
  self.cache_asset_regexps = yml['cache_asset_regexps'] if yml.has_key?("cache_asset_regexps")
192
228
  self.include_manifest = yml['include_manifest'] if yml.has_key?("include_manifest")
229
+ self.concurrent_uploads = yml['concurrent_uploads'] if yml.has_key?('concurrent_uploads')
230
+ self.concurrent_uploads_max_threads = yml['concurrent_uploads_max_threads'] if yml.has_key?('concurrent_uploads_max_threads')
231
+ self.remote_file_list_cache_file_path = yml['remote_file_list_cache_file_path'] if yml.has_key?('remote_file_list_cache_file_path')
193
232
 
194
233
  self.azure_storage_account_name = yml['azure_storage_account_name'] if yml.has_key?("azure_storage_account_name")
195
234
  self.azure_storage_access_key = yml['azure_storage_access_key'] if yml.has_key?("azure_storage_access_key")
@@ -222,8 +261,10 @@ module AssetSync
222
261
  :aws_access_key_id => aws_access_key_id,
223
262
  :aws_secret_access_key => aws_secret_access_key
224
263
  })
264
+ options.merge!({:aws_session_token => aws_session_token}) if aws_session_token
225
265
  end
226
266
  options.merge!({:host => fog_host}) if fog_host
267
+ options.merge!({:port => fog_port}) if fog_port
227
268
  options.merge!({:scheme => fog_scheme}) if fog_scheme
228
269
  options.merge!({:aws_signature_version => aws_signature_version}) if aws_signature_version
229
270
  options.merge!({:path_style => fog_path_style}) if fog_path_style
@@ -236,10 +277,14 @@ module AssetSync
236
277
  options.merge!({ :rackspace_region => fog_region }) if fog_region
237
278
  options.merge!({ :rackspace_auth_url => rackspace_auth_url }) if rackspace_auth_url
238
279
  elsif google?
239
- options.merge!({
240
- :google_storage_secret_access_key => google_storage_secret_access_key,
241
- :google_storage_access_key_id => google_storage_access_key_id
242
- })
280
+ if google_json_key_location
281
+ options.merge!({:google_json_key_location => google_json_key_location, :google_project => google_project})
282
+ else
283
+ options.merge!({
284
+ :google_storage_secret_access_key => google_storage_secret_access_key,
285
+ :google_storage_access_key_id => google_storage_access_key_id
286
+ })
287
+ end
243
288
  options.merge!({:region => fog_region}) if fog_region
244
289
  elsif azure_rm?
245
290
  require 'fog/azurerm'
@@ -340,7 +385,7 @@ module AssetSync
340
385
  end
341
386
 
342
387
  def to_bool
343
- !@value.nil?
388
+ !!@value
344
389
  end
345
390
  end
346
391
  end
@@ -17,11 +17,13 @@ module AssetSync
17
17
  config.fog_directory = ENV['FOG_DIRECTORY'] if ENV.has_key?('FOG_DIRECTORY')
18
18
  config.fog_region = ENV['FOG_REGION'] if ENV.has_key?('FOG_REGION')
19
19
  config.fog_host = ENV['FOG_HOST'] if ENV.has_key?('FOG_HOST')
20
+ config.fog_port = ENV['FOG_PORT'] if ENV.has_key?('FOG_PORT')
20
21
  config.fog_scheme = ENV['FOG_SCHEMA'] if ENV.has_key?('FOG_SCHEMA')
21
22
  config.fog_path_style = ENV['FOG_PATH_STYLE'] if ENV.has_key?('FOG_PATH_STYLE')
22
23
 
23
24
  config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID'] if ENV.has_key?('AWS_ACCESS_KEY_ID')
24
25
  config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] if ENV.has_key?('AWS_SECRET_ACCESS_KEY')
26
+ config.aws_session_token = ENV['AWS_SESSION_TOKEN'] if ENV.has_key?('AWS_SESSION_TOKEN')
25
27
  config.aws_signature_version = ENV['AWS_SIGNATURE_VERSION'] if ENV.has_key?('AWS_SIGNATURE_VERSION')
26
28
  config.aws_reduced_redundancy = ENV['AWS_REDUCED_REDUNDANCY'] == true if ENV.has_key?('AWS_REDUCED_REDUNDANCY')
27
29
 
@@ -41,6 +43,8 @@ module AssetSync
41
43
  config.gzip_compression = (ENV['ASSET_SYNC_GZIP_COMPRESSION'] == 'true') if ENV.has_key?('ASSET_SYNC_GZIP_COMPRESSION')
42
44
  config.manifest = (ENV['ASSET_SYNC_MANIFEST'] == 'true') if ENV.has_key?('ASSET_SYNC_MANIFEST')
43
45
  config.include_manifest = (ENV['ASSET_SYNC_INCLUDE_MANIFEST'] == 'true') if ENV.has_key?('ASSET_SYNC_INCLUDE_MANIFEST')
46
+ config.concurrent_uploads = (ENV['ASSET_SYNC_CONCURRENT_UPLOADS'] == 'true') if ENV.has_key?('ASSET_SYNC_CONCURRENT_UPLOADS')
47
+ config.remote_file_list_cache_file_path = ENV['ASSET_SYNC_REMOTE_FILE_LIST_CACHE_FILE_PATH'] if ENV.has_key?('ASSET_SYNC_REMOTE_FILE_LIST_CACHE_FILE_PATH')
44
48
  end
45
49
 
46
50
  config.prefix = ENV['ASSET_SYNC_PREFIX'] if ENV.has_key?('ASSET_SYNC_PREFIX')
@@ -11,9 +11,9 @@ module AssetSync
11
11
  end
12
12
 
13
13
  if defined?(::MIME::Types)
14
- ::MIME::Types.type_for(ext).first
14
+ ::MIME::Types.type_for(ext).first.to_s
15
15
  elsif defined?(::Mime::Type)
16
- ::Mime::Type.lookup_by_extension(ext)
16
+ ::Mime::Type.lookup_by_extension(ext).to_s
17
17
  elsif defined?(::Rack::Mime)
18
18
  ext_with_dot = ".#{ext}"
19
19
  ::Rack::Mime.mime_type(ext_with_dot)
@@ -37,6 +37,10 @@ module AssetSync
37
37
  self.config.public_path
38
38
  end
39
39
 
40
+ def remote_file_list_cache_file_path
41
+ self.config.remote_file_list_cache_file_path
42
+ end
43
+
40
44
  def ignored_files
41
45
  expand_file_names(self.config.ignored_files)
42
46
  end
@@ -58,6 +62,32 @@ module AssetSync
58
62
  (get_local_files + config.additional_local_file_paths).uniq
59
63
  end
60
64
 
65
+ def remote_files
66
+ return [] if ignore_existing_remote_files?
67
+ return @remote_files if @remote_files
68
+
69
+ if remote_file_list_cache_file_path && File.file?(remote_file_list_cache_file_path)
70
+ begin
71
+ content = File.read(remote_file_list_cache_file_path)
72
+ return @remote_files = JSON.parse(content)
73
+ rescue JSON::ParserError
74
+ warn "Failed to parse #{remote_file_list_cache_file_path} as json"
75
+ end
76
+ end
77
+
78
+ @remote_files = get_remote_files
79
+ end
80
+
81
+ def update_remote_file_list_cache(local_files_to_upload)
82
+ return unless remote_file_list_cache_file_path
83
+ return if ignore_existing_remote_files?
84
+
85
+ File.open(self.remote_file_list_cache_file_path, 'w') do |file|
86
+ uploaded = local_files_to_upload + remote_files
87
+ file.write(uploaded.to_json)
88
+ end
89
+ end
90
+
61
91
  def always_upload_files
62
92
  expand_file_names(self.config.always_upload) + get_manifest_path
63
93
  end
@@ -132,9 +162,15 @@ module AssetSync
132
162
  from_remote_files_to_delete = remote_files - local_files - ignored_files - always_upload_files
133
163
 
134
164
  log "Flagging #{from_remote_files_to_delete.size} file(s) for deletion"
135
- # Delete unneeded remote files
136
- bucket.files.each do |f|
137
- delete_file(f, from_remote_files_to_delete)
165
+ # Delete unneeded remote files, if we are on aws delete in bulk else use sequential delete
166
+ if self.config.aws? && connection.respond_to?(:delete_multiple_objects)
167
+ from_remote_files_to_delete.each_slice(500) do |slice|
168
+ connection.delete_multiple_objects(config.fog_directory, slice)
169
+ end
170
+ else
171
+ bucket.files.each do |f|
172
+ delete_file(f, from_remote_files_to_delete)
173
+ end
138
174
  end
139
175
  end
140
176
 
@@ -231,28 +267,38 @@ module AssetSync
231
267
  })
232
268
  end
233
269
 
234
- if config.azure_rm?
235
- # converts content_type from MIME::Type to String.
236
- # because Azure::Storage (called from Fog::AzureRM) expects content_type as a String like "application/json; charset=utf-8"
237
- file[:content_type] = file[:content_type].content_type if file[:content_type].is_a?(::MIME::Type)
238
- end
239
-
240
270
  bucket.files.create( file ) unless ignore
241
271
  file_handle.close
242
272
  gzip_file_handle.close if gzip_file_handle
243
273
  end
244
274
 
245
275
  def upload_files
246
- # get a fresh list of remote files
247
- remote_files = ignore_existing_remote_files? ? [] : get_remote_files
248
276
  # fixes: https://github.com/rumblelabs/asset_sync/issues/19
249
277
  local_files_to_upload = local_files - ignored_files - remote_files + always_upload_files
250
278
  local_files_to_upload = (local_files_to_upload + get_non_fingerprinted(local_files_to_upload)).uniq
251
-
252
- # Upload new files
253
- local_files_to_upload.each do |f|
254
- next unless File.file? "#{path}/#{f}" # Only files.
255
- upload_file f
279
+ # Only files.
280
+ local_files_to_upload = local_files_to_upload.select { |f| File.file? "#{path}/#{f}" }
281
+
282
+ if self.config.concurrent_uploads
283
+ jobs = Queue.new
284
+ local_files_to_upload.each { |f| jobs.push(f) }
285
+ jobs.close
286
+
287
+ num_threads = [self.config.concurrent_uploads_max_threads, local_files_to_upload.length].min
288
+ # Upload new files
289
+ workers = Array.new(num_threads) do
290
+ Thread.new do
291
+ while f = jobs.pop
292
+ upload_file(f)
293
+ end
294
+ end
295
+ end
296
+ workers.map(&:join)
297
+ else
298
+ # Upload new files
299
+ local_files_to_upload.each do |f|
300
+ upload_file f
301
+ end
256
302
  end
257
303
 
258
304
  if self.config.cdn_distribution_id && files_to_invalidate.any?
@@ -261,6 +307,8 @@ module AssetSync
261
307
  data = cdn.post_invalidation(self.config.cdn_distribution_id, files_to_invalidate)
262
308
  log "Invalidation id: #{data.body["Id"]}"
263
309
  end
310
+
311
+ update_remote_file_list_cache(local_files_to_upload)
264
312
  end
265
313
 
266
314
  def sync
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AssetSync
4
- VERSION = "2.6.0".freeze
4
+ VERSION = "2.12.1"
5
5
  end
@@ -35,6 +35,10 @@ module AssetSync
35
35
  "<%= ENV['AWS_SECRET_ACCESS_KEY'] %>"
36
36
  end
37
37
 
38
+ def aws_session_token
39
+ "<%= ENV['AWS_SESSION_TOKEN'] %>"
40
+ end
41
+
38
42
  def google_storage_access_key_id
39
43
  "<%= ENV['GOOGLE_STORAGE_ACCESS_KEY_ID'] %>"
40
44
  end
@@ -4,6 +4,7 @@ if defined?(AssetSync)
4
4
  config.fog_provider = 'AWS'
5
5
  config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
6
6
  config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
7
+ config.aws_session_token = ENV['AWS_SESSION_TOKEN'] if ENV.key?('AWS_SESSION_TOKEN')
7
8
  # To use AWS reduced redundancy storage.
8
9
  # config.aws_reduced_redundancy = true
9
10
  #
@@ -13,6 +14,9 @@ if defined?(AssetSync)
13
14
  # Change host option in fog (only if you need to)
14
15
  # config.fog_host = "s3.amazonaws.com"
15
16
  #
17
+ # Change port option in fog (only if you need to)
18
+ # config.fog_port = "9000"
19
+ #
16
20
  # Use http instead of https. Default should be "https" (at least for fog-aws)
17
21
  # config.fog_scheme = "http"
18
22
  <%- elsif google? -%>
@@ -60,6 +64,12 @@ if defined?(AssetSync)
60
64
  # Upload the manifest file also.
61
65
  # config.include_manifest = false
62
66
  #
67
+ # Upload files concurrently
68
+ # config.concurrent_uploads = false
69
+ #
70
+ # Path to cache file to skip scanning remote
71
+ # config.remote_file_list_cache_file_path = './.asset_sync_remote_file_list_cache.json'
72
+ #
63
73
  # Fail silently. Useful for environments such as Heroku
64
74
  # config.fail_silently = true
65
75
  #
@@ -13,6 +13,9 @@ defaults: &defaults
13
13
  # Change host option in fog (only if you need to)
14
14
  # fog_host: "s3.amazonaws.com"
15
15
  #
16
+ # Change port option in fog (only if you need to)
17
+ # config.fog_port = "9000"
18
+ #
16
19
  # Use http instead of https. Default should be "https" (at least for fog-aws)
17
20
  # fog_scheme: "http"
18
21
  <%- elsif google? -%>
@@ -0,0 +1,19 @@
1
+ defaults: &defaults
2
+ fog_provider: "Google"
3
+ google_json_key_location: 'gcs.json'
4
+ google_project: 'some-project'
5
+
6
+ development:
7
+ <<: *defaults
8
+ fog_directory: "rails_app_development"
9
+ existing_remote_files: keep
10
+
11
+ test:
12
+ <<: *defaults
13
+ fog_directory: "rails_app_test"
14
+ existing_remote_files: keep
15
+
16
+ production:
17
+ <<: *defaults
18
+ fog_directory: "rails_app_production"
19
+ existing_remote_files: delete
@@ -145,7 +145,7 @@ describe AssetSync do
145
145
 
146
146
  it "should default asset_regexps to match regexps" do
147
147
  expect(AssetSync.config.cache_asset_regexps).to eq(['cache_me.js', /cache_some\.\d{8}\.css/])
148
- end
148
+ end
149
149
  end
150
150
 
151
151
  describe 'from yml, exporting to a mobile hybrid development directory' do
@@ -255,12 +255,12 @@ describe AssetSync do
255
255
  expect(AssetSync.config.manifest_path).to match(/public\/custom_assets\/manifest.yml/)
256
256
  end
257
257
  end
258
-
258
+
259
259
  describe 'with cache_asset_regexps' do
260
260
  before(:each) do
261
261
  AssetSync.config = AssetSync::Config.new
262
262
  end
263
-
263
+
264
264
  it "config.cache_asset_regexp should set cache_asset_regexps" do
265
265
  AssetSync.config.cache_asset_regexp = /\.[a-f0-9]{8}/i
266
266
  expect(AssetSync.config.cache_asset_regexps.size).to eq(1)
@@ -283,4 +283,36 @@ describe AssetSync do
283
283
  expect{ AssetSync::Config.new }.to raise_error(Psych::SyntaxError)
284
284
  end
285
285
  end
286
+
287
+ describe 'FogPublicValue' do
288
+ describe "#to_bool" do
289
+ it "true should be converted to true" do
290
+ expect(AssetSync::Config::FogPublicValue.new(true).to_bool).to be_truthy
291
+ end
292
+ it "false should be converted to false" do
293
+ expect(AssetSync::Config::FogPublicValue.new(false).to_bool).to be_falsey
294
+ end
295
+ it "nil should be converted to false" do
296
+ expect(AssetSync::Config::FogPublicValue.new(nil).to_bool).to be_falsey
297
+ end
298
+ it "'default' should be converted to false" do
299
+ expect(AssetSync::Config::FogPublicValue.new("default").to_bool).to be_truthy
300
+ end
301
+ end
302
+
303
+ describe "#use_explicit_value?" do
304
+ it "true should be converted to true" do
305
+ expect(AssetSync::Config::FogPublicValue.new(true).use_explicit_value?).to be_truthy
306
+ end
307
+ it "false should be converted to true" do
308
+ expect(AssetSync::Config::FogPublicValue.new(false).use_explicit_value?).to be_truthy
309
+ end
310
+ it "nil should be converted to true" do
311
+ expect(AssetSync::Config::FogPublicValue.new(nil).use_explicit_value?).to be_truthy
312
+ end
313
+ it "'default' should be converted to false" do
314
+ expect(AssetSync::Config::FogPublicValue.new("default").use_explicit_value?).to be_falsey
315
+ end
316
+ end
317
+ end
286
318
  end
@@ -8,8 +8,6 @@ describe AssetSync do
8
8
  AssetSync.config = AssetSync::Config.new
9
9
  AssetSync.configure do |config|
10
10
  config.fog_provider = 'Google'
11
- config.google_storage_access_key_id = 'aaaa'
12
- config.google_storage_secret_access_key = 'bbbb'
13
11
  config.fog_directory = 'mybucket'
14
12
  config.existing_remote_files = "keep"
15
13
  end
@@ -24,14 +22,6 @@ describe AssetSync do
24
22
  expect(AssetSync.config.existing_remote_files?).to eq(true)
25
23
  end
26
24
 
27
- it "should configure google_storage_access_key_id" do
28
- expect(AssetSync.config.google_storage_access_key_id).to eq("aaaa")
29
- end
30
-
31
- it "should configure google_storage_secret_access_key" do
32
- expect(AssetSync.config.google_storage_secret_access_key).to eq("bbbb")
33
- end
34
-
35
25
  it "should configure fog_directory" do
36
26
  expect(AssetSync.config.fog_directory).to eq("mybucket")
37
27
  end
@@ -47,36 +37,119 @@ describe AssetSync do
47
37
  it "should default manifest to false" do
48
38
  expect(AssetSync.config.manifest).to be_falsey
49
39
  end
50
- end
51
40
 
52
- describe 'from yml' do
53
- before(:each) do
54
- set_rails_root('google_with_yml')
55
- AssetSync.config = AssetSync::Config.new
56
- end
41
+ describe "when using S3 interop API" do
42
+ before(:each) do
43
+ AssetSync.configure do |config|
44
+ config.google_storage_access_key_id = 'aaaa'
45
+ config.google_storage_secret_access_key = 'bbbb'
46
+ end
47
+ end
57
48
 
58
- it "should configure google_storage_access_key_id" do
59
- expect(AssetSync.config.google_storage_access_key_id).to eq("xxxx")
60
- end
49
+ it "should configure google_storage_access_key_id" do
50
+ expect(AssetSync.config.google_storage_access_key_id).to eq("aaaa")
51
+ end
61
52
 
62
- it "should configure google_storage_secret_access_key" do
63
- expect(AssetSync.config.google_storage_secret_access_key).to eq("zzzz")
64
- end
53
+ it "should configure google_storage_secret_access_key" do
54
+ expect(AssetSync.config.google_storage_secret_access_key).to eq("bbbb")
55
+ end
65
56
 
66
- it "should configure google_storage_access_key" do
67
- expect(AssetSync.config.fog_directory).to eq("rails_app_test")
57
+ it "should return the correct fog_options" do
58
+ expected_fog_options = { google_storage_access_key_id: "aaaa",
59
+ google_storage_secret_access_key: "bbbb",
60
+ provider: "Google"}
61
+ expect(AssetSync.config.fog_options).to eq(expected_fog_options)
62
+ end
63
+
64
+ it "should not require that google_json_key_location be set" do
65
+ expect(AssetSync.config.valid?).to eq(true)
66
+ end
67
+
68
+ it "should require that google_storage_secret_access_key or access_key_id be set" do
69
+
70
+ AssetSync.configure do |config|
71
+ config.google_storage_access_key_id = nil
72
+ config.google_storage_secret_access_key = nil
73
+ end
74
+
75
+ expect(AssetSync.config.valid?).to eq(false)
76
+ end
68
77
  end
69
78
 
70
- it "should configure google_storage_access_key" do
71
- expect(AssetSync.config.existing_remote_files).to eq("keep")
79
+ describe "when using service account" do
80
+ before(:each) do
81
+ AssetSync.configure do |config|
82
+ config.google_json_key_location = '/path/to.json'
83
+ config.google_project = 'a-google-project-name'
84
+ end
85
+ end
86
+
87
+ it "should configure google_json_key_location" do
88
+ expect(AssetSync.config.google_json_key_location).to eq("/path/to.json")
89
+ end
90
+
91
+ it "should return the correct fog_options" do
92
+ expected_fog_options = { google_json_key_location: "/path/to.json",
93
+ google_project: 'a-google-project-name',
94
+ provider: "Google"}
95
+ expect(AssetSync.config.fog_options).to eq(expected_fog_options)
96
+ end
97
+ it "should not require that google_storage_secret_access_key or access_key_id be set" do
98
+ expect(AssetSync.config.valid?).to eq(true)
99
+ end
72
100
  end
73
101
 
74
- it "should default gzip_compression to false" do
75
- expect(AssetSync.config.gzip_compression).to be_falsey
102
+ end
103
+
104
+ describe 'from yml' do
105
+ describe 'when using S3 interop API' do
106
+ before(:each) do
107
+ set_rails_root('google_with_yml')
108
+ AssetSync.config = AssetSync::Config.new
109
+ end
110
+
111
+ it "should configure google_storage_access_key_id" do
112
+ expect(AssetSync.config.google_storage_access_key_id).to eq("xxxx")
113
+ end
114
+
115
+ it "should configure google_storage_secret_access_key" do
116
+ expect(AssetSync.config.google_storage_secret_access_key).to eq("zzzz")
117
+ end
118
+
119
+ it "should not configure google_json_key_location" do
120
+ expect(AssetSync.config.google_json_key_location).to eq(nil)
121
+ end
122
+
123
+ it "should configure fog_directory" do
124
+ expect(AssetSync.config.fog_directory).to eq("rails_app_test")
125
+ end
126
+
127
+ it "should configure existing_remote_files" do
128
+ expect(AssetSync.config.existing_remote_files).to eq("keep")
129
+ end
130
+
131
+ it "should default gzip_compression to false" do
132
+ expect(AssetSync.config.gzip_compression).to be_falsey
133
+ end
134
+
135
+ it "should default manifest to false" do
136
+ expect(AssetSync.config.manifest).to be_falsey
137
+ end
76
138
  end
77
139
 
78
- it "should default manifest to false" do
79
- expect(AssetSync.config.manifest).to be_falsey
140
+ describe 'when using service account API' do
141
+ before(:each) do
142
+ set_rails_root('google_with_service_account_yml')
143
+ AssetSync.config = AssetSync::Config.new
144
+ end
145
+
146
+ it "should configure google_json_key_location" do
147
+ expect(AssetSync.config.google_json_key_location).to eq("gcs.json")
148
+ end
149
+
150
+ it "should not configure google_storage_secret_access_key" do
151
+ expect(AssetSync.config.google_storage_secret_access_key).to eq(nil)
152
+ end
80
153
  end
81
154
  end
82
155
 
@@ -14,7 +14,7 @@ describe AssetSync do
14
14
  config.fog_region = 'eu-west-1'
15
15
  config.existing_remote_files = "keep"
16
16
  config.prefix = "assets"
17
- config.public_path = Pathname("./public")
17
+ config.public_path = "./public"
18
18
  end
19
19
  end
20
20
 
@@ -22,8 +22,9 @@ describe AssetSync do
22
22
  expect(AssetSync.config.prefix).to eq("assets")
23
23
  end
24
24
 
25
- it "should have prefix of assets" do
26
- expect(AssetSync.config.public_path.to_s).to eq("./public")
25
+ it "should have public_path" do
26
+ expect(AssetSync.config.public_path.to_s).to be_end_with("/public")
27
+ expect(AssetSync.config.public_path).to be_absolute
27
28
  end
28
29
 
29
30
  it "should default AssetSync to enabled" do
@@ -54,6 +54,87 @@ describe AssetSync::Storage do
54
54
  storage.upload_files
55
55
  end
56
56
 
57
+ it 'should upload files concurrently if enabled' do
58
+ @config.concurrent_uploads = true
59
+ storage = AssetSync::Storage.new(@config)
60
+
61
+ allow(storage).to receive(:get_local_files).and_return(@local_files)
62
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
63
+ allow(File).to receive(:file?).and_return(true) # Pretend they all exist
64
+
65
+ expect(Thread).to receive(:new).exactly(3).times.and_call_original
66
+ (@local_files - @remote_files + storage.always_upload_files).each do |file|
67
+ expect(storage).to receive(:upload_file).with(file)
68
+ end
69
+
70
+ storage.upload_files
71
+ end
72
+
73
+ it 'should allow custom number of threads' do
74
+ @config.concurrent_uploads = true
75
+ @config.concurrent_uploads_max_threads = 2
76
+ storage = AssetSync::Storage.new(@config)
77
+
78
+ allow(storage).to receive(:get_local_files).and_return(@local_files)
79
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
80
+ allow(File).to receive(:file?).and_return(true) # Pretend they all exist
81
+
82
+ expect(Thread).to receive(:new).exactly(2).times.and_call_original
83
+ (@local_files - @remote_files + storage.always_upload_files).each do |file|
84
+ expect(storage).to receive(:upload_file).with(file)
85
+ end
86
+
87
+ storage.upload_files
88
+ end
89
+
90
+ it 'should allow remote_file_list_cache_file_path configuration' do
91
+ file_path = './foo.json'
92
+ @config.remote_file_list_cache_file_path = file_path
93
+ storage = AssetSync::Storage.new(@config)
94
+
95
+ allow(storage).to receive(:get_local_files).and_return(@local_files)
96
+ File.write(file_path, @remote_files.to_json)
97
+ expect(storage).not_to receive(:get_remote_files)
98
+ allow(File).to receive(:file?).and_return(true) # Pretend they all exist
99
+
100
+ (@local_files - @remote_files + storage.always_upload_files).each do |file|
101
+ expect(storage).to receive(:upload_file).with(file)
102
+ end
103
+
104
+ expect(storage).not_to receive(:warn)
105
+ storage.upload_files
106
+
107
+ # update remote_file_list_cache corretly
108
+ updated = JSON.parse(File.read(file_path))
109
+ expect(updated.sort.uniq).to eq (@remote_files + @local_files + storage.always_upload_files).sort.uniq
110
+
111
+ File.delete(file_path)
112
+ end
113
+
114
+ it 'should work with broken cache' do
115
+ file_path = './foo.json'
116
+ @config.remote_file_list_cache_file_path = file_path
117
+
118
+ storage = AssetSync::Storage.new(@config)
119
+
120
+ File.write(file_path, 'some non-json text file content')
121
+
122
+ allow(storage).to receive(:get_local_files).and_return(@local_files)
123
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
124
+ allow(File).to receive(:file?).and_return(true) # Pretend they all exist
125
+
126
+ (@local_files - @remote_files + storage.always_upload_files).each do |file|
127
+ expect(storage).to receive(:upload_file).with(file)
128
+ end
129
+
130
+ # when broken, warning message should be prompted
131
+ expect(storage).to receive(:warn)
132
+
133
+ storage.upload_files
134
+
135
+ File.delete(file_path)
136
+ end
137
+
57
138
  it 'should upload updated non-fingerprinted files' do
58
139
  @local_files = [
59
140
  'public/image.png',
@@ -125,7 +206,7 @@ describe AssetSync::Storage do
125
206
  end
126
207
  end
127
208
 
128
- it 'should upload additonal files' do
209
+ it 'should upload additonal files' do
129
210
  @local_files = [
130
211
  'public/image.png',
131
212
  'public/image-82389298328.png',
@@ -307,4 +388,59 @@ describe AssetSync::Storage do
307
388
  storage.upload_file('assets/some_longer_path/local_image2.jpg')
308
389
  end
309
390
  end
391
+
392
+ describe '#delete_extra_remote_files' do
393
+ it 'should delete the files in bulk' do
394
+ remote_files = ['public/image.png']
395
+ connection = double
396
+ config = double
397
+
398
+ storage = AssetSync::Storage.new(@config)
399
+
400
+ [:local_files, :ignored_files, :always_upload_files].each do |method|
401
+ expect(storage).to receive(method).and_return([])
402
+ end
403
+
404
+ allow(storage).to receive(:get_remote_files).and_return(remote_files)
405
+ allow(storage).to receive(:connection).and_return(connection).twice
406
+ allow(storage).to receive(:config).and_return(config).twice
407
+ allow(config).to receive(:aws?).and_return(true)
408
+ allow(config).to receive(:fog_directory).and_return('foo')
409
+ expect(connection).to receive(:delete_multiple_objects).with('foo', remote_files)
410
+
411
+ storage.delete_extra_remote_files
412
+ end
413
+
414
+ context 'when not aws' do
415
+ it 'deletes files sequentially' do
416
+ remote_files = ['public/image.png']
417
+ connection = double
418
+ config = double
419
+ directories = double
420
+ directory = double
421
+ file = double
422
+
423
+ storage = AssetSync::Storage.new(@config)
424
+
425
+ [:local_files, :ignored_files, :always_upload_files].each do |method|
426
+ expect(storage).to receive(method).and_return([])
427
+ end
428
+
429
+ allow(storage).to receive(:get_remote_files).and_return(remote_files)
430
+ allow(storage).to receive(:connection).and_return(connection).twice
431
+ allow(storage).to receive(:config).and_return(config)
432
+ allow(config).to receive(:aws?).and_return(false)
433
+ allow(config).to receive(:fog_directory).and_return('foo')
434
+ allow(config).to receive(:assets_prefix).and_return('foo')
435
+ allow(directories).to receive(:get).and_return(directory)
436
+ allow(directory).to receive(:files).and_return([file])
437
+ allow(file).to receive(:key).and_return('public/image.png')
438
+ allow(connection).to receive(:directories).and_return(directories)
439
+ expect(connection).not_to receive(:delete_multiple_objects)
440
+ expect(file).to receive(:destroy)
441
+
442
+ storage.delete_extra_remote_files
443
+ end
444
+ end
445
+ end
310
446
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asset_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.0
4
+ version: 2.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Hamilton
8
8
  - David Rice
9
9
  - Phil McClure
10
10
  - Toby Osbourn
11
- autorequire:
11
+ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2018-12-07 00:00:00.000000000 Z
14
+ date: 2020-06-17 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: fog-core
@@ -203,10 +203,10 @@ files:
203
203
  - UPGRADING.md
204
204
  - asset_sync.gemspec
205
205
  - docs/heroku.md
206
- - gemfiles/rails_4_2.gemfile
207
206
  - gemfiles/rails_5_0.gemfile
208
207
  - gemfiles/rails_5_1.gemfile
209
208
  - gemfiles/rails_5_2.gemfile
209
+ - gemfiles/rails_6_0.gemfile
210
210
  - lib/asset_sync.rb
211
211
  - lib/asset_sync/asset_sync.rb
212
212
  - lib/asset_sync/config.rb
@@ -223,6 +223,7 @@ files:
223
223
  - spec/dummy_app/app/assets/javascripts/application.js
224
224
  - spec/fixtures/aws_with_yml/config/asset_sync.yml
225
225
  - spec/fixtures/azure_rm_with_yml/config/asset_sync.yml
226
+ - spec/fixtures/google_with_service_account_yml/config/asset_sync.yml
226
227
  - spec/fixtures/google_with_yml/config/asset_sync.yml
227
228
  - spec/fixtures/rackspace_with_yml/config/asset_sync.yml
228
229
  - spec/fixtures/with_invalid_yml/config/asset_sync.yml
@@ -240,7 +241,7 @@ homepage: https://github.com/rumblelabs/asset_sync
240
241
  licenses:
241
242
  - MIT
242
243
  metadata: {}
243
- post_install_message:
244
+ post_install_message:
244
245
  rdoc_options: []
245
246
  require_paths:
246
247
  - lib
@@ -255,9 +256,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
255
256
  - !ruby/object:Gem::Version
256
257
  version: '0'
257
258
  requirements: []
258
- rubyforge_project: asset_sync
259
- rubygems_version: 2.7.8
260
- signing_key:
259
+ rubygems_version: 3.1.4
260
+ signing_key:
261
261
  specification_version: 4
262
262
  summary: Synchronises Assets in a Rails 3 application and Amazon S3/Cloudfront and
263
263
  Rackspace Cloudfiles
@@ -266,6 +266,7 @@ test_files:
266
266
  - spec/dummy_app/app/assets/javascripts/application.js
267
267
  - spec/fixtures/aws_with_yml/config/asset_sync.yml
268
268
  - spec/fixtures/azure_rm_with_yml/config/asset_sync.yml
269
+ - spec/fixtures/google_with_service_account_yml/config/asset_sync.yml
269
270
  - spec/fixtures/google_with_yml/config/asset_sync.yml
270
271
  - spec/fixtures/rackspace_with_yml/config/asset_sync.yml
271
272
  - spec/fixtures/with_invalid_yml/config/asset_sync.yml