git-lfs-s3 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4548ca444d7fc60b4f00896823b11b6385e43243
4
+ data.tar.gz: 986bcbcc585dfda6dd70656bed1e005bf519ac77
5
+ SHA512:
6
+ metadata.gz: 6d383ec8ef3ff7c0347e438650402e25db7141deb24e41de8b2684330ead5abd38d295a6784071d48a7a562ab9db7cff1e5544fbc446080da879783e907a4aee
7
+ data.tar.gz: 701233c012f4b11ff74494b8de0ffca43682eafed2f799bb38344939a42f1914219d5358423181410db2d60913be625fc28f12d57af985f45f9029f85be92cd6
@@ -0,0 +1,4 @@
1
+ .env
2
+ .DS_Store
3
+ logs
4
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,39 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ git-lfs-s3 (0.0.1)
5
+ aws-sdk (~> 2)
6
+ multi_json
7
+ sinatra
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ aws-sdk (2.0.38)
13
+ aws-sdk-resources (= 2.0.38)
14
+ aws-sdk-core (2.0.38)
15
+ builder (~> 3.0)
16
+ jmespath (~> 1.0)
17
+ multi_json (~> 1.0)
18
+ aws-sdk-resources (2.0.38)
19
+ aws-sdk-core (= 2.0.38)
20
+ builder (3.2.2)
21
+ jmespath (1.0.2)
22
+ multi_json (~> 1.0)
23
+ multi_json (1.11.0)
24
+ rack (1.6.0)
25
+ rack-protection (1.5.3)
26
+ rack
27
+ rake (10.4.2)
28
+ sinatra (1.4.6)
29
+ rack (~> 1.4)
30
+ rack-protection (~> 1.4)
31
+ tilt (>= 1.3, < 3)
32
+ tilt (2.0.1)
33
+
34
+ PLATFORMS
35
+ ruby
36
+
37
+ DEPENDENCIES
38
+ git-lfs-s3!
39
+ rake
@@ -0,0 +1,67 @@
1
+ # Git LFS S3
2
+
3
+ A [Git LFS](https://git-lfs.github.com/) server that stores your large Git files on S3.
4
+
5
+ It works by generating a presigned URL that the Git LFS client can use to upload directly to S3. It also provides download URLs that allow Git clients to download directly from S3. No data is proxied through the Git LFS server.
6
+
7
+ **Note:** the current version does not implement any authentication yet, so use with caution. Authentication will be added soon.
8
+
9
+ ## Installation
10
+
11
+ Git LFS S3 is available on RubyGems.
12
+
13
+ ``` bash
14
+ gem install git-lfs-s3
15
+ ```
16
+
17
+ Or add it to your Gemfile if you wish to bundle it as a part of another application.
18
+
19
+ ``` ruby
20
+ gem 'git-lfs-s3'
21
+ ```
22
+
23
+ ## Configuration
24
+
25
+ ### Standalone
26
+
27
+ All configuration is done via environment variables. All of the configuration variables must be set.
28
+
29
+ * `AWS_REGION` - the region where your S3 bucket is.
30
+ * `AWS_ACCESS_KEY_ID` - your AWS access key.
31
+ * `AWS_SECRET_ACCESS_KEY` - your AWS secret key.
32
+ * `S3_BUCKET` - the bucket you wish to use for LFS storage. While not required, I recommend using a dedicated bucket for this.
33
+ * `LFS_SERVER_URL` - the URL where this server can be reached; needed to fetch download URLs.
34
+
35
+ ### Bundled
36
+
37
+ If you are bundling the server inside of another application, such as Rails, you can set the configuration directly on `GitLfsS3::Application`. See [bin/git-lfs-s3](https://github.com/meltingice/git-lfs-s3/blob/master/bin/git-lfs-s3) for an example.
38
+
39
+ ### Git Setup
40
+
41
+ If you are new to Git LFS, make sure you read the [Getting Started](https://git-lfs.github.com/) guide first. Once that's done, you can configure your Git client to use this server by creating a `.gitconfig` file in the root of your repository and adding this config, but with your server address:
42
+
43
+ ``` git
44
+ [lfs]
45
+ url = "http://yourserver.com"
46
+ ```
47
+
48
+ Once that is done, you can tell Git LFS to track files with `git lfs track "*.psd"`, for example.
49
+
50
+ ## Running
51
+
52
+ This repository contains an executable that will run a basic WEBrick server. Since this service is so lightweight, that's likely all you'll need. The port will default to 8080, but can be configured with an environment variable.
53
+
54
+ ``` bash
55
+ PORT=4000 git-lfs-s3
56
+ ```
57
+
58
+ However, because this is a Sinatra application, it can also be mounted within other Rack based projects or other Rack-based servers such as Unicorn or Puma. For example, if you wanted to add this to your Rails project, configure `GitLfsS3` in an initializer, and add this your routes:
59
+
60
+ ``` ruby
61
+ mount GitLfsS3::Application => '/lfs'
62
+ ```
63
+
64
+ ## TODO
65
+
66
+ * Authentication
67
+ * Cloudfront support
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "git-lfs-s3"
5
+
6
+ GitLfsS3::Application.set :aws_region, ENV['AWS_REGION']
7
+ GitLfsS3::Application.set :aws_access_key_id, ENV['AWS_ACCESS_KEY_ID']
8
+ GitLfsS3::Application.set :aws_secret_access_key, ENV['AWS_SECRET_ACCESS_KEY']
9
+ GitLfsS3::Application.set :s3_bucket, ENV['S3_BUCKET']
10
+ GitLfsS3::Application.set :server_url, ENV['LFS_SERVER_URL']
11
+
12
+ Rack::Handler::WEBrick.run(
13
+ GitLfsS3::Application.new,
14
+ Port: ENV['PORT'] || 8080
15
+ )
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git-lfs-s3/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "git-lfs-s3"
8
+ gem.version = GitLfsS3::VERSION
9
+ gem.authors = ["Ryan LeFevre"]
10
+ gem.email = ["meltingice8917@gmail.com"]
11
+ gem.description = %q{A Git LFS server that uses S3 for the storage backend.}
12
+ gem.summary = %q{A Git LFS server that uses S3 for the storage backend by providing presigned S3 URLs.}
13
+ gem.homepage = "https://github.com/meltingice/git-lfs-s3"
14
+ gem.license = 'MIT'
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+
21
+ gem.add_dependency 'aws-sdk', '~> 2'
22
+ gem.add_dependency 'sinatra'
23
+ gem.add_dependency 'multi_json'
24
+
25
+ gem.add_development_dependency 'rake'
26
+ end
@@ -0,0 +1,8 @@
1
+ require 'logger'
2
+ require 'sinatra/base'
3
+ require 'aws-sdk'
4
+ require 'multi_json'
5
+
6
+ require "git-lfs-s3/aws"
7
+ require "git-lfs-s3/services/upload"
8
+ require "git-lfs-s3/application"
@@ -0,0 +1,78 @@
1
+ module GitLfsS3
2
+ class Application < Sinatra::Application
3
+ include AwsHelpers
4
+
5
+ configure do
6
+ disable :sessions
7
+ enable :logging
8
+
9
+ Dir.mkdir('logs') unless Dir.exists?('logs')
10
+ $logger = Logger.new("logs/#{settings.environment}.log", "weekly")
11
+ $logger.level = Logger::INFO
12
+ end
13
+
14
+ configure :development do
15
+ $logger.level = Logger::DEBUG
16
+ end
17
+
18
+ helpers do
19
+ def logger
20
+ $logger
21
+ end
22
+ end
23
+
24
+ # before do
25
+ # raise headers['Accept'].inspect
26
+ # if headers['Accept'] != 'application/vnd.git-lfs+json'
27
+ # halt 406, {'Content-Type' => 'text/plain'}, 'Server only accepts application/vnd.git-lfs+json'
28
+ # end
29
+ # end
30
+
31
+ get "/objects/:oid", provides: 'application/vnd.git-lfs+json' do
32
+ object = object_data(params[:oid])
33
+
34
+ if object.exists?
35
+ status 200
36
+ resp = {
37
+ 'oid' => params[:oid],
38
+ 'size' => object.size,
39
+ '_links' => {
40
+ 'self' => {
41
+ 'href' => File.join(settings.server_url, 'objects', params[:oid])
42
+ },
43
+ 'download' => {
44
+ # TODO: cloudfront support
45
+ 'href' => object_data(params[:oid]).presigned_url(:get)
46
+ }
47
+ }
48
+ }
49
+
50
+ body MultiJson.dump(resp)
51
+ else
52
+ status 404
53
+ body MultiJson.dump({message: 'Object not found'})
54
+ end
55
+ end
56
+
57
+ post "/objects", provides: 'application/vnd.git-lfs+json' do
58
+ logger.debug headers.inspect
59
+ service = UploadService.service_for(request.body)
60
+ logger.debug service.response
61
+ logger.debug service.to_curl
62
+
63
+ status service.status
64
+ body MultiJson.dump(service.response)
65
+ end
66
+
67
+ post '/verify', provides: 'application/vnd.git-lfs+json' do
68
+ data = MultiJson.load(request.body.tap { |b| b.rewind }.read)
69
+ object = object_data(data['oid'])
70
+
71
+ if object.exists? && object.size == data['size']
72
+ status 200
73
+ else
74
+ status 404
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,35 @@
1
+ module GitLfsS3
2
+ module AwsHelpers
3
+ def s3
4
+ @s3 ||= Aws::S3::Client.new({
5
+ region: aws_region,
6
+ access_key_id: aws_access_key_id,
7
+ secret_access_key: aws_secret_access_key
8
+ })
9
+ end
10
+
11
+ def bucket_name
12
+ GitLfsS3::Application.settings.s3_bucket
13
+ end
14
+
15
+ def bucket
16
+ @bucket ||= Aws::S3::Bucket.new(name: bucket_name, client: s3)
17
+ end
18
+
19
+ def object_data(oid)
20
+ bucket.object("data/#{oid}")
21
+ end
22
+
23
+ def aws_region
24
+ GitLfsS3::Application.settings.aws_region
25
+ end
26
+
27
+ def aws_access_key_id
28
+ GitLfsS3::Application.settings.aws_access_key_id
29
+ end
30
+
31
+ def aws_secret_access_key
32
+ GitLfsS3::Application.settings.aws_secret_access_key
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,26 @@
1
+ require "git-lfs-s3/services/upload/base"
2
+ require "git-lfs-s3/services/upload/object_exists"
3
+ require "git-lfs-s3/services/upload/upload_required"
4
+
5
+ module GitLfsS3
6
+ module UploadService
7
+ extend self
8
+ extend AwsHelpers
9
+
10
+ MODULES = [
11
+ ObjectExists,
12
+ UploadRequired
13
+ ]
14
+
15
+ def service_for(data)
16
+ req = MultiJson.load data.tap { |d| d.rewind }.read
17
+ object = object_data(req['oid'])
18
+
19
+ MODULES.each do |mod|
20
+ return mod.new(req, object) if mod.should_handle?(req, object)
21
+ end
22
+
23
+ nil
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ module GitLfsS3
2
+ module UploadService
3
+ class Base
4
+ include AwsHelpers
5
+
6
+ attr_reader :req, :object
7
+
8
+ def initialize(req, object)
9
+ @req = req
10
+ @object = object
11
+ end
12
+
13
+ def response
14
+ raise "Override"
15
+ end
16
+
17
+ def status
18
+ raise "Override"
19
+ end
20
+
21
+ private
22
+
23
+ def server_url
24
+ GitLfsS3::Application.settings.server_url
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ module GitLfsS3
2
+ module UploadService
3
+ class ObjectExists < Base
4
+ def self.should_handle?(req, object)
5
+ object.exists? && object.size == req['size']
6
+ end
7
+
8
+ def response
9
+ {
10
+ '_links' => {
11
+ 'download' => {
12
+ 'href' => object.presigned_url(:get)
13
+ }
14
+ }
15
+ }
16
+ end
17
+
18
+ def status
19
+ 200
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,48 @@
1
+ module GitLfsS3
2
+ module UploadService
3
+ class UploadRequired < Base
4
+ def self.should_handle?(req, object)
5
+ !object.exists? || object.size != req['size']
6
+ end
7
+
8
+ def response
9
+ {
10
+ '_links' => {
11
+ 'upload' => {
12
+ 'href' => upload_destination,
13
+ 'header' => upload_headers
14
+ },
15
+ 'verify' => {
16
+ 'href' => File.join(server_url, 'verify')
17
+ }
18
+ }
19
+ }
20
+ end
21
+
22
+ def status
23
+ 202
24
+ end
25
+
26
+ def to_curl
27
+ curl = ["curl -XPUT"]
28
+ curl << "-T \"{{file}}\""
29
+ upload_headers.each do |k, v|
30
+ curl << "-H \"#{k}: #{v}\""
31
+ end
32
+ curl << upload_destination
33
+
34
+ curl.join(' ')
35
+ end
36
+
37
+ private
38
+
39
+ def upload_destination
40
+ object.presigned_url(:put)
41
+ end
42
+
43
+ def upload_headers
44
+ {'content-type' => ''}
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module GitLfsS3
2
+ VERSION = '0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-lfs-s3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan LeFevre
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sinatra
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: multi_json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A Git LFS server that uses S3 for the storage backend.
70
+ email:
71
+ - meltingice8917@gmail.com
72
+ executables:
73
+ - git-lfs-s3
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - README.md
81
+ - Rakefile
82
+ - bin/git-lfs-s3
83
+ - git-lfs-s3.gemspec
84
+ - lib/git-lfs-s3.rb
85
+ - lib/git-lfs-s3/application.rb
86
+ - lib/git-lfs-s3/aws.rb
87
+ - lib/git-lfs-s3/services/upload.rb
88
+ - lib/git-lfs-s3/services/upload/base.rb
89
+ - lib/git-lfs-s3/services/upload/object_exists.rb
90
+ - lib/git-lfs-s3/services/upload/upload_required.rb
91
+ - lib/git-lfs-s3/version.rb
92
+ homepage: https://github.com/meltingice/git-lfs-s3
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.4.5
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: A Git LFS server that uses S3 for the storage backend by providing presigned
116
+ S3 URLs.
117
+ test_files: []