# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. from __future__ import unicode_literals class HostsLine(object): def __init__(self, ip_address, canonical_hostname, aliases=None, comment=None): self.ip_address = ip_address self.canonical_hostname = canonical_hostname self.aliases = aliases if aliases is not None else [] self.comment = comment if self.ip_address is None: assert self.canonical_hostname is None assert not self.aliases assert self.comment is not None @classmethod def from_string(cls, line): if not line.strip(): return line = line.strip() ip_address = None canonical_hostname = None aliases = [] comment = None comment_parts = line.split("#", 1) if len(comment_parts) > 1: comment = comment_parts[1] data = comment_parts[0].strip() if data: fields = data.split() if len(fields) < 2: raise ValueError("Invalid hosts line") ip_address = fields[0] canonical_hostname = fields[1] aliases = fields[2:] return cls(ip_address, canonical_hostname, aliases, comment) class HostsFile(object): def __init__(self): self.data = [] self.by_hostname = {} def set_host(self, host): if host.canonical_hostname is None: self.data.append(host) elif host.canonical_hostname in self.by_hostname: old_host = self.by_hostname[host.canonical_hostname] old_host.ip_address = host.ip_address old_host.aliases = host.aliases old_host.comment = host.comment else: self.data.append(host) self.by_hostname[host.canonical_hostname] = host @classmethod def from_file(cls, f): rv = cls() for line in f: host = HostsLine.from_string(line) if host is not None: rv.set_host(host) return rv def to_string(self): field_widths = [0, 0] for line in self.data: if line.ip_address is not None: field_widths[0] = max(field_widths[0], len(line.ip_address)) field_widths[1] = max(field_widths[1], len(line.canonical_hostname)) lines = [] for host in self.data: line = "" if host.ip_address is not None: ip_string = host.ip_address.ljust(field_widths[0]) hostname_str = host.canonical_hostname if host.aliases: hostname_str = "%s %s" % (hostname_str.ljust(field_widths[1]), " ".join(host.aliases)) line = "%s %s" % (ip_string, hostname_str) if host.comment: if line: line += " " line += "#%s" % host.comment lines.append(line) lines.append("") return "\n".join(lines) def to_file(self, f): f.write(self.to_string().encode("utf8"))