middleman-s3_sync 3.0.10 → 3.0.11

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog.md ADDED
@@ -0,0 +1,10 @@
1
+ # Middleman::S3Sync Changelog
2
+
3
+ ## v3.0.11
4
+
5
+ * Adds support for GZipped resources (fixes #3)
6
+ * Quiets Fog's warning messages (fixes #10)
7
+ * Rename the options method to s3_sync_options to remove a method name collision (fixes #9)
8
+ * Colorize the output.
9
+
10
+
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Middleman::S3Sync
2
2
 
3
+ [![Code
4
+ Climate](https://codeclimate.com/github/fredjean/middleman-s3_sync.png)](https://codeclimate.com/github/fredjean/middleman-s3_sync)
5
+
3
6
  This gem determines which files need to be added, updated and optionally deleted
4
7
  and only transfer these files up. This reduces the impact of an update
5
8
  on a web site hosted on S3.
@@ -38,6 +41,7 @@ activate :s3_sync do |s3_sync|
38
41
  s3_sync.aws_secret_access_key = 'AWS SECRET KEY'
39
42
  s3_sync.delete = false # We delete stray files by default.
40
43
  s3_sync.after_build = false # We chain after the build step by default. This may not be your desired behavior...
44
+ s3_sync.prefer_gzip = true
41
45
  end
42
46
  ```
43
47
 
@@ -50,6 +54,13 @@ such case, you can pass the ```--force``` option:
50
54
 
51
55
  $ middleman s3_sync --force
52
56
 
57
+ ## Overriding the destination bucket
58
+
59
+ You can now override the destination bucket using the --bucket switch.
60
+ The command is:
61
+
62
+ $ middleman s3_sync --bucket=my.new.bucket
63
+
53
64
  ## HTTP Caching
54
65
 
55
66
  By default, ```middleman-s3_sync``` does not set caching headers. In
@@ -121,6 +132,14 @@ are (I'm looking at you Chrome!). Setting the `Cache-Control` or
121
132
  that stand between them and your content will behave the way you want
122
133
  them to. YMMV.
123
134
 
135
+ ### GZipped Content Encoding
136
+
137
+ You can set the ```prefer_gzip``` option to look for a gzipped version
138
+ of a resource. The gzipped version of the resource will be pushed to S3
139
+ instead of the original and the ```Content-Encoding``` and ```Content-Type```
140
+ headers will be set correctly. This will cause Amazon to serve the
141
+ compressed version of the resource.
142
+
124
143
  ## A Debt of Gratitude
125
144
 
126
145
  I used Middleman Sync as a template for building a Middleman extension.
@@ -1,9 +1,14 @@
1
1
  require 'middleman-core'
2
2
  require 'fog'
3
- require 'parallel'
3
+ require 'pmap'
4
+ require 'ruby-progressbar'
4
5
  require 'digest/md5'
5
6
  require 'middleman-s3_sync/version'
6
7
  require 'middleman-s3_sync/commands'
8
+ require 'middleman/s3_sync/status'
9
+ require 'middleman/s3_sync/resource'
10
+
11
+ Fog::Logger[:warning] = nil
7
12
 
8
13
  ::Middleman::Extensions.register(:s3_sync, '>= 3.0.0') do
9
14
  require 'middleman-s3_sync/extension'
@@ -13,140 +18,112 @@ end
13
18
  module Middleman
14
19
  module S3Sync
15
20
  class << self
21
+ include Status
22
+
16
23
  def sync
17
- if files_to_create.empty? && files_to_update.empty? && files_to_delete.empty?
18
- puts "\nAll S3 files are up to date."
24
+ unless work_to_be_done?
25
+ say_status "\nAll S3 files are up to date."
19
26
  return
20
27
  end
21
28
 
22
- puts "\nReady to apply updates to #{options.bucket}."
23
-
24
- files_to_create.each do |f|
25
- puts "Creating #{f}"
26
- file_hash = {
27
- :key => f,
28
- :body => File.open(local_path(f)),
29
- :public => true,
30
- :acl => 'public-read',
31
- :content_type => MIME::Types.of(f).first
32
- }
33
-
34
- # Add cache-control headers
35
- if policy = options.caching_policy_for(file_hash[:content_type])
36
- file_hash[:cache_control] = policy.cache_control if policy.cache_control
37
- file_hash[:expires] = policy.expires if policy.expires
38
- end
39
-
40
- bucket.files.create(file_hash)
41
- end
29
+ say_status "\nReady to apply updates to #{s3_sync_options.bucket}."
42
30
 
43
- files_to_update.each do |f|
44
- puts "Updating #{f}"
45
- file = s3_files.get(f)
46
- file.body = File.open(local_path(f))
47
- file.public = true
48
- file.content_type = MIME::Types.of(f).first
49
- if policy = options.caching_policy_for(file.content_type)
50
- file.cache_control = policy.cache_control if policy.cache_control
51
- file.expires = policy.expires if policy.expires
52
- end
53
-
54
- file.save
55
- end
31
+ create_resources
32
+ update_resources
33
+ delete_resources
34
+ end
56
35
 
57
- files_to_delete.each do |f|
58
- puts "Deleting #{f}"
59
- if file = s3_files.get(f)
60
- file.destroy
61
- end
62
- end
36
+ def bucket
37
+ @bucket ||= connection.directories.get(s3_sync_options.bucket)
63
38
  end
64
39
 
65
40
  protected
66
41
  def connection
67
42
  @connection ||= Fog::Storage.new({
68
43
  :provider => 'AWS',
69
- :aws_access_key_id => options.aws_access_key_id,
70
- :aws_secret_access_key => options.aws_secret_access_key,
71
- :region => options.region
44
+ :aws_access_key_id => s3_sync_options.aws_access_key_id,
45
+ :aws_secret_access_key => s3_sync_options.aws_secret_access_key,
46
+ :region => s3_sync_options.region
72
47
  })
73
48
  end
74
49
 
75
- def bucket
76
- @bucket ||= connection.directories.get(options.bucket)
50
+ def resources
51
+ @resources ||= paths.pmap do |p|
52
+ progress_bar.increment
53
+ S3Sync::Resource.new(p)
54
+ end
77
55
  end
78
56
 
79
- def s3_files
80
- @s3_files ||= bucket.files
57
+ def progress_bar
58
+ @progress_bar ||= ProgressBar.create(total: paths.length)
81
59
  end
82
60
 
83
- def remote_files
84
- @remote_files ||= begin
85
- puts "Gathering remote files from #{options.bucket}"
86
- bucket.files.map { |f| f.key }
87
- end
61
+ def paths
62
+ @paths ||= begin
63
+ say_status "Gathering the paths to evaluate."
64
+ (remote_paths + local_paths).uniq.sort
65
+ end
88
66
  end
89
- def local_files
90
- @local_files ||= begin
91
- puts "Gathering local files."
92
- (Dir[build_dir + "/**/*"] + Dir[build_dir + "/**/.*"])
93
- .reject { |f| File.directory?(f) }
94
- .map { |f| f.gsub(/^#{build_dir}\//, '') }
67
+
68
+ def local_paths
69
+ @local_paths ||= begin
70
+ local_paths = (Dir[build_dir + "/**/*"] + Dir[build_dir + "/**/.*"])
71
+ .reject { |p| File.directory?(p) }
72
+
73
+ if s3_sync_options.prefer_gzip
74
+ local_paths.reject! { |p| p =~ /\.gz$/ && File.exist?(p.gsub(/\.gz$/, '')) }
75
+ end
76
+
77
+ local_paths.pmap { |p| p.gsub(/#{build_dir}\//, '') }
95
78
  end
96
79
  end
97
80
 
98
- def files_to_delete
99
- @files_to_delete ||= begin
100
- if options.delete
101
- puts "\nDetermine which files to delete from #{options.bucket}"
102
- remote_files - local_files
103
- else
104
- []
105
- end
106
- end
81
+ def remote_paths
82
+ @remote_paths ||= bucket.files.map{ |f| f.key }
107
83
  end
108
84
 
109
- def files_to_create
110
- @files_to_create ||= begin
111
- puts "Determine files to add to #{options.bucket}."
112
- local_files - remote_files
113
- end
85
+ def create_resources
86
+ files_to_create.each do |r|
87
+ r.create!
88
+ end
114
89
  end
115
90
 
116
- def files_to_evaluate
117
- @files_to_evaluate ||= begin
118
- local_files - files_to_create
119
- end
91
+ def update_resources
92
+ files_to_update.each do |r|
93
+ r.update!
94
+ end
120
95
  end
121
96
 
122
- def files_to_update
123
- return files_to_evaluate if options.force
124
-
125
- @files_to_update ||= begin
126
- puts "Determine which local files to update their S3 counterparts"
127
- files_to_update = []
128
- Parallel.each(files_to_evaluate, :in_threads => 4) do |f|
129
- print '.'
130
- remote_file = s3_files.get(f)
131
- local_mtime = File.mtime(local_path(f))
132
- remote_mtime = remote_file.last_modified
133
- if remote_mtime < local_mtime
134
- local_md5 = Digest::MD5.hexdigest(File.read(local_path(f)))
135
- remote_md5 = remote_file.etag
136
- files_to_update << f if local_md5 != remote_md5
137
- end
138
- end
139
- puts ""
140
- files_to_update
97
+ def delete_resources
98
+ files_to_delete.each do |r|
99
+ r.destroy!
100
+ end
101
+ end
102
+
103
+ def work_to_be_done?
104
+ !(files_to_create.empty? && files_to_update.empty? && files_to_delete.empty?)
105
+ end
106
+
107
+ def files_to_delete
108
+ @files_to_delete ||= if s3_sync_options.delete
109
+ resources.select { |r| r.to_delete? }
110
+ else
111
+ []
141
112
  end
142
113
  end
143
114
 
144
- def local_path(f)
145
- "#{build_dir}/#{f}"
115
+ def files_to_create
116
+ @files_to_create ||= resources.select { |r| r.to_create? }
117
+ end
118
+
119
+ def files_to_update
120
+ return resources.select { |r| r.local? } if s3_sync_options.force
121
+
122
+ @files_to_update ||= resources.select { |r| r.to_update? }
146
123
  end
147
124
 
148
125
  def build_dir
149
- @build_dir ||= options.build_dir
126
+ @build_dir ||= s3_sync_options.build_dir
150
127
  end
151
128
  end
152
129
  end
@@ -18,16 +18,21 @@ module Middleman
18
18
  option :bucket, type: :string,
19
19
  desc: "Specify which bucket to use, overrides the configured bucket.",
20
20
  aliases: :b
21
+ option :verbose, type: :boolean,
22
+ desc: "Adds more verbosity...",
23
+ aliases: :v
21
24
 
22
25
  def s3_sync
23
26
  shared_inst = ::Middleman::Application.server.inst
24
- bucket = shared_inst.options.bucket
27
+ bucket = shared_inst.s3_sync_options.bucket
25
28
  if (!bucket)
26
29
  raise Thor::Error.new "You need to activate this extension."
27
30
  end
28
31
 
29
- shared_inst.options.force = options[:force] if options[:force]
30
- shared_inst.options.bucket = options[:bucket] if options[:bucket]
32
+ # Override options based on what was passed on the command line...
33
+ shared_inst.s3_sync_options.force = options[:force] if options[:force]
34
+ shared_inst.s3_sync_options.bucket = options[:bucket] if options[:bucket]
35
+ shared_inst.s3_sync_options.verbose = options[:verbose] if options[:verbose]
31
36
 
32
37
  ::Middleman::S3Sync.sync
33
38
  end
@@ -13,7 +13,9 @@ module Middleman
13
13
  :delete,
14
14
  :existing_remote_file,
15
15
  :build_dir,
16
- :force
16
+ :force,
17
+ :prefer_gzip,
18
+ :verbose
17
19
  )
18
20
 
19
21
  def add_caching_policy(content_type, options)
@@ -66,7 +68,7 @@ module Middleman
66
68
  end
67
69
 
68
70
  class << self
69
- def options
71
+ def s3_sync_options
70
72
  @@options
71
73
  end
72
74
 
@@ -90,16 +92,16 @@ module Middleman
90
92
  alias :included :registered
91
93
 
92
94
  module Helpers
93
- def options
94
- ::Middleman::S3Sync.options
95
+ def s3_sync_options
96
+ ::Middleman::S3Sync.s3_sync_options
95
97
  end
96
98
 
97
99
  def default_caching_policy(policy = {})
98
- options.add_caching_policy(:default, policy)
100
+ s3_sync_options.add_caching_policy(:default, policy)
99
101
  end
100
102
 
101
103
  def caching_policy(content_type, policy = {})
102
- options.add_caching_policy(content_type, policy)
104
+ s3_sync_options.add_caching_policy(content_type, policy)
103
105
  end
104
106
  end
105
107
  end
@@ -1,5 +1,5 @@
1
1
  module Middleman
2
2
  module S3Sync
3
- VERSION = "3.0.10"
3
+ VERSION = "3.0.11"
4
4
  end
5
5
  end
@@ -0,0 +1,168 @@
1
+ module Middleman
2
+ module S3Sync
3
+ class Resource
4
+ attr_accessor :path, :s3_resource, :content_type, :gzipped
5
+
6
+ CONTENT_MD5_KEY = 'x-amz-meta-content-md5'
7
+
8
+ include Status
9
+
10
+ def initialize(path)
11
+ @path = path
12
+ @s3_resource = bucket.files.get(path) rescue nil
13
+ end
14
+
15
+ def remote_path
16
+ s3_resource ? s3_resource.key : path
17
+ end
18
+ alias :key :remote_path
19
+
20
+ def to_h
21
+ attributes = {
22
+ :key => key,
23
+ :body => body,
24
+ :public => true,
25
+ :acl => 'public-read',
26
+ :content_type => content_type,
27
+ CONTENT_MD5_KEY => content_md5
28
+ }
29
+
30
+ if caching_policy
31
+ attributes[:cache_control] = caching_policy.cache_control
32
+ attributes[:expires] = caching_policy.expires
33
+ end
34
+
35
+ if options.prefer_gzip && gzipped
36
+ attributes[:content_encoding] = "gzip"
37
+ end
38
+
39
+ attributes
40
+ end
41
+ alias :attributes :to_h
42
+
43
+ def update!
44
+ say_status "Updating".blue + " #{path}#{ gzipped ? ' (gzipped)'.white : ''}"
45
+ if options.verbose
46
+ say_status "Original: #{original_path.white}"
47
+ say_status "Local Path: #{local_path.white}"
48
+ say_status "remote md5: #{remote_md5.white}"
49
+ say_status "content md5: #{content_md5.white}"
50
+ end
51
+ s3_resource.body = body
52
+ s3_resource.public = true
53
+ s3_resource.acl = 'public-read'
54
+ s3_resource.content_type = content_type
55
+ s3_resource.metadata = { CONTENT_MD5_KEY => content_md5 }
56
+
57
+ if caching_policy
58
+ s3_resource.cache_control = caching_policy.cache_control
59
+ s3_resource.expires = caching_policy.expires
60
+ end
61
+
62
+ if options.prefer_gzip && gzipped
63
+ s3_resource.content_encoding = "gzip"
64
+ end
65
+
66
+ s3_resource.save
67
+ end
68
+
69
+ def local_path
70
+ local_path = build_dir + '/' + path
71
+ if options.prefer_gzip && File.exist?(local_path + ".gz")
72
+ @gzipped = true
73
+ local_path += ".gz"
74
+ end
75
+ local_path
76
+ end
77
+
78
+ def destroy!
79
+ say_status "Deleting".red + " #{path}".red
80
+ s3_resource.destroy
81
+ end
82
+
83
+ def create!
84
+ say_status "Creating".green + " #{path}#{ gzipped ? ' (gzipped)'.white : ''}"
85
+ bucket.files.create(to_h)
86
+ end
87
+
88
+ def to_delete?
89
+ status == :deleted
90
+ end
91
+
92
+ def to_create?
93
+ status == :new
94
+ end
95
+
96
+ def identical?
97
+ status == :identical
98
+ end
99
+
100
+ def to_update?
101
+ status == :updated
102
+ end
103
+
104
+ def body
105
+ @body = File.open(local_path)
106
+ end
107
+
108
+ def status
109
+ @status ||= if local? && remote?
110
+ if content_md5 != remote_md5
111
+ :updated
112
+ else
113
+ :identical
114
+ end
115
+ elsif local?
116
+ :new
117
+ else
118
+ :deleted
119
+ end
120
+ end
121
+
122
+ def local?
123
+ File.exist?(local_path)
124
+ end
125
+
126
+ def remote?
127
+ s3_resource
128
+ end
129
+
130
+ def relative_path
131
+ @relative_path ||= local_path.gsub(/#{build_dir}/, '')
132
+ end
133
+
134
+ def remote_md5
135
+ s3_resource.metadata[CONTENT_MD5_KEY] || s3_resource.etag
136
+ end
137
+
138
+ def content_md5
139
+ @content_md5 ||= Digest::MD5.hexdigest(File.read(original_path))
140
+ end
141
+
142
+ def original_path
143
+ gzipped ? local_path.gsub(/\.gz$/, '') : local_path
144
+ end
145
+
146
+ def content_type
147
+ @content_type ||= MIME::Types.of(path).first
148
+ end
149
+
150
+ def caching_policy
151
+ @caching_policy ||= options.caching_policy_for(content_type)
152
+ end
153
+
154
+ protected
155
+ def bucket
156
+ Middleman::S3Sync.bucket
157
+ end
158
+
159
+ def build_dir
160
+ options.build_dir
161
+ end
162
+
163
+ def options
164
+ Middleman::S3Sync.s3_sync_options
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,11 @@
1
+ require 'colorize'
2
+
3
+ module Middleman
4
+ module S3Sync
5
+ module Status
6
+ def say_status(status)
7
+ puts :s3_sync.to_s.rjust(12).green + " #{status}"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -19,8 +19,10 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.add_runtime_dependency 'middleman-core', '>= 3.0.0'
21
21
  gem.add_runtime_dependency 'fog'
22
- gem.add_runtime_dependency 'parallel'
23
22
  gem.add_runtime_dependency 'map'
23
+ gem.add_runtime_dependency 'pmap'
24
+ gem.add_runtime_dependency 'ruby-progressbar'
25
+ gem.add_runtime_dependency 'colorize'
24
26
 
25
27
  gem.add_development_dependency 'rake'
26
28
  gem.add_development_dependency 'pry'
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: middleman-s3_sync
3
3
  version: !ruby/object:Gem::Version
4
+ version: 3.0.11
4
5
  prerelease:
5
- version: 3.0.10
6
6
  platform: ruby
7
7
  authors:
8
8
  - Frederic Jean
@@ -10,33 +10,42 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-04-17 00:00:00.000000000 Z
13
+ date: 2013-05-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- version_requirements: !ruby/object:Gem::Requirement
16
+ name: middleman-core
17
+ requirement: !ruby/object:Gem::Requirement
17
18
  none: false
18
19
  requirements:
19
20
  - - ! '>='
20
21
  - !ruby/object:Gem::Version
21
22
  version: 3.0.0
22
- name: middleman-core
23
+ type: :runtime
23
24
  prerelease: false
24
- requirement: !ruby/object:Gem::Requirement
25
+ version_requirements: !ruby/object:Gem::Requirement
25
26
  none: false
26
27
  requirements:
27
28
  - - ! '>='
28
29
  - !ruby/object:Gem::Version
29
30
  version: 3.0.0
30
- type: :runtime
31
31
  - !ruby/object:Gem::Dependency
32
- version_requirements: !ruby/object:Gem::Requirement
32
+ name: fog
33
+ requirement: !ruby/object:Gem::Requirement
33
34
  none: false
34
35
  requirements:
35
36
  - - ! '>='
36
37
  - !ruby/object:Gem::Version
37
38
  version: '0'
38
- name: fog
39
+ type: :runtime
39
40
  prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: map
40
49
  requirement: !ruby/object:Gem::Requirement
41
50
  none: false
42
51
  requirements:
@@ -44,15 +53,15 @@ dependencies:
44
53
  - !ruby/object:Gem::Version
45
54
  version: '0'
46
55
  type: :runtime
47
- - !ruby/object:Gem::Dependency
56
+ prerelease: false
48
57
  version_requirements: !ruby/object:Gem::Requirement
49
58
  none: false
50
59
  requirements:
51
60
  - - ! '>='
52
61
  - !ruby/object:Gem::Version
53
62
  version: '0'
54
- name: parallel
55
- prerelease: false
63
+ - !ruby/object:Gem::Dependency
64
+ name: pmap
56
65
  requirement: !ruby/object:Gem::Requirement
57
66
  none: false
58
67
  requirements:
@@ -60,15 +69,15 @@ dependencies:
60
69
  - !ruby/object:Gem::Version
61
70
  version: '0'
62
71
  type: :runtime
63
- - !ruby/object:Gem::Dependency
72
+ prerelease: false
64
73
  version_requirements: !ruby/object:Gem::Requirement
65
74
  none: false
66
75
  requirements:
67
76
  - - ! '>='
68
77
  - !ruby/object:Gem::Version
69
78
  version: '0'
70
- name: map
71
- prerelease: false
79
+ - !ruby/object:Gem::Dependency
80
+ name: ruby-progressbar
72
81
  requirement: !ruby/object:Gem::Requirement
73
82
  none: false
74
83
  requirements:
@@ -76,15 +85,31 @@ dependencies:
76
85
  - !ruby/object:Gem::Version
77
86
  version: '0'
78
87
  type: :runtime
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
79
95
  - !ruby/object:Gem::Dependency
96
+ name: colorize
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :runtime
104
+ prerelease: false
80
105
  version_requirements: !ruby/object:Gem::Requirement
81
106
  none: false
82
107
  requirements:
83
108
  - - ! '>='
84
109
  - !ruby/object:Gem::Version
85
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
86
112
  name: rake
87
- prerelease: false
88
113
  requirement: !ruby/object:Gem::Requirement
89
114
  none: false
90
115
  requirements:
@@ -92,15 +117,15 @@ dependencies:
92
117
  - !ruby/object:Gem::Version
93
118
  version: '0'
94
119
  type: :development
95
- - !ruby/object:Gem::Dependency
120
+ prerelease: false
96
121
  version_requirements: !ruby/object:Gem::Requirement
97
122
  none: false
98
123
  requirements:
99
124
  - - ! '>='
100
125
  - !ruby/object:Gem::Version
101
126
  version: '0'
127
+ - !ruby/object:Gem::Dependency
102
128
  name: pry
103
- prerelease: false
104
129
  requirement: !ruby/object:Gem::Requirement
105
130
  none: false
106
131
  requirements:
@@ -108,15 +133,15 @@ dependencies:
108
133
  - !ruby/object:Gem::Version
109
134
  version: '0'
110
135
  type: :development
111
- - !ruby/object:Gem::Dependency
136
+ prerelease: false
112
137
  version_requirements: !ruby/object:Gem::Requirement
113
138
  none: false
114
139
  requirements:
115
140
  - - ! '>='
116
141
  - !ruby/object:Gem::Version
117
142
  version: '0'
143
+ - !ruby/object:Gem::Dependency
118
144
  name: pry-nav
119
- prerelease: false
120
145
  requirement: !ruby/object:Gem::Requirement
121
146
  none: false
122
147
  requirements:
@@ -124,6 +149,13 @@ dependencies:
124
149
  - !ruby/object:Gem::Version
125
150
  version: '0'
126
151
  type: :development
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ! '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
127
159
  description: Only syncs files that have been updated to S3.
128
160
  email:
129
161
  - fred@fredjean.net
@@ -132,6 +164,7 @@ extensions: []
132
164
  extra_rdoc_files: []
133
165
  files:
134
166
  - .gitignore
167
+ - Changelog.md
135
168
  - Gemfile
136
169
  - LICENSE.txt
137
170
  - README.md
@@ -140,6 +173,8 @@ files:
140
173
  - lib/middleman-s3_sync/commands.rb
141
174
  - lib/middleman-s3_sync/extension.rb
142
175
  - lib/middleman-s3_sync/version.rb
176
+ - lib/middleman/s3_sync/resource.rb
177
+ - lib/middleman/s3_sync/status.rb
143
178
  - lib/middleman_extension.rb
144
179
  - middleman-s3_sync.gemspec
145
180
  homepage: http://github.com/fredjean/middleman-s3_sync
@@ -153,19 +188,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
153
188
  requirements:
154
189
  - - ! '>='
155
190
  - !ruby/object:Gem::Version
191
+ version: '0'
156
192
  segments:
157
193
  - 0
158
- hash: 2846065098887891118
159
- version: '0'
194
+ hash: 963813138401624681
160
195
  required_rubygems_version: !ruby/object:Gem::Requirement
161
196
  none: false
162
197
  requirements:
163
198
  - - ! '>='
164
199
  - !ruby/object:Gem::Version
200
+ version: '0'
165
201
  segments:
166
202
  - 0
167
- hash: 2846065098887891118
168
- version: '0'
203
+ hash: 963813138401624681
169
204
  requirements: []
170
205
  rubyforge_project:
171
206
  rubygems_version: 1.8.23