[PATCH 1/2] Make a main class OfflineImap that is being called

Sebastian Spaeth Sebastian at SSpaeth.de
Mon Dec 6 12:36:54 GMT 2010


Rather than calling a function in a module, invoke offlineimap by
calling an OfflineImap object.

This removes code lying outside of objects; I prefer to keep code
within an object and provides us with a nicer Object encapsulation.

It will also ease the testing of Object functionality in unittests
when they are introduced.

Previously we would import and start Offlineimap like this:

from offlineimap import init
init.startup('6.2.0')

now we do:
from offlineimap import OfflineImap

offlineimap = OfflineImap()
offlineimap.startup('6.2.0')

Signed-off-by: Sebastian Spaeth <Sebastian at SSpaeth.de>
---
 bin/offlineimap         |    6 +-
 offlineimap.py          |    6 +-
 offlineimap/__init__.py |    2 +
 offlineimap/init.py     |  387 ++++++++++++++++++++++++-----------------------
 4 files changed, 205 insertions(+), 196 deletions(-)

diff --git a/bin/offlineimap b/bin/offlineimap
index 03700ca..420ddb0 100755
--- a/bin/offlineimap
+++ b/bin/offlineimap
@@ -17,5 +17,7 @@
 #    along with this program; if not, write to the Free Software
 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
-from offlineimap import init
-init.startup('6.2.0')
+from offlineimap import OfflineImap
+
+offlineimap = OfflineImap()
+offlineimap.startup('6.2.0')
diff --git a/offlineimap.py b/offlineimap.py
index e8684e4..566bd36 100755
--- a/offlineimap.py
+++ b/offlineimap.py
@@ -17,5 +17,7 @@
 #    along with this program; if not, write to the Free Software
 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-from offlineimap import init
-init.startup('6.2.0')
+from offlineimap import OfflineImap
+
+offlineimap = OfflineImap()
+offlineimap.startup('6.2.0')
diff --git a/offlineimap/__init__.py b/offlineimap/__init__.py
index b19e419..c36246c 100644
--- a/offlineimap/__init__.py
+++ b/offlineimap/__init__.py
@@ -1,3 +1,5 @@
+from offlineimap.init import OfflineImap
+
 __all__ = ['ui', 'folder', 'repository', 'mbnames', 'threadutil', 'init']
 
 
diff --git a/offlineimap/init.py b/offlineimap/init.py
index 4d015ec..f930c0f 100644
--- a/offlineimap/init.py
+++ b/offlineimap/init.py
@@ -36,198 +36,201 @@ except:
 
 lockfd = None
 
