Alessio Caiazza is sharing code with you

Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.

Don't show this again

nolith / avahiserve

Avahi mercurial extension. Works only on Linux.

Clone this repository (size: 23.4 KB): HTTPS / SSH
hg clone https://bitbucket.org/nolith/avahiserve
hg clone ssh://hg@bitbucket.org/nolith/avahiserve

avahiserve / avahiserve.py

#!/usr/bin/env python

from mercurial import hg
from mercurial import commands

import dbus
import gobject
import avahi
from dbus.mainloop.glib import DBusGMainLoop

class AvahiReg:

        def __init__(self, name, port):
                self.verbose = False
                self.serviceName = "Mercurial"
                if name != '':
                        self.serviceName += ": " + name
                self.serviceType = "_http._tcp" # See http://www.dns-sd.org/ServiceTypes.html
                self.servicePort = port
                self.serviceTXT = ["extension's author=Alessio Caiazza"] #TXT record for the service

                self.domain = "" # Domain to publish on, default to .local
                self.host = "" # Host to publish records for, default to localhost

                self.group = None #our entry group
                self.rename_count = 12 # Counter so we only rename after collisions a sensible number of times

        def add_service(self):
                if self.group is None:
                        self.group = dbus.Interface(
                                self.bus.get_object( avahi.DBUS_NAME, self.server.EntryGroupNew()),
                                avahi.DBUS_INTERFACE_ENTRY_GROUP)
                        self.group.connect_to_signal('StateChanged', self.entry_group_state_changed)
                if self.verbose:
                        print "Adding service '%s' of type '%s' ..." % (self.serviceName, self.serviceType)
                self.group.AddService(
                        avahi.IF_UNSPEC,    #interface
                        avahi.PROTO_UNSPEC, #protocol
                        0,                  #flags
                        self.serviceName, self.serviceType,
                        self.domain, self.host,
                        dbus.UInt16(self.servicePort),
                        avahi.string_array_to_txt_array(self.serviceTXT))
                self.group.Commit()

        def remove_service(self):
                if not group is None:
                        group.Reset()

        def server_state_changed(self, state):
                if state == avahi.SERVER_COLLISION:
                        if self.verbose:
                                print "WARNING: Server name collision"
                        remove_service()
                elif state == avahi.SERVER_RUNNING:
                        self.add_service()

        def entry_group_state_changed(self,state, error):

                if self.verbose:
                        print "state change: %i" % state

                if state == avahi.ENTRY_GROUP_ESTABLISHED:
                        print "Service established."
                elif state == avahi.ENTRY_GROUP_COLLISION:

                        rename_count = rename_count - 1
                        if rename_count > 0:
                                name = server.GetAlternativeServiceName(name)
                                if self.verbose:
                                        print "WARNING: Service name collision, changing name to '%s' ..." % name
                                remove_service()
                                add_service()

                        else:
                                if self.verbose:
                                        print "ERROR: No suitable service name found after %i retries, exiting." % n_rename
                                main_loop.quit()
                elif state == avahi.ENTRY_GROUP_FAILURE:
                        if self.verbose:
                                print "Error in group state changed", error
                        main_loop.quit()
                        return

        def start(self):
                DBusGMainLoop( set_as_default=True )
                self.bus = dbus.SystemBus()

                self.server = dbus.Interface(
                        self.bus.get_object( avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER ),
                        avahi.DBUS_INTERFACE_SERVER )

                self.server.connect_to_signal( "StateChanged", self.server_state_changed )
                self.server_state_changed( self.server.GetState() )
        
        def stop(self):
                if self.verbose:
                        print "Stopping avahi-publish-service"
                if not self.group is None:
                        self.group.Free()

# every command must take a ui and and repo as arguments.
# opts is a dict where you can find other command line flags
#
# Other parameters are taken in order from items on the command line that
# don't start with a dash.  If no default value is given in the parameter list,
# they are required.
def avahi_serve(ui, repo, **opts):
        # The doc string below will show up in hg help
        """Serve and publish on avahi zeroconf"""

        #print opts
        if opts['port'] != 0:
                port = int(opts['port'])
        else:
                port = 8000
        a = AvahiReg(opts['name'], port)

        if ui.cdata.has_option('web', 'description'):
                a.serviceTXT += ["description=" + ui.cdata.get('web','description')]
        if ui.cdata.has_option('ui', 'username'):
                #remove < and > cose make problems on Avahi Discovery
                a.serviceTXT += ["owner=" + 
                                ui.cdata.get('ui','username')
                                .replace('<','')
                                .replace('>','')]

        a.verbose = ui.verbose
        a.start()
        try:
                commands.serve(ui,repo, **opts)
        except KeyboardInterrupt:
                pass
        
        a.stop()

cmdtable = {
        # cmd name        function call
        "aserve": (avahi_serve,
                commands.table['^serve'][1],
                "hg aserve [OPTION]...")
}