roast 0.1.0

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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in roast.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 blahed
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # Roast [![Build Status](https://travis-ci.org/blahed/roast.png?branch=master)](https://travis-ci.org/blahed/roast)
2
+
3
+ Roast helps you manage entries in your `/etc/hosts` file. Roast allows you to group entries together in a named group and disable/enable them all at once. It's pretty useful if you work with a lot of entries in your hosts file and find it annoying to constantly be enabled/editing your hosts file manually.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ $ gem install roast
9
+ ```
10
+
11
+ ## Commands
12
+
13
+ Roast has a decent set of commands available:
14
+ ```
15
+ list list the entries in the hosts file alias: l
16
+ add adds a new entry to the hosts file alias: a
17
+ enable enables a disabled (commented out) entry alias: e
18
+ enable-group enables an entire group alias: eg
19
+ disable disables an entry (comments it out) alias: d
20
+ disable-group disables an entire group alias: dg
21
+ delete deletes an entry entirely
22
+ delete-group deletes an enitre group
23
+ ```
24
+ *a few of the commands have aliases, they are listed to the right*
25
+
26
+ ## Usage
27
+
28
+ A few examples of using roast to manage your `/etc/hosts` file:
29
+ ```bash
30
+ # list all entires
31
+ $ roast list
32
+
33
+ # add an entry to the base group
34
+ $ sudo roast add 10.0.1.1 something.dev
35
+
36
+ # add an entry to the "testing" group
37
+ $ sudo roast add testing 127.0.0.1 exampleapp.dev
38
+
39
+ # disable all entries with the ip "10.0.1.1"
40
+ $ sudo roast disable 10.0.1.1
41
+
42
+ # delete an entry entirely
43
+ $ sudo roast delete exampleapp.dev
44
+ ```
45
+
46
+ *notice that you can list entries without sudo, but editing the hosts file does require sudo*
47
+
48
+ ## Contributing
49
+
50
+ 1. Fork it
51
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
52
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
53
+ 4. Push to the branch (`git push origin my-new-feature`)
54
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require 'rake/testtask'
3
+ require 'bundler/gem_tasks'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ t.test_files = FileList['test/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/roast ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
3
+
4
+ require 'roast'
5
+
6
+ Roast::CLI.new.run
@@ -0,0 +1,125 @@
1
+ module Roast
2
+ class CLI
3
+ module Commands
4
+ ALIASES = {
5
+ 'a' => 'add',
6
+ 'e' => 'enable',
7
+ 'eg' => 'enable-group',
8
+ 'd' => 'disable',
9
+ 'dg' => 'disable-group',
10
+ 'l' => 'list'
11
+ }
12
+
13
+ def dispatch
14
+ command = ARGV.shift
15
+ command = (ALIASES[command] || command).tr('-', '_')
16
+
17
+ if respond_to? command
18
+ @hosts_file = HostsFile.new.read
19
+ send(command, *ARGV)
20
+ else
21
+ puts "`#{command}' is an unknown command, use --help to see available commands"
22
+ exit
23
+ end
24
+ end
25
+
26
+ def add(*args)
27
+ if args.length < 2
28
+ raise ArgumentError, "You must provide an ip address and a hostname to point it too"
29
+ elsif args.length == 3
30
+ group = args.shift
31
+ else
32
+ group = 'base'
33
+ end
34
+
35
+ args.reverse! if args.last =~ Host::IP_PATTERN
36
+ ip_address, hostname = args
37
+
38
+ if @hosts_file.add(group, ip_address, hostname)
39
+ @hosts_file.write
40
+ puts "added host entry for `#{ip_address} \033[4m#{hostname}\033[0m'"
41
+ end
42
+ end
43
+
44
+ def enable(*args)
45
+ entry = args.first
46
+ results = @hosts_file.enable(entry)
47
+ if results.empty?
48
+ puts "no entries found matching `#{entry}'"
49
+ else
50
+ @hosts_file.write
51
+ puts "enabled entry#{results.length > 1 ? 's' : ''} matching `#{entry}'"
52
+ end
53
+ end
54
+
55
+ def disable(*args)
56
+ entry = args.first
57
+ results = @hosts_file.disable(entry)
58
+ if results.empty?
59
+ puts "no entries found matching `#{entry}'"
60
+ else
61
+ @hosts_file.write
62
+ puts "disabled entry#{results.length > 1 ? 's' : ''} matching `#{entry}'"
63
+ end
64
+ end
65
+
66
+ def delete(*args)
67
+ entry = args.first
68
+ results = @hosts_file.delete(entry)
69
+ if results.empty?
70
+ puts "no entries found matching `#{entry}'"
71
+ else
72
+ @hosts_file.write
73
+ puts "deleted entry#{results.length > 1 ? 's' : ''} matching `#{entry}'"
74
+ end
75
+ end
76
+
77
+ def enable_group(*args)
78
+ group = args.first
79
+
80
+ if @hosts_file.enable_group(group)
81
+ @hosts_file.write
82
+ puts "enabled group `#{group}'"
83
+ else
84
+ puts "Unable to enable the group `#{group}', it doesn't exist yet."
85
+ end
86
+ end
87
+
88
+ def disable_group(*args)
89
+ group = args.first
90
+
91
+ if @hosts_file.disable_group(group)
92
+ @hosts_file.write
93
+ puts "disabled group `#{group}'"
94
+ else
95
+ puts "Unable to disable the group `#{group}', it doesn't exist yet."
96
+ end
97
+ end
98
+
99
+ def delete_group(*args)
100
+ group = args.first
101
+
102
+ if @hosts_file.delete_group(group)
103
+ @hosts_file.write
104
+ puts "deleted group `#{group}'"
105
+ else
106
+ puts "Unable to delete the group `#{group}', it doesn't exist yet."
107
+ end
108
+ end
109
+
110
+ def list(*args)
111
+ # TODO: a bit awkward, use a class var?
112
+ path, groups = @hosts_file.list
113
+
114
+ if groups.empty?
115
+ puts "there are no roast entries in `#{path}'\n"
116
+ else
117
+ entries = ''
118
+ groups.each { |group| entries << group.to_cli }
119
+ puts entries.chomp
120
+ end
121
+ end
122
+
123
+ end
124
+ end
125
+ end
data/lib/roast/cli.rb ADDED
@@ -0,0 +1,69 @@
1
+ module Roast
2
+ class CLI
3
+ include Roast::CLI::Commands
4
+
5
+ BANNER = <<-BANNER
6
+ Usage: roast COMMAND [ARGS]
7
+
8
+ Description:
9
+ The roast command manages groups/entries in your /etc/hosts file. It
10
+ has a few different commands available:
11
+
12
+ list list the entries in the hosts file alias: l
13
+ add adds a new entry to the hosts file alias: a
14
+ enable enables a disabled (commented out) entry alias: e
15
+ enable-group enables an entire group alias: eg
16
+ disable disables an entry (comments it out) alias: d
17
+ disable-group disables an entire group alias: dg
18
+ delete deletes an entry entirely
19
+ delete-group deletes an enitre group
20
+
21
+ Examples:
22
+ # list all entires
23
+ > roast list
24
+
25
+ # add an entry to the base group
26
+ > roast add 10.0.1.1 something.dev
27
+
28
+ # add an entry to the "testing" group
29
+ > roast add testing 127.0.0.1 exampleapp.dev
30
+
31
+ # disable all entries with the ip "10.0.1.1"
32
+ > roast disable 10.0.1.1
33
+ BANNER
34
+
35
+ # Use OptionParser to parse options, then we remove them from ARGV
36
+ def parse_options
37
+ @opts = OptionParser.new do |opts|
38
+ opts.banner = BANNER.gsub(/^ {4}/, '')
39
+
40
+ opts.separator ''
41
+ opts.separator 'Options:'
42
+
43
+ opts.on('-v', 'Print the version') do
44
+ puts Roast::VERSION
45
+ exit
46
+ end
47
+
48
+ opts.on( '-h', '--help', 'Display this help.' ) do
49
+ puts opts
50
+ exit
51
+ end
52
+ end
53
+
54
+ @opts.parse!
55
+ end
56
+
57
+ def print_usage_and_exit!
58
+ puts @opts
59
+ exit
60
+ end
61
+
62
+ # Called from the executable. Parses the command line arguments
63
+ def run
64
+ parse_options
65
+ print_usage_and_exit! if ARGV.empty?
66
+ dispatch
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,88 @@
1
+ module Roast
2
+ class Group
3
+ attr_reader :name
4
+
5
+ def initialize(name)
6
+ @name = name
7
+ @hosts = {}
8
+ end
9
+
10
+ def disable!
11
+ hosts.each { |h| h.disable! }
12
+ end
13
+
14
+ def enable!
15
+ hosts.each { |h| h.enable! }
16
+ end
17
+
18
+ def disabled?
19
+ hosts.all? { |h| h.disabled? }
20
+ end
21
+
22
+ def enabled?
23
+ hosts.all? { |h| h.enabled? }
24
+ end
25
+
26
+ def hosts
27
+ @hosts.values
28
+ end
29
+
30
+ def <<(host)
31
+ @hosts[host.hostname] = host
32
+ end
33
+
34
+ def [](hostname)
35
+ @hosts[hostname]
36
+ end
37
+
38
+ def find_host(entry)
39
+ if entry =~ Host::IP_PATTERN
40
+ hosts.select { |h| h.ip_address == entry }
41
+ else
42
+ hosts.select { |h| h.hostname == entry }
43
+ end
44
+ end
45
+
46
+ def delete_host(entry)
47
+ deleted = []
48
+ if entry =~ Host::IP_PATTERN
49
+ @hosts.each { |k, h| deleted << @hosts.delete(k) if h.ip_address == entry }
50
+ else
51
+ @hosts.each { |k, h| deleted << @hosts.delete(k) if h.hostname == entry }
52
+ end
53
+
54
+ deleted
55
+ end
56
+
57
+ def to_cli
58
+ string = " - \033[4m#{name}\033[0m\n"
59
+ max = hosts.map { |h| h.hostname.size }.max
60
+
61
+ hosts.each do |host|
62
+ padding = ' ' * (max - host.hostname.size + 4)
63
+ if host.disabled?
64
+ string << " \033[31m \u00D7 "
65
+ else
66
+ string << ' '
67
+ end
68
+ string << "#{host.hostname}#{padding}#{host.ip_address}\033[0m\n"
69
+ end
70
+
71
+ string
72
+ end
73
+
74
+ def to_hosts_file
75
+ max = hosts.map { |h| h.ip_address.size }.max
76
+ section = "## [#{name}]\n"
77
+
78
+ hosts.each do |host|
79
+ padding = ' ' * (max - host.ip_address.size + 4)
80
+ section << '# ' if host.disabled?
81
+ section << "#{host.ip_address}#{padding}#{host.hostname}\n"
82
+ end
83
+
84
+ section
85
+ end
86
+
87
+ end
88
+ end
data/lib/roast/host.rb ADDED
@@ -0,0 +1,37 @@
1
+ module Roast
2
+ class Host
3
+ IP_PATTERN = /\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/
4
+ HOST_PATTERN = /\A[a-z0-9\-\.]+\z/
5
+
6
+ attr_reader :ip_address
7
+ attr_reader :hostname
8
+
9
+ def initialize(ip_address, hostname)
10
+ @ip_address = ip_address.chomp
11
+ @hostname = hostname.chomp.downcase
12
+ @state = 'enabled'
13
+ validate!
14
+ end
15
+
16
+ def validate!
17
+ raise ArgumentError, "`#{ip_address}' is an invalid ip address" unless ip_address =~ IP_PATTERN
18
+ raise ArgumentError, "`#{hostname}' is an invalid hostname" unless hostname =~ HOST_PATTERN
19
+ end
20
+
21
+ def disable!
22
+ @state = 'disabled'
23
+ end
24
+
25
+ def enable!
26
+ @state = 'enabled'
27
+ end
28
+
29
+ def disabled?
30
+ @state == 'disabled'
31
+ end
32
+
33
+ def enabled?
34
+ @state == 'enabled'
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,128 @@
1
+ module Roast
2
+ class HostsFile
3
+ GROUP_PATTERN = /^## \[([\w\s-]+)\]$/
4
+ HOST_PATTERN = /^#?\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+([^\s]+)/
5
+ DISABLED_PATTERN = /^# \d+/
6
+
7
+ attr_reader :path
8
+ attr_reader :static_lines
9
+
10
+ def initialize(path = '/etc/hosts')
11
+ @path = path
12
+ @static_lines = []
13
+ @groups = {}
14
+ end
15
+
16
+ def groups
17
+ @groups.values
18
+ end
19
+
20
+ def hosts
21
+ groups.map { |g| g.hosts }.flatten
22
+ end
23
+
24
+ def [](group)
25
+ @groups[group]
26
+ end
27
+
28
+ def read
29
+ in_group = false
30
+ group = nil
31
+
32
+ File.open(path, 'r') do |file|
33
+ file.each_line do |line|
34
+ if group_match = line.match(GROUP_PATTERN)
35
+ in_group = true
36
+ group = Group.new(group_match[1])
37
+ @groups[group.name] ||= group
38
+ elsif group && host_match = line.match(HOST_PATTERN)
39
+ host = Host.new(host_match[1], host_match[2])
40
+ host.disable! if line =~ DISABLED_PATTERN
41
+ group << host
42
+ else
43
+ static_lines << line
44
+ end
45
+ end
46
+ end
47
+
48
+ self
49
+ end
50
+
51
+ def write(output_path = nil)
52
+ output_path = output_path || path
53
+ temp_file = Tempfile.new('hosts')
54
+
55
+ temp_file << static_lines.join.sub(/\n{3,}\z/, "\n\n")
56
+ temp_file << groups.map { |g| g.to_hosts_file.chomp }.join("\n\n")
57
+
58
+ File.chmod(0644, temp_file)
59
+ FileUtils.cp(path, path + '.bak') if output_path.eql?(path)
60
+ FileUtils.mv(temp_file.path, output_path, :force => true)
61
+ ensure
62
+ temp_file.close
63
+ temp_file.unlink
64
+ end
65
+
66
+ def find_host(entry)
67
+ groups.map { |g| g.find_host(entry) }.flatten
68
+ end
69
+
70
+ def delete_host(entry)
71
+ groups.map { |g| g.delete_host(entry) }.flatten
72
+ end
73
+
74
+ def add(group, ip_address, hostname)
75
+ @groups[group] ||= Group.new(group)
76
+ @groups[group] << Host.new(ip_address, hostname)
77
+ end
78
+
79
+ def enable(entry)
80
+ results = find_host(entry)
81
+
82
+ results.each { |h| h.enable! }
83
+ results
84
+ end
85
+
86
+ def disable(entry)
87
+ results = find_host(entry)
88
+
89
+ results.each { |h| h.disable! }
90
+ results
91
+ end
92
+
93
+ def delete(entry)
94
+ results = delete_host(entry)
95
+
96
+ results
97
+ end
98
+
99
+ def enable_group(group)
100
+ return false unless @groups.has_key?(group)
101
+
102
+ @groups[group].enable!
103
+
104
+ true
105
+ end
106
+
107
+ def disable_group(group)
108
+ return false unless @groups.has_key?(group)
109
+
110
+ @groups[group].disable!
111
+
112
+ true
113
+ end
114
+
115
+ def delete_group(group)
116
+ return false unless @groups.has_key?(group)
117
+
118
+ @groups.delete(group)
119
+
120
+ true
121
+ end
122
+
123
+ def list
124
+ [path, groups]
125
+ end
126
+
127
+ end
128
+ end
@@ -0,0 +1,3 @@
1
+ module Roast
2
+ VERSION = '0.1.0'
3
+ end
data/lib/roast.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'fileutils'
2
+ require 'optparse'
3
+ require 'tempfile'
4
+
5
+ require 'roast/cli/commands'
6
+ require 'roast/cli'
7
+ require 'roast/group'
8
+ require 'roast/host'
9
+ require 'roast/hosts_file'
10
+ require 'roast/version'
11
+
12
+ module Roast
13
+
14
+ end
data/roast.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'roast/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "roast"
8
+ spec.version = Roast::VERSION
9
+ spec.authors = ["blahed"]
10
+ spec.email = ["tdunn13@gmail.com"]
11
+ spec.description = "Roast is a simple /etc/hosts entry manager"
12
+ spec.summary = "Roast helps you group and manage entries in your hosts file"
13
+ spec.homepage = "https://github.com/blahed/roast/"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'minitest', '~> 3.0.0'
23
+ spec.add_development_dependency 'rake'
24
+ end
data/test/files/one ADDED
@@ -0,0 +1,22 @@
1
+ 127.0.0.1 localhost
2
+ 255.255.255.255 broadcasthost
3
+
4
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
5
+ 10.0.1.1 example.dev
6
+
7
+ ::1 localhost
8
+ fe80::1%lo0 localhost
9
+
10
+ ## [base]
11
+ 127.0.0.1 local.dev
12
+ 10.0.1.2 something.dev
13
+ 127.0.0.1 example.org
14
+
15
+ ## [foo]
16
+ # 10.0.3.1 foo.bar
17
+ # 10.0.3.2 food.bar
18
+
19
+ ## [staging]
20
+ 10.0.20.1 staging.something.com
21
+ 10.0.20.2 staging-two.something.com
22
+ # 10.10.30.1 staging.three.something.com
@@ -0,0 +1,82 @@
1
+ require 'test_helper'
2
+
3
+ describe Roast::Group do
4
+
5
+ before do
6
+ @group = Roast::Group.new(:base)
7
+ @group << Roast::Host.new('127.0.0.1', 'foo.bar.dev')
8
+ @group << Roast::Host.new('10.0.1.1', 'example.org')
9
+ end
10
+
11
+ it "adds a host to the group" do
12
+ host = Roast::Host.new('127.0.0.1', 'something.dev')
13
+ @group << host
14
+ @group.hosts.include?(host).must_equal true
15
+ end
16
+
17
+ it "disables and enables all hosts in the group" do
18
+ @group.disable!
19
+ @group.must_be :disabled?
20
+ @group.hosts.all? { |h| h.disabled? }.must_equal true
21
+
22
+ @group.enable!
23
+ @group.must_be :enabled?
24
+ @group.hosts.all? { |h| h.enabled? }.must_equal true
25
+ end
26
+
27
+ it "finds hosts by ip address" do
28
+ results = @group.find_host('127.0.0.1')
29
+ results.wont_be :empty?
30
+ results.size.must_equal 1
31
+ results.first.must_equal @group.hosts.first
32
+ end
33
+
34
+ it "finds hosts by hostname" do
35
+ results = @group.find_host('example.org')
36
+ results.wont_be :empty?
37
+ results.size.must_equal 1
38
+ results.first.must_equal @group.hosts.last
39
+ end
40
+
41
+ it "deletes hosts by ip address" do
42
+ deleted = @group.hosts.first
43
+ results = @group.delete_host('127.0.0.1')
44
+ results.wont_be :empty?
45
+ results.size.must_equal 1
46
+ results.first.must_equal deleted
47
+ @group.hosts.size.must_equal 1
48
+ @group.hosts.include?(deleted).wont_equal true
49
+ end
50
+
51
+ it "deletes hosts by hostname" do
52
+ deleted = @group.hosts.last
53
+ results = @group.delete_host('example.org')
54
+ results.wont_be :empty?
55
+ results.size.must_equal 1
56
+ results.first.must_equal deleted
57
+ @group.hosts.size.must_equal 1
58
+ @group.hosts.include?(deleted).wont_equal true
59
+ end
60
+
61
+ it "returns an empty array if host could not be found" do
62
+ results = @group.find_host('something.else')
63
+ results.must_be :empty?
64
+ end
65
+
66
+ it "outputs host entries to cli correctly" do
67
+ @group.to_cli.must_equal <<-RESULT.gsub(/^\s{4}/, "")
68
+ - \e[4mbase\e[0m
69
+ foo.bar.dev 127.0.0.1\e[0m
70
+ example.org 10.0.1.1\e[0m
71
+ RESULT
72
+ end
73
+
74
+ it "converts the group to a string correctly" do
75
+ @group.to_hosts_file.must_equal <<-RESULT.gsub(/^\s+/, "")
76
+ ## [base]
77
+ 127.0.0.1 foo.bar.dev
78
+ 10.0.1.1 example.org
79
+ RESULT
80
+ end
81
+
82
+ end
data/test/host_test.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ describe Roast::Host do
4
+
5
+ it "validates the ip address" do
6
+ ['foo', 'example.com', '127.0.0.1.1', '1277.0.0.1'].each do |ip|
7
+ lambda { Roast::Host.new(ip, 'blah.dev') }.must_raise ArgumentError
8
+ end
9
+ end
10
+
11
+ it "validates the hostname" do
12
+ ['foo_com', '@#$asdf.com'].each do |hostname|
13
+ lambda { Roast::Host.new('127.0.0.1', hostname) }.must_raise ArgumentError
14
+ end
15
+ end
16
+
17
+
18
+ end
@@ -0,0 +1,411 @@
1
+ require 'test_helper'
2
+
3
+ describe Roast::HostsFile do
4
+ FILES_PATH = File.expand_path("../files", __FILE__)
5
+
6
+ after do
7
+ baks = Dir[File.join(FILES_PATH, '*.bak')]
8
+ news = Dir[File.join(FILES_PATH, '*.new')]
9
+ FileUtils.rm(baks)
10
+ FileUtils.rm(news)
11
+ end
12
+
13
+ it "parses a hostfile and creates groups and host entries" do
14
+ hosts = hosts_from_file('one')
15
+ hosts.groups.length.must_equal 3
16
+ [
17
+ [ '127.0.0.1', 'local.dev' ],
18
+ [ '10.0.1.2', 'something.dev' ]
19
+ ].each_with_index do |host, i|
20
+ hosts['base'].hosts[i].ip_address.must_equal host.first
21
+ hosts['base'].hosts[i].hostname.must_equal host.last
22
+ end
23
+ [
24
+ [ '10.0.20.1', 'staging.something.com' ],
25
+ [ '10.0.20.2', 'staging-two.something.com' ]
26
+ ].each_with_index do |host, i|
27
+ hosts['staging'].hosts[i].ip_address.must_equal host.first
28
+ hosts['staging'].hosts[i].hostname.must_equal host.last
29
+ end
30
+ end
31
+
32
+ it "adds entries to an existing group" do
33
+ hosts = hosts_from_file('one')
34
+ new_path = File.join(FILES_PATH, 'one.new')
35
+ hosts.groups.length.must_equal 3
36
+ hosts.add('staging', '10.0.1.1', 'added-entry.dev')
37
+ hosts.write(new_path)
38
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
39
+ 127.0.0.1 localhost
40
+ 255.255.255.255 broadcasthost
41
+
42
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
43
+ 10.0.1.1 example.dev
44
+
45
+ ::1 localhost
46
+ fe80::1%lo0 localhost
47
+
48
+ ## [base]
49
+ 127.0.0.1 local.dev
50
+ 10.0.1.2 something.dev
51
+ 127.0.0.1 example.org
52
+
53
+ ## [foo]
54
+ # 10.0.3.1 foo.bar
55
+ # 10.0.3.2 food.bar
56
+
57
+ ## [staging]
58
+ 10.0.20.1 staging.something.com
59
+ 10.0.20.2 staging-two.something.com
60
+ # 10.10.30.1 staging.three.something.com
61
+ 10.0.1.1 added-entry.dev
62
+ RESULT
63
+ end
64
+
65
+ it "adds a new entry and group if the group doesn't exist" do
66
+ hosts = hosts_from_file('one')
67
+ new_path = File.join(FILES_PATH, 'one.new')
68
+
69
+ hosts.groups.length.must_equal 3
70
+ hosts.add('testing', '10.0.30.1', 'something.testing')
71
+ hosts.write(new_path)
72
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
73
+ 127.0.0.1 localhost
74
+ 255.255.255.255 broadcasthost
75
+
76
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
77
+ 10.0.1.1 example.dev
78
+
79
+ ::1 localhost
80
+ fe80::1%lo0 localhost
81
+
82
+ ## [base]
83
+ 127.0.0.1 local.dev
84
+ 10.0.1.2 something.dev
85
+ 127.0.0.1 example.org
86
+
87
+ ## [foo]
88
+ # 10.0.3.1 foo.bar
89
+ # 10.0.3.2 food.bar
90
+
91
+ ## [staging]
92
+ 10.0.20.1 staging.something.com
93
+ 10.0.20.2 staging-two.something.com
94
+ # 10.10.30.1 staging.three.something.com
95
+
96
+ ## [testing]
97
+ 10.0.30.1 something.testing
98
+ RESULT
99
+ end
100
+
101
+ it "disables an entry via hostname" do
102
+ hosts = hosts_from_file('one')
103
+ new_path = File.join(FILES_PATH, 'one.new')
104
+
105
+ hosts.groups.length.must_equal 3
106
+ hosts.disable('local.dev')
107
+ hosts.write(new_path)
108
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
109
+ 127.0.0.1 localhost
110
+ 255.255.255.255 broadcasthost
111
+
112
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
113
+ 10.0.1.1 example.dev
114
+
115
+ ::1 localhost
116
+ fe80::1%lo0 localhost
117
+
118
+ ## [base]
119
+ # 127.0.0.1 local.dev
120
+ 10.0.1.2 something.dev
121
+ 127.0.0.1 example.org
122
+
123
+ ## [foo]
124
+ # 10.0.3.1 foo.bar
125
+ # 10.0.3.2 food.bar
126
+
127
+ ## [staging]
128
+ 10.0.20.1 staging.something.com
129
+ 10.0.20.2 staging-two.something.com
130
+ # 10.10.30.1 staging.three.something.com
131
+ RESULT
132
+ end
133
+
134
+ it "disables entries via ip address" do
135
+ hosts = hosts_from_file('one')
136
+ new_path = File.join(FILES_PATH, 'one.new')
137
+
138
+ hosts.groups.length.must_equal 3
139
+ hosts.disable('127.0.0.1')
140
+ hosts.write(new_path)
141
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
142
+ 127.0.0.1 localhost
143
+ 255.255.255.255 broadcasthost
144
+
145
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
146
+ 10.0.1.1 example.dev
147
+
148
+ ::1 localhost
149
+ fe80::1%lo0 localhost
150
+
151
+ ## [base]
152
+ # 127.0.0.1 local.dev
153
+ 10.0.1.2 something.dev
154
+ # 127.0.0.1 example.org
155
+
156
+ ## [foo]
157
+ # 10.0.3.1 foo.bar
158
+ # 10.0.3.2 food.bar
159
+
160
+ ## [staging]
161
+ 10.0.20.1 staging.something.com
162
+ 10.0.20.2 staging-two.something.com
163
+ # 10.10.30.1 staging.three.something.com
164
+ RESULT
165
+ end
166
+
167
+ it "enables an entry via hostname" do
168
+ hosts = hosts_from_file('one')
169
+ new_path = File.join(FILES_PATH, 'one.new')
170
+
171
+ hosts.groups.length.must_equal 3
172
+ hosts.enable('staging.three.something.com')
173
+ hosts.write(new_path)
174
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
175
+ 127.0.0.1 localhost
176
+ 255.255.255.255 broadcasthost
177
+
178
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
179
+ 10.0.1.1 example.dev
180
+
181
+ ::1 localhost
182
+ fe80::1%lo0 localhost
183
+
184
+ ## [base]
185
+ 127.0.0.1 local.dev
186
+ 10.0.1.2 something.dev
187
+ 127.0.0.1 example.org
188
+
189
+ ## [foo]
190
+ # 10.0.3.1 foo.bar
191
+ # 10.0.3.2 food.bar
192
+
193
+ ## [staging]
194
+ 10.0.20.1 staging.something.com
195
+ 10.0.20.2 staging-two.something.com
196
+ 10.10.30.1 staging.three.something.com
197
+ RESULT
198
+ end
199
+
200
+ it "enables an entry via ip address" do
201
+ hosts = hosts_from_file('one')
202
+ new_path = File.join(FILES_PATH, 'one.new')
203
+
204
+ hosts.groups.length.must_equal 3
205
+ hosts.enable('10.10.30.1')
206
+ hosts.write(new_path)
207
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
208
+ 127.0.0.1 localhost
209
+ 255.255.255.255 broadcasthost
210
+
211
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
212
+ 10.0.1.1 example.dev
213
+
214
+ ::1 localhost
215
+ fe80::1%lo0 localhost
216
+
217
+ ## [base]
218
+ 127.0.0.1 local.dev
219
+ 10.0.1.2 something.dev
220
+ 127.0.0.1 example.org
221
+
222
+ ## [foo]
223
+ # 10.0.3.1 foo.bar
224
+ # 10.0.3.2 food.bar
225
+
226
+ ## [staging]
227
+ 10.0.20.1 staging.something.com
228
+ 10.0.20.2 staging-two.something.com
229
+ 10.10.30.1 staging.three.something.com
230
+ RESULT
231
+ end
232
+
233
+ it "enables a group" do
234
+ hosts = hosts_from_file('one')
235
+ new_path = File.join(FILES_PATH, 'one.new')
236
+
237
+ hosts.groups.length.must_equal 3
238
+ hosts.enable_group('foo')
239
+ hosts.write(new_path)
240
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
241
+ 127.0.0.1 localhost
242
+ 255.255.255.255 broadcasthost
243
+
244
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
245
+ 10.0.1.1 example.dev
246
+
247
+ ::1 localhost
248
+ fe80::1%lo0 localhost
249
+
250
+ ## [base]
251
+ 127.0.0.1 local.dev
252
+ 10.0.1.2 something.dev
253
+ 127.0.0.1 example.org
254
+
255
+ ## [foo]
256
+ 10.0.3.1 foo.bar
257
+ 10.0.3.2 food.bar
258
+
259
+ ## [staging]
260
+ 10.0.20.1 staging.something.com
261
+ 10.0.20.2 staging-two.something.com
262
+ # 10.10.30.1 staging.three.something.com
263
+ RESULT
264
+ end
265
+
266
+ it "disables a group" do
267
+ hosts = hosts_from_file('one')
268
+ new_path = File.join(FILES_PATH, 'one.new')
269
+
270
+ hosts.groups.length.must_equal 3
271
+ hosts.disable_group('staging')
272
+ hosts.write(new_path)
273
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
274
+ 127.0.0.1 localhost
275
+ 255.255.255.255 broadcasthost
276
+
277
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
278
+ 10.0.1.1 example.dev
279
+
280
+ ::1 localhost
281
+ fe80::1%lo0 localhost
282
+
283
+ ## [base]
284
+ 127.0.0.1 local.dev
285
+ 10.0.1.2 something.dev
286
+ 127.0.0.1 example.org
287
+
288
+ ## [foo]
289
+ # 10.0.3.1 foo.bar
290
+ # 10.0.3.2 food.bar
291
+
292
+ ## [staging]
293
+ # 10.0.20.1 staging.something.com
294
+ # 10.0.20.2 staging-two.something.com
295
+ # 10.10.30.1 staging.three.something.com
296
+ RESULT
297
+ end
298
+
299
+ it "deletes an entry via hostname" do
300
+ hosts = hosts_from_file('one')
301
+ new_path = File.join(FILES_PATH, 'one.new')
302
+
303
+ hosts.groups.length.must_equal 3
304
+ hosts.delete('local.dev')
305
+ hosts.write(new_path)
306
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
307
+ 127.0.0.1 localhost
308
+ 255.255.255.255 broadcasthost
309
+
310
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
311
+ 10.0.1.1 example.dev
312
+
313
+ ::1 localhost
314
+ fe80::1%lo0 localhost
315
+
316
+ ## [base]
317
+ 10.0.1.2 something.dev
318
+ 127.0.0.1 example.org
319
+
320
+ ## [foo]
321
+ # 10.0.3.1 foo.bar
322
+ # 10.0.3.2 food.bar
323
+
324
+ ## [staging]
325
+ 10.0.20.1 staging.something.com
326
+ 10.0.20.2 staging-two.something.com
327
+ # 10.10.30.1 staging.three.something.com
328
+ RESULT
329
+ end
330
+
331
+ it "deletes entries via ip address" do
332
+ hosts = hosts_from_file('one')
333
+ new_path = File.join(FILES_PATH, 'one.new')
334
+
335
+ hosts.groups.length.must_equal 3
336
+ hosts.delete('127.0.0.1')
337
+ hosts.write(new_path)
338
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
339
+ 127.0.0.1 localhost
340
+ 255.255.255.255 broadcasthost
341
+
342
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
343
+ 10.0.1.1 example.dev
344
+
345
+ ::1 localhost
346
+ fe80::1%lo0 localhost
347
+
348
+ ## [base]
349
+ 10.0.1.2 something.dev
350
+
351
+ ## [foo]
352
+ # 10.0.3.1 foo.bar
353
+ # 10.0.3.2 food.bar
354
+
355
+ ## [staging]
356
+ 10.0.20.1 staging.something.com
357
+ 10.0.20.2 staging-two.something.com
358
+ # 10.10.30.1 staging.three.something.com
359
+ RESULT
360
+ end
361
+
362
+ it "deletes a group" do
363
+ hosts = hosts_from_file('one')
364
+ new_path = File.join(FILES_PATH, 'one.new')
365
+
366
+ hosts.groups.length.must_equal 3
367
+ hosts.delete_group('staging')
368
+ hosts.write(new_path)
369
+ File.read(new_path).must_equal <<-RESULT.gsub(/^ +/, "").chomp
370
+ 127.0.0.1 localhost
371
+ 255.255.255.255 broadcasthost
372
+
373
+ 127.0.0.1 hl2rcv.adobe.com # HEHE
374
+ 10.0.1.1 example.dev
375
+
376
+ ::1 localhost
377
+ fe80::1%lo0 localhost
378
+
379
+ ## [base]
380
+ 127.0.0.1 local.dev
381
+ 10.0.1.2 something.dev
382
+ 127.0.0.1 example.org
383
+
384
+ ## [foo]
385
+ # 10.0.3.1 foo.bar
386
+ # 10.0.3.2 food.bar
387
+ RESULT
388
+ end
389
+
390
+ it "does not create a backup file if the output file is a different name" do
391
+ hosts = hosts_from_file('one')
392
+ hosts.groups.length.must_equal 3
393
+ hosts['base'] << Roast::Host.new('127.0.0.1', 'example.org')
394
+ hosts.write(File.join(FILES_PATH, 'two.new'))
395
+ File.exist?(File.join(FILES_PATH, 'one.bak')).wont_equal true
396
+ end
397
+
398
+ it "creates a backup file if the output file is the same as the input file" do
399
+ hosts = hosts_from_file('one')
400
+ hosts.groups.length.must_equal 3
401
+ hosts['base'] << Roast::Host.new('127.0.0.1', 'example.org')
402
+ hosts.write
403
+ File.exist?(File.join(FILES_PATH, 'one.bak')).must_equal true
404
+ end
405
+
406
+ def hosts_from_file(file_name)
407
+ path = File.join(FILES_PATH, file_name)
408
+ @hosts = Roast::HostsFile.new(path).read
409
+ end
410
+
411
+ end
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../../test', __FILE__))
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ Bundler.setup
6
+
7
+ require 'minitest/autorun'
8
+ require 'minitest/pride'
9
+
10
+ require 'roast'
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: roast
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - blahed
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: minitest
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 3.0.0
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 3.0.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
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'
62
+ description: Roast is a simple /etc/hosts entry manager
63
+ email:
64
+ - tdunn13@gmail.com
65
+ executables:
66
+ - roast
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - .gitignore
71
+ - .travis.yml
72
+ - Gemfile
73
+ - LICENSE.txt
74
+ - README.md
75
+ - Rakefile
76
+ - bin/roast
77
+ - lib/roast.rb
78
+ - lib/roast/cli.rb
79
+ - lib/roast/cli/commands.rb
80
+ - lib/roast/group.rb
81
+ - lib/roast/host.rb
82
+ - lib/roast/hosts_file.rb
83
+ - lib/roast/version.rb
84
+ - roast.gemspec
85
+ - test/files/one
86
+ - test/group_test.rb
87
+ - test/host_test.rb
88
+ - test/hosts_file_test.rb
89
+ - test/test_helper.rb
90
+ homepage: https://github.com/blahed/roast/
91
+ licenses:
92
+ - MIT
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 1.8.23
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: Roast helps you group and manage entries in your hosts file
115
+ test_files:
116
+ - test/files/one
117
+ - test/group_test.rb
118
+ - test/host_test.rb
119
+ - test/hosts_file_test.rb
120
+ - test/test_helper.rb