git_dump 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +62 -0
- data/.travis.yml +37 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +75 -0
- data/git_dump.gemspec +22 -0
- data/lib/git_dump.rb +41 -0
- data/lib/git_dump/cmd.rb +118 -0
- data/lib/git_dump/entry.rb +31 -0
- data/lib/git_dump/path_object.rb +11 -0
- data/lib/git_dump/repo.rb +42 -0
- data/lib/git_dump/repo/git.rb +331 -0
- data/lib/git_dump/repo/rugged.rb +97 -0
- data/lib/git_dump/tree.rb +31 -0
- data/lib/git_dump/tree/base.rb +54 -0
- data/lib/git_dump/tree/builder.rb +62 -0
- data/lib/git_dump/version.rb +55 -0
- data/lib/git_dump/version/base.rb +21 -0
- data/lib/git_dump/version/builder.rb +77 -0
- data/script/benchmark +81 -0
- data/spec/git_dump_spec.rb +392 -0
- data/spec/spec_helper.rb +0 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZDRlN2E3ZTg5MmUzZWI5M2IxNjhjYzU0Y2Y3ZmQ2YWZiYzU3MTcwMg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MThmYjAxMzY5NGI3Yzg4YjU5ODg3ZDQwOTBlYTQ1MTJmOGYwZDk0Yw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YTA2NjUwNWNmNDU4NDVhNDNjYzUxN2U1ZDFkODg5N2I2YzY4MmE0MGI5OGYy
|
10
|
+
Zjk2OGI3YzYxZTQ4NWY1NTFmYzRiNzgxNmQ0NzZiYTE3ZGNkZjgxOWE0ODMw
|
11
|
+
ZDgyMDhkZGFjNWFhM2IyNWE5MDVmMTI2MmE3OGUzMDMxZGQ3N2Q=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
N2RiOTIxY2Y3ZTgxOWM2MTYzOTMyNWNlNDhiMGNiYjBhNzNlYzM3ZDk2NGFk
|
14
|
+
MzdiN2RmODBjZmE2NGU2Nzk3MThmYzJlYjM4NWU2NDEyNWE1ZjcwMDdmZDMz
|
15
|
+
NWQ2YzJiMzUzNzg5OTRhYjMyNmQ4NzEwMTlmMWVkNGRlZGVkYzA=
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- '*.gemspec'
|
4
|
+
|
5
|
+
Lint/EndAlignment:
|
6
|
+
AlignWith: variable
|
7
|
+
|
8
|
+
Metrics/AbcSize:
|
9
|
+
Max: 25
|
10
|
+
|
11
|
+
Metrics/CyclomaticComplexity:
|
12
|
+
Max: 10
|
13
|
+
|
14
|
+
Metrics/MethodLength:
|
15
|
+
Max: 20
|
16
|
+
|
17
|
+
Metrics/PerceivedComplexity:
|
18
|
+
Max: 8
|
19
|
+
|
20
|
+
Style/AccessModifierIndentation:
|
21
|
+
EnforcedStyle: outdent
|
22
|
+
|
23
|
+
Style/BracesAroundHashParameters:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Style/CaseIndentation:
|
27
|
+
IndentWhenRelativeTo: end
|
28
|
+
|
29
|
+
Style/DotPosition:
|
30
|
+
EnforcedStyle: trailing
|
31
|
+
|
32
|
+
Style/DoubleNegation:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Style/Encoding:
|
36
|
+
EnforcedStyle: when_needed
|
37
|
+
|
38
|
+
Style/HashSyntax:
|
39
|
+
EnforcedStyle: hash_rockets
|
40
|
+
|
41
|
+
Style/IfUnlessModifier:
|
42
|
+
MaxLineLength: 40
|
43
|
+
|
44
|
+
Style/IndentHash:
|
45
|
+
EnforcedStyle: consistent
|
46
|
+
|
47
|
+
Style/PercentLiteralDelimiters:
|
48
|
+
PreferredDelimiters:
|
49
|
+
'%w': '[]'
|
50
|
+
'%W': '[]'
|
51
|
+
|
52
|
+
Style/Semicolon:
|
53
|
+
AllowAsExpressionSeparator: true
|
54
|
+
|
55
|
+
Style/SpaceBeforeBlockBraces:
|
56
|
+
EnforcedStyle: no_space
|
57
|
+
|
58
|
+
Style/SpaceInsideHashLiteralBraces:
|
59
|
+
EnforcedStyle: no_space
|
60
|
+
|
61
|
+
Style/TrailingComma:
|
62
|
+
EnforcedStyleForMultiline: comma
|
data/.travis.yml
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.8.7
|
4
|
+
- 1.9.3
|
5
|
+
- '2.0'
|
6
|
+
- '2.1'
|
7
|
+
- '2.2'
|
8
|
+
- jruby-18mode
|
9
|
+
- jruby-19mode
|
10
|
+
- ree
|
11
|
+
script:
|
12
|
+
if [ -n "$RUBOCOP" ]; then
|
13
|
+
bundle exec rubocop
|
14
|
+
; elif [ -n "$BENCHMARK" ]; then
|
15
|
+
RUGGED=0 bundle exec script/benchmark; RUGGED=1 bundle exec script/benchmark
|
16
|
+
; else
|
17
|
+
bundle exec rspec
|
18
|
+
; fi
|
19
|
+
env:
|
20
|
+
-
|
21
|
+
- RUGGED=1
|
22
|
+
matrix:
|
23
|
+
fast_finish: true
|
24
|
+
include:
|
25
|
+
- env: RUBOCOP=true
|
26
|
+
rvm: default
|
27
|
+
- env: BENCHMARK=true RUGGED=1
|
28
|
+
rvm: default
|
29
|
+
exclude:
|
30
|
+
- rvm: 1.8.7
|
31
|
+
env: RUGGED=1
|
32
|
+
- rvm: jruby-18mode
|
33
|
+
env: RUGGED=1
|
34
|
+
- rvm: jruby-19mode
|
35
|
+
env: RUGGED=1
|
36
|
+
- rvm: ree
|
37
|
+
env: RUGGED=1
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012-2014 Ivan Kuchin
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
[![Gem Version](https://img.shields.io/gem/v/git_dump.svg?style=flat)](https://rubygems.org/gems/git_dump)
|
2
|
+
[![Build Status](https://img.shields.io/travis/toy/git_dump/master.svg?style=flat)](https://travis-ci.org/toy/git_dump)
|
3
|
+
[![Code Climate](https://img.shields.io/codeclimate/github/toy/git_dump.svg?style=flat)](https://codeclimate.com/github/toy/git_dump)
|
4
|
+
[![Dependency Status](https://img.shields.io/gemnasium/toy/git_dump.svg?style=flat)](https://gemnasium.com/toy/git_dump)
|
5
|
+
[![Inch CI](http://inch-ci.org/github/toy/git_dump.svg?branch=master&style=flat)](http://inch-ci.org/github/toy/git_dump)
|
6
|
+
|
7
|
+
# git_dump
|
8
|
+
|
9
|
+
Distributed versioned store using git.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
```sh
|
14
|
+
gem install git_dump
|
15
|
+
```
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
Init:
|
20
|
+
|
21
|
+
```rb
|
22
|
+
dump = GitDump.new('dump.git', :create => true)
|
23
|
+
```
|
24
|
+
|
25
|
+
Create version:
|
26
|
+
|
27
|
+
```rb
|
28
|
+
version = dump.new_version
|
29
|
+
version['a/b/c'] = 'string'
|
30
|
+
version.store('b/c/d', StringIO.new('string'), 0644)
|
31
|
+
version.store('d/e', File.open('path'), 0755)
|
32
|
+
version.store_from('e/f', 'path')
|
33
|
+
version.commit(:tags => 'test')
|
34
|
+
```
|
35
|
+
|
36
|
+
Read version:
|
37
|
+
|
38
|
+
```rb
|
39
|
+
version = dump.versions.last
|
40
|
+
version['a/b/c'].open{ |f| f.read }
|
41
|
+
version['a/b/c'].read
|
42
|
+
version['a/b/c'].write_to('new_path')
|
43
|
+
|
44
|
+
version.each do |path_object|
|
45
|
+
path_object.path
|
46
|
+
end
|
47
|
+
|
48
|
+
version.each_recursive do |entry|
|
49
|
+
entry.read
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
Versions:
|
54
|
+
|
55
|
+
```rb
|
56
|
+
dump.versions.each do |version|
|
57
|
+
puts [version.id, version.time, version.commit_time].join(' ')
|
58
|
+
end
|
59
|
+
|
60
|
+
dump.versions.first.remove
|
61
|
+
```
|
62
|
+
|
63
|
+
Remote (url in any syntax supported by git including local paths):
|
64
|
+
|
65
|
+
```rb
|
66
|
+
ids = GitDump.remote_version_ids(url)
|
67
|
+
|
68
|
+
dump.versions.last.push(url)
|
69
|
+
|
70
|
+
dump.fetch(url, ids.first)
|
71
|
+
```
|
72
|
+
|
73
|
+
## Copyright
|
74
|
+
|
75
|
+
Copyright (c) 2012-2014 Ivan Kuchin. See LICENSE.txt for details.
|
data/git_dump.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'git_dump'
|
5
|
+
s.version = '0.1.0'
|
6
|
+
s.summary = %q{Distributed versioned store using git}
|
7
|
+
s.homepage = "http://github.com/toy/#{s.name}"
|
8
|
+
s.authors = ['Ivan Kuchin']
|
9
|
+
s.license = 'MIT'
|
10
|
+
|
11
|
+
s.rubyforge_project = s.name
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
s.require_paths = %w[lib]
|
17
|
+
|
18
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
19
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9.3')
|
20
|
+
s.add_development_dependency 'rubocop', '~> 0.27'
|
21
|
+
end
|
22
|
+
end
|
data/lib/git_dump.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'git_dump/repo'
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
# Main interface, most instance methods forwarded to Repo
|
7
|
+
class GitDump
|
8
|
+
# Initialize using existing repositiory
|
9
|
+
# use `:create => true` or `:create => :bare` to create bare repo if missing
|
10
|
+
# or `:create => :non_bare` for non bare one
|
11
|
+
def initialize(path, options = {})
|
12
|
+
@repo = Repo.new(path, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
extend Forwardable
|
16
|
+
|
17
|
+
def_delegators :@repo, :path, :new_version, :versions, :fetch, :gc
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# List remote version ids
|
21
|
+
def remote_version_ids(url)
|
22
|
+
Repo.remote_version_ids(url)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# hostname as returned by `hostname` or "unknown"
|
27
|
+
def self.hostname
|
28
|
+
@hostname ||= begin
|
29
|
+
hostname = `hostname`.chomp
|
30
|
+
hostname.empty? ? 'unknown' : hostname
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# From 1.9 securerandom.rb, to replace with SecureRandom.uuid
|
35
|
+
def self.uuid
|
36
|
+
ary = SecureRandom.random_bytes(16).unpack('NnnnnN')
|
37
|
+
ary[2] = (ary[2] & 0x0fff) | 0x4000
|
38
|
+
ary[3] = (ary[3] & 0x3fff) | 0x8000
|
39
|
+
format '%08x-%04x-%04x-%04x-%04x%08x', *ary
|
40
|
+
end
|
41
|
+
end
|
data/lib/git_dump/cmd.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
require 'English'
|
3
|
+
|
4
|
+
class GitDump
|
5
|
+
# Running commands using system and popen
|
6
|
+
class Cmd
|
7
|
+
# Non succesfull exit code
|
8
|
+
class Failure < StandardError; end
|
9
|
+
|
10
|
+
# Run git command
|
11
|
+
def self.git(*args)
|
12
|
+
new(:git, *args)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Command arguments
|
16
|
+
attr_reader :args
|
17
|
+
|
18
|
+
# Environment variables to set for command
|
19
|
+
attr_reader :env
|
20
|
+
|
21
|
+
# Working dir for running command
|
22
|
+
attr_reader :chdir
|
23
|
+
|
24
|
+
# Pipe /dev/null to stdin
|
25
|
+
attr_reader :no_stdin
|
26
|
+
|
27
|
+
# Redirect stdout to /dev/null
|
28
|
+
attr_reader :no_stdout
|
29
|
+
|
30
|
+
# Redirect stderr to /dev/null
|
31
|
+
attr_reader :no_stderr
|
32
|
+
|
33
|
+
# Construct command, last argument can be a hash of options with keys:
|
34
|
+
# :env - hash of environment varibles
|
35
|
+
# :chdir - working dir for running command
|
36
|
+
# :no_stdin - pipe /dev/null to stdin
|
37
|
+
# :no_stdout - redirect stdout to /dev/null
|
38
|
+
# :no_stderr - redirect stderr to /dev/null
|
39
|
+
def initialize(*args)
|
40
|
+
args = args.dup
|
41
|
+
options = args.pop if args.last.is_a?(Hash)
|
42
|
+
@args = args.map(&:to_s)
|
43
|
+
|
44
|
+
parse_options(options) if options
|
45
|
+
end
|
46
|
+
|
47
|
+
# Construct command string
|
48
|
+
def to_s
|
49
|
+
cmd = args.shelljoin
|
50
|
+
if env
|
51
|
+
env_str = env.map{ |k, v| "#{k}=#{v}" }.shelljoin
|
52
|
+
cmd = "export #{env_str}; #{cmd}"
|
53
|
+
end
|
54
|
+
cmd = "cd #{chdir}; #{cmd}" if chdir
|
55
|
+
cmd << ' < /dev/null' if no_stdin
|
56
|
+
cmd << ' > /dev/null' if no_stdout
|
57
|
+
cmd << ' 2> /dev/null' if no_stderr
|
58
|
+
cmd
|
59
|
+
end
|
60
|
+
|
61
|
+
# Run using system
|
62
|
+
def run
|
63
|
+
success = system(*arguments)
|
64
|
+
return true if success
|
65
|
+
fail Failure, "`#{self}` failed with #{$CHILD_STATUS.exitstatus}"
|
66
|
+
end
|
67
|
+
|
68
|
+
# Run using popen
|
69
|
+
def popen(mode = 'r', &block)
|
70
|
+
if block
|
71
|
+
result = IO.popen(arguments, mode, &block)
|
72
|
+
return result if $CHILD_STATUS.success?
|
73
|
+
fail Failure, "`#{self}` failed with #{$CHILD_STATUS.exitstatus}"
|
74
|
+
else
|
75
|
+
IO.popen(arguments, mode)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Capture output
|
80
|
+
def capture
|
81
|
+
popen(&:read)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Captured lines
|
85
|
+
def stripped_lines
|
86
|
+
capture.split(/[\n\r]+/)
|
87
|
+
end
|
88
|
+
|
89
|
+
def inspect
|
90
|
+
"#<#{self.class} #{self}>"
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# Parse options hash, fail on unknown options
|
96
|
+
def parse_options(options)
|
97
|
+
@env = options.delete(:env).to_hash if options.key?(:env)
|
98
|
+
@chdir = options.delete(:chdir).to_s if options.key?(:chdir)
|
99
|
+
@no_stdin = !!options.delete(:no_stdin) if options.key?(:no_stdin)
|
100
|
+
@no_stdout = !!options.delete(:no_stdout) if options.key?(:no_stdout)
|
101
|
+
@no_stderr = !!options.delete(:no_stderr) if options.key?(:no_stderr)
|
102
|
+
|
103
|
+
fail "Unknown options: #{options.inspect}" unless options.empty?
|
104
|
+
end
|
105
|
+
|
106
|
+
# For ruby < 1.9 and jruby use to_s, otherwise return args with env hash
|
107
|
+
# prepanded and options hash appended
|
108
|
+
def arguments
|
109
|
+
return to_s if RUBY_VERSION < '1.9' || defined?(JRUBY_VERSION)
|
110
|
+
options = {}
|
111
|
+
options[:chdir] = chdir if chdir
|
112
|
+
options[:in] = '/dev/null' if no_stdin
|
113
|
+
options[:out] = '/dev/null' if no_stdout
|
114
|
+
options[:err] = '/dev/null' if no_stderr
|
115
|
+
[env || {}] + args + [options]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'git_dump/path_object'
|
2
|
+
|
3
|
+
class GitDump
|
4
|
+
# Entry at path
|
5
|
+
class Entry < PathObject
|
6
|
+
attr_reader :sha, :mode
|
7
|
+
def initialize(repo, dir, name, sha, mode)
|
8
|
+
super(repo, dir, name)
|
9
|
+
@sha, @mode = sha, (mode & 0100) == 0 ? 0644 : 0755
|
10
|
+
end
|
11
|
+
|
12
|
+
# Pipe for reading data
|
13
|
+
def open(&block)
|
14
|
+
repo.blob_pipe(sha, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Data
|
18
|
+
def read
|
19
|
+
repo.blob_read(sha)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Write to path
|
23
|
+
def write_to(path)
|
24
|
+
repo.blob_unpack(sha, path, mode)
|
25
|
+
end
|
26
|
+
|
27
|
+
def inspect
|
28
|
+
"#<#{self.class} sha=#{@sha} mode=#{format '%03o', @mode}>"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|