jbox-gitolite 1.2.0 → 1.2.1
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 +4 -4
- data/.gitignore +7 -7
- data/Guardfile +2 -2
- data/README.md +3 -2
- data/Rakefile +26 -8
- data/gitolite.gemspec +3 -3
- data/lib/gitolite.rb +5 -2
- data/lib/gitolite/config.rb +181 -152
- data/lib/gitolite/config/group.rb +11 -0
- data/lib/gitolite/config/repo.rb +22 -9
- data/lib/gitolite/dirty_proxy.rb +3 -0
- data/lib/gitolite/gitolite_admin.rb +0 -2
- data/lib/gitolite/ssh_key.rb +52 -38
- data/lib/gitolite/version.rb +1 -1
- data/spec/config_spec.rb +18 -11
- data/spec/dirty_proxy_spec.rb +4 -1
- data/spec/fixtures/configs/complicated.conf +311 -0
- data/spec/fixtures/configs/simple.conf +5 -0
- data/spec/{keys/bob-ins@zilla-site.com@desktop.pub → fixtures/keys/bob+joe@test.zilla.com@desktop.pub} +0 -0
- data/spec/{keys/bob.joe@test.zilla.com@desktop.pub → fixtures/keys/bob-ins@zilla-site.com@desktop.pub} +0 -0
- data/spec/{keys/bob@zilla.com@desktop.pub → fixtures/keys/bob.joe@test.zilla.com@desktop.pub} +0 -0
- data/spec/{keys → fixtures/keys}/bob.pub +0 -0
- data/spec/{keys → fixtures/keys}/bob@desktop.pub +0 -0
- data/spec/{keys → fixtures/keys}/bob@foo-bar.pub +0 -0
- data/spec/{keys → fixtures/keys}/bob@zilla.com.pub +0 -0
- data/spec/{keys/joe-bob@god-zilla.com@desktop.pub → fixtures/keys/bob@zilla.com@desktop.pub} +0 -0
- data/spec/{keys → fixtures/keys}/jakub123.pub +0 -0
- data/spec/{keys → fixtures/keys}/jakub123@foo.net.pub +0 -0
- data/spec/fixtures/keys/joe-bob@god-zilla.com@desktop.pub +1 -0
- data/spec/{keys → fixtures/keys}/joe@sch.ool.edu.pub +0 -0
- data/spec/{keys → fixtures/keys}/joe@sch.ool.edu@desktop.pub +0 -0
- data/spec/gitolite_admin_spec.rb +6 -8
- data/spec/group_spec.rb +0 -1
- data/spec/repo_spec.rb +0 -1
- data/spec/spec_helper.rb +2 -2
- data/spec/ssh_key_spec.rb +15 -10
- metadata +39 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8242365723c05acd430cfdaa34f8f18e201fe860
|
4
|
+
data.tar.gz: 767660c5aa70ce7f4a3a8df74164ec667af0f289
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a79d5689bede554598122604aacc28d7740cc9de1d13c4e7c8a9c3def8ade3363b7f401a172f6b71b573e62a86733cfbf6c9bfc8f88f16e2355b55f4d611dc8b
|
7
|
+
data.tar.gz: 3ae1bf550e36a15a22302d25b84af0dfb963506bfcf55bc0d02cf6623e3139e552666bcffd335d8fc4f77b9b9f8b3bb0e6e22e6cd30ddd9dbd8adb77f218c22c
|
data/.gitignore
CHANGED
data/Guardfile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# More info at https://github.com/guard/guard#readme
|
2
2
|
|
3
|
-
guard
|
3
|
+
guard :rspec, :cmd => "bundle exec rspec --color --format nested --fail-fast" do
|
4
4
|
watch(%r{^spec/.+_spec\.rb$})
|
5
5
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
6
6
|
watch('spec/spec_helper.rb') { "spec" }
|
7
7
|
end
|
8
8
|
|
9
|
-
guard
|
9
|
+
guard :spork, :rspec_env => { 'RAILS_ENV' => 'test' }, :rspec_port => 9090 do
|
10
10
|
watch(%r{^lib/(.+)\.rb$})
|
11
11
|
watch('Gemfile.lock')
|
12
12
|
watch('spec/spec_helper.rb') { :rspec }
|
data/README.md
CHANGED
@@ -15,8 +15,9 @@ You can follow announcements [here](https://github.com/jbox-web/gitolite/wiki/An
|
|
15
15
|
## Code status
|
16
16
|
|
17
17
|
* [](http://badge.fury.io/rb/jbox-gitolite)
|
18
|
-
* [](https://travis-ci.org/jbox-web/gitolite)
|
19
19
|
* [](https://codeclimate.com/github/jbox-web/gitolite)
|
20
|
+
* [](https://gemnasium.com/jbox-web/gitolite)
|
20
21
|
|
21
22
|
## Requirements ##
|
22
23
|
* Ruby 1.9.x or 2.0.x
|
@@ -32,7 +33,7 @@ Read the documentation and more in the [Wiki](https://github.com/jbox-web/gitoli
|
|
32
33
|
## Copyrights & License
|
33
34
|
gitolite is completely free and open source and released under the [MIT License](https://github.com/jbox-web/gitolite/blob/devel/LICENSE.txt).
|
34
35
|
|
35
|
-
Copyright (c) 2013-2014 Nicolas Rodriguez (nrodriguez@jbox-web.com), JBox Web (http://www.jbox-web.com)
|
36
|
+
Copyright (c) 2013-2014 Nicolas Rodriguez (nrodriguez@jbox-web.com), JBox Web (http://www.jbox-web.com) [](https://coderwall.com/n-rodriguez)
|
36
37
|
|
37
38
|
Copyright (c) 2011-2013 Stafford Brunk (stafford.brunk@gmail.com)
|
38
39
|
|
data/Rakefile
CHANGED
@@ -5,24 +5,20 @@ require 'rake'
|
|
5
5
|
require 'rspec/core/rake_task'
|
6
6
|
require 'rdoc/task'
|
7
7
|
|
8
|
-
|
8
|
+
|
9
|
+
## Helper Functions
|
9
10
|
def name
|
10
11
|
@name ||= Dir['*.gemspec'].first.split('.').first
|
11
12
|
end
|
12
13
|
|
14
|
+
|
13
15
|
def version
|
14
16
|
line = File.read("lib/#{name}/version.rb")[/^\s*VERSION\s*=\s*.*/]
|
15
17
|
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
16
18
|
end
|
17
19
|
|
18
|
-
# Standard tasks
|
19
|
-
RSpec::Core::RakeTask.new(:spec) do |config|
|
20
|
-
config.rspec_opts = "--color --format nested --fail-fast"
|
21
|
-
end
|
22
|
-
|
23
|
-
task :default => :spec
|
24
|
-
task :test => :spec
|
25
20
|
|
21
|
+
## RDoc Task
|
26
22
|
Rake::RDocTask.new do |rdoc|
|
27
23
|
rdoc.rdoc_dir = 'rdoc'
|
28
24
|
rdoc.title = "#{name} #{version}"
|
@@ -30,12 +26,34 @@ Rake::RDocTask.new do |rdoc|
|
|
30
26
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
31
27
|
end
|
32
28
|
|
29
|
+
|
30
|
+
## Other Tasks
|
33
31
|
desc "Open an irb session preloaded with this library"
|
34
32
|
task :console do
|
35
33
|
sh "irb -rubygems -r ./lib/#{name}.rb"
|
36
34
|
end
|
37
35
|
|
36
|
+
|
38
37
|
desc "Show library version"
|
39
38
|
task :version do
|
40
39
|
puts "#{name} #{version}"
|
41
40
|
end
|
41
|
+
|
42
|
+
|
43
|
+
desc "Start unit tests"
|
44
|
+
task :test => :default
|
45
|
+
task :default do
|
46
|
+
RSpec::Core::RakeTask.new(:spec) do |config|
|
47
|
+
config.rspec_opts = "--color --format nested --fail-fast"
|
48
|
+
end
|
49
|
+
Rake::Task["spec"].invoke
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
desc "Start unit tests in JUnit format"
|
54
|
+
task :test_junit do
|
55
|
+
RSpec::Core::RakeTask.new(:spec) do |config|
|
56
|
+
config.rspec_opts = "--format RspecJunitFormatter --out junit/rspec.xml"
|
57
|
+
end
|
58
|
+
Rake::Task["spec"].invoke
|
59
|
+
end
|
data/gitolite.gemspec
CHANGED
@@ -18,9 +18,9 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.add_development_dependency "rake", "~> 10.3.1"
|
19
19
|
s.add_development_dependency "rdoc", "~> 4.1.1"
|
20
20
|
s.add_development_dependency "rspec", "~> 2.14.1"
|
21
|
-
s.add_development_dependency "guard-rspec", "~> 2.
|
21
|
+
s.add_development_dependency "guard-rspec", "~> 4.2.8"
|
22
22
|
s.add_development_dependency "guard-spork", "~> 1.5.1"
|
23
|
-
s.add_development_dependency "forgery", "~> 0.
|
23
|
+
s.add_development_dependency "forgery", "~> 0.6.0"
|
24
24
|
s.add_development_dependency "travis-lint", "~> 1.8.0"
|
25
25
|
|
26
26
|
s.add_development_dependency "simplecov", "~> 0.8.2"
|
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.add_development_dependency "rspec_junit_formatter", "~> 0.1.6"
|
30
30
|
|
31
31
|
s.add_dependency "gitlab-grit", "~> 2.6.5"
|
32
|
-
s.add_dependency "
|
32
|
+
s.add_dependency "plexus", "~> 0.5.10"
|
33
33
|
|
34
34
|
s.files = `git ls-files`.split("\n")
|
35
35
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/lib/gitolite.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
module Gitolite
|
2
2
|
require 'grit'
|
3
|
-
require '
|
3
|
+
require 'plexus'
|
4
|
+
require 'gitolite/gitolite_admin'
|
5
|
+
require 'gitolite/dirty_proxy'
|
4
6
|
require 'gitolite/ssh_key'
|
5
7
|
require 'gitolite/config'
|
6
|
-
require 'gitolite/
|
8
|
+
require 'gitolite/config/repo'
|
9
|
+
require 'gitolite/config/group'
|
7
10
|
end
|
data/lib/gitolite/config.rb
CHANGED
@@ -1,17 +1,10 @@
|
|
1
1
|
require 'tempfile'
|
2
|
-
require File.join(File.dirname(__FILE__), 'config', 'repo')
|
3
|
-
require File.join(File.dirname(__FILE__), 'config', 'group')
|
4
2
|
|
5
3
|
module Gitolite
|
4
|
+
|
6
5
|
class Config
|
7
|
-
attr_accessor :repos, :groups, :filename
|
8
6
|
|
9
|
-
|
10
|
-
@repos = {}
|
11
|
-
@groups = {}
|
12
|
-
@filename = File.basename(config)
|
13
|
-
process_config(config)
|
14
|
-
end
|
7
|
+
attr_accessor :repos, :groups, :filename
|
15
8
|
|
16
9
|
def self.init(filename = "gitolite.conf")
|
17
10
|
file = Tempfile.new(filename)
|
@@ -21,47 +14,64 @@ module Gitolite
|
|
21
14
|
conf
|
22
15
|
end
|
23
16
|
|
24
|
-
|
17
|
+
|
18
|
+
def initialize(config)
|
19
|
+
@repos = {}
|
20
|
+
@groups = {}
|
21
|
+
@filename = File.basename(config)
|
22
|
+
process_config(config)
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# TODO: merge repo unless overwrite = true
|
25
27
|
def add_repo(repo, overwrite = false)
|
26
28
|
raise ArgumentError, "Repo must be of type Gitolite::Config::Repo!" unless repo.instance_of? Gitolite::Config::Repo
|
27
29
|
@repos[repo.name] = repo
|
28
30
|
end
|
29
31
|
|
32
|
+
|
30
33
|
def rm_repo(repo)
|
31
34
|
name = normalize_repo_name(repo)
|
32
35
|
@repos.delete(name)
|
33
36
|
end
|
34
37
|
|
38
|
+
|
35
39
|
def has_repo?(repo)
|
36
40
|
name = normalize_repo_name(repo)
|
37
41
|
@repos.has_key?(name)
|
38
42
|
end
|
39
43
|
|
44
|
+
|
40
45
|
def get_repo(repo)
|
41
46
|
name = normalize_repo_name(repo)
|
42
47
|
@repos[name]
|
43
48
|
end
|
44
49
|
|
50
|
+
|
45
51
|
def add_group(group, overwrite = false)
|
46
52
|
raise ArgumentError, "Group must be of type Gitolite::Config::Group!" unless group.instance_of? Gitolite::Config::Group
|
47
53
|
@groups[group.name] = group
|
48
54
|
end
|
49
55
|
|
56
|
+
|
50
57
|
def rm_group(group)
|
51
58
|
name = normalize_group_name(group)
|
52
59
|
@groups.delete(name)
|
53
60
|
end
|
54
61
|
|
62
|
+
|
55
63
|
def has_group?(group)
|
56
64
|
name = normalize_group_name(group)
|
57
65
|
@groups.has_key?(name)
|
58
66
|
end
|
59
67
|
|
68
|
+
|
60
69
|
def get_group(group)
|
61
70
|
name = normalize_group_name(group)
|
62
71
|
@groups[name]
|
63
72
|
end
|
64
73
|
|
74
|
+
|
65
75
|
def to_file(path=".", filename=@filename)
|
66
76
|
raise ArgumentError, "Path contains a filename or does not exist" unless File.directory?(path)
|
67
77
|
|
@@ -69,7 +79,7 @@ module Gitolite
|
|
69
79
|
File.open(new_conf, "w") do |f|
|
70
80
|
f.sync = true
|
71
81
|
|
72
|
-
#Output groups
|
82
|
+
# Output groups
|
73
83
|
dep_order = build_groups_depgraph
|
74
84
|
dep_order.each {|group| f.write group.to_s }
|
75
85
|
|
@@ -89,167 +99,186 @@ module Gitolite
|
|
89
99
|
new_conf
|
90
100
|
end
|
91
101
|
|
102
|
+
|
92
103
|
private
|
93
|
-
#Based on
|
94
|
-
#https://github.com/sitaramc/gitolite/blob/pu/src/gl-compile-conf#cleanup_conf_line
|
95
|
-
def cleanup_config_line(line)
|
96
|
-
#remove comments, even those that happen inline
|
97
|
-
line.gsub!(/^((".*?"|[^#"])*)#.*/) {|m| m=$1}
|
98
|
-
|
99
|
-
#fix whitespace
|
100
|
-
line.gsub!('=', ' = ')
|
101
|
-
line.gsub!(/\s+/, ' ')
|
102
|
-
line.strip
|
103
|
-
end
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
@
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
105
|
+
|
106
|
+
# Based on
|
107
|
+
# https://github.com/sitaramc/gitolite/blob/pu/src/gl-compile-conf#cleanup_conf_line
|
108
|
+
def cleanup_config_line(line)
|
109
|
+
# remove comments, even those that happen inline
|
110
|
+
line.gsub!(/^((".*?"|[^#"])*)#.*/) {|m| m=$1}
|
111
|
+
|
112
|
+
# fix whitespace
|
113
|
+
line.gsub!('=', ' = ')
|
114
|
+
line.gsub!(/\s+/, ' ')
|
115
|
+
line.strip
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def process_config(config)
|
120
|
+
context = [] #will store our context for permissions or config declarations
|
121
|
+
|
122
|
+
#Read each line of our config
|
123
|
+
File.open(config, 'r').each do |l|
|
124
|
+
|
125
|
+
line = cleanup_config_line(l)
|
126
|
+
next if line.empty? #lines are empty if we killed a comment
|
127
|
+
|
128
|
+
case line
|
129
|
+
|
130
|
+
# found a repo definition
|
131
|
+
when /^repo (.*)/
|
132
|
+
#Empty our current context
|
133
|
+
context = []
|
134
|
+
|
135
|
+
repos = $1.split
|
136
|
+
repos.each do |r|
|
137
|
+
context << r
|
138
|
+
|
139
|
+
@repos[r] = Repo.new(r) unless has_repo?(r)
|
140
|
+
end
|
141
|
+
|
142
|
+
# repo permissions
|
143
|
+
when /^(-|C|R|RW\+?(?:C?D?|D?C?)M?) (.* )?= (.+)/
|
144
|
+
perm = $1
|
145
|
+
refex = $2 || ""
|
146
|
+
users = $3.split
|
147
|
+
|
148
|
+
context.each do |c|
|
149
|
+
@repos[c].add_permission(perm, refex, users)
|
150
|
+
end
|
151
|
+
|
152
|
+
# repo git config
|
153
|
+
when /^config (.+) = ?(.*)/
|
154
|
+
key = $1
|
155
|
+
value = $2
|
156
|
+
|
157
|
+
context.each do |c|
|
158
|
+
@repos[c].set_git_config(key, value)
|
159
|
+
end
|
160
|
+
|
161
|
+
# repo gitolite option
|
162
|
+
when /^option (.+) = (.*)/
|
163
|
+
key = $1
|
164
|
+
value = $2
|
165
|
+
|
166
|
+
raise ParseError, "Missing gitolite option value for repo: #{repo} and key: #{key}" if value.nil?
|
167
|
+
|
168
|
+
context.each do |c|
|
169
|
+
@repos[c].set_gitolite_option(key, value)
|
170
|
+
end
|
171
|
+
|
172
|
+
# group definition
|
173
|
+
when /^#{Group::PREPEND_CHAR}(\S+) = ?(.*)/
|
174
|
+
group = $1
|
175
|
+
users = $2.split
|
176
|
+
|
177
|
+
@groups[group] = Group.new(group) unless has_group?(group)
|
178
|
+
@groups[group].add_users(users)
|
179
|
+
|
180
|
+
# gitweb definition
|
181
|
+
when /^(\S+)(?: "(.*?)")? = "(.*)"$/
|
182
|
+
repo = $1
|
183
|
+
owner = $2
|
184
|
+
description = $3
|
185
|
+
|
186
|
+
#Check for missing description
|
187
|
+
raise ParseError, "Missing Gitweb description for repo: #{repo}" if description.nil?
|
188
|
+
|
189
|
+
#Check for groups
|
190
|
+
raise ParseError, "Gitweb descriptions cannot be set for groups" if repo =~ /@.+/
|
191
|
+
|
192
|
+
if has_repo? repo
|
193
|
+
r = @repos[repo]
|
187
194
|
else
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
195
|
+
r = Repo.new(repo)
|
196
|
+
add_repo(r)
|
197
|
+
end
|
198
|
+
|
199
|
+
r.owner = owner
|
200
|
+
r.description = description
|
201
|
+
|
202
|
+
when /^include "(.+)"/
|
203
|
+
#TODO: implement includes
|
204
|
+
#ignore includes for now
|
205
|
+
|
206
|
+
when /^subconf (\S+)$/
|
207
|
+
#TODO: implement subconfs
|
208
|
+
#ignore subconfs for now
|
192
209
|
|
193
|
-
# Normalizes the various different input objects to Strings
|
194
|
-
def normalize_name(context, constant = nil)
|
195
|
-
case context
|
196
|
-
when constant
|
197
|
-
context.name
|
198
|
-
when Symbol
|
199
|
-
context.to_s
|
200
210
|
else
|
201
|
-
|
211
|
+
raise ParseError, "'#{line}' cannot be processed"
|
202
212
|
end
|
203
213
|
end
|
214
|
+
end
|
204
215
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
normalize_name(args[0], Gitolite::Config::Group)
|
214
|
-
end
|
216
|
+
|
217
|
+
# Normalizes the various different input objects to Strings
|
218
|
+
def normalize_name(context, constant = nil)
|
219
|
+
case context
|
220
|
+
when constant
|
221
|
+
context.name
|
222
|
+
when Symbol
|
223
|
+
context.to_s
|
215
224
|
else
|
216
|
-
|
217
|
-
end
|
225
|
+
context
|
218
226
|
end
|
227
|
+
end
|
219
228
|
|
220
|
-
# Builds a dependency tree from the groups in order to ensure all groups
|
221
|
-
# are defined before they are used
|
222
|
-
def build_groups_depgraph
|
223
|
-
dp = ::GRATR::Digraph.new
|
224
229
|
|
225
|
-
|
226
|
-
|
227
|
-
|
230
|
+
def method_missing(meth, *args, &block)
|
231
|
+
if meth.to_s =~ /normalize_(\w+)_name/
|
232
|
+
# Could use Object.const_get to figure out the constant here
|
233
|
+
# but for only two cases, this is more readable
|
234
|
+
case $1
|
235
|
+
when "repo"
|
236
|
+
normalize_name(args[0], Gitolite::Config::Repo)
|
237
|
+
when "group"
|
238
|
+
normalize_name(args[0], Gitolite::Config::Group)
|
239
|
+
end
|
240
|
+
else
|
241
|
+
super
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
228
245
|
|
229
|
-
|
230
|
-
|
246
|
+
# Builds a dependency tree from the groups in order to ensure all groups
|
247
|
+
# are defined before they are used
|
248
|
+
def build_groups_depgraph
|
249
|
+
dp = ::Plexus::Digraph.new
|
231
250
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
end
|
251
|
+
# Add each group to the graph
|
252
|
+
@groups.each_value do |group|
|
253
|
+
dp.add_vertex! group
|
236
254
|
|
237
|
-
#
|
238
|
-
|
255
|
+
# Select group names from the users
|
256
|
+
subgroups = group.users.select {|u| u =~ /^#{Group::PREPEND_CHAR}.*$/}.map{|g| get_group g.gsub(Group::PREPEND_CHAR, '') }
|
239
257
|
|
240
|
-
|
241
|
-
|
258
|
+
subgroups.each do |subgroup|
|
259
|
+
dp.add_edge! subgroup, group
|
242
260
|
end
|
243
|
-
|
244
|
-
dep_order
|
245
261
|
end
|
246
262
|
|
247
|
-
#
|
248
|
-
|
249
|
-
end
|
263
|
+
# Figure out if we have a good depedency graph
|
264
|
+
dep_order = dp.topsort
|
250
265
|
|
251
|
-
|
252
|
-
|
266
|
+
if dep_order.empty?
|
267
|
+
raise GroupDependencyError unless @groups.empty?
|
253
268
|
end
|
269
|
+
|
270
|
+
dep_order
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
#Raised when something in a config fails to parse properly
|
275
|
+
class ParseError < RuntimeError
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
# Raised when group dependencies cannot be suitably resolved for output
|
280
|
+
class GroupDependencyError < RuntimeError
|
281
|
+
end
|
282
|
+
|
254
283
|
end
|
255
284
|
end
|