middleman-s3_sync 3.0.10 → 3.0.11

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