jbox-gitolite 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -7
  3. data/Guardfile +2 -2
  4. data/README.md +3 -2
  5. data/Rakefile +26 -8
  6. data/gitolite.gemspec +3 -3
  7. data/lib/gitolite.rb +5 -2
  8. data/lib/gitolite/config.rb +181 -152
  9. data/lib/gitolite/config/group.rb +11 -0
  10. data/lib/gitolite/config/repo.rb +22 -9
  11. data/lib/gitolite/dirty_proxy.rb +3 -0
  12. data/lib/gitolite/gitolite_admin.rb +0 -2
  13. data/lib/gitolite/ssh_key.rb +52 -38
  14. data/lib/gitolite/version.rb +1 -1
  15. data/spec/config_spec.rb +18 -11
  16. data/spec/dirty_proxy_spec.rb +4 -1
  17. data/spec/fixtures/configs/complicated.conf +311 -0
  18. data/spec/fixtures/configs/simple.conf +5 -0
  19. data/spec/{keys/bob-ins@zilla-site.com@desktop.pub → fixtures/keys/bob+joe@test.zilla.com@desktop.pub} +0 -0
  20. data/spec/{keys/bob.joe@test.zilla.com@desktop.pub → fixtures/keys/bob-ins@zilla-site.com@desktop.pub} +0 -0
  21. data/spec/{keys/bob@zilla.com@desktop.pub → fixtures/keys/bob.joe@test.zilla.com@desktop.pub} +0 -0
  22. data/spec/{keys → fixtures/keys}/bob.pub +0 -0
  23. data/spec/{keys → fixtures/keys}/bob@desktop.pub +0 -0
  24. data/spec/{keys → fixtures/keys}/bob@foo-bar.pub +0 -0
  25. data/spec/{keys → fixtures/keys}/bob@zilla.com.pub +0 -0
  26. data/spec/{keys/joe-bob@god-zilla.com@desktop.pub → fixtures/keys/bob@zilla.com@desktop.pub} +0 -0
  27. data/spec/{keys → fixtures/keys}/jakub123.pub +0 -0
  28. data/spec/{keys → fixtures/keys}/jakub123@foo.net.pub +0 -0
  29. data/spec/fixtures/keys/joe-bob@god-zilla.com@desktop.pub +1 -0
  30. data/spec/{keys → fixtures/keys}/joe@sch.ool.edu.pub +0 -0
  31. data/spec/{keys → fixtures/keys}/joe@sch.ool.edu@desktop.pub +0 -0
  32. data/spec/gitolite_admin_spec.rb +6 -8
  33. data/spec/group_spec.rb +0 -1
  34. data/spec/repo_spec.rb +0 -1
  35. data/spec/spec_helper.rb +2 -2
  36. data/spec/ssh_key_spec.rb +15 -10
  37. metadata +39 -37
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 63c530bb8eff13306344887fcc5580ef058cd745
4
- data.tar.gz: 86b5e4506055f9355b1ac97d85dde40018c1f5c0
3
+ metadata.gz: 8242365723c05acd430cfdaa34f8f18e201fe860
4
+ data.tar.gz: 767660c5aa70ce7f4a3a8df74164ec667af0f289
5
5
  SHA512:
