git-lfs-s3 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/.gitignore +4 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +39 -0
- data/README.md +67 -0
- data/Rakefile +1 -0
- data/bin/git-lfs-s3 +15 -0
- data/git-lfs-s3.gemspec +26 -0
- data/lib/git-lfs-s3.rb +8 -0
- data/lib/git-lfs-s3/application.rb +78 -0
- data/lib/git-lfs-s3/aws.rb +35 -0
- data/lib/git-lfs-s3/services/upload.rb +26 -0
- data/lib/git-lfs-s3/services/upload/base.rb +28 -0
- data/lib/git-lfs-s3/services/upload/object_exists.rb +23 -0
- data/lib/git-lfs-s3/services/upload/upload_required.rb +48 -0
- data/lib/git-lfs-s3/version.rb +3 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -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
|
data/README.md
ADDED
@@ -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
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/git-lfs-s3
ADDED
@@ -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
|
+
)
|
data/git-lfs-s3.gemspec
ADDED
@@ -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
|
data/lib/git-lfs-s3.rb
ADDED
@@ -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
|
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: []
|