multi_sync 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,44 @@
1
+ module MultiSync
2
+ module Extensions
3
+ class AssetSync
4
+ class << self
5
+ def asset_sync_yml_exists?
6
+ ::Rails.root.nil? ? false : File.exist?(asset_sync_yml_path)
7
+ end
8
+
9
+ def asset_sync_yml_path
10
+ ::Rails.root.join('config', 'asset_sync.yml')
11
+ end
12
+
13
+ def asset_sync_yml
14
+ @asset_sync_yml ||= YAML.load_file(asset_sync_yml_path)[MultiSync.env]
15
+ end
16
+
17
+ def check_and_migrate
18
+ return unless self.asset_sync_yml_exists?
19
+ MultiSync.info 'AssetSync YAML file found, migrating options...'
20
+
21
+ MultiSync.source(:rails,
22
+ type: :manifest,
23
+ source_dir: MultiSync::Extensions::Rails.source_dir
24
+ )
25
+
26
+ MultiSync.target(:assets,
27
+ type: asset_sync_yml['fog_provider'],
28
+ target_dir: asset_sync_yml['fog_directory'],
29
+ destination_dir: MultiSync::Extensions::Rails.destination_dir,
30
+ credentials: {
31
+ region: asset_sync_yml['region'],
32
+ aws_access_key_id: asset_sync_yml['aws_access_key_id'],
33
+ aws_secret_access_key: asset_sync_yml['aws_secret_access_key'],
34
+ path_style: asset_sync_yml['path_style']
35
+ }
36
+ )
37
+
38
+ MultiSync.delete_abandoned_files = asset_sync_yml['existing_remote_files'] == 'delete'
39
+ MultiSync.run_on_build = asset_sync_yml['run_on_precompile']
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ module MultiSync
2
+ module Extensions
3
+ class Railtie < Rails::Railtie
4
+ railtie_name :multi_sync
5
+
6
+ rake_tasks do
7
+ load 'tasks/multi_sync_rails.rake'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,60 @@
1
+ require 'logger'
2
+
3
+ module MultiSync
4
+ module Logging
5
+ MUTEX = Mutex.new
6
+
7
+ def logger
8
+ @logger || initialize_logger
9
+ end
10
+
11
+ def logger=(new_logger)
12
+ @logger = new_logger ? new_logger : Logger.new('/dev/null')
13
+ end
14
+
15
+ def status_logger
16
+ @status_logger || initialize_status_logger
17
+ end
18
+
19
+ def status_logger=(new_status_logger)
20
+ @status_logger = new_status_logger ? new_status_logger : nil
21
+ end
22
+
23
+ def say_status(status, message, log_status = true)
24
+ return if status_logger.nil?
25
+
26
+ if defined?(Thor) && status_logger.is_a?(Thor)
27
+ MUTEX.synchronize do
28
+ status_logger.say_status status, message, log_status
29
+ end
30
+ end
31
+ end
32
+
33
+ def log(message, level = :debug)
34
+ # We're in verbose mode so disable all non-info logs
35
+ return if !MultiSync.verbose && level != :info
36
+
37
+ MUTEX.synchronize do
38
+ logger.send(level, message)
39
+ end
40
+ end
41
+
42
+ # Create methods for the different shorthand log methods
43
+ [:info, :debug, :warn, :error].each do |log_method|
44
+ # Shorthand log method
45
+ define_method log_method do |message|
46
+ send(:log, message, log_method)
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def initialize_logger
53
+ @logger = ::Logger.new(STDOUT)
54
+ end
55
+
56
+ def initialize_status_logger
57
+ @status_logger = nil
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ module MultiSync
2
+ module Mixins
3
+ module LogHelper
4
+ def class_name
5
+ self.class.name.split('::').last
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ module MultiSync
2
+ module Mixins
3
+ module PluralizeHelper
4
+ def pluralize(n, singular, plural = nil, prefix = true)
5
+ if n == 1
6
+ (prefix ? '1 ' : '') + singular
7
+ elsif plural
8
+ (prefix ? "#{n} " : '') + plural
9
+ else
10
+ (prefix ? "#{n} " : '') + "#{singular}s"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,84 @@
1
+ require 'virtus'
2
+ require 'pathname'
3
+ require 'digest/md5'
4
+ require 'multi_sync/mixins/log_helper'
5
+
6
+ module MultiSync
7
+ class Resource
8
+ include Virtus
9
+ include Comparable
10
+ include MultiSync::Mixins::LogHelper
11
+
12
+ attribute :file, File
13
+ attribute :path_with_root, Pathname
14
+ attribute :path_without_root, Pathname
15
+
16
+ attribute :etag, String
17
+ attribute :mtime, Time
18
+ attribute :content_length, Numeric
19
+ attribute :content_type, String
20
+ attribute :digest, String
21
+
22
+ AWS_ATTRIBUTES = [{
23
+ name: :storage_class,
24
+ type: String,
25
+ default_value: 'STANDARD'
26
+ }, {
27
+ name: :acl,
28
+ type: String,
29
+ default_value: 'public-read'
30
+ }, {
31
+ name: :expires,
32
+ type: String,
33
+ default_value: nil
34
+ }, {
35
+ name: :cache_control,
36
+ type: String,
37
+ default_value: nil
38
+ }, {
39
+ name: :encryption,
40
+ type: String,
41
+ default_value: nil
42
+ }]
43
+
44
+ AWS_ATTRIBUTES.each do |attribute_hash|
45
+ send(:attribute, attribute_hash[:name], attribute_hash[:type])
46
+ end
47
+
48
+ # Initialize a new Resource object
49
+ #
50
+ # @param options [Hash]
51
+ def initialize(options = {})
52
+ fail(ArgumentError, 'with_root must be present') unless options[:with_root]
53
+ fail(ArgumentError, 'without_root must be present') unless options[:without_root]
54
+ self.path_with_root = options.fetch(:with_root)
55
+ self.path_without_root = options.fetch(:without_root)
56
+ self.etag = options.fetch(:etag, determine_etag)
57
+ self.mtime = options.fetch(:mtime, determine_mtime)
58
+ self.content_length = options.fetch(:content_length, determine_content_length)
59
+ self.content_type = options.fetch(:content_type, determine_content_type)
60
+ self.digest = options.fetch(:digest, '')
61
+
62
+ AWS_ATTRIBUTES.each do |attribute_hash|
63
+ send("#{attribute_hash[:name]}=".to_sym, options.fetch(attribute_hash[:name], attribute_hash[:default_value]))
64
+ end
65
+ end
66
+
67
+ def hash
68
+ path_without_root.hash
69
+ end
70
+
71
+ def <=>(other)
72
+ path_without_root <=> other.path_without_root
73
+ end
74
+
75
+ def ==(other)
76
+ path_without_root == other.path_without_root
77
+ end
78
+ alias_method :eql?, :==
79
+
80
+ def matching_etag?(other)
81
+ etag == other.etag
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,30 @@
1
+ require 'multi_mime'
2
+ require 'multi_sync/resource'
3
+
4
+ module MultiSync
5
+ class LocalResource < Resource
6
+ def body
7
+ File.read(path_with_root.to_s)
8
+ rescue
9
+ return nil
10
+ end
11
+
12
+ def determine_etag
13
+ body.nil? ? nil : Digest::MD5.hexdigest(body)
14
+ end
15
+
16
+ def determine_mtime
17
+ File.mtime(path_with_root.to_s)
18
+ rescue
19
+ return nil
20
+ end
21
+
22
+ def determine_content_type
23
+ MultiMime.type_for_path(path_with_root.to_s)
24
+ end
25
+
26
+ def determine_content_length
27
+ body.nil? ? 0 : Fog::Storage.get_body_size(body)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ require 'multi_sync/resource'
2
+
3
+ module MultiSync
4
+ class RemoteResource < Resource
5
+ def initialize(options = {})
6
+ self.file = options.fetch(:file, nil)
7
+ super(options)
8
+ end
9
+
10
+ def body
11
+ file.body
12
+ end
13
+
14
+ def determine_etag
15
+ file.etag
16
+ rescue NoMethodError # Fog::Storage::Local::File's don't have an etag method :(
17
+ Digest::MD5.hexdigest(File.read(path_with_root))
18
+ end
19
+
20
+ def determine_mtime
21
+ file.last_modified
22
+ end
23
+
24
+ def determine_content_type
25
+ file.content_type
26
+ end
27
+
28
+ def determine_content_length
29
+ file.content_length
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,40 @@
1
+ require 'virtus'
2
+ require 'pathname'
3
+ require 'lazily'
4
+ require 'multi_sync/mixins/log_helper'
5
+
6
+ module MultiSync
7
+ class Source
8
+ include Virtus
9
+ include MultiSync::Mixins::LogHelper
10
+
11
+ attribute :targets, Array, default: []
12
+ attribute :source_dir, String
13
+ attribute :source_options, Hash
14
+ attribute :include, String
15
+ attribute :exclude, String
16
+
17
+ # Initialize a new Source object
18
+ #
19
+ # @param options [Hash]
20
+ def initialize(options = {})
21
+ fail(ArgumentError, 'source_dir must be a present') unless options[:source_dir]
22
+ targets.concat([*options.fetch(:targets, [])])
23
+ self.source_dir = options.fetch(:source_dir).to_s
24
+ source_dir << '/' unless source_dir.end_with?('/')
25
+ self.source_dir = Pathname.new(source_dir)
26
+ self.include = options.fetch(:include, '**/*')
27
+ self.exclude = options.fetch(:exclude, nil)
28
+ end
29
+
30
+ private
31
+
32
+ def path_to_local_resource(path, options = {})
33
+ pathname = Pathname.new(path)
34
+ MultiSync::LocalResource.new({
35
+ with_root: pathname,
36
+ without_root: pathname.relative_path_from(source_dir).cleanpath
37
+ }.merge(options).merge(source_options))
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ require 'multi_sync/source'
2
+ require 'multi_sync/resources/local_resource'
3
+
4
+ module MultiSync
5
+ class LocalSource < Source
6
+ def files
7
+ files = []
8
+ included_files = Dir.glob(source_dir + include)
9
+ excluded_files = exclude.nil? ? [] : Dir.glob(source_dir + exclude)
10
+ (included_files - excluded_files).lazily.each { |path|
11
+ next if File.directory?(path)
12
+ files << path_to_local_resource(path)
13
+ }
14
+ files
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,82 @@
1
+ require 'yaml'
2
+ require 'multi_json'
3
+ require 'multi_sync/source'
4
+ require 'multi_sync/resources/local_resource'
5
+
6
+ module MultiSync
7
+ class ManifestSource < Source
8
+ def files
9
+ files = []
10
+ manifest_hash = {}
11
+
12
+ # ::ActionView::Base has a shortcut to the manifest file
13
+ # otherwise lets hunt down that manifest file!
14
+ if defined?(::ActionView::Base) && ::ActionView::Base.respond_to?(:assets_manifest)
15
+ manifest_hash = ::ActionView::Base.assets_manifest.files
16
+ else
17
+ manifest_path = locate_manifest(source_dir)
18
+ manifest_hash = parse_manifest(manifest_path)
19
+ end
20
+
21
+ # create a local_resource from each file
22
+ # making sure to skip any that do not match the include/exclude patterns
23
+ manifest_hash.lazily.each { |key, value|
24
+ path = source_dir + key
25
+ next if !path.fnmatch?(include.to_s) or path.fnmatch?(exclude.to_s || '')
26
+ file = path_to_local_resource(path, mtime: value['mtime'], digest: value['digest'], content_length: value['size'])
27
+ files << file
28
+ }
29
+
30
+ files
31
+ end
32
+
33
+ private
34
+
35
+ def locate_manifest(dir)
36
+ Dir.glob(dir.to_s + 'manifest*.{json,yaml,yml}').max { |f| File.ctime(f) }
37
+ end
38
+
39
+ def parse_manifest(manifest_path)
40
+ manifest_hash = {}
41
+ manifest_data = File.read(manifest_path)
42
+
43
+ # manifest files can be YAML or JSON but Sprockets::Manifest isn't backwards compatible with that in mind :(
44
+ case File.extname(manifest_path)
45
+ when '.json'
46
+ manifest_hash = MultiJson.load(manifest_data)
47
+ when '.yml', '.yaml'
48
+ manifest_hash = YAML.load(manifest_data)
49
+ end
50
+
51
+ # different versions of Sprockets have different manifest layouts, lets try and work around this by checking for the presence of "files" and "assets" in the manifest first
52
+ # else we know it must be an old manifest file, so its root is "files"
53
+ if manifest_hash.key?('files') || manifest_hash.key?('assets')
54
+ manifest_hash = manifest_hash['files']
55
+ else
56
+
57
+ # index.* files are special and should be ignored from sync
58
+ # something which seems to only happen in older versions of Sprockets
59
+ manifest_hash.delete_if { |key, value|
60
+ key.include?('/index.')
61
+ }
62
+
63
+ # lets manipulate this older manifest to appear similiar to the newer manifest's "files"
64
+ modified_manifest_hash = {}
65
+ manifest_hash.each { |key, value|
66
+ modified_manifest_hash[value] = {
67
+ 'logical_path' => key,
68
+ 'mtime' => nil,
69
+ 'size' => nil,
70
+ 'digest' => nil
71
+ }
72
+ }
73
+
74
+ #
75
+ manifest_hash = modified_manifest_hash
76
+
77
+ end
78
+
79
+ manifest_hash
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,34 @@
1
+ require 'fog'
2
+ require 'lazily'
3
+ require 'virtus'
4
+ require 'pathname'
5
+ require 'celluloid'
6
+ require 'multi_sync/mixins/log_helper'
7
+
8
+ module MultiSync
9
+ class Target
10
+ include Virtus
11
+ include Celluloid
12
+ include MultiSync::Mixins::LogHelper
13
+
14
+ attribute :connection
15
+ attribute :target_dir, Pathname
16
+ attribute :destination_dir, Pathname
17
+ attribute :credentials, Hash, default: :default_credentials
18
+
19
+ # Initialize a new Target object
20
+ #
21
+ # @param options [Hash]
22
+ def initialize(options = {})
23
+ fail(ArgumentError, 'target_dir must be present') unless options[:target_dir]
24
+ self.target_dir = Pathname.new(options.fetch(:target_dir, ''))
25
+ self.destination_dir = Pathname.new(options.fetch(:destination_dir, ''))
26
+ credentials.merge!(options.fetch(:credentials, {}))
27
+ end
28
+
29
+ def default_credentials
30
+ # deep clone just in case
31
+ Marshal.load(Marshal.dump(MultiSync.credentials))
32
+ end
33
+ end
34
+ end