multi_sync 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.gitignore +20 -0
- data/.rubocop.yml +26 -0
- data/.travis.yml +24 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +0 -0
- data/CONTRIBUTING.md +44 -0
- data/Gemfile +17 -0
- data/LICENSE.md +20 -0
- data/README.md +134 -0
- data/Rakefile +45 -0
- data/examples/custom.rb +34 -0
- data/examples/rails-3-2/.gitignore +15 -0
- data/examples/rails-3-2/Gemfile +43 -0
- data/examples/rails-3-2/README.rdoc +261 -0
- data/examples/rails-3-2/Rakefile +7 -0
- data/examples/rails-3-2/app/assets/images/rails.png +0 -0
- data/examples/rails-3-2/app/assets/javascripts/application.js +15 -0
- data/examples/rails-3-2/app/assets/stylesheets/application.css +13 -0
- data/examples/rails-3-2/app/controllers/application_controller.rb +3 -0
- data/examples/rails-3-2/app/helpers/application_helper.rb +2 -0
- data/examples/rails-3-2/app/mailers/.gitkeep +0 -0
- data/examples/rails-3-2/app/models/.gitkeep +0 -0
- data/examples/rails-3-2/app/views/layouts/application.html.erb +14 -0
- data/examples/rails-3-2/config.ru +4 -0
- data/examples/rails-3-2/config/application.rb +62 -0
- data/examples/rails-3-2/config/asset_sync.yml +21 -0
- data/examples/rails-3-2/config/boot.rb +6 -0
- data/examples/rails-3-2/config/database.yml +25 -0
- data/examples/rails-3-2/config/environment.rb +5 -0
- data/examples/rails-3-2/config/environments/development.rb +37 -0
- data/examples/rails-3-2/config/environments/production.rb +67 -0
- data/examples/rails-3-2/config/environments/test.rb +37 -0
- data/examples/rails-3-2/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/rails-3-2/config/initializers/inflections.rb +15 -0
- data/examples/rails-3-2/config/initializers/mime_types.rb +5 -0
- data/examples/rails-3-2/config/initializers/multi_sync.rb +29 -0
- data/examples/rails-3-2/config/initializers/secret_token.rb +7 -0
- data/examples/rails-3-2/config/initializers/session_store.rb +8 -0
- data/examples/rails-3-2/config/initializers/wrap_parameters.rb +14 -0
- data/examples/rails-3-2/config/locales/en.yml +5 -0
- data/examples/rails-3-2/config/routes.rb +58 -0
- data/examples/rails-3-2/db/seeds.rb +7 -0
- data/examples/rails-3-2/lib/assets/.gitkeep +0 -0
- data/examples/rails-3-2/lib/tasks/.gitkeep +0 -0
- data/examples/rails-3-2/log/.gitkeep +0 -0
- data/examples/rails-3-2/public/404.html +26 -0
- data/examples/rails-3-2/public/422.html +26 -0
- data/examples/rails-3-2/public/500.html +25 -0
- data/examples/rails-3-2/public/favicon.ico +0 -0
- data/examples/rails-3-2/public/index.html +241 -0
- data/examples/rails-3-2/public/robots.txt +5 -0
- data/examples/rails-3-2/script/rails +6 -0
- data/examples/rails-3-2/test/fixtures/.gitkeep +0 -0
- data/examples/rails-3-2/test/functional/.gitkeep +0 -0
- data/examples/rails-3-2/test/integration/.gitkeep +0 -0
- data/examples/rails-3-2/test/performance/browsing_test.rb +12 -0
- data/examples/rails-3-2/test/test_helper.rb +13 -0
- data/examples/rails-3-2/test/unit/.gitkeep +0 -0
- data/examples/rails-4-0/.gitignore +16 -0
- data/examples/rails-4-0/Gemfile +50 -0
- data/examples/rails-4-0/README.rdoc +28 -0
- data/examples/rails-4-0/Rakefile +6 -0
- data/examples/rails-4-0/app/assets/images/.keep +0 -0
- data/examples/rails-4-0/app/assets/javascripts/application.js +16 -0
- data/examples/rails-4-0/app/assets/stylesheets/application.css +13 -0
- data/examples/rails-4-0/app/controllers/application_controller.rb +5 -0
- data/examples/rails-4-0/app/controllers/concerns/.keep +0 -0
- data/examples/rails-4-0/app/helpers/application_helper.rb +2 -0
- data/examples/rails-4-0/app/mailers/.keep +0 -0
- data/examples/rails-4-0/app/models/.keep +0 -0
- data/examples/rails-4-0/app/models/concerns/.keep +0 -0
- data/examples/rails-4-0/app/views/layouts/application.html.erb +14 -0
- data/examples/rails-4-0/config.ru +4 -0
- data/examples/rails-4-0/config/application.rb +24 -0
- data/examples/rails-4-0/config/asset_sync.yml +21 -0
- data/examples/rails-4-0/config/boot.rb +4 -0
- data/examples/rails-4-0/config/database.yml +25 -0
- data/examples/rails-4-0/config/environment.rb +5 -0
- data/examples/rails-4-0/config/environments/development.rb +29 -0
- data/examples/rails-4-0/config/environments/production.rb +80 -0
- data/examples/rails-4-0/config/environments/test.rb +36 -0
- data/examples/rails-4-0/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/rails-4-0/config/initializers/filter_parameter_logging.rb +4 -0
- data/examples/rails-4-0/config/initializers/inflections.rb +16 -0
- data/examples/rails-4-0/config/initializers/mime_types.rb +5 -0
- data/examples/rails-4-0/config/initializers/multi_sync.rb +29 -0
- data/examples/rails-4-0/config/initializers/secret_token.rb +12 -0
- data/examples/rails-4-0/config/initializers/session_store.rb +3 -0
- data/examples/rails-4-0/config/initializers/wrap_parameters.rb +14 -0
- data/examples/rails-4-0/config/locales/en.yml +23 -0
- data/examples/rails-4-0/config/routes.rb +56 -0
- data/examples/rails-4-0/db/seeds.rb +7 -0
- data/examples/rails-4-0/lib/assets/.keep +0 -0
- data/examples/rails-4-0/lib/tasks/.keep +0 -0
- data/examples/rails-4-0/log/.keep +0 -0
- data/examples/rails-4-0/public/404.html +58 -0
- data/examples/rails-4-0/public/422.html +58 -0
- data/examples/rails-4-0/public/500.html +57 -0
- data/examples/rails-4-0/public/favicon.ico +0 -0
- data/examples/rails-4-0/public/robots.txt +5 -0
- data/examples/rails-4-0/test/controllers/.keep +0 -0
- data/examples/rails-4-0/test/fixtures/.keep +0 -0
- data/examples/rails-4-0/test/helpers/.keep +0 -0
- data/examples/rails-4-0/test/integration/.keep +0 -0
- data/examples/rails-4-0/test/mailers/.keep +0 -0
- data/examples/rails-4-0/test/models/.keep +0 -0
- data/examples/rails-4-0/test/test_helper.rb +15 -0
- data/gemfiles/middleman-3.1.x.gemfile +5 -0
- data/gemfiles/rails-3.2.x.gemfile +5 -0
- data/gemfiles/rails-4.0.x.gemfile +5 -0
- data/lib/multi_sync.rb +92 -0
- data/lib/multi_sync/client.rb +243 -0
- data/lib/multi_sync/configuration.rb +36 -0
- data/lib/multi_sync/environment.rb +37 -0
- data/lib/multi_sync/extensions/middleman.rb +22 -0
- data/lib/multi_sync/extensions/rails.rb +20 -0
- data/lib/multi_sync/extensions/rails/asset_sync.rb +44 -0
- data/lib/multi_sync/extensions/rails/railtie.rb +11 -0
- data/lib/multi_sync/logging.rb +60 -0
- data/lib/multi_sync/mixins/log_helper.rb +9 -0
- data/lib/multi_sync/mixins/pluralize_helper.rb +15 -0
- data/lib/multi_sync/resource.rb +84 -0
- data/lib/multi_sync/resources/local_resource.rb +30 -0
- data/lib/multi_sync/resources/remote_resource.rb +32 -0
- data/lib/multi_sync/source.rb +40 -0
- data/lib/multi_sync/sources/local_source.rb +17 -0
- data/lib/multi_sync/sources/manifest_source.rb +82 -0
- data/lib/multi_sync/target.rb +34 -0
- data/lib/multi_sync/targets/aws_target.rb +80 -0
- data/lib/multi_sync/targets/local_target.rb +58 -0
- data/lib/multi_sync/version.rb +3 -0
- data/lib/tasks/multi_sync_rails.rake +15 -0
- data/multi_sync.gemspec +35 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/celluloid.rb +14 -0
- data/spec/support/fakefs.rb +7 -0
- data/spec/support/fog.rb +25 -0
- data/spec/support/pry.rb +6 -0
- data/spec/support/timecop.rb +2 -0
- data/spec/unit/multi_sync/client_spec.rb +301 -0
- data/spec/unit/multi_sync/configuration_spec.rb +92 -0
- data/spec/unit/multi_sync/resources/local_resource_spec.rb +55 -0
- data/spec/unit/multi_sync/sources/local_source_spec.rb +48 -0
- data/spec/unit/multi_sync/sources/manifest_source_spec.rb +57 -0
- data/spec/unit/multi_sync/targets/aws_target_spec.rb +60 -0
- data/spec/unit/multi_sync/targets/local_target_spec.rb +41 -0
- data/spec/unit/multi_sync_spec.rb +55 -0
- 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,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,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
|