pax_global_header00006660000000000000000000000064136325620630014520gustar00rootroot0000000000000052 comment=ce3646e7a8469d39a8e913b789fe99dd016d245d asset_sync-2.11.0/000077500000000000000000000000001363256206300137545ustar00rootroot00000000000000asset_sync-2.11.0/.editorconfig000066400000000000000000000007041363256206300164320ustar00rootroot00000000000000# EditorConfig is awesome: http://EditorConfig.org # top-most EditorConfig file root = true # default configuration [*] indent_style = space indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true # Unix-style newlines with a newline ending every file end_of_line = lf # Set default charset charset = utf-8 # Tab indentation (no size specified) [Makefile] indent_style = tab [*.{md,markdown}] trim_trailing_whitespace = false asset_sync-2.11.0/.gitignore000066400000000000000000000002451363256206300157450ustar00rootroot00000000000000.DS_Store *.gem .bundle Gemfile.lock pkg/* *.swp coverage/* .env spec/dummy_app/public/* spec/dummy_app/log/* spec/dummy_app/tmp/* .rbx gemfiles/*.lock .rvmrc .idea asset_sync-2.11.0/.travis.yml000066400000000000000000000026721363256206300160740ustar00rootroot00000000000000# Send builds to container-based infrastructure # http://docs.travis-ci.com/user/workers/container-based-infrastructure/ sudo: false language: ruby cache: bundler: true rvm: - 2.3 - 2.4 - 2.5 - 2.6 - 2.7 - ruby-head - jruby - jruby-head gemfile: - gemfiles/rails_5_0.gemfile - gemfiles/rails_5_1.gemfile - gemfiles/rails_5_2.gemfile - gemfiles/rails_6_0.gemfile before_install: # Cannot use bundler 2.x due to dependency (mainly rails 4.2) # Solution from https://github.com/rails/rails/blob/4-2-stable/.travis.yml - "travis_retry gem update --system --no-doc || travis_retry gem update --system --no-rdoc --no-ri" - "travis_retry gem install bundler -v '<2'" env: global: - FOG_DIRECTORY=asset-sync-travis - FOG_PROVIDER=AWS - secure: "dy8Fqlg3b1ZMK1BY5z6NMQLbzAVd7GWVYY0MeCQALz76zRac0z8MyU8hkv6h\nozFry7DSdbGehGT9foOnkWTwzGzf1rzdd5cmWrUPk1wDTRgMM9SrwodPj1TU\nzsq2EFx0a79vADQN8JXkpLC1YD6kEb9aWkTxrIT9KBgw+J5H32o=" - secure: "Hmx7D7/p2LlA2ya/xBIz21s/8MLIQCjvfYB7RWBNlWk1PfqRLAz8wX6TUVWy\nfAFktMjLnpRLRYO7AgQS4jcfQ/k0HYK9IXzqXzeI00TNm0Vwp0TCXhawiOFT\nSvUMhs2/1vRfjN0HOJ75XlWRhJzV/G5rOMiafAZLsVzN/0iiB8g=" matrix: fast_finish: true allow_failures: - rvm: ruby-head - rvm: jruby-head exclude: - rvm: 2.3 gemfile: gemfiles/rails_6_0.gemfile - rvm: 2.4 gemfile: gemfiles/rails_6_0.gemfile notifications: webhooks: urls: - https://www.travisbuddy.com/ on_success: never asset_sync-2.11.0/Appraisals000066400000000000000000000003341363256206300157760ustar00rootroot00000000000000 appraise "rails_5_0" do gem "rails", "~> 5.0.0" end appraise "rails_5_1" do gem "rails", "~> 5.1.0" end appraise "rails_5_2" do gem "rails", "~> 5.2.0" end appraise "rails_6_0" do gem "rails", "~> 6.0.0" end asset_sync-2.11.0/CHANGELOG.md000066400000000000000000000672161363256206300156010ustar00rootroot00000000000000# Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added - Nothing ### Changed - Nothing ### Fixed - Nothing ## [2.11.0] - 2020-03-13 ### Added - Add option `remote_file_list_cache_file_path` to skip scanning remote (https://github.com/AssetSync/asset_sync/pull/400) ## [2.10.0] - 2020-02-26 ### Added - Add option `concurrent_uploads_max_threads` to limit number of threads for uploading files (https://github.com/AssetSync/asset_sync/pull/398) ## [2.9.1] - 2020-02-20 ### Fixed - Fix uploading of sprockets manifest file (https://github.com/AssetSync/asset_sync/pull/397) ## [2.9.0] - 2020-01-15 ### Added - Add option `concurrent_uploads` to improve speed of uploading (https://github.com/AssetSync/asset_sync/pull/393) ## [2.8.2] - 2019-12-27 ### Changed - Use `delete_multiple_objects` when storage is `aws` (https://github.com/AssetSync/asset_sync/pull/392) ## [2.8.1] - 2019-07-25 ### Changed - Removed `rubyforge_project` from gemspec (https://github.com/AssetSync/asset_sync/pull/386) ### Fixed - Fixed when `fog_public` set to `false`, file were still set to be public (https://github.com/AssetSync/asset_sync/pull/387) ## [2.8.0] - 2019-06-17 ### Added - Add option `fog_port` (https://github.com/AssetSync/asset_sync/pull/385) ## [2.7.0] - 2019-03-15 ### Added - Adds JSON API support when using Google Storage (https://github.com/AssetSync/asset_sync/pull/381) ### Changed - Update `AssetSync::MultiMime.lookup` to always return strings (kind of internal change) (https://github.com/AssetSync/asset_sync/pull/380) ## [2.6.0] - 2018-12-07 ### Added - Add option `fog_public` (https://github.com/AssetSync/asset_sync/pull/377) ## [2.5.0] - 2018-10-25 ### Added - Add ruby only option `file_ext_to_mime_type_overrides` (https://github.com/AssetSync/asset_sync/pull/374) ### Changed - Start testing against rails 5.2, stop testing against rails 4.1 ### Fixed - Only enhance rake task assets:precompile if it's defined (https://github.com/AssetSync/asset_sync/commit/e1eb1a16b06fd39def1759428a2d94733915bbff) - Avoid ruby warning due to "method redefined" (https://github.com/AssetSync/asset_sync/pull/371) ## [2.4.0] - 2017-12-20 ### Added - Add support for Azure Blob storage (https://github.com/AssetSync/asset_sync/pull/363) - Add option: `include_manifest` (https://github.com/AssetSync/asset_sync/pull/365) ### Changed - Add public API method `get_asset_files_from_manifest` split from `get_local_files` for another gem (https://github.com/AssetSync/asset_sync/pull/366) ### Fixed - Nothing ## [2.3.0] - 2017-12-05 ### Added - Add options: `aws_signature_version`, `fog_host`, `fog_scheme` (https://github.com/AssetSync/asset_sync/pull/362) ### Changed - Change initializer template to only run when AssetSync const defined ## [2.2.0] - 2017-07-12 ### Added - Add method `add_local_file_paths` to config for uploading additional files, like webpacker (https://github.com/AssetSync/asset_sync/pull/347) ### Changed - Nothing ### Fixed - Fix too many files open when uploading local files (https://github.com/AssetSync/asset_sync/pull/351) ## [2.1.0] - 2017-05-19 ### Added - Allow customization of regexp of files on target bucket to be marked as 'Cacheable' so that browsers when serving the content would cache them. The value can be set by `cache_asset_regexps` ### Changed - Only support mime-type >= 2.99, which is released at the end of 2015 - Only support activemodel >= 4.1, which is released in 2014 ## [2.0.0] - 2016-12-21 ### Changed - [BREAKING] require “fog-core” instead of “fog” as runtime requirement ## [1.3.0] - 2016-11-30 ### Changed - Add regex support to always_upload (https://github.com/AssetSync/asset_sync/pull/333) - Stop failing sliently when YAML file does not contain key for rails environment (https://github.com/AssetSync/asset_sync/pull/270) - Stop failing sliently when YAML file cannot be parsed due to syntax error ## [1.2.1] - 2016-08-19 ### Fixed - Respect value of option `log_silently` even when `ENV['RAILS_GROUPS'] == 'assets'` ## [1.2.0] - 2016-08-17 ### Added - Support for `fog_path_style` config option (AWS only) (https://github.com/AssetSync/asset_sync/pull/302) ### Changed - Set Expires and Cache-Control headers for .gz files (https://github.com/AssetSync/asset_sync/pull/329) ### Fixed - Add missing runtime dependency declaration for `mime-types` to gemspec (https://github.com/AssetSync/asset_sync/pull/328) - Update outdated error message for unknown AssetSync provider (https://github.com/AssetSync/asset_sync/pull/298) - Allow hash digest in file name with over 32 chars (for sprockets 3+) (https://github.com/AssetSync/asset_sync/pull/315) - Fix `config.log_silently?` (https://github.com/AssetSync/asset_sync/pull/324) - Stop using deprecated Ruby API (https://github.com/AssetSync/asset_sync/pull/276) ## v1.1.0 / 2014-08-13 Version 1.1.0 (Toby Osbourn ) Changes: * 1 Change * Bumping master to 1.1.0 - preparing to update RubyGems ## v0.5.6 / 2014-08-12 Version 0.5.6 (Toby Osbourn ) Changes: * 1 Change * Merged in support for optimized fog loading ## v0.5.5 / 2014-08-12 Version 0.5.5 (Toby Osbourn ) Changes: * 2 Nominal Changes * Merged some spec changes to get Travis to pass the build correctly * Support using AWS IAM Roles ## v0.5.1 / 2012-10-22 Version 0.5.1 (David Rice ) Changes: * 5 Nominal Changes * Add a CHANGELOG.md (as generated by vclog -r -f markdown * Improve documentation on ignored_files config option * Allow failure of specs against ruby-head and jruby-head * Merge pull request #115 from demirhanaydin/patch-1 * Merge support for always providing mime_type #93 from patdeegan/master ## v0.5.0 / 2012-08-23 Version 0.5.0 (David Rice ) Changes: * 8 Nominal Changes * Merge branch 'sinatra' of github.com:rumblelabs/asset_sync into sinatra * Version 0.5.0, sinatra / rack support * Some refactoring to further remove dependency on Rails, add spec for railsless configuration * Update readme. * Add public_path and prefix config options so asset_sync can be used outside Rails. * Some refactoring to further remove dependency on Rails, add spec for railsless configuration * Merge branch 'ejholmes/sinatra' into sinatra * Version 0.4.3, removed dependency on Rails Time additions ## v0.4.3 / 2012-08-19 Version 0.4.3 (David Rice ) Changes: * 21 Nominal Changes * Refactor cache control and expiry hearder definition to use same value of one year * Merge pull request #94 from karlfreeman/time Remove Rails time dependency * Allow failures in ruby-head * Merge pull request #88 from potomak/patch-1 Fix defined? syntax * Merge pull request #95 from bbhoss/patch-1 Fix syntax error in documentation * Describe using S3 HTTPS better * Fix syntax error * remove Rails time dependency * Update readme. * Add public_path and prefix config options so asset_sync can be used outside Rails. * Fix defined? syntax * Force build on travis * Get specs running under jruby and travis /cc @headius :) * Ignore ds_store * Add jruby-openssl gem to get tests passing on jruby * test all the things * Add travis config for rbx * Merge branch 'master' of github.com:rumblelabs/asset_sync * Update README for installing on heroku, labs is no-longer a plugin * Merge pull request #75 from mscottford/master Update asset_host configuration in README to not rely on request object * Version 0.4.2, allow configuration of an array of strings or regex for files to ignore uploading. #euruko ## v0.4.2 / 2012-06-02 Version 0.4.2 (David Rice ) Changes: * 7 Nominal Changes * Remove errant puts from spec * Merge * Add option to configure ignored_files through YAML config file * Removes errant end in the asset_host config example. * Updates README to suggest a different asset_host configuration The previous version will fail in some cases because a request is not always available during asset compilation. * Fix Fog warnings when running specs. * Version 0.4.1, allow programatic disabling of AssetSync.config.enabled ## v0.4.1 / 2012-05-04 Version 0.4.1 (David Rice ) Changes: * 10 Nominal Changes * Update docs * Don't default to disabled if ASSET_SYNC_ENABLED env var is not specified. * Add option to ignore files * Add support for ASSET_SYNC_ENABLED with env vars. * Oops, should have used the accessor * Add support for enabled in the yaml config. * Add specs for AssetSync.enabled? configured through the initializer. * Make it possible to turn off AssetSync... Useful when precompiling to export to a hybrid mobile app such as PhoneGap. Would fix issue #66. * How many times will I forget to update the release date? many * Version 0.4.0, google storage support. Allow force upload of all or selected files. Travis CI enabled ## v0.4.0 / 2012-04-26 Version 0.4.0 (David Rice ) Changes: * 22 Nominal Changes * Add google storage options to built in initializer to allow config via ENV vars * Add google storage configuration to README * fix case on google provider in generator * added google storage tests * added google storage generators * add attr_accessor for google keys * add support for fog gems google storage option * Oh, travisci will build an orgs repos if you configure the webhookd. Use rumblelabs/asset_sync as build status * Merge branch 'master' into levent/feature/overwrite_specific_remote_files * Use my travis-ci build in README * Merge pull request #69 from levent/integrate_travis Integrate Travis CI * Merge branch 'integrate_travis' into feature/overwrite_specific_remote_files * Specs for uploading assets * Travis build logo * Setting up for Travis * Updated README * always_upload config option added * gitignore *.swp (for vim) * Add ability to ignore remote files * Correct name of specs * Allows specifying an array of assets to always upload to remote * Version 0.3.2, set content encoding header for .gz files ## v0.3.2 / 2012-04-18 Version 0.3.2 (David Rice ) Changes: * 11 Nominal Changes * Remove trailing comma * Merge pull request #57 from nathanhumbert/master Set Content-Encoding for gzip files when config.gzip? is not true * Merge pull request #59 from kamui/master Use Rails.public_path and Pathname#join for path concat and string interpolation * Merge pull request #55 from manuelmeurer/patch-1 Remove comments taken from another gem * Dir.chdir to path first to avoid a map call and path string slicing * add Rails.public_path stub and make Rails.root return Pathname class to match Rails behavior * Rails.root returns a Pathname, use Pathname#join instead of File.join and string interpolation * use Rails.public_path instead of concat Rails.root and 'public' * Set Content-Encoding for gzip files when config.gzip? is not true This allows a S3 bucket served via CloudFront to properly handle the Accept-Encoding request header. * Remove comments taken from another gem * Merge branch 'master' of github.com:rumblelabs/asset_sync ## v0.3.1 / 2012-03-07 Version 0.3.1 (David Rice ) Changes: * 6 Nominal Changes * Version 0.3.1, improve logging of asset_sync configuration and sync events * Remove some debugging stuffs * Improve logging during asset_sync progress. * Separate log and warn message, should not mess up heroku precompile thread as it watches STDERR for output. * Improve logging, only log to STDERR if RAILS_GROUPS=assets. * Version 0.3.0, all configuration can be managed via env variables, improve docs on configuration ## v0.3.0 / 2012-03-07 Version 0.3.0 (David Rice ) Changes: * 10 Nominal Changes * Merge pull request #50 from hampei/master made gzip_compression settable via ENV * namespaced the ENV gzip option: ASSET_SYNC_GZIP_COMPRESSION. added option to readme * made gzip_compression settable via ENV * Typo * Improve documentation * Version 0.2.12, fix the asset_sync rake task enhancement in Rails 3.2 (still supporting earlier releases) * Turns out this was an issue with Rails handling of the config.assets.digest parameter * When running rake assets:precompile this config variable is modified by Rails * So it therefore cannot be depended on to test wether to enhance the nondigest task or not * The solution is to always enhance assets:precompile:nondigest if it exists. ## v0.2.9 / 2012-01-30 Version 0.2.9 (David Rice ) Changes: * 3 Nominal Changes * Merge pull request #42 from genuitytech/master Now correctly setting config.fog_region. * Now correctly setting config.fog_region. * Version 0.2.8, improve http headers. Add far future expires and cache control, public. ## v0.2.8 / 2012-01-27 Version 0.2.8 (David Rice ) Changes: * 2 Nominal Changes * Add far future expires header * Version 0.2.7, Rails 3.2 compatibility, default Rake task improved ## v0.2.7 / 2012-01-25 Version 0.2.7 (David Rice ) Changes: * 2 Nominal Changes * Merge branch 'rails-3-2' * Version 0.2.6, Rails 3.2 compatibility, default Rake task improved ## v0.2.6 / 2012-01-25 Version 0.2.6 (David Rice ) Changes: * 3 Nominal Changes * Doc * Add Rails 3.2 compatible rake task * Fix issue #38 for when Rails.config.assets.prefix starts with a slash. ## v0.2.5 / 2012-01-10 Version 0.2.5 (David Rice ) Changes: * 1 Nominal Changes * Version 0.2.4, Support for Rails.config.assets.prefix ## v0.2.4 / 2012-01-06 Version 0.2.4 (David Rice ) Changes: * 5 Nominal Changes * Merge pull request #35 from siliconsalad/config_assets_prefix Rails.config.assets.prefix used for sync * added test with Rails.config.assets.prefix set * Rails.config.assets.prefix used for sync (instead of hardcoded 'assets' value) * specs now use shared context to mock Rails and fixed pending tests that were failing * Version 0.2.3, Rackspace London support ## v0.2.3 / 2011-12-06 Version 0.2.3 (David Rice ) Changes: * 3 Nominal Changes * Merge pull request #28 from robink/master Rackspace London support * Only merge racksace_auth_url to fog config if defined * Bump date for release ## v0.2.2 / 2011-11-29 Version 0.2.2 (David Rice ) Changes: * 10 Nominal Changes * Version 0.2.2: add fail_silently config option to avoid heroku installing the rails31_enable_runtime_asset_compilation, fixes issues #24, #29 * Further explanation of fail_silently option * Merge pull request #29 from neilmiddleton/master Allow precompile to fail quietly on heroku * Update README, and generator templates * Changes as discussed in PR#29 * Disable pre-compilation on Heroku. * Updated README and generators * Added support for specifying rackspace_auth_url (then the possibility to use Rackspace London) * Fixed typo in readme * Updated version and release date ## v0.2.12 / 2012-03-04 Version 0.2.12 (David Rice ) Changes: * 1 Nominal Changes * Version 0.2.11, minor fix to YAML loading and improved docs ## v0.2.11 / 2012-03-04 Version 0.2.11 (David Rice ) Changes: * 7 Nominal Changes * Merge pull request #48 from samsoffes/patch-1 Fix Heroku Labs plugin URL and add code coloring to readme. * Fix Heroku Labs plugin URL and add code coloring to readme. * Merge pull request #47 from dbalatero/dont_read_yml_file_every_time Cache the YML config to avoid multiple file reads. * Cache the YML config to avoid multiple file reads. * Fix documentation typos * Move old known issues about heroku ENV variables to a docs folder, write new content referencing the recommended use of user_env_compile * Version 0.2.10, fix handling of non standard Rails.config.assets.manifest path ## v0.2.10 / 2012-02-16 Version 0.2.10 (David Rice ) Changes: * 5 Nominal Changes * Add an AssetSync.log method for outputing sync config failure so we can stub it out easily in tests * Merge pull request #44 from dbalatero/fix_nonstandard_manifest_location Fixes asset_sync to correctly read manifest.yml files. * Fixes asset_sync to correctly read manifest.yml files. Rails.config.assets.manifest only points to the directory that contains the manifest.yml file: https://github.com/rails/rails/blob/226783d1e8891a38d4a61017952528970dba903d/actionpack/lib/sprockets/railtie.rb#L36 * Add hack, seems required for some applications on push to Heroku, not for others * Version 0.2.9 fix bug in internal initializer ## v0.2.1 / 2011-11-21 Version 0.2.1 (Phil ) Changes: * 4 Nominal Changes * Only configure with ENV vars if initializer and yml file do not exist * Typo in yaml, underscore need not be escaped here * Fix readme * Version 0.2.0 ## v0.2.0 / 2011-11-15 Version 0.2.0 (David Rice ) Changes: * 15 Nominal Changes * Add upgrade notice to README * Use fog directory * Merge * Fix readme * Tidy readme * Get AWS or Rackspace generators working correctly * Remove generated rake task, no need * Improve generators to generate AWS or Rackspace compatible initializer or yml * Prepare 0.2.0 for release * Convert readme and generators to new config options * Fix fog_options * Fix typo * Fix bug * Working on migrating the exposed config variables to reflect fog, add in a start on rackspace support. Write more specs, tidy up and document config * Add specs for manifest config ## v0.1.9 / 2011-11-06 Version 0.1.9 (David Rice ) Changes: * 37 Nominal Changes * Document gzip compression * Add note about gzip_compression * Add spec to test config defaults gzip_compression to false * Add gzip compression info to generated asset_sync.rb or .yml. Fix .yml example with new config settings * Update gemspec * Update docs to note that rake task is no longer generated within the app. * Add todo * Add % symbol for clarity * Output % savings when uploading gzipped files. Only use gzipped files if the compressed version is actually smaller than the original. * Tidy readme * Get AWS or Rackspace generators working correctly * Remove generated rake task, no need * Improve generators to generate AWS or Rackspace compatible initializer or yml * Prepare 0.2.0 for release * Convert readme and generators to new config options * Fix fog_options * Fix bug * Fix typo * Working on migrating the exposed config variables to reflect fog, add in a start on rackspace support. Write more specs, tidy up and document config * Add spec for gzip? config method * Reorder logic to execute quicker if gzip? compression disabled and ignore .gz uploads correctly * Ignore .gz assets if we are in gzip_compression mode * Do not set a Vary: Accept-Encoding header, S3 does not support at all * Try setting vary header a different way * Set http header Vary: Accept-Encoding when storing gzipped assets to S3 * Add todo * Refactor to computed path * Add path * Instead of overwriting the original file when processing the .gz, overwrite the original if a gz file exists to avoid any issues with whichever order files are processed in * Bump version (no release just yet) * Only handle gzip files specially if we have configured gzip_compression * Overwrite original files with gzipped equivalent, improve logging to show GZIP in action, make it a configurable option, config.gzip_compression that defaults to false * Upload GZIP compressed assets nicely to S3 with correct content type and encoding. * Refactor upload method to make enhancing nicer * Merge pull request #12 from bobbrez/master Minor correction to README for generated YAML file path. * Correcting location of generated yml in README * Comment out unnecessary logic for now ## v0.1.8 / 2011-10-17 Version 0.1.8 (David Rice ) Changes: * 4 Nominal Changes * Don't log any debugging info v0.1.8 should add a debug mode in future * Fix specs, only require asset_sync engine and railtie if Rails is initialized * Improve docs * Tidy up for release of Rails 3.1.1 support. ## v0.1.7 / 2011-10-15 Version 0.1.7 (David Rice ) Changes: * 6 Nominal Changes * Merge pull request #7 from hone/6_rails3.1.1 Rails 3.1.1 Compatability * rails 3.1.1 support * fix typo * Update the generated yml config with a staging environment, use defaults more. Engine within asset sync doesn't appear to be ran even with :group => :assets in the definition. Add railtie to allow setting config.asset_sync configuration within a rails application.rb, this and moving the initializer style of config seems to work for Rails 3.1.1, also so does purely relying on the YAML config * New version of asset_sync to work around Rails 3.1.1 issues. Test if config/initializers/asset_sync.rb exists and load that, otherwise provide a default initializer that is configurable with environment variables. Then merge in settings if config/asset_sync.yml is found. Add the asset_sync.rake in to lib/tasks so it is autoloaded and don't bother generating it anymore * Bugfix ## v0.1.6 / 2011-09-26 Version 0.1.6 (David Rice ) Changes: * 1 Nominal Changes * Fix gemfile ## v0.1.5 / 2011-09-26 Version 0.1.5 (David Rice ) Changes: * 5 Nominal Changes * Should raise storage error if AWS S3 bucket is not found. Version 0.1.5 * explain further * Merge branch 'master' of github.com:rumblelabs/asset_sync * List known issues with heroku and possible work arounds * Should raise error with no configuration ## v0.1.4 / 2011-08-30 Version 0.1.4 (David Rice ) Changes: * 2 Nominal Changes * Require dependancy of active_model, add config validation, better specs, version 0.1.4 * Tidied up read me with a DRYer use of AWS_BUCKET for asset_host. ## v0.1.3 / 2011-08-27 Version 0.1.3 (Simon Hamilton ) Changes: * 1 Nominal Changes * Bump version for release ## v0.1.2 / 2011-08-25 Version 0.1.2 (Simon Hamilton ) Changes: * 2 Nominal Changes * Removed public from cache control. May be causing a problem with uploads * Bump version for release ## v0.1.10 / 2011-11-15 Version 0.1.10 (David Rice ) Changes: * 7 Nominal Changes * Improve manifest configuration by making it a boolean option only, it will automatically use the configured manifest path if different from the default. Add documentation to readme about the new option and upgrade generated configs. * Merge pull request #20 from agworld/e26f5ca36dee1c2196653268ed6bb38c0226e4d2 Fixes issues #16, #17, #18 and #19 * fixes https://github.com/rumblelabs/asset_sync/issues/19 * Implements https://github.com/rumblelabs/asset_sync/issues/17 * fixes https://github.com/rumblelabs/asset_sync/issues/18 * fixes https://github.com/rumblelabs/asset_sync/issues/16 * Merge branch 'gzip-compression' ## v0.1.1 / 2011-08-24 Version 0.1.1 (Simon Hamilton ) Changes: * 5 Nominal Changes * Merge pull request #4 from jsmestad/patch-1 [BUGFIX] Add support for 'existing_remote_files' configuration in YAML fi * Verbose output about the delete process. * Condense logic on keep * [BUGFIX] Add support for 'existing_remote_files' configuration in YAML file. * Version 0.1.0 ready ## v0.1.0 / 2011-08-22 Version 0.1.0 (David Rice ) Changes: * 1 Nominal Changes * Merge 0.0.7 from master into new refactor branch ## v0.0.7 / 2011-08-22 Version 0.0.7 (David Rice ) Changes: * 9 Nominal Changes * Added Cache-control header (1 year, public) on uploaded files * Update README to reflect new configuration styles * Extract all file manipulation methods to a storage class, update generator templates, fix a few bugs. * Config class working, specs added, still @wip * Refactoring * Get config working and loading yml or the initializer * small additions * @wip working on extracting out a configuration class and allow config via an initializer alone, also support yml file usage for when that is useful * merge config changes ## v0.0.6 / 2011-08-06 Version 0.0.6 (Simon Hamilton ) Changes: * 1 Nominal Changes * Include ERB template rendering of yml. v0.0.5 ## v0.0.5 / 2011-08-05 Version 0.0.5 (David Rice ) Changes: * 3 Nominal Changes * now it parses the YAML file with ERB. * Set gem date for release * 0.0.4 Release ## v0.0.4 / 2011-08-05 Version 0.0.4 (David Rice ) ## v0.0.3 / 2011-07-31 Version 0.0.3 (David Rice ) Changes: * 1 Nominal Changes * Added homepage to gemspec ## v0.0.2 / 2011-07-31 Version 0.0.2 (Simon Hamilton ) Changes: * 7 Nominal Changes * Added a rails generator to install the rake task and the config. Just do "rails generate asset_sync:install" * Updated readme * Getting ready to release the gem * Revert "remove version file" This reverts commit 7ebd853947b8d5f3b6e81f96535dfce843f2c855. * remove version file * Initial commit * Initial commit ## HEAD / 2012-08-27 Current Development (David Rice) Changes: * 2 Nominal Changes * Improve documentation on ignored_files config option * Merge branch 'sinatra' [Unreleased]: https://github.com/AssetSync/asset_sync/compare/v2.11.0...HEAD [2.11.0]: https://github.com/AssetSync/asset_sync/compare/v2.10.0...v2.11.0 [2.10.0]: https://github.com/AssetSync/asset_sync/compare/v2.9.1...v2.10.0 [2.9.1]: https://github.com/AssetSync/asset_sync/compare/v2.9.0...v2.9.1 [2.9.0]: https://github.com/AssetSync/asset_sync/compare/v2.8.2...v2.9.0 [2.8.2]: https://github.com/AssetSync/asset_sync/compare/v2.8.1...v2.8.2 [2.8.1]: https://github.com/AssetSync/asset_sync/compare/v2.8.0...v2.8.1 [2.8.0]: https://github.com/AssetSync/asset_sync/compare/v2.7.0...v2.8.0 [2.7.0]: https://github.com/AssetSync/asset_sync/compare/v2.6.0...v2.7.0 [2.6.0]: https://github.com/AssetSync/asset_sync/compare/v2.5.0...v2.6.0 [2.5.0]: https://github.com/AssetSync/asset_sync/compare/v2.4.0...v2.5.0 [2.4.0]: https://github.com/AssetSync/asset_sync/compare/v2.3.0...v2.4.0 [2.3.0]: https://github.com/AssetSync/asset_sync/compare/v2.2.0...v2.3.0 [2.2.0]: https://github.com/AssetSync/asset_sync/compare/v2.1.0...v2.2.0 [2.1.0]: https://github.com/AssetSync/asset_sync/compare/v2.0.0...v2.1.0 [2.0.0]: https://github.com/AssetSync/asset_sync/compare/v1.3.0...v2.0.0 [1.3.0]: https://github.com/AssetSync/asset_sync/compare/v1.2.1...v1.3.0 [1.2.1]: https://github.com/AssetSync/asset_sync/compare/v1.2.0...v1.2.1 [1.2.0]: https://github.com/AssetSync/asset_sync/compare/v1.1.0...v1.2.0 asset_sync-2.11.0/Gemfile000066400000000000000000000004411363256206300152460ustar00rootroot00000000000000source 'https://rubygems.org' gemspec gem 'rcov', :platforms => :mri_18, :group => [:development, :test] gem 'simplecov', :platforms => [:jruby, :mri_19, :ruby_19, :mri_20, :rbx], :group => [:development, :test], :require => false gem 'jruby-openssl', :platform => :jruby gem 'rails' asset_sync-2.11.0/README.md000066400000000000000000000606221363256206300152410ustar00rootroot00000000000000 [![Gem Version](https://img.shields.io/gem/v/asset_sync.svg?style=flat-square)](http://badge.fury.io/rb/asset_sync) [![Build Status](https://img.shields.io/travis/AssetSync/asset_sync.svg?style=flat-square)](http://travis-ci.org/AssetSync/asset_sync) [![Coverage Status](http://img.shields.io/coveralls/AssetSync/asset_sync.svg?style=flat-square)](https://coveralls.io/r/AssetSync/asset_sync) # Asset Sync Synchronises Assets between Rails and S3. 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 bucket, optionally deleting unused files and only uploading the files it needs to. This was initially built and is intended to work on [Heroku](http://heroku.com) but can work on any platform. ## Upgrading? Upgraded from 1.x? Read `UPGRADING.md` ## Installation Since 2.x, Asset Sync depends on gem `fog-core` instead of `fog`. This is due to `fog` is including many unused storage provider gems as its dependencies. Asset Sync has no idea about what provider will be used, so you are responsible for bundling the right gem for the provider to be used. In your Gemfile: ```ruby gem "asset_sync" gem "fog-aws" ``` Or, to use Azure Blob storage, configure as this. ``` ruby gem "asset_sync" gem "fog-azure-rm" ``` ### Extended Installation (Faster sync with turbosprockets) It's possible to improve **asset:precompile** time if you are using Rails 3.2.x the main source of which being compilation of **non-digest** assets. [turbo-sprockets-rails3](https://github.com/ndbroadbent/turbo-sprockets-rails3) solves this by only compiling **digest** assets. Thus cutting compile time in half. > NOTE: It will be **deprecated in Rails 4** as sprockets-rails has been extracted out of Rails and will only compile **digest** assets by default. ## Configuration ### Rails Configure __config/environments/production.rb__ to use Amazon S3 as the asset host and ensure precompiling is enabled. ``` ruby #config/environments/production.rb config.action_controller.asset_host = "//#{ENV['FOG_DIRECTORY']}.s3.amazonaws.com" ``` Or, to use Google Storage Cloud, configure as this. ``` ruby #config/environments/production.rb config.action_controller.asset_host = "//#{ENV['FOG_DIRECTORY']}.storage.googleapis.com" ``` Or, to use Azure Blob storage, configure as this. ``` ruby #config/environments/production.rb config.action_controller.asset_host = "//#{ENV['AZURE_STORAGE_ACCOUNT_NAME']}.blob.core.windows.net/#{ENV['FOG_DIRECTORY']}" ``` 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. > 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. ``` ruby config.action_controller.asset_host = "//s3.amazonaws.com/#{ENV['FOG_DIRECTORY']}" ``` Or, to use Google Storage Cloud, configure as this. ``` ruby config.action_controller.asset_host = "//storage.googleapis.com/#{ENV['FOG_DIRECTORY']}" ``` Or, to use Azure Blob storage, configure as this. ``` ruby #config/environments/production.rb config.action_controller.asset_host = "//#{ENV['AZURE_STORAGE_ACCOUNT_NAME']}.blob.core.windows.net/#{ENV['FOG_DIRECTORY']}" ``` 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. 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 ``` ruby # store assets in a 'folder' instead of bucket root config.assets.prefix = "/production/assets" ``` Also, ensure the following are defined (in production.rb or application.rb) * **config.assets.digest** is set to **true**. * **config.assets.enabled** is set to **true**. Additionally, if you depend on any configuration that is setup in your `initializers` you will need to ensure that * **config.assets.initialize\_on\_precompile** is set to **true** ### AssetSync **AssetSync** supports the following methods of configuration. * [Built-in Initializer](https://github.com/AssetSync/asset_sync/blob/master/lib/asset_sync/engine.rb) (configured through environment variables) * Rails Initializer * A YAML config file 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. If you need more control over configuration you will want to use a **custom rails initializer**. Configuration using a **YAML** file (a common strategy for Capistrano deployments) is also supported. 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. ### Built-in Initializer (Environment Variables) The Built-in Initializer will configure **AssetSync** based on the contents of your environment variables. Add your configuration details to **heroku** ``` bash heroku config:add AWS_ACCESS_KEY_ID=xxxx heroku config:add AWS_SECRET_ACCESS_KEY=xxxx heroku config:add FOG_DIRECTORY=xxxx heroku config:add FOG_PROVIDER=AWS # and optionally: heroku config:add FOG_REGION=eu-west-1 heroku config:add ASSET_SYNC_GZIP_COMPRESSION=true heroku config:add ASSET_SYNC_MANIFEST=true heroku config:add ASSET_SYNC_EXISTING_REMOTE_FILES=keep ``` Or add to a traditional unix system ``` bash export AWS_ACCESS_KEY_ID=xxxx export AWS_SECRET_ACCESS_KEY=xxxx export FOG_DIRECTORY=xxxx ``` Rackspace configuration is also supported ``` bash heroku config:add RACKSPACE_USERNAME=xxxx heroku config:add RACKSPACE_API_KEY=xxxx heroku config:add FOG_DIRECTORY=xxxx heroku config:add FOG_PROVIDER=Rackspace ``` 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 ```bash heroku config:add FOG_PROVIDER=Google heroku config:add GOOGLE_PROJECT=xxxx heroku config:add GOOGLE_JSON_KEY_LOCATION=xxxx heroku config:add FOG_DIRECTORY=xxxx ``` If using the S3 API the following config is required ``` bash heroku config:add FOG_PROVIDER=Google heroku config:add GOOGLE_STORAGE_ACCESS_KEY_ID=xxxx heroku config:add GOOGLE_STORAGE_SECRET_ACCESS_KEY=xxxx heroku config:add FOG_DIRECTORY=xxxx ``` The Built-in Initializer also sets the AssetSync default for **existing_remote_files** to **keep**. ### Custom Rails Initializer (config/initializers/asset_sync.rb) If you want to enable some of the advanced configuration options you will want to create your own initializer. Run the included Rake task to generate a starting point. rails g asset_sync:install --provider=Rackspace rails g asset_sync:install --provider=AWS rails g asset_sync:install --provider=AzureRM The generator will create a Rails initializer at `config/initializers/asset_sync.rb`. ``` ruby AssetSync.configure do |config| config.fog_provider = 'AWS' config.fog_directory = ENV['FOG_DIRECTORY'] config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID'] config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] # Don't delete files from the store # config.existing_remote_files = 'keep' # # Increase upload performance by configuring your region # config.fog_region = 'eu-west-1' # # Set `public` option when uploading file depending on value, # Setting to "default" makes asset sync skip setting the option # Possible values: true, false, "default" (default: true) # config.fog_public = true # # Change AWS signature version. Default is 4 # config.aws_signature_version = 4 # # Change host option in fog (only if you need to) # config.fog_host = 's3.amazonaws.com' # # Change port option in fog (only if you need to) # config.fog_port = "9000" # # Use http instead of https. # config.fog_scheme = 'http' # # Automatically replace files with their equivalent gzip compressed version # config.gzip_compression = true # # Use the Rails generated 'manifest.yml' file to produce the list of files to # upload instead of searching the assets directory. # config.manifest = true # # Upload the manifest file also. # config.include_manifest = false # # Upload files concurrently # config.concurrent_uploads = false # # Number of threads when concurrent_uploads is enabled # config.concurrent_uploads_max_threads = 10 # # Path to cache file to skip scanning remote # config.remote_file_list_cache_file_path = './.asset_sync_remote_file_list_cache.json' # # Fail silently. Useful for environments such as Heroku # config.fail_silently = true # # Log silently. Default is `true`. But you can set it to false if more logging message are preferred. # Logging messages are sent to `STDOUT` when `log_silently` is falsy # config.log_silently = true # # Allow custom assets to be cacheable. Note: The base filename will be matched # If you have an asset with name `app.0b1a4cd3.js`, only `app.0b1a4cd3` will need to be matched # only one of `cache_asset_regexp` or `cache_asset_regexps` is allowed. # config.cache_asset_regexp = /\.[a-f0-9]{8}$/i # config.cache_asset_regexps = [ /\.[a-f0-9]{8}$/i, /\.[a-f0-9]{20}$/i ] end ``` ### YAML (config/asset_sync.yml) Run the included Rake task to generate a starting point. rails g asset_sync:install --use-yml --provider=Rackspace rails g asset_sync:install --use-yml --provider=AWS rails g asset_sync:install --use-yml --provider=AzureRM The generator will create a YAML file at `config/asset_sync.yml`. ``` yaml defaults: &defaults fog_provider: "AWS" fog_directory: "rails-app-assets" aws_access_key_id: "<%= ENV['AWS_ACCESS_KEY_ID'] %>" aws_secret_access_key: "<%= ENV['AWS_SECRET_ACCESS_KEY'] %>" # To use AWS reduced redundancy storage. # aws_reduced_redundancy: true # # You may need to specify what region your storage bucket is in # fog_region: "eu-west-1" # # Change AWS signature version. Default is 4 # aws_signature_version: 4 # # Change host option in fog (only if you need to) # fog_host: "s3.amazonaws.com" # # Use http instead of https. Default should be "https" (at least for fog-aws) # fog_scheme: "http" existing_remote_files: keep # Existing pre-compiled assets on S3 will be kept # To delete existing remote files. # existing_remote_files: delete # To ignore existing remote files and overwrite. # existing_remote_files: ignore # Automatically replace files with their equivalent gzip compressed version # gzip_compression: true # Fail silently. Useful for environments such as Heroku # fail_silently: true # Always upload. Useful if you want to overwrite specific remote assets regardless of their existence # eg: Static files in public often reference non-fingerprinted application.css # note: You will still need to expire them from the CDN's edge cache locations # always_upload: ['application.js', 'application.css', !ruby/regexp '/application-/\d{32}\.css/'] # Ignored files. Useful if there are some files that are created dynamically on the server and you don't want to upload on deploy. # ignored_files: ['ignore_me.js', !ruby/regexp '/ignore_some/\d{32}\.css/'] # Allow custom assets to be cacheable. Note: The base filename will be matched # If you have an asset with name "app.0b1a4cd3.js", only "app.0b1a4cd3" will need to be matched # cache_asset_regexps: ['cache_me.js', !ruby/regexp '/cache_some\.\d{8}\.css/'] development: <<: *defaults test: <<: *defaults production: <<: *defaults ``` ### Available Configuration Options Most AssetSync configuration can be modified directly using environment variables with the **Built-in initializer**. e.g. ```ruby AssetSync.config.fog_provider == ENV['FOG_PROVIDER'] ``` 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. ```ruby AssetSync.config.gzip_compression == ENV['ASSET_SYNC_GZIP_COMPRESSION'] ``` #### AssetSync (optional) * **existing_remote_files**: (`'keep', 'delete', 'ignore'`) what to do with previously precompiled files. **default:** `'keep'` * **gzip\_compression**: (`true, false`) when enabled, will automatically replace files that have a gzip compressed equivalent with the compressed version. **default:** `'false'` * **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'` * **include_manifest**: (`true, false`) when enabled, will upload the `manifest.yml` generated by Rails. **default:** `'false'` * **concurrent_uploads**: (`true, false`) when enabled, will upload the files in different Threads, this greatly improves the upload speed. **default:** `'false'` * **concurrent_uploads_max_threads**: when concurrent_uploads is enabled, this determines the number of threads that will be created. **default:** `10` * **remote_file_list_cache_file_path**: if present, use this path to cache remote file list to skip scanning remote **default:** `nil` * **enabled**: (`true, false`) when false, will disable asset sync. **default:** `'true'` (enabled) * **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**: `[]` * **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**: `[]` ##### Config Method `add_local_file_paths` Adding local files by providing a block: ```ruby AssetSync.configure do |config| # The block should return an array of file paths config.add_local_file_paths do # Any code that returns paths of local asset files to be uploaded # Like Webpacker public_root = Rails.root.join("public") Dir.chdir(public_root) do packs_dir = Webpacker.config.public_output_path.relative_path_from(public_root) Dir[File.join(packs_dir, '/**/**')] end end end ``` The blocks are run when local files are being scanned and uploaded ##### Config Method `file_ext_to_mime_type_overrides` It's reported that `mime-types` 3.x returns `application/ecmascript` instead of `application/javascript` Such change of mime type might cause some CDN to disable asset compression So this gem has defined a default override for file ext `js` to be mapped to `application/javascript` by default To customize the overrides: ```ruby AssetSync.configure do |config| # Clear the default overrides config.file_ext_to_mime_type_overrides.clear # Add/Edit overrides # Will call `#to_s` for inputs config.file_ext_to_mime_type_overrides.add(:js, :"application/x-javascript") end ``` The blocks are run when local files are being scanned and uploaded #### Fog (Required) * **fog\_provider**: your storage provider *AWS* (S3) or *Rackspace* (Cloud Files) or *Google* (Google Storage) or *AzureRM* (Azure Blob) * **fog\_directory**: your bucket name #### Fog (Optional) * **fog\_region**: the region your storage bucket is in e.g. *eu-west-1* (AWS), *ord* (Rackspace), *japanwest* (Azure Blob) * **fog\_path\_style**: To use buckets with dot in names, check https://github.com/fog/fog/issues/2381#issuecomment-28088524 #### AWS * **aws\_access\_key\_id**: your Amazon S3 access key * **aws\_secret\_access\_key**: your Amazon S3 access secret #### Rackspace * **rackspace\_username**: your Rackspace username * **rackspace\_api\_key**: your Rackspace API Key. #### Google Storage When using the JSON API - **google\_project**: your Google Cloud Project name where the Google Cloud Storage bucket resides - **google\_json\_key\_location**: path to the location of the service account key. The service account key must be a JSON type key When using the S3 API * **google\_storage\_access\_key\_id**: your Google Storage access key * **google\_storage\_secret\_access\_key**: your Google Storage access secret #### Azure Blob * **azure\_storage\_account\_name**: your Azure Blob access key * **azure\_storage\_access\_key**: your Azure Blob access secret #### Rackspace (Optional) * **rackspace\_auth\_url**: Rackspace auth URL, for Rackspace London use: `https://lon.identity.api.rackspacecloud.com/v2.0` ## Amazon S3 Multiple Region Support 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. ``` bash heroku config:add FOG_REGION=eu-west-1 ``` Or via a custom initializer ``` ruby AssetSync.configure do |config| # ... config.fog_region = 'eu-west-1' end ``` Or via YAML ``` yaml production: # ... fog_region: 'eu-west-1' ``` ### Amazon (AWS) IAM Users Amazon has switched to the more secure IAM User security policy model. When generating a user & policy for asset_sync you **must** ensure the policy has the following permissions, or you'll see the error: ``` Expected(200) <=> Actual(403 Forbidden) ``` IAM User Policy Example with minimum require permissions (replace `bucket_name` with your bucket): ``` json { "Statement": [ { "Action": "s3:ListBucket", "Effect": "Allow", "Resource": "arn:aws:s3:::bucket_name" }, { "Action": "s3:PutObject*", "Effect": "Allow", "Resource": "arn:aws:s3:::bucket_name/*" } ] } ``` If you want to use IAM roles you must set ```config.aws_iam_roles = true``` in your initializers. ``` AssetSync.configure do |config| # ... config.aws_iam_roles = true end ``` ## Automatic gzip compression 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. If the compressed file is actually larger than the uncompressed file we will ignore this rule and upload the standard uncompressed version. ## Fail Silently With the `fail_silently` option enabled, when running `rake assets:precompile` AssetSync will never throw an error due to missing configuration variables. 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: > 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. > 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. ## Rake Task A rake task is included within the **asset_sync** gem to perform the sync: ``` ruby namespace :assets do desc "Synchronize assets to S3" task :sync => :environment do AssetSync.sync end end ``` 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: ``` ruby if Rake::Task.task_defined?("assets:precompile:nondigest") Rake::Task["assets:precompile:nondigest"].enhance do Rake::Task["assets:sync"].invoke if defined?(AssetSync) && AssetSync.config.run_on_precompile end else Rake::Task["assets:precompile"].enhance do Rake::Task["assets:sync"].invoke if defined?(AssetSync) && AssetSync.config.run_on_precompile end end ``` You can disable this behavior by setting `AssetSync.config.run_on_precompile = false`. ## Sinatra/Rack Support You can use the gem with any Rack application, but you must specify two additional options; `prefix` and `public_path`. ```ruby AssetSync.configure do |config| config.fog_provider = 'AWS' config.fog_directory = ENV['FOG_DIRECTORY'] config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID'] config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] config.prefix = 'assets' # Can be a `Pathname` or `String` # Will be converted into an `Pathname` # If relative, will be converted into an absolute path # via `::Rails.root` or `::Dir.pwd` config.public_path = Pathname('./public') end ``` Then manually call `AssetSync.sync` at the end of your asset precompilation task. ```ruby namespace :assets do desc 'Precompile assets' task :precompile do target = Pathname('./public/assets') manifest = Sprockets::Manifest.new(sprockets, './public/assets/manifest.json') sprockets.each_logical_path do |logical_path| if (!File.extname(logical_path).in?(['.js', '.css']) || logical_path =~ /application\.(css|js)$/) && asset = sprockets.find_asset(logical_path) filename = target.join(logical_path) FileUtils.mkpath(filename.dirname) puts "Write asset: #{filename}" asset.write_to(filename) manifest.compile(logical_path) end end AssetSync.sync end end ``` ## Webpacker (> 2.0) support 1. Add webpacker files and disable `run_on_precompile`: ```ruby AssetSync.configure do |config| # Disable automatic run on precompile in order to attach to webpacker rake task config.run_on_precompile = false # The block should return an array of file paths config.add_local_file_paths do # Support webpacker assets public_root = Rails.root.join("public") Dir.chdir(public_root) do packs_dir = Webpacker.config.public_output_path.relative_path_from(public_root) Dir[File.join(packs_dir, '/**/**')] end end end ``` 2. Add a `asset_sync.rake` in your `lib/tasks` directory that enhances the correct task, otherwise asset_sync runs before `webpacker:compile` does: ``` if defined?(AssetSync) Rake::Task['webpacker:compile'].enhance do Rake::Task["assets:sync"].invoke end end ``` ### Caveat By adding local files outside the normal Rails `assets` directory, the uploading part works, however checking that the asset was previously uploaded is not working because asset_sync is only fetching the files in the `assets` directory on the remote bucket. This will mean additional time used to upload the same assets again on every precompilation. ## Running the specs Make sure you have a .env file with these details:- # for AWS provider AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= FOG_DIRECTORY= FOG_REGION= # for AzureRM provider AZURE_STORAGE_ACCOUNT_NAME= AZURE_STORAGE_ACCESS_KEY= FOG_DIRECTORY= FOG_REGION= Make sure the bucket has read/write permissions. Then to run the tests:- foreman run rake ## Todo 1. Add some before and after filters for deleting and uploading 2. Support more cloud storage providers 3. Better test coverage 4. Add rake tasks to clean old assets from a bucket ## Credits Inspired by: - [https://github.com/moocode/asset_id](https://github.com/moocode/asset_id) - [https://gist.github.com/1053855](https://gist.github.com/1053855) ## License MIT License. Copyright 2011-2013 Rumble Labs Ltd. [rumblelabs.com](http://rumblelabs.com) asset_sync-2.11.0/Rakefile000066400000000000000000000026671363256206300154340ustar00rootroot00000000000000#!/usr/bin/env rake begin require 'bundler/setup' require 'appraisal' rescue LoadError puts 'You must `gem install bundler` and `bundle install` to run rake tasks' end require 'bundler/gem_tasks' require 'rspec/core/rake_task' namespace :spec do RSpec::Core::RakeTask.new(:unit) do |spec| spec.pattern = 'spec/unit/*_spec.rb' spec.rspec_opts = ['--backtrace'] rbx = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx' jruby = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby' if RUBY_VERSION == '1.8.7' && !(rbx || jruby) spec.rcov = true spec.rcov_opts = %w{--exclude gems\/,spec\/} end end RSpec::Core::RakeTask.new(:integration) do |spec| spec.pattern = 'spec/integration/*_spec.rb' spec.rspec_opts = ['--backtrace'] end desc "run spec:unit and spec:integration tasks" task :all do Rake::Task['spec:unit'].execute # Travis CI does not expose encrypted ENV variables for pull requests, so # do not run integration specs # http://about.travis-ci.org/docs/user/build-configuration/#Set-environment-variables # pull_request = ENV['TRAVIS_PULL_REQUEST'] == 'true' ci_build = ENV['TRAVIS'] == 'true' if !ci_build || (ci_build && pull_request) Rake::Task['spec:integration'].execute end end end if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"] task :default do sh "appraisal install && rake appraisal spec:unit" end else task default: ["spec:unit"] end asset_sync-2.11.0/UPGRADING.md000066400000000000000000000013061363256206300156160ustar00rootroot00000000000000# Guide to upgrading from AssetSync 1.x to 2.x Make sure that you're running the latest AssetSync 1.x release. This upgrading guide touches on: - Changed dependencies ## Changed dependencies Asset Sync now depends on gem `fog-core` instead of `fog`. This is due to `fog` is including many unused storage provider gems as its dependencies. Asset Sync has no idea about what provider will be used, so you are responsible for bundling the right gem for the provider to be used. For example, when using AWS as fog provider: ```ruby # Gemfile gem "asset_sync" gem "fog-aws" ``` If you don't install the required gem, Fog will complain (by exception) about it when provider is set by Asset Sync. asset_sync-2.11.0/asset_sync.gemspec000066400000000000000000000027461363256206300175050ustar00rootroot00000000000000# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "asset_sync/version" Gem::Specification.new do |s| s.name = "asset_sync" s.version = AssetSync::VERSION s.platform = Gem::Platform::RUBY s.authors = ["Simon Hamilton", "David Rice", "Phil McClure", "Toby Osbourn"] s.email = ["shamilton@rumblelabs.com", "me@davidjrice.co.uk", "pmcclure@rumblelabs.com", "tosbourn@rumblelabs.com"] s.homepage = "https://github.com/rumblelabs/asset_sync" s.summary = %q{Synchronises Assets in a Rails 3 application and Amazon S3/Cloudfront and Rackspace Cloudfiles} s.description = %q{After you run assets:precompile your compiled assets will be synchronised with your S3 bucket.} s.license = 'MIT' s.add_dependency("fog-core") s.add_dependency('unf') s.add_dependency('activemodel', ">= 4.1.0") s.add_dependency('mime-types', ">= 2.99") s.add_development_dependency "rspec" s.add_development_dependency "bundler" s.add_development_dependency "coveralls", ">= 0.7" s.add_development_dependency('mime-types', ">= 3.0") s.add_development_dependency "fog-aws" s.add_development_dependency "fog-azure-rm" s.add_development_dependency "uglifier" s.add_development_dependency "appraisal" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] end asset_sync-2.11.0/docs/000077500000000000000000000000001363256206300147045ustar00rootroot00000000000000asset_sync-2.11.0/docs/heroku.md000066400000000000000000000031611363256206300165240ustar00rootroot00000000000000The following issues are currently present in Heroku if you are not following the steps outlined in the main [README](http://github.com/rumblelabs/asset_sync) ## KNOWN ISSUES (IMPORTANT) We are currently trying to talk with Heroku to iron these out. 1. Will not work on heroku on an application with a *RAILS_ENV* configured as anything other than production 2. Will not work on heroku using ENV variables with the configuration as described below, you must hardcode all variables ### 1. RAILS_ENV When you see `rake assets:precompile` during deployment. Heroku is actually running something like env RAILS_ENV=production DATABASE_URL=scheme://user:pass@127.0.0.1/dbname bundle exec rake assets:precompile 2>&1 This means the *RAILS_ENV* you have set via *heroku:config* is not used. **Workaround:** you could have just one S3 bucket dedicated to assets and configure `AssetSync` to not delete existing files: AssetSync.configure do |config| ... config.fog_directory = 'app-assets' config.existing_remote_files = "keep" end ### 2. ENV varables not available Currently when heroku runs `rake assets:precompile` during deployment. It does not load your Rails application's environment config. This means using any **ENV** variables you could normally depend on are not available. For now you can just run `heroku run rake assets:precompile` after deploy. **Workaround:** you could just hardcode your AWS credentials in the initializer or yml AssetSync.configure do |config| config.aws_access_key_id = 'xxx' config.aws_secret_access_key = 'xxx' config.fog_directory = 'mybucket' end asset_sync-2.11.0/gemfiles/000077500000000000000000000000001363256206300155475ustar00rootroot00000000000000asset_sync-2.11.0/gemfiles/rails_5_0.gemfile000066400000000000000000000005141363256206300206560ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rcov", platforms: :mri_18, group: [:development, :test] gem "simplecov", platforms: [:jruby, :mri_19, :ruby_19, :mri_20, :rbx], group: [:development, :test], require: false gem "jruby-openssl", platform: :jruby gem "rails", "~> 5.0.0" gemspec path: "../" asset_sync-2.11.0/gemfiles/rails_5_1.gemfile000066400000000000000000000005141363256206300206570ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rcov", platforms: :mri_18, group: [:development, :test] gem "simplecov", platforms: [:jruby, :mri_19, :ruby_19, :mri_20, :rbx], group: [:development, :test], require: false gem "jruby-openssl", platform: :jruby gem "rails", "~> 5.1.0" gemspec path: "../" asset_sync-2.11.0/gemfiles/rails_5_2.gemfile000066400000000000000000000005141363256206300206600ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rcov", platforms: :mri_18, group: [:development, :test] gem "simplecov", platforms: [:jruby, :mri_19, :ruby_19, :mri_20, :rbx], group: [:development, :test], require: false gem "jruby-openssl", platform: :jruby gem "rails", "~> 5.2.0" gemspec path: "../" asset_sync-2.11.0/gemfiles/rails_6_0.gemfile000066400000000000000000000005141363256206300206570ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rcov", platforms: :mri_18, group: [:development, :test] gem "simplecov", platforms: [:jruby, :mri_19, :ruby_19, :mri_20, :rbx], group: [:development, :test], require: false gem "jruby-openssl", platform: :jruby gem "rails", "~> 6.0.0" gemspec path: "../" asset_sync-2.11.0/lib/000077500000000000000000000000001363256206300145225ustar00rootroot00000000000000asset_sync-2.11.0/lib/asset_sync.rb000066400000000000000000000003331363256206300172210ustar00rootroot00000000000000require "asset_sync/asset_sync" require 'asset_sync/config' require 'asset_sync/storage' require 'asset_sync/multi_mime' require 'asset_sync/railtie' if defined?(Rails) require 'asset_sync/engine' if defined?(Rails) asset_sync-2.11.0/lib/asset_sync/000077500000000000000000000000001363256206300166755ustar00rootroot00000000000000asset_sync-2.11.0/lib/asset_sync/asset_sync.rb000066400000000000000000000022631363256206300214000ustar00rootroot00000000000000module AssetSync class << self def config=(data) @config = data end def config @config ||= Config.new @config end def reset_config! remove_instance_variable :@config if defined?(@config) end def configure(&proc) @config ||= Config.new yield @config end def storage @storage ||= Storage.new(self.config) end def sync with_config do self.storage.sync end end def clean with_config do self.storage.delete_extra_remote_files end end def with_config(&block) return unless AssetSync.enabled? errors = config.valid? ? "" : config.errors.full_messages.join(', ') if !(config && config.valid?) if config.fail_silently? self.warn(errors) else raise Config::Invalid.new(errors) end else block.call end end def warn(msg) stderr.puts msg end def log(msg) stdout.puts msg unless config.log_silently? end def enabled? config.enabled? end # easier to stub def stderr ; STDERR ; end def stdout ; STDOUT ; end end end asset_sync-2.11.0/lib/asset_sync/config.rb000066400000000000000000000335661363256206300205040ustar00rootroot00000000000000# frozen_string_literal: true require "active_model" require "erb" require "yaml" module AssetSync class Config include ActiveModel::Validations class Invalid < StandardError; end # AssetSync attr_accessor :existing_remote_files # What to do with your existing remote files? (keep or delete) attr_accessor :gzip_compression attr_accessor :manifest attr_accessor :fail_silently attr_accessor :log_silently attr_accessor :always_upload attr_accessor :ignored_files attr_accessor :prefix attr_accessor :enabled attr_accessor :custom_headers attr_accessor :run_on_precompile attr_accessor :invalidate attr_accessor :cdn_distribution_id attr_accessor :cache_asset_regexps attr_accessor :include_manifest attr_accessor :concurrent_uploads attr_accessor :concurrent_uploads_max_threads attr_accessor :remote_file_list_cache_file_path # FOG configuration attr_accessor :fog_provider # Currently Supported ['AWS', 'Rackspace'] attr_accessor :fog_directory # e.g. 'the-bucket-name' attr_accessor :fog_region # e.g. 'eu-west-1' attr_reader :fog_public # e.g. true, false, "default" # Amazon AWS attr_accessor :aws_access_key_id, :aws_secret_access_key, :aws_reduced_redundancy, :aws_iam_roles, :aws_signature_version attr_accessor :fog_host # e.g. 's3.amazonaws.com' attr_accessor :fog_port # e.g. '9000' attr_accessor :fog_path_style # e.g. true attr_accessor :fog_scheme # e.g. 'http' # Rackspace attr_accessor :rackspace_username, :rackspace_api_key, :rackspace_auth_url # Google Storage attr_accessor :google_storage_secret_access_key, :google_storage_access_key_id # when using S3 interop attr_accessor :google_json_key_location # when using service accounts attr_accessor :google_project # when using service accounts # Azure Blob with Fog::AzureRM attr_accessor :azure_storage_account_name attr_accessor :azure_storage_access_key validates :existing_remote_files, :inclusion => { :in => %w(keep delete ignore) } validates :fog_provider, :presence => true validates :fog_directory, :presence => true validates :aws_access_key_id, :presence => true, :if => proc {aws? && !aws_iam?} validates :aws_secret_access_key, :presence => true, :if => proc {aws? && !aws_iam?} validates :rackspace_username, :presence => true, :if => :rackspace? validates :rackspace_api_key, :presence => true, :if => :rackspace? validates :google_storage_secret_access_key, :presence => true, :if => :google_interop? validates :google_storage_access_key_id, :presence => true, :if => :google_interop? validates :google_json_key_location, :presence => true, :if => :google_service_account? validates :google_project, :presence => true, :if => :google_service_account? validates :concurrent_uploads, :inclusion => { :in => [true, false] } def initialize self.fog_region = nil self.fog_public = true self.existing_remote_files = 'keep' self.gzip_compression = false self.manifest = false self.fail_silently = false self.log_silently = true self.always_upload = [] self.ignored_files = [] self.custom_headers = {} self.enabled = true self.run_on_precompile = true self.cdn_distribution_id = nil self.invalidate = [] self.cache_asset_regexps = [] self.include_manifest = false self.concurrent_uploads = false self.concurrent_uploads_max_threads = 10 self.remote_file_list_cache_file_path = nil @additional_local_file_paths_procs = [] load_yml! if defined?(::Rails) && yml_exists? end def manifest_path directory = ::Rails.application.config.assets.manifest || default_manifest_directory File.join(directory, "manifest.yml") end def gzip? self.gzip_compression end def existing_remote_files? ['keep', 'ignore'].include?(self.existing_remote_files) end def aws? fog_provider =~ /aws/i end def aws_rrs? aws_reduced_redundancy == true end def aws_iam? aws_iam_roles == true end def fail_silently? fail_silently || !enabled? end def log_silently? !!self.log_silently end def enabled? enabled == true end def rackspace? fog_provider =~ /rackspace/i end def google? fog_provider =~ /google/i end def google_interop? google? && google_json_key_location.nil? end def google_service_account? google? && google_json_key_location end def azure_rm? fog_provider =~ /azurerm/i end def cache_asset_regexp=(cache_asset_regexp) self.cache_asset_regexps = [cache_asset_regexp] end def yml_exists? defined?(::Rails.root) ? File.exist?(self.yml_path) : false end def yml @yml ||= ::YAML.load(::ERB.new(IO.read(yml_path)).result)[::Rails.env] || {} end def yml_path ::Rails.root.join("config", "asset_sync.yml").to_s end def assets_prefix # Fix for Issue #38 when Rails.config.assets.prefix starts with a slash self.prefix || ::Rails.application.config.assets.prefix.sub(/^\//, '') end def public_path @public_path || ::Rails.public_path end def public_path=(path) # Generate absolute path even when relative path passed in # Required for generating relative sprockets manifest path pathname = Pathname(path) @public_path = if pathname.absolute? pathname elsif defined?(::Rails.root) ::Rails.root.join(pathname) else Pathname(::Dir.pwd).join(pathname) end end def load_yml! self.enabled = yml["enabled"] if yml.has_key?('enabled') self.fog_provider = yml["fog_provider"] self.fog_host = yml["fog_host"] self.fog_port = yml["fog_port"] self.fog_directory = yml["fog_directory"] self.fog_region = yml["fog_region"] self.fog_public = yml["fog_public"] if yml.has_key?("fog_public") self.fog_path_style = yml["fog_path_style"] self.fog_scheme = yml["fog_scheme"] self.aws_access_key_id = yml["aws_access_key_id"] self.aws_secret_access_key = yml["aws_secret_access_key"] self.aws_reduced_redundancy = yml["aws_reduced_redundancy"] self.aws_iam_roles = yml["aws_iam_roles"] self.aws_signature_version = yml["aws_signature_version"] self.rackspace_username = yml["rackspace_username"] self.rackspace_auth_url = yml["rackspace_auth_url"] if yml.has_key?("rackspace_auth_url") self.rackspace_api_key = yml["rackspace_api_key"] self.google_json_key_location = yml["google_json_key_location"] if yml.has_key?("google_json_key_location") self.google_project = yml["google_project"] if yml.has_key?("google_project") self.google_storage_secret_access_key = yml["google_storage_secret_access_key"] if yml.has_key?("google_storage_secret_access_key") self.google_storage_access_key_id = yml["google_storage_access_key_id"] if yml.has_key?("google_storage_access_key_id") self.existing_remote_files = yml["existing_remote_files"] if yml.has_key?("existing_remote_files") self.gzip_compression = yml["gzip_compression"] if yml.has_key?("gzip_compression") self.manifest = yml["manifest"] if yml.has_key?("manifest") self.fail_silently = yml["fail_silently"] if yml.has_key?("fail_silently") self.always_upload = yml["always_upload"] if yml.has_key?("always_upload") self.ignored_files = yml["ignored_files"] if yml.has_key?("ignored_files") self.custom_headers = yml["custom_headers"] if yml.has_key?("custom_headers") self.run_on_precompile = yml["run_on_precompile"] if yml.has_key?("run_on_precompile") self.invalidate = yml["invalidate"] if yml.has_key?("invalidate") self.cdn_distribution_id = yml['cdn_distribution_id'] if yml.has_key?("cdn_distribution_id") self.cache_asset_regexps = yml['cache_asset_regexps'] if yml.has_key?("cache_asset_regexps") self.include_manifest = yml['include_manifest'] if yml.has_key?("include_manifest") self.concurrent_uploads = yml['concurrent_uploads'] if yml.has_key?('concurrent_uploads') self.concurrent_uploads_max_threads = yml['concurrent_uploads_max_threads'] if yml.has_key?('concurrent_uploads_max_threads') self.remote_file_list_cache_file_path = yml['remote_file_list_cache_file_path'] if yml.has_key?('remote_file_list_cache_file_path') self.azure_storage_account_name = yml['azure_storage_account_name'] if yml.has_key?("azure_storage_account_name") self.azure_storage_access_key = yml['azure_storage_access_key'] if yml.has_key?("azure_storage_access_key") # TODO deprecate the other old style config settings. FML. self.aws_access_key_id = yml["aws_access_key"] if yml.has_key?("aws_access_key") self.aws_secret_access_key = yml["aws_access_secret"] if yml.has_key?("aws_access_secret") self.fog_directory = yml["aws_bucket"] if yml.has_key?("aws_bucket") self.fog_region = yml["aws_region"] if yml.has_key?("aws_region") # TODO deprecate old style config settings self.aws_access_key_id = yml["access_key_id"] if yml.has_key?("access_key_id") self.aws_secret_access_key = yml["secret_access_key"] if yml.has_key?("secret_access_key") self.fog_directory = yml["bucket"] if yml.has_key?("bucket") self.fog_region = yml["region"] if yml.has_key?("region") self.public_path = yml["public_path"] if yml.has_key?("public_path") end def fog_options options = { :provider => fog_provider } if aws? if aws_iam? options.merge!({ :use_iam_profile => true }) else options.merge!({ :aws_access_key_id => aws_access_key_id, :aws_secret_access_key => aws_secret_access_key }) end options.merge!({:host => fog_host}) if fog_host options.merge!({:port => fog_port}) if fog_port options.merge!({:scheme => fog_scheme}) if fog_scheme options.merge!({:aws_signature_version => aws_signature_version}) if aws_signature_version options.merge!({:path_style => fog_path_style}) if fog_path_style options.merge!({:region => fog_region}) if fog_region elsif rackspace? options.merge!({ :rackspace_username => rackspace_username, :rackspace_api_key => rackspace_api_key }) options.merge!({ :rackspace_region => fog_region }) if fog_region options.merge!({ :rackspace_auth_url => rackspace_auth_url }) if rackspace_auth_url elsif google? if google_json_key_location options.merge!({:google_json_key_location => google_json_key_location, :google_project => google_project}) else options.merge!({ :google_storage_secret_access_key => google_storage_secret_access_key, :google_storage_access_key_id => google_storage_access_key_id }) end options.merge!({:region => fog_region}) if fog_region elsif azure_rm? require 'fog/azurerm' options.merge!({ :azure_storage_account_name => azure_storage_account_name, :azure_storage_access_key => azure_storage_access_key, }) options.merge!({:environment => fog_region}) if fog_region else raise ArgumentError, "AssetSync Unknown provider: #{fog_provider} only AWS, Rackspace and Google are supported currently." end options end # @api def add_local_file_paths(&block) @additional_local_file_paths_procs = additional_local_file_paths_procs + [block] end # @api private # This is to be called in Storage # Not to be called by user def additional_local_file_paths return [] if additional_local_file_paths_procs.empty? # Using `Array()` to ensure it works when single value is returned additional_local_file_paths_procs.each_with_object([]) do |proc, paths| paths.concat(Array(proc.call)) end end #@api def file_ext_to_mime_type_overrides @file_ext_to_mime_type_overrides ||= FileExtToMimeTypeOverrides.new end def fog_public=(new_val) @fog_public = FogPublicValue.new(new_val) end private # This is a proc to get additional local files paths # Since this is a proc it won't be able to be configured by a YAML file attr_reader :additional_local_file_paths_procs def default_manifest_directory File.join(::Rails.public_path, assets_prefix) end # @api private class FileExtToMimeTypeOverrides def initialize # The default is to prevent new mime type `application/ecmascript` to be returned # which disables compression on some CDNs @overrides = { "js" => "application/javascript", } end # @api def add(ext, mime_type) # Symbol / Mime type object might be passed in # But we want strings only @overrides.store( ext.to_s, mime_type.to_s, ) end # @api def clear @overrides = {} end # @api private def key?(key) @overrides.key?(key) end # @api private def fetch(key) @overrides.fetch(key) end end # @api private class FogPublicValue def initialize(val) @value = val end def use_explicit_value? @value.to_s != "default" end def to_bool !!@value end end end end asset_sync-2.11.0/lib/asset_sync/engine.rb000066400000000000000000000073641363256206300205010ustar00rootroot00000000000000module AssetSync class Engine < Rails::Engine engine_name "asset_sync" initializer "asset_sync config", :group => :all do |app| app_initializer = Rails.root.join('config', 'initializers', 'asset_sync.rb').to_s app_yaml = Rails.root.join('config', 'asset_sync.yml').to_s if File.exist?( app_initializer ) AssetSync.log "AssetSync: using #{app_initializer}" load app_initializer elsif !File.exist?( app_initializer ) && !File.exist?( app_yaml ) AssetSync.log "AssetSync: using default configuration from built-in initializer" AssetSync.configure do |config| config.fog_provider = ENV['FOG_PROVIDER'] if ENV.has_key?('FOG_PROVIDER') config.fog_directory = ENV['FOG_DIRECTORY'] if ENV.has_key?('FOG_DIRECTORY') config.fog_region = ENV['FOG_REGION'] if ENV.has_key?('FOG_REGION') config.fog_host = ENV['FOG_HOST'] if ENV.has_key?('FOG_HOST') config.fog_port = ENV['FOG_PORT'] if ENV.has_key?('FOG_PORT') config.fog_scheme = ENV['FOG_SCHEMA'] if ENV.has_key?('FOG_SCHEMA') config.fog_path_style = ENV['FOG_PATH_STYLE'] if ENV.has_key?('FOG_PATH_STYLE') config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID'] if ENV.has_key?('AWS_ACCESS_KEY_ID') config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] if ENV.has_key?('AWS_SECRET_ACCESS_KEY') config.aws_signature_version = ENV['AWS_SIGNATURE_VERSION'] if ENV.has_key?('AWS_SIGNATURE_VERSION') config.aws_reduced_redundancy = ENV['AWS_REDUCED_REDUNDANCY'] == true if ENV.has_key?('AWS_REDUCED_REDUNDANCY') config.rackspace_username = ENV['RACKSPACE_USERNAME'] if ENV.has_key?('RACKSPACE_USERNAME') config.rackspace_api_key = ENV['RACKSPACE_API_KEY'] if ENV.has_key?('RACKSPACE_API_KEY') config.google_storage_access_key_id = ENV['GOOGLE_STORAGE_ACCESS_KEY_ID'] if ENV.has_key?('GOOGLE_STORAGE_ACCESS_KEY_ID') config.google_storage_secret_access_key = ENV['GOOGLE_STORAGE_SECRET_ACCESS_KEY'] if ENV.has_key?('GOOGLE_STORAGE_SECRET_ACCESS_KEY') config.azure_storage_account_name = ENV['AZURE_STORAGE_ACCOUNT_NAME'] if ENV.has_key?('AZURE_STORAGE_ACCOUNT_NAME') config.azure_storage_access_key = ENV['AZURE_STORAGE_ACCESS_KEY'] if ENV.has_key?('AZURE_STORAGE_ACCESS_KEY') config.enabled = (ENV['ASSET_SYNC_ENABLED'] == 'true') if ENV.has_key?('ASSET_SYNC_ENABLED') config.existing_remote_files = ENV['ASSET_SYNC_EXISTING_REMOTE_FILES'] || "keep" config.gzip_compression = (ENV['ASSET_SYNC_GZIP_COMPRESSION'] == 'true') if ENV.has_key?('ASSET_SYNC_GZIP_COMPRESSION') config.manifest = (ENV['ASSET_SYNC_MANIFEST'] == 'true') if ENV.has_key?('ASSET_SYNC_MANIFEST') config.include_manifest = (ENV['ASSET_SYNC_INCLUDE_MANIFEST'] == 'true') if ENV.has_key?('ASSET_SYNC_INCLUDE_MANIFEST') config.concurrent_uploads = (ENV['ASSET_SYNC_CONCURRENT_UPLOADS'] == 'true') if ENV.has_key?('ASSET_SYNC_CONCURRENT_UPLOADS') 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') end config.prefix = ENV['ASSET_SYNC_PREFIX'] if ENV.has_key?('ASSET_SYNC_PREFIX') config.existing_remote_files = ENV['ASSET_SYNC_EXISTING_REMOTE_FILES'] || "keep" config.gzip_compression = (ENV['ASSET_SYNC_GZIP_COMPRESSION'] == 'true') if ENV.has_key?('ASSET_SYNC_GZIP_COMPRESSION') config.manifest = (ENV['ASSET_SYNC_MANIFEST'] == 'true') if ENV.has_key?('ASSET_SYNC_MANIFEST') end if File.exist?( app_yaml ) AssetSync.log "AssetSync: YAML file found #{app_yaml} settings will be merged into the configuration" end end end end asset_sync-2.11.0/lib/asset_sync/multi_mime.rb000066400000000000000000000011421363256206300213610ustar00rootroot00000000000000require 'mime/types' module AssetSync class MultiMime def self.lookup(ext) overrides = ::AssetSync.config.file_ext_to_mime_type_overrides if overrides.key?(ext) return overrides.fetch(ext) end if defined?(::MIME::Types) ::MIME::Types.type_for(ext).first.to_s elsif defined?(::Mime::Type) ::Mime::Type.lookup_by_extension(ext).to_s elsif defined?(::Rack::Mime) ext_with_dot = ".#{ext}" ::Rack::Mime.mime_type(ext_with_dot) else raise "No library found for mime type lookup" end end end end asset_sync-2.11.0/lib/asset_sync/railtie.rb000066400000000000000000000001231363256206300206470ustar00rootroot00000000000000class Rails::Railtie::Configuration def asset_sync AssetSync.config end endasset_sync-2.11.0/lib/asset_sync/storage.rb000066400000000000000000000270521363256206300206740ustar00rootroot00000000000000require "fog/core" require "asset_sync/multi_mime" module AssetSync class Storage REGEXP_FINGERPRINTED_FILES = /^(.*)\/([^-]+)-[^\.]+\.([^\.]+)$/ REGEXP_ASSETS_TO_CACHE_CONTROL = /-[0-9a-fA-F]{32,}$/ class BucketNotFound < StandardError; end attr_accessor :config def initialize(cfg) @config = cfg end def connection @connection ||= Fog::Storage.new(self.config.fog_options) end def bucket # fixes: https://github.com/rumblelabs/asset_sync/issues/18 @bucket ||= connection.directories.get(self.config.fog_directory, :prefix => self.config.assets_prefix) end def log(msg) AssetSync.log(msg) end def keep_existing_remote_files? self.config.existing_remote_files? end def path self.config.public_path end def remote_file_list_cache_file_path self.config.remote_file_list_cache_file_path end def ignored_files expand_file_names(self.config.ignored_files) end def get_manifest_path return [] unless self.config.include_manifest if ActionView::Base.respond_to?(:assets_manifest) manifest = Sprockets::Manifest.new(ActionView::Base.assets_manifest.environment, ActionView::Base.assets_manifest.dir) manifest_path = manifest.filename else manifest_path = self.config.manifest_path end [manifest_path.sub(/^#{path}\//, "")] # full path to relative path end def local_files @local_files ||= (get_local_files + config.additional_local_file_paths).uniq end def remote_files return [] if ignore_existing_remote_files? return @remote_files if @remote_files if remote_file_list_cache_file_path && File.file?(remote_file_list_cache_file_path) begin content = File.read(remote_file_list_cache_file_path) return @remote_files = JSON.parse(content) rescue JSON::ParserError warn "Failed to parse #{remote_file_list_cache_file_path} as json" end end @remote_files = get_remote_files end def update_remote_file_list_cache(local_files_to_upload) return unless remote_file_list_cache_file_path return if ignore_existing_remote_files? File.open(self.remote_file_list_cache_file_path, 'w') do |file| uploaded = local_files_to_upload + remote_files file.write(uploaded.to_json) end end def always_upload_files expand_file_names(self.config.always_upload) + get_manifest_path end def files_with_custom_headers self.config.custom_headers.inject({}) { |h,(k, v)| h[File.join(self.config.assets_prefix, k)] = v; h; } end def files_to_invalidate self.config.invalidate.map { |filename| File.join("/", self.config.assets_prefix, filename) } end # @api # To get a list of asset files indicated in a manifest file. # It makes sense if a user sets `config.manifest` is true. def get_asset_files_from_manifest if self.config.manifest if ActionView::Base.respond_to?(:assets_manifest) log "Using: Rails 4.0 manifest access" manifest = Sprockets::Manifest.new(ActionView::Base.assets_manifest.environment, ActionView::Base.assets_manifest.dir) return manifest.assets.values.map { |f| File.join(self.config.assets_prefix, f) } elsif File.exist?(self.config.manifest_path) log "Using: Manifest #{self.config.manifest_path}" yml = YAML.load(IO.read(self.config.manifest_path)) return yml.map do |original, compiled| # Upload font originals and compiled if original =~ /^.+(eot|svg|ttf|woff)$/ [original, compiled] else compiled end end.flatten.map { |f| File.join(self.config.assets_prefix, f) }.uniq! else log "Warning: Manifest could not be found" end end end def get_local_files if from_manifest = get_asset_files_from_manifest return from_manifest end log "Using: Directory Search of #{path}/#{self.config.assets_prefix}" Dir.chdir(path) do to_load = self.config.assets_prefix.present? ? "#{self.config.assets_prefix}/**/**" : '**/**' Dir[to_load] end end def get_remote_files raise BucketNotFound.new("#{self.config.fog_provider} Bucket: #{self.config.fog_directory} not found.") unless bucket # fixes: https://github.com/rumblelabs/asset_sync/issues/16 # (work-around for https://github.com/fog/fog/issues/596) files = [] bucket.files.each { |f| files << f.key } return files end def delete_file(f, remote_files_to_delete) if remote_files_to_delete.include?(f.key) log "Deleting: #{f.key}" f.destroy end end def delete_extra_remote_files log "Fetching files to flag for delete" remote_files = get_remote_files # fixes: https://github.com/rumblelabs/asset_sync/issues/19 from_remote_files_to_delete = remote_files - local_files - ignored_files - always_upload_files log "Flagging #{from_remote_files_to_delete.size} file(s) for deletion" # Delete unneeded remote files, if we are on aws delete in bulk else use sequential delete if self.config.aws? && connection.respond_to?(:delete_multiple_objects) from_remote_files_to_delete.each_slice(500) do |slice| connection.delete_multiple_objects(config.fog_directory, slice) end else bucket.files.each do |f| delete_file(f, from_remote_files_to_delete) end end end def upload_file(f) # TODO output files in debug logs as asset filename only. one_year = 31557600 ext = File.extname(f)[1..-1] mime = MultiMime.lookup(ext) gzip_file_handle = nil file_handle = File.open("#{path}/#{f}") file = { :key => f, :body => file_handle, :content_type => mime } # region fog_public if config.fog_public.use_explicit_value? file[:public] = config.fog_public.to_bool end # endregion fog_public uncompressed_filename = f.sub(/\.gz\z/, '') basename = File.basename(uncompressed_filename, File.extname(uncompressed_filename)) assets_to_cache_control = Regexp.union([REGEXP_ASSETS_TO_CACHE_CONTROL] | config.cache_asset_regexps).source if basename.match(Regexp.new(assets_to_cache_control)).present? file.merge!({ :cache_control => "public, max-age=#{one_year}", :expires => CGI.rfc1123_date(Time.now + one_year) }) end # overwrite headers if applicable, you probably shouldn't specific key/body, but cache-control headers etc. if files_with_custom_headers.has_key? f file.merge! files_with_custom_headers[f] log "Overwriting #{f} with custom headers #{files_with_custom_headers[f].to_s}" elsif key = self.config.custom_headers.keys.detect {|k| f.match(Regexp.new(k))} headers = {} self.config.custom_headers[key].each do |k, value| headers[k.to_sym] = value end file.merge! headers log "Overwriting matching file #{f} with custom headers #{headers.to_s}" end gzipped = "#{path}/#{f}.gz" ignore = false if config.gzip? && File.extname(f) == ".gz" # Don't bother uploading gzipped assets if we are in gzip_compression mode # as we will overwrite file.css with file.css.gz if it exists. log "Ignoring: #{f}" ignore = true elsif config.gzip? && File.exist?(gzipped) original_size = File.size("#{path}/#{f}") gzipped_size = File.size(gzipped) if gzipped_size < original_size percentage = ((gzipped_size.to_f/original_size.to_f)*100).round(2) gzip_file_handle = File.open(gzipped) file.merge!({ :key => f, :body => gzip_file_handle, :content_encoding => 'gzip' }) log "Uploading: #{gzipped} in place of #{f} saving #{percentage}%" else percentage = ((original_size.to_f/gzipped_size.to_f)*100).round(2) log "Uploading: #{f} instead of #{gzipped} (compression increases this file by #{percentage}%)" end else if !config.gzip? && File.extname(f) == ".gz" # set content encoding for gzipped files this allows cloudfront to properly handle requests with Accept-Encoding # http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html uncompressed_filename = f[0..-4] ext = File.extname(uncompressed_filename)[1..-1] mime = MultiMime.lookup(ext) file.merge!({ :content_type => mime, :content_encoding => 'gzip' }) end log "Uploading: #{f}" end if config.aws? && config.aws_rrs? file.merge!({ :storage_class => 'REDUCED_REDUNDANCY' }) end bucket.files.create( file ) unless ignore file_handle.close gzip_file_handle.close if gzip_file_handle end def upload_files # fixes: https://github.com/rumblelabs/asset_sync/issues/19 local_files_to_upload = local_files - ignored_files - remote_files + always_upload_files local_files_to_upload = (local_files_to_upload + get_non_fingerprinted(local_files_to_upload)).uniq # Only files. local_files_to_upload = local_files_to_upload.select { |f| File.file? "#{path}/#{f}" } if self.config.concurrent_uploads jobs = Queue.new local_files_to_upload.each { |f| jobs.push(f) } jobs.close num_threads = [self.config.concurrent_uploads_max_threads, local_files_to_upload.length].min # Upload new files workers = Array.new(num_threads) do Thread.new do while f = jobs.pop upload_file(f) end end end workers.map(&:join) else # Upload new files local_files_to_upload.each do |f| upload_file f end end if self.config.cdn_distribution_id && files_to_invalidate.any? log "Invalidating Files" cdn ||= Fog::CDN.new(self.config.fog_options.except(:region)) data = cdn.post_invalidation(self.config.cdn_distribution_id, files_to_invalidate) log "Invalidation id: #{data.body["Id"]}" end update_remote_file_list_cache(local_files_to_upload) end def sync # fixes: https://github.com/rumblelabs/asset_sync/issues/19 log "AssetSync: Syncing." upload_files delete_extra_remote_files unless keep_existing_remote_files? log "AssetSync: Done." end private def ignore_existing_remote_files? self.config.existing_remote_files == 'ignore' end def get_non_fingerprinted(files) files.map do |file| match_data = file.match(REGEXP_FINGERPRINTED_FILES) match_data && "#{match_data[1]}/#{match_data[2]}.#{match_data[3]}" end.compact end def expand_file_names(names) files = [] Array(names).each do |name| case name when Regexp files += self.local_files.select do |file| file =~ name end when String files += self.local_files.select do |file| file.split('/').last == name end else log "Error: please define file names as string or regular expression. #{name} (#{name.class}) ignored." end end files.uniq end end end asset_sync-2.11.0/lib/asset_sync/version.rb000066400000000000000000000001111363256206300207000ustar00rootroot00000000000000# frozen_string_literal: true module AssetSync VERSION = "2.11.0" end asset_sync-2.11.0/lib/generators/000077500000000000000000000000001363256206300166735ustar00rootroot00000000000000asset_sync-2.11.0/lib/generators/asset_sync/000077500000000000000000000000001363256206300210465ustar00rootroot00000000000000asset_sync-2.11.0/lib/generators/asset_sync/install_generator.rb000066400000000000000000000037401363256206300251130ustar00rootroot00000000000000require 'rails/generators' module AssetSync class InstallGenerator < Rails::Generators::Base desc "Install a config/asset_sync.yml and the asset:precompile rake task enhancer" # Commandline options can be defined here using Thor-like options: class_option :use_yml, :type => :boolean, :default => false, :desc => "Use YML file instead of Rails Initializer" class_option :provider, :type => :string, :default => "AWS", :desc => "Generate with support for 'AWS', 'Rackspace', 'Google', or 'AzureRM" def self.source_root @source_root ||= File.join(File.dirname(__FILE__), 'templates') end def aws? options[:provider] == 'AWS' end def google? options[:provider] == 'Google' end def rackspace? options[:provider] == 'Rackspace' end def azure_rm? options[:provider] == 'AzureRM' end def aws_access_key_id "<%= ENV['AWS_ACCESS_KEY_ID'] %>" end def aws_secret_access_key "<%= ENV['AWS_SECRET_ACCESS_KEY'] %>" end def google_storage_access_key_id "<%= ENV['GOOGLE_STORAGE_ACCESS_KEY_ID'] %>" end def google_storage_secret_access_key "<%= ENV['GOOGLE_STORAGE_SECRET_ACCESS_KEY'] %>" end def rackspace_username "<%= ENV['RACKSPACE_USERNAME'] %>" end def rackspace_api_key "<%= ENV['RACKSPACE_API_KEY'] %>" end def azure_storage_account_name "<%= ENV['AZURE_STORAGE_ACCOUNT_NAME'] %>" end def azure_storage_access_key "<%= ENV['AZURE_STORAGE_ACCESS_KEY'] %>" end def app_name @app_name ||= Rails.application.is_a?(Rails::Application) && Rails.application.class.name.sub(/::Application$/, "").downcase end def generate_config if options[:use_yml] template "asset_sync.yml", "config/asset_sync.yml" end end def generate_initializer unless options[:use_yml] template "asset_sync.rb", "config/initializers/asset_sync.rb" end end end end asset_sync-2.11.0/lib/generators/asset_sync/templates/000077500000000000000000000000001363256206300230445ustar00rootroot00000000000000asset_sync-2.11.0/lib/generators/asset_sync/templates/asset_sync.rb000066400000000000000000000065641363256206300255570ustar00rootroot00000000000000if defined?(AssetSync) AssetSync.configure do |config| <%- if aws? -%> config.fog_provider = 'AWS' config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID'] config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] # To use AWS reduced redundancy storage. # config.aws_reduced_redundancy = true # # Change AWS signature version. Default is 4 # config.aws_signature_version = 4 # # Change host option in fog (only if you need to) # config.fog_host = "s3.amazonaws.com" # # Change port option in fog (only if you need to) # config.fog_port = "9000" # # Use http instead of https. Default should be "https" (at least for fog-aws) # config.fog_scheme = "http" <%- elsif google? -%> config.fog_provider = 'Google' config.google_storage_access_key_id = ENV['GOOGLE_STORAGE_ACCESS_KEY_ID'] config.google_storage_secret_access_key = ENV['GOOGLE_STORAGE_SECRET_ACCESS_KEY'] <%- elsif rackspace? -%> config.fog_provider = 'Rackspace' config.rackspace_username = ENV['RACKSPACE_USERNAME'] config.rackspace_api_key = ENV['RACKSPACE_API_KEY'] # if you need to change rackspace_auth_url (e.g. if you need to use Rackspace London) # config.rackspace_auth_url = "lon.auth.api.rackspacecloud.com" <%- elsif azure_rm? -%> config.fog_provider = 'AzureRM' config.azure_storage_account_name = ENV['AZURE_STORAGE_ACCOUNT_NAME'] config.azure_storage_access_key = ENV['AZURE_STORAGE_ACCESS_KEY'] # config.fog_directory specifies container name of Azure Blob storage <%- end -%> config.fog_directory = ENV['FOG_DIRECTORY'] # Invalidate a file on a cdn after uploading files # config.cdn_distribution_id = "12345" # config.invalidate = ['file1.js'] # Increase upload performance by configuring your region # config.fog_region = 'eu-west-1' # # Set `public` option when uploading file depending on value, # Setting to "default" makes asset sync skip setting the option # Possible values: true, false, "default" (default: true) # config.fog_public = true # # Don't delete files from the store # config.existing_remote_files = "keep" # # Automatically replace files with their equivalent gzip compressed version # config.gzip_compression = true # # Use the Rails generated 'manifest.yml' file to produce the list of files to # upload instead of searching the assets directory. # config.manifest = true # # Upload the manifest file also. # config.include_manifest = false # # Upload files concurrently # config.concurrent_uploads = false # # Path to cache file to skip scanning remote # config.remote_file_list_cache_file_path = './.asset_sync_remote_file_list_cache.json' # # Fail silently. Useful for environments such as Heroku # config.fail_silently = true # # Log silently. Default is `true`. But you can set it to false if more logging message are preferred. # Logging messages are sent to `STDOUT` when `log_silently` is falsy # config.log_silently = true # # Allow custom assets to be cacheable. Note: The base filename will be matched # If you have an asset with name `app.0ba4d3.js`, only `app.0ba4d3` will need to be matched # config.cache_asset_regexps = [ /\.[a-f0-9]{8}$/i, /\.[a-f0-9]{20}$/i ] # config.cache_asset_regexp = /\.[a-f0-9]{8}$/i end end asset_sync-2.11.0/lib/generators/asset_sync/templates/asset_sync.yml000066400000000000000000000045141363256206300257460ustar00rootroot00000000000000defaults: &defaults <%- if aws? -%> fog_provider: 'AWS' aws_access_key_id: "<%= aws_access_key_id %>" aws_secret_access_key: "<%= aws_secret_access_key %>" # To use AWS reduced redundancy storage. # aws_reduced_redundancy: true # # Change AWS signature version. Default is 4 # aws_signature_version: 4 # # Change host option in fog (only if you need to) # fog_host: "s3.amazonaws.com" # # Change port option in fog (only if you need to) # config.fog_port = "9000" # # Use http instead of https. Default should be "https" (at least for fog-aws) # fog_scheme: "http" <%- elsif google? -%> fog_provider: 'Google' google_storage_access_key_id: "<%= google_storage_access_key_id %>" google_storage_secret_access_key: "<%= google_storage_secret_access_key %>" <%- elsif rackspace? -%> fog_provider: 'Rackspace' rackspace_username: "<%= rackspace_username %>" rackspace_api_key: "<%= rackspace_api_key %>" # if you need to change rackspace_auth_url (e.g. if you need to use Rackspace London) # rackspace_auth_url: "https://lon.identity.api.rackspacecloud.com/v2.0" <%- elsif azure_rm? -%> fog_provider: 'AzureRM' azure_storage_account_name: "<%= azure_storage_account_name %>" azure_storage_access_key: "<%= azure_storage_access_key %>" # fog_directory specifies container name of Azure Blob storage <%- end -%> fog_directory: "<%= app_name %>-assets" # You may need to specify what region your storage bucket is in # fog_region: "eu-west-1" # Set `public` option when uploading file depending on value, # Setting to "default" makes asset sync skip setting the option # Possible values: true, false, "default" (default: true) # config.fog_public = true existing_remote_files: keep # To delete existing remote files. # existing_remote_files: delete # Automatically replace files with their equivalent gzip compressed version # gzip_compression: true # Fail silently. Useful for environments such as Heroku # fail_silently: true # Allow custom assets to be cacheable. Note: The base filename will be matched # cache_asset_regexps: ['cache_me.js', !ruby/regexp '/cache_some\.\d{8}\.css/'] development: <<: *defaults enabled: false test: <<: *defaults enabled: false staging: <<: *defaults fog_directory: "<%= app_name %>-staging-assets" production: <<: *defaults asset_sync-2.11.0/lib/tasks/000077500000000000000000000000001363256206300156475ustar00rootroot00000000000000asset_sync-2.11.0/lib/tasks/asset_sync.rake000066400000000000000000000022401363256206300206640ustar00rootroot00000000000000namespace :assets do desc 'Synchronize assets to remote (assumes assets are already compiled)' task :sync => :environment do AssetSync.sync end namespace :sync do desc 'Delete out-of-sync files on remote' task :clean => :environment do AssetSync.clean end end end if Rake::Task.task_defined?("assets:precompile:nondigest") Rake::Task["assets:precompile:nondigest"].enhance do # Conditional execution needs to be inside the enhance block because the enhance block # will get executed before yaml or Rails initializers. Rake::Task["assets:sync"].invoke if defined?(AssetSync) && AssetSync.config.run_on_precompile end elsif Rake::Task.task_defined?("assets:precompile") Rake::Task["assets:precompile"].enhance do # rails 3.1.1 will clear out Rails.application.config if the env vars # RAILS_GROUP and RAILS_ENV are not defined. We need to reload the # assets environment in this case. # Rake::Task["assets:environment"].invoke if Rake::Task.task_defined?("assets:environment") Rake::Task["assets:sync"].invoke if defined?(AssetSync) && AssetSync.config.run_on_precompile end else # Nothing to be enhanced end asset_sync-2.11.0/spec/000077500000000000000000000000001363256206300147065ustar00rootroot00000000000000asset_sync-2.11.0/spec/dummy_app/000077500000000000000000000000001363256206300167015ustar00rootroot00000000000000asset_sync-2.11.0/spec/dummy_app/Rakefile000066400000000000000000000021431363256206300203460ustar00rootroot00000000000000require 'rubygems' # require "rake" ENV['RAILS_ROOT'] = File.dirname(__FILE__) # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) # require 'rails/all' require "action_controller/railtie" require "sprockets/railtie" if defined?(Bundler) Bundler.require(*Rails.groups(:assets => %w(development test))) end module AssetSyncTest class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] config.eager_load = false config.assets.enabled = true config.assets.version = '1.0' config.secret_token = 'bf196b4383deefa4e0120a6ef1d9af1cc45f5c4ebd04405' config.session_store :cookie_store, :key => '_asset_sync_test_session', :secret => 'xxxx' config.active_support.deprecation = :log config.assets.compress = true config.assets.digest = true config.assets.prefix = ENV['ASSET_SYNC_PREFIX'] end end AssetSyncTest::Application.initialize! AssetSyncTest::Application.load_tasks # Rake::Task['assets:precompile:all'].invoke asset_sync-2.11.0/spec/dummy_app/app/000077500000000000000000000000001363256206300174615ustar00rootroot00000000000000asset_sync-2.11.0/spec/dummy_app/app/assets/000077500000000000000000000000001363256206300207635ustar00rootroot00000000000000asset_sync-2.11.0/spec/dummy_app/app/assets/javascripts/000077500000000000000000000000001363256206300233145ustar00rootroot00000000000000asset_sync-2.11.0/spec/dummy_app/app/assets/javascripts/application.js000066400000000000000000000000251363256206300261520ustar00rootroot00000000000000console.log("hello");asset_sync-2.11.0/spec/fixtures/000077500000000000000000000000001363256206300165575ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/aws_with_yml/000077500000000000000000000000001363256206300212655ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/aws_with_yml/config/000077500000000000000000000000001363256206300225325ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/aws_with_yml/config/asset_sync.yml000066400000000000000000000011111363256206300254220ustar00rootroot00000000000000defaults: &defaults fog_provider: "AWS" aws_access_key_id: "xxxx" aws_secret_access_key: "zzzz" region: "eu-west-1" run_on_precompile: false fog_path_style: true cache_asset_regexps: ['cache_me.js', !ruby/regexp '/cache_some\.\d{8}\.css/'] development: <<: *defaults fog_directory: "rails_app_development" existing_remote_files: keep test: <<: *defaults fog_directory: "rails_app_test" existing_remote_files: keep production: <<: *defaults fog_directory: "rails_app_production" existing_remote_files: delete hybrid: <<: *defaults enabled: false asset_sync-2.11.0/spec/fixtures/azure_rm_with_yml/000077500000000000000000000000001363256206300223175ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/azure_rm_with_yml/config/000077500000000000000000000000001363256206300235645ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/azure_rm_with_yml/config/asset_sync.yml000066400000000000000000000006271363256206300264670ustar00rootroot00000000000000defaults: &defaults fog_provider: "AzureRM" azure_storage_account_name: 'xxxx' azure_storage_access_key: 'zzzz' development: <<: *defaults fog_directory: "rails_app_development" existing_remote_files: keep test: <<: *defaults fog_directory: "rails_app_test" existing_remote_files: keep production: <<: *defaults fog_directory: "rails_app_production" existing_remote_files: delete asset_sync-2.11.0/spec/fixtures/google_with_service_account_yml/000077500000000000000000000000001363256206300252035ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/google_with_service_account_yml/config/000077500000000000000000000000001363256206300264505ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/google_with_service_account_yml/config/asset_sync.yml000066400000000000000000000006261363256206300313520ustar00rootroot00000000000000defaults: &defaults fog_provider: "Google" google_json_key_location: 'gcs.json' google_project: 'some-project' development: <<: *defaults fog_directory: "rails_app_development" existing_remote_files: keep test: <<: *defaults fog_directory: "rails_app_test" existing_remote_files: keep production: <<: *defaults fog_directory: "rails_app_production" existing_remote_files: delete asset_sync-2.11.0/spec/fixtures/google_with_yml/000077500000000000000000000000001363256206300217475ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/google_with_yml/config/000077500000000000000000000000001363256206300232145ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/google_with_yml/config/asset_sync.yml000066400000000000000000000006401363256206300261120ustar00rootroot00000000000000defaults: &defaults fog_provider: "Google" google_storage_access_key_id: 'xxxx' google_storage_secret_access_key: 'zzzz' development: <<: *defaults fog_directory: "rails_app_development" existing_remote_files: keep test: <<: *defaults fog_directory: "rails_app_test" existing_remote_files: keep production: <<: *defaults fog_directory: "rails_app_production" existing_remote_files: delete asset_sync-2.11.0/spec/fixtures/rackspace_with_yml/000077500000000000000000000000001363256206300224275ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/rackspace_with_yml/config/000077500000000000000000000000001363256206300236745ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/rackspace_with_yml/config/asset_sync.yml000066400000000000000000000006401363256206300265720ustar00rootroot00000000000000defaults: &defaults fog_provider: "Rackspace" rackspace_username: "xxxx" rackspace_api_key: "zzzz" region: "eu-west-1" development: <<: *defaults fog_directory: "rails_app_development" existing_remote_files: keep test: <<: *defaults fog_directory: "rails_app_test" existing_remote_files: keep production: <<: *defaults fog_directory: "rails_app_production" existing_remote_files: delete asset_sync-2.11.0/spec/fixtures/with_invalid_yml/000077500000000000000000000000001363256206300221215ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/with_invalid_yml/config/000077500000000000000000000000001363256206300233665ustar00rootroot00000000000000asset_sync-2.11.0/spec/fixtures/with_invalid_yml/config/asset_sync.yml000066400000000000000000000007071363256206300262700ustar00rootroot00000000000000defaults: &defaults fog_provider= "AWS" aws_access_key_id: "xxxx" aws_secret_access_key: "zzzz" region: "eu-west-1" development: <<: *defaults fog_directory: "rails_app_development" existing_remote_files: keep test: <<: *defaults fog_directory: "rails_app_test" existing_remote_files: keep production: <<: *defaults fog_directory: "rails_app_production" existing_remote_files: delete hybrid: <<: *defaults enabled: false asset_sync-2.11.0/spec/integration/000077500000000000000000000000001363256206300172315ustar00rootroot00000000000000asset_sync-2.11.0/spec/integration/aws_integration_spec.rb000066400000000000000000000036231363256206300237710ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../spec_helper' require "fog/aws" def bucket(name) options = { :provider => 'AWS', :aws_access_key_id => ENV['AWS_ACCESS_KEY_ID'], :aws_secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'] } connection = Fog::Storage.new(options) connection.directories.get(ENV['FOG_DIRECTORY'], :prefix => name) end def execute(command) app_path = File.expand_path("../../dummy_app", __FILE__) Dir.chdir app_path `#{command}` end describe "AssetSync" do before(:each) do @prefix = SecureRandom.hex(6) end let(:app_js_regex){ /#{@prefix}\/application-[a-zA-Z0-9]*.js$/ } let(:app_js_gz_regex){ /#{@prefix}\/application-[a-zA-Z0-9]*.js.gz$/ } let(:files){ bucket(@prefix).files } after(:each) do @directory = bucket(@prefix) @directory.files.each do |f| f.destroy end end it "sync" do execute "rake ASSET_SYNC_PREFIX=#{@prefix} assets:precompile" files = bucket(@prefix).files app_js_path = files.select{ |f| f.key =~ app_js_regex }.first app_js_gz_path = files.select{ |f| f.key =~ app_js_gz_regex }.first app_js = files.get( app_js_path.key ) expect(app_js.content_type).to eq("text/javascript") app_js_gz = files.get( app_js_gz_path.key ) expect(app_js_gz.content_type).to eq("text/javascript") expect(app_js_gz.content_encoding).to eq("gzip") end it "sync with enabled=false" do execute "rake ASSET_SYNC_PREFIX=#{@prefix} ASSET_SYNC_ENABLED=false assets:precompile" expect(bucket(@prefix).files.size).to eq(0) end it "sync with gzip_compression=true" do execute "rake ASSET_SYNC_PREFIX=#{@prefix} ASSET_SYNC_GZIP_COMPRESSION=true assets:precompile" # bucket(@prefix).files.size.should == 3 app_js_path = files.select{ |f| f.key =~ app_js_regex }.first app_js = files.get( app_js_path.key ) expect(app_js.content_type).to eq("text/javascript") end end asset_sync-2.11.0/spec/integration/azure_rm_integration_spec.rb000066400000000000000000000036711363256206300250260ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../spec_helper' require "fog/azurerm" def bucket(name) options = { :provider => 'AzureRM', :azure_storage_account_name => ENV['AZURE_STORAGE_ACCOUNT_NAME'], :azure_storage_access_key => ENV['AZURE_STORAGE_ACCESS_KEY'] } options.merge!({ :environment => ENV['FOG_REGION'] }) if ENV.has_key?('FOG_REGION') connection = Fog::Storage.new(options) connection.directories.get(ENV['FOG_DIRECTORY'], :prefix => name) end def execute(command) app_path = File.expand_path("../../dummy_app", __FILE__) Dir.chdir app_path `#{command}` end describe "AssetSync" do before(:each) do @prefix = SecureRandom.hex(6) end let(:app_js_regex){ /#{@prefix}\/application-[a-zA-Z0-9]*.js$/ } let(:app_js_gz_regex){ /#{@prefix}\/application-[a-zA-Z0-9]*.js.gz$/ } let(:files){ bucket(@prefix).files } after(:each) do @directory = bucket(@prefix) @directory.files.each do |f| f.destroy end end it "sync" do execute "rake ASSET_SYNC_PREFIX=#{@prefix} assets:precompile" files = bucket(@prefix).files app_js = files.select{ |f| f.key =~ app_js_regex }.first expect(app_js.content_type).to eq("application/javascript") app_js_gz = files.select{ |f| f.key =~ app_js_gz_regex }.first expect(app_js_gz.content_type).to eq("application/javascript") expect(app_js_gz.content_encoding).to eq("gzip") end it "sync with enabled=false" do execute "rake ASSET_SYNC_PREFIX=#{@prefix} ASSET_SYNC_ENABLED=false assets:precompile" expect(bucket(@prefix).files.size).to eq(0) end it "sync with gzip_compression=true" do execute "rake ASSET_SYNC_PREFIX=#{@prefix} ASSET_SYNC_GZIP_COMPRESSION=true assets:precompile" # bucket(@prefix).files.size.should == 3 app_js_path = files.select{ |f| f.key =~ app_js_regex }.first app_js = files.get( app_js_path.key ) expect(app_js.content_type).to eq("application/javascript") end end asset_sync-2.11.0/spec/spec_helper.rb000066400000000000000000000033201363256206300175220ustar00rootroot00000000000000require 'rubygems' require 'bundler' begin require 'simplecov' SimpleCov.start do add_filter 'spec' end rescue LoadError # SimpleCov ain't available - continue end if ENV["TRAVIS"] require "coveralls" Coveralls.wear!("rails") end begin Bundler.setup(:default, :development) rescue Bundler::BundlerError => e $stderr.puts e.message $stderr.puts "Run `bundle install` to install missing gems" exit e.status_code end $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $LOAD_PATH.unshift(File.dirname(__FILE__)) require 'asset_sync' require 'rspec' RSpec.configure do |config| config.mock_framework = :rspec end shared_context "mock without Rails" do before(:each) do if defined? Rails Object.send(:remove_const, :Rails) end allow(AssetSync).to receive(:log) end end shared_context "mock Rails" do before(:each) do Object.send(:remove_const, :Rails) if defined? Rails Rails = double 'Rails' allow(Rails).to receive(:env).and_return('test') allow(Rails).to receive_messages :application => double('application') allow(Rails.application).to receive_messages :config => double('config') allow(Rails.application.config).to receive_messages :assets => ActiveSupport::OrderedOptions.new Rails.application.config.assets.prefix = '/assets' allow(AssetSync).to receive(:log) end end shared_context "mock Rails without_yml" do include_context "mock Rails" before(:each) do set_rails_root('without_yml') allow(Rails).to receive(:public_path).and_return(Rails.root.join('public').to_s) end end def set_rails_root(path) allow(Rails).to receive(:root).and_return(Pathname.new(File.join(File.dirname(__FILE__), 'fixtures', path))) end asset_sync-2.11.0/spec/unit/000077500000000000000000000000001363256206300156655ustar00rootroot00000000000000asset_sync-2.11.0/spec/unit/asset_sync_spec.rb000066400000000000000000000230271363256206300214030ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../spec_helper' describe AssetSync do include_context "mock Rails without_yml" describe 'with initializer' do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.fog_provider = 'AWS' config.aws_access_key_id = 'aaaa' config.aws_secret_access_key = 'bbbb' config.fog_directory = 'mybucket' config.fog_region = 'eu-west-1' config.fog_path_style = 'true' config.existing_remote_files = "keep" end end it "should default to running on precompile" do expect(AssetSync.config.run_on_precompile).to be_truthy end it "should default AssetSync to enabled" do expect(AssetSync.config.enabled?).to be_truthy expect(AssetSync.enabled?).to be_truthy end it "should configure provider as AWS" do expect(AssetSync.config.fog_provider).to eq('AWS') expect(AssetSync.config).to be_aws end it "should should keep existing remote files" do expect(AssetSync.config.existing_remote_files?).to eq(true) end it "should configure aws_access_key" do expect(AssetSync.config.aws_access_key_id).to eq("aaaa") end it "should configure aws_secret_access_key" do expect(AssetSync.config.aws_secret_access_key).to eq("bbbb") end it "should configure aws_access_key" do expect(AssetSync.config.fog_directory).to eq("mybucket") end it "should configure fog_region" do expect(AssetSync.config.fog_region).to eq("eu-west-1") end it "should configure path_style" do expect(AssetSync.config.fog_path_style).to be_truthy end it "should configure existing_remote_files" do expect(AssetSync.config.existing_remote_files).to eq("keep") end it "should default gzip_compression to false" do expect(AssetSync.config.gzip_compression).to be_falsey end it "should default manifest to false" do expect(AssetSync.config.manifest).to be_falsey end it "should default log_silently to true" do expect(AssetSync.config.log_silently).to be_truthy end it "log_silently? should reflect the configuration" do AssetSync.config.log_silently = false expect(AssetSync.config.log_silently?).to eq(false) end it "log_silently? should always be true if ENV['RAILS_GROUPS'] == 'assets'" do AssetSync.config.log_silently = false allow(ENV).to receive(:[]).with('RAILS_GROUPS').and_return('assets') expect(AssetSync.config.log_silently?).to eq(false) end it "should default cdn_distribution_id to nil" do expect(AssetSync.config.cdn_distribution_id).to be_nil end it "should default invalidate to empty array" do expect(AssetSync.config.invalidate).to eq([]) end it "should default asset_regexps to empty array" do expect(AssetSync.config.cache_asset_regexps).to eq([]) end end describe 'from yml' do before(:each) do set_rails_root('aws_with_yml') AssetSync.config = AssetSync::Config.new end it "should default AssetSync to enabled" do expect(AssetSync.config.enabled?).to be_truthy expect(AssetSync.enabled?).to be_truthy end it "should configure run_on_precompile" do expect(AssetSync.config.run_on_precompile).to be_falsey end it "should configure aws_access_key_id" do expect(AssetSync.config.aws_access_key_id).to eq("xxxx") end it "should configure aws_secret_access_key" do expect(AssetSync.config.aws_secret_access_key).to eq("zzzz") end it "should configure fog_directory" do expect(AssetSync.config.fog_directory).to eq("rails_app_test") end it "should configure fog_region" do expect(AssetSync.config.fog_region).to eq("eu-west-1") end it "should configure path_style" do expect(AssetSync.config.fog_path_style).to be_truthy end it "should configure existing_remote_files" do expect(AssetSync.config.existing_remote_files).to eq("keep") end it "should default gzip_compression to false" do expect(AssetSync.config.gzip_compression).to be_falsey end it "should default manifest to false" do expect(AssetSync.config.manifest).to be_falsey end it "should default asset_regexps to match regexps" do expect(AssetSync.config.cache_asset_regexps).to eq(['cache_me.js', /cache_some\.\d{8}\.css/]) end end describe 'from yml, exporting to a mobile hybrid development directory' do before(:each) do Rails.env.replace('hybrid') set_rails_root('aws_with_yml') AssetSync.config = AssetSync::Config.new end it "should be disabled" do expect{ AssetSync.sync }.not_to raise_error end after(:each) do Rails.env.replace('test') end end describe 'with no configuration' do before(:each) do AssetSync.config = AssetSync::Config.new end it "should be invalid" do expect{ AssetSync.sync }.to raise_error(::AssetSync::Config::Invalid) end end describe "with no other configuration than enabled = false" do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.enabled = false end end it "should do nothing, without complaining" do expect{ AssetSync.sync }.not_to raise_error end end describe 'with fail_silent configuration' do before(:each) do allow(AssetSync).to receive(:stderr).and_return(@stderr = StringIO.new) AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.fail_silently = true end end it "should not raise an invalid exception" do expect{ AssetSync.sync }.not_to raise_error end it "should output a warning to stderr" do AssetSync.sync expect(@stderr.string).to match(/can't be blank/) end end describe 'with disabled config' do before(:each) do allow(AssetSync).to receive(:stderr).and_return(@stderr = StringIO.new) AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.enabled = false end end it "should not raise an invalid exception" do expect{ AssetSync.sync }.not_to raise_error end end describe 'with gzip_compression enabled' do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.config.gzip_compression = true end it "config.gzip? should be true" do expect(AssetSync.config.gzip?).to be_truthy end end describe 'with manifest enabled' do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.config.manifest = true end it "config.manifest should be true" do expect(AssetSync.config.manifest).to be_truthy end it "config.manifest_path should default to public/assets.." do expect(AssetSync.config.manifest_path).to match(/public\/assets\/manifest.yml/) end it "config.manifest_path should default to public/assets.." do Rails.application.config.assets.manifest = "/var/assets" expect(AssetSync.config.manifest_path).to eq("/var/assets/manifest.yml") end it "config.manifest_path should default to public/custom_assets.." do Rails.application.config.assets.prefix = 'custom_assets' expect(AssetSync.config.manifest_path).to match(/public\/custom_assets\/manifest.yml/) end end describe 'with cache_asset_regexps' do before(:each) do AssetSync.config = AssetSync::Config.new end it "config.cache_asset_regexp should set cache_asset_regexps" do AssetSync.config.cache_asset_regexp = /\.[a-f0-9]{8}/i expect(AssetSync.config.cache_asset_regexps.size).to eq(1) expect(AssetSync.config.cache_asset_regexps[0]).to eq(/\.[a-f0-9]{8}/i) end it "set cache_asset_regexps" do AssetSync.config.cache_asset_regexps = ["app.abc123.js", /\.[a-f0-9]{10}/i] expect(AssetSync.config.cache_asset_regexps.size).to eq(2) expect(AssetSync.config.cache_asset_regexps).to eq(["app.abc123.js", /\.[a-f0-9]{10}/i]) end end describe 'with invalid yml' do before(:each) do set_rails_root('with_invalid_yml') end it "an error" do expect{ AssetSync::Config.new }.to raise_error(Psych::SyntaxError) end end describe 'FogPublicValue' do describe "#to_bool" do it "true should be converted to true" do expect(AssetSync::Config::FogPublicValue.new(true).to_bool).to be_truthy end it "false should be converted to false" do expect(AssetSync::Config::FogPublicValue.new(false).to_bool).to be_falsey end it "nil should be converted to false" do expect(AssetSync::Config::FogPublicValue.new(nil).to_bool).to be_falsey end it "'default' should be converted to false" do expect(AssetSync::Config::FogPublicValue.new("default").to_bool).to be_truthy end end describe "#use_explicit_value?" do it "true should be converted to true" do expect(AssetSync::Config::FogPublicValue.new(true).use_explicit_value?).to be_truthy end it "false should be converted to true" do expect(AssetSync::Config::FogPublicValue.new(false).use_explicit_value?).to be_truthy end it "nil should be converted to true" do expect(AssetSync::Config::FogPublicValue.new(nil).use_explicit_value?).to be_truthy end it "'default' should be converted to false" do expect(AssetSync::Config::FogPublicValue.new("default").use_explicit_value?).to be_falsey end end end end asset_sync-2.11.0/spec/unit/azure_rm_spec.rb000066400000000000000000000102101363256206300210420ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../spec_helper' describe AssetSync do include_context "mock Rails without_yml" describe 'with initializer' do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.fog_provider = 'AzureRM' config.azure_storage_account_name = 'aaaa' config.azure_storage_access_key = 'bbbb' config.fog_directory = 'mybucket' config.existing_remote_files = "keep" end end it "should configure provider as AzureRM" do expect(AssetSync.config.fog_provider).to eq('AzureRM') expect(AssetSync.config).to be_azure_rm end it "should should keep existing remote files" do expect(AssetSync.config.existing_remote_files?).to eq(true) end it "should configure azure_storage_account_name" do expect(AssetSync.config.azure_storage_account_name).to eq("aaaa") end it "should configure azure_storage_access_key" do expect(AssetSync.config.azure_storage_access_key).to eq("bbbb") end it "should configure fog_directory" do expect(AssetSync.config.fog_directory).to eq("mybucket") end it "should configure existing_remote_files" do expect(AssetSync.config.existing_remote_files).to eq("keep") end it "should default gzip_compression to false" do expect(AssetSync.config.gzip_compression).to be_falsey end it "should default manifest to false" do expect(AssetSync.config.manifest).to be_falsey end end describe 'from yml' do before(:each) do set_rails_root('azure_rm_with_yml') AssetSync.config = AssetSync::Config.new end it "should configure azure_storage_account_name" do expect(AssetSync.config.azure_storage_account_name).to eq("xxxx") end it "should configure azure_storage_access_key" do expect(AssetSync.config.azure_storage_access_key).to eq("zzzz") end it "should configure fog_directory" do expect(AssetSync.config.fog_directory).to eq("rails_app_test") end it "should configure existing_remote_files" do expect(AssetSync.config.existing_remote_files).to eq("keep") end it "should default gzip_compression to false" do expect(AssetSync.config.gzip_compression).to be_falsey end it "should default manifest to false" do expect(AssetSync.config.manifest).to be_falsey end end describe 'with no configuration' do before(:each) do AssetSync.config = AssetSync::Config.new end it "should be invalid" do expect{ AssetSync.sync }.to raise_error(::AssetSync::Config::Invalid) end end describe 'with fail_silent configuration' do before(:each) do allow(AssetSync).to receive(:stderr).and_return(StringIO.new) AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.fail_silently = true end end it "should not raise an invalid exception" do expect{ AssetSync.sync }.not_to raise_error end end describe 'with gzip_compression enabled' do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.config.gzip_compression = true end it "config.gzip? should be true" do expect(AssetSync.config.gzip?).to be_truthy end end describe 'with manifest enabled' do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.config.manifest = true end it "config.manifest should be true" do expect(AssetSync.config.manifest).to be_truthy end it "config.manifest_path should default to public/assets.." do expect(AssetSync.config.manifest_path).to match(/public\/assets\/manifest.yml/) end it "config.manifest_path should default to public/assets.." do Rails.application.config.assets.manifest = "/var/assets" expect(AssetSync.config.manifest_path).to eq("/var/assets/manifest.yml") end it "config.manifest_path should default to public/custom_assets.." do Rails.application.config.assets.prefix = 'custom_assets' expect(AssetSync.config.manifest_path).to match(/public\/custom_assets\/manifest.yml/) end end end asset_sync-2.11.0/spec/unit/google_spec.rb000066400000000000000000000152761363256206300205130ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../spec_helper' describe AssetSync do include_context "mock Rails without_yml" describe 'with initializer' do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.fog_provider = 'Google' config.fog_directory = 'mybucket' config.existing_remote_files = "keep" end end it "should configure provider as Google" do expect(AssetSync.config.fog_provider).to eq('Google') expect(AssetSync.config).to be_google end it "should should keep existing remote files" do expect(AssetSync.config.existing_remote_files?).to eq(true) end it "should configure fog_directory" do expect(AssetSync.config.fog_directory).to eq("mybucket") end it "should configure existing_remote_files" do expect(AssetSync.config.existing_remote_files).to eq("keep") end it "should default gzip_compression to false" do expect(AssetSync.config.gzip_compression).to be_falsey end it "should default manifest to false" do expect(AssetSync.config.manifest).to be_falsey end describe "when using S3 interop API" do before(:each) do AssetSync.configure do |config| config.google_storage_access_key_id = 'aaaa' config.google_storage_secret_access_key = 'bbbb' end end it "should configure google_storage_access_key_id" do expect(AssetSync.config.google_storage_access_key_id).to eq("aaaa") end it "should configure google_storage_secret_access_key" do expect(AssetSync.config.google_storage_secret_access_key).to eq("bbbb") end it "should return the correct fog_options" do expected_fog_options = { google_storage_access_key_id: "aaaa", google_storage_secret_access_key: "bbbb", provider: "Google"} expect(AssetSync.config.fog_options).to eq(expected_fog_options) end it "should not require that google_json_key_location be set" do expect(AssetSync.config.valid?).to eq(true) end it "should require that google_storage_secret_access_key or access_key_id be set" do AssetSync.configure do |config| config.google_storage_access_key_id = nil config.google_storage_secret_access_key = nil end expect(AssetSync.config.valid?).to eq(false) end end describe "when using service account" do before(:each) do AssetSync.configure do |config| config.google_json_key_location = '/path/to.json' config.google_project = 'a-google-project-name' end end it "should configure google_json_key_location" do expect(AssetSync.config.google_json_key_location).to eq("/path/to.json") end it "should return the correct fog_options" do expected_fog_options = { google_json_key_location: "/path/to.json", google_project: 'a-google-project-name', provider: "Google"} expect(AssetSync.config.fog_options).to eq(expected_fog_options) end it "should not require that google_storage_secret_access_key or access_key_id be set" do expect(AssetSync.config.valid?).to eq(true) end end end describe 'from yml' do describe 'when using S3 interop API' do before(:each) do set_rails_root('google_with_yml') AssetSync.config = AssetSync::Config.new end it "should configure google_storage_access_key_id" do expect(AssetSync.config.google_storage_access_key_id).to eq("xxxx") end it "should configure google_storage_secret_access_key" do expect(AssetSync.config.google_storage_secret_access_key).to eq("zzzz") end it "should not configure google_json_key_location" do expect(AssetSync.config.google_json_key_location).to eq(nil) end it "should configure fog_directory" do expect(AssetSync.config.fog_directory).to eq("rails_app_test") end it "should configure existing_remote_files" do expect(AssetSync.config.existing_remote_files).to eq("keep") end it "should default gzip_compression to false" do expect(AssetSync.config.gzip_compression).to be_falsey end it "should default manifest to false" do expect(AssetSync.config.manifest).to be_falsey end end describe 'when using service account API' do before(:each) do set_rails_root('google_with_service_account_yml') AssetSync.config = AssetSync::Config.new end it "should configure google_json_key_location" do expect(AssetSync.config.google_json_key_location).to eq("gcs.json") end it "should not configure google_storage_secret_access_key" do expect(AssetSync.config.google_storage_secret_access_key).to eq(nil) end end end describe 'with no configuration' do before(:each) do AssetSync.config = AssetSync::Config.new end it "should be invalid" do expect{ AssetSync.sync }.to raise_error(::AssetSync::Config::Invalid) end end describe 'with fail_silent configuration' do before(:each) do allow(AssetSync).to receive(:stderr).and_return(StringIO.new) AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.fail_silently = true end end it "should not raise an invalid exception" do expect{ AssetSync.sync }.not_to raise_error end end describe 'with gzip_compression enabled' do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.config.gzip_compression = true end it "config.gzip? should be true" do expect(AssetSync.config.gzip?).to be_truthy end end describe 'with manifest enabled' do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.config.manifest = true end it "config.manifest should be true" do expect(AssetSync.config.manifest).to be_truthy end it "config.manifest_path should default to public/assets.." do expect(AssetSync.config.manifest_path).to match(/public\/assets\/manifest.yml/) end it "config.manifest_path should default to public/assets.." do Rails.application.config.assets.manifest = "/var/assets" expect(AssetSync.config.manifest_path).to eq("/var/assets/manifest.yml") end it "config.manifest_path should default to public/custom_assets.." do Rails.application.config.assets.prefix = 'custom_assets' expect(AssetSync.config.manifest_path).to match(/public\/custom_assets\/manifest.yml/) end end end asset_sync-2.11.0/spec/unit/multi_mime_spec.rb000066400000000000000000000056661363256206300214020ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../spec_helper' describe AssetSync::MultiMime do before(:each) do # Object#remove_const does not remove the loaded # file from the $" variable # # So we need do both # # 1. Remove constant(s) to avoid warning messages # 2. Remove loaded file(s) Object.send(:remove_const, :Rails) if defined?(Rails) Object.send(:remove_const, :Mime) if defined?(Mime) Object.send(:remove_const, :Rack) if defined?(Rack) Object.send(:remove_const, :MIME) if defined?(MIME) $".grep(/mime\//).each do |file_path| $".delete(file_path) end end after(:each) do # Object#remove_const does not remove the loaded # file from the $" variable # # So we need do both # # 1. Remove constant(s) to avoid warning messages # 2. Remove loaded file(s) Object.send(:remove_const, :Rails) if defined?(Rails) Object.send(:remove_const, :Mime) if defined?(Mime) Object.send(:remove_const, :Rack) if defined?(Rack) Object.send(:remove_const, :MIME) if defined?(MIME) $".grep(/mime\//).each do |file_path| $".delete(file_path) end AssetSync.config = AssetSync::Config.new end after(:all) do require 'mime/types' end describe 'Mime::Type' do it 'should detect mime type' do require 'rails' expect(AssetSync::MultiMime.lookup('css')).to eq("text/css") end end describe 'Rack::Mime' do it 'should detect mime type' do require 'rack/mime' expect(AssetSync::MultiMime.lookup('css')).to eq("text/css") end end describe 'MIME::Types' do it 'should detect mime type' do require 'mime/types' expect(AssetSync::MultiMime.lookup('css')).to eq("text/css") end end describe "use of option file_ext_to_mime_type_overrides" do before(:each) do require 'mime/types' end context "with default value" do it "should return default value set by gem" do expect( AssetSync::MultiMime.lookup("js").to_s, ).to eq("application/javascript") end end context "with empty value" do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.file_ext_to_mime_type_overrides.clear end end it "should return value from mime-types gem" do expect( AssetSync::MultiMime.lookup("js").to_s, ).to eq(::MIME::Types.type_for("js").first.to_s) end end context "with custom value" do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.file_ext_to_mime_type_overrides.add( :js, :"application/x-javascript", ) end end it "should return custom value" do expect( AssetSync::MultiMime.lookup("js").to_s, ).to eq("application/x-javascript") end end end end asset_sync-2.11.0/spec/unit/rackspace_spec.rb000066400000000000000000000051101363256206300211550ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../spec_helper' describe AssetSync do include_context "mock Rails" describe 'using Rackspace with initializer' do before(:each) do set_rails_root('without_yml') AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.fog_provider = 'Rackspace' config.fog_directory = 'mybucket' config.fog_region = 'dunno' config.rackspace_username = 'aaaa' config.rackspace_api_key = 'bbbb' config.existing_remote_files = 'keep' end end it "should configure provider as Rackspace" do expect(AssetSync.config.fog_provider).to eq('Rackspace') expect(AssetSync.config).to be_rackspace end it "should keep existing remote files" do expect(AssetSync.config.existing_remote_files?).to eq(true) end it "should configure rackspace_username" do expect(AssetSync.config.rackspace_username).to eq("aaaa") end it "should configure rackspace_api_key" do expect(AssetSync.config.rackspace_api_key).to eq("bbbb") end it "should configure fog_directory" do expect(AssetSync.config.fog_directory).to eq("mybucket") end it "should configure fog_region" do expect(AssetSync.config.fog_region).to eq("dunno") end it "should configure existing_remote_files" do expect(AssetSync.config.existing_remote_files).to eq("keep") end it "should configure existing_remote_files" do expect(AssetSync.config.existing_remote_files).to eq("keep") end it "should default rackspace_auth_url to false" do expect(AssetSync.config.rackspace_auth_url).to be_falsey end end describe 'using Rackspace from yml' do before(:each) do set_rails_root('rackspace_with_yml') AssetSync.config = AssetSync::Config.new end it "should keep existing remote files" do expect(AssetSync.config.existing_remote_files?).to eq(true) end it "should configure rackspace_username" do expect(AssetSync.config.rackspace_username).to eq("xxxx") end it "should configure rackspace_api_key" do expect(AssetSync.config.rackspace_api_key).to eq("zzzz") end it "should configure fog_directory" do expect(AssetSync.config.fog_directory).to eq("rails_app_test") end it "should configure fog_region" do expect(AssetSync.config.fog_region).to eq("eu-west-1") end it "should configure existing_remote_files" do expect(AssetSync.config.existing_remote_files).to eq("keep") end end end asset_sync-2.11.0/spec/unit/railsless_spec.rb000066400000000000000000000041461363256206300212320ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../spec_helper' describe AssetSync do include_context "mock without Rails" describe 'with initializer' do before(:each) do AssetSync.config = AssetSync::Config.new AssetSync.configure do |config| config.fog_provider = 'AWS' config.aws_access_key_id = 'aaaa' config.aws_secret_access_key = 'bbbb' config.fog_directory = 'mybucket' config.fog_region = 'eu-west-1' config.existing_remote_files = "keep" config.prefix = "assets" config.public_path = "./public" end end it "should have prefix of assets" do expect(AssetSync.config.prefix).to eq("assets") end it "should have public_path" do expect(AssetSync.config.public_path.to_s).to be_end_with("/public") expect(AssetSync.config.public_path).to be_absolute end it "should default AssetSync to enabled" do expect(AssetSync.config.enabled?).to be_truthy expect(AssetSync.enabled?).to be_truthy end it "should configure provider as AWS" do expect(AssetSync.config.fog_provider).to eq('AWS') expect(AssetSync.config).to be_aws end it "should should keep existing remote files" do expect(AssetSync.config.existing_remote_files?).to eq(true) end it "should configure aws_access_key" do expect(AssetSync.config.aws_access_key_id).to eq("aaaa") end it "should configure aws_secret_access_key" do expect(AssetSync.config.aws_secret_access_key).to eq("bbbb") end it "should configure aws_access_key" do expect(AssetSync.config.fog_directory).to eq("mybucket") end it "should configure fog_region" do expect(AssetSync.config.fog_region).to eq("eu-west-1") end it "should configure existing_remote_files" do expect(AssetSync.config.existing_remote_files).to eq("keep") end it "should default gzip_compression to false" do expect(AssetSync.config.gzip_compression).to be_falsey end it "should default manifest to false" do expect(AssetSync.config.manifest).to be_falsey end end end asset_sync-2.11.0/spec/unit/storage_spec.rb000066400000000000000000000400001363256206300206620ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../spec_helper' describe AssetSync::Storage do include_context "mock Rails without_yml" let(:file_like_object) do double("file like object").as_null_object end describe '#upload_files' do before(:each) do @local_files = ["local_image2.jpg", "local_image1.jpg", "local_stylesheet1.css", "local_stylesheet2.css"] @remote_files = ["local_image.jpg", "local_image3.svg", "local_image4.svg", "local_stylesheet1.css"] @config = AssetSync::Config.new end it 'should overwrite all remote files if set to ignore' do @config.existing_remote_files = 'ignore' storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) allow(File).to receive(:file?).and_return(true) # Pretend they all exist @local_files.each do |file| expect(storage).to receive(:upload_file).with(file) end storage.upload_files end it 'should allow force overwriting of specific files' do @config.always_upload = ['local_image.jpg', /local_image\d\.svg/] storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) allow(File).to receive(:file?).and_return(true) # Pretend they all exist (@local_files - @remote_files + storage.always_upload_files).each do |file| expect(storage).to receive(:upload_file).with(file) end storage.upload_files end it 'should allow to ignore files' do @config.ignored_files = ['local_image1.jpg', /local_stylesheet\d\.css/] storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) allow(File).to receive(:file?).and_return(true) # Pretend they all exist (@local_files - @remote_files - storage.ignored_files + storage.always_upload_files).each do |file| expect(storage).to receive(:upload_file).with(file) end storage.upload_files end it 'should upload files concurrently if enabled' do @config.concurrent_uploads = true storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) allow(File).to receive(:file?).and_return(true) # Pretend they all exist expect(Thread).to receive(:new).exactly(3).times.and_call_original (@local_files - @remote_files + storage.always_upload_files).each do |file| expect(storage).to receive(:upload_file).with(file) end storage.upload_files end it 'should allow custom number of threads' do @config.concurrent_uploads = true @config.concurrent_uploads_max_threads = 2 storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) allow(File).to receive(:file?).and_return(true) # Pretend they all exist expect(Thread).to receive(:new).exactly(2).times.and_call_original (@local_files - @remote_files + storage.always_upload_files).each do |file| expect(storage).to receive(:upload_file).with(file) end storage.upload_files end it 'should allow remote_file_list_cache_file_path configuration' do file_path = './foo.json' @config.remote_file_list_cache_file_path = file_path storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) File.write(file_path, @remote_files.to_json) expect(storage).not_to receive(:get_remote_files) allow(File).to receive(:file?).and_return(true) # Pretend they all exist (@local_files - @remote_files + storage.always_upload_files).each do |file| expect(storage).to receive(:upload_file).with(file) end expect(storage).not_to receive(:warn) storage.upload_files # update remote_file_list_cache corretly updated = JSON.parse(File.read(file_path)) expect(updated.sort.uniq).to eq (@remote_files + @local_files + storage.always_upload_files).sort.uniq File.delete(file_path) end it 'should work with broken cache' do file_path = './foo.json' @config.remote_file_list_cache_file_path = file_path storage = AssetSync::Storage.new(@config) File.write(file_path, 'some non-json text file content') allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) allow(File).to receive(:file?).and_return(true) # Pretend they all exist (@local_files - @remote_files + storage.always_upload_files).each do |file| expect(storage).to receive(:upload_file).with(file) end # when broken, warning message should be prompted expect(storage).to receive(:warn) storage.upload_files File.delete(file_path) end it 'should upload updated non-fingerprinted files' do @local_files = [ 'public/image.png', 'public/image-82389298328.png', 'public/image-a8389f9h324.png', 'public/application.js', 'public/application-b3389d983k1.js', 'public/application-ac387d53f31.js', 'public', ] @remote_files = [ 'public/image.png', 'public/image-a8389f9h324.png', 'public/application.js', 'public/application-b3389d983k1.js', ] storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) allow(File).to receive(:file?).and_return(true) # Pretend they all exist updated_nonfingerprinted_files = [ 'public/image.png', 'public/application.js', ] (@local_files - @remote_files + updated_nonfingerprinted_files).each do |file| expect(storage).to receive(:upload_file).with(file) end storage.upload_files end context "when config #add_local_file_paths is called" do let(:additional_local_file_paths) do ["webpack/example_asset.jpg"] end before(:each) do @config.add_local_file_paths do additional_local_file_paths end end let(:storage) do AssetSync::Storage.new(@config) end let(:file_paths_should_be_uploaded) do @local_files - @remote_files - storage.ignored_files + storage.always_upload_files + additional_local_file_paths end before do # Stubbing allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) # Pretend the files all exist allow(File).to receive(:file?).and_return(true) end it "uploads additional files in additional to local files" do file_paths_should_be_uploaded.each do |file| expect(storage).to receive(:upload_file).with(file) end storage.upload_files end end it 'should upload additonal files' do @local_files = [ 'public/image.png', 'public/image-82389298328.png', 'public/image-a8389f9h324.png', 'public/application.js', 'public/application-b3389d983k1.js', 'public/application-ac387d53f31.js', 'public', ] @remote_files = [ 'public/image.png', 'public/image-a8389f9h324.png', 'public/application.js', 'public/application-b3389d983k1.js', ] storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) allow(File).to receive(:file?).and_return(true) # Pretend they all exist updated_nonfingerprinted_files = [ 'public/image.png', 'public/application.js', ] (@local_files - @remote_files + updated_nonfingerprinted_files).each do |file| expect(storage).to receive(:upload_file).with(file) end storage.upload_files end it 'should correctly set expire date' do local_files = [ 'file1.jpg', 'file1-1234567890abcdef1234567890abcdef.jpg', 'file1-1234567890abcdef1234567890abcdef.jpg.gz', 'file1-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef.jpg', 'file1-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef.jpg.gz' ] local_files += [ 'dir1/dir2/file2.jpg', 'dir1/dir2/file2-1234567890abcdef1234567890abcdef.jpg', 'dir1/dir2/file2-1234567890abcdef1234567890abcdef.jpg.gz', 'dir1/dir2/file2-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef.jpg', 'dir1/dir2/file2-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef.jpg.gz' ] local_files += [ 'file3.png', 'file3.zabcde.png', 'file3.zab1cde2.png', 'file3.abcdef.jpg', 'file3.abc1def2.jpg', 'dir3/file3.abc123.jpg', 'dir3/file3.abcdf123.jpg' ] remote_files = [] @config.cache_asset_regexps = [/\.[a-f0-9]{6}$/i, /\.[a-f0-9]{8}$/i] storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(local_files) allow(storage).to receive(:get_remote_files).and_return(remote_files) allow(File).to receive(:file?).and_return(true) allow(File).to receive(:open).and_return(file_like_object) def check_file(file) case file[:key] when 'file1.jpg', 'dir1/dir2/file2.jpg', 'file3.png', 'file3.zabcde.png', 'file3.zab1cde2.png' !expect(file).not_to include(:cache_control, :expires) when 'file1-1234567890abcdef1234567890abcdef.jpg', 'file1-1234567890abcdef1234567890abcdef.jpg.gz', 'file1-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef.jpg', 'file1-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef.jpg.gz', 'dir1/dir2/file2-1234567890abcdef1234567890abcdef.jpg', 'dir1/dir2/file2-1234567890abcdef1234567890abcdef.jpg.gz', 'dir1/dir2/file2-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef.jpg', 'dir1/dir2/file2-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef.jpg.gz', 'file3.abcdef.jpg', 'file3.abc1def2.jpg', 'dir3/file3.abc123.jpg', 'dir3/file3.abcdf123.jpg' expect(file).to include(:cache_control, :expires) else fail end end files = double() local_files.count.times do expect(files).to receive(:create) { |file| check_file(file) } end allow(storage).to receive_message_chain(:bucket, :files).and_return(files) storage.upload_files end it "should invalidate files" do @config.cdn_distribution_id = "1234" @config.invalidate = ['local_image1.jpg'] @config.fog_provider = 'AWS' storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) allow(storage).to receive(:upload_file).and_return(true) mock_cdn = double expect(Fog::CDN).to receive(:new).and_return(mock_cdn) expect(mock_cdn).to receive(:post_invalidation).with("1234", ["/assets/local_image1.jpg"]).and_return(double({:body => {:id => '1234'}})) storage.upload_files end end describe '#upload_file' do before(:each) do # Object#remove_const does not remove the loaded # file from the $" variable # # So we need do both # # 1. Remove constant(s) to avoid warning messages # 2. Remove loaded file(s) Object.send(:remove_const, :MIME) if defined?(MIME) $".grep(/mime\//).each do |file_path| $".delete(file_path) end require 'mime/types' @config = AssetSync::Config.new end it 'accepts custom headers per file' do @config.custom_headers = { "local_image2.jpg" => { :cache_control => 'max-age=0' } } storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) # Pretend they all exist allow(File).to receive(:open).and_return(file_like_object) bucket = double files = double allow(storage).to receive(:bucket).and_return(bucket) allow(bucket).to receive(:files).and_return(files) expect(files).to receive(:create) do |argument| expect(argument[:cache_control]).to eq('max-age=0') end storage.upload_file('assets/local_image2.jpg') end it 'accepts custom headers with a regular expression' do @config.custom_headers = { ".*\.jpg" => { :cache_control => 'max-age=0' } } storage = AssetSync::Storage.new(@config) allow(storage).to receive(:get_local_files).and_return(@local_files) allow(storage).to receive(:get_remote_files).and_return(@remote_files) # Pretend they all exist allow(File).to receive(:open).and_return(file_like_object) bucket = double files = double allow(storage).to receive(:bucket).and_return(bucket) allow(bucket).to receive(:files).and_return(files) expect(files).to receive(:create) do |argument| expect(argument[:cache_control]).to eq('max-age=0') end storage.upload_file('assets/some_longer_path/local_image2.jpg') end end describe '#delete_extra_remote_files' do it 'should delete the files in bulk' do remote_files = ['public/image.png'] connection = double config = double storage = AssetSync::Storage.new(@config) [:local_files, :ignored_files, :always_upload_files].each do |method| expect(storage).to receive(method).and_return([]) end allow(storage).to receive(:get_remote_files).and_return(remote_files) allow(storage).to receive(:connection).and_return(connection).twice allow(storage).to receive(:config).and_return(config).twice allow(config).to receive(:aws?).and_return(true) allow(config).to receive(:fog_directory).and_return('foo') expect(connection).to receive(:delete_multiple_objects).with('foo', remote_files) storage.delete_extra_remote_files end context 'when not aws' do it 'deletes files sequentially' do remote_files = ['public/image.png'] connection = double config = double directories = double directory = double file = double storage = AssetSync::Storage.new(@config) [:local_files, :ignored_files, :always_upload_files].each do |method| expect(storage).to receive(method).and_return([]) end allow(storage).to receive(:get_remote_files).and_return(remote_files) allow(storage).to receive(:connection).and_return(connection).twice allow(storage).to receive(:config).and_return(config) allow(config).to receive(:aws?).and_return(false) allow(config).to receive(:fog_directory).and_return('foo') allow(config).to receive(:assets_prefix).and_return('foo') allow(directories).to receive(:get).and_return(directory) allow(directory).to receive(:files).and_return([file]) allow(file).to receive(:key).and_return('public/image.png') allow(connection).to receive(:directories).and_return(directories) expect(connection).not_to receive(:delete_multiple_objects) expect(file).to receive(:destroy) storage.delete_extra_remote_files end end end end