multi_git 0.0.1.alpha2 → 0.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
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