Make a main class OfflineImap that is being called
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@SSpaeth.de> Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
parent
35dd236155
commit
325dd833ba
@ -17,5 +17,7 @@
|
|||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
from offlineimap import init
|
from offlineimap import OfflineImap
|
||||||
init.startup('6.2.0')
|
|
||||||
|
offlineimap = OfflineImap()
|
||||||
|
offlineimap.startup('6.2.0')
|
||||||
|
@ -17,5 +17,7 @@
|
|||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
from offlineimap import init
|
from offlineimap import OfflineImap
|
||||||
init.startup('6.2.0')
|
|
||||||
|
offlineimap = OfflineImap()
|
||||||
|
offlineimap.startup('6.2.0')
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from offlineimap.init import OfflineImap
|
||||||
|
|
||||||
__all__ = ['ui', 'folder', 'repository', 'mbnames', 'threadutil', 'init']
|
__all__ = ['ui', 'folder', 'repository', 'mbnames', 'threadutil', 'init']
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,198 +36,201 @@ except:
|
|||||||
|
|
||||||
lockfd = None
|
lockfd = None
|
||||||
|
|
||||||
def lock(config, ui):
|
class OfflineImap:
|
||||||
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):
|
def lock(self, config, ui):
|
||||||
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)
|
global lockfd, hasfcntl
|
||||||
options = {}
|
if not hasfcntl:
|
||||||
options['-k'] = []
|
return
|
||||||
if '--help' in sys.argv[1:]:
|
lockfd = open(config.getmetadatadir() + "/lock", "w")
|
||||||
sys.stdout.write(version.getcmdhelp() + "\n")
|
try:
|
||||||
sys.exit(0)
|
fcntl.flock(lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||||
|
except IOError:
|
||||||
|
ui.locked()
|
||||||
|
ui.terminate(1)
|
||||||
|
|
||||||
for optlist in getopt(sys.argv[1:], 'P:1oqa:c:d:l:u:hk:f:')[0]:
|
def startup(self, versionno):
|
||||||
if optlist[0] == '-k':
|
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[optlist[0]].append(optlist[1])
|
options = {}
|
||||||
else:
|
options['-k'] = []
|
||||||
options[optlist[0]] = optlist[1]
|
if '--help' in sys.argv[1:]:
|
||||||
|
sys.stdout.write(version.getcmdhelp() + "\n")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
if options.has_key('-h'):
|
for optlist in getopt(sys.argv[1:], 'P:1oqa:c:d:l:u:hk:f:')[0]:
|
||||||
sys.stdout.write(version.getcmdhelp())
|
if optlist[0] == '-k':
|
||||||
sys.stdout.write("\n")
|
options[optlist[0]].append(optlist[1])
|
||||||
sys.exit(0)
|
else:
|
||||||
configfilename = os.path.expanduser("~/.offlineimaprc")
|
options[optlist[0]] = optlist[1]
|
||||||
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 options.has_key('-h'):
|
||||||
if not os.path.exists(configfilename):
|
sys.stdout.write(version.getcmdhelp())
|
||||||
sys.stderr.write(" *** Config file %s does not exist; aborting!\n" % configfilename)
|
sys.stdout.write("\n")
|
||||||
sys.exit(1)
|
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.read(configfilename)
|
config = CustomConfigParser()
|
||||||
|
if not os.path.exists(configfilename):
|
||||||
|
sys.stderr.write(" *** Config file %s does not exist; aborting!\n" % configfilename)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# override config values with option '-k'
|
config.read(configfilename)
|
||||||
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'))
|
# override config values with option '-k'
|
||||||
UIBase.setglobalui(ui)
|
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)
|
||||||
|
|
||||||
if options.has_key('-l'):
|
ui = offlineimap.ui.detector.findUI(config, options.get('-u'))
|
||||||
ui.setlogfd(open(options['-l'], 'wt'))
|
UIBase.setglobalui(ui)
|
||||||
|
|
||||||
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:
|
|
||||||
if options.has_key('-l'):
|
if options.has_key('-l'):
|
||||||
sys.stderr = ui.logfile
|
ui.setlogfd(open(options['-l'], 'wt'))
|
||||||
|
|
||||||
socktimeout = config.getdefaultint("general", "socktimeout", 0)
|
ui.init_banner()
|
||||||
if socktimeout > 0:
|
|
||||||
socket.setdefaulttimeout(socktimeout)
|
|
||||||
|
|
||||||
activeaccounts = config.get("general", "accounts")
|
if options.has_key('-d'):
|
||||||
if options.has_key('-a'):
|
for debugtype in options['-d'].split(','):
|
||||||
activeaccounts = options['-a']
|
ui.add_debug(debugtype.strip())
|
||||||
activeaccounts = activeaccounts.replace(" ", "")
|
if debugtype == 'imap':
|
||||||
activeaccounts = activeaccounts.split(",")
|
imaplib.Debug = 5
|
||||||
allaccounts = accounts.AccountHashGenerator(config)
|
if debugtype == 'thread':
|
||||||
|
threading._VERBOSE = 1
|
||||||
|
|
||||||
syncaccounts = []
|
if options.has_key('-o'):
|
||||||
for account in activeaccounts:
|
# FIXME: maybe need a better
|
||||||
if account not in allaccounts:
|
for section in accounts.getaccountlist(config):
|
||||||
if len(allaccounts) == 0:
|
config.remove_option('Account ' + section, "autorefresh")
|
||||||
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
|
if options.has_key('-q'):
|
||||||
remoterepos = None
|
for section in accounts.getaccountlist(config):
|
||||||
localrepos = None
|
config.set('Account ' + section, "quick", '-1')
|
||||||
|
|
||||||
if options.has_key('-1'):
|
if options.has_key('-f'):
|
||||||
threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
|
foldernames = options['-f'].replace(" ", "").split(",")
|
||||||
else:
|
folderfilter = "lambda f: f in %s" % foldernames
|
||||||
threadutil.initInstanceLimit("ACCOUNTLIMIT",
|
folderincludes = "[]"
|
||||||
config.getdefaultint("general", "maxsyncaccounts", 1))
|
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)
|
||||||
|
|
||||||
for reposname in config.getsectionlist('Repository'):
|
self.lock(config, ui)
|
||||||
for instancename in ["FOLDER_" + reposname,
|
|
||||||
"MSGCOPY_" + reposname]:
|
|
||||||
if options.has_key('-1'):
|
def sigterm_handler(self, signum, frame):
|
||||||
threadutil.initInstanceLimit(instancename, 1)
|
# die immediately
|
||||||
else:
|
ui.terminate(errormsg="terminating...")
|
||||||
threadutil.initInstanceLimit(instancename,
|
signal.signal(signal.SIGTERM,sigterm_handler)
|
||||||
config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
|
|
||||||
siglisteners = []
|
try:
|
||||||
def sig_handler(signum, frame):
|
pidfd = open(config.getmetadatadir() + "/pid", "w")
|
||||||
if signum == signal.SIGUSR1:
|
pidfd.write(str(os.getpid()) + "\n")
|
||||||
# tell each account to do a full sync asap
|
pidfd.close()
|
||||||
signum = (1,)
|
except:
|
||||||
elif signum == signal.SIGHUP:
|
pass
|
||||||
# tell each account to die asap
|
|
||||||
signum = (2,)
|
try:
|
||||||
elif signum == signal.SIGUSR2:
|
if options.has_key('-l'):
|
||||||
# tell each account to do a full sync asap, then die
|
sys.stderr = ui.logfile
|
||||||
signum = (1, 2)
|
|
||||||
# one listener per account thread (up to maxsyncaccounts)
|
socktimeout = config.getdefaultint("general", "socktimeout", 0)
|
||||||
for listener in siglisteners:
|
if socktimeout > 0:
|
||||||
for sig in signum:
|
socket.setdefaulttimeout(socktimeout)
|
||||||
listener.put_nowait(sig)
|
|
||||||
signal.signal(signal.SIGHUP,sig_handler)
|
activeaccounts = config.get("general", "accounts")
|
||||||
signal.signal(signal.SIGUSR1,sig_handler)
|
if options.has_key('-a'):
|
||||||
signal.signal(signal.SIGUSR2,sig_handler)
|
activeaccounts = options['-a']
|
||||||
|
activeaccounts = activeaccounts.replace(" ", "")
|
||||||
threadutil.initexitnotify()
|
activeaccounts = activeaccounts.split(",")
|
||||||
t = ExitNotifyThread(target=syncmaster.syncitall,
|
allaccounts = accounts.AccountHashGenerator(config)
|
||||||
name='Sync Runner',
|
|
||||||
kwargs = {'accounts': syncaccounts,
|
syncaccounts = []
|
||||||
'config': config,
|
for account in activeaccounts:
|
||||||
'siglisteners': siglisteners})
|
if account not in allaccounts:
|
||||||
t.setDaemon(1)
|
if len(allaccounts) == 0:
|
||||||
t.start()
|
errormsg = 'The account "%s" does not exist because no accounts are defined!'%account
|
||||||
except:
|
else:
|
||||||
ui.mainException()
|
errormsg = 'The account "%s" does not exist. Valid accounts are:'%account
|
||||||
|
for name in allaccounts.keys():
|
||||||
try:
|
errormsg += '\n%s'%name
|
||||||
threadutil.exitnotifymonitorloop(threadutil.threadexited)
|
ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
|
||||||
except SystemExit:
|
if account not in syncaccounts:
|
||||||
raise
|
syncaccounts.append(account)
|
||||||
except:
|
|
||||||
ui.mainException() # Also expected to terminate.
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user