@@ -19,7 +19,7 @@ def update_guest(machine)
19
19
# download and modify file with Vagrant-managed entries
20
20
file = @global_env . tmp_path . join ( "hosts.#{ machine . name } " )
21
21
machine . communicate . download ( realhostfile , file )
22
- update_file ( file , machine )
22
+ update_file ( file , machine , false )
23
23
24
24
# upload modified file and remove temporary file
25
25
machine . communicate . upload ( file , '/tmp/hosts' )
@@ -55,43 +55,27 @@ class << self
55
55
56
56
private
57
57
58
- def update_file ( file , resolving_machine = nil )
59
- # build array of host file entries from Vagrant configuration
60
- entries = [ ]
61
- destroyed_entries = [ ]
62
- ids = [ ]
63
- get_machines . each do |name , p |
64
- if @provider == p
65
- machine = @global_env . machine ( name , p )
66
- host = machine . config . vm . hostname || name
67
- id = machine . id
68
- ip = get_ip_address ( machine , resolving_machine )
69
- aliases = machine . config . hostmanager . aliases . join ( ' ' ) . chomp
70
- if id . nil?
71
- destroyed_entries << "#{ ip } \t #{ host } #{ aliases } "
72
- else
73
- entries << "#{ ip } \t #{ host } #{ aliases } \t # VAGRANT ID: #{ id } \n "
74
- ids << id unless ids . include? ( id )
75
- end
76
- end
77
- end
58
+ def update_file ( file , resolving_machine = nil , include_id = true )
59
+ file = Pathname . new ( file )
60
+ new_file_content = update_content ( file . read , resolving_machine , include_id )
61
+ file . open ( 'w' ) { |io | io . write ( new_file_content ) }
62
+ end
78
63
79
- tmp_file = Tempfile . open ( 'hostmanager' , @global_env . tmp_path , 'a' )
80
- begin
81
- # copy each line not managed by Vagrant
82
- File . open ( file ) . each_line do |line |
83
- # Eliminate lines for machines that have been destroyed
84
- next if destroyed_entries . any? { |entry | line =~ /^#{ entry } \t # VAGRANT ID: .*/ }
85
- tmp_file << line unless ids . any? { |id | line =~ /# VAGRANT ID: #{ id } / }
86
- end
64
+ def update_content ( file_content , resolving_machine , include_id )
65
+ id = include_id ? " id: #{ read_or_create_id } " : ""
66
+ header = "## vagrant-hostmanager-start#{ id } \n "
67
+ footer = "## vagrant-hostmanager-end\n "
68
+ body = get_machines
69
+ . map { |machine | get_hosts_file_entry ( machine , resolving_machine ) }
70
+ . join
71
+ get_new_content ( header , footer , body , file_content )
72
+ end
87
73
88
- # write a line for each Vagrant-managed entry
89
- entries . each { |entry | tmp_file << entry }
90
- ensure
91
- tmp_file . close
92
- FileUtils . cp ( tmp_file , file )
93
- tmp_file . unlink
94
- end
74
+ def get_hosts_file_entry ( machine , resolving_machine )
75
+ ip = get_ip_address ( machine , resolving_machine )
76
+ host = machine . config . vm . hostname || machine . name
77
+ aliases = machine . config . hostmanager . aliases . join ( ' ' ) . chomp
78
+ "#{ ip } \t #{ host } #{ aliases } \n "
95
79
end
96
80
97
81
def get_ip_address ( machine , resolving_machine )
@@ -108,23 +92,51 @@ def get_ip_address(machine, resolving_machine)
108
92
end
109
93
end
110
94
ip || ( machine . ssh_info ? machine . ssh_info [ :host ] : nil )
111
- end
95
+ end
112
96
end
113
97
114
98
def get_machines
115
99
if @global_env . config_global . hostmanager . include_offline?
116
- machines = [ ]
117
- @global_env . machine_names . each do |name |
118
- begin
119
- @global_env . machine ( name , @provider )
120
- machines << [ name , @provider ]
121
- rescue Vagrant ::Errors ::MachineNotFound
100
+ machines = @global_env . machine_names
101
+ else
102
+ machines = @global_env . active_machines
103
+ end
104
+ # Collect only machines that exist for the current provider
105
+ machines . collect do |name , _ |
106
+ begin
107
+ machine = @global_env . machine ( name , @provider )
108
+ rescue Vagrant ::Errors ::MachineNotFound
109
+ # ignore
110
+ end
111
+ machine
122
112
end
123
- end
124
- machines
113
+ . reject ( &:nil? )
114
+ end
115
+
116
+ def get_new_content ( header , footer , body , old_content )
117
+ if body . empty?
118
+ block = "\n "
119
+ else
120
+ block = "\n \n " + header + body + footer + "\n "
121
+ end
122
+ # Pattern for finding existing block
123
+ header_pattern = Regexp . quote ( header )
124
+ footer_pattern = Regexp . quote ( footer )
125
+ pattern = Regexp . new ( "\n *#{ header_pattern } .*?#{ footer_pattern } \n *" , Regexp ::MULTILINE )
126
+ # Replace existing block or append
127
+ old_content . match ( pattern ) ? old_content . sub ( pattern , block ) : old_content . rstrip + block
128
+ end
129
+
130
+ def read_or_create_id
131
+ file = Pathname . new ( "#{ @global_env . local_data_path } /hostmanager/id" )
132
+ if ( file . file? )
133
+ id = file . read . strip
125
134
else
126
- @global_env . active_machines
135
+ id = SecureRandom . uuid
136
+ file . dirname . mkpath
137
+ file . open ( 'w' ) { |io | io . write ( id ) }
127
138
end
139
+ id
128
140
end
129
141
130
142
## Windows support for copying files, requesting elevated privileges if necessary
0 commit comments