git_dump 0.1.0

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.
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