Tuesday, 23 August 2011

toggling /etc/hosts file via a simple gui

Like many folks who play at web development, I have local running instances of all my websites to enable offline development and/or testing.

To switch between the two, I have a launcher to a little gui I've written.

The Interface
The Dialog raised on request.

works great.

the code is below.

Incidentally, as /etc/hosts required root permissions, I call the write using gksu. KDE users would need to change this.

Here's the full code.
#! /usr/bin/env python

'''
This script modifies the /etc/hosts file so that I utilise this machines
web server rather than doing a dns lookup and going to the online 
sites.
It's for testing purposes. 

my /etc/hosts file has this text present.

127.0.0.1   localhost 
127.0.0.1   rowinggolfer.org 
127.0.0.1   openmolar.com 
127.0.0.1   academydental.com 
127.0.1.1    slim-maroon

and when I want to use the "cloud" servers, the sites listed in variable SITES
are commented out.

'''

from PyQt4 import QtGui, QtCore
import re, subprocess, sys, tempfile

SITES = ["rowinggolfer.org", "academydental.com", "openmolar.com",]


class Dialog(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)
    
        self.setWindowTitle("toggle /etc/hosts file")
        
        self.local_rb = QtGui.QRadioButton("Using localhost")
        self.global_rb = QtGui.QRadioButton("Using remote host(s)")
        
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.local_rb)
        layout.addWidget(self.global_rb)
        
        self.global_rb.setChecked(True)
        self.local_rb.setChecked(self.check_state)
        
        self.local_rb.toggled.connect(self.apply_changes)
    
    def sizeHint(self):
        return QtCore.QSize(200,50)
    
    @property
    def check_state(self):
        '''
        checks /etc/hosts to see if it is set to use the local instance of 
        apache2 for the SITES
        '''
        local = False
        
        f = open("/etc/hosts", "r")
        for line in f:
            for site in SITES:
                if re.match("127\.0\.0\.1[ \t]*%s"% site, line):
                    local = True
        
        return local
        
    def apply_changes(self, use_local):
        host = "localhost" if use_local else "remote host(s)"
        
        message = '''modify <em>/etc/hosts</em> so that 
            <b>%s</b> is used for the following sites?<ul>{sites}</ul>'''% host
        
        sites = ""
        for site in SITES:
            sites += "<li>%s</li>"% site
            
        message = message.replace("{sites}", sites)
        
        result = QtGui.QMessageBox.question(self, "confirm", message,
        QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel,
        QtGui.QMessageBox.Ok) == QtGui.QMessageBox.Ok
        
        if result:
            self.write_file(use_local)
        
        
        success = use_local == self.check_state
        
        if success:
            QtGui.QMessageBox.inforamtion(self, "success", 
                "changes applied sucessfully")
        
        self.local_rb.toggled.disconnect(self.apply_changes)
        self.local_rb.setChecked(self.check_state)
        self.local_rb.toggled.connect(self.apply_changes)
        
        
        
    def write_file(self, local):
    
        def repl(arg):
            if local:
                return re.sub("\n#*", "\n", arg.group())
            else:
                return arg.group().replace("\n", "\n#")
    
        f = open("/etc/hosts", "r")
        data = f.read()
        f.close()
        if not local:
            for site in SITES:
                data = re.sub(  "(\n127\.0\.0\.1[ \t]*%s)"% site, 
                                repl, data)
        else:
            for site in SITES:
                data = re.sub(  "\n#*127\.0\.0\.1[ \t]*(%s)"% site, 
                                repl, data)
    
        t = tempfile.NamedTemporaryFile("w", delete=False)
        t.write(data)
        t.close()
        
        p = subprocess.Popen(["gksu", "mv", t.name, "/etc/hosts"]) 
        assert p.wait()==0
        
        
if __name__ == "__main__":
    app = QtGui.QApplication([])
    dl = Dialog()
    dl.exec_()
    
    

No comments: