[PATCH] Prepare dynamic plugins (again)
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Here we go again, this time much smaller and without the
GnomeUI.
This patch allows ui plugins to be dropped only
inside the ui/plugins folder and work without modifying
any other file. This should be good for packagers.
* config:
Old config options like "Curses.Blinkenlights" still work
New ui plugins can use Modulename only if they provide a
getUIClass() method, I think thats a compromise
* default ui:
I have made Curses.Blinkenlights the default ui, but
perhaps TTY.TTYUI is a better choice for that.
* testing:
I tested against Blinkenlights, TTY and Gnome ui (which is not
yet in the mainline branch)
Signed-off-by: Christoph H=C3=B6ger <choeger@xxxxxxxxxxxxxxx>
---
HACKING | 11 +++++++
offlineimap/ui/__init__.py | 17 -----------
offlineimap/ui/detector.py | 35 +++++++++++++-----=
-----
offlineimap/ui/{ =3D> plugins}/Blinkenlights.py | 8 +----
offlineimap/ui/{ =3D> plugins}/Curses.py | 6 ++--
offlineimap/ui/{ =3D> plugins}/Machine.py | 4 +--
offlineimap/ui/{ =3D> plugins}/Noninteractive.py | 6 ++--
offlineimap/ui/{ =3D> plugins}/TTY.py | 2 +-
offlineimap/ui/plugins/__init__.py | 18 ++++++++++++
setup.py | 3 +-
10 files changed, 61 insertions(+), 49 deletions(-)
create mode 100644 HACKING
rename offlineimap/ui/{ =3D> plugins}/Blinkenlights.py (96%)
rename offlineimap/ui/{ =3D> plugins}/Curses.py (99%)
rename offlineimap/ui/{ =3D> plugins}/Machine.py (98%)
rename offlineimap/ui/{ =3D> plugins}/Noninteractive.py (93%)
rename offlineimap/ui/{ =3D> plugins}/TTY.py (98%)
create mode 100644 offlineimap/ui/plugins/__init__.py
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..8c6fb19
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,11 @@
+Developing your own UI
+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
+
+You can develop your own plugin by simply subclassing the UIBase class f=
rom offlineimap.ui.UIBase (have a look at TTYUI for a basic understanding=
of that).
+In difference to versions <=3D 6.2.0 you can now easily activate your pl=
ugin by putting it into the offlineimap/ui/plugins folder. This works wit=
hout any other preparation. So if your module is named foo.py and your UI=
class is Bar the user can now use it with offlineimap -u foo.Bar
+If you want to make the life of the user even easier, just add a getUICl=
ass() method in your module, let's say:
+
+ # note: you return a class, not the instance!
+ def getUIClass(): return Bar
+
+Then the user can run offlineimap -u foo even without knowing about Bar =
(allowing for multiple UI Classes in one module).
diff --git a/offlineimap/ui/__init__.py b/offlineimap/ui/__init__.py
index 0206ab4..081c1fc 100644
--- a/offlineimap/ui/__init__.py
+++ b/offlineimap/ui/__init__.py
@@ -16,23 +16,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-13=
01 USA
=20
-
-import UIBase, Blinkenlights
-try:
- import TTY
-except ImportError:
- pass
-
-try:
- import curses
-except ImportError:
- pass
-else:
- import Curses
-
-import Noninteractive
-import Machine
-
# Must be last
import detector
=20
diff --git a/offlineimap/ui/detector.py b/offlineimap/ui/detector.py
index 4ec7503..d73c9d0 100644
--- a/offlineimap/ui/detector.py
+++ b/offlineimap/ui/detector.py
@@ -19,17 +19,8 @@
import offlineimap.ui
import sys
=20
-DEFAULT_UI_LIST =3D ('Curses.Blinkenlights', 'TTY.TTYUI',
- 'Noninteractive.Basic', 'Noninteractive.Quiet',
- 'Machine.MachineUI')
-
def findUI(config, chosenUI=3DNone):
- uistrlist =3D list(DEFAULT_UI_LIST)
- namespace=3D{}
- for ui in dir(offlineimap.ui):
- if ui.startswith('_') or ui in ('detector', 'UIBase'):
- continue
- namespace[ui]=3Dgetattr(offlineimap.ui, ui)
+ uistrlist =3D ["Curses.Blinkenlights"]
=20
if chosenUI is not None:
uistrlist =3D [chosenUI]
@@ -37,7 +28,7 @@ def findUI(config, chosenUI=3DNone):
uistrlist =3D config.get("general", "ui").replace(" ", "").split=
(",")
=20
for uistr in uistrlist:
- uimod =3D getUImod(uistr, config.getlocaleval(), namespace)
+ uimod =3D getUImod(uistr)
if uimod:
uiinstance =3D uimod(config)
if uiinstance.isusable():
@@ -45,10 +36,24 @@ def findUI(config, chosenUI=3DNone):
sys.stderr.write("ERROR: No UIs were found usable!\n")
sys.exit(200)
=20
-def getUImod(uistr, localeval, namespace):
+def getUImod(uistr):
+ # ensure backwards compatibility with configs from <=3D 6.1
+ # uiClassName and dot will be empty if no . is found
+ uimodName,dot,uiClassName=3Duistr.partition(".")
+ =20
+ # this asserts that all elements are in place
try:
- uimod =3D localeval.eval(uistr, namespace)
+ # get the module from the plugin path
+ uimod =3D __import__("offlineimap.ui.plugins." + uimodName,[],[]=
,[uimodName])
+ if not uiClassName =3D=3D "":
+ # if uiClassName is set, we use the old method (introspectio=
n
+ # rocks!)
+ uiClass=3Duimod.__dict__[uiClassName]
+ else:
+ # asking the plugin for the class name is less error prone
+ uiClass =3D uimod.getUIClass()
except (AttributeError, NameError), e:
- #raise
+ print e
+ #raise
return None
- return uimod
+ return uiClass
diff --git a/offlineimap/ui/Blinkenlights.py b/offlineimap/ui/plugins/Bli=
nkenlights.py
similarity index 96%
rename from offlineimap/ui/Blinkenlights.py
rename to offlineimap/ui/plugins/Blinkenlights.py
index dcc4e01..6982351 100644
--- a/offlineimap/ui/Blinkenlights.py
+++ b/offlineimap/ui/plugins/Blinkenlights.py
@@ -127,15 +127,11 @@ class BlinkenBase:
return tf
finally:
s.tflock.release()
-
- def callhook(s, msg):
- s.gettf().setcolor('white')
- s.__class__.__bases__[-1].callhook(s, msg)
=20
- def sleep(s, sleepsecs, siglistener):
+ def sleep(s, sleepsecs):
s.gettf().setcolor('red')
s.getaccountframe().startsleep(sleepsecs)
- return UIBase.sleep(s, sleepsecs, siglistener)
+ UIBase.sleep(s, sleepsecs)
=20
def sleeping(s, sleepsecs, remainingsecs):
if remainingsecs and s.gettf().getcolor() =3D=3D 'black':
diff --git a/offlineimap/ui/Curses.py b/offlineimap/ui/plugins/Curses.py
similarity index 99%
rename from offlineimap/ui/Curses.py
rename to offlineimap/ui/plugins/Curses.py
index 8eb709f..949edb8 100644
--- a/offlineimap/ui/Curses.py
+++ b/offlineimap/ui/plugins/Curses.py
@@ -17,7 +17,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-13=
01 USA
=20
from Blinkenlights import BlinkenBase
-from UIBase import UIBase
+from offlineimap.ui.UIBase import UIBase
from threading import *
import thread, time, sys, os, signal, time
from offlineimap import version, threadutil
@@ -541,10 +541,10 @@ class Blinkenlights(BlinkenBase, UIBase):
s.c.stop()
UIBase.mainException(s)
=20
- def sleep(s, sleepsecs, siglistener):
+ def sleep(s, sleepsecs):
s.gettf().setcolor('red')
s._msg("Next sync in %d:%02d" % (sleepsecs / 60, sleepsecs % 60)=
)
- return BlinkenBase.sleep(s, sleepsecs, siglistener)
+ BlinkenBase.sleep(s, sleepsecs)
=20
if __name__ =3D=3D '__main__':
x =3D Blinkenlights(None)
diff --git a/offlineimap/ui/Machine.py b/offlineimap/ui/plugins/Machine.p=
y
similarity index 98%
rename from offlineimap/ui/Machine.py
rename to offlineimap/ui/plugins/Machine.py
index 0a07e3e..c77a3c5 100644
--- a/offlineimap/ui/Machine.py
+++ b/offlineimap/ui/plugins/Machine.py
@@ -17,7 +17,7 @@
=20
import offlineimap.version
import urllib, sys, re, time, traceback, threading, thread
-from UIBase import UIBase
+from offlineimap.ui.UIBase import UIBase
from threading import *
=20
protocol =3D '6.0.0'
@@ -175,5 +175,3 @@ class MachineUI(UIBase):
def init_banner(s):
s._printData('initbanner', offlineimap.version.banner)
=20
- def callhook(s, msg):
- s._printData('callhook', msg)
diff --git a/offlineimap/ui/Noninteractive.py b/offlineimap/ui/plugins/No=
ninteractive.py
similarity index 93%
rename from offlineimap/ui/Noninteractive.py
rename to offlineimap/ui/plugins/Noninteractive.py
index 9cd5eca..ca8ff5a 100644
--- a/offlineimap/ui/Noninteractive.py
+++ b/offlineimap/ui/plugins/Noninteractive.py
@@ -17,7 +17,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-13=
01 USA
=20
import sys, time
-from UIBase import UIBase
+from offlineimap.ui.UIBase import UIBase
=20
class Basic(UIBase):
def getpass(s, accountname, config, errmsg =3D None):
@@ -33,10 +33,10 @@ class Basic(UIBase):
warntxt =3D 'warning'
sys.stderr.write(warntxt + ": " + str(msg) + "\n")
=20
- def sleep(s, sleepsecs, siglistener):
+ def sleep(s, sleepsecs):
if s.verbose >=3D 0:
s._msg("Sleeping for %d:%02d" % (sleepsecs / 60, sleepsecs %=
60))
- return UIBase.sleep(s, sleepsecs, siglistener)
+ UIBase.sleep(s, sleepsecs)
=20
def sleeping(s, sleepsecs, remainingsecs):
if sleepsecs > 0:
diff --git a/offlineimap/ui/TTY.py b/offlineimap/ui/plugins/TTY.py
similarity index 98%
rename from offlineimap/ui/TTY.py
rename to offlineimap/ui/plugins/TTY.py
index 99c46d4..32d6279 100644
--- a/offlineimap/ui/TTY.py
+++ b/offlineimap/ui/plugins/TTY.py
@@ -16,7 +16,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-13=
01 USA
=20
-from UIBase import UIBase
+from offlineimap.ui.UIBase import UIBase
from getpass import getpass
import select, sys
from threading import *
diff --git a/offlineimap/ui/plugins/__init__.py b/offlineimap/ui/plugins/=
__init__.py
new file mode 100644
index 0000000..1b42165
--- /dev/null
+++ b/offlineimap/ui/plugins/__init__.py
@@ -0,0 +1,18 @@
+# UI module directory
+# Copyright (C) 2002 John Goerzen
+# <jgoerzen@xxxxxxxxxxxx>
+#
+# This program is free software; you can redistribute it and/or modif=
y
+# it under the terms of the GNU General Public License as published b=
y
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-13=
01 USA
+
diff --git a/setup.py b/setup.py
index 92fb1fd..fe3c53d 100644
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,8 @@ setup(name =3D "offlineimap",
author_email =3D offlineimap.version.author_email,
url =3D offlineimap.version.homepage,
packages =3D ['offlineimap', 'offlineimap.folder',
- 'offlineimap.repository', 'offlineimap.ui'],
+ 'offlineimap.repository',
+ 'offlineimap.ui','offlineimap.ui.plugins'],
scripts =3D ['bin/offlineimap'],
license =3D offlineimap.version.copyright + \
", Licensed under the GPL version 2"
--=20
1.6.2.5
- [PATCH] Prepare dynamic plugins (again),
Christoph Höger <=
[PATCH] Prepare dynamic plugins (again), Christoph Höger, 2009/09/09
|
|