Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #33 from TheDeveloper/unique-hostnames

Set and purge methods for hosts file store
  • Loading branch information...
commit 5e25106b104248d8f3621e5056daad12370d6b0c 2 parents 8235c68 + 95c016d
@bjeanes authored
View
4 ghost.gemspec
@@ -10,13 +10,13 @@ Gem::Specification.new do |s|
s.description = "Allows you to create, list, and modify local hostnames on POSIX systems (e.g. Mac OS X and Linux) and Windows"
s.email = "me@bjeanes.com"
s.executables = ["ghost"]
- s.files = ["LICENSE", "README.md", "bin/ghost", "lib/ghost", "lib/ghost/cli", "lib/ghost/cli/task", "lib/ghost/cli/task/add.rb", "lib/ghost/cli/task/delete.rb", "lib/ghost/cli/task/empty.rb", "lib/ghost/cli/task/export.rb", "lib/ghost/cli/task/help.rb", "lib/ghost/cli/task/import.rb", "lib/ghost/cli/task/list.rb", "lib/ghost/cli/task.rb", "lib/ghost/cli.rb", "lib/ghost/host.rb", "lib/ghost/store", "lib/ghost/store/dscl_store.rb", "lib/ghost/store/hosts_file_store.rb", "lib/ghost/store.rb", "lib/ghost/tokenized_file.rb", "lib/ghost/version.rb", "lib/ghost.rb", "spec/cli", "spec/ghost", "spec/ghost/cli", "spec/ghost/cli/task", "spec/ghost/cli/task/add_spec.rb", "spec/ghost/cli/task/delete_spec.rb", "spec/ghost/cli/task/empty_spec.rb", "spec/ghost/cli/task/export_spec.rb", "spec/ghost/cli/task/help_spec.rb", "spec/ghost/cli/task/import_spec.rb", "spec/ghost/cli/task/list_spec.rb", "spec/ghost/cli_spec.rb", "spec/ghost/host_spec.rb", "spec/ghost/store", "spec/ghost/store/dscl_store_spec.rb", "spec/ghost/store/hosts_file_store_spec.rb", "spec/ghost/store_spec.rb", "spec/ghost/tokenized_file_spec.rb", "spec/spec_helper.rb", "spec/support", "spec/support/cli.rb", "spec/support/resolv.rb"]
+ s.files = ["LICENSE", "README.md", "bin/ghost", "lib/ghost", "lib/ghost/cli", "lib/ghost/cli/task", "lib/ghost/cli/task/add.rb", "lib/ghost/cli/task/delete.rb", "lib/ghost/cli/task/empty.rb", "lib/ghost/cli/task/export.rb", "lib/ghost/cli/task/help.rb", "lib/ghost/cli/task/import.rb", "lib/ghost/cli/task/list.rb", "lib/ghost/cli/task.rb", "lib/ghost/cli.rb", "lib/ghost/host.rb", "lib/ghost/store", "lib/ghost/store/dscl_store.rb", "lib/ghost/store/hosts_file_store.rb", "lib/ghost/store.rb", "lib/ghost/tokenized_file.rb", "lib/ghost/version.rb", "lib/ghost.rb", "spec/ghost/cli", "spec/ghost", "spec/ghost/cli", "spec/ghost/cli/task", "spec/ghost/cli/task/add_spec.rb", "spec/ghost/cli/task/delete_spec.rb", "spec/ghost/cli/task/empty_spec.rb", "spec/ghost/cli/task/export_spec.rb", "spec/ghost/cli/task/help_spec.rb", "spec/ghost/cli/task/import_spec.rb", "spec/ghost/cli/task/list_spec.rb", "spec/ghost/cli_spec.rb", "spec/ghost/host_spec.rb", "spec/ghost/store", "spec/ghost/store/dscl_store_spec.rb", "spec/ghost/store/hosts_file_store_spec.rb", "spec/ghost/store_spec.rb", "spec/ghost/tokenized_file_spec.rb", "spec/spec_helper.rb", "spec/support", "spec/support/cli.rb", "spec/support/resolv.rb"]
s.homepage = "http://github.com/bjeanes/ghost"
s.require_paths = ["lib"]
s.rubyforge_project = "ghost"
s.rubygems_version = "1.8.10"
s.summary = "Allows you to create, list, and modify local hostnames"
- s.test_files = ["spec/cli", "spec/ghost", "spec/ghost/cli", "spec/ghost/cli/task", "spec/ghost/cli/task/add_spec.rb", "spec/ghost/cli/task/delete_spec.rb", "spec/ghost/cli/task/empty_spec.rb", "spec/ghost/cli/task/export_spec.rb", "spec/ghost/cli/task/help_spec.rb", "spec/ghost/cli/task/import_spec.rb", "spec/ghost/cli/task/list_spec.rb", "spec/ghost/cli_spec.rb", "spec/ghost/host_spec.rb", "spec/ghost/store", "spec/ghost/store/dscl_store_spec.rb", "spec/ghost/store/hosts_file_store_spec.rb", "spec/ghost/store_spec.rb", "spec/ghost/tokenized_file_spec.rb", "spec/spec_helper.rb", "spec/support", "spec/support/cli.rb", "spec/support/resolv.rb"]
+ s.test_files = ["spec/ghost/cli", "spec/ghost", "spec/ghost/cli", "spec/ghost/cli/task", "spec/ghost/cli/task/add_spec.rb", "spec/ghost/cli/task/delete_spec.rb", "spec/ghost/cli/task/empty_spec.rb", "spec/ghost/cli/task/export_spec.rb", "spec/ghost/cli/task/help_spec.rb", "spec/ghost/cli/task/import_spec.rb", "spec/ghost/cli/task/list_spec.rb", "spec/ghost/cli_spec.rb", "spec/ghost/host_spec.rb", "spec/ghost/store", "spec/ghost/store/dscl_store_spec.rb", "spec/ghost/store/hosts_file_store_spec.rb", "spec/ghost/store_spec.rb", "spec/ghost/tokenized_file_spec.rb", "spec/spec_helper.rb", "spec/support", "spec/support/cli.rb", "spec/support/resolv.rb"]
if s.respond_to? :specification_version then
s.specification_version = 3
View
25 lib/ghost/cli/task/set.rb
@@ -0,0 +1,25 @@
+Ghost::Cli.task :set do
+ desc "Add a host or modify the IP of an existing host"
+ def perform(host, ip = nil)
+ host = Ghost::Host.new(*[host, ip].compact)
+ Ghost.store.set(host)
+ puts "[Setting] #{host.name} -> #{host.ip}"
+ rescue Ghost::Host::NotResolvable
+ abort "Unable to resolve IP address for target host #{ip.inspect}."
+ end
+
+ help do
+ <<-EOF.unindent
+ Usage: ghost set <local host name> [<remote host name>|<IP address>]
+
+ #{desc}.
+
+ If a second parameter is not provided, it defaults to 127.0.0.1
+
+ Examples:
+ ghost set my-localhost # points to 127.0.0.1
+ ghost set google.dev google.com # points to the IP of google.com
+ ghost set router 192.168.1.1 # points to 192.168.1.1
+ EOF
+ end
+end
View
46 lib/ghost/store/hosts_file_store.rb
@@ -9,11 +9,12 @@ module Store
# TODO: A lot of this duplicates Resolv::Hosts in Ruby stdlib.
# Can that be modifiied to use tokens in place of this?
class HostsFileStore
- attr_accessor :path, :file
+ attr_accessor :path, :file, :strict
def initialize(path = Resolv::Hosts::DefaultFileName)
self.path = path
self.file = Ghost::TokenizedFile.new(path, "# ghost start", "# ghost end")
+ self.strict = true
end
def add(host)
@@ -25,6 +26,16 @@ def add(host)
true
end
+ def set(host)
+ sync do |buffer|
+ delete_host host, buffer
+ buffer[host.ip] << host.name
+ buffer_changed!
+ end
+
+ true
+ end
+
def all
sync do |buffer|
buffer.map do |ip, hosts|
@@ -38,17 +49,34 @@ def find(filter)
end
def delete(host)
- result = SortedSet.new
sync do |buffer|
- buffer.each do |ip, names|
- names.dup.each do |name|
- next unless host.match(name)
- next if host.respond_to?(:ip) && host.ip != ip
+ delete_host host, buffer, :strict
+ end
+ end
+
+ def purge(host)
+ sync do |buffer|
+ delete_host host, buffer
+ end
+ end
- result << Ghost::Host.new(name, ip)
- names.delete(name)
- buffer_changed!
+ def delete_host(host, buffer, strict = false)
+ result = SortedSet.new
+ buffer.each do |ip, names|
+ names.each do |name|
+ if host.kind_of? Host
+ next unless host.name == name
+ elsif host.kind_of? String
+ next unless host == name
+ else
+ next unless host.match(name)
end
+
+ next if host.respond_to?(:ip) && host.ip != ip && strict
+
+ result << Ghost::Host.new(name, ip)
+ names.delete(name)
+ buffer_changed!
end
end
result.to_a
View
1  spec/ghost/cli/task/help_spec.rb
@@ -14,6 +14,7 @@
export Export all hosts in /etc/hosts format
import Import hosts in /etc/hosts format
list Show all (or a filtered) list of hosts
+ set Add a host or modify the IP of an existing host
See 'ghost help <task>' for more information on a specific task.
EOF
View
89 spec/ghost/store/hosts_file_store_spec.rb
@@ -279,6 +279,95 @@ def no_write
end
end
+ describe "#set" do
+ let(:host) { Ghost::Host.new("github.com", "127.0.0.1") }
+
+ context 'with existing ghost-managed hosts in the file' do
+ let(:contents) do
+ <<-EOF.gsub(/^\s+/,'')
+ 127.0.0.1 localhost localhost.localdomain
+ # ghost start
+ 192.168.1.1 github.com
+ 192.168.1.2 github.com
+ # ghost end
+ EOF
+ end
+
+ context 'when setting the host to an IP' do
+ it 'replaces all instances of that hostname with a single entry for that IP' do
+ store.set(host)
+ read.should == <<-EOF.gsub(/^\s+/,'')
+ 127.0.0.1 localhost localhost.localdomain
+ # ghost start
+ 127.0.0.1 github.com
+ # ghost end
+ EOF
+ end
+
+ it 'returns true' do
+ store.set(host).should be_true
+ end
+ end
+ end
+ end
+
+ describe "#purge" do
+ context 'with existing ghost-managed hosts in the file' do
+ let(:contents) do
+ <<-EOF.gsub(/^\s+/,'')
+ 127.0.0.1 localhost localhost.localdomain
+ # ghost start
+ 127.0.0.1 google.com
+ 127.0.0.2 gooogle.com
+ 192.168.1.1 github.com
+ # ghost end
+ EOF
+ end
+
+ context 'when purging one of the ghost entries' do
+ context 'using a Ghost::Host to identify host' do
+ context 'and the IP does not match an entry' do
+ let(:host) { Ghost::Host.new("google.com", "127.0.0.2") }
+
+ it 'returns array of removed hosts' do
+ store.purge(host).should == [Ghost::Host.new('google.com', '127.0.0.1')]
+ end
+
+ it 'removes the host from the file' do
+ store.purge(host)
+ read.should == <<-EOF.gsub(/^\s+/,'')
+ 127.0.0.1 localhost localhost.localdomain
+ # ghost start
+ 127.0.0.2 gooogle.com
+ 192.168.1.1 github.com
+ # ghost end
+ EOF
+ end
+ end
+
+ context 'and the IP matches an entry' do
+ let(:host) { Ghost::Host.new("google.com", "127.0.0.1") }
+
+ it 'returns array of removed hosts' do
+ store.purge(host).should == [Ghost::Host.new('google.com', '127.0.0.1')]
+ end
+
+ it 'removes the host from the file' do
+ store.purge(host)
+ read.should == <<-EOF.gsub(/^\s+/,'')
+ 127.0.0.1 localhost localhost.localdomain
+ # ghost start
+ 127.0.0.2 gooogle.com
+ 192.168.1.1 github.com
+ # ghost end
+ EOF
+ end
+ end
+ end
+ end
+ end
+ end
+
describe "#empty" do
context 'with no ghost-managed hosts in the file' do
it 'returns false' do
Please sign in to comment.
Something went wrong with that request. Please try again.