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,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