alkesh-ghost 0.2.8

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Bodaniel Jeanes
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,111 @@
1
+ Ghost
2
+ =====
3
+
4
+ A gem that allows you to create, list, and modify local hostnames
5
+ with ease in linux and OS (more to come)...
6
+
7
+ Requirements
8
+ ============
9
+
10
+ Unix-based OS (for now)
11
+
12
+ Intended Usage
13
+ ==============
14
+
15
+ This gem is designed primarily for web developers who need to add
16
+ and modify hostnames to their system for virtual hosts on their
17
+ local/remote web server. However, it could be of use to other people
18
+ who would otherwise modify their `/etc/hosts` file manually and
19
+ flush the cache.
20
+
21
+ Command
22
+ -------
23
+
24
+ $ ghost add mydevsite.local
25
+ [Adding] mydevsite.local -> 127.0.0.1
26
+
27
+ $ ghost add staging-server.local 67.207.136.164
28
+ [Adding] staging-server.local -> 67.207.136.164
29
+
30
+ $ ghost list
31
+ Listing 2 host(s):
32
+ mydevsite.local -> 127.0.0.1
33
+ staging-server.local -> 67.207.136.164
34
+
35
+ $ ghost delete mydevsite.local
36
+ [Deleting] mydevsite.local
37
+
38
+ $ ghost delete_matching test
39
+ [Deleting] test2.local
40
+ [Deleting] test.local
41
+
42
+ $ ghost list
43
+ Listing 1 host(s):
44
+ staging-server.local -> 67.207.136.164
45
+
46
+ $ ghost modify staging-server.local 64.233.167.99
47
+ [Modifying] staging-server.local -> 64.233.167.99
48
+
49
+ $ ghost list
50
+ Listing 1 host(s):
51
+ staging-server.local -> 64.233.167.99
52
+
53
+ $ ghost export > some_file
54
+
55
+ $ ghost empty
56
+ [Emptying] Done.
57
+
58
+ $ ghost list
59
+ Listing 0 host(s):
60
+
61
+ $ ghost import some_file
62
+ [Adding] staging-server.local -> 64.233.167.99
63
+
64
+ $ ghost list
65
+ Listing 1 host(s):
66
+ staging-server.local -> 64.233.167.99
67
+
68
+ Library
69
+ -------
70
+
71
+ There is also a library that can be used in Ruby scripts. The `ghost`
72
+ command is a wrapper for the library. View the source of `bin/ghost`
73
+ to see how to use the library.
74
+
75
+ Installation
76
+ ============
77
+
78
+ sudo gem install ghost
79
+
80
+ Contributors
81
+ ============
82
+
83
+ * [Bodaniel Jeanes](http://github.com/bjeanes)
84
+ * [Ben Hoskings](http://github.com/benhoskings)
85
+ * [Mitchell V Riley](http://github.com/mitchellvriley)
86
+ * [Courtois Simon](http://github.com/simonc)
87
+ * [Justin Mazzi](http://github.com/jmazzi)
88
+
89
+ Legal Stuff
90
+ ===========
91
+
92
+ Copyright (c) 2008-2010 Bodaniel Jeanes
93
+
94
+ Permission is hereby granted, free of charge, to any person obtaining
95
+ a copy of this software and associated documentation files (the
96
+ "Software"), to deal in the Software without restriction, including
97
+ without limitation the rights to use, copy, modify, merge, publish,
98
+ distribute, sublicense, and/or sell copies of the Software, and to
99
+ permit persons to whom the Software is furnished to do so, subject to
100
+ the following conditions:
101
+
102
+ The above copyright notice and this permission notice shall be
103
+ included in all copies or substantial portions of the Software.
104
+
105
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
106
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
107
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
108
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
109
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
110
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
111
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+
6
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
7
+
8
+
9
+ #### MISC TASKS ####
10
+
11
+ desc "list tasks"
12
+ task :default do
13
+ puts `rake -T`.grep(/^[^(].*$/)
14
+ end
15
+
16
+ desc "Outstanding TODO's"
17
+ task :todo do
18
+ files = ["**/*.{rb,rake}" "bin/*", "README.mkdn"]
19
+
20
+ File.open('TODO','w') do |f|
21
+ FileList[*files].egrep(/TODO|FIXME/) do |file, line, text|
22
+ output = "#{file}:#{line} - #{text.chomp.gsub(/^\s+|\s+$/ , "")}"
23
+
24
+ puts output
25
+ f.puts output
26
+ end
27
+ end
28
+ end
data/TODO ADDED
File without changes
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Bodaniel Jeanes on 2008-8-19.
4
+ # Copyright (c) 2008. All rights reserved.
5
+
6
+ begin
7
+ require 'rubygems'
8
+ rescue LoadError
9
+ # no rubygems to load, so we fail silently
10
+ end
11
+ require 'ghost'
12
+
13
+ def help_text(exit_code = 0)
14
+ script_name = File.basename $0
15
+ puts """USAGE: #{script_name} add <hostname> [<ip=127.0.1.1>]
16
+ #{script_name} modify <hostname> <ip> OR <hostname> (will lookup ip)
17
+ #{script_name} delete <hostname>
18
+ #{script_name} delete_matching <pattern>
19
+ #{script_name} list
20
+ #{script_name} empty
21
+ #{script_name} export
22
+ #{script_name} import <file>
23
+ """
24
+ exit(exit_code)
25
+ end
26
+
27
+ if ARGV.size.zero? || ['-h', '--help', 'help'].include?(ARGV.first)
28
+ help_text
29
+ else
30
+ case ARGV[0]
31
+ when 'add'
32
+ if [2,3].include?(ARGV.size)
33
+ begin
34
+ ARGV.shift
35
+ host = Host.add(*ARGV)
36
+ puts " [Adding] #{host.name} -> #{host.ip}"
37
+ exit 0
38
+ rescue SocketError
39
+ $stderr.puts "Cannot find ip for host"
40
+ exit 3
41
+ rescue StandardError
42
+ $stderr.puts "Cannot overwrite an existing entry. Use the modify subcommand"
43
+ exit 3
44
+ end
45
+ else
46
+ $stderr.puts "The add subcommand requires at least a hostname.\n\n"
47
+ help_text 2
48
+ end
49
+ when 'modify'
50
+ if ARGV.size == 3
51
+ ARGV.shift
52
+ ARGV << true
53
+ host = Host.add(*ARGV)
54
+ puts " [Modifying] #{host.name} -> #{host.ip}"
55
+ exit 0
56
+ else
57
+ $stderr.puts "The modify subcommand requires a hostname and an IP.\n\n"
58
+ help_text 4
59
+ end
60
+ when 'delete', 'del', 'remove', 'rm'
61
+ if ARGV.size == 2
62
+ Host.delete(ARGV[1])
63
+ puts " [Deleting] #{ARGV[1]}"
64
+ exit 0
65
+ else
66
+ $stderr.puts "The delete subcommand requires a hostname.\n\n"
67
+ help_text 2
68
+ end
69
+ when 'delete_matching'
70
+ if ARGV.size == 2
71
+ matched = Host.delete_matching(ARGV[1])
72
+ if matched.empty?
73
+ puts " No matching entries found"
74
+ else
75
+ matched.each { |h| puts " [Deleting] #{h}" }
76
+ end
77
+ exit 0
78
+ else
79
+ $stderr.puts "The delete_matching subcommand requires a hostname pattern.\n\n"
80
+ help_text 2
81
+ end
82
+ when 'list'
83
+ hosts = Host.list
84
+ pad = hosts.max{|a,b| a.to_s.length <=> b.to_s.length }.to_s.length
85
+
86
+ puts "Listing #{hosts.size} host(s):"
87
+
88
+ hosts.each do |host|
89
+ puts "#{host.name.rjust(pad+2)} -> #{host.ip}"
90
+ end
91
+ exit 0
92
+ when 'empty'
93
+ print " [Emptying] "
94
+ Host.empty!
95
+ puts "Done."
96
+ exit 0
97
+ when 'export'
98
+ hosts = Host.list
99
+ hosts.each do |host|
100
+ puts "#{host.name} #{host.ip}"
101
+ end
102
+ exit 0
103
+ when 'import'
104
+ if ARGV.size == 2
105
+ begin
106
+ File.foreach(ARGV[1]) do |line|
107
+ host_infos = line.strip.split(' ', 2)
108
+ host = Host.add(*host_infos)
109
+ puts " [Adding] #{host.name} -> #{host.ip}"
110
+ end
111
+ exit 0
112
+ rescue
113
+ $stderr.puts "Cannot import. A problem occured while opening the import file."
114
+ exit 5
115
+ end
116
+ else
117
+ $stderr.puts "The import command requires an input file.\n\n"
118
+ help_text 6
119
+ end
120
+ else
121
+ $stderr.puts "Invalid option: #{ARGV[0]}"
122
+ help_text 1
123
+ end
124
+ end
@@ -0,0 +1,8 @@
1
+ $: << File.dirname(__FILE__)
2
+
3
+ case RUBY_PLATFORM
4
+ when /darwin/
5
+ require 'ghost/mac-host'
6
+ when /linux/
7
+ require 'ghost/linux-host'
8
+ end
@@ -0,0 +1,92 @@
1
+ require 'socket'
2
+
3
+ class Host
4
+ attr_reader :host, :ip
5
+
6
+ def initialize(host, ip)
7
+ @host = host
8
+ @ip = ip
9
+ end
10
+
11
+ def ==(other)
12
+ @host == other.host && @ip = other.ip
13
+ end
14
+
15
+ alias :to_s :host
16
+ alias :name :host
17
+ alias :hostname :host
18
+
19
+ @@hosts_file = '/etc/hosts'
20
+ @@permanent_hosts = [Host.new("localhost", "127.0.0.1"),
21
+ Host.new(`hostname`.chomp, "127.0.0.1")]
22
+ class << self
23
+ protected :new
24
+
25
+ def list
26
+ entries = []
27
+ File.open(@@hosts_file).each do |line|
28
+ next if line =~ /^#/
29
+ if line =~ /^(\d+\.\d+\.\d+\.\d+)\s+(.*)$/
30
+ ip = $1
31
+ hosts = $2.split(/\s+/)
32
+ hosts.each { |host| entries << Host.new(host, ip) }
33
+ end
34
+ end
35
+ entries.delete_if { |host| @@permanent_hosts.include? host }
36
+ entries
37
+ end
38
+
39
+ def add(host, ip = "127.0.0.1", force = false)
40
+ if find_by_host(host).nil? || force
41
+ delete(host)
42
+
43
+ unless ip[/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/]
44
+ ip = Socket.gethostbyname(ip)[3].bytes.to_a.join('.')
45
+ end
46
+
47
+ new_host = Host.new(host, ip)
48
+
49
+ hosts = list
50
+ hosts << new_host
51
+ write_out!(hosts)
52
+
53
+ new_host
54
+ else
55
+ raise "Can not overwrite existing record"
56
+ end
57
+ end
58
+
59
+ def find_by_host(hostname)
60
+ list.find{ |host| host.hostname == hostname }
61
+ end
62
+
63
+ def find_by_ip(ip)
64
+ list.find_all{ |host| host.ip == ip }
65
+ end
66
+
67
+ def empty!
68
+ write_out!([])
69
+ end
70
+
71
+ def delete(name)
72
+ hosts = list
73
+ hosts = hosts.delete_if { |host| host.name == name }
74
+ write_out!(hosts)
75
+ end
76
+
77
+ def delete_matching(pattern)
78
+ pattern = Regexp.escape(pattern)
79
+ hosts = list.select { |host| host.name.match(/#{pattern}/) }
80
+ hosts.each { |host| delete(host.name) }
81
+ hosts
82
+ end
83
+
84
+ protected
85
+
86
+ def write_out!(hosts)
87
+ hosts += @@permanent_hosts
88
+ output = hosts.inject("") {|s, h| s + "#{h.ip} #{h.hostname}\n" }
89
+ File.open(@@hosts_file, 'w') {|f| f.print output }
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,114 @@
1
+ require 'socket'
2
+
3
+ class Host
4
+ ListCmd = "dscl localhost -list /Local/Default/Hosts 2>&1"
5
+ ReadCmd = "dscl localhost -read /Local/Default/Hosts/%s 2>&1"
6
+ CreateCmd = "sudo dscl localhost -create /Local/Default/Hosts/%s IPAddress %s 2>&1"
7
+ DeleteCmd = "sudo dscl localhost -delete /Local/Default/Hosts/%s 2>&1"
8
+
9
+ class << self
10
+ protected :new
11
+
12
+ def list
13
+ list = `#{ListCmd}`
14
+ list = list.split("\n")
15
+ list.collect { |host| Host.new(host.chomp) }
16
+ end
17
+
18
+ def add(host, ip = "127.0.0.1", force = false)
19
+ if find_by_host(host).nil? || force
20
+ unless ip[/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/]
21
+ ip = Socket.gethostbyname(ip)[3].bytes.to_a.join('.')
22
+ end
23
+
24
+ `#{CreateCmd % [host, ip]}`
25
+ flush!
26
+ find_by_host(host)
27
+ else
28
+ raise "Can not overwrite existing record"
29
+ end
30
+ end
31
+
32
+ def find_by_host(host)
33
+ @hosts ||= {}
34
+ @hosts[host] ||= begin
35
+ output = `#{ReadCmd % host}`
36
+
37
+ if output =~ /eDSRecordNotFound/
38
+ nil
39
+ else
40
+ host = parse_host(output)
41
+ ip = parse_ip(output)
42
+
43
+ Host.new(host, ip)
44
+ end
45
+ end
46
+ end
47
+
48
+ def find_by_ip(ip)
49
+ nil
50
+ end
51
+
52
+ def empty!
53
+ list.each { |h| delete(h) }
54
+ nil
55
+ end
56
+
57
+ def delete(host)
58
+ `#{DeleteCmd % host.to_s}`
59
+ flush!
60
+ end
61
+
62
+ def delete_matching(pattern)
63
+ pattern = Regexp.escape(pattern)
64
+ hosts = list.select { |h| h.to_s.match(/#{pattern}/) }
65
+ hosts.each do |h|
66
+ delete(h)
67
+ end
68
+ flush! unless hosts.empty?
69
+ hosts
70
+ end
71
+
72
+ # Flushes the DNS Cache
73
+ def flush!
74
+ `dscacheutil -flushcache`
75
+ @hosts = {}
76
+ true
77
+ end
78
+
79
+ protected
80
+ def parse_host(output)
81
+ parse_value(output, 'RecordName')
82
+ end
83
+
84
+ def parse_ip(output)
85
+ parse_value(output, 'IPAddress')
86
+ end
87
+
88
+ def parse_value(output, key)
89
+ match = output.match(Regexp.new("^#{key}: (.*)$"))
90
+ match[1] unless match.nil?
91
+ end
92
+ end
93
+
94
+ def initialize(host, ip=nil)
95
+ @host = host
96
+ @ip = ip
97
+ end
98
+
99
+ def hostname
100
+ @host
101
+ end
102
+ alias :to_s :hostname
103
+ alias :host :hostname
104
+ alias :name :hostname
105
+
106
+ def ip
107
+ @ip ||= self.class.send(:parse_ip, dump)
108
+ end
109
+
110
+ private
111
+ def dump
112
+ @dump ||= `#{ReadCmd % hostname}`
113
+ end
114
+ end
@@ -0,0 +1,155 @@
1
+ require 'ghost/linux-host'
2
+
3
+ $hosts_file = File.expand_path(File.join(File.dirname(__FILE__), "etc_hosts"))
4
+
5
+ describe Host do
6
+ before(:all) do
7
+ class Host
8
+ @@hosts_file = $hosts_file
9
+ end
10
+ end
11
+ before { `touch #{$hosts_file.inspect}` }
12
+ after { `rm -f #{$hosts_file.inspect}` }
13
+
14
+ it "has an IP" do
15
+ hostname = 'ghost-test-hostname.local'
16
+
17
+ Host.add(hostname)
18
+ host = Host.list.first
19
+ host.ip.should eql('127.0.0.1')
20
+
21
+ Host.empty!
22
+
23
+ ip = '169.254.23.121'
24
+ host = Host.add(hostname, ip)
25
+ host.ip.should eql(ip)
26
+ end
27
+
28
+ it "has a hostname" do
29
+ hostname = 'ghost-test-hostname.local'
30
+
31
+ Host.add(hostname)
32
+ host = Host.list.first
33
+ host.hostname.should eql(hostname)
34
+
35
+ Host.empty!
36
+
37
+ ip = '169.254.23.121'
38
+ Host.add(hostname, ip)
39
+ host.hostname.should eql(hostname)
40
+ end
41
+
42
+ describe ".list" do
43
+ it "returns an array" do
44
+ Host.list.should be_instance_of(Array)
45
+ end
46
+
47
+ it "contains instances of Host" do
48
+ Host.add('ghost-test-hostname.local')
49
+ Host.list.first.should be_instance_of(Host)
50
+ end
51
+
52
+ it "gets all hosts on a single /etc/hosts line" do
53
+ example = "127.0.0.1\tproject_a.local\t\t\tproject_b.local project_c.local"
54
+ File.open($hosts_file, 'w') {|f| f << example}
55
+ hosts = Host.list
56
+ hosts.should have(3).items
57
+ hosts.map{|h|h.ip}.uniq.should == ['127.0.0.1']
58
+ hosts.map{|h|h.host}.sort.should == %w[project_a.local project_b.local project_c.local]
59
+ Host.add("project_d.local")
60
+ Host.list.should have(4).items
61
+ end
62
+ end
63
+
64
+ describe "#to_s" do
65
+ it "returns hostname" do
66
+ hostname = 'ghost-test-hostname.local'
67
+
68
+ Host.add(hostname)
69
+ host = Host.list.first
70
+ host.to_s.should eql(hostname)
71
+ end
72
+ end
73
+
74
+ describe "finder methods" do
75
+ before do
76
+ Host.add('abc.local')
77
+ Host.add('def.local')
78
+ Host.add('efg.local', '10.2.2.4')
79
+ end
80
+
81
+ it "returns valid Host when searching for host name" do
82
+ Host.find_by_host('abc.local').should be_instance_of(Host)
83
+ end
84
+ end
85
+
86
+ describe ".add" do
87
+ it "returns Host object when passed hostname" do
88
+ Host.add('ghost-test-hostname.local').should be_instance_of(Host)
89
+ end
90
+
91
+ it "returns Host object when passed hostname" do
92
+ Host.add('ghost-test-hostname.local', '10.0.0.2').should be_instance_of(Host)
93
+ end
94
+
95
+ it "raises error if hostname already exists and not add a duplicate" do
96
+ Host.empty!
97
+ Host.add('ghost-test-hostname.local')
98
+ lambda { Host.add('ghost-test-hostname.local') }.should raise_error
99
+ Host.list.should have(1).thing
100
+ end
101
+
102
+ it "overwrites existing hostname if forced" do
103
+ hostname = 'ghost-test-hostname.local'
104
+
105
+ Host.empty!
106
+ Host.add(hostname)
107
+
108
+ Host.list.first.hostname.should eql(hostname)
109
+ Host.list.first.ip.should eql('127.0.0.1')
110
+
111
+ Host.add(hostname, '10.0.0.1', true)
112
+ Host.list.first.hostname.should eql(hostname)
113
+ Host.list.first.ip.should eql('10.0.0.1')
114
+
115
+ Host.list.should have(1).thing
116
+ end
117
+
118
+ it "should add a hostname using second hostname's ip" do
119
+ hostname = 'ghost-test-hostname.local'
120
+ alias_hostname = 'ghost-test-alias-hostname.local'
121
+
122
+ Host.empty!
123
+
124
+ Host.add(hostname)
125
+ Host.add(alias_hostname, hostname)
126
+
127
+ Host.list.last.ip.should eql(Host.list.first.ip)
128
+ end
129
+
130
+ it "should raise SocketError if it can't find hostname's ip" do
131
+ Host.empty!
132
+ lambda { Host.add('ghost-test-alias-hostname.google', 'google') }.should raise_error(SocketError)
133
+ end
134
+ end
135
+
136
+ describe ".empty!" do
137
+ it "empties the hostnames" do
138
+ Host.add('ghost-test-hostname.local') # add a hostname to be sure
139
+ Host.empty!
140
+ Host.list.should have(0).things
141
+ end
142
+ end
143
+
144
+ describe ".delete_matching" do
145
+ it "deletes matching hostnames" do
146
+ keep = 'ghost-test-hostname-keep.local'
147
+ Host.add(keep)
148
+ Host.add('ghost-test-hostname-match1.local')
149
+ Host.add('ghost-test-hostname-match2.local')
150
+ Host.delete_matching('match')
151
+ Host.list.should have(1).thing
152
+ Host.list.first.hostname.should eql(keep)
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,151 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'ghost'
3
+
4
+ # Warning: these tests will delete all hostnames in the system. Please back them up first
5
+
6
+ Host.empty!
7
+
8
+ describe Host, ".list" do
9
+ after(:each) { Host.empty! }
10
+
11
+ it "should return an array" do
12
+ Host.list.should be_instance_of(Array)
13
+ end
14
+
15
+ it "should contain instances of Host" do
16
+ Host.add('ghost-test-hostname.local')
17
+ Host.list.first.should be_instance_of(Host)
18
+ end
19
+ end
20
+
21
+ describe Host do
22
+ after(:each) { Host.empty! }
23
+
24
+ it "should have an IP" do
25
+ hostname = 'ghost-test-hostname.local'
26
+
27
+ Host.add(hostname)
28
+ host = Host.list.first
29
+ host.ip.should eql('127.0.0.1')
30
+
31
+ Host.empty!
32
+
33
+ ip = '169.254.23.121'
34
+ host = Host.add(hostname, ip)
35
+ host.ip.should eql(ip)
36
+ end
37
+
38
+ it "should have a hostname" do
39
+ hostname = 'ghost-test-hostname.local'
40
+
41
+ Host.add(hostname)
42
+ host = Host.list.first
43
+ host.hostname.should eql(hostname)
44
+
45
+ Host.empty!
46
+
47
+ ip = '169.254.23.121'
48
+ Host.add(hostname, ip)
49
+ host.hostname.should eql(hostname)
50
+ end
51
+
52
+ it ".to_s should return hostname" do
53
+ hostname = 'ghost-test-hostname.local'
54
+
55
+ Host.add(hostname)
56
+ host = Host.list.first
57
+ host.to_s.should eql(hostname)
58
+ end
59
+ end
60
+
61
+ describe Host, "finder methods" do
62
+ after(:all) { Host.empty! }
63
+ before(:all) do
64
+ Host.add('abc.local')
65
+ Host.add('def.local')
66
+ Host.add('efg.local', '10.2.2.4')
67
+ end
68
+
69
+ it "should return valid Host when searching for host name" do
70
+ Host.find_by_host('abc.local').should be_instance_of(Host)
71
+ end
72
+
73
+ end
74
+
75
+ describe Host, ".add" do
76
+ after(:each) { Host.empty! }
77
+
78
+ it "should return Host object when passed hostname" do
79
+ Host.add('ghost-test-hostname.local').should be_instance_of(Host)
80
+ end
81
+
82
+ it "should return Host object when passed hostname" do
83
+ Host.add('ghost-test-hostname.local', '10.0.0.2').should be_instance_of(Host)
84
+ end
85
+
86
+ it "should raise error if hostname already exists and not add a duplicate" do
87
+ Host.empty!
88
+ Host.add('ghost-test-hostname.local')
89
+ lambda { Host.add('ghost-test-hostname.local') }.should raise_error
90
+ Host.list.should have(1).thing
91
+ end
92
+
93
+ it "should overwrite existing hostname if forced" do
94
+ hostname = 'ghost-test-hostname.local'
95
+
96
+ Host.empty!
97
+ Host.add(hostname)
98
+
99
+ Host.list.first.hostname.should eql(hostname)
100
+ Host.list.first.ip.should eql('127.0.0.1')
101
+
102
+ Host.add(hostname, '10.0.0.1', true)
103
+ Host.list.first.hostname.should eql(hostname)
104
+ Host.list.first.ip.should eql('10.0.0.1')
105
+
106
+ Host.list.should have(1).thing
107
+ end
108
+
109
+ it "should add a hostname using second hostname's ip" do
110
+ hostname = 'ghost-test-hostname.local'
111
+ alias_hostname = 'ghost-test-alias-hostname.local'
112
+
113
+ Host.empty!
114
+
115
+ Host.add(hostname)
116
+ Host.add(alias_hostname, hostname)
117
+
118
+ Host.list.last.ip.should eql(Host.list.first.ip)
119
+ end
120
+
121
+ it "should raise SocketError if it can't find hostname's ip" do
122
+ Host.empty!
123
+ lambda { Host.add('ghost-test-alias-hostname.google', 'google') }.should raise_error(SocketError)
124
+ end
125
+ end
126
+
127
+ describe Host, ".empty!" do
128
+ it "should empty the hostnames" do
129
+ Host.add('ghost-test-hostname.local') # add a hostname to be sure
130
+ Host.empty!
131
+ Host.list.should have(0).things
132
+ end
133
+ end
134
+
135
+ describe Host, ".delete_matching" do
136
+ it "should delete matching hostnames" do
137
+ keep = 'ghost-test-hostname-keep.local'
138
+ Host.add(keep)
139
+ Host.add('ghost-test-hostname-match1.local')
140
+ Host.add('ghost-test-hostname-match2.local')
141
+ Host.delete_matching('match')
142
+ Host.list.should have(1).thing
143
+ Host.list.first.hostname.should eql(keep)
144
+ end
145
+ end
146
+
147
+
148
+ describe Host, ".backup and", Host, ".restore" do
149
+ it "should return a yaml file of all hosts and IPs when backing up"
150
+ it "should empty the hosts and restore only the ones in given yaml"
151
+ end
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,4 @@
1
+ $TESTING=true
2
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'rubygems'
4
+ require 'spec'
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alkesh-ghost
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 8
9
+ version: 0.2.8
10
+ platform: ruby
11
+ authors:
12
+ - Bodaniel Jeanes
13
+ autorequire: ghost
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-21 00:00:00 +01:00
18
+ default_executable: ghost
19
+ dependencies: []
20
+
21
+ description: Allows you to create, list, and modify local hostnames
22
+ email: me@bjeanes.com
23
+ executables:
24
+ - ghost
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README
29
+ - LICENSE
30
+ - TODO
31
+ files:
32
+ - LICENSE
33
+ - README
34
+ - Rakefile
35
+ - TODO
36
+ - bin/ghost
37
+ - lib/ghost/linux-host.rb
38
+ - lib/ghost/mac-host.rb
39
+ - lib/ghost.rb
40
+ - spec/etc_hosts_spec.rb
41
+ - spec/ghost_spec.rb
42
+ - spec/spec.opts
43
+ - spec/spec_helper.rb
44
+ has_rdoc: true
45
+ homepage: http://github.com/bjeanes/ghost
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options:
50
+ - --line-numbers
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ requirements: []
68
+
69
+ rubyforge_project: ghost
70
+ rubygems_version: 1.3.6
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Allows you to create, list, and modify local hostnames
74
+ test_files: []
75
+