roast 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -0
- data/lib/roast.rb +1 -0
- data/lib/roast/cli/commands.rb +18 -8
- data/lib/roast/group.rb +8 -4
- data/lib/roast/host.rb +18 -6
- data/lib/roast/hosts_file.rb +15 -6
- data/lib/roast/version.rb +1 -1
- data/roast.gemspec +1 -0
- data/test/files/one +1 -1
- data/test/host_test.rb +27 -4
- data/test/hosts_file_test.rb +17 -16
- data/test/test_helper.rb +2 -0
- metadata +18 -2
data/README.md
CHANGED
@@ -36,6 +36,9 @@ $ sudo roast add 10.0.1.1 something.dev
|
|
36
36
|
# add an entry to the "testing" group
|
37
37
|
$ sudo roast add testing 127.0.0.1 exampleapp.dev
|
38
38
|
|
39
|
+
# add an entry to the "testing" group via another hostname (resolve the ip)
|
40
|
+
$ sudo roast add testing example.org exampleapp.dev
|
41
|
+
|
39
42
|
# disable all entries with the ip "10.0.1.1"
|
40
43
|
$ sudo roast disable 10.0.1.1
|
41
44
|
|
data/lib/roast.rb
CHANGED
data/lib/roast/cli/commands.rb
CHANGED
@@ -21,23 +21,30 @@ module Roast
|
|
21
21
|
puts "`#{command}' is an unknown command, use --help to see available commands"
|
22
22
|
exit
|
23
23
|
end
|
24
|
+
rescue ArgumentError => e
|
25
|
+
puts e.message
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def confirm(message = 'Are you sure that you want to do that?')
|
30
|
+
puts "#{message} [\"yes\" or \"no\"]"
|
31
|
+
exit if $stdin.gets.chomp !~ /\Ay(?:es)?\Z/i
|
24
32
|
end
|
25
33
|
|
26
34
|
def add(*args)
|
27
35
|
if args.length < 2
|
28
|
-
raise ArgumentError, "You must provide an ip address and a hostname to point it
|
36
|
+
raise ArgumentError, "You must provide an ip address and a hostname to point it to: `roast add 127.0.0.1 something.dev'"
|
29
37
|
elsif args.length == 3
|
30
38
|
group = args.shift
|
31
39
|
else
|
32
|
-
group =
|
40
|
+
group = nil
|
33
41
|
end
|
34
42
|
|
35
|
-
|
36
|
-
ip_address, hostname = args
|
43
|
+
source, hostname = args
|
37
44
|
|
38
|
-
if @hosts_file.add(group,
|
45
|
+
if @hosts_file.add(group, source, hostname)
|
39
46
|
@hosts_file.write
|
40
|
-
puts "added host entry for `#{
|
47
|
+
puts "added host entry for `#{source} \033[4m#{hostname}\033[0m'"
|
41
48
|
end
|
42
49
|
end
|
43
50
|
|
@@ -65,6 +72,7 @@ module Roast
|
|
65
72
|
|
66
73
|
def delete(*args)
|
67
74
|
entry = args.first
|
75
|
+
confirm("Are you sure that you want to delete entries matching `#{entry}'?")
|
68
76
|
results = @hosts_file.delete(entry)
|
69
77
|
if results.empty?
|
70
78
|
puts "no entries found matching `#{entry}'"
|
@@ -98,7 +106,7 @@ module Roast
|
|
98
106
|
|
99
107
|
def delete_group(*args)
|
100
108
|
group = args.first
|
101
|
-
|
109
|
+
confirm("Are you sure that you want to delete the group `#{group}'?")
|
102
110
|
if @hosts_file.delete_group(group)
|
103
111
|
@hosts_file.write
|
104
112
|
puts "deleted group `#{group}'"
|
@@ -115,7 +123,9 @@ module Roast
|
|
115
123
|
puts "there are no roast entries in `#{path}'\n"
|
116
124
|
else
|
117
125
|
entries = ''
|
118
|
-
groups.
|
126
|
+
indent = groups.map { |g| g.hosts.map { |h| h.hostname.size }.max }.max
|
127
|
+
|
128
|
+
groups.each { |group| entries << group.to_cli(indent) }
|
119
129
|
puts entries.chomp
|
120
130
|
end
|
121
131
|
end
|
data/lib/roast/group.rb
CHANGED
@@ -54,9 +54,9 @@ module Roast
|
|
54
54
|
deleted
|
55
55
|
end
|
56
56
|
|
57
|
-
def to_cli
|
57
|
+
def to_cli(max_indent = nil)
|
58
58
|
string = " - \033[4m#{name}\033[0m\n"
|
59
|
-
max
|
59
|
+
max = max_indent || hosts.map { |h| h.hostname.size }.max
|
60
60
|
|
61
61
|
hosts.each do |host|
|
62
62
|
padding = ' ' * (max - host.hostname.size + 4)
|
@@ -65,7 +65,9 @@ module Roast
|
|
65
65
|
else
|
66
66
|
string << ' '
|
67
67
|
end
|
68
|
-
string << "#{host.hostname}#{padding}#{host.ip_address}
|
68
|
+
string << "#{host.hostname}#{padding}#{host.ip_address}"
|
69
|
+
string << " # #{host.alias}" if host.alias
|
70
|
+
string << "\033[0m\n"
|
69
71
|
end
|
70
72
|
|
71
73
|
string
|
@@ -78,7 +80,9 @@ module Roast
|
|
78
80
|
hosts.each do |host|
|
79
81
|
padding = ' ' * (max - host.ip_address.size + 4)
|
80
82
|
section << '# ' if host.disabled?
|
81
|
-
section << "#{host.ip_address}#{padding}#{host.hostname}
|
83
|
+
section << "#{host.ip_address}#{padding}#{host.hostname}"
|
84
|
+
section << " # #{host.alias}" if host.alias
|
85
|
+
section << "\n"
|
82
86
|
end
|
83
87
|
|
84
88
|
section
|
data/lib/roast/host.rb
CHANGED
@@ -1,23 +1,35 @@
|
|
1
1
|
module Roast
|
2
2
|
class Host
|
3
|
-
IP_PATTERN = /\A
|
3
|
+
IP_PATTERN = /\A([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}\z/
|
4
4
|
HOST_PATTERN = /\A[a-z0-9\-\.]+\z/
|
5
5
|
|
6
|
-
attr_reader
|
7
|
-
attr_reader
|
6
|
+
attr_reader :ip_address
|
7
|
+
attr_reader :hostname
|
8
|
+
attr_reader :state
|
9
|
+
attr_accessor :alias
|
8
10
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
+
def initialize(source, hostname)
|
12
|
+
if source !~ IP_PATTERN
|
13
|
+
@alias = source.chomp
|
14
|
+
resolve_source
|
15
|
+
else
|
16
|
+
@ip_address = source.chomp
|
17
|
+
end
|
11
18
|
@hostname = hostname.chomp.downcase
|
12
19
|
@state = 'enabled'
|
13
20
|
validate!
|
14
21
|
end
|
15
22
|
|
16
23
|
def validate!
|
17
|
-
raise ArgumentError, "`#{ip_address}' is an invalid ip address" unless ip_address =~ IP_PATTERN
|
18
24
|
raise ArgumentError, "`#{hostname}' is an invalid hostname" unless hostname =~ HOST_PATTERN
|
19
25
|
end
|
20
26
|
|
27
|
+
def resolve_source
|
28
|
+
@ip_address = IPSocket.getaddress(@alias)
|
29
|
+
rescue SocketError
|
30
|
+
raise ArgumentError, "unable to determine the ip address of `#{@alias}'"
|
31
|
+
end
|
32
|
+
|
21
33
|
def disable!
|
22
34
|
@state = 'disabled'
|
23
35
|
end
|
data/lib/roast/hosts_file.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Roast
|
2
2
|
class HostsFile
|
3
3
|
GROUP_PATTERN = /^## \[([\w\s-]+)\]$/
|
4
|
-
HOST_PATTERN = /^#?\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+([
|
4
|
+
HOST_PATTERN = /^#?\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+([a-z0-9\.\-]+)\s*(?:#\s*(\S+))?$/
|
5
5
|
DISABLED_PATTERN = /^# \d+/
|
6
6
|
|
7
7
|
attr_reader :path
|
@@ -37,6 +37,7 @@ module Roast
|
|
37
37
|
@groups[group.name] ||= group
|
38
38
|
elsif group && host_match = line.match(HOST_PATTERN)
|
39
39
|
host = Host.new(host_match[1], host_match[2])
|
40
|
+
host.alias = host_match[3]
|
40
41
|
host.disable! if line =~ DISABLED_PATTERN
|
41
42
|
group << host
|
42
43
|
else
|
@@ -46,6 +47,9 @@ module Roast
|
|
46
47
|
end
|
47
48
|
|
48
49
|
self
|
50
|
+
rescue Errno::EACCES
|
51
|
+
puts "Unable to read hosts file: `#{@path}', you might need to `sudo roast'"
|
52
|
+
exit 1
|
49
53
|
end
|
50
54
|
|
51
55
|
def write(output_path = nil)
|
@@ -54,10 +58,14 @@ module Roast
|
|
54
58
|
|
55
59
|
temp_file << static_lines.join.sub(/\n{3,}\z/, "\n\n")
|
56
60
|
temp_file << groups.map { |g| g.to_hosts_file.chomp }.join("\n\n")
|
57
|
-
|
58
61
|
File.chmod(0644, temp_file.path)
|
59
|
-
|
60
|
-
|
62
|
+
begin
|
63
|
+
FileUtils.cp(path, path + '.roast.bak') if output_path.eql?(path)
|
64
|
+
FileUtils.mv(temp_file.path, output_path, :force => true)
|
65
|
+
rescue Errno::EACCES
|
66
|
+
puts "Unable to write to hosts file: `#{@path}', you might need to `sudo roast'"
|
67
|
+
exit 1
|
68
|
+
end
|
61
69
|
ensure
|
62
70
|
temp_file.close
|
63
71
|
temp_file.unlink
|
@@ -71,9 +79,10 @@ module Roast
|
|
71
79
|
groups.map { |g| g.delete_host(entry) }.flatten
|
72
80
|
end
|
73
81
|
|
74
|
-
def add(group,
|
82
|
+
def add(group, source, hostname)
|
83
|
+
group ||= 'base'
|
75
84
|
@groups[group] ||= Group.new(group)
|
76
|
-
@groups[group] << Host.new(
|
85
|
+
@groups[group] << Host.new(source, hostname)
|
77
86
|
end
|
78
87
|
|
79
88
|
def enable(entry)
|
data/lib/roast/version.rb
CHANGED
data/roast.gemspec
CHANGED
data/test/files/one
CHANGED
data/test/host_test.rb
CHANGED
@@ -2,10 +2,33 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
describe Roast::Host do
|
4
4
|
|
5
|
-
it "
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
it "initializes a Host" do
|
6
|
+
host = Roast::Host.new('127.0.0.1', 'blah.dev')
|
7
|
+
host.hostname.must_equal 'blah.dev'
|
8
|
+
host.ip_address.must_equal '127.0.0.1'
|
9
|
+
host.state.must_equal 'enabled'
|
10
|
+
host.must_be :enabled?
|
11
|
+
end
|
12
|
+
|
13
|
+
it "disables a host" do
|
14
|
+
host = Roast::Host.new('127.0.0.1', 'blah.dev')
|
15
|
+
host.state.must_equal 'enabled'
|
16
|
+
host.disable!
|
17
|
+
host.state.must_equal 'disabled'
|
18
|
+
host.must_be :disabled?
|
19
|
+
end
|
20
|
+
|
21
|
+
it "enables a host" do
|
22
|
+
host = Roast::Host.new('127.0.0.1', 'blah.dev')
|
23
|
+
host.disable!
|
24
|
+
host.must_be :disabled?
|
25
|
+
host.enable!
|
26
|
+
host.must_be :enabled?
|
27
|
+
end
|
28
|
+
|
29
|
+
it "attempts to resolve a source hostname if given" do
|
30
|
+
Roast::Host.any_instance.expects(:resolve_source)
|
31
|
+
Roast::Host.new('google.com', 'blah.dev')
|
9
32
|
end
|
10
33
|
|
11
34
|
it "validates the hostname" do
|
data/test/hosts_file_test.rb
CHANGED
@@ -15,10 +15,12 @@ describe Roast::HostsFile do
|
|
15
15
|
hosts.groups.length.must_equal 3
|
16
16
|
[
|
17
17
|
[ '127.0.0.1', 'local.dev' ],
|
18
|
-
[ '10.0.1.2', 'something.dev' ]
|
18
|
+
[ '10.0.1.2', 'something.dev' ],
|
19
|
+
[ '127.0.0.1', 'example.org', 'whatever.org']
|
19
20
|
].each_with_index do |host, i|
|
20
|
-
hosts['base'].hosts[i].ip_address.must_equal host
|
21
|
-
hosts['base'].hosts[i].hostname.must_equal host
|
21
|
+
hosts['base'].hosts[i].ip_address.must_equal host[0]
|
22
|
+
hosts['base'].hosts[i].hostname.must_equal host[1]
|
23
|
+
hosts['base'].hosts[i].alias.must_equal host[2] if host[2]
|
22
24
|
end
|
23
25
|
[
|
24
26
|
[ '10.0.20.1', 'staging.something.com' ],
|
@@ -48,7 +50,7 @@ describe Roast::HostsFile do
|
|
48
50
|
## [base]
|
49
51
|
127.0.0.1 local.dev
|
50
52
|
10.0.1.2 something.dev
|
51
|
-
127.0.0.1 example.org
|
53
|
+
127.0.0.1 example.org # whatever.org
|
52
54
|
|
53
55
|
## [foo]
|
54
56
|
# 10.0.3.1 foo.bar
|
@@ -82,7 +84,7 @@ describe Roast::HostsFile do
|
|
82
84
|
## [base]
|
83
85
|
127.0.0.1 local.dev
|
84
86
|
10.0.1.2 something.dev
|
85
|
-
127.0.0.1 example.org
|
87
|
+
127.0.0.1 example.org # whatever.org
|
86
88
|
|
87
89
|
## [foo]
|
88
90
|
# 10.0.3.1 foo.bar
|
@@ -118,7 +120,7 @@ describe Roast::HostsFile do
|
|
118
120
|
## [base]
|
119
121
|
# 127.0.0.1 local.dev
|
120
122
|
10.0.1.2 something.dev
|
121
|
-
127.0.0.1 example.org
|
123
|
+
127.0.0.1 example.org # whatever.org
|
122
124
|
|
123
125
|
## [foo]
|
124
126
|
# 10.0.3.1 foo.bar
|
@@ -151,7 +153,7 @@ describe Roast::HostsFile do
|
|
151
153
|
## [base]
|
152
154
|
# 127.0.0.1 local.dev
|
153
155
|
10.0.1.2 something.dev
|
154
|
-
# 127.0.0.1 example.org
|
156
|
+
# 127.0.0.1 example.org # whatever.org
|
155
157
|
|
156
158
|
## [foo]
|
157
159
|
# 10.0.3.1 foo.bar
|
@@ -184,7 +186,7 @@ describe Roast::HostsFile do
|
|
184
186
|
## [base]
|
185
187
|
127.0.0.1 local.dev
|
186
188
|
10.0.1.2 something.dev
|
187
|
-
127.0.0.1 example.org
|
189
|
+
127.0.0.1 example.org # whatever.org
|
188
190
|
|
189
191
|
## [foo]
|
190
192
|
# 10.0.3.1 foo.bar
|
@@ -217,7 +219,7 @@ describe Roast::HostsFile do
|
|
217
219
|
## [base]
|
218
220
|
127.0.0.1 local.dev
|
219
221
|
10.0.1.2 something.dev
|
220
|
-
127.0.0.1 example.org
|
222
|
+
127.0.0.1 example.org # whatever.org
|
221
223
|
|
222
224
|
## [foo]
|
223
225
|
# 10.0.3.1 foo.bar
|
@@ -250,7 +252,7 @@ describe Roast::HostsFile do
|
|
250
252
|
## [base]
|
251
253
|
127.0.0.1 local.dev
|
252
254
|
10.0.1.2 something.dev
|
253
|
-
127.0.0.1 example.org
|
255
|
+
127.0.0.1 example.org # whatever.org
|
254
256
|
|
255
257
|
## [foo]
|
256
258
|
10.0.3.1 foo.bar
|
@@ -283,7 +285,7 @@ describe Roast::HostsFile do
|
|
283
285
|
## [base]
|
284
286
|
127.0.0.1 local.dev
|
285
287
|
10.0.1.2 something.dev
|
286
|
-
127.0.0.1 example.org
|
288
|
+
127.0.0.1 example.org # whatever.org
|
287
289
|
|
288
290
|
## [foo]
|
289
291
|
# 10.0.3.1 foo.bar
|
@@ -315,7 +317,7 @@ describe Roast::HostsFile do
|
|
315
317
|
|
316
318
|
## [base]
|
317
319
|
10.0.1.2 something.dev
|
318
|
-
127.0.0.1 example.org
|
320
|
+
127.0.0.1 example.org # whatever.org
|
319
321
|
|
320
322
|
## [foo]
|
321
323
|
# 10.0.3.1 foo.bar
|
@@ -379,7 +381,7 @@ describe Roast::HostsFile do
|
|
379
381
|
## [base]
|
380
382
|
127.0.0.1 local.dev
|
381
383
|
10.0.1.2 something.dev
|
382
|
-
127.0.0.1 example.org
|
384
|
+
127.0.0.1 example.org # whatever.org
|
383
385
|
|
384
386
|
## [foo]
|
385
387
|
# 10.0.3.1 foo.bar
|
@@ -392,15 +394,14 @@ describe Roast::HostsFile do
|
|
392
394
|
hosts.groups.length.must_equal 3
|
393
395
|
hosts['base'] << Roast::Host.new('127.0.0.1', 'example.org')
|
394
396
|
hosts.write(File.join(FILES_PATH, 'two.new'))
|
395
|
-
File.exist?(File.join(FILES_PATH, 'one.bak')).wont_equal true
|
397
|
+
File.exist?(File.join(FILES_PATH, 'one.roast.bak')).wont_equal true
|
396
398
|
end
|
397
399
|
|
398
400
|
it "creates a backup file if the output file is the same as the input file" do
|
399
401
|
hosts = hosts_from_file('one')
|
400
402
|
hosts.groups.length.must_equal 3
|
401
|
-
hosts['base'] << Roast::Host.new('127.0.0.1', 'example.org')
|
402
403
|
hosts.write
|
403
|
-
File.exist?(File.join(FILES_PATH, 'one.bak')).must_equal true
|
404
|
+
File.exist?(File.join(FILES_PATH, 'one.roast.bak')).must_equal true
|
404
405
|
end
|
405
406
|
|
406
407
|
def hosts_from_file(file_name)
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roast
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: 3.0.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: mocha
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.13.3
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.13.3
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: rake
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|