-def lock(config, ui):
-    global lockfd, hasfcntl
-    if not hasfcntl:
-        return
-    lockfd = open(config.getmetadatadir() + "/lock", "w")
-    try:
-        fcntl.flock(lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB)
-    except IOError:
-        ui.locked()
-        ui.terminate(1)
-
-def startup(versionno):
-    assert versionno == version.versionstr, "Revision of main program (%s) does not match that of library (%s).  Please double-check your PYTHONPATH and installation locations." % (versionno, version.versionstr)
-    options = {}
-    options['-k'] = []
-    if '--help' in sys.argv[1:]:
-        sys.stdout.write(version.getcmdhelp() + "\n")
-        sys.exit(0)
-
-    for optlist in getopt(sys.argv[1:], 'P:1oqa:c:d:l:u:hk:f:')[0]:
-        if optlist[0] == '-k':
-            options[optlist[0]].append(optlist[1])
-        else:
-            options[optlist[0]] = optlist[1]
-
-    if options.has_key('-h'):
-        sys.stdout.write(version.getcmdhelp())
-        sys.stdout.write("\n")
-        sys.exit(0)
-    configfilename = os.path.expanduser("~/.offlineimaprc")
-    if options.has_key('-c'):
-        configfilename = options['-c']
-    if options.has_key('-P'):
-        if not options.has_key('-1'):
-            sys.stderr.write("FATAL: profile mode REQUIRES -1\n")
-            sys.exit(100)
-        profiledir = options['-P']
-        os.mkdir(profiledir)
-        threadutil.setprofiledir(profiledir)
-        sys.stderr.write("WARNING: profile mode engaged;\nPotentially large data will be created in " + profiledir + "\n")
-
-    config = CustomConfigParser()
-    if not os.path.exists(configfilename):
-        sys.stderr.write(" *** Config file %s does not exist; aborting!\n" % configfilename)
-        sys.exit(1)
-
-    config.read(configfilename)
-
-    # override config values with option '-k'
-    for option in options['-k']:
-        (key, value) = option.split('=', 1)
-        if ':' in key:
-            (secname, key) = key.split(':', 1)
-            section = secname.replace("_", " ")
-        else:
-            section = "general"
-        config.set(section, key, value)
-
-    ui = offlineimap.ui.detector.findUI(config, options.get('-u'))
-    UIBase.setglobalui(ui)
-
-    if options.has_key('-l'):
-        ui.setlogfd(open(options['-l'], 'wt'))
-
-    ui.init_banner()
-
-    if options.has_key('-d'):
-        for debugtype in options['-d'].split(','):
-            ui.add_debug(debugtype.strip())
-            if debugtype == 'imap':
-                imaplib.Debug = 5
-            if debugtype == 'thread':
-                threading._VERBOSE = 1
-
-    if options.has_key('-o'):
-        # FIXME: maybe need a better
-        for section in accounts.getaccountlist(config):
-            config.remove_option('Account ' + section, "autorefresh")
-
-    if options.has_key('-q'):
-        for section in accounts.getaccountlist(config):
-            config.set('Account ' + section, "quick", '-1')
-
-    if options.has_key('-f'):
-        foldernames = options['-f'].replace(" ", "").split(",")
-        folderfilter = "lambda f: f in %s" % foldernames
-        folderincludes = "[]"
-        for accountname in accounts.getaccountlist(config):
-            account_section = 'Account ' + accountname
-            remote_repo_section = 'Repository ' + \
-                                  config.get(account_section, 'remoterepository')
-            local_repo_section = 'Repository ' + \
-                                 config.get(account_section, 'localrepository')
-            for section in [remote_repo_section, local_repo_section]:
-                config.set(section, "folderfilter", folderfilter)
-                config.set(section, "folderincludes", folderincludes)
-
-    lock(config, ui)
-
-    def sigterm_handler(signum, frame):
-        # die immediately
-        ui.terminate(errormsg="terminating...")
-    signal.signal(signal.SIGTERM,sigterm_handler)
-
-    try:
-        pidfd = open(config.getmetadatadir() + "/pid", "w")
-        pidfd.write(str(os.getpid()) + "\n")
-        pidfd.close()
-    except:
-        pass
-
-    try:
+class OfflineImap:
+
+    def lock(self, config, ui):
+        global lockfd, hasfcntl
+        if not hasfcntl:
+            return
+        lockfd = open(config.getmetadatadir() + "/lock", "w")
+        try:
+            fcntl.flock(lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB)
+        except IOError:
+            ui.locked()
+            ui.terminate(1)
+    
+    def startup(self, versionno):
+        assert versionno == version.versionstr, "Revision of main program (%s) does not match that of library (%s).  Please double-check your PYTHONPATH and installation locations." % (versionno, version.versionstr)
+        options = {}
+        options['-k'] = []
+        if '--help' in sys.argv[1:]:
+            sys.stdout.write(version.getcmdhelp() + "\n")
+            sys.exit(0)
+    
+        for optlist in getopt(sys.argv[1:], 'P:1oqa:c:d:l:u:hk:f:')[0]:
+            if optlist[0] == '-k':
+                options[optlist[0]].append(optlist[1])
+            else:
+                options[optlist[0]] = optlist[1]
+    
+        if options.has_key('-h'):
+            sys.stdout.write(version.getcmdhelp())
+            sys.stdout.write("\n")
+            sys.exit(0)
+        configfilename = os.path.expanduser("~/.offlineimaprc")
+        if options.has_key('-c'):
+            configfilename = options['-c']
+        if options.has_key('-P'):
+            if not options.has_key('-1'):
+                sys.stderr.write("FATAL: profile mode REQUIRES -1\n")
+                sys.exit(100)
+            profiledir = options['-P']
+            os.mkdir(profiledir)
+            threadutil.setprofiledir(profiledir)
+            sys.stderr.write("WARNING: profile mode engaged;\nPotentially large data will be created in " + profiledir + "\n")
+    
+        config = CustomConfigParser()
+        if not os.path.exists(configfilename):
+            sys.stderr.write(" *** Config file %s does not exist; aborting!\n" % configfilename)
+            sys.exit(1)
+    
+        config.read(configfilename)
+    
+        # override config values with option '-k'
+        for option in options['-k']:
+            (key, value) = option.split('=', 1)
+            if ':' in key:
+                (secname, key) = key.split(':', 1)
+                section = secname.replace("_", " ")
+            else:
+                section = "general"
+            config.set(section, key, value)
+    
+        ui = offlineimap.ui.detector.findUI(config, options.get('-u'))
+        UIBase.setglobalui(ui)
+    
         if options.has_key('-l'):
-            sys.stderr = ui.logfile
-
-        socktimeout = config.getdefaultint("general", "socktimeout", 0)
-        if socktimeout > 0:
-            socket.setdefaulttimeout(socktimeout)
-
-        activeaccounts = config.get("general", "accounts")
-        if options.has_key('-a'):
-            activeaccounts = options['-a']
-        activeaccounts = activeaccounts.replace(" ", "")
-        activeaccounts = activeaccounts.split(",")
-        allaccounts = accounts.AccountHashGenerator(config)
-
-        syncaccounts = []
-        for account in activeaccounts:
-            if account not in allaccounts:
-                if len(allaccounts) == 0:
-                    errormsg = 'The account "%s" does not exist because no accounts are defined!'%account
-                else:
-                    errormsg = 'The account "%s" does not exist.  Valid accounts are:'%account
-                    for name in allaccounts.keys():
-                        errormsg += '\n%s'%name
-                ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
-            if account not in syncaccounts:
-                syncaccounts.append(account)
-
-        server = None
-        remoterepos = None
-        localrepos = None
-
-        if options.has_key('-1'):
-            threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
-        else:
-            threadutil.initInstanceLimit("ACCOUNTLIMIT",
-                                         config.getdefaultint("general", "maxsyncaccounts", 1))
-
-        for reposname in config.getsectionlist('Repository'):
-            for instancename in ["FOLDER_" + reposname,
-                                 "MSGCOPY_" + reposname]:
-                if options.has_key('-1'):
-                    threadutil.initInstanceLimit(instancename, 1)
-                else:
-                    threadutil.initInstanceLimit(instancename,
-                                                 config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
-        siglisteners = []
-        def sig_handler(signum, frame):
-            if signum == signal.SIGUSR1:
-                # tell each account to do a full sync asap
-                signum = (1,)
-            elif signum == signal.SIGHUP:
-                # tell each account to die asap
-                signum = (2,)
-            elif signum == signal.SIGUSR2:
-                # tell each account to do a full sync asap, then die
-                signum = (1, 2)
-            # one listener per account thread (up to maxsyncaccounts)
-            for listener in siglisteners:
-                for sig in signum:
-                    listener.put_nowait(sig)
-        signal.signal(signal.SIGHUP,sig_handler)
-        signal.signal(signal.SIGUSR1,sig_handler)
-        signal.signal(signal.SIGUSR2,sig_handler)
-
-        threadutil.initexitnotify()
-        t = ExitNotifyThread(target=syncmaster.syncitall,
-                             name='Sync Runner',
-                             kwargs = {'accounts': syncaccounts,
-                                       'config': config,
-                                       'siglisteners': siglisteners})
-        t.setDaemon(1)
-        t.start()
-    except:
-        ui.mainException()
-
-    try:
-        threadutil.exitnotifymonitorloop(threadutil.threadexited)
-    except SystemExit:
-        raise
-    except:
-        ui.mainException()                  # Also expected to terminate.
+            ui.setlogfd(open(options['-l'], 'wt'))
+    
+        ui.init_banner()
+    
+        if options.has_key('-d'):
+            for debugtype in options['-d'].split(','):
+                ui.add_debug(debugtype.strip())
+                if debugtype == 'imap':
+                    imaplib.Debug = 5
+                if debugtype == 'thread':
+                    threading._VERBOSE = 1
+    
+        if options.has_key('-o'):
+            # FIXME: maybe need a better
+            for section in accounts.getaccountlist(config):
+                config.remove_option('Account ' + section, "autorefresh")
+    
+        if options.has_key('-q'):
+            for section in accounts.getaccountlist(config):
+                config.set('Account ' + section, "quick", '-1')
+    
+        if options.has_key('-f'):
+            foldernames = options['-f'].replace(" ", "").split(",")
+            folderfilter = "lambda f: f in %s" % foldernames
+            folderincludes = "[]"
+            for accountname in accounts.getaccountlist(config):
+                account_section = 'Account ' + accountname
+                remote_repo_section = 'Repository ' + \
+                                      config.get(account_section, 'remoterepository')
+                local_repo_section = 'Repository ' + \
+                                     config.get(account_section, 'localrepository')
+                for section in [remote_repo_section, local_repo_section]:
+                    config.set(section, "folderfilter", folderfilter)
+                    config.set(section, "folderincludes", folderincludes)
+    
+        self.lock(config, ui)
+
+    
+        def sigterm_handler(self, signum, frame):
+            # die immediately
+            ui.terminate(errormsg="terminating...")
+        signal.signal(signal.SIGTERM,sigterm_handler)
+    
+        try:
+            pidfd = open(config.getmetadatadir() + "/pid", "w")
+            pidfd.write(str(os.getpid()) + "\n")
+            pidfd.close()
+        except:
+            pass
+    
+        try:
+            if options.has_key('-l'):
+                sys.stderr = ui.logfile
+    
+            socktimeout = config.getdefaultint("general", "socktimeout", 0)
+            if socktimeout > 0:
+                socket.setdefaulttimeout(socktimeout)
+    
+            activeaccounts = config.get("general", "accounts")
+            if options.has_key('-a'):
+                activeaccounts = options['-a']
+            activeaccounts = activeaccounts.replace(" ", "")
+            activeaccounts = activeaccounts.split(",")
+            allaccounts = accounts.AccountHashGenerator(config)
+    
+            syncaccounts = []
+            for account in activeaccounts:
+                if account not in allaccounts:
+                    if len(allaccounts) == 0:
+                        errormsg = 'The account "%s" does not exist because no accounts are defined!'%account
+                    else:
+                        errormsg = 'The account "%s" does not exist.  Valid accounts are:'%account
+                        for name in allaccounts.keys():
+                            errormsg += '\n%s'%name
+                    ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
+                if account not in syncaccounts:
+                    syncaccounts.append(account)
+    
+            server = None
+            remoterepos = None
+            localrepos = None
+    
+            if options.has_key('-1'):
+                threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
+            else:
+                threadutil.initInstanceLimit("ACCOUNTLIMIT",
+                                             config.getdefaultint("general", "maxsyncaccounts", 1))
+    
+            for reposname in config.getsectionlist('Repository'):
+                for instancename in ["FOLDER_" + reposname,
+                                     "MSGCOPY_" + reposname]:
+                    if options.has_key('-1'):
+                        threadutil.initInstanceLimit(instancename, 1)
+                    else:
+                        threadutil.initInstanceLimit(instancename,
+                                                     config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
+            siglisteners = []
+            def sig_handler(signum, frame):
+                if signum == signal.SIGUSR1:
+                    # tell each account to do a full sync asap
+                    signum = (1,)
+                elif signum == signal.SIGHUP:
+                    # tell each account to die asap
+                    signum = (2,)
+                elif signum == signal.SIGUSR2:
+                    # tell each account to do a full sync asap, then die
+                    signum = (1, 2)
+                # one listener per account thread (up to maxsyncaccounts)
+                for listener in siglisteners:
+                    for sig in signum:
+                        listener.put_nowait(sig)
+            signal.signal(signal.SIGHUP,sig_handler)
+            signal.signal(signal.SIGUSR1,sig_handler)
+            signal.signal(signal.SIGUSR2,sig_handler)
+    
+            threadutil.initexitnotify()
+            t = ExitNotifyThread(target=syncmaster.syncitall,
+                                 name='Sync Runner',
+                                 kwargs = {'accounts': syncaccounts,
+                                           'config': config,
+                                           'siglisteners': siglisteners})
+            t.setDaemon(1)
+            t.start()
+        except:
+            ui.mainException()
+    
+        try:
+            threadutil.exitnotifymonitorloop(threadutil.threadexited)
+        except SystemExit:
+            raise
+        except:
+            ui.mainException()                  # Also expected to terminate.
 
         
-- 
1.7.1





More information about the OfflineIMAP-project mailing list