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