rstreet 1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5c9c064930f22deb7fb0a3fab8b8323509bcc533
4
+ data.tar.gz: e429f6c7e6ac79f70bed6253eb741cf9308007ef
5
+ SHA512:
6
+ metadata.gz: 8960137d9358d4e36fe35cc9020c48027be18c870be28585689dbed2ebe9d589d762a859b37bfa01814f5acc92540d2e7737c21000df306d08b38bb4b122530e
7
+ data.tar.gz: 1209e3e3483d148cc166287b5fba2bd42cb92c11bc1593c952e0082d0629e7ebd866d320cb61a3c362c72e543ce287517fc17e77600ea4e320b5ef58acad87a2
@@ -0,0 +1,3 @@
1
+ S3_BUCKET=asdf
2
+ AWS_ACCESS_KEY_ID=qwer
3
+ AWS_SECRET_ACCESS_KEY=zxcv
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rstreet.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 jaketrent
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,163 @@
1
+ # Rstreet
2
+
3
+ Smart Uploader for AWS S3 buckets.
4
+
5
+ Generates a manifest file upon first upload;
6
+ subsequent uploads only send changed files. Especially useful as a deploy tool
7
+ for uploading static websites to S3. Benefits of using Street:
8
+
9
+ * Upload only changed files; reduces **PUT** requests.
10
+ * GZip Compressed **manifest** file stored on S3 is very small.
11
+ * Mime-type lookup on upload to facilitate proper browser handling.
12
+ * Non-destructive *(mostly)*. Works with existing buckets and data. See *Manifest
13
+ File* section below for more details.
14
+
15
+ Ruby port of [tgroshon's](https://github.com/tgroshon) [street.js](https://github.com/tgroshon/street.js)
16
+
17
+ ## tl;dr
18
+
19
+ * Install with `gem install rstreet` to get the `rstreet` cli tool.
20
+ * Export **AWS_ACCESS_KEY_ID** and **AWS_SECRET_ACCESS_KEY** to your environment.
21
+ * Run `rstreet -e -b <Target S3 Bucket> path/to/upload/dir`
22
+
23
+ ## Installation
24
+
25
+ Add this line to your application's Gemfile:
26
+
27
+ ```ruby
28
+ gem 'rstreet'
29
+ ```
30
+
31
+ And then execute:
32
+
33
+ $ bundle
34
+
35
+ Or install it yourself as:
36
+
37
+ $ gem install rstreet
38
+
39
+ ## Command Line Options
40
+
41
+ A helpful interface into Street is using the command line tool `rstreet`. The
42
+ command line tool requires a path to a directory that you want to upload to S3 as
43
+ the last argument.
44
+ Run `rstreet --help` to see a list of options.
45
+
46
+ #### -e, --load-env, Load Environment Variables ####
47
+
48
+ Rstreet can load environment variables declared in a `.env` file of the current
49
+ working directory. With this option, Rstreet searches for 3 AWS variables:
50
+
51
+ 1. **AWS_ACCESS_KEY_ID**
52
+ 2. **AWS_SECRET_ACCESS_KEY**
53
+ 3. **S3_BUCKET**
54
+
55
+ Instead of using Environment Variables, you can some or all of these through
56
+ the command line options `--aws-key`, `--aws-secret`, and `--bucket`
57
+ respectively.
58
+
59
+ *Example*: `rstreet -e path/to/upload/dir`
60
+
61
+ #### -b, --bucket [bucket], S3 Destination Bucket ####
62
+
63
+ The Amazon S3 bucket to be the destination of your uploaded files.
64
+
65
+ *Example*: `rstreet -b <S3 bucket name> path/to/upload/dir`
66
+
67
+ #### -k, --aws-key [key], AWS Access Key Id ####
68
+
69
+ The AWS Access Key Id to be used for authenticating the S3 session. User must
70
+ have `PUT` and `GET` permissions on the bucket.
71
+
72
+ *Example*: `street -k <AWS Access Key Id> path/to/upload/dir`
73
+
74
+ #### -s, --aws-secret [secret], AWS Secret Access Key ####
75
+
76
+ The AWS Secret Access Key associated with the AWS Access Key Id you are using.
77
+
78
+ *Example*: `rstreet -s <AWS Secret Key> path/to/upload/dir`
79
+
80
+ #### -v, --verbose, Run with expanded messages ####
81
+
82
+ Shows the number of files uploaded, but not much else. This option will do more
83
+ in the future.
84
+
85
+ *Example*: `rstreet -v /path/to/upload/dir`
86
+
87
+ #### -n, --dry-run, Run but do not upload ####
88
+
89
+ Best if used in conjuction with the `--verbose` option.
90
+
91
+ *Example*:
92
+
93
+ `rstreet -n path/to/upload/dir`
94
+
95
+ `rstreet -nv path/to/upload/dir`
96
+
97
+ `rstreet -n path/to/upload/dir`
98
+
99
+ ## Run Programmatically
100
+
101
+ If you want to incorporate the Rstreet uploader into another program, that's
102
+ also possible. Perhaps you'd like to use it as a part of an API that can upload
103
+ to S3 or your own build script. Usage is simple. It takes a hash of options that
104
+ match the commandline interface. However, note that the names of the options are slightly
105
+ different.
106
+
107
+ ```ruby
108
+ require "rstreet"
109
+
110
+ options = {
111
+ src: 'path/to/upload/dir', # Path to directory to upload.
112
+ dry_run: false, # Disable upload mechanism.
113
+ s3_bucket: 'bucketname.com', # Name of S3 Bucket to upload to.
114
+ aws_key: 'AWS Access Key Id', # AWS Access Key Id for authentication w/ S3.
115
+ aws_secret: 'AWS Secret Key', # AWS Secret Key for authentication w/ S3.
116
+ load_env: true, # Load Environment Variables with 'dotenv'.
117
+ verbose: true, # Trigger extra messages.
118
+ }
119
+
120
+ Rstreet::Uploader.new(options).run
121
+ ```
122
+
123
+ You can make this part of a [Grunt](http://gruntjs.com/) task or your own,
124
+ standalone deploy script. Dealer's choice!
125
+
126
+ ## Manifest File
127
+
128
+ The `manifest.json.gz` file is a GZipped JSON file that maps S3 Object Keys (file
129
+ names) to MD5 Hashes.
130
+
131
+ The `manifest.json.gz` file is generated each time Street is run. On the first run
132
+ of Street on a specific directory, the `manifest.json.gz` file is written to that
133
+ directory (called the *upload directory*), and all files it found are uploaded to
134
+ S3. The next time Street is run, a **new manifest** is generated locally, the
135
+ **old manifest** is pulled down from S3, and the two files are compared to
136
+ search for differences. The **new manifest** is only written if files have
137
+ been changed. If files have been changed, the new `manifest.json.gz` and changed
138
+ files are then uploaded to S3 where they replace the objects of the same name.
139
+
140
+ This approach has two important effects that you should be aware of:
141
+
142
+ 1. **\*IMPORTANT\*** Upon first run of Street, all files in the directory
143
+ and a new `manifest.json.gz` file will be uploaded and replace S3 objects with
144
+ the same name.
145
+
146
+ 2. A `manifest.json.gz` file on S3 does *not* hold information on all the objects in
147
+ that bucket; only on objects that Street has specifically uploaded.
148
+
149
+ Keep these in mind as you work.
150
+
151
+ ## Setup AWS Access Policies
152
+
153
+ Make sure that the credentials that you're providing to the tool have sufficient access to read and write to the bucket you're attempting to access.
154
+
155
+ For an easy default, attach the managed access control policy "AmazonS3FullAccess" to your user/group.
156
+
157
+ ## Contributing
158
+
159
+ 1. Fork it ( https://github.com/[jaketrent]/rstreet/fork )
160
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
161
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
162
+ 4. Push to the branch (`git push origin my-new-feature`)
163
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rstreet"
4
+ require "opts_parser"
5
+
6
+ options = Rstreet::OptsParser.parse(ARGV)
7
+ chatter = Rstreet::Uploader.new(options)
8
+ chatter.run
9
+
@@ -0,0 +1,42 @@
1
+ require "s3"
2
+
3
+ require "manifest_builder"
4
+
5
+ module Rstreet
6
+ class BucketCommunicator
7
+ def initialize(s3_bucket, dry_run)
8
+ @s3, @dry_run = S3.new(s3_bucket), dry_run
9
+ end
10
+
11
+ def pull_manifest(manifest_uploadable)
12
+ manifest_file = @s3.get_file(manifest_uploadable)
13
+ if manifest_file
14
+ ManifestBuilder.new(manifest_file).read
15
+ else
16
+ ManifestBuilder.empty_manifest
17
+ end
18
+ end
19
+
20
+ def upload(uploadables)
21
+ # TODO: refactor into sep procs
22
+ uploadables.map do |u|
23
+ if dry_run?
24
+ puts "dry run upload: #{u.name}"
25
+ else
26
+ begin
27
+ @s3.put_file(u)
28
+ puts "uploaded: #{u.name}"
29
+ rescue StandardError => e
30
+ puts "error uploading: #{u.name}", e
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def dry_run?
39
+ @dry_run
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,20 @@
1
+ require 'set'
2
+
3
+ module Rstreet
4
+ class FilesReader
5
+ def self.read_all(dir)
6
+ dir = File.realpath dir
7
+ # TODO: print if verbose
8
+ # puts "Found files in #{@dir}:"
9
+
10
+ files = Dir.glob("#{dir}/**/*").to_set
11
+ dirs = Dir.glob("#{dir}/**/*/").map { |d| d[0..-2] }.to_set
12
+
13
+ # puts files.inspect
14
+ # puts ""
15
+ # puts dirs.inspect
16
+
17
+ files.subtract(dirs).to_a
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,48 @@
1
+ require "json"
2
+
3
+ module Rstreet
4
+ # TODO: name something more general to manifests (does more than builds)
5
+ class ManifestBuilder
6
+ attr_reader :manifest
7
+
8
+ def initialize(manifest_file)
9
+ @manifest = {}
10
+ @manifest_file = manifest_file
11
+ end
12
+
13
+ def self.empty_manifest
14
+ {}
15
+ end
16
+
17
+ def read
18
+ gz = Zlib::GzipReader.new(StringIO.new(@manifest_file))
19
+ @manifest = JSON.parse(gz.read).to_h
20
+ gz.close
21
+ @manifest
22
+ end
23
+
24
+ def write()
25
+ File.open(@manifest_file, "w") do |f|
26
+ gz = Zlib::GzipWriter.new(f)
27
+ gz.write @manifest.to_json.to_s
28
+ gz.close
29
+ end
30
+ end
31
+
32
+ def add(uploadable)
33
+ @manifest[uploadable.name] = uploadable.hash
34
+ end
35
+
36
+ def diff(other_manifest)
37
+ # TODO: determine if this is the diff algorithm we want
38
+ # TODO: in the future, account for deletions and delete objects from bucket
39
+ # 8 [ruby-2.1.5]::rstreet]>a.to_set
40
+ # => #<Set: {[:a, 1], [:b, 2], [:c, 3]}>
41
+ # 9 [ruby-2.1.5]::rstreet]>a.to_set.difference b.to_set
42
+ # => #<Set: {[:b, 2], [:c, 3]}>
43
+ # 10 [ruby-2.1.5]::rstreet]>b.to_set.difference a.to_set
44
+ # => #<Set: {[:b, 4]}>
45
+ @manifest.to_set.difference(other_manifest.to_set).to_h.keys
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,47 @@
1
+ require "optparse"
2
+ require "ostruct"
3
+
4
+ module Rstreet
5
+ class OptsParser
6
+ def self.parse(args)
7
+ options = OpenStruct.new
8
+ options.src = args[-1]
9
+
10
+ opt_parser = OptionParser.new do |opts|
11
+ opts.banner = "Usage: rstreet [options] <src_dir>"
12
+ opts.separator ""
13
+ opts.separator "Options:"
14
+
15
+ # TODO: DRY up
16
+ opts.on("-e", "--load-env",
17
+ "Load environment from .env file") do |load_env|
18
+ options.load_env = true
19
+ end
20
+ opts.on("-b b", "--bucket b",
21
+ "S3 destination bucket") do |s3_bucket|
22
+ options.s3_bucket = s3_bucket
23
+ end
24
+ opts.on("-k k", "--aws-key k",
25
+ "AWS Access Key ID") do |aws_key|
26
+ options.aws_key = aws_key
27
+ end
28
+ opts.on("-s s", "--aws-secret s",
29
+ "AWS Secret Access Key") do |aws_secret|
30
+ options.aws_secret = aws_secret
31
+ end
32
+ opts.on("-v", "--verbose",
33
+ "Run with expanded messages") do |verbose|
34
+ options.verbose = true
35
+ end
36
+ opts.on("-n", "--dry-run",
37
+ "Run but do not upload") do |dry_run|
38
+ options.dry_run = true
39
+ end
40
+
41
+ end
42
+
43
+ opt_parser.parse!(args)
44
+ options
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,58 @@
1
+ require "aws-sdk"
2
+ require "dotenv"
3
+
4
+ require "bucket_communicator"
5
+ require "rstreet/version"
6
+ require "uploadable_collector"
7
+
8
+ module Rstreet
9
+ class Uploader
10
+ def initialize(options)
11
+ @options = options
12
+ load_env if should_load_env?
13
+ config_aws
14
+ validate_options
15
+ end
16
+
17
+ def run
18
+ collector = UploadableCollector.new(@options.src)
19
+ uploadables = collector.collect
20
+
21
+ bucket_communicator = BucketCommunicator.new(@options.s3_bucket, @options.dry_run)
22
+ old_manifest = bucket_communicator.pull_manifest(collector.manifest_uploadable)
23
+ current_manifest_builder = collector.manifest_builder
24
+ diff = current_manifest_builder.diff(old_manifest)
25
+
26
+ to_upload = collector.find_uploadables(diff)
27
+ bucket_communicator.upload(to_upload)
28
+ end
29
+
30
+ private
31
+
32
+ def config_aws
33
+ AWS.config(access_key_id: @options.aws_key, secret_access_key: @options.aws_secret)
34
+ end
35
+
36
+ def load_env
37
+ Dotenv.load
38
+ @options.s3_bucket ||= ENV["S3_BUCKET"]
39
+ @options.aws_key ||= ENV["AWS_ACCESS_KEY_ID"]
40
+ @options.aws_secret ||= ENV["AWS_SECRET_ACCESS_KEY"]
41
+ end
42
+
43
+ def should_load_env?
44
+ @options.load_env
45
+ end
46
+
47
+ def validate_options
48
+ # TODO: DRY'ify
49
+ raise ArgumentError, "Specify a source directory in options.src" if @options.src.nil?
50
+
51
+ raise ArgumentError, "Specify an S3 Bucket in an env var called S3_BUCKET or options.s3_bucket" if @options.s3_bucket.nil?
52
+
53
+ raise ArgumentError, "Specify an AWS Access Key Id in an env var called AWS_ACCESS_KEY_ID or options.aws_key" if @options.aws_key.nil?
54
+
55
+ raise ArgumentError, "Specify an AWS Secret Access Key in env var called AWS_SECRET_ACCESS_KEY or options.aws_secret" if @options.aws_secret.nil?
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module Rstreet
2
+ VERSION = "1.0.1"
3
+ end
@@ -0,0 +1,19 @@
1
+ require "aws-sdk"
2
+
3
+ module Rstreet
4
+ class S3
5
+ def initialize(s3_bucket)
6
+ @s3 = AWS::S3.new
7
+ @s3_bucket = s3_bucket
8
+ end
9
+
10
+ def get_file(uploadable)
11
+ @s3.buckets[@s3_bucket].objects[uploadable.name].read
12
+ rescue AWS::S3::Errors::NoSuchKey
13
+ end
14
+
15
+ def put_file(uploadable)
16
+ @s3.buckets[@s3_bucket].objects[uploadable.name].write(file: uploadable.path, acl: :authenticated_read)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ require "mime/types"
2
+
3
+ module Rstreet
4
+ class Uploadable
5
+ attr_reader :name, :path, :hash
6
+
7
+ def initialize(name, path)
8
+ @name, @path = name, path
9
+ @hash = gen_hash || ""
10
+ @content_type = gen_content_type || "application/octet-stream"
11
+ end
12
+
13
+ private
14
+
15
+ def gen_hash
16
+ Digest::MD5.file(@path).hexdigest if File.file?(@path)
17
+ end
18
+
19
+ def gen_content_type
20
+ MIME::Types.type_for(@path).first.content_type
21
+ rescue
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,72 @@
1
+ require "files_reader"
2
+ require "manifest_builder"
3
+ require "uploadable"
4
+
5
+ module Rstreet
6
+ class UploadableCollector
7
+
8
+ # TODO: Shouldn't need to get this for the pull_manifest in rstreet.rb
9
+ # Instead, consider some class method with the default file path info
10
+ attr_reader :manifest_builder, :manifest_uploadable
11
+
12
+ def initialize(src)
13
+ @src = File.realpath src
14
+ # TODO: get rid of cache and consolidate inside of manifest builder
15
+ @uploadables_cache = {}
16
+ init_manifest_builder
17
+ end
18
+
19
+ def collect
20
+ files = FilesReader.read_all(@src)
21
+ uploadables = convert_files_to_uploadables files
22
+ uploadables = add_manifest_to_uploadables uploadables
23
+ save_uploadables_in_manifest uploadables
24
+ uploadables
25
+ end
26
+
27
+ # TODO: be more consistent with name, file, path var names
28
+ def find_uploadables(file_names)
29
+ @uploadables_cache.select { |k, v| file_names.include? k }.values
30
+ end
31
+
32
+ private
33
+
34
+ def save_uploadables_in_manifest(uploadables)
35
+ uploadables.each do |u|
36
+ @manifest_builder.add u
37
+ @uploadables_cache[u.name] = u
38
+ end
39
+ @manifest_builder.write
40
+ end
41
+
42
+ def init_manifest_builder
43
+ manifest_file = File.join(@src, ".manifest.json.gz")
44
+ @manifest_uploadable = convert_to_uploadable(manifest_file)
45
+ @manifest_builder = ManifestBuilder.new manifest_file
46
+ end
47
+
48
+ def convert_files_to_uploadables(files)
49
+ files.map do |file|
50
+ convert_to_uploadable(file)
51
+ end
52
+ end
53
+
54
+ def add_manifest_to_uploadables(uploadables)
55
+ uploadables << @manifest_uploadable if uploadables.any?
56
+ uploadables
57
+ end
58
+
59
+ def convert_to_uploadable(file)
60
+ Uploadable.new(format_uploadable_name(file), file)
61
+ end
62
+
63
+ def format_uploadable_name(file)
64
+ file.sub(ensure_ends_with_separator(@src), "")
65
+ end
66
+
67
+ def ensure_ends_with_separator(path)
68
+ path.end_with?(File::SEPARATOR) ? path : "#{path}#{File::SEPARATOR}"
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rstreet/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rstreet"
8
+ spec.version = Rstreet::VERSION
9
+ spec.authors = ["jaketrent"]
10
+ spec.email = ["trent.jake@gmail.com"]
11
+ spec.summary = %q{Smart uploader for S3}
12
+ spec.description = %q{Smart s3 uploader. Generates a manifest file on first upload. Minimizes future uploads by only sending changed files.}
13
+ spec.homepage = "https://github.com/jaketrent/rstreet"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "dotenv", "~> 1.0.2"
24
+ spec.add_development_dependency "mime-types", "~> 2.4.3"
25
+ spec.add_development_dependency "aws-sdk", "~> 2"
26
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rstreet
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - jaketrent
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dotenv
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.0.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: mime-types
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 2.4.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 2.4.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: aws-sdk
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2'
83
+ description: Smart s3 uploader. Generates a manifest file on first upload. Minimizes
84
+ future uploads by only sending changed files.
85
+ email:
86
+ - trent.jake@gmail.com
87
+ executables:
88
+ - rstreet
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".env.example"
93
+ - ".gitignore"
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - bin/rstreet
99
+ - lib/bucket_communicator.rb
100
+ - lib/files_reader.rb
101
+ - lib/manifest_builder.rb
102
+ - lib/opts_parser.rb
103
+ - lib/rstreet.rb
104
+ - lib/rstreet/version.rb
105
+ - lib/s3.rb
106
+ - lib/uploadable.rb
107
+ - lib/uploadable_collector.rb
108
+ - rstreet.gemspec
109
+ homepage: https://github.com/jaketrent/rstreet
110
+ licenses:
111
+ - MIT
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 2.4.3
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: Smart uploader for S3
133
+ test_files: []
134
+ has_rdoc: