multi_git 0.0.1.alpha2 → 0.0.1.beta1

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8a8d438d8d1f815345a1c5cc77b3ce2b7689435d
4
+ data.tar.gz: 77b256666dcca0c97155d6e540104bc653a3b319
5
+ SHA512:
6
+ metadata.gz: 7c075d5f6b65bc3f9ae092b617555db1870a01dd555a5b52375641208aaf87d14ba8f3889770c042763ec2d194c3d9ad405874bd24c39d808750744032c7cffb
7
+ data.tar.gz: 65134503f98f6fb7acea989182ea69fa9fde0d32c9396380f0b6b7cbb660ceddcf7fb62367ca594f7ce4450639fc4a4146b43b5efe18bcc12ff55aaa2d76bd66
@@ -0,0 +1,26 @@
1
+ require 'multi_git/config/schema'
2
+ module MultiGit
3
+ module Config
4
+
5
+ DEFAULT_SCHEMA = \
6
+ Schema.build do
7
+
8
+ section 'core' do
9
+ bool 'bare', false
10
+ bool 'filemode', true
11
+ bool 'logallrefupdates', false
12
+ int 'repositoryformatversion', 0
13
+ end
14
+
15
+ section 'remote' do
16
+ any_section do
17
+ array 'url'
18
+ array 'pushurl'
19
+ string 'fetch'
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,141 @@
1
+ require 'forwardable'
2
+ module MultiGit; module Config
3
+
4
+ class Schema
5
+
6
+ attr :default
7
+
8
+ def initialize(default = nil)
9
+ @default = default
10
+ end
11
+
12
+ def list?
13
+ false
14
+ end
15
+
16
+ def convert( plain_value )
17
+ plain_value
18
+ end
19
+
20
+ def unconvert( complex_value )
21
+ complex_value.to_s
22
+ end
23
+
24
+ NULL = self.new
25
+
26
+ class String < self
27
+ end
28
+
29
+ class Integer < self
30
+ def convert( plain_value )
31
+ plain_value.to_i
32
+ end
33
+ end
34
+
35
+ class Array < self
36
+ def list?
37
+ true
38
+ end
39
+ def unconvert( complex_value )
40
+ complex_value.map(&:to_s)
41
+ end
42
+ end
43
+
44
+ class Boolean < self
45
+ CONVERSIONS = {
46
+ 'true' => true,
47
+ 'yes' => true,
48
+ '1' => true,
49
+ 'false' => false,
50
+ 'no' => false,
51
+ '0' => false
52
+ }
53
+ CONVERSIONS.default = true
54
+ def convert( plain_value )
55
+ CONVERSIONS[plain_value]
56
+ end
57
+ end
58
+
59
+ class Root
60
+
61
+ def initialize(hash = Hash.new(Hash.new(Hash.new(NULL))) )
62
+ @hash = hash
63
+ end
64
+
65
+ def schema
66
+ @hash
67
+ end
68
+
69
+ def section(key, &block)
70
+ sec = Section.new(@hash.fetch(key){ @hash[key] = Hash.new(Hash.new(NULL))})
71
+ sec.instance_eval(&block) if block_given?
72
+ return sec
73
+ end
74
+
75
+ end
76
+
77
+ class Section
78
+
79
+ extend Forwardable
80
+
81
+ def initialize(hash)
82
+ @hash = hash
83
+ end
84
+
85
+ def section(key, &block)
86
+ sec = Subsection.new(@hash.fetch(key){ @hash[key] = Hash.new(NULL)})
87
+ sec.instance_eval(&block) if block_given?
88
+ return sec
89
+ end
90
+
91
+ def nil_section
92
+ section(nil)
93
+ end
94
+
95
+ def any_section(&block)
96
+ sec = Subsection.new(@hash.default)
97
+ sec.instance_eval(&block) if block_given?
98
+ return sec
99
+ end
100
+
101
+ delegate [:integer, :string, :array, :bool] => :nil_section
102
+
103
+ alias int integer
104
+
105
+ end
106
+
107
+ class Subsection
108
+
109
+ def initialize(hash)
110
+ @hash = hash
111
+ end
112
+
113
+ def integer(name, default = nil)
114
+ @hash[name] = Integer.new(default)
115
+ end
116
+
117
+ def string(name, default = nil)
118
+ @hash[name] = String.new(default)
119
+ end
120
+
121
+ def array(name, default = [])
122
+ @hash[name] = Array.new(default)
123
+ end
124
+
125
+ def bool(name, default = nil)
126
+ @hash[name] = Boolean.new(default)
127
+ end
128
+
129
+ alias int integer
130
+
131
+ end
132
+
133
+ def self.build(&block)
134
+ ro = Root.new
135
+ ro.instance_eval(&block)
136
+ return ro.schema
137
+ end
138
+
139
+ end
140
+
141
+ end; end
@@ -0,0 +1,170 @@
1
+ require 'multi_git/utils'
2
+ require 'multi_git/config/default_schema'
3
+ module MultiGit
4
+ module Config
5
+
6
+ class Section
7
+
8
+ include Enumerable
9
+
10
+ attr :section, :subsection
11
+ attr :schema
12
+
13
+ def initialize(config, section, subsection)
14
+ @config = config
15
+ @section = section
16
+ @subsection = subsection
17
+ @schema = config.schema[section][subsection]
18
+ end
19
+
20
+ def schema_for( key )
21
+ schema[key]
22
+ end
23
+
24
+ def default?( key )
25
+ config.get(section, subsection, key) == schema_for(key).default
26
+ end
27
+
28
+ def [](key)
29
+ config.get(section, subsection, key)
30
+ end
31
+
32
+ alias get []
33
+
34
+ def each_explicit_key
35
+ return to_enum(:each_explicit_key) unless block_given?
36
+ config.each_explicit_key do |sec, subsec, key|
37
+ yield(key) if sec == section && subsec == subsection
38
+ end
39
+ end
40
+
41
+ # Expensive. Use only for debug
42
+ def each
43
+ return to_enum unless block_given?
44
+ each_explicit_key do |key|
45
+ next if default?(key)
46
+ yield key, get(key)
47
+ end
48
+ end
49
+
50
+ # Expensive. Use only for debug.
51
+ def to_h
52
+ Hash[each.to_a]
53
+ end
54
+
55
+ # :nocov:
56
+ # @visibility private
57
+ def inspect
58
+ ["{config #{section} \"#{subsection}\"", *each.map{|key, value| " "+qualified_key(*key)+" => "+value.inspect },'}'].join("\n")
59
+ end
60
+ # :nocov:
61
+
62
+ protected
63
+
64
+ attr :config
65
+
66
+ end
67
+
68
+ extend Utils::AbstractMethods
69
+ include Enumerable
70
+
71
+ def schema
72
+ @schema ||= DEFAULT_SCHEMA
73
+ end
74
+
75
+ def schema_for( section, subsection, key )
76
+ schema[section][subsection][key]
77
+ end
78
+
79
+ def default?( section, subsection, key )
80
+ get(section, subsection, key) == schema_for(section, subsection, key).default
81
+ end
82
+
83
+ # @overload []( section, subsection = nil, key )
84
+ # @param section [String]
85
+ # @param subsection [String, nil]
86
+ # @param key [String]
87
+ # @return value
88
+ #
89
+ # @overload []( qualified_key )
90
+ # @param qualified_key [String] the fully-qualified key, seperated by dots
91
+ # @return value
92
+ #
93
+ def []( *args )
94
+ case( args.size )
95
+ when 3 then get( *args )
96
+ when 2 then get( args[0], nil, args[1] )
97
+ when 1 then
98
+ get( *split_key(args[0]) )
99
+ else
100
+ raise ArgumentError,
101
+ "wrong number of arguments (#{args.size} for 1..3)"
102
+ end
103
+ end
104
+
105
+ # @!method get( section, subsection, key)
106
+ # @api private
107
+ abstract :get
108
+
109
+ # @!method each_explicit_key
110
+ # @yield [section, subsection, key]
111
+ abstract :each_explicit_key
112
+
113
+ #
114
+ # @param section [String]
115
+ # @param subsection [String, nil]
116
+ # @return [Section]
117
+ def section(section, subsection = nil)
118
+ Section.new(self, section, subsection)
119
+ end
120
+
121
+ # @visibility private
122
+ DOT = '.'
123
+
124
+ def qualified_key( section, subsection = nil, key )
125
+ [section, DOT, subsection, subsection ? DOT : nil, key].join
126
+ end
127
+
128
+ def split_key( qualified_key )
129
+ split = qualified_key.split(DOT)
130
+ case(split.size)
131
+ when 2 then [ split[0], nil, split[1] ]
132
+ when 3 then split
133
+ else
134
+ raise ArgumentError, "Expected the qualified key to be formatted as 'section[.subsection].key' got #{qualified_key}"
135
+ end
136
+ end
137
+
138
+ # Expensive. Use only for debug
139
+ def each
140
+ return to_enum unless block_given?
141
+ each_explicit_key do |*key|
142
+ next if default?(*key)
143
+ yield key, get(*key)
144
+ end
145
+ end
146
+
147
+ # Expensive. Use only for debug.
148
+ def to_h
149
+ Hash[each.to_a]
150
+ end
151
+
152
+ # :nocov:
153
+ # @visibility private
154
+ def inspect
155
+ ['{config', *each.map{|key, value| " "+qualified_key(*key)+" => "+value.inspect },'}'].join("\n")
156
+ end
157
+ # :nocov:
158
+
159
+ # Dups the object with a different schema
160
+ # @api private
161
+ def with_schema(sch)
162
+ d = dup
163
+ d.instance_eval do
164
+ @schema = sch
165
+ end
166
+ return d
167
+ end
168
+
169
+ end
170
+ end
@@ -66,6 +66,10 @@ If this happens frequently, you may have want to run "git gc" to remove clobber.
66
66
  end
67
67
  end
68
68
 
69
+ class DuplicateConfigKey < Exception
70
+ include Error
71
+ end
72
+
69
73
  end
70
74
 
71
75
  end
@@ -20,9 +20,14 @@ module MultiGit::GitBackend
20
20
  end
21
21
  end
22
22
 
23
- def initialize(command, options = {})
24
- @cmd = command
25
- @opts = options
23
+ def initialize(*args)
24
+ if args.first.kind_of? Hash
25
+ @env = args.shift
26
+ else
27
+ @env = {}
28
+ end
29
+ @cmd = args.shift
30
+ @opts = args.any? ? args.shift.dup : {}
26
31
  end
27
32
 
28
33
  READ_BLOCK = lambda{|io|
@@ -34,7 +39,7 @@ module MultiGit::GitBackend
34
39
  block ||= READ_BLOCK
35
40
  result = nil
36
41
  message = nil
37
- status = popen_foo(env, s.join(' ')) do | stdin, stdout, stderr |
42
+ status = popen_foo(@env.merge(env), s.join(' ')) do | stdin, stdout, stderr |
38
43
  if block.arity == 1
39
44
  stdin.close
40
45
  result = block.call(stdout)
@@ -66,7 +66,7 @@ module MultiGit
66
66
 
67
67
  def parse_signature(content)
68
68
  match = SIGNATURE_RX.match(content)
69
- return MultiGit::Handle.new(match[1],match[2]), Time.at(match[3].to_i).localtime(match[4]+':'+match[5])
69
+ return MultiGit::Handle.new(match[1],match[2]), Time.at(match[3].to_i).getlocal(match[4]+':'+match[5])
70
70
  end
71
71
 
72
72
  end
@@ -0,0 +1,47 @@
1
+ require 'forwardable'
2
+ require 'set'
3
+ require 'multi_git/config'
4
+ module MultiGit
5
+ module GitBackend
6
+ class Config
7
+
8
+ include MultiGit::Config
9
+
10
+ def initialize(cmd)
11
+ @cmd = cmd
12
+ end
13
+
14
+ def get( section, subsection, key )
15
+ s = schema_for(section, subsection, key)
16
+ begin
17
+ # git < 1.8.0 barfs when using --get on a multiply defined
18
+ # value, but uses the last value internally.
19
+ # git >= 1.8.0 simply returns the last value
20
+ value = @cmd['config', '--get-all', qualified_key(section, subsection, key)].lines.map(&:chomp)
21
+ value = value.last unless s.list?
22
+ return s.convert(value)
23
+ rescue Cmd::Error::ExitCode1
24
+ return s.default
25
+ rescue Cmd::Error::ExitCode2
26
+ raise Error::DuplicateConfigKey, qualified_key(section, subsection, key)
27
+ end
28
+ end
29
+
30
+ def each_explicit_key
31
+ return to_enum(:each_explicit_key) unless block_given?
32
+ seen = Set.new
33
+ @cmd.('config','--list') do |io|
34
+ io.each_line do |line|
35
+ name, _ = line.split('=',2)
36
+ next if seen.include? name
37
+ seen << name
38
+ yield *split_key(name)
39
+ end
40
+ end
41
+ return self
42
+ end
43
+
44
+
45
+ end
46
+ end
47
+ end
@@ -15,19 +15,20 @@ module MultiGit
15
15
 
16
16
  private
17
17
 
18
- SHOW_REF_LINE = /\A(\h{40}) ([^\n]+)\Z/.freeze
18
+ SYMBOLIC_REF_LINE = /\Aref: ([a-z0-9_]+(?:\/[a-z0-9_]+)*)\Z/i.freeze
19
+ OID_REF_LINE = /\A(\h{40})\Z/i.freeze
19
20
 
20
21
  def read!
21
22
  begin
22
- if symbolic?
23
- content = repository.__backend__['symbolic-ref', name]
24
- @target = repository.ref(content.chomp)
23
+ content = IO.read(::File.join(repository.git_dir,name))
24
+ if content =~ SYMBOLIC_REF_LINE
25
+ @target = repository.ref($1)
26
+ elsif content =~ OID_REF_LINE
27
+ @target = repository.read($1)
25
28
  else
26
- lines = repository.__backend__['show-ref', name].lines
27
- match = SHOW_REF_LINE.match(lines.first)
28
- @target = repository.read(match[1])
29
+ raise content.inspect
29
30
  end
30
- rescue Cmd::Error::ExitCode1
31
+ rescue Errno::ENOENT
31
32
  # doesn't exists
32
33
  end
33
34
  end
@@ -0,0 +1,47 @@
1
+ require 'multi_git/remote'
2
+ module MultiGit
3
+ module GitBackend
4
+ class Remote
5
+ include MultiGit::Remote
6
+
7
+ attr :repository
8
+
9
+ class Persistent < self
10
+ include MultiGit::Remote::Persistent
11
+
12
+ attr :repository
13
+ attr :name
14
+
15
+ def initialize( repo, name )
16
+ @name = name
17
+ @repository = repo
18
+ end
19
+
20
+ def fetch_urls
21
+ return repository.config['remote',name,'url']
22
+ end
23
+
24
+ def push_urls
25
+ pu = repository.config['remote',name,'pushurl']
26
+ return pu.any? ? pu : fetch_urls
27
+ end
28
+
29
+ end
30
+
31
+ attr :fetch_urls
32
+ attr :push_urls
33
+
34
+ def initialize( repo, url, push_url = url )
35
+ @repository = repo
36
+ @fetch_urls = Array(url)
37
+ @push_urls = Array(push_url)
38
+ end
39
+
40
+ def fetch(*refspecs)
41
+ rs = parse_fetch_refspec(*refspecs)
42
+ repository.__backend__['fetch',fetch_urls.first,*rs.map(&:to_s)]
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -6,6 +6,8 @@ require 'multi_git/git_backend/blob'
6
6
  require 'multi_git/git_backend/tree'
7
7
  require 'multi_git/git_backend/commit'
8
8
  require 'multi_git/git_backend/ref'
9
+ require 'multi_git/git_backend/config'
10
+ require 'multi_git/git_backend/remote'
9
11
  module MultiGit::GitBackend
10
12
 
11
13
  class Repository < MultiGit::Repository
@@ -35,7 +37,7 @@ module MultiGit::GitBackend
35
37
  @git_binary = `which git`.chomp
36
38
  options = initialize_options(path, options)
37
39
  git_dir = options[:repository]
38
- @git = Cmd.new(git_binary, :git_dir => git_dir )
40
+ @git = Cmd.new({'GIT_CONFIG_NOSYSTEM'=>'1'}, git_binary, :git_dir => git_dir )
39
41
  if !::File.exists?(git_dir) || MultiGit::Utils.empty_dir?(git_dir)
40
42
  if options[:init]
41
43
  if options[:bare]
@@ -130,6 +132,19 @@ module MultiGit::GitBackend
130
132
  MultiGit::GitBackend::Ref.new(self, name)
131
133
  end
132
134
 
135
+ def config
136
+ @config ||= Config.new(@git)
137
+ end
138
+
139
+ def remote( name_or_url )
140
+ if looks_like_remote_url? name_or_url
141
+ remote = Remote.new(self, name_or_url)
142
+ else
143
+ remote = Remote::Persistent.new(self, name_or_url)
144
+ end
145
+ return remote
146
+ end
147
+
133
148
  private
134
149
  TRUE_LAMBDA = proc{ true }
135
150
  public
@@ -0,0 +1,52 @@
1
+ require 'multi_git/config'
2
+ module MultiGit
3
+ module JGitBackend
4
+ class Config
5
+
6
+ include MultiGit::Config
7
+
8
+ def initialize(java_config)
9
+ @java_config = java_config
10
+ end
11
+
12
+ def get(section, subsection, name)
13
+ s = schema_for(section, subsection, name)
14
+ if s.list?
15
+ value = java_config.getStringList(section, subsection, name).to_a
16
+ if value.any?
17
+ return s.convert(value)
18
+ else
19
+ return s.default
20
+ end
21
+ else
22
+ value = java_config.getString(section, subsection, name)
23
+ if value.nil?
24
+ return s.default
25
+ else
26
+ return s.convert( value )
27
+ end
28
+ end
29
+ end
30
+
31
+ def each_explicit_key
32
+ return to_enum(:each_explicit_key) unless block_given?
33
+ java_config.sections.map do |sec|
34
+ java_config.getNames(sec.to_java, nil.to_java).each do |name|
35
+ yield sec, nil, name
36
+ end
37
+ java_config.getSubsections(sec.to_java).each do |subsec|
38
+ java_config.getNames(sec.to_java, subsec.to_java).each do |name|
39
+ yield sec, subsec, name
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ attr :java_config
46
+
47
+ alias to_java java_config
48
+
49
+ end
50
+ end
51
+ end
52
+
@@ -0,0 +1,74 @@
1
+ require 'multi_git/remote'
2
+ module MultiGit
3
+ module JGitBackend
4
+ class Remote
5
+
6
+ include MultiGit::Remote
7
+
8
+ attr :repository
9
+
10
+ class Persistent < self
11
+
12
+ include MultiGit::Remote::Persistent
13
+
14
+ def initialize( repository, name )
15
+ @repository = repository
16
+ @java_config = Java::OrgEclipseJgitTransport::RemoteConfig.new(repository.config.to_java, name)
17
+ end
18
+
19
+ def name
20
+ java_config.getName
21
+ end
22
+
23
+ end
24
+
25
+ REMOTE_SECTION = 'remote'.to_java
26
+ TEMPORARY_SECTION = 'tmp'.to_java
27
+ FETCH_URL_KEY = 'url'.to_java
28
+ PUSH_URL_KEY = 'pushurl'.to_java
29
+
30
+ FETCH = Java::OrgEclipseJgitTransport::Transport::Operation::FETCH
31
+ PUSH = Java::OrgEclipseJgitTransport::Transport::Operation::PUSH
32
+
33
+ def initialize( repository, url, push_url = url )
34
+ @repository = repository
35
+ conf = Java::OrgEclipseJgitLib::Config.new
36
+ conf.setStringList(REMOTE_SECTION, TEMPORARY_SECTION, FETCH_URL_KEY, Array(url))
37
+ conf.setStringList(REMOTE_SECTION, TEMPORARY_SECTION, PUSH_URL_KEY, Array(push_url))
38
+ @java_config = Java::OrgEclipseJgitTransport::RemoteConfig.new(conf, TEMPORARY_SECTION)
39
+ end
40
+
41
+ def fetch_urls
42
+ java_config.getURIs.map(&:to_s)
43
+ end
44
+
45
+ def push_urls
46
+ pu = java_config.getPushURIs.map(&:to_s)
47
+ pu.any? ? pu : fetch_urls
48
+ end
49
+
50
+ def fetch( *refspecs )
51
+ rs = parse_fetch_refspec(*refspecs).map{|refspec| Java::OrgEclipseJgitTransport::RefSpec.new(refspec.to_s) }
52
+ use_transport( FETCH ) do | transport |
53
+ transport.fetch( transport_monitor, rs )
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ attr :java_config
60
+
61
+ def use_transport( op )
62
+ tr = Java::OrgEclipseJgitTransport::Transport.open(repository.__backend__, java_config, op)
63
+ yield tr
64
+ ensure
65
+ tr.close
66
+ end
67
+
68
+ def transport_monitor
69
+ Java::OrgEclipseJgitLib::NullProgressMonitor::INSTANCE
70
+ end
71
+
72
+ end
73
+ end
74
+ end