6
- metadata.gz: 1bb6ea32939e9cb36c1d52f703bf0b89d0b19694371dee7d6a33781904fa0ec7c875da4b05fd8fee0e52b5aca947a0a261b48e3717008f8f087f54cefd4ae88b
7
- data.tar.gz: 26c895891e7976fb68165923ec56e3d4490b1f0401fabee1c1a720609ba87599756b44dcbbc6ce0f07f38977a3f37ea54e3ad79cffe40310da8d2067e3f91f55
6
+ metadata.gz: a79d5689bede554598122604aacc28d7740cc9de1d13c4e7c8a9c3def8ade3363b7f401a172f6b71b573e62a86733cfbf6c9bfc8f88f16e2355b55f4d611dc8b
7
+ data.tar.gz: 3ae1bf550e36a15a22302d25b84af0dfb963506bfcf55bc0d02cf6623e3139e552666bcffd335d8fc4f77b9b9f8b3bb0e6e22e6cd30ddd9dbd8adb77f218c22c
data/.gitignore CHANGED
@@ -1,9 +1,9 @@
1
- pkg/*
2
1
  *.gem
3
- .bundle
4
- rdoc/*
5
- *.conf
6
- coverage
7
2
  *.lock
8
- junit/
9
- tmp/
3
+ *.log
4
+ .bundle
5
+ /pkg
6
+ /rdoc
7
+ /coverage
8
+ /junit
9
+ /tmp
data/Guardfile CHANGED
@@ -1,12 +1,12 @@
1
1
  # More info at https://github.com/guard/guard#readme
2
2
 
3
- guard 'rspec', :cli => "--color --format nested --fail-fast" do
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 'spork', :rspec_env => { 'RAILS_ENV' => 'test' }, :rspec_port => 9090 do
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
  * [![Gem Version](https://badge.fury.io/rb/jbox-gitolite.svg)](http://badge.fury.io/rb/jbox-gitolite)
18
- * [![Build Status](https://travis-ci.org/jbox-web/gitolite.svg?branch=v1.2.0)](https://travis-ci.org/jbox-web/gitolite)
18
+ * [![Build Status](https://travis-ci.org/jbox-web/gitolite.svg?branch=devel)](https://travis-ci.org/jbox-web/gitolite)
19
19
  * [![Code Climate](https://codeclimate.com/github/jbox-web/gitolite.png)](https://codeclimate.com/github/jbox-web/gitolite)
20
+ * [![Dependency Status](https://gemnasium.com/jbox-web/gitolite.svg)](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) [![endorse](https://api.coderwall.com/n-rodriguez/endorsecount.png)](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
- # Helper Functions
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.6.0"
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.5.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 "gratr19", "~> 0.4.4.1"
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 'gratr'
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/gitolite_admin'
8
+ require 'gitolite/config/repo'
9
+ require 'gitolite/config/group'
7
10
  end
@@ -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
- def initialize(config)
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
- #TODO: merge repo unless overwrite = true
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
- def process_config(config)
106
- context = [] #will store our context for permissions or config declarations
107
-
108
- #Read each line of our config
109
- File.open(config, 'r').each do |l|
110
-
111
- line = cleanup_config_line(l)
112
- next if line.empty? #lines are empty if we killed a comment
113
-
114
- case line
115
- #found a repo definition
116
- when /^repo (.*)/
117
- #Empty our current context
118
- context = []
119
-
120
- repos = $1.split
121
- repos.each do |r|
122
- context << r
123
-
124
- @repos[r] = Repo.new(r) unless has_repo?(r)
125
- end
126
- #repo permissions
127
- when /^(-|C|R|RW\+?(?:C?D?|D?C?)M?) (.* )?= (.+)/
128
- perm = $1
129
- refex = $2 || ""
130
- users = $3.split
131
-
132
- context.each do |c|
133
- @repos[c].add_permission(perm, refex, users)
134
- end
135
- #repo git config
136
- when /^config (.+) = ?(.*)/
137
- key = $1
138
- value = $2
139
-
140
- context.each do |c|
141
- @repos[c].set_git_config(key, value)
142
- end
143
- #repo gitolite option
144
- when /^option (.+) = (.*)/
145
- key = $1
146
- value = $2
147
-
148
- raise ParseError, "Missing gitolite option value for repo: #{repo} and key: #{key}" if value.nil?
149
-
150
- context.each do |c|
151
- @repos[c].set_gitolite_option(key, value)
152
- end
153
- #group definition
154
- when /^#{Group::PREPEND_CHAR}(\S+) = ?(.*)/
155
- group = $1
156
- users = $2.split
157
-
158
- @groups[group] = Group.new(group) unless has_group?(group)
159
- @groups[group].add_users(users)
160
- #gitweb definition
161
- when /^(\S+)(?: "(.*?)")? = "(.*)"$/
162
- repo = $1
163
- owner = $2
164
- description = $3
165
-
166
- #Check for missing description
167
- raise ParseError, "Missing Gitweb description for repo: #{repo}" if description.nil?
168
-
169
- #Check for groups
170
- raise ParseError, "Gitweb descriptions cannot be set for groups" if repo =~ /@.+/
171
-
172
- if has_repo? repo
173
- r = @repos[repo]
174
- else
175
- r = Repo.new(repo)
176
- add_repo(r)
177
- end
178
-
179
- r.owner = owner
180
- r.description = description
181
- when /^include "(.+)"/
182
- #TODO: implement includes
183
- #ignore includes for now
184
- when /^subconf (\S+)$/
185
- #TODO: implement subconfs
186
- #ignore subconfs for now
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
- raise ParseError, "'#{line}' cannot be processed"
189
- end
190
- end
191
- end
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
- context
211
+ raise ParseError, "'#{line}' cannot be processed"
202
212
  end
203
213
  end
214
+ end
204
215
 
205
- def method_missing(meth, *args, &block)
206
- if meth.to_s =~ /normalize_(\w+)_name/
207
- #Could use Object.const_get to figure out the constant here
208
- #but for only two cases, this is more readable
209
- case $1
210
- when "repo"
211
- normalize_name(args[0], Gitolite::Config::Repo)
212
- when "group"
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
- super
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
- # Add each group to the graph
226
- @groups.each_value do |group|
227
- dp.add_vertex! group
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
- # Select group names from the users
230
- subgroups = group.users.select {|u| u =~ /^#{Group::PREPEND_CHAR}.*$/}.map{|g| get_group g.gsub(Group::PREPEND_CHAR, '') }
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
- subgroups.each do |subgroup|
233
- dp.add_edge! subgroup, group
234
- end
235
- end
251
+ # Add each group to the graph
252
+ @groups.each_value do |group|
253
+ dp.add_vertex! group
236
254
 
237
- # Figure out if we have a good depedency graph
238
- dep_order = dp.topsort
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
- if dep_order.empty?
241
- raise GroupDependencyError unless @groups.empty?
258
+ subgroups.each do |subgroup|
259
+ dp.add_edge! subgroup, group
242
260
  end
243
-
244
- dep_order
245
261
  end
246
262
 
247
- #Raised when something in a config fails to parse properly
248
- class ParseError < RuntimeError
249
- end
263
+ # Figure out if we have a good depedency graph
264
+ dep_order = dp.topsort
250
265
 
251
- # Raised when group dependencies cannot be suitably resolved for output
252
- class GroupDependencyError < RuntimeError
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