UNIT_TEST=nosetests --with-doctest -w .
SYNTAX_TEST=support/test_syntax.py
+STYLE_TEST=../../Python/tools/pep8.py --ignore=W191,E501
LINT_RC=./support/pylint.rc
LINT=pylint --rcfile=$(LINT_RC)
PROFILE_GEN=python -m cProfile -o .profile
PROFILE_VIEW=python -m pstats .profile
+TODO_FINDER=support/todo.py
+CTAGS=ctags-exuberant
-.PHONY: all run profile test lint clean distclean install update_po build_mo
+.PHONY: all run profile debug test lint tags todo clean distclean install update_po build_mo
-all: build_mo
- python2.5 setup.py build
+all: test
-run:
+run: $(OBJ)
$(PROGRAM)
-profile:
+profile: $(OBJ)
$(PROFILE_GEN) $(PROGRAM)
$(PROFILE_VIEW)
+debug: $(OBJ)
+ $(DEBUGGER) $(PROGRAM)
+
test: $(OBJ)
$(UNIT_TEST)
lint: $(OBJ)
$(foreach file, $(SOURCE), $(LINT) $(file) ; )
-clean:
+tags: $(TAG_FILE)
+
+todo: $(TODO_FILE)
+
+clean:
rm -rf ./locale
- rm -rf $(OBJ)
+ rm -Rf $(OBJ)
rm -Rf $(BUILD_PATH)
- python2.5 setup.py clean --all
+ rm -Rf $(TODO_FILE)
-distclean: clean
+distclean:
+ rm -Rf $(OBJ)
+ rm -Rf $(BUILD_PATH)
+ rm -Rf $(TAG_FILE)
find $(SOURCE_PATH) -name "*.*~" | xargs rm -f
find $(SOURCE_PATH) -name "*.swp" | xargs rm -f
find $(SOURCE_PATH) -name "*.bak" | xargs rm -f
find $(SOURCE_PATH) -name ".*.swp" | xargs rm -f
-install: build_mo
- python2.5 setup.py install --root $(DESTDIR)
+$(TAG_FILE): $(OBJ)
+ mkdir -p $(dir $(TAG_FILE))
+ $(CTAGS) -o $(TAG_FILE) $(SOURCE)
+
+$(TODO_FILE): $(SOURCE)
+ @- $(TODO_FINDER) $(SOURCE) > $(TODO_FILE)
%.pyc: %.py
$(SYNTAX_TEST) $<
Name=Quicknote
Comment=Quicknote
Type=Application
-Exec=/usr/bin/quicknote.py
+Exec=/usr/bin/run-standalone.sh /usr/bin/quicknote.py
Icon=quicknote
X-Window-Icon=quicknote
X-Window-Icon-Dimmed=quicknote
+import os
+
__pretty_app_name__ = "Quicknote"
__app_name__ = "quicknote"
__version__ = "0.7.8"
+__build__ = 1
+_data_path_ = os.path.join(os.path.expanduser("~"), ".quicknote")
__app_magic__ = 0xdeadbeef
from __future__ import with_statement
+import os
+import errno
import sys
-import traceback
+import time
+import itertools
import functools
import contextlib
-import warnings
+import logging
+import threading
+import Queue
import gobject
import gtk
+_moduleLogger = logging.getLogger("gtk_toolbox")
+
+
+def get_screen_orientation():
+ width, height = gtk.gdk.get_default_root_window().get_size()
+ if width < height:
+ return gtk.ORIENTATION_VERTICAL
+ else:
+ return gtk.ORIENTATION_HORIZONTAL
+
+
+def orientation_change_connect(handler, *args):
+ """
+ @param handler(orientation, *args) -> None(?)
+ """
+ initialScreenOrientation = get_screen_orientation()
+ orientationAndArgs = list(itertools.chain((initialScreenOrientation, ), args))
+
+ def _on_screen_size_changed(screen):
+ newScreenOrientation = get_screen_orientation()
+ if newScreenOrientation != orientationAndArgs[0]:
+ orientationAndArgs[0] = newScreenOrientation
+ handler(*orientationAndArgs)
+
+ rootScreen = gtk.gdk.get_default_root_window()
+ return gtk.connect(rootScreen, "size-changed", _on_screen_size_changed)
+
+
+@contextlib.contextmanager
+def flock(path, timeout=-1):
+ WAIT_FOREVER = -1
+ DELAY = 0.1
+ timeSpent = 0
+
+ acquired = False
+
+ while timeSpent <= timeout or timeout == WAIT_FOREVER:
+ try:
+ fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR)
+ acquired = True
+ break
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+ time.sleep(DELAY)
+ timeSpent += DELAY
+
+ assert acquired, "Failed to grab file-lock %s within timeout %d" % (path, timeout)
+
+ try:
+ yield fd
+ finally:
+ os.unlink(path)
+
+
@contextlib.contextmanager
def gtk_lock():
gtk.gdk.threads_enter()
return immediate_func
+def autostart(func):
+ """
+ >>> @autostart
+ ... def grep_sink(pattern):
+ ... print "Looking for %s" % pattern
+ ... while True:
+ ... line = yield
+ ... if pattern in line:
+ ... print line,
+ >>> g = grep_sink("python")
+ Looking for python
+ >>> g.send("Yeah but no but yeah but no")
+ >>> g.send("A series of tubes")
+ >>> g.send("python generators rock!")
+ python generators rock!
+ >>> g.close()
+ """
+
+ @functools.wraps(func)
+ def start(*args, **kwargs):
+ cr = func(*args, **kwargs)
+ cr.next()
+ return cr
+
+ return start
+
+
+@autostart
+def printer_sink(format = "%s"):
+ """
+ >>> pr = printer_sink("%r")
+ >>> pr.send("Hello")
+ 'Hello'
+ >>> pr.send("5")
+ '5'
+ >>> pr.send(5)
+ 5
+ >>> p = printer_sink()
+ >>> p.send("Hello")
+ Hello
+ >>> p.send("World")
+ World
+ >>> # p.throw(RuntimeError, "Goodbye")
+ >>> # p.send("Meh")
+ >>> # p.close()
+ """
+ while True:
+ item = yield
+ print format % (item, )
+
+
+@autostart
+def null_sink():
+ """
+ Good for uses like with cochain to pick up any slack
+ """
+ while True:
+ item = yield
+
+
+@autostart
+def comap(function, target):
+ """
+ >>> p = printer_sink()
+ >>> cm = comap(lambda x: x+1, p)
+ >>> cm.send((0, ))
+ 1
+ >>> cm.send((1.0, ))
+ 2.0
+ >>> cm.send((-2, ))
+ -1
+ """
+ while True:
+ try:
+ item = yield
+ mappedItem = function(*item)
+ target.send(mappedItem)
+ except Exception, e:
+ _moduleLogger.exception("Forwarding exception!")
+ target.throw(e.__class__, str(e))
+
+
+def _flush_queue(queue):
+ while not queue.empty():
+ yield queue.get()
+
+
+@autostart
+def queue_sink(queue):
+ """
+ >>> q = Queue.Queue()
+ >>> qs = queue_sink(q)
+ >>> qs.send("Hello")
+ >>> qs.send("World")
+ >>> qs.throw(RuntimeError, "Goodbye")
+ >>> qs.send("Meh")
+ >>> qs.close()
+ >>> print [i for i in _flush_queue(q)]
+ [(None, 'Hello'), (None, 'World'), (<type 'exceptions.RuntimeError'>, 'Goodbye'), (None, 'Meh'), (<type 'exceptions.GeneratorExit'>, None)]
+ """
+ while True:
+ try:
+ item = yield
+ queue.put((None, item))
+ except Exception, e:
+ queue.put((e.__class__, str(e)))
+ except GeneratorExit:
+ queue.put((GeneratorExit, None))
+ raise
+
+
+def decode_item(item, target):
+ if item[0] is None:
+ target.send(item[1])
+ return False
+ elif item[0] is GeneratorExit:
+ target.close()
+ return True
+ else:
+ target.throw(item[0], item[1])
+ return False
+
+
+def nonqueue_source(queue, target):
+ isDone = False
+ while not isDone:
+ item = queue.get()
+ isDone = decode_item(item, target)
+ while not queue.empty():
+ queue.get_nowait()
+
+
+def threaded_stage(target, thread_factory = threading.Thread):
+ messages = Queue.Queue()
+
+ run_source = functools.partial(nonqueue_source, messages, target)
+ thread = thread_factory(target=run_source)
+ thread.setDaemon(True)
+ thread.start()
+
+ # Sink running in current thread
+ return queue_sink(messages)
+
+
+class LoginWindow(object):
+
+ def __init__(self, widgetTree):
+ """
+ @note Thread agnostic
+ """
+ self._dialog = widgetTree.get_widget("loginDialog")
+ self._parentWindow = widgetTree.get_widget("mainWindow")
+ self._serviceCombo = widgetTree.get_widget("serviceCombo")
+ self._usernameEntry = widgetTree.get_widget("usernameentry")
+ self._passwordEntry = widgetTree.get_widget("passwordentry")
+
+ self._serviceList = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
+ self._serviceCombo.set_model(self._serviceList)
+ cell = gtk.CellRendererText()
+ self._serviceCombo.pack_start(cell, True)
+ self._serviceCombo.add_attribute(cell, 'text', 1)
+ self._serviceCombo.set_active(0)
+
+ widgetTree.get_widget("loginbutton").connect("clicked", self._on_loginbutton_clicked)
+ widgetTree.get_widget("logins_close_button").connect("clicked", self._on_loginclose_clicked)
+
+ def request_credentials(self,
+ parentWindow = None,
+ defaultCredentials = ("", "")
+ ):
+ """
+ @note UI Thread
+ """
+ if parentWindow is None:
+ parentWindow = self._parentWindow
+
+ self._serviceCombo.hide()
+ self._serviceList.clear()
+
+ self._usernameEntry.set_text(defaultCredentials[0])
+ self._passwordEntry.set_text(defaultCredentials[1])
+
+ try:
+ self._dialog.set_transient_for(parentWindow)
+ self._dialog.set_default_response(gtk.RESPONSE_OK)
+ response = self._dialog.run()
+ if response != gtk.RESPONSE_OK:
+ raise RuntimeError("Login Cancelled")
+
+ username = self._usernameEntry.get_text()
+ password = self._passwordEntry.get_text()
+ self._passwordEntry.set_text("")
+ finally:
+ self._dialog.hide()
+
+ return username, password
+
+ def request_credentials_from(self,
+ services,
+ parentWindow = None,
+ defaultCredentials = ("", "")
+ ):
+ """
+ @note UI Thread
+ """
+ if parentWindow is None:
+ parentWindow = self._parentWindow
+
+ self._serviceList.clear()
+ for serviceIdserviceName in services:
+ self._serviceList.append(serviceIdserviceName)
+ self._serviceCombo.set_active(0)
+ self._serviceCombo.show()
+
+ self._usernameEntry.set_text(defaultCredentials[0])
+ self._passwordEntry.set_text(defaultCredentials[1])
+
+ try:
+ self._dialog.set_transient_for(parentWindow)
+ self._dialog.set_default_response(gtk.RESPONSE_OK)
+ response = self._dialog.run()
+ if response != gtk.RESPONSE_OK:
+ raise RuntimeError("Login Cancelled")
+
+ username = self._usernameEntry.get_text()
+ password = self._passwordEntry.get_text()
+ finally:
+ self._dialog.hide()
+
+ itr = self._serviceCombo.get_active_iter()
+ serviceId = int(self._serviceList.get_value(itr, 0))
+ self._serviceList.clear()
+ return serviceId, username, password
+
+ def _on_loginbutton_clicked(self, *args):
+ self._dialog.response(gtk.RESPONSE_OK)
+
+ def _on_loginclose_clicked(self, *args):
+ self._dialog.response(gtk.RESPONSE_CANCEL)
+
+
+def safecall(f, errorDisplay=None, default=None, exception=Exception):
+ '''
+ Returns modified f. When the modified f is called and throws an
+ exception, the default value is returned
+ '''
+ def _safecall(*args, **argv):
+ try:
+ return f(*args,**argv)
+ except exception, e:
+ if errorDisplay is not None:
+ errorDisplay.push_exception(e)
+ return default
+ return _safecall
+
+
class ErrorDisplay(object):
def __init__(self, widgetTree):
self.push_message(message)
def push_message(self, message):
- if 0 < len(self.__messages):
- self.__messages.append(message)
- else:
+ self.__messages.append(message)
+ if 1 == len(self.__messages):
self.__show_message(message)
- def push_exception_with_lock(self, exception = None):
+ def push_exception_with_lock(self):
with gtk_lock():
- self.push_exception(exception)
+ self.push_exception()
- def push_exception(self, exception = None):
- if exception is None:
- userMessage = str(sys.exc_value)
- warningMessage = str(traceback.format_exc())
- else:
- userMessage = str(exception)
- warningMessage = str(exception)
+ def push_exception(self):
+ userMessage = str(sys.exc_info()[1])
self.push_message(userMessage)
- warnings.warn(warningMessage, stacklevel=3)
+ _moduleLogger.exception(userMessage)
def pop_message(self):
- if 0 < len(self.__messages):
- self.__show_message(self.__messages[0])
- del self.__messages[0]
- else:
+ del self.__messages[0]
+ if 0 == len(self.__messages):
self.__hide_message()
+ else:
+ self.__errorDescription.set_text(self.__messages[0])
def _on_close(self, *args):
self.pop_message()
self.__show_message(message)
def push_exception(self, exception = None):
- if exception is None:
- warningMessage = traceback.format_exc()
- else:
- warningMessage = exception
- warnings.warn(warningMessage, stacklevel=3)
+ userMessage = str(sys.exc_value)
+ _moduleLogger.exception(userMessage)
def pop_message(self):
if 0 < len(self.__messages):
del self.__messages[0]
def __show_message(self, message):
- warnings.warn(message, stacklevel=2)
+ _moduleLogger.debug(message)
class MessageBox(gtk.MessageDialog):
try:
self._calendar.select_month(self._displayDate.month, self._displayDate.year)
self._calendar.select_day(self._displayDate.day)
- except StandardError, e:
- warnings.warn(e.message)
+ except Exception, e:
+ _moduleLogger.exception(e)
if __name__ == "__main__":
--- /dev/null
+#!/usr/bin/env python
+
+"""
+Open Issues
+ @bug Buttons are too small
+"""
+
+
+import gobject
+import gtk
+import dbus
+
+
+class _NullHildonModule(object):
+ pass
+
+
+try:
+ import hildon as _hildon
+ hildon = _hildon # Dumb but gets around pyflakiness
+except (ImportError, OSError):
+ hildon = _NullHildonModule
+
+
+IS_HILDON_SUPPORTED = hildon is not _NullHildonModule
+
+
+class _NullHildonProgram(object):
+
+ def add_window(self, window):
+ pass
+
+
+def _hildon_get_app_class():
+ return hildon.Program
+
+
+def _null_get_app_class():
+ return _NullHildonProgram
+
+
+try:
+ hildon.Program
+ get_app_class = _hildon_get_app_class
+except AttributeError:
+ get_app_class = _null_get_app_class
+
+
+def _hildon_set_application_title(window, title):
+ pass
+
+
+def _null_set_application_title(window, title):
+ window.set_title(title)
+
+
+if IS_HILDON_SUPPORTED:
+ set_application_title = _hildon_set_application_title
+else:
+ set_application_title = _null_set_application_title
+
+
+def _fremantle_hildonize_window(app, window):
+ oldWindow = window
+ newWindow = hildon.StackableWindow()
+ oldWindow.get_child().reparent(newWindow)
+ app.add_window(newWindow)
+ return newWindow
+
+
+def _hildon_hildonize_window(app, window):
+ oldWindow = window
+ newWindow = hildon.Window()
+ oldWindow.get_child().reparent(newWindow)
+ app.add_window(newWindow)
+ return newWindow
+
+
+def _null_hildonize_window(app, window):
+ return window
+
+
+try:
+ hildon.StackableWindow
+ hildonize_window = _fremantle_hildonize_window
+except AttributeError:
+ try:
+ hildon.Window
+ hildonize_window = _hildon_hildonize_window
+ except AttributeError:
+ hildonize_window = _null_hildonize_window
+
+
+def _fremantle_hildonize_menu(window, gtkMenu, buttons):
+ appMenu = hildon.AppMenu()
+ for button in buttons:
+ appMenu.append(button)
+ window.set_app_menu(appMenu)
+ gtkMenu.get_parent().remove(gtkMenu)
+ return appMenu
+
+
+def _hildon_hildonize_menu(window, gtkMenu, ignoredButtons):
+ hildonMenu = gtk.Menu()
+ for child in gtkMenu.get_children():
+ child.reparent(hildonMenu)
+ window.set_menu(hildonMenu)
+ gtkMenu.destroy()
+ return hildonMenu
+
+
+def _null_hildonize_menu(window, gtkMenu, ignoredButtons):
+ return gtkMenu
+
+
+try:
+ hildon.AppMenu
+ GTK_MENU_USED = False
+ IS_FREMANTLE_SUPPORTED = True
+ hildonize_menu = _fremantle_hildonize_menu
+except AttributeError:
+ GTK_MENU_USED = True
+ IS_FREMANTLE_SUPPORTED = False
+ if IS_HILDON_SUPPORTED:
+ hildonize_menu = _hildon_hildonize_menu
+ else:
+ hildonize_menu = _null_hildonize_menu
+
+
+def _hildon_set_button_auto_selectable(button):
+ button.set_theme_size(hildon.HILDON_SIZE_AUTO_HEIGHT)
+
+
+def _null_set_button_auto_selectable(button):
+ pass
+
+
+try:
+ hildon.HILDON_SIZE_AUTO_HEIGHT
+ gtk.Button.set_theme_size
+ set_button_auto_selectable = _hildon_set_button_auto_selectable
+except AttributeError:
+ set_button_auto_selectable = _null_set_button_auto_selectable
+
+
+def _hildon_set_button_finger_selectable(button):
+ button.set_theme_size(hildon.HILDON_SIZE_FINGER_HEIGHT)
+
+
+def _null_set_button_finger_selectable(button):
+ pass
+
+
+try:
+ hildon.HILDON_SIZE_FINGER_HEIGHT
+ gtk.Button.set_theme_size
+ set_button_finger_selectable = _hildon_set_button_finger_selectable
+except AttributeError:
+ set_button_finger_selectable = _null_set_button_finger_selectable
+
+
+def _hildon_set_button_thumb_selectable(button):
+ button.set_theme_size(hildon.HILDON_SIZE_THUMB_HEIGHT)
+
+
+def _null_set_button_thumb_selectable(button):
+ pass
+
+
+try:
+ hildon.HILDON_SIZE_THUMB_HEIGHT
+ gtk.Button.set_theme_size
+ set_button_thumb_selectable = _hildon_set_button_thumb_selectable
+except AttributeError:
+ set_button_thumb_selectable = _null_set_button_thumb_selectable
+
+
+def _hildon_set_cell_thumb_selectable(renderer):
+ renderer.set_property("scale", 1.5)
+
+
+def _null_set_cell_thumb_selectable(renderer):
+ pass
+
+
+if IS_HILDON_SUPPORTED:
+ set_cell_thumb_selectable = _hildon_set_cell_thumb_selectable
+else:
+ set_cell_thumb_selectable = _null_set_cell_thumb_selectable
+
+
+def _fremantle_show_information_banner(parent, message):
+ hildon.hildon_banner_show_information(parent, "", message)
+
+
+def _hildon_show_information_banner(parent, message):
+ hildon.hildon_banner_show_information(parent, None, message)
+
+
+def _null_show_information_banner(parent, message):
+ pass
+
+
+if IS_FREMANTLE_SUPPORTED:
+ show_information_banner = _fremantle_show_information_banner
+else:
+ try:
+ hildon.hildon_banner_show_information
+ show_information_banner = _hildon_show_information_banner
+ except AttributeError:
+ show_information_banner = _null_show_information_banner
+
+
+def _fremantle_show_busy_banner_start(parent, message):
+ hildon.hildon_gtk_window_set_progress_indicator(parent, True)
+ return parent
+
+
+def _fremantle_show_busy_banner_end(banner):
+ hildon.hildon_gtk_window_set_progress_indicator(banner, False)
+
+
+def _hildon_show_busy_banner_start(parent, message):
+ return hildon.hildon_banner_show_animation(parent, None, message)
+
+
+def _hildon_show_busy_banner_end(banner):
+ banner.destroy()
+
+
+def _null_show_busy_banner_start(parent, message):
+ return None
+
+
+def _null_show_busy_banner_end(banner):
+ assert banner is None
+
+
+try:
+ hildon.hildon_gtk_window_set_progress_indicator
+ show_busy_banner_start = _fremantle_show_busy_banner_start
+ show_busy_banner_end = _fremantle_show_busy_banner_end
+except AttributeError:
+ try:
+ hildon.hildon_banner_show_animation
+ show_busy_banner_start = _hildon_show_busy_banner_start
+ show_busy_banner_end = _hildon_show_busy_banner_end
+ except AttributeError:
+ show_busy_banner_start = _null_show_busy_banner_start
+ show_busy_banner_end = _null_show_busy_banner_end
+
+
+def _hildon_hildonize_text_entry(textEntry):
+ textEntry.set_property('hildon-input-mode', 7)
+
+
+def _null_hildonize_text_entry(textEntry):
+ pass
+
+
+if IS_HILDON_SUPPORTED:
+ hildonize_text_entry = _hildon_hildonize_text_entry
+else:
+ hildonize_text_entry = _null_hildonize_text_entry
+
+
+def _hildon_mark_window_rotatable(window):
+ # gtk documentation is unclear whether this does a "=" or a "|="
+ window.set_flags(hildon.HILDON_PORTRAIT_MODE_SUPPORT)
+
+
+def _null_mark_window_rotatable(window):
+ pass
+
+
+try:
+ hildon.HILDON_PORTRAIT_MODE_SUPPORT
+ mark_window_rotatable = _hildon_mark_window_rotatable
+except AttributeError:
+ mark_window_rotatable = _null_mark_window_rotatable
+
+
+def _hildon_window_to_portrait(window):
+ # gtk documentation is unclear whether this does a "=" or a "|="
+ window.set_flags(hildon.HILDON_PORTRAIT_MODE_SUPPORT)
+
+
+def _hildon_window_to_landscape(window):
+ # gtk documentation is unclear whether this does a "=" or a "&= ~"
+ window.unset_flags(hildon.HILDON_PORTRAIT_MODE_REQUEST)
+
+
+def _null_window_to_portrait(window):
+ pass
+
+
+def _null_window_to_landscape(window):
+ pass
+
+
+try:
+ hildon.HILDON_PORTRAIT_MODE_SUPPORT
+ hildon.HILDON_PORTRAIT_MODE_REQUEST
+
+ window_to_portrait = _hildon_window_to_portrait
+ window_to_landscape = _hildon_window_to_landscape
+except AttributeError:
+ window_to_portrait = _null_window_to_portrait
+ window_to_landscape = _null_window_to_landscape
+
+
+def get_device_orientation():
+ bus = dbus.SystemBus()
+ try:
+ rawMceRequest = bus.get_object("com.nokia.mce", "/com/nokia/mce/request")
+ mceRequest = dbus.Interface(rawMceRequest, dbus_interface="com.nokia.mce.request")
+ orientation, standState, faceState, xAxis, yAxis, zAxis = mceRequest.get_device_orientation()
+ except dbus.exception.DBusException:
+ # catching for documentation purposes that when a system doesn't
+ # support this, this is what to expect
+ raise
+
+ if orientation == "":
+ return gtk.ORIENTATION_HORIZONTAL
+ elif orientation == "":
+ return gtk.ORIENTATION_VERTICAL
+ else:
+ raise RuntimeError("Unknown orientation: %s" % orientation)
+
+
+def _hildon_hildonize_password_entry(textEntry):
+ textEntry.set_property('hildon-input-mode', 7 | (1 << 29))
+
+
+def _null_hildonize_password_entry(textEntry):
+ pass
+
+
+if IS_HILDON_SUPPORTED:
+ hildonize_password_entry = _hildon_hildonize_password_entry
+else:
+ hildonize_password_entry = _null_hildonize_password_entry
+
+
+def _hildon_hildonize_combo_entry(comboEntry):
+ comboEntry.set_property('hildon-input-mode', 1 << 4)
+
+
+def _null_hildonize_combo_entry(textEntry):
+ pass
+
+
+if IS_HILDON_SUPPORTED:
+ hildonize_combo_entry = _hildon_hildonize_combo_entry
+else:
+ hildonize_combo_entry = _null_hildonize_combo_entry
+
+
+def _fremantle_hildonize_scrollwindow(scrolledWindow):
+ pannableWindow = hildon.PannableArea()
+
+ child = scrolledWindow.get_child()
+ scrolledWindow.remove(child)
+ pannableWindow.add(child)
+
+ parent = scrolledWindow.get_parent()
+ parent.remove(scrolledWindow)
+ parent.add(pannableWindow)
+
+ return pannableWindow
+
+
+def _hildon_hildonize_scrollwindow(scrolledWindow):
+ hildon.hildon_helper_set_thumb_scrollbar(scrolledWindow, True)
+ return scrolledWindow
+
+
+def _null_hildonize_scrollwindow(scrolledWindow):
+ return scrolledWindow
+
+
+try:
+ hildon.PannableArea
+ hildonize_scrollwindow = _fremantle_hildonize_scrollwindow
+ hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
+except AttributeError:
+ try:
+ hildon.hildon_helper_set_thumb_scrollbar
+ hildonize_scrollwindow = _hildon_hildonize_scrollwindow
+ hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
+ except AttributeError:
+ hildonize_scrollwindow = _null_hildonize_scrollwindow
+ hildonize_scrollwindow_with_viewport = _null_hildonize_scrollwindow
+
+
+def _hildon_request_number(parent, title, range, default):
+ spinner = hildon.NumberEditor(*range)
+ spinner.set_value(default)
+
+ dialog = gtk.Dialog(
+ title,
+ parent,
+ gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+ )
+ dialog.set_default_response(gtk.RESPONSE_CANCEL)
+ dialog.get_child().add(spinner)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_OK:
+ return spinner.get_value()
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+ finally:
+ dialog.hide()
+ dialog.destroy()
+
+
+def _null_request_number(parent, title, range, default):
+ adjustment = gtk.Adjustment(default, range[0], range[1], 1, 5, 0)
+ spinner = gtk.SpinButton(adjustment, 0, 0)
+ spinner.set_wrap(False)
+
+ dialog = gtk.Dialog(
+ title,
+ parent,
+ gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+ )
+ dialog.set_default_response(gtk.RESPONSE_CANCEL)
+ dialog.get_child().add(spinner)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_OK:
+ return spinner.get_value_as_int()
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+ finally:
+ dialog.hide()
+ dialog.destroy()
+
+
+try:
+ hildon.NumberEditor # TODO deprecated in fremantle
+ request_number = _hildon_request_number
+except AttributeError:
+ request_number = _null_request_number
+
+
+def _hildon_touch_selector(parent, title, items, defaultIndex):
+ model = gtk.ListStore(gobject.TYPE_STRING)
+ for item in items:
+ model.append((item, ))
+
+ selector = hildon.TouchSelector()
+ selector.append_text_column(model, True)
+ selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
+ selector.set_active(0, defaultIndex)
+
+ dialog = hildon.PickerDialog(parent)
+ dialog.set_selector(selector)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_OK:
+ return selector.get_active(0)
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+ finally:
+ dialog.hide()
+ dialog.destroy()
+
+
+def _on_null_touch_selector_activated(treeView, path, column, dialog, pathData):
+ dialog.response(gtk.RESPONSE_OK)
+ pathData[0] = path
+
+
+def _null_touch_selector(parent, title, items, defaultIndex = -1):
+ parentSize = parent.get_size()
+
+ model = gtk.ListStore(gobject.TYPE_STRING)
+ for item in items:
+ model.append((item, ))
+
+ cell = gtk.CellRendererText()
+ set_cell_thumb_selectable(cell)
+ column = gtk.TreeViewColumn(title)
+ column.pack_start(cell, expand=True)
+ column.add_attribute(cell, "text", 0)
+
+ treeView = gtk.TreeView()
+ treeView.set_model(model)
+ treeView.append_column(column)
+ selection = treeView.get_selection()
+ selection.set_mode(gtk.SELECTION_SINGLE)
+ if 0 < defaultIndex:
+ selection.select_path((defaultIndex, ))
+
+ scrolledWin = gtk.ScrolledWindow()
+ scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scrolledWin.add(treeView)
+
+ dialog = gtk.Dialog(
+ title,
+ parent,
+ gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+ )
+ dialog.set_default_response(gtk.RESPONSE_CANCEL)
+ dialog.get_child().add(scrolledWin)
+ dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
+
+ scrolledWin = hildonize_scrollwindow(scrolledWin)
+ pathData = [None]
+ treeView.connect("row-activated", _on_null_touch_selector_activated, dialog, pathData)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_OK:
+ if pathData[0] is None:
+ raise RuntimeError("No selection made")
+ return pathData[0][0]
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+ finally:
+ dialog.hide()
+ dialog.destroy()
+
+
+try:
+ hildon.PickerDialog
+ hildon.TouchSelector
+ touch_selector = _hildon_touch_selector
+except AttributeError:
+ touch_selector = _null_touch_selector
+
+
+def _hildon_touch_selector_entry(parent, title, items, defaultItem):
+ # Got a segfault when using append_text_column with TouchSelectorEntry, so using this way
+ try:
+ selector = hildon.TouchSelectorEntry(text=True)
+ except TypeError:
+ selector = hildon.hildon_touch_selector_entry_new_text()
+ defaultIndex = -1
+ for i, item in enumerate(items):
+ selector.append_text(item)
+ if item == defaultItem:
+ defaultIndex = i
+
+ dialog = hildon.PickerDialog(parent)
+ dialog.set_selector(selector)
+
+ if 0 < defaultIndex:
+ selector.set_active(0, defaultIndex)
+ else:
+ selector.get_entry().set_text(defaultItem)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+ finally:
+ dialog.hide()
+
+ if response == gtk.RESPONSE_OK:
+ return selector.get_entry().get_text()
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+
+
+def _on_null_touch_selector_entry_entry_changed(entry, result, selection, defaultIndex):
+ custom = entry.get_text().strip()
+ if custom:
+ result[0] = custom
+ selection.unselect_all()
+ else:
+ result[0] = None
+ selection.select_path((defaultIndex, ))
+
+
+def _on_null_touch_selector_entry_entry_activated(customEntry, dialog, result):
+ dialog.response(gtk.RESPONSE_OK)
+ result[0] = customEntry.get_text()
+
+
+def _on_null_touch_selector_entry_tree_activated(treeView, path, column, dialog, result):
+ dialog.response(gtk.RESPONSE_OK)
+ model = treeView.get_model()
+ itr = model.get_iter(path)
+ if itr is not None:
+ result[0] = model.get_value(itr, 0)
+
+
+def _null_touch_selector_entry(parent, title, items, defaultItem):
+ parentSize = parent.get_size()
+
+ model = gtk.ListStore(gobject.TYPE_STRING)
+ defaultIndex = -1
+ for i, item in enumerate(items):
+ model.append((item, ))
+ if item == defaultItem:
+ defaultIndex = i
+
+ cell = gtk.CellRendererText()
+ set_cell_thumb_selectable(cell)
+ column = gtk.TreeViewColumn(title)
+ column.pack_start(cell, expand=True)
+ column.add_attribute(cell, "text", 0)
+
+ treeView = gtk.TreeView()
+ treeView.set_model(model)
+ treeView.append_column(column)
+ selection = treeView.get_selection()
+ selection.set_mode(gtk.SELECTION_SINGLE)
+
+ scrolledWin = gtk.ScrolledWindow()
+ scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scrolledWin.add(treeView)
+
+ customEntry = gtk.Entry()
+
+ layout = gtk.VBox()
+ layout.pack_start(customEntry, expand=False)
+ layout.pack_start(scrolledWin)
+
+ dialog = gtk.Dialog(
+ title,
+ parent,
+ gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+ )
+ dialog.set_default_response(gtk.RESPONSE_CANCEL)
+ dialog.get_child().add(layout)
+ dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
+
+ scrolledWin = hildonize_scrollwindow(scrolledWin)
+
+ result = [None]
+ if 0 < defaultIndex:
+ selection.select_path((defaultIndex, ))
+ result[0] = defaultItem
+ else:
+ customEntry.set_text(defaultItem)
+
+ customEntry.connect("activate", _on_null_touch_selector_entry_entry_activated, dialog, result)
+ customEntry.connect("changed", _on_null_touch_selector_entry_entry_changed, result, selection, defaultIndex)
+ treeView.connect("row-activated", _on_null_touch_selector_entry_tree_activated, dialog, result)
+
+ try:
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_OK:
+ _, itr = selection.get_selected()
+ if itr is not None:
+ return model.get_value(itr, 0)
+ else:
+ enteredText = customEntry.get_text().strip()
+ if enteredText:
+ return enteredText
+ elif result[0] is not None:
+ return result[0]
+ else:
+ raise RuntimeError("No selection made")
+ elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+ raise RuntimeError("User cancelled request")
+ else:
+ raise RuntimeError("Unrecognized response %r", response)
+ finally:
+ dialog.hide()
+ dialog.destroy()
+
+
+try:
+ hildon.PickerDialog
+ hildon.TouchSelectorEntry
+ touch_selector_entry = _hildon_touch_selector_entry
+except AttributeError:
+ touch_selector_entry = _null_touch_selector_entry
+
+
+if __name__ == "__main__":
+ app = get_app_class()()
+
+ label = gtk.Label("Hello World from a Label!")
+
+ win = gtk.Window()
+ win.add(label)
+ win = hildonize_window(app, win)
+ if False:
+ print touch_selector(win, "Test", ["A", "B", "C", "D"], 2)
+ if True:
+ print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "C")
+ print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "Blah")
+ if False:
+ import pprint
+ name, value = "", ""
+ goodLocals = [
+ (name, value) for (name, value) in locals().iteritems()
+ if not name.startswith("_")
+ ]
+ pprint.pprint(goodLocals)
+ if False:
+ import time
+ show_information_banner(win, "Hello World")
+ time.sleep(5)
+ if False:
+ import time
+ banner = show_busy_banner_start(win, "Hello World")
+ time.sleep(5)
+ show_busy_banner_end(banner)
"""
+import logging
+
import gtk
_ = lambda x: x
+_moduleLogger = logging.getLogger("history")
+
+
class Dialog(gtk.Dialog):
def __init__(self, daten = None):
_ = lambda x: x
+_moduleLogger = logging.getLogger("kopfzeile")
+
+
class Kopfzeile(gtk.HBox):
__gsignals__ = {
self._db = db
gtk.HBox.__init__(self, homogeneous = False, spacing = 3)
- logging.info("libkopfzeile, init")
+ _moduleLogger.info("libkopfzeile, init")
categoryHBox = gtk.HBox()
self.pack_start(categoryHBox, expand = False, fill = True, padding = 0)
self._searchEntry.connect("changed", self.search_entry_changed, None)
def category_combo_changed(self, widget = None, data = None):
- logging.debug("comboCategoryChanged")
+ _moduleLogger.debug("comboCategoryChanged")
if self._lastCategory != self.categoryCombo.get_active():
sql = "UPDATE categories SET liste = ? WHERE id = 1"
self._db.speichereSQL(sql, (self.categoryCombo.get_active(), ))
self.emit("reload_notes")
def search_entry_changed(self, widget = None, data = None):
- logging.debug("search_entry_changed")
+ _moduleLogger.debug("search_entry_changed")
self.emit("reload_notes")
def get_category(self):
_ = lambda x: x
+_moduleLogger = logging.getLogger("notizen")
+
+
class Notizen(gtk.HBox):
def __init__(self, db, topBox):
self._categoryName = ""
gtk.HBox.__init__(self, homogeneous = False, spacing = 0)
- logging.info("libnotizen, init")
+ _moduleLogger.info("libnotizen, init")
self._noteslist = simple_list.SimpleList()
self._noteslist.set_eventfunction_cursor_changed(self._update_noteslist)
self._historyBox.hide()
def load_notes(self, data = None):
- logging.info("load_notes params: pos:"+str(self._pos)+" noteid:"+str(self.noteId))
+ _moduleLogger.info("load_notes params: pos:"+str(self._pos)+" noteid:"+str(self.noteId))
self._noteslist.clear_items()
self._noteslist.append_item(_("New Note..."), "new")
self._noteBodyView.get_buffer().set_text("")
def save_note(self, widget = None, data = None, data2 = None):
- logging.info("save_note params: pos:"+str(self._pos)+" noteid:"+str(self.noteId))
+ _moduleLogger.info("save_note params: pos:"+str(self._pos)+" noteid:"+str(self.noteId))
#print "params:", data, data2
buf = self._noteBodyView.get_buffer().get_text(self._noteBodyView.get_buffer().get_start_iter(), self._noteBodyView.get_buffer().get_end_iter())
if buf is None or len(buf) == 0:
if buf == self._noteBody:
return
- logging.info("Saving note: "+buf)
+ _moduleLogger.info("Saving note: "+buf)
if self._pos == -1 or self.noteId == -1:
self._pos = -1
self.noteId = str(uuid.uuid4())
data = dialog.get_selected_row()
if data is not None:
self._db.speichereSQL(data[2], data[3].split(" <<Tren-ner>> "), rowid = self.noteId)
- logging.info("loading History")
+ _moduleLogger.info("loading History")
self._update_noteslist()
dialog.destroy()
-#/usr/bin/env python2.5
+#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
_ = lambda x: x
+_moduleLogger = logging.getLogger("quick")
+
+
class QuicknoteProgram(hildon.Program):
_user_data = os.path.join(os.path.expanduser("~"), ".%s" % constants.__app_name__)
dblog = os.path.join(self._user_data, "quicknote.log")
- # define a Handler which writes INFO messages or higher to the sys.stderr
- console = logging.StreamHandler()
- console.setLevel(logging.DEBUG)
- # set a format which is simpler for console use
- formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
- # tell the handler to use this format
- console.setFormatter(formatter)
- # add the handler to the root logger
- logging.getLogger('').addHandler(console)
-
- logging.info('Starting quicknote')
+ _moduleLogger.info('Starting quicknote')
if osso is not None:
self._osso_c = osso.Context(constants.__app_name__, constants.__version__, False)
res = sqldiag.run()
sqldiag.hide()
if res == sqldiag.EXPORT_RESPONSE:
- logging.info("exporting sql")
+ _moduleLogger.info("exporting sql")
dlg = hildon.FileChooserDialog(parent=self._window, action=gtk.FILE_CHOOSER_ACTION_SAVE)
dialog.set_authors(["Christoph Wurstle <n800@axique.net>", "Ed Page <edpage@byu.net> (Blame him for the most recent bugs)"])
dialog.run()
dialog.destroy()
+
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.DEBUG)
+ app = QuicknoteProgram()
+ app.main()
_ = lambda x: x
+_moduleLogger = logging.getLogger("speichern")
+
+
class Speichern():
def __init__(self):
def speichereDirekt(self, schluessel, daten):
self.d[schluessel] = daten
- logging.info("speichereDirekt "+str(schluessel)+" "+str(daten)+" lesen: "+str(self.d[schluessel]))
+ _moduleLogger.info("speichereDirekt "+str(schluessel)+" "+str(daten)+" lesen: "+str(self.d[schluessel]))
def ladeDirekt(self, schluessel, default = ""):
if (self.d.has_key(schluessel) == True):
s = str(sys.exc_info())
if s.find(" already exists") == -1:
if (programSQLError == True):
- logging.error("speichereSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
+ _moduleLogger.error("speichereSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
else:
- logging.error("speichereSQL-Exception in Logging!!!! :"+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
+ _moduleLogger.error("speichereSQL-Exception in Logging!!!! :"+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
return False
def commitSQL(self):
self.cur.execute(sql, tupel)
return self.cur.fetchall()
except StandardError:
- logging.error("ladeSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
+ _moduleLogger.error("ladeSQL-Exception "+str(sys.exc_info())+" "+str(sql)+" "+str(tupel))
return ()
def ladeHistory(self, sql_condition, param_condition):
self.conn.close()
except StandardError:
pass
- logging.info("Alle Data saved")
+ _moduleLogger.info("Alle Data saved")
def __del__(self):
self.close()
_ = lambda x: x
+_moduleLogger = logging.getLogger("sqldialog")
+
+
class SqlDialog(gtk.Dialog):
EXPORT_RESPONSE = 444
def __init__(self, db):
self.db = db
- logging.info("sqldialog, init")
+ _moduleLogger.info("sqldialog, init")
gtk.Dialog.__init__(self, _("SQL History (the past two days):"), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
_ = lambda x: x
+_moduleLogger = logging.getLogger("sync")
+
+
class ProgressDialog(gtk.Dialog):
def __init__(self, title = _("Sync process"), parent = None):
gtk.Dialog.__init__(self, title, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, ())
- logging.info("ProgressDialog, init")
+ _moduleLogger.info("ProgressDialog, init")
label = gtk.Label(_("Sync process running...please wait"))
self.vbox.pack_start(label, True, True, 0)
def __init__(self, db, parentwindow, port):
gtk.VBox.__init__(self, homogeneous = False, spacing = 0)
- logging.info("Sync, init")
+ _moduleLogger.info("Sync, init")
self.db = db
self.progress = None
self.server = None
syncpartner, pcdatum = rows[0]
else:
pcdatum = -1
- logging.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time())))
+ _moduleLogger.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time())))
return pcdatum
def check4commit(self, newSQL, lastdate):
- logging.info("check4commit 1")
+ _moduleLogger.info("check4commit 1")
if self.concernedRows is None:
- logging.info("check4commit Updatung concernedRows")
+ _moduleLogger.info("check4commit Updatung concernedRows")
sql = "SELECT pcdatum, rowid FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
self.concernedRows = self.db.ladeSQL(sql, (lastdate, ))
for x in self.concernedRows:
if x[1] == rowid:
if pcdatum < x[0]:
- logging.info("newer sync entry, ignoring old one")
+ _moduleLogger.info("newer sync entry, ignoring old one")
return False
else:
return True
self.concernedRows = None
pausenzaehler = 0
- logging.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels")
+ _moduleLogger.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels")
for newSQL in newSQLs:
if newSQL[3] != "":
param = newSQL[3].split(" <<Tren-ner>> ")
if (commitSQL == True):
self.db.speichereSQL(newSQL[2], param, commit = False, pcdatum = newSQL[1], rowid = newSQL[5])
else:
- logging.error("writeSQLTupel: Error")
+ _moduleLogger.error("writeSQLTupel: Error")
pausenzaehler += 1
if (pausenzaehler % 10) == 0:
while gtk.events_pending():
gtk.main_iteration()
- logging.info("Alle SQLs an sqlite geschickt, commiting now")
+ _moduleLogger.info("Alle SQLs an sqlite geschickt, commiting now")
self.db.commitSQL()
- logging.info("Alle SQLs commited")
+ _moduleLogger.info("Alle SQLs commited")
def doSync(self, sync_uuid, pcdatum, newSQLs, pcdatumjetzt):
self.changeSyncStatus(True, "sync process running")
if 30 < diff:
return -1
- logging.info("doSync read sqls")
+ _moduleLogger.info("doSync read sqls")
sql = "SELECT * FROM logtable WHERE pcdatum>?"
rows = self.db.ladeSQL(sql, (pcdatum, ))
- logging.info("doSync read sqls")
+ _moduleLogger.info("doSync read sqls")
self.writeSQLTupel(newSQLs, pcdatum)
- logging.info("doSync wrote "+str(len(newSQLs))+" sqls")
- logging.info("doSync sending "+str(len(rows))+" sqls")
+ _moduleLogger.info("doSync wrote "+str(len(newSQLs))+" sqls")
+ _moduleLogger.info("doSync sending "+str(len(rows))+" sqls")
return rows
def getRemoteSyncUUID(self):
self.db.speichereDirekt("syncServerIP", self.comboIP.get_child().get_text())
if widget.get_active():
- logging.info("Starting Server")
+ _moduleLogger.info("Starting Server")
try:
ip = self.comboIP.get_child().get_text()
except StandardError:
s = str(sys.exc_info())
- logging.error("libsync: could not start server. Error: "+s)
+ _moduleLogger.error("libsync: could not start server. Error: "+s)
mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Could not start SyncServer. Check IP, port settings.")) #gtk.DIALOG_MODAL
mbox.set_modal(False)
response = mbox.run()
mbox.destroy()
widget.set_active(False)
else:
- logging.info("Stopping Server")
+ _moduleLogger.info("Stopping Server")
try:
del self.rpcserver
except StandardError:
return (self.sync_uuid, pcdatum)
def syncButton(self, widget, data = None):
- logging.info("Syncing")
+ _moduleLogger.info("Syncing")
self.changeSyncStatus(True, _("sync process running"))
while (gtk.events_pending()):
sql = "SELECT * FROM logtable WHERE pcdatum>?"
rows = self.db.ladeSQL(sql, (lastDate, ))
- logging.info("loaded concerned rows")
+ _moduleLogger.info("loaded concerned rows")
newSQLs = self.server.doSync(self.sync_uuid, lastDate, rows, time.time())
- logging.info("did do sync, processing sqls now")
+ _moduleLogger.info("did do sync, processing sqls now")
if newSQLs != -1:
self.writeSQLTupel(newSQLs, lastDate)
mbox.hide()
mbox.destroy()
else:
- logging.warning("Zeitdiff zu groß/oder anderer db-Fehler")
+ _moduleLogger.warning("Zeitdiff zu groß/oder anderer db-Fehler")
self.changeSyncStatus(False, _("no sync process (at the moment)"))
mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("The clocks are not synchronized between stations"))
response = mbox.run()
mbox.hide()
mbox.destroy()
except StandardError:
- logging.warning("Sync connect failed")
+ _moduleLogger.warning("Sync connect failed")
self.changeSyncStatus(False, _("no sync process (at the moment)"))
mbox = gtk.MessageDialog(
None,
published by the Free Software Foundation.
"""
-
+import os
import sys
-sys.path.append('/usr/lib/quicknote')
-
-import locale
+import logging
import gettext
+
+_moduleLogger = logging.getLogger("quicknote")
gettext.install('quicknote', unicode = 1)
+sys.path.append('/usr/lib/quicknote')
+
+import constants
import libquicknote
if __name__ == "__main__":
+ try:
+ os.makedirs(constants._data_path_)
+ except OSError, e:
+ if e.errno != 17:
+ raise
+
+ userLogPath = "%s/quicknote.log" % constants._data_path_
+ logging.basicConfig(level=logging.DEBUG, filename=userLogPath)
+ _moduleLogger.info("quicknote %s-%s" % (constants.__version__, constants.__build__))
+
app = libquicknote.QuicknoteProgram()
app.main()
__appname__ = constants.__app_name__
-__description__ = "Simple note taking application in a similar vein as PalmOS Memos"
+__description__ = """Simple note taking application in a similar vein as PalmOS Memos
+.
+Homepage: http://quicknote.garage.maemo.org/
+"""
__author__ = "Christoph Wurstle"
__email__ = "n800@axique.net"
__version__ = constants.__version__
-__build__ = 0
-__changelog__ = '''
+__build__ = constants.__build__
+__changelog__ = """
0.7.8
* Spell checking
* Fixing the application title
0.7.0
* Initial Release.
-'''
+"""
-__postinstall__ = '''#!/bin/sh -e
+__postinstall__ = """#!/bin/sh -e
gtk-update-icon-cache -f /usr/share/icons/hicolor
-exit 0
-'''
+rm -f ~/.quicknote/quicknote.log
+"""
def find_files(path, root):
except:
pass
+ py2deb.Py2deb.SECTIONS = py2deb.SECTIONS_BY_POLICY[distribution]
p = py2deb.Py2deb(__appname__)
+ p.prettyName = constants.__pretty_app_name__
p.description = __description__
+ p.bugTracker = "https://bugs.maemo.org/enter_bug.cgi?product=ejpi"
+ p.upgradeDescription = __changelog__.split("\n\n", 1)[0]
p.author = __author__
p.mail = __email__
p.license = "lgpl"
- p.depends = {
- "diablo": "python2.5, python2.5-gtk2",
- "mer": "python2.6, python-gtk2",
+ p.depends = ", ".join([
+ "python2.6 | python2.5",
+ "python-gtk2 | python2.5-gtk2",
+ "python-xml | python2.5-xml",
+ ])
+ maemoSpecificDepends = ", python-osso | python2.5-osso, python-hildon | python2.5-hildon"
+ p.depends += {
+ "debian": ", python-glade2",
+ "chinook": maemoSpecificDepends,
+ "diablo": maemoSpecificDepends,
+ "fremantle": maemoSpecificDepends + ", python-glade2",
+ "mer": maemoSpecificDepends + ", python-glade2",
+ }[distribution]
+ p.section = {
+ "debian": "accessories",
+ "chinook": "accessories",
+ "diablo": "user/office",
+ "fremantle": "user/office",
+ "mer": "user/office",
}[distribution]
- p.section = "user/other"
p.arch = "all"
p.urgency = "low"
- p.distribution = "chinook diablo fremantle mer"
+ p.distribution = "chinook diablo fremantle mer debian"
p.repository = "extras"
p.changelog = __changelog__
p.postinstall = __postinstall__
- p.icon = "26x26-quicknote.png"
+ p.icon = {
+ "debian": "26x26-quicknote.png",
+ "chinook": "26x26-quicknote.png",
+ "diablo": "26x26-quicknote.png",
+ "fremantle": "64x64-quicknote.png", # Fremantle natively uses 48x48
+ "mer": "64x64-quicknote.png",
+ }[distribution]
p["/usr/bin"] = [ "quicknote.py" ]
for relPath, files in unflatten_files(find_files(".", "locale")).iteritems():
fullPath = "/usr/share/locale"
for (oldName, newName) in files
)
p["/usr/share/applications/hildon"] = ["quicknote.desktop"]
- p["/usr/share/dbus-1/services"] = ["quicknote.service"]
+ #p["/usr/share/dbus-1/services"] = ["quicknote.service"]
p["/usr/share/icons/hicolor/26x26/hildon"] = ["26x26-quicknote.png|quicknote.png"]
p["/usr/share/icons/hicolor/40x40/hildon"] = ["40x40-quicknote.png|quicknote.png"]
p["/usr/share/icons/hicolor/48x48/hildon"] = ["48x48-quicknote.png|quicknote.png"]
print p
print p.generate(
- __version__, __build__, changelog=__changelog__,
- tar=True, dsc=True, changes=True, build=False, src=True
+ version="%s-%s" % (__version__, __build__),
+ changelog=__changelog__,
+ build=False,
+ tar=True,
+ changes=True,
+ dsc=True,
)
print "Building for %s finished" % distribution
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+##
+## Copyright (C) 2009 manatlan manatlan[at]gmail(dot)com
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published
+## by the Free Software Foundation; version 2 only.
+##
+## 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.
+##
+"""
+Known limitations :
+- don't sign package (-us -uc)
+- no distinctions between author and maintainer(packager)
+
+depends on :
+- dpkg-dev (dpkg-buildpackage)
+- alien
+- python
+- fakeroot
+
+changelog
+ - ??? ?/??/20?? (By epage)
+ - PEP8
+ - added recommends
+ - fixed bug where it couldn't handle the contents of the pre/post scripts being specified
+ - Added customization based on the targeted policy for sections (Maemo support)
+ - Added maemo specific tarball, dsc, changes file generation support (including icon support)
+ - Added armel architecture
+ - Reduced the size of params being passed around by reducing the calls to locals()
+ - Added respository, distribution, priority
+ - Made setting control file a bit more flexible
+ - 0.5 05/09/2009
+ - pre/post install/remove scripts enabled
+ - deb package install py2deb in dist-packages for py2.6
+ - 0.4 14/10/2008
+ - use os.environ USERNAME or USER (debian way)
+ - install on py 2.(4,5,6) (*FIX* do better here)
+
+"""
+
+import os
+import hashlib
+import sys
+import shutil
+import time
+import string
+import StringIO
+import stat
+import commands
+import base64
+import tarfile
+from glob import glob
+from datetime import datetime
+import socket # gethostname()
+from subprocess import Popen, PIPE
+
+#~ __version__ = "0.4"
+__version__ = "0.5"
+__author__ = "manatlan"
+__mail__ = "manatlan@gmail.com"
+
+
+PERMS_URW_GRW_OR = stat.S_IRUSR | stat.S_IWUSR | \
+ stat.S_IRGRP | stat.S_IWGRP | \
+ stat.S_IROTH
+
+UID_ROOT = 0
+GID_ROOT = 0
+
+
+def run(cmds):
+ p = Popen(cmds, shell=False, stdout=PIPE, stderr=PIPE)
+ time.sleep(0.01) # to avoid "IOError: [Errno 4] Interrupted system call"
+ out = string.join(p.stdout.readlines()).strip()
+ outerr = string.join(p.stderr.readlines()).strip()
+ return out
+
+
+def deb2rpm(file):
+ txt=run(['alien', '-r', file])
+ return txt.split(" generated")[0]
+
+
+def py2src(TEMP, name):
+ l=glob("%(TEMP)s/%(name)s*.tar.gz" % locals())
+ if len(l) != 1:
+ raise Py2debException("don't find source package tar.gz")
+
+ tar = os.path.basename(l[0])
+ shutil.move(l[0], tar)
+
+ return tar
+
+
+def md5sum(filename):
+ f = open(filename, "r")
+ try:
+ return hashlib.md5(f.read()).hexdigest()
+ finally:
+ f.close()
+
+
+class Py2changes(object):
+
+ def __init__(self, ChangedBy, description, changes, files, category, repository, **kwargs):
+ self.options = kwargs # TODO: Is order important?
+ self.description = description
+ self.changes=changes
+ self.files=files
+ self.category=category
+ self.repository=repository
+ self.ChangedBy=ChangedBy
+
+ def getContent(self):
+ content = ["%s: %s" % (k, v)
+ for k,v in self.options.iteritems()]
+
+ if self.description:
+ description=self.description.replace("\n","\n ")
+ content.append('Description: ')
+ content.append(' %s' % description)
+ if self.changes:
+ changes=self.changes.replace("\n","\n ")
+ content.append('Changes: ')
+ content.append(' %s' % changes)
+ if self.ChangedBy:
+ content.append("Changed-By: %s" % self.ChangedBy)
+
+ content.append('Files:')
+
+ for onefile in self.files:
+ md5 = md5sum(onefile)
+ size = os.stat(onefile).st_size.__str__()
+ content.append(' ' + md5 + ' ' + size + ' ' + self.category +' '+self.repository+' '+os.path.basename(onefile))
+
+ return "\n".join(content) + "\n\n"
+
+
+def py2changes(params):
+ changescontent = Py2changes(
+ "%(author)s <%(mail)s>" % params,
+ "%(description)s" % params,
+ "%(changelog)s" % params,
+ (
+ "%(TEMP)s/%(name)s_%(version)s.tar.gz" % params,
+ "%(TEMP)s/%(name)s_%(version)s.dsc" % params,
+ ),
+ "%(section)s" % params,
+ "%(repository)s" % params,
+ Format='1.7',
+ Date=time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()),
+ Source="%(name)s" % params,
+ Architecture="%(arch)s" % params,
+ Version="%(version)s" % params,
+ Distribution="%(distribution)s" % params,
+ Urgency="%(urgency)s" % params,
+ Maintainer="%(author)s <%(mail)s>" % params
+ )
+ f = open("%(TEMP)s/%(name)s_%(version)s.changes" % params,"wb")
+ f.write(changescontent.getContent())
+ f.close()
+
+ fileHandle = open('/tmp/py2deb2.tmp', 'w')
+ fileHandle.write('#!/bin/sh\n')
+ fileHandle.write("cd " +os.getcwd()+ "\n")
+ fileHandle.write("gpg --local-user %(mail)s --clearsign %(TEMP)s/%(name)s_%(version)s.changes\n" % params)
+ fileHandle.write("mv %(TEMP)s/%(name)s_%(version)s.changes.asc %(TEMP)s/%(name)s_%(version)s.changes\n" % params)
+ fileHandle.write('\nexit')
+ fileHandle.close()
+ commands.getoutput("chmod 777 /tmp/py2deb2.tmp")
+ commands.getoutput("/tmp/py2deb2.tmp")
+
+ ret = []
+
+ l=glob("%(TEMP)s/%(name)s*.tar.gz" % params)
+ if len(l)!=1:
+ raise Py2debException("don't find source package tar.gz")
+ tar = os.path.basename(l[0])
+ shutil.move(l[0],tar)
+ ret.append(tar)
+
+ l=glob("%(TEMP)s/%(name)s*.dsc" % params)
+ if len(l)!=1:
+ raise Py2debException("don't find source package dsc")
+ tar = os.path.basename(l[0])
+ shutil.move(l[0],tar)
+ ret.append(tar)
+
+ l=glob("%(TEMP)s/%(name)s*.changes" % params)
+ if len(l)!=1:
+ raise Py2debException("don't find source package changes")
+ tar = os.path.basename(l[0])
+ shutil.move(l[0],tar)
+ ret.append(tar)
+
+ return ret
+
+
+class Py2dsc(object):
+
+ def __init__(self, StandardsVersion, BuildDepends, files, **kwargs):
+ self.options = kwargs # TODO: Is order important?
+ self.StandardsVersion = StandardsVersion
+ self.BuildDepends=BuildDepends
+ self.files=files
+
+ @property
+ def content(self):
+ content = ["%s: %s" % (k, v)
+ for k,v in self.options.iteritems()]
+
+ if self.BuildDepends:
+ content.append("Build-Depends: %s" % self.BuildDepends)
+ if self.StandardsVersion:
+ content.append("Standards-Version: %s" % self.StandardsVersion)
+
+ content.append('Files:')
+
+ for onefile in self.files:
+ print onefile
+ md5 = md5sum(onefile)
+ size = os.stat(onefile).st_size.__str__()
+ content.append(' '+md5 + ' ' + size +' '+os.path.basename(onefile))
+
+ return "\n".join(content)+"\n\n"
+
+
+def py2dsc(TEMP, name, version, depends, author, mail, arch):
+ dsccontent = Py2dsc(
+ "%(version)s" % locals(),
+ "%(depends)s" % locals(),
+ ("%(TEMP)s/%(name)s_%(version)s.tar.gz" % locals(),),
+ Format='1.0',
+ Source="%(name)s" % locals(),
+ Version="%(version)s" % locals(),
+ Maintainer="%(author)s <%(mail)s>" % locals(),
+ Architecture="%(arch)s" % locals(),
+ )
+
+ filename = "%(TEMP)s/%(name)s_%(version)s.dsc" % locals()
+
+ f = open(filename, "wb")
+ try:
+ f.write(dsccontent.content)
+ finally:
+ f.close()
+
+ fileHandle = open('/tmp/py2deb.tmp', 'w')
+ try:
+ fileHandle.write('#!/bin/sh\n')
+ fileHandle.write("cd " + os.getcwd() + "\n")
+ fileHandle.write("gpg --local-user %(mail)s --clearsign %(TEMP)s/%(name)s_%(version)s.dsc\n" % locals())
+ fileHandle.write("mv %(TEMP)s/%(name)s_%(version)s.dsc.asc %(filename)s\n" % locals())
+ fileHandle.write('\nexit')
+ fileHandle.close()
+ finally:
+ f.close()
+
+ commands.getoutput("chmod 777 /tmp/py2deb.tmp")
+ commands.getoutput("/tmp/py2deb.tmp")
+
+ return filename
+
+
+class Py2tar(object):
+
+ def __init__(self, dataDirectoryPath):
+ self._dataDirectoryPath = dataDirectoryPath
+
+ def packed(self):
+ return self._getSourcesFiles()
+
+ def _getSourcesFiles(self):
+ directoryPath = self._dataDirectoryPath
+
+ outputFileObj = StringIO.StringIO() # TODO: Do more transparently?
+
+ tarOutput = tarfile.TarFile.open('sources',
+ mode = "w:gz",
+ fileobj = outputFileObj)
+
+ # Note: We can't use this because we need to fiddle permissions:
+ # tarOutput.add(directoryPath, arcname = "")
+
+ for root, dirs, files in os.walk(directoryPath):
+ archiveRoot = root[len(directoryPath):]
+
+ tarinfo = tarOutput.gettarinfo(root, archiveRoot)
+ # TODO: Make configurable?
+ tarinfo.uid = UID_ROOT
+ tarinfo.gid = GID_ROOT
+ tarinfo.uname = ""
+ tarinfo.gname = ""
+ tarOutput.addfile(tarinfo)
+
+ for f in files:
+ tarinfo = tarOutput.gettarinfo(os.path.join(root, f),
+ os.path.join(archiveRoot, f))
+ tarinfo.uid = UID_ROOT
+ tarinfo.gid = GID_ROOT
+ tarinfo.uname = ""
+ tarinfo.gname = ""
+ tarOutput.addfile(tarinfo, file(os.path.join(root, f)))
+
+ tarOutput.close()
+
+ data_tar_gz = outputFileObj.getvalue()
+
+ return data_tar_gz
+
+
+def py2tar(DEST, TEMP, name, version):
+ tarcontent = Py2tar("%(DEST)s" % locals())
+ filename = "%(TEMP)s/%(name)s_%(version)s.tar.gz" % locals()
+ f = open(filename, "wb")
+ try:
+ f.write(tarcontent.packed())
+ finally:
+ f.close()
+ return filename
+
+
+class Py2debException(Exception):
+ pass
+
+
+SECTIONS_BY_POLICY = {
+ # http://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections
+ "debian": "admin, base, comm, contrib, devel, doc, editors, electronics, embedded, games, gnome, graphics, hamradio, interpreters, kde, libs, libdevel, mail, math, misc, net, news, non-free, oldlibs, otherosfs, perl, python, science, shells, sound, tex, text, utils, web, x11",
+ # http://maemo.org/forrest-images/pdf/maemo-policy.pdf
+ "chinook": "accessories, communication, games, multimedia, office, other, programming, support, themes, tools",
+ # http://wiki.maemo.org/Task:Package_categories
+ "diablo": "user/desktop, user/development, user/education, user/games, user/graphics, user/multimedia, user/navigation, user/network, user/office, user/science, user/system, user/utilities",
+ # http://wiki.maemo.org/Task:Fremantle_application_categories
+ "mer": "user/desktop, user/development, user/education, user/games, user/graphics, user/multimedia, user/navigation, user/network, user/office, user/science, user/system, user/utilities",
+ # http://wiki.maemo.org/Task:Fremantle_application_categories
+ "fremantle": "user/desktop, user/development, user/education, user/games, user/graphics, user/multimedia, user/navigation, user/network, user/office, user/science, user/system, user/utilities",
+}
+
+
+LICENSE_AGREEMENT = {
+ "gpl": """
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This package 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 package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.
+""",
+ "lgpl":"""
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This package 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+On Debian systems, the complete text of the GNU Lesser General
+Public License can be found in `/usr/share/common-licenses/LGPL'.
+""",
+ "bsd": """
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted under the terms of the BSD License.
+
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+On Debian systems, the complete text of the BSD License can be
+found in `/usr/share/common-licenses/BSD'.
+""",
+ "artistic": """
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the "Artistic License" which comes with Debian.
+
+ THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
+ OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+On Debian systems, the complete text of the Artistic License
+can be found in `/usr/share/common-licenses/Artistic'.
+"""
+}
+
+
+class Py2deb(object):
+ """
+ heavily based on technic described here :
+ http://wiki.showmedo.com/index.php?title=LinuxJensMakingDeb
+ """
+ ## STATICS
+ clear = False # clear build folder after py2debianization
+
+ SECTIONS = SECTIONS_BY_POLICY["debian"]
+
+ #http://www.debian.org/doc/debian-policy/footnotes.html#f69
+ ARCHS = "all i386 ia64 alpha amd64 armeb arm hppa m32r m68k mips mipsel powerpc ppc64 s390 s390x sh3 sh3eb sh4 sh4eb sparc darwin-i386 darwin-ia64 darwin-alpha darwin-amd64 darwin-armeb darwin-arm darwin-hppa darwin-m32r darwin-m68k darwin-mips darwin-mipsel darwin-powerpc darwin-ppc64 darwin-s390 darwin-s390x darwin-sh3 darwin-sh3eb darwin-sh4 darwin-sh4eb darwin-sparc freebsd-i386 freebsd-ia64 freebsd-alpha freebsd-amd64 freebsd-armeb freebsd-arm freebsd-hppa freebsd-m32r freebsd-m68k freebsd-mips freebsd-mipsel freebsd-powerpc freebsd-ppc64 freebsd-s390 freebsd-s390x freebsd-sh3 freebsd-sh3eb freebsd-sh4 freebsd-sh4eb freebsd-sparc kfreebsd-i386 kfreebsd-ia64 kfreebsd-alpha kfreebsd-amd64 kfreebsd-armeb kfreebsd-arm kfreebsd-hppa kfreebsd-m32r kfreebsd-m68k kfreebsd-mips kfreebsd-mipsel kfreebsd-powerpc kfreebsd-ppc64 kfreebsd-s390 kfreebsd-s390x kfreebsd-sh3 kfreebsd-sh3eb kfreebsd-sh4 kfreebsd-sh4eb kfreebsd-sparc knetbsd-i386 knetbsd-ia64 knetbsd-alpha knetbsd-amd64 knetbsd-armeb knetbsd-arm knetbsd-hppa knetbsd-m32r knetbsd-m68k knetbsd-mips knetbsd-mipsel knetbsd-powerpc knetbsd-ppc64 knetbsd-s390 knetbsd-s390x knetbsd-sh3 knetbsd-sh3eb knetbsd-sh4 knetbsd-sh4eb knetbsd-sparc netbsd-i386 netbsd-ia64 netbsd-alpha netbsd-amd64 netbsd-armeb netbsd-arm netbsd-hppa netbsd-m32r netbsd-m68k netbsd-mips netbsd-mipsel netbsd-powerpc netbsd-ppc64 netbsd-s390 netbsd-s390x netbsd-sh3 netbsd-sh3eb netbsd-sh4 netbsd-sh4eb netbsd-sparc openbsd-i386 openbsd-ia64 openbsd-alpha openbsd-amd64 openbsd-armeb openbsd-arm openbsd-hppa openbsd-m32r openbsd-m68k openbsd-mips openbsd-mipsel openbsd-powerpc openbsd-ppc64 openbsd-s390 openbsd-s390x openbsd-sh3 openbsd-sh3eb openbsd-sh4 openbsd-sh4eb openbsd-sparc hurd-i386 hurd-ia64 hurd-alpha hurd-amd64 hurd-armeb hurd-arm hurd-hppa hurd-m32r hurd-m68k hurd-mips hurd-mipsel hurd-powerpc hurd-ppc64 hurd-s390 hurd-s390x hurd-sh3 hurd-sh3eb hurd-sh4 hurd-sh4eb hurd-sparc armel".split(" ")
+
+ # license terms taken from dh_make
+ LICENSES = list(LICENSE_AGREEMENT.iterkeys())
+
+ def __setitem__(self, path, files):
+
+ if not type(files)==list:
+ raise Py2debException("value of key path '%s' is not a list"%path)
+ if not files:
+ raise Py2debException("value of key path '%s' should'nt be empty"%path)
+ if not path.startswith("/"):
+ raise Py2debException("key path '%s' malformed (don't start with '/')"%path)
+ if path.endswith("/"):
+ raise Py2debException("key path '%s' malformed (shouldn't ends with '/')"%path)
+
+ nfiles=[]
+ for file in files:
+
+ if ".." in file:
+ raise Py2debException("file '%s' contains '..', please avoid that!"%file)
+
+
+ if "|" in file:
+ if file.count("|")!=1:
+ raise Py2debException("file '%s' is incorrect (more than one pipe)"%file)
+
+ file, nfile = file.split("|")
+ else:
+ nfile=file # same localisation
+
+ if os.path.isdir(file):
+ raise Py2debException("file '%s' is a folder, and py2deb refuse folders !"%file)
+
+ if not os.path.isfile(file):
+ raise Py2debException("file '%s' doesn't exist"%file)
+
+ if file.startswith("/"): # if an absolute file is defined
+ if file==nfile: # and not renamed (pipe trick)
+ nfile=os.path.basename(file) # it's simply copied to 'path'
+
+ nfiles.append((file, nfile))
+
+ nfiles.sort(lambda a, b: cmp(a[1], b[1])) #sort according new name (nfile)
+
+ self.__files[path]=nfiles
+
+ def __delitem__(self, k):
+ del self.__files[k]
+
+ def __init__(self,
+ name,
+ description="no description",
+ license="gpl",
+ depends="",
+ section="utils",
+ arch="all",
+
+ url="",
+ author = None,
+ mail = None,
+
+ preinstall = None,
+ postinstall = None,
+ preremove = None,
+ postremove = None
+ ):
+
+ if author is None:
+ author = ("USERNAME" in os.environ) and os.environ["USERNAME"] or None
+ if author is None:
+ author = ("USER" in os.environ) and os.environ["USER"] or "unknown"
+
+ if mail is None:
+ mail = author+"@"+socket.gethostname()
+
+ self.name = name
+ self.prettyName = ""
+ self.description = description
+ self.upgradeDescription = ""
+ self.bugTracker = ""
+ self.license = license
+ self.depends = depends
+ self.recommends = ""
+ self.section = section
+ self.arch = arch
+ self.url = url
+ self.author = author
+ self.mail = mail
+ self.icon = ""
+ self.distribution = ""
+ self.respository = ""
+ self.urgency = "low"
+
+ self.preinstall = preinstall
+ self.postinstall = postinstall
+ self.preremove = preremove
+ self.postremove = postremove
+
+ self.__files={}
+
+ def __repr__(self):
+ name = self.name
+ license = self.license
+ description = self.description
+ depends = self.depends
+ recommends = self.recommends
+ section = self.section
+ arch = self.arch
+ url = self.url
+ author = self.author
+ mail = self.mail
+
+ preinstall = self.preinstall
+ postinstall = self.postinstall
+ preremove = self.preremove
+ postremove = self.postremove
+
+ paths=self.__files.keys()
+ paths.sort()
+ files=[]
+ for path in paths:
+ for file, nfile in self.__files[path]:
+ #~ rfile=os.path.normpath(os.path.join(path, nfile))
+ rfile=os.path.join(path, nfile)
+ if nfile==file:
+ files.append(rfile)
+ else:
+ files.append(rfile + " (%s)"%file)
+
+ files.sort()
+ files = "\n".join(files)
+
+
+ lscripts = [ preinstall and "preinst",
+ postinstall and "postinst",
+ preremove and "prerm",
+ postremove and "postrm",
+ ]
+ scripts = lscripts and ", ".join([i for i in lscripts if i]) or "None"
+ return """
+----------------------------------------------------------------------
+NAME : %(name)s
+----------------------------------------------------------------------
+LICENSE : %(license)s
+URL : %(url)s
+AUTHOR : %(author)s
+MAIL : %(mail)s
+----------------------------------------------------------------------
+DEPENDS : %(depends)s
+RECOMMENDS : %(recommends)s
+ARCH : %(arch)s
+SECTION : %(section)s
+----------------------------------------------------------------------
+DESCRIPTION :
+%(description)s
+----------------------------------------------------------------------
+SCRIPTS : %(scripts)s
+----------------------------------------------------------------------
+FILES :
+%(files)s
+""" % locals()
+
+ def generate(self, version, changelog="", rpm=False, src=False, build=True, tar=False, changes=False, dsc=False):
+ """ generate a deb of version 'version', with or without 'changelog', with or without a rpm
+ (in the current folder)
+ return a list of generated files
+ """
+ if not sum([len(i) for i in self.__files.values()])>0:
+ raise Py2debException("no files are defined")
+
+ if not changelog:
+ changelog="* no changelog"
+
+ name = self.name
+ description = self.description
+ license = self.license
+ depends = self.depends
+ recommends = self.recommends
+ section = self.section
+ arch = self.arch
+ url = self.url
+ distribution = self.distribution
+ repository = self.repository
+ urgency = self.urgency
+ author = self.author
+ mail = self.mail
+ files = self.__files
+ preinstall = self.preinstall
+ postinstall = self.postinstall
+ preremove = self.preremove
+ postremove = self.postremove
+
+ if section not in Py2deb.SECTIONS:
+ raise Py2debException("section '%s' is unknown (%s)" % (section, str(Py2deb.SECTIONS)))
+
+ if arch not in Py2deb.ARCHS:
+ raise Py2debException("arch '%s' is unknown (%s)"% (arch, str(Py2deb.ARCHS)))
+
+ if license not in Py2deb.LICENSES:
+ raise Py2debException("License '%s' is unknown (%s)" % (license, str(Py2deb.LICENSES)))
+
+ # create dates (buildDate, buildDateYear)
+ d=datetime.now()
+ buildDate=d.strftime("%a, %d %b %Y %H:%M:%S +0000")
+ buildDateYear=str(d.year)
+
+ #clean description (add a space before each next lines)
+ description=description.replace("\r", "").strip()
+ description = "\n ".join(description.split("\n"))
+
+ #clean changelog (add 2 spaces before each next lines)
+ changelog=changelog.replace("\r", "").strip()
+ changelog = "\n ".join(changelog.split("\n"))
+
+ TEMP = ".py2deb_build_folder"
+ DEST = os.path.join(TEMP, name)
+ DEBIAN = os.path.join(DEST, "debian")
+
+ packageContents = locals()
+
+ # let's start the process
+ try:
+ shutil.rmtree(TEMP)
+ except:
+ pass
+
+ os.makedirs(DEBIAN)
+ try:
+ rules=[]
+ dirs=[]
+ for path in files:
+ for ofile, nfile in files[path]:
+ if os.path.isfile(ofile):
+ # it's a file
+
+ if ofile.startswith("/"): # if absolute path
+ # we need to change dest
+ dest=os.path.join(DEST, nfile)
+ else:
+ dest=os.path.join(DEST, ofile)
+
+ # copy file to be packaged
+ destDir = os.path.dirname(dest)
+ if not os.path.isdir(destDir):
+ os.makedirs(destDir)
+
+ shutil.copy2(ofile, dest)
+
+ ndir = os.path.join(path, os.path.dirname(nfile))
+ nname = os.path.basename(nfile)
+
+ # make a line RULES to be sure the destination folder is created
+ # and one for copying the file
+ fpath = "/".join(["$(CURDIR)", "debian", name+ndir])
+ rules.append('mkdir -p "%s"' % fpath)
+ rules.append('cp -a "%s" "%s"' % (ofile, os.path.join(fpath, nname)))
+
+ # append a dir
+ dirs.append(ndir)
+
+ else:
+ raise Py2debException("unknown file '' "%ofile) # shouldn't be raised (because controlled before)
+
+ # make rules right
+ rules= "\n\t".join(rules) + "\n"
+ packageContents["rules"] = rules
+
+ # make dirs right
+ dirs= [i[1:] for i in set(dirs)]
+ dirs.sort()
+
+ #==========================================================================
+ # CREATE debian/dirs
+ #==========================================================================
+ open(os.path.join(DEBIAN, "dirs"), "w").write("\n".join(dirs))
+
+ #==========================================================================
+ # CREATE debian/changelog
+ #==========================================================================
+ clog="""%(name)s (%(version)s) stable; urgency=low
+
+ %(changelog)s
+
+ -- %(author)s <%(mail)s> %(buildDate)s
+""" % packageContents
+
+ open(os.path.join(DEBIAN, "changelog"), "w").write(clog)
+
+ #==========================================================================
+ #Create pre/post install/remove
+ #==========================================================================
+ def mkscript(name, dest):
+ if name and name.strip()!="":
+ if os.path.isfile(name): # it's a file
+ content = file(name).read()
+ else: # it's a script
+ content = name
+ open(os.path.join(DEBIAN, dest), "w").write(content)
+
+ mkscript(preinstall, "preinst")
+ mkscript(postinstall, "postinst")
+ mkscript(preremove, "prerm")
+ mkscript(postremove, "postrm")
+
+
+ #==========================================================================
+ # CREATE debian/compat
+ #==========================================================================
+ open(os.path.join(DEBIAN, "compat"), "w").write("5\n")
+
+ #==========================================================================
+ # CREATE debian/control
+ #==========================================================================
+ generalParagraphFields = [
+ "Source: %(name)s",
+ "Maintainer: %(author)s <%(mail)s>",
+ "Section: %(section)s",
+ "Priority: extra",
+ "Build-Depends: debhelper (>= 5)",
+ "Standards-Version: 3.7.2",
+ ]
+
+ specificParagraphFields = [
+ "Package: %(name)s",
+ "Architecture: %(arch)s",
+ "Depends: %(depends)s",
+ "Recommends: %(recommends)s",
+ "Description: %(description)s",
+ ]
+
+ if self.prettyName:
+ prettyName = "XSBC-Maemo-Display-Name: %s" % self.prettyName.strip()
+ specificParagraphFields.append("\n ".join(prettyName.split("\n")))
+
+ if self.bugTracker:
+ bugTracker = "XSBC-Bugtracker: %s" % self.bugTracker.strip()
+ specificParagraphFields.append("\n ".join(bugTracker.split("\n")))
+
+ if self.upgradeDescription:
+ upgradeDescription = "XSBC-Maemo-Upgrade-Description: %s" % self.upgradeDescription.strip()
+ specificParagraphFields.append("\n ".join(upgradeDescription.split("\n")))
+
+ if self.icon:
+ f = open(self.icon, "rb")
+ try:
+ rawIcon = f.read()
+ finally:
+ f.close()
+ uueIcon = base64.b64encode(rawIcon)
+ uueIconLines = []
+ for i, c in enumerate(uueIcon):
+ if i % 60 == 0:
+ uueIconLines.append("")
+ uueIconLines[-1] += c
+ uueIconLines[0:0] = ("XSBC-Maemo-Icon-26:", )
+ specificParagraphFields.append("\n ".join(uueIconLines))
+
+ generalParagraph = "\n".join(generalParagraphFields)
+ specificParagraph = "\n".join(specificParagraphFields)
+ controlContent = "\n\n".join((generalParagraph, specificParagraph)) % packageContents
+ open(os.path.join(DEBIAN, "control"), "w").write(controlContent)
+
+ #==========================================================================
+ # CREATE debian/copyright
+ #==========================================================================
+ packageContents["txtLicense"] = LICENSE_AGREEMENT[license]
+ packageContents["pv"] =__version__
+ txt="""This package was py2debianized(%(pv)s) by %(author)s <%(mail)s> on
+%(buildDate)s.
+
+It was downloaded from %(url)s
+
+Upstream Author: %(author)s <%(mail)s>
+
+Copyright: %(buildDateYear)s by %(author)s
+
+License:
+
+%(txtLicense)s
+
+The Debian packaging is (C) %(buildDateYear)s, %(author)s <%(mail)s> and
+is licensed under the GPL, see above.
+
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
+""" % packageContents
+ open(os.path.join(DEBIAN, "copyright"), "w").write(txt)
+
+ #==========================================================================
+ # CREATE debian/rules
+ #==========================================================================
+ txt="""#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+
+
+CFLAGS = -Wall -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -O0
+else
+ CFLAGS += -O2
+endif
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+ # Add here commands to configure the package.
+
+ touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp
+ dh_testdir
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp configure-stamp
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ # ======================================================
+ #$(MAKE) DESTDIR="$(CURDIR)/debian/%(name)s" install
+ mkdir -p "$(CURDIR)/debian/%(name)s"
+
+ %(rules)s
+ # ======================================================
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs debian/changelog
+ dh_installdocs
+ dh_installexamples
+# dh_install
+# dh_installmenu
+# dh_installdebconf
+# dh_installlogrotate
+# dh_installemacsen
+# dh_installpam
+# dh_installmime
+# dh_python
+# dh_installinit
+# dh_installcron
+# dh_installinfo
+ dh_installman
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+# dh_perl
+# dh_makeshlibs
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
+""" % packageContents
+ open(os.path.join(DEBIAN, "rules"), "w").write(txt)
+ os.chmod(os.path.join(DEBIAN, "rules"), 0755)
+
+ ###########################################################################
+ ###########################################################################
+ ###########################################################################
+
+ generatedFiles = []
+
+ if build:
+ #http://www.debian.org/doc/manuals/maint-guide/ch-build.fr.html
+ ret = os.system('cd "%(DEST)s"; dpkg-buildpackage -tc -rfakeroot -us -uc' % packageContents)
+ if ret != 0:
+ raise Py2debException("buildpackage failed (see output)")
+
+ l=glob("%(TEMP)s/%(name)s*.deb" % packageContents)
+ if len(l) != 1:
+ raise Py2debException("didn't find builded deb")
+
+ tdeb = l[0]
+ deb = os.path.basename(tdeb)
+ shutil.move(tdeb, deb)
+
+ generatedFiles = [deb, ]
+
+ if rpm:
+ rpmFilename = deb2rpm(deb)
+ generatedFiles.append(rpmFilename)
+
+ if src:
+ tarFilename = py2src(TEMP, name)
+ generatedFiles.append(tarFilename)
+
+ if tar:
+ tarFilename = py2tar(DEST, TEMP, name, version)
+ generatedFiles.append(tarFilename)
+
+ if dsc:
+ dscFilename = py2dsc(TEMP, name, version, depends, author, mail, arch)
+ generatedFiles.append(dscFilename)
+
+ if changes:
+ changesFilenames = py2changes(packageContents)
+ generatedFiles.extend(changesFilenames)
+
+ return generatedFiles
+
+ #~ except Exception,m:
+ #~ raise Py2debException("build error :"+str(m))
+
+ finally:
+ if Py2deb.clear:
+ shutil.rmtree(TEMP)
+
+
+if __name__ == "__main__":
+ try:
+ os.chdir(os.path.dirname(sys.argv[0]))
+ except:
+ pass
+
+ p=Py2deb("python-py2deb")
+ p.description="Generate simple deb(/rpm/tgz) from python (2.4, 2.5 and 2.6)"
+ p.url = "http://www.manatlan.com/page/py2deb"
+ p.author=__author__
+ p.mail=__mail__
+ p.depends = "dpkg-dev, fakeroot, alien, python"
+ p.section="python"
+ p["/usr/lib/python2.6/dist-packages"] = ["py2deb.py", ]
+ p["/usr/lib/python2.5/site-packages"] = ["py2deb.py", ]
+ p["/usr/lib/python2.4/site-packages"] = ["py2deb.py", ]
+ #~ p.postinstall = "s.py"
+ #~ p.preinstall = "s.py"
+ #~ p.postremove = "s.py"
+ #~ p.preremove = "s.py"
+ print p
+ print p.generate(__version__, changelog = __doc__, src=True)
--- /dev/null
+#!/usr/bin/env python
+
+from __future__ import with_statement
+import itertools
+
+
+verbose = False
+
+
+def tag_parser(file, tag):
+ """
+ >>> nothing = []
+ >>> for todo in tag_parser(nothing, "@todo"):
+ ... print todo
+ ...
+ >>> one = ["@todo Help!"]
+ >>> for todo in tag_parser(one, "@todo"):
+ ... print todo
+ ...
+ 1: @todo Help!
+ >>> mixed = ["one", "@todo two", "three"]
+ >>> for todo in tag_parser(mixed, "@todo"):
+ ... print todo
+ ...
+ 2: @todo two
+ >>> embedded = ["one @todo two", "three"]
+ >>> for todo in tag_parser(embedded, "@todo"):
+ ... print todo
+ ...
+ 1: @todo two
+ >>> continuation = ["one", "@todo two", " three"]
+ >>> for todo in tag_parser(continuation, "@todo"):
+ ... print todo
+ ...
+ 2: @todo two three
+ >>> series = ["one", "@todo two", "@todo three"]
+ >>> for todo in tag_parser(series, "@todo"):
+ ... print todo
+ ...
+ 2: @todo two
+ 3: @todo three
+ """
+ currentTodo = []
+ prefix = None
+ for lineNumber, line in enumerate(file):
+ column = line.find(tag)
+ if column != -1:
+ if currentTodo:
+ yield "\n".join (currentTodo)
+ prefix = line[0:column]
+ currentTodo = ["%d: %s" % (lineNumber+1, line[column:].strip())]
+ elif prefix is not None and len(prefix)+1 < len(line) and line.startswith(prefix) and line[len(prefix)].isspace():
+ currentTodo.append (line[len(prefix):].rstrip())
+ elif currentTodo:
+ yield "\n".join (currentTodo)
+ currentTodo = []
+ prefix = None
+ if currentTodo:
+ yield "\n".join (currentTodo)
+
+
+def tag_finder(filename, tag):
+ todoList = []
+
+ with open(filename) as file:
+ body = "\n".join (tag_parser(file, tag))
+ passed = not body
+ if passed:
+ output = "No %s's for %s" % (tag, filename) if verbose else ""
+ else:
+ header = "%s's for %s:\n" % (tag, filename) if verbose else ""
+ output = header + body
+ output += "\n" if verbose else ""
+
+ return (passed, output)
+
+
+if __name__ == "__main__":
+ import sys
+ import os
+ import optparse
+
+ opar = optparse.OptionParser()
+ opar.add_option("-v", "--verbose", dest="verbose", help="Toggle verbosity", action="store_true", default=False)
+ options, args = opar.parse_args(sys.argv[1:])
+ verbose = options.verbose
+
+ bugsAsError = True
+ todosAsError = False
+
+ completeOutput = []
+ allPassed = True
+ for filename in args:
+ bugPassed, bugOutput = tag_finder(filename, "@bug")
+ todoPassed, todoOutput = tag_finder(filename, "@todo")
+ output = "\n".join ([bugOutput, todoOutput])
+ if (not bugPassed and bugsAsError) or (not todoPassed and todosAsError):
+ allPassed = False
+ output = output.strip()
+ if output:
+ completeOutput.append(filename+":\n"+output+"\n\n")
+ print "\n".join(completeOutput)
+
+ sys.exit(0 if allPassed else 1);