]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
first stab at windows build details.
authorrobk-tahoe <robk-tahoe@allmydata.com>
Thu, 10 Jan 2008 02:01:56 +0000 (19:01 -0700)
committerrobk-tahoe <robk-tahoe@allmydata.com>
Thu, 10 Jan 2008 02:01:56 +0000 (19:01 -0700)
there are many and various fiddly details that were involved in this process
on mountain view.  This is a stripped down version of the build process used
there.  there's hence a good chance that one or two necessary details got
stripped down through the cracks.

this provides a py2exe setup.py to build a tahoe.exe and a tahoesvc.exe
the former is equivalent to bin/tahoe, but without the start/stop commands.
the latter is a windows service that instantiates a client whose basedir
is found in the registry.

windows/registry.py [new file with mode: 0644]
windows/setup.py [new file with mode: 0644]
windows/tahoe.py [new file with mode: 0644]
windows/tahoesvc.py [new file with mode: 0644]

diff --git a/windows/registry.py b/windows/registry.py
new file mode 100644 (file)
index 0000000..2b87689
--- /dev/null
@@ -0,0 +1,77 @@
+import sys
+import _winreg
+
+_AMD_KEY = r"Software\Allmydata"
+_BDIR_KEY = 'Base Dir Path'
+
+if sys.platform not in ('win32'):
+    raise ImportError, "registry cannot be used on non-windows systems"
+    class WindowsError(Exception): # stupid voodoo to appease pyflakes
+        pass
+
+def get_registry_setting(key, name, _topkey=None):
+    """
+    This function iterates through _topkey (if not None),
+    HKEY_CURRENT_USER, and HKEY_LOCAL_MACHINE before giving up.
+
+    @note: Only supports string values.
+
+    @param key: The key we are searching.
+    @type key: String
+
+    @param name: The name of the setting we are querying.
+    @type name: String
+    """
+    topkeys = [_winreg.HKEY_CURRENT_USER, _winreg.HKEY_LOCAL_MACHINE]
+
+    if _topkey:
+        topkeys.insert(0, _topkey)
+
+    for topkey in topkeys:
+        try:
+            regkey = _winreg.OpenKey(topkey, key)
+
+            sublen, vallen, timestamp = _winreg.QueryInfoKey(regkey)
+            for validx in xrange(vallen):
+                keyname, value, keytype = _winreg.EnumValue(regkey, validx)
+                if keyname == name and keytype == _winreg.REG_SZ:
+                    return value
+
+        except WindowsError:
+            continue
+    # We didn't find the key:
+    raise KeyError, (key, name, "registry setting not found")
+
+def set_registry_setting(key, name, data, reg_type=_winreg.REG_SZ,
+                         _topkey=_winreg.HKEY_LOCAL_MACHINE, create_key_if_missing=True):
+    """
+    Sets a registry setting.
+
+    defaults to string values (REG_SZ) - overridable with reg_type.
+    """
+    try:
+        regkey = _winreg.OpenKey(_topkey, key, 0, _winreg.KEY_SET_VALUE)
+    except WindowsError:
+        if create_key_if_missing:
+            regkey = _winreg.CreateKey(_topkey, key)
+        else:
+            raise KeyError, (key, "registry key not found")
+
+    try:
+        _winreg.DeleteValue(regkey, name)
+    except:
+        pass
+
+    _winreg.SetValueEx(regkey, name, 0, reg_type, data)
+
+def get_registry_value(keyname):
+    """
+    retrieves a registry key value from within the Software/Allmydata Inc key
+    """
+    try:
+        return get_registry_setting(_AMD_KEY, keyname)
+    except KeyError:
+        return None
+
+def get_base_dir_path():
+    return get_registry_value(_BDIR_KEY)
diff --git a/windows/setup.py b/windows/setup.py
new file mode 100644 (file)
index 0000000..e93e1b2
--- /dev/null
@@ -0,0 +1,41 @@
+from distutils.core import setup
+import py2exe
+
+setup_args = {
+    'name': 'Tahoe',
+    'description': 'Allmydata Tahoe distributated storage',
+    'author': 'Allmydata, Inc.',
+    'windows': [
+    ],
+    'console': [
+        'tahoe.py',
+    ],
+    'service': [
+        'tahoesvc',
+    ],
+    'data_files': [
+        ('.', [
+        ],),
+    ],
+    'zipfile' : 'library.zip',
+    'options': {
+        "py2exe": {
+            "excludes": [
+            ],
+            "includes": [
+            ],
+            "packages": [
+                "encodings",
+                "_xmlplus",
+            ],
+            #"optimize" : 2,
+        },
+    },
+}
+
+if __name__ == '__main__':
+    setup(**setup_args)
+
+
+_junk = py2exe # appease pyflakes
+del _junk
diff --git a/windows/tahoe.py b/windows/tahoe.py
new file mode 100644 (file)
index 0000000..7c5d2d0
--- /dev/null
@@ -0,0 +1,2 @@
+from allmydata.scripts import runner
+runner.run(install_node_control=False)
diff --git a/windows/tahoesvc.py b/windows/tahoesvc.py
new file mode 100644 (file)
index 0000000..11eebb4
--- /dev/null
@@ -0,0 +1,158 @@
+import sys
+reload(sys)
+sys.setdefaultencoding("utf-8")
+
+import win32serviceutil
+import win32service
+import win32event
+import win32evtlogutil
+
+import os
+import thread
+import time
+import traceback
+
+# this logging should go away once service startup is considered debugged.
+logfilehandle = file('c:\\tahoe_service.log', 'ab+')
+def logmsg(msg):
+    logfilehandle.write("%s: %s\r\n" % (time.strftime('%Y%m%d_%H%M%S'), msg))
+    logfilehandle.flush()
+logmsg('service loaded')
+
+#
+# Now with some bootstrap util functions in place, let's try and init things:
+try:
+    logmsg('loading base dir')
+    import registry
+    basedir = registry.get_base_dir_path()
+    logmsg("got base dir (%s)" % (basedir,))
+    if not basedir:
+        regpth = "%s : %s " % (registry._AMD_KEY, registry._BDIR_KEY)
+        raise RuntimeError('"%s" not set in registry' % (regpth,))
+    os.chdir(basedir)
+    logmsg("chdir(%s)" % (basedir,))
+except:
+    logmsg("exception")
+    traceback.print_exc(None, logfilehandle)
+    logfilehandle.flush()
+    logfilehandle.close()
+    raise
+
+class Tahoe(win32serviceutil.ServiceFramework):
+    _svc_name_ = "Tahoe"
+    _svc_display_name_ = "Allmydata Tahoe Node"
+    def __init__(self, args):
+        logmsg("init")
+        try:
+            # The exe-file has messages for the Event Log Viewer.
+            # Register the exe-file as event source.
+            #
+            # Probably it would be better if this is done at installation time,
+            # so that it also could be removed if the service is uninstalled.
+            # Unfortunately it cannot be done in the 'if __name__ == "__main__"'
+            # block below, because the 'frozen' exe-file does not run this code.
+            #
+            logmsg("service start")
+            win32evtlogutil.AddSourceToRegistry(self._svc_display_name_,
+                                                sys.executable,
+                                                "Application")
+            win32serviceutil.ServiceFramework.__init__(self, args)
+            self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
+        except:
+            try:
+                logmsg("exception")
+                traceback.print_exc(None, logfilehandle)
+                logfilehandle.flush()
+                logfilehandle.close()
+            except:
+                os.abort()
+
+    def SvcStop(self):
+        logmsg("service stop")
+        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
+        win32event.SetEvent(self.hWaitStop)
+
+    def SvcDoRun(self):
+        try:
+            logmsg("service run")
+            import servicemanager
+            # Write a 'started' event to the event log...
+            win32evtlogutil.ReportEvent(self._svc_display_name_,
+                                        servicemanager.PYS_SERVICE_STARTED,
+                                        0, # category
+                                        servicemanager.EVENTLOG_INFORMATION_TYPE,
+                                        (self._svc_name_, ''))
+
+            reactor_type = registry.get_registry_value('reactor')
+            if reactor_type == 'iocp':
+                from twisted.internet import iocpreactor
+                iocpreactor.install()
+            else:
+                from twisted.internet import selectreactor
+                selectreactor.install()
+            from twisted.internet import reactor
+
+            if os.path.exists('DISABLE_STARTUP'):
+                logmsg("DISABLE_STARTUP exists: exiting")
+            else:
+                logmsg("runing reactorthread")
+
+                # launch main thread...
+                thread.start_new_thread(self.launch_node, ())
+
+                # ...and block until service stop request
+                win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
+
+                logmsg("wake up")
+
+                reactor.callFromThread(self.app.shutdown)
+                reactor.callFromThread(reactor.stop)
+
+                time.sleep(2) # give the node/reactor a chance to cleanup
+
+            # and write a 'stopped' event to the event log.
+            win32evtlogutil.ReportEvent(self._svc_display_name_,
+                                        servicemanager.PYS_SERVICE_STOPPED,
+                                        0, # category
+                                        servicemanager.EVENTLOG_INFORMATION_TYPE,
+                                        (self._svc_name_, ''))
+        except:
+            try:
+                logmsg("exception")
+                traceback.print_exc(None, logfilehandle)
+                logfilehandle.flush()
+                logfilehandle.close()
+            except:
+                os.abort()
+
+    def launch_node(self):
+        try:
+            logmsg("main thread startup")
+
+            from twisted.internet import reactor
+            from twisted.python import log, logfile
+            from allmydata import client
+
+            # set up twisted logging. this will become part of the node rsn.
+            logdir = os.path.join(basedir, 'logs')
+            if not os.path.exists(logdir):
+                os.makedirs(logdir)
+            lf = logfile.LogFile('tahoesvc.log', logdir)
+            log.startLogging(lf)
+
+            # run the node itself
+            c = client.Client(basedir)
+            reactor.callLater(c.startService) # after reactor startup
+            reactor.run(dont_bind_signals=True) # does a reactor.run()
+
+            logmsg("main thread shutdown")
+        except:
+            logmsg("exception")
+            traceback.print_exc(None, logfilehandle)
+            logfilehandle.flush()
+            os.abort()
+
+if __name__ == '__main__':
+    logmsg("service main")
+    win32serviceutil.HandleCommandLine(Tahoe)
+