git_dump 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,14 @@
1
+ /pkg/
2
+ /*.gem
3
+
4
+ /doc/
5
+ /rdoc/
6
+ /.yardoc/
7
+ /coverage/
8
+
9
+ Makefile
10
+ *.o
11
+ *.bundle
12
+ /tmp/
13
+
14
+ /Gemfile.lock
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
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rugged' if ENV['RUGGED'] == '1'
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
@@ -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