Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

only change /etc/hosts between control tokens on linux #21

Merged
merged 1 commit into from over 2 years ago

2 participants

Sam Beam Bo Jeanes
Sam Beam
sbeam commented

Here is a re-done version of the recently closed pull request for this functionality, based on the the latest clean HEAD. Also tidied up a few things and added more explicit tests around the tokens themselves.

Note, this will have an unexpected effect on someone who is already using ghost, since it will start ignoring their previously entered entries. They'd have to re-add things, or add the #ghost start and # ghost end comments to the hosts file. Probably worth mentioning in the docs.

Sam Beam sbeam only change /etc/hosts between control tokens
affects only linux version because dscl is used on OSX

puts '# ghost start' and '# ghost end' comments in the hostsfile on
first run, and only changes lines in between these tokens thereafter.
a44249b
Bo Jeanes bjeanes merged commit f1d4333 into from
Bo Jeanes bjeanes closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Apr 09, 2012
Sam Beam sbeam only change /etc/hosts between control tokens
affects only linux version because dscl is used on OSX

puts '# ghost start' and '# ghost end' comments in the hostsfile on
first run, and only changes lines in between these tokens thereafter.
a44249b
This page is out of date. Refresh to see the latest.

Showing 2 changed files with 83 additions and 19 deletions. Show diff stats Hide diff stats

  1. +42 13 lib/ghost/linux-host.rb
  2. +41 6 spec/etc_hosts_spec.rb
55 lib/ghost/linux-host.rb
@@ -18,24 +18,31 @@ def ==(other)
18 18 alias :hostname :host
19 19
20 20 @@hosts_file = '/etc/hosts'
21   - @@permanent_hosts = [Host.new("localhost", "127.0.0.1"),
22   - Host.new(`hostname`.chomp, "127.0.0.1")]
  21 + @@start_token, @@end_token = '# ghost start', '# ghost end'
  22 +
23 23 class << self
24 24 protected :new
25 25
26 26 def list
27 27 with_exclusive_file_access do |file|
28 28 entries = []
  29 + in_ghost_area = false
29 30 file.pos = 0
  31 +
30 32 file.each do |line|
31   - next if line =~ /^#/
32   - if line =~ /^(\d+\.\d+\.\d+\.\d+)\s+(.*)$/
33   - ip = $1
34   - hosts = $2.split(/\s+/)
35   - hosts.each { |host| entries << Host.new(host, ip) }
  33 + if !in_ghost_area and line =~ /^#{@@start_token}/
  34 + in_ghost_area = true
  35 + elsif in_ghost_area
  36 + if line =~ /^#{@@end_token}/o
  37 + in_ghost_area = false
  38 + elsif line =~ /^(\d+\.\d+\.\d+\.\d+)\s+(.*)$/
  39 + ip = $1
  40 + hosts = $2.split(/\s+/)
  41 + hosts.each { |host| entries << Host.new(host, ip) }
  42 + end
36 43 end
37 44 end
38   - entries.delete_if { |host| @@permanent_hosts.include? host }
  45 +
39 46 entries
40 47 end
41 48 end
@@ -43,7 +50,8 @@ def list
43 50 def add(host, ip = "127.0.0.1", force = false)
44 51 with_exclusive_file_access do
45 52 if find_by_host(host).nil? || force
46   - delete(host)
  53 + hosts = list
  54 + hosts = hosts.delete_if { |h| h.name == host }
47 55
48 56 unless ip[/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/]
49 57 ip = Socket.gethostbyname(ip)[3].bytes.to_a.join('.')
@@ -51,7 +59,6 @@ def add(host, ip = "127.0.0.1", force = false)
51 59
52 60 new_host = Host.new(host, ip)
53 61
54   - hosts = list
55 62 hosts << new_host
56 63 write_out!(hosts)
57 64
@@ -63,7 +70,7 @@ def add(host, ip = "127.0.0.1", force = false)
63 70 end
64 71
65 72 def find_by_host(hostname)
66   - list.find{ |host| host.hostname == hostname }
  73 + list.find { |host| host.hostname == hostname }
67 74 end
68 75
69 76 def find_by_ip(ip)
@@ -115,13 +122,35 @@ def with_exclusive_file_access
115 122
116 123 def write_out!(hosts)
117 124 with_exclusive_file_access do |f|
118   - hosts += @@permanent_hosts
119   - output = hosts.inject("") {|s, h| s + "#{h.ip} #{h.hostname}\n" }
  125 + new_ghosts = hosts.inject("") {|s, h| s + "#{h.ip} #{h.hostname}\n" }
  126 +
  127 + output = ""
  128 + in_ghost_area, seen_tokens = false,false
  129 + f.pos = 0
  130 +
  131 + f.each do |line|
  132 + if line =~ /^#{@@start_token}/o
  133 + in_ghost_area, seen_tokens = true,true
  134 + output << line << new_ghosts
  135 + elsif line =~ /^#{@@end_token}/o
  136 + in_ghost_area = false
  137 + end
  138 + output << line unless in_ghost_area
  139 + end
  140 + if !seen_tokens
  141 + output << surround_with_tokens( new_ghosts )
  142 + end
  143 +
120 144 f.pos = 0
121 145 f.print output
122 146 f.truncate(f.pos)
123 147 end
124 148 end
  149 +
  150 +
  151 + def surround_with_tokens(str)
  152 + "\n#{@@start_token}\n#{str}#{@@end_token}\n"
  153 + end
125 154 end
126 155 end
127 156 end
47 spec/etc_hosts_spec.rb
@@ -50,17 +50,52 @@ class Ghost::Host
50 50 end
51 51
52 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}
  53 + example = <<-EoEx
  54 + 127.0.0.1 localhost.localdomain
  55 + # ghost start
  56 + 123.123.123.1 project_a.local\t\tproject_b.local project_c.local
  57 + 127.0.0.1 local.bb
  58 + # ghost end
  59 + EoEx
  60 + File.open($hosts_file, 'w') {|f| f << example.gsub!(/^\s*/, '')}
55 61 hosts = Ghost::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]
  62 + hosts.should have(4).items
  63 + hosts.map{|h|h.ip}.uniq.sort.should == ['123.123.123.1', '127.0.0.1']
  64 + hosts.map{|h|h.host}.sort.should == %w[local.bb project_a.local project_b.local project_c.local]
  65 +
59 66 Ghost::Host.add("project_d.local")
60   - Ghost::Host.list.should have(4).items
  67 + Ghost::Host.list.should have(5).items
61 68 end
62 69 end
63 70
  71 +
  72 + it "does not change hosts files outside of control tokens" do
  73 + f = File.open($hosts_file, 'w')
  74 + f.write "10.0.0.23 adserver.example.com\n"
  75 + f.close
  76 + hosts = Ghost::Host.list
  77 + hosts.should have(0).items
  78 +
  79 + hostname = "ghost-test-hostname-b.local"
  80 + Ghost::Host.add(hostname)
  81 + Ghost::Host.list.should have(1).items
  82 +
  83 + hostsfile = File.read($hosts_file)
  84 + hostsfile.should =~ /^10.0.0.23 adserver.example.com\n/
  85 + end
  86 +
  87 + it "adds control tokens to untouched hosts files" do
  88 + f = File.open($hosts_file, 'w')
  89 + f.write "10.0.0.23 adserver.example.com\n"
  90 + f.close
  91 + hostname = "ghost-test-hostname-b.local"
  92 + ip = '123.45.67.89'
  93 + Ghost::Host.add(hostname, ip)
  94 +
  95 + hostsfile = File.read($hosts_file)
  96 + hostsfile.should =~ /# ghost start\n#{ip}\s+#{hostname}\n# ghost end/
  97 + end
  98 +
64 99 describe "#to_s" do
65 100 it "returns hostname" do
66 101 hostname = 'ghost-test-hostname.local'

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.