multi_sync 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.gitignore +20 -0
  4. data/.rubocop.yml +26 -0
  5. data/.travis.yml +24 -0
  6. data/.yardopts +6 -0
  7. data/CHANGELOG.md +0 -0
  8. data/CONTRIBUTING.md +44 -0
  9. data/Gemfile +17 -0
  10. data/LICENSE.md +20 -0
  11. data/README.md +134 -0
  12. data/Rakefile +45 -0
  13. data/examples/custom.rb +34 -0
  14. data/examples/rails-3-2/.gitignore +15 -0
  15. data/examples/rails-3-2/Gemfile +43 -0
  16. data/examples/rails-3-2/README.rdoc +261 -0
  17. data/examples/rails-3-2/Rakefile +7 -0
  18. data/examples/rails-3-2/app/assets/images/rails.png +0 -0
  19. data/examples/rails-3-2/app/assets/javascripts/application.js +15 -0
  20. data/examples/rails-3-2/app/assets/stylesheets/application.css +13 -0
  21. data/examples/rails-3-2/app/controllers/application_controller.rb +3 -0
  22. data/examples/rails-3-2/app/helpers/application_helper.rb +2 -0
  23. data/examples/rails-3-2/app/mailers/.gitkeep +0 -0
  24. data/examples/rails-3-2/app/models/.gitkeep +0 -0
  25. data/examples/rails-3-2/app/views/layouts/application.html.erb +14 -0
  26. data/examples/rails-3-2/config.ru +4 -0
  27. data/examples/rails-3-2/config/application.rb +62 -0
  28. data/examples/rails-3-2/config/asset_sync.yml +21 -0
  29. data/examples/rails-3-2/config/boot.rb +6 -0
  30. data/examples/rails-3-2/config/database.yml +25 -0
  31. data/examples/rails-3-2/config/environment.rb +5 -0
  32. data/examples/rails-3-2/config/environments/development.rb +37 -0
  33. data/examples/rails-3-2/config/environments/production.rb +67 -0
  34. data/examples/rails-3-2/config/environments/test.rb +37 -0
  35. data/examples/rails-3-2/config/initializers/backtrace_silencers.rb +7 -0
  36. data/examples/rails-3-2/config/initializers/inflections.rb +15 -0
  37. data/examples/rails-3-2/config/initializers/mime_types.rb +5 -0
  38. data/examples/rails-3-2/config/initializers/multi_sync.rb +29 -0
  39. data/examples/rails-3-2/config/initializers/secret_token.rb +7 -0
  40. data/examples/rails-3-2/config/initializers/session_store.rb +8 -0
  41. data/examples/rails-3-2/config/initializers/wrap_parameters.rb +14 -0
  42. data/examples/rails-3-2/config/locales/en.yml +5 -0
  43. data/examples/rails-3-2/config/routes.rb +58 -0
  44. data/examples/rails-3-2/db/seeds.rb +7 -0
  45. data/examples/rails-3-2/lib/assets/.gitkeep +0 -0
  46. data/examples/rails-3-2/lib/tasks/.gitkeep +0 -0
  47. data/examples/rails-3-2/log/.gitkeep +0 -0
  48. data/examples/rails-3-2/public/404.html +26 -0
  49. data/examples/rails-3-2/public/422.html +26 -0
  50. data/examples/rails-3-2/public/500.html +25 -0
  51. data/examples/rails-3-2/public/favicon.ico +0 -0
  52. data/examples/rails-3-2/public/index.html +241 -0
  53. data/examples/rails-3-2/public/robots.txt +5 -0
  54. data/examples/rails-3-2/script/rails +6 -0
  55. data/examples/rails-3-2/test/fixtures/.gitkeep +0 -0
  56. data/examples/rails-3-2/test/functional/.gitkeep +0 -0
  57. data/examples/rails-3-2/test/integration/.gitkeep +0 -0
  58. data/examples/rails-3-2/test/performance/browsing_test.rb +12 -0
  59. data/examples/rails-3-2/test/test_helper.rb +13 -0
  60. data/examples/rails-3-2/test/unit/.gitkeep +0 -0
  61. data/examples/rails-4-0/.gitignore +16 -0
  62. data/examples/rails-4-0/Gemfile +50 -0
  63. data/examples/rails-4-0/README.rdoc +28 -0
  64. data/examples/rails-4-0/Rakefile +6 -0
  65. data/examples/rails-4-0/app/assets/images/.keep +0 -0
  66. data/examples/rails-4-0/app/assets/javascripts/application.js +16 -0
  67. data/examples/rails-4-0/app/assets/stylesheets/application.css +13 -0
  68. data/examples/rails-4-0/app/controllers/application_controller.rb +5 -0
  69. data/examples/rails-4-0/app/controllers/concerns/.keep +0 -0
  70. data/examples/rails-4-0/app/helpers/application_helper.rb +2 -0
  71. data/examples/rails-4-0/app/mailers/.keep +0 -0
  72. data/examples/rails-4-0/app/models/.keep +0 -0
  73. data/examples/rails-4-0/app/models/concerns/.keep +0 -0
  74. data/examples/rails-4-0/app/views/layouts/application.html.erb +14 -0
  75. data/examples/rails-4-0/config.ru +4 -0
  76. data/examples/rails-4-0/config/application.rb +24 -0
  77. data/examples/rails-4-0/config/asset_sync.yml +21 -0
  78. data/examples/rails-4-0/config/boot.rb +4 -0
  79. data/examples/rails-4-0/config/database.yml +25 -0
  80. data/examples/rails-4-0/config/environment.rb +5 -0
  81. data/examples/rails-4-0/config/environments/development.rb +29 -0
  82. data/examples/rails-4-0/config/environments/production.rb +80 -0
  83. data/examples/rails-4-0/config/environments/test.rb +36 -0
  84. data/examples/rails-4-0/config/initializers/backtrace_silencers.rb +7 -0
  85. data/examples/rails-4-0/config/initializers/filter_parameter_logging.rb +4 -0
  86. data/examples/rails-4-0/config/initializers/inflections.rb +16 -0
  87. data/examples/rails-4-0/config/initializers/mime_types.rb +5 -0
  88. data/examples/rails-4-0/config/initializers/multi_sync.rb +29 -0
  89. data/examples/rails-4-0/config/initializers/secret_token.rb +12 -0
  90. data/examples/rails-4-0/config/initializers/session_store.rb +3 -0
  91. data/examples/rails-4-0/config/initializers/wrap_parameters.rb +14 -0
  92. data/examples/rails-4-0/config/locales/en.yml +23 -0
  93. data/examples/rails-4-0/config/routes.rb +56 -0
  94. data/examples/rails-4-0/db/seeds.rb +7 -0
  95. data/examples/rails-4-0/lib/assets/.keep +0 -0
  96. data/examples/rails-4-0/lib/tasks/.keep +0 -0
  97. data/examples/rails-4-0/log/.keep +0 -0
  98. data/examples/rails-4-0/public/404.html +58 -0
  99. data/examples/rails-4-0/public/422.html +58 -0
  100. data/examples/rails-4-0/public/500.html +57 -0
  101. data/examples/rails-4-0/public/favicon.ico +0 -0
  102. data/examples/rails-4-0/public/robots.txt +5 -0
  103. data/examples/rails-4-0/test/controllers/.keep +0 -0
  104. data/examples/rails-4-0/test/fixtures/.keep +0 -0
  105. data/examples/rails-4-0/test/helpers/.keep +0 -0
  106. data/examples/rails-4-0/test/integration/.keep +0 -0
  107. data/examples/rails-4-0/test/mailers/.keep +0 -0
  108. data/examples/rails-4-0/test/models/.keep +0 -0
  109. data/examples/rails-4-0/test/test_helper.rb +15 -0
  110. data/gemfiles/middleman-3.1.x.gemfile +5 -0
  111. data/gemfiles/rails-3.2.x.gemfile +5 -0
  112. data/gemfiles/rails-4.0.x.gemfile +5 -0
  113. data/lib/multi_sync.rb +92 -0
  114. data/lib/multi_sync/client.rb +243 -0
  115. data/lib/multi_sync/configuration.rb +36 -0
  116. data/lib/multi_sync/environment.rb +37 -0
  117. data/lib/multi_sync/extensions/middleman.rb +22 -0
  118. data/lib/multi_sync/extensions/rails.rb +20 -0
  119. data/lib/multi_sync/extensions/rails/asset_sync.rb +44 -0
  120. data/lib/multi_sync/extensions/rails/railtie.rb +11 -0
  121. data/lib/multi_sync/logging.rb +60 -0
  122. data/lib/multi_sync/mixins/log_helper.rb +9 -0
  123. data/lib/multi_sync/mixins/pluralize_helper.rb +15 -0
  124. data/lib/multi_sync/resource.rb +84 -0
  125. data/lib/multi_sync/resources/local_resource.rb +30 -0
  126. data/lib/multi_sync/resources/remote_resource.rb +32 -0
  127. data/lib/multi_sync/source.rb +40 -0
  128. data/lib/multi_sync/sources/local_source.rb +17 -0
  129. data/lib/multi_sync/sources/manifest_source.rb +82 -0
  130. data/lib/multi_sync/target.rb +34 -0
  131. data/lib/multi_sync/targets/aws_target.rb +80 -0
  132. data/lib/multi_sync/targets/local_target.rb +58 -0
  133. data/lib/multi_sync/version.rb +3 -0
  134. data/lib/tasks/multi_sync_rails.rake +15 -0
  135. data/multi_sync.gemspec +35 -0
  136. data/spec/spec_helper.rb +22 -0
  137. data/spec/support/celluloid.rb +14 -0
  138. data/spec/support/fakefs.rb +7 -0
  139. data/spec/support/fog.rb +25 -0
  140. data/spec/support/pry.rb +6 -0
  141. data/spec/support/timecop.rb +2 -0
  142. data/spec/unit/multi_sync/client_spec.rb +301 -0
  143. data/spec/unit/multi_sync/configuration_spec.rb +92 -0
  144. data/spec/unit/multi_sync/resources/local_resource_spec.rb +55 -0
  145. data/spec/unit/multi_sync/sources/local_source_spec.rb +48 -0
  146. data/spec/unit/multi_sync/sources/manifest_source_spec.rb +57 -0
  147. data/spec/unit/multi_sync/targets/aws_target_spec.rb +60 -0
  148. data/spec/unit/multi_sync/targets/local_target_spec.rb +41 -0
  149. data/spec/unit/multi_sync_spec.rb +55 -0
  150. metadata +377 -0
@@ -0,0 +1,80 @@
1
+ require 'multi_sync/target'
2
+ require 'multi_sync/resources/remote_resource'
3
+
4
+ module MultiSync
5
+ class AwsTarget < Target
6
+ # Initialize a new AwsTarget object
7
+ #
8
+ # @param options [Hash]
9
+ def initialize(options = {})
10
+ super(options)
11
+ self.connection = ::Fog::Storage.new(credentials.merge(provider: :aws))
12
+ end
13
+
14
+ def files
15
+ files = []
16
+
17
+ directory = connection.directories.get(target_dir.to_s, prefix: destination_dir.to_s)
18
+ return files if directory.nil?
19
+
20
+ directory.files.lazily.each { |file|
21
+
22
+ pathname = Pathname.new(file.key)
23
+
24
+ # eg directory or overreaching AWS globbing
25
+ next unless valid_path?(pathname)
26
+
27
+ files << MultiSync::RemoteResource.new(
28
+ file: file,
29
+ with_root: target_dir + pathname, # pathname seems to already have the prefix (destination_dir)
30
+ without_root: destination_dir != '' ? pathname.relative_path_from(destination_dir).cleanpath : pathname
31
+ )
32
+
33
+ }
34
+
35
+ files
36
+ end
37
+
38
+ def upload(resource)
39
+ MultiSync.say_status :upload, resource.path_without_root.to_s
40
+ MultiSync.debug "Upload #{resource.class_name}:'#{resource.path_without_root}' to #{class_name}:'#{File.join('/', target_dir + destination_dir)}'"
41
+ directory = connection.directories.get(target_dir.to_s)
42
+ return if directory.nil?
43
+
44
+ upload_hash = {
45
+ key: (destination_dir + resource.path_without_root).to_s,
46
+ body: resource.body,
47
+ content_type: resource.content_type,
48
+ content_md5: Digest::MD5.base64digest(resource.body)
49
+ }
50
+
51
+ MultiSync::Resource::AWS_ATTRIBUTES.each do |attribute_hash|
52
+ upload_hash[attribute_hash[:name]] = resource.send(attribute_hash[:name])
53
+ end
54
+
55
+ directory.files.create(upload_hash)
56
+
57
+ resource
58
+ end
59
+
60
+ def delete(resource)
61
+ MultiSync.say_status :upload, resource.path_without_root.to_s
62
+ MultiSync.debug "Delete #{resource.class_name}:'#{resource.path_without_root}' from #{class_name}:'#{File.join('/', target_dir + destination_dir)}'"
63
+ connection.delete_object(target_dir.to_s, (destination_dir + resource.path_without_root).to_s)
64
+ resource
65
+ end
66
+
67
+ private
68
+
69
+ # directory or overreaching AWS globbing
70
+ def valid_path?(pathname)
71
+ # directory
72
+ return false if pathname.to_s =~ /\/$/
73
+
74
+ # overreaching AWS globbing
75
+ return false if !destination_dir.to_s.empty? && !(pathname.to_s =~ /^#{destination_dir.to_s}\//)
76
+
77
+ true
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,58 @@
1
+ require 'multi_sync/target'
2
+ require 'multi_sync/resources/remote_resource'
3
+
4
+ module MultiSync
5
+ class LocalTarget < Target
6
+ # Initialize a new LocalTarget object
7
+ #
8
+ # @param options [Hash]
9
+ def initialize(options = {})
10
+ super(options)
11
+ self.connection = ::Fog::Storage.new(credentials.merge(provider: :local))
12
+ end
13
+
14
+ def files
15
+ files = []
16
+
17
+ directory = connection.directories.get(destination_dir.to_s)
18
+ return files if directory.nil?
19
+
20
+ directory.files.lazily.each { |file|
21
+
22
+ pathname = Pathname.new(file.key)
23
+
24
+ # directory
25
+ next if pathname.directory?
26
+
27
+ MultiSync.debug "Found RemoteResource:'#{pathname}' from #{class_name}:'#{File.join(connection.local_root, destination_dir)}'"
28
+
29
+ files << MultiSync::RemoteResource.new(
30
+ file: file,
31
+ with_root: target_dir + destination_dir + pathname,
32
+ without_root: pathname
33
+ )
34
+
35
+ }
36
+
37
+ files
38
+ end
39
+
40
+ def upload(resource)
41
+ key = resource.path_without_root.to_s
42
+ MultiSync.say_status :upload, key
43
+ MultiSync.debug "Upload #{resource.class_name}:'#{key}' to #{class_name}:'#{File.join(connection.local_root, destination_dir)}'"
44
+ directory = connection.directories.get(destination_dir.to_s)
45
+ return if directory.nil?
46
+ directory.files.create(key: key, body: resource.body)
47
+ resource
48
+ end
49
+
50
+ def delete(resource)
51
+ key = resource.path_without_root.to_s
52
+ MultiSync.say_status :delete, key
53
+ MultiSync.debug "Delete #{resource.class_name}:'#{key}' from #{class_name}:'#{File.join(connection.local_root, destination_dir)}'"
54
+ connection.directories.get(destination_dir.to_s).files.get(key).destroy
55
+ resource
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module MultiSync
2
+ VERSION = '0.0.1' unless defined?(MultiSync::VERSION)
3
+ end
@@ -0,0 +1,15 @@
1
+ require 'multi_sync'
2
+
3
+ namespace :assets do
4
+ desc 'Synchronize assets'
5
+ task :sync => :environment do
6
+ ActiveSupport::Notifications.instrument 'multi_sync.run' do
7
+ MultiSync::Extensions::AssetSync.check_and_migrate
8
+ MultiSync.run
9
+ end
10
+ end
11
+ end
12
+
13
+ Rake::Task['assets:precompile'].enhance do
14
+ Rake::Task['assets:sync'].invoke if defined?(MultiSync) && MultiSync.run_on_build
15
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'multi_sync/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'multi_sync'
8
+ spec.version = MultiSync::VERSION
9
+ spec.authors = ['Karl Freeman']
10
+ spec.email = ['karlfreeman@gmail.com']
11
+ spec.summary = %q{A flexible synchronisation library for your assets}
12
+ spec.description = %q{A flexible synchronisation library for your assets}
13
+ spec.homepage = 'https://github.com/karlfreeman/multi_sync'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+ spec.required_ruby_version = '>= 1.9.3'
21
+
22
+ spec.add_dependency 'fog', '~> 1.12'
23
+ spec.add_dependency 'lazily', '~> 0.1'
24
+ spec.add_dependency 'virtus', '~> 0.5'
25
+ spec.add_dependency 'celluloid', '~> 0.15'
26
+ spec.add_dependency 'multi_mime', '~> 1.0'
27
+ spec.add_dependency 'multi_json', '~> 1.7'
28
+
29
+ spec.add_development_dependency 'bundler', '~> 1.5'
30
+ spec.add_development_dependency 'rake', '~> 10.0'
31
+ spec.add_development_dependency 'kramdown', '>= 0.14'
32
+ spec.add_development_dependency 'rubocop'
33
+ spec.add_development_dependency 'pry'
34
+ spec.add_development_dependency 'yard'
35
+ end
@@ -0,0 +1,22 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+
3
+ require 'bundler'
4
+ Bundler.setup
5
+
6
+ %w(support).each do |dir|
7
+ Dir.glob(File.expand_path("../#{dir}/**/*.rb", __FILE__), &method(:require))
8
+ end
9
+
10
+ require 'multi_sync'
11
+
12
+ RSpec.configure do |config|
13
+ config.expect_with :rspec do |c|
14
+ c.syntax = :expect
15
+ end
16
+
17
+ config.before(:each) do
18
+ MultiSync.reset!
19
+ MultiSync.env = :test
20
+ MultiSync.verbose = true
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ require 'celluloid/test'
2
+ Celluloid.shutdown_timeout = 1
3
+ RSpec.configure do |config|
4
+ config.around do |ex|
5
+ Celluloid.actor_system = nil
6
+ Thread.list.each do |thread|
7
+ next if thread == Thread.current
8
+ thread.kill
9
+ end
10
+ Celluloid.boot
11
+ ex.run
12
+ Celluloid.shutdown
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ require 'fakefs/safe'
2
+ require 'fakefs/spec_helpers'
3
+ require 'pathname'
4
+ require 'fileutils'
5
+ RSpec.configure do |config|
6
+ config.include FakeFS::SpecHelpers, fakefs: true
7
+ end
@@ -0,0 +1,25 @@
1
+ require 'fog'
2
+ Fog::Mock.delay = 0
3
+
4
+ module Fog
5
+ module SpecHelpers
6
+ def self.extended(example_group)
7
+ example_group.before(:each) do
8
+ Fog.mock!
9
+ Fog::Mock.reset
10
+ end
11
+
12
+ example_group.after(:each) do
13
+ Fog.unmock!
14
+ end
15
+ end
16
+
17
+ def self.included(example_group)
18
+ example_group.extend self
19
+ end
20
+ end
21
+ end
22
+
23
+ RSpec.configure do |config|
24
+ config.include Fog::SpecHelpers, fog: true
25
+ end
@@ -0,0 +1,6 @@
1
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
2
+ begin
3
+ require 'pry' unless ENV['CI']
4
+ rescue LoadError
5
+ end
6
+ end
@@ -0,0 +1,2 @@
1
+ require 'timecop'
2
+ Timecop.freeze
@@ -0,0 +1,301 @@
1
+ require 'spec_helper'
2
+
3
+ describe MultiSync::Client, fakefs: true do
4
+
5
+ before do
6
+ FileUtils.mkdir_p('/tmp/simple')
7
+ File.open('/tmp/simple/foo.txt', 'w') do |f| f.write('foo') end
8
+ File.open('/tmp/simple/bar.txt', 'w') do |f| f.write('bar') end
9
+ FileUtils.mkdir_p('/tmp/simple/in-a-dir')
10
+ File.open('/tmp/simple/in-a-dir/baz.html', 'w') do |f| f.write('baz') end
11
+
12
+ FileUtils.cp_r('/tmp/simple', '/tmp/simple-with-missing-file')
13
+ FileUtils.rm_r('/tmp/simple-with-missing-file/foo.txt')
14
+
15
+ FileUtils.cp_r('/tmp/simple', '/tmp/simple-with-abandoned-file')
16
+ File.open('/tmp/simple-with-abandoned-file/baz.txt', 'w') do |f| f.write('baz') end
17
+
18
+ FileUtils.cp_r('/tmp/simple', '/tmp/simple-with-outdated-file')
19
+ File.open('/tmp/simple-with-outdated-file/foo.txt', 'w') do |f| f.write('not-foo') end
20
+
21
+ FileUtils.mkdir_p('/tmp/complex')
22
+ 50.times do
23
+ File.open("/tmp/complex/#{SecureRandom.urlsafe_base64}.txt", 'w') do |f| f.write(SecureRandom.random_bytes) end
24
+ end
25
+
26
+ FileUtils.mkdir_p('/tmp/complex-empty')
27
+ end
28
+
29
+ context :sync do
30
+ context :local do
31
+ context 'simple' do
32
+ it 'should work' do
33
+ missing_files_target_options = {
34
+ type: :local,
35
+ target_dir: '/tmp',
36
+ destination_dir: 'simple-with-missing-file',
37
+ credentials: {
38
+ local_root: '/tmp'
39
+ }
40
+ }
41
+
42
+ abandoned_files_target_options = {
43
+ type: :local,
44
+ target_dir: '/tmp',
45
+ destination_dir: 'simple-with-abandoned-file',
46
+ credentials: {
47
+ local_root: '/tmp'
48
+ }
49
+ }
50
+
51
+ outdated_files_target_options = {
52
+ type: :local,
53
+ target_dir: '/tmp',
54
+ destination_dir: 'simple-with-outdated-file',
55
+ credentials: {
56
+ local_root: '/tmp'
57
+ }
58
+ }
59
+
60
+ local_source_options = {
61
+ type: :local,
62
+ source_dir: '/tmp/simple'
63
+ }
64
+
65
+ missing_files_target = MultiSync::LocalTarget.new(missing_files_target_options)
66
+ abandoned_files_target = MultiSync::LocalTarget.new(abandoned_files_target_options)
67
+ outdated_files_target = MultiSync::LocalTarget.new(outdated_files_target_options)
68
+
69
+ expect(missing_files_target).to have(2).files
70
+ expect(abandoned_files_target).to have(4).files
71
+ expect(outdated_files_target).to have(3).files
72
+
73
+ local_source = MultiSync::LocalSource.new(local_source_options)
74
+ expect(local_source).to have(3).files
75
+
76
+ expect(outdated_files_target.files[1].body).to eq 'not-foo'
77
+
78
+ MultiSync.run do
79
+ target :missing_files_target, missing_files_target_options
80
+ target :abandoned_files_target, abandoned_files_target_options
81
+ target :outdated_files_target, outdated_files_target_options
82
+ source :simple, local_source_options.merge(targets: [:missing_files_target, :abandoned_files_target, :outdated_files_target])
83
+ end
84
+
85
+ expect(missing_files_target).to have(3).files
86
+ expect(abandoned_files_target).to have(3).files
87
+ expect(outdated_files_target).to have(3).files
88
+ expect(outdated_files_target.files[1].body).to eq 'foo'
89
+ end
90
+ end
91
+
92
+ context 'complex' do
93
+ it 'should work' do
94
+ complex_empty_target_options = {
95
+ type: :local,
96
+ target_dir: '/tmp',
97
+ destination_dir: 'complex-empty',
98
+ credentials: {
99
+ local_root: '/tmp'
100
+ }
101
+ }
102
+
103
+ local_source_options = {
104
+ type: :local,
105
+ source_dir: '/tmp/complex'
106
+ }
107
+
108
+ complex_empty_target = MultiSync::LocalTarget.new(complex_empty_target_options)
109
+ expect(complex_empty_target).to have(0).files
110
+
111
+ local_source = MultiSync::LocalSource.new(local_source_options)
112
+ expect(local_source).to have(50).files
113
+
114
+ MultiSync.run do
115
+ target :complex_empty_target, complex_empty_target_options
116
+ source :complex, local_source_options.merge(targets: [:complex_empty_target])
117
+ end
118
+
119
+ expect(complex_empty_target).to have(50).files
120
+ end
121
+ end
122
+ end
123
+
124
+ context :aws, fog: true do
125
+ context 'simple' do
126
+ before do
127
+ connection = Fog::Storage.new(
128
+ provider: :aws,
129
+ region: 'us-east-1',
130
+ aws_access_key_id: 'xxx',
131
+ aws_secret_access_key: 'xxx'
132
+ )
133
+
134
+ directory = connection.directories.create(key: 'multi_sync', public: true)
135
+
136
+ %w(simple simple-with-missing-file simple-with-abandoned-file simple-with-outdated-file).each do |fixture_name|
137
+ Dir.glob("/tmp/#{fixture_name}/**/*").reject { |path| File.directory?(path) }.each do |path|
138
+ directory.files.create(
139
+ key: path.gsub('/tmp/', ''),
140
+ body: File.open(path, 'r'),
141
+ public: true
142
+ )
143
+ end
144
+ end
145
+ end
146
+
147
+ it 'should work' do
148
+ missing_files_target_options = {
149
+ type: :aws,
150
+ target_dir: 'multi_sync',
151
+ destination_dir: 'simple-with-missing-file',
152
+ credentials: {
153
+ region: 'us-east-1',
154
+ aws_access_key_id: 'xxx',
155
+ aws_secret_access_key: 'xxx'
156
+ }
157
+ }
158
+
159
+ abandoned_files_target_options = {
160
+ type: :aws,
161
+ target_dir: 'multi_sync',
162
+ destination_dir: 'simple-with-abandoned-file',
163
+ credentials: {
164
+ region: 'us-east-1',
165
+ aws_access_key_id: 'xxx',
166
+ aws_secret_access_key: 'xxx'
167
+ }
168
+ }
169
+
170
+ outdated_files_target_options = {
171
+ type: :aws,
172
+ target_dir: 'multi_sync',
173
+ destination_dir: 'simple-with-outdated-file',
174
+ credentials: {
175
+ region: 'us-east-1',
176
+ aws_access_key_id: 'xxx',
177
+ aws_secret_access_key: 'xxx'
178
+ }
179
+ }
180
+
181
+ local_source_options = {
182
+ type: :local,
183
+ source_dir: '/tmp/simple'
184
+ }
185
+
186
+ missing_files_target = MultiSync::AwsTarget.new(missing_files_target_options)
187
+ abandoned_files_target = MultiSync::AwsTarget.new(abandoned_files_target_options)
188
+ outdated_files_target = MultiSync::AwsTarget.new(outdated_files_target_options)
189
+
190
+ expect(missing_files_target).to have(2).files
191
+ expect(abandoned_files_target).to have(4).files
192
+ expect(outdated_files_target).to have(3).files
193
+
194
+ local_source = MultiSync::LocalSource.new(local_source_options)
195
+ expect(local_source).to have(3).files
196
+
197
+ expect(outdated_files_target.files[1].body).to eq 'not-foo'
198
+
199
+ MultiSync.run do
200
+ target :missing_files_target, missing_files_target_options
201
+ target :abandoned_files_target, abandoned_files_target_options
202
+ target :outdated_files_target, outdated_files_target_options
203
+ source :simple, local_source_options.merge(targets: [:missing_files_target, :abandoned_files_target, :outdated_files_target])
204
+ end
205
+
206
+ expect(missing_files_target).to have(3).files
207
+ expect(abandoned_files_target).to have(3).files
208
+ expect(outdated_files_target).to have(3).files
209
+ expect(outdated_files_target.files[1].body).to eq 'foo'
210
+ end
211
+ end
212
+
213
+ context 'complex' do
214
+ before do
215
+ connection = Fog::Storage.new(
216
+ provider: :aws,
217
+ region: 'us-east-1',
218
+ aws_access_key_id: 'xxx',
219
+ aws_secret_access_key: 'xxx'
220
+ )
221
+
222
+ connection.directories.create(key: 'multi_sync', public: true)
223
+ end
224
+
225
+ it 'should work' do
226
+ complex_empty_target_options = {
227
+ type: :aws,
228
+ target_dir: 'multi_sync',
229
+ destination_dir: 'complex-empty',
230
+ credentials: {
231
+ region: 'us-east-1',
232
+ aws_access_key_id: 'xxx',
233
+ aws_secret_access_key: 'xxx'
234
+ }
235
+ }
236
+
237
+ local_source_options = {
238
+ type: :local,
239
+ source_dir: '/tmp/complex'
240
+ }
241
+
242
+ complex_empty_target = MultiSync::AwsTarget.new(complex_empty_target_options)
243
+ expect(complex_empty_target).to have(0).files
244
+
245
+ local_source = MultiSync::LocalSource.new(local_source_options)
246
+ expect(local_source).to have(50).files
247
+
248
+ MultiSync.run do
249
+ target :complex_empty_target, complex_empty_target_options
250
+ source :complex, local_source_options.merge(targets: [:complex_empty_target])
251
+ end
252
+
253
+ expect(complex_empty_target).to have(50).files
254
+ end
255
+ end
256
+
257
+ context 'without a destination_dir' do
258
+ before do
259
+ connection = Fog::Storage.new(
260
+ provider: :aws,
261
+ region: 'us-east-1',
262
+ aws_access_key_id: 'xxx',
263
+ aws_secret_access_key: 'xxx'
264
+ )
265
+
266
+ connection.directories.create(key: 'without_destination_dir', public: true)
267
+ end
268
+
269
+ it 'should work' do
270
+ without_destination_dir_target_options = {
271
+ type: :aws,
272
+ target_dir: 'without_destination_dir',
273
+ credentials: {
274
+ region: 'us-east-1',
275
+ aws_access_key_id: 'xxx',
276
+ aws_secret_access_key: 'xxx'
277
+ }
278
+ }
279
+
280
+ local_source_options = {
281
+ type: :local,
282
+ source_dir: '/tmp/simple'
283
+ }
284
+
285
+ without_destination_dir_target = MultiSync::AwsTarget.new(without_destination_dir_target_options)
286
+ expect(without_destination_dir_target).to have(0).files
287
+
288
+ local_source = MultiSync::LocalSource.new(local_source_options)
289
+ expect(local_source).to have(3).files
290
+
291
+ MultiSync.run do
292
+ target :without_destination_dir_target, without_destination_dir_target_options
293
+ source :local, local_source_options.merge(targets: :without_destination_dir_target)
294
+ end
295
+
296
+ expect(without_destination_dir_target).to have(3).files
297
+ end
298
+ end
299
+ end
300
+ end
301
+ end