# -*- coding: utf-8 -*-
-import sys
-
-
-sys.path.append("/opt/dialcentral/lib")
-
-
-import dialcentral_qt
+from dialcentral import dialcentral_qt
if __name__ == "__main__":
PROJECT_NAME=dialcentral
-SOURCE_PATH=src
+PACKAGE_NAME=$(PROJECT_NAME)
+
+SOURCE_PATH=$(PACKAGE_NAME)
SOURCE=$(shell find $(SOURCE_PATH) -iname "*.py")
-PROGRAM=$(SOURCE_PATH)/$(PROJECT_NAME).py
-DATA_PATH=data
-DATA_TYPES=*.ini *.map *.glade *.png
-DATA=$(foreach type, $(DATA_TYPES), $(shell find $(DATA_PATH) -iname "$(type)"))
+
+PROGRAM=DialCentral
+ICON_SIZES=26 32 48 80
+ICONS=$(foreach size, $(ICON_SIZES), data/icons/$(size)/$(PROJECT_NAME).png)
+PACKAGE_VARIANTS=fremantle harmattan ubuntu
+DESKTOP_FILES=$(foreach variant, $(PACKAGE_VARIANTS), data/$(variant)/$(PROJECT_NAME).desktop)
+SETUP_FILES=$(foreach variant, $(PACKAGE_VARIANTS), ./setup.$(variant).py)
+DIST_BASE_PATH=./dist
+DIST_PATHS=$(foreach variant, $(PACKAGE_VARIANTS), $(DIST_BASE_PATH)_$(variant)) $(DIST_BASE_PATH)_diablo
+
OBJ=$(SOURCE:.py=.pyc)
-BUILD_PATH=./build
TAG_FILE=~/.ctags/$(PROJECT_NAME).tags
TODO_FILE=./TODO
TODO_FINDER=support/todo.py
CTAGS=ctags-exuberant
+
.PHONY: all run profile debug test build lint tags todo clean distclean
all: test
run: $(OBJ)
- $(SOURCE_PATH)/$(PROJECT_NAME)_qt.py
+ $(PROGRAM)
profile: $(OBJ)
$(PROFILE_GEN) $(PROGRAM)
test: $(OBJ)
$(UNIT_TEST)
-package: $(OBJ)
- rm -Rf $(BUILD_PATH)
-
- mkdir -p $(BUILD_PATH)/generic
- cp $(SOURCE_PATH)/constants.py $(BUILD_PATH)/generic
- cp $(SOURCE_PATH)/$(PROJECT_NAME).py $(BUILD_PATH)/generic
- $(foreach file, $(DATA), cp $(file) $(BUILD_PATH)/generic/$(subst /,-,$(file)) ; )
- $(foreach file, $(SOURCE), cp $(file) $(BUILD_PATH)/generic/$(subst /,-,$(file)) ; )
- cp support/$(PROJECT_NAME).desktop $(BUILD_PATH)/generic
- cp support/icons/hicolor/26x26/hildon/$(PROJECT_NAME).png $(BUILD_PATH)/generic/26x26-$(PROJECT_NAME).png
- cp support/icons/hicolor/64x64/hildon/$(PROJECT_NAME).png $(BUILD_PATH)/generic/64x64-$(PROJECT_NAME).png
- cp support/icons/hicolor/scalable/hildon/$(PROJECT_NAME).png $(BUILD_PATH)/generic/scale-$(PROJECT_NAME).png
- cp support/builddeb.py $(BUILD_PATH)/generic
- cp support/py2deb.py $(BUILD_PATH)/generic
- cp support/fake_py2deb.py $(BUILD_PATH)/generic
-
- mkdir -p $(BUILD_PATH)/diablo
- cp -R $(BUILD_PATH)/generic/* $(BUILD_PATH)/diablo
- cd $(BUILD_PATH)/diablo ; python builddeb.py diablo
- mkdir -p $(BUILD_PATH)/fremantle
- cp -R $(BUILD_PATH)/generic/* $(BUILD_PATH)/fremantle
- cd $(BUILD_PATH)/fremantle ; python builddeb.py fremantle
- mkdir -p $(BUILD_PATH)/debian
- cp -R $(BUILD_PATH)/generic/* $(BUILD_PATH)/debian
- cd $(BUILD_PATH)/debian ; python builddeb.py debian
+package: $(OBJ) $(ICONS) $(SETUP_FILES) $(DESKTOP_FILES)
+ rm -Rf $(DIST_BASE_PATH)_*/*
+ ./setup.fremantle.py sdist_diablo \
+ -d $(DIST_BASE_PATH)_diablo \
+ --install-purelib=/usr/lib/python2.5/site-packages
+ ./setup.fremantle.py sdist_fremantle \
+ -d $(DIST_BASE_PATH)_fremantle \
+ --install-purelib=/usr/lib/python2.5/site-packages
+ ./setup.harmattan.py sdist_harmattan \
+ -d $(DIST_BASE_PATH)_harmattan
+ --install-purelib=/usr/lib/python2.6/dist-packages
+ ./setup.ubuntu.py sdist_ubuntu \
+ -d $(DIST_BASE_PATH)_ubuntu
+ mkdir $(DIST_BASE_PATH)_ubuntu/build
+ cd $(DIST_BASE_PATH)_ubuntu/build ; tar -zxvf ../*.tar.gz
+ cd $(DIST_BASE_PATH)_ubuntu/build ; dpkg-buildpackage -tc -rfakeroot -us -uc
upload:
- dput fremantle-extras-builder $(BUILD_PATH)/fremantle/$(PROJECT_NAME)*.changes
- dput diablo-extras-builder $(BUILD_PATH)/diablo/$(PROJECT_NAME)*.changes
- cp $(BUILD_PATH)/debian/*.deb ./www/$(PROJECT_NAME).deb
+ dput diablo-extras-builder $(DIST_BASE_PATH)_diablo/$(PROJECT_NAME)*.changes
+ dput fremantle-extras-builder $(DIST_BASE_PATH)_fremantle/$(PROJECT_NAME)*.changes
+ cp $(DIST_BASE_PATH)_ubuntu/*.deb www/$(PROJECT_NAME).deb
lint: $(OBJ)
$(foreach file, $(SOURCE), $(LINT) $(file) ; )
clean:
rm -Rf $(OBJ)
- rm -Rf $(BUILD_PATH)
rm -Rf $(TODO_FILE)
+ rm -f $(ICONS) $(SETUP_FILES) $(DESKTOP_FILES)
+ rm -Rf $(DIST_PATHS)
-distclean:
- rm -Rf $(OBJ)
- rm -Rf $(BUILD_PATH)
- rm -Rf $(TAG_FILE)
+distclean: clean
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
+
+$(SETUP_FILES): VARIANT=$(word 2, $(subst ., ,$@))
+
+setup.fremantle.py: setup.py src/constants.py
+ cog.py -c \
+ -D DESKTOP_FILE_PATH=/usr/share/applications/hildon \
+ -D INPUT_DESKTOP_FILE=data/$(VARIANT)/$(PROJECT_NAME).desktop \
+ -D ICON_CATEGORY=hildon \
+ -D ICON_SIZES=26,32,48 \
+ -o $@ $<
+ chmod +x $@
+
+setup.harmattan.py: setup.py src/constants.py
+ cog.py -c \
+ -D DESKTOP_FILE_PATH=/usr/share/applications \
+ -D INPUT_DESKTOP_FILE=data/$(VARIANT)/$(PROJECT_NAME).desktop \
+ -D ICON_CATEGORY=hildon \
+ -D ICON_SIZES=32,80 \
+ -o $@ $<
+ chmod +x $@
+
+setup.ubuntu.py: setup.py src/constants.py
+ cog.py -c \
+ -D DESKTOP_FILE_PATH=/usr/share/applications \
+ -D INPUT_DESKTOP_FILE=data/$(VARIANT)/$(PROJECT_NAME).desktop \
+ -D ICON_CATEGORY=apps \
+ -D ICON_SIZES=32,48 \
+ -o $@ $<
+ chmod +x $@
+
+$(ICONS): SIZE=$(word 3, $(subst /, ,$@))
+$(ICONS): data/$(PROJECT_NAME).png support/scale.py
+ mkdir -p $(dir $@)
+ support/scale.py --input $< --output $@ --size $(SIZE)
+
+$(DESKTOP_FILES): VARIANT=$(word 2, $(subst /, ,$@))
+$(DESKTOP_FILES): data/template.desktop
+ mkdir -p $(dir $@)
+ cog.py -d \
+ -D VARIANT=$(VARIANT) \
+ -D PROGRAM=$(PROGRAM) \
+ -o $@ $<
+
+
$(TAG_FILE): $(OBJ)
mkdir -p $(dir $(TAG_FILE))
$(CTAGS) -o $(TAG_FILE) $(SOURCE)
+++ /dev/null
-http://www.gentleface.com/free_icon_set.html
-The Creative Commons Attribution-NonCommercial -- FREE
-http://creativecommons.org/licenses/by-nc-nd/3.0/
-
-Sound:
-http://www.freesound.org/samplesViewSingle.php?id=2166
-http://creativecommons.org/licenses/sampling+/1.0/
-
-placed.png, received.png, placed.png
-Free for commercial use
-http://www.iconeden.com/icon/free/get/bright-free-stock-iconset
[Desktop Entry]
-Encoding=UTF-8
-Version=1.0
-Type=Application
Name=DialCentral
-Exec=/usr/bin/run-standalone.sh /opt/dialcentral/bin/dialcentral.py
+GenericName=Google Voice Client
+Comment=Google Voice Client
+#[[[cog
+# if VARIANT == "fremantle":
+# cog.outl("Exec=/usr/bin/run-standalone.sh /usr/local/bin/%s" % PROGRAM)
+# elif VARIANT == "harmattan":
+# cog.outl("Exec=/usr/bin/invoker --single-instance --type=e /usr/local/bin/%s" % PROGRAM)
+# elif VARIANT == "ubuntu":
+# cog.outl("Exec=/usr/local/bin/%s" % PROGRAM)
+# else:
+# raise RuntimeError("Unsupported desktop file flavor %r" % PROGRAM)
+#]]]
+Exec=/usr/local/bin/DialCentral
+#[[[end]]]
Icon=dialcentral
Categories=Network;InstantMessaging;Qt;
+Type=Application
+Encoding=UTF-8
+Version=1.0
+X-Osso-Type=application/x-executable
from gvoice import gvoice
-from util import io as io_utils
+from dialcentral.util import io as io_utils
_moduleLogger = logging.getLogger(__name__)
import logging
-import util.qt_compat as qt_compat
+from dialcentral.util import qt_compat
if qt_compat.USES_PYSIDE:
try:
import QtMobility.Contacts as _QtContacts
_custom_notifier_settings_ = "%s/notifier.ini" % _data_path_
_user_logpath_ = "%s/%s.log" % (_data_path_, __app_name__)
_notifier_logpath_ = "%s/notifier.log" % _data_path_
+
IS_MAEMO = True
--- /dev/null
+http://www.gentleface.com/free_icon_set.html
+The Creative Commons Attribution-NonCommercial -- FREE
+http://creativecommons.org/licenses/by-nc-nd/3.0/
+
+Sound:
+http://www.freesound.org/samplesViewSingle.php?id=2166
+http://creativecommons.org/licenses/sampling+/1.0/
+
+placed.png, received.png, placed.png
+Free for commercial use
+http://www.iconeden.com/icon/free/get/bright-free-stock-iconset
class Dialcentral(qwrappers.ApplicationWrapper):
_DATA_PATHS = [
- os.path.join(os.path.dirname(__file__), "../share"),
- os.path.join(os.path.dirname(__file__), "../data"),
+ os.path.join(os.path.dirname(__file__), "data"),
]
def __init__(self, app):
--- /dev/null
+#!/usr/bin/env python
+
+"""
+QML Tips:
+ Large images:
+ QML asynchronous = true; cache = false; [1]
+ Insert properties at top of element declarations [1]
+ Non-visible items: set opacity to 0 [2]
+ Use Loader [1]
+ Keep QML files small [1]
+
+[1] http://sf2011.meego.com/program/sessions/performance-tips-and-tricks-qtqml-applications-0
+[2] http://doc.qt.nokia.com/4.7/qdeclarativeperformance.html
+"""
+
+from __future__ import with_statement
+from __future__ import division
+
+import logging
+
+import util.qt_compat as qt_compat
+QtCore = qt_compat.QtCore
+QtGui = qt_compat.import_module("QtGui")
+QtDeclarative = qt_compat.import_module("QtDeclarative")
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+class DeclarativeView(QtDeclarative.QDeclarativeView):
+
+ def __init__(self):
+ QtDeclarative.QDeclarativeView.__init__(self)
+
+ closing = qt_compat.Signal()
+
+ def closeEvent(self, event):
+ self.closing.emit()
+ event.ignore()
+
+
+def disable_default_window_painting(view):
+ """
+ See http://doc.qt.nokia.com/4.7-snapshot/qdeclarativeperformance.html
+ """
+ view.setAttribute(QtCore.Qt.WA_OpaquePaintEvent)
+ view.setAttribute(QtCore.Qt.WA_NoSystemBackground)
+ view.viewport().setAttribute(QtCore.Qt.WA_OpaquePaintEvent)
+ view.viewport().setAttribute(QtCore.Qt.WA_NoSystemBackground)
+
+
+if __name__ == "__main__":
+ pass
+
+#!/usr/bin/env python
+
+import contextlib
import logging
import qt_compat
callback(result)
except Exception:
_moduleLogger.exception("Callback errored")
+
+
+def create_single_column_list_model(columnName, **kwargs):
+ """
+ >>> class Single(object): pass
+ >>> SingleListModel = create_single_column_list_model("s")
+ >>> slm = SingleListModel([Single(), Single(), Single()])
+ """
+
+ class SingleColumnListModel(QtCore.QAbstractListModel):
+
+ def __init__(self, l = None):
+ QtCore.QAbstractListModel.__init__(self)
+ self._list = l if l is not None else []
+ self.setRoleNames({0: columnName})
+
+ def __len__(self):
+ return len(self._list)
+
+ def __getitem__(self, key):
+ return self._list[key]
+
+ def __setitem__(self, key, value):
+ with scoped_model_reset(self):
+ self._list[key] = value
+
+ def __delitem__(self, key):
+ with scoped_model_reset(self):
+ del self._list[key]
+
+ def __iter__(self):
+ return iter(self._list)
+
+ def __repr__(self):
+ return '<%s (%s)>' % (
+ self.__class__.__name__,
+ columnName,
+ )
+
+ def rowCount(self, parent=QtCore.QModelIndex()):
+ return len(self._list)
+
+ def data(self, index, role):
+ if index.isValid() and role == 0:
+ return self._list[index.row()]
+ return None
+
+ if "name" in kwargs:
+ SingleColumnListModel.__name__ = kwargs["name"]
+
+ return SingleColumnListModel
+
+
+def create_tupled_list_model(*columnNames, **kwargs):
+ """
+ >>> class Column0(object): pass
+ >>> class Column1(object): pass
+ >>> class Column2(object): pass
+ >>> MultiColumnedListModel = create_tupled_list_model("c0", "c1", "c2")
+ >>> mclm = MultiColumnedListModel([(Column0(), Column1(), Column2())])
+ """
+
+ class TupledListModel(QtCore.QAbstractListModel):
+
+ def __init__(self, l = None):
+ QtCore.QAbstractListModel.__init__(self)
+ self._list = l if l is not None else []
+ self.setRoleNames(dict(enumerate(columnNames)))
+
+ def __len__(self):
+ return len(self._list)
+
+ def __getitem__(self, key):
+ return self._list[key]
+
+ def __setitem__(self, key, value):
+ with scoped_model_reset(self):
+ self._list[key] = value
+
+ def __delitem__(self, key):
+ with scoped_model_reset(self):
+ del self._list[key]
+
+ def __iter__(self):
+ return iter(self._list)
+
+ def __repr__(self):
+ return '<%s (%s)>' % (
+ self.__class__.__name__,
+ ', '.join(columnNames),
+ )
+
+ def rowCount(self, parent=QtCore.QModelIndex()):
+ return len(self._list)
+
+ def data(self, index, role):
+ if index.isValid() and 0 <= role and role < len(columnNames):
+ return self._list[index.row()][role]
+ return None
+
+ if "name" in kwargs:
+ TupledListModel.__name__ = kwargs["name"]
+
+ return TupledListModel
+
+
+class FileSystemModel(QtCore.QAbstractListModel):
+ """
+ Wrapper around QtGui.QFileSystemModel
+ """
+
+ FILEINFOS = [
+ "fileName",
+ "isDir",
+ "filePath",
+ "completeSuffix",
+ "baseName",
+ ]
+
+ EXTINFOS = [
+ "type",
+ ]
+
+ ALLINFOS = FILEINFOS + EXTINFOS
+
+ def __init__(self, model, path):
+ QtCore.QAbstractListModel.__init__(self)
+ self._path = path
+
+ self._model = model
+ self._rootIndex = self._model.index(self._path)
+
+ self._child = None
+ self.setRoleNames(dict(enumerate(self.ALLINFOS)))
+ self._model.directoryLoaded.connect(self._on_directory_loaded)
+
+ childChanged = qt_compat.Signal(QtCore.QObject)
+
+ def _child(self):
+ assert self._child is not None
+ return self._child
+
+ child = qt_compat.Property(QtCore.QObject, _child, notify=childChanged)
+
+ backendChanged = qt_compat.Signal()
+
+ def _parent(self):
+ finfo = self._model.fileInfo(self._rootIndex)
+ return finfo.fileName()
+
+ parent = qt_compat.Property(str, _parent, notify=backendChanged)
+
+ @qt_compat.Slot(str)
+ def browse_to(self, path):
+ if self._child is None:
+ self._child = FileSystemModel(self._model, path)
+ else:
+ self._child.switch_to(path)
+ self.childChanged.emit()
+ return self._child
+
+ @qt_compat.Slot(str)
+ def switch_to(self, path):
+ with scoped_model_reset(self):
+ self._path = path
+ self._rootIndex = self._model.index(self._path)
+ self.backendChanged.emit()
+
+ def __len__(self):
+ return self._model.rowCount(self._rootIndex)
+
+ def __getitem__(self, key):
+ return self._model.index(key, 0, self._rootIndex)
+
+ def __iter__(self):
+ return (self[i] for i in xrange(len(self)))
+
+ def rowCount(self, parent=QtCore.QModelIndex()):
+ return len(self)
+
+ def data(self, index, role):
+ if index.isValid() and 0 <= role and role < len(self.ALLINFOS):
+ internalIndex = self._translate_index(index)
+ info = self._model.fileInfo(internalIndex)
+ if role < len(self.FILEINFOS):
+ field = self.FILEINFOS[role]
+ value = getattr(info, field)()
+ else:
+ role -= len(self.FILEINFOS)
+ field = self.EXTINFOS[role]
+ if field == "type":
+ return self._model.type(internalIndex)
+ else:
+ raise NotImplementedError("Out of range that was already checked")
+ return value
+ return None
+
+ def _on_directory_loaded(self, path):
+ if self._path == path:
+ self.backendChanged.emit()
+ self.reset()
+
+ def _translate_index(self, externalIndex):
+ internalIndex = self._model.index(externalIndex.row(), 0, self._rootIndex)
+ return internalIndex
+
+
+@contextlib.contextmanager
+def scoped_model_reset(model):
+ model.beginResetModel()
+ try:
+ yield
+ finally:
+ model.endResetModel()
+
+
+def create_qobject(*classDef, **kwargs):
+ """
+ >>> Car = create_qobject(
+ ... ('model', str),
+ ... ('brand', str),
+ ... ('year', int),
+ ... ('inStock', bool),
+ ... name='Car'
+ ... )
+ >>> print Car
+ <class '__main__.AutoQObject'>
+ >>>
+ >>> c = Car(model='Fiesta', brand='Ford', year=1337)
+ >>> print c.model, c.brand, c.year, c.inStock
+ Fiesta Ford 1337 False
+ >>> print c
+ <Car (model='Fiesta', brand='Ford', year=1337, inStock=False)>
+ >>>
+ >>> c.inStock = True
+ >>>
+ >>> print c.model, c.brand, c.year, c.inStock
+ Fiesta Ford 1337 True
+ >>> print c
+ <Car (model='Fiesta', brand='Ford', year=1337, inStock=True)>
+ """
+
+ class AutoQObject(QtCore.QObject):
+
+ def __init__(self, **initKwargs):
+ QtCore.QObject.__init__(self)
+ for key, val in classDef:
+ setattr(self, '_'+key, initKwargs.get(key, val()))
+
+ def __repr__(self):
+ values = (
+ '%s=%r' % (key, getattr(self, '_'+key))
+ for key, value in classDef
+ )
+ return '<%s (%s)>' % (
+ kwargs.get('name', self.__class__.__name__),
+ ', '.join(values),
+ )
+
+ for key, value in classDef:
+ nfy = locals()['_nfy_'+key] = qt_compat.Signal()
+
+ def _get(key):
+ def f(self):
+ return self.__dict__['_'+key]
+ return f
+
+ def _set(key):
+ def f(self, value):
+ setattr(self, '_'+key, value)
+ getattr(self, '_nfy_'+key).emit()
+ return f
+
+ setter = locals()['_set_'+key] = _set(key)
+ getter = locals()['_get_'+key] = _get(key)
+
+ locals()[key] = qt_compat.Property(value, getter, setter, notify=nfy)
+ del nfy, _get, _set, getter, setter
+
+ return AutoQObject
+
+
+class QObjectProxy(object):
+ """
+ Proxy for accessing properties and slots as attributes
+
+ This class acts as a proxy for the object for which it is
+ created, and makes property access more Pythonic while
+ still allowing access to slots (as member functions).
+
+ Attribute names starting with '_' are not proxied.
+ """
+
+ def __init__(self, rootObject):
+ self._rootObject = rootObject
+ m = self._rootObject.metaObject()
+ self._properties = [
+ m.property(i).name()
+ for i in xrange(m.propertyCount())
+ ]
+
+ def __getattr__(self, key):
+ value = self._rootObject.property(key)
+
+ # No such property, so assume we call a slot
+ if value is None and key not in self._properties:
+ return getattr(self._rootObject, key)
+
+ return value
+
+ def __setattr__(self, key, value):
+ if key.startswith('_'):
+ object.__setattr__(self, key, value)
+ else:
+ self._rootObject.setProperty(key, value)
+
+
+if __name__ == "__main__":
+ import doctest
+ print doctest.testmod()
from __future__ import with_statement
from __future__ import division
-#try:
-# import PySide.QtCore as _QtCore
-# QtCore = _QtCore
-# USES_PYSIDE = True
-#except ImportError:
-if True:
+_TRY_PYSIDE = False
+
+try:
+ if not _TRY_PYSIDE:
+ raise ImportError()
+ import PySide.QtCore as _QtCore
+ QtCore = _QtCore
+ USES_PYSIDE = True
+except ImportError:
import sip
sip.setapi('QString', 2)
sip.setapi('QVariant', 2)
QtCore = qt_compat.QtCore
QtGui = qt_compat.import_module("QtGui")
-from util import qui_utils
-from util import misc as misc_utils
+import qui_utils
+import misc as misc_utils
_moduleLogger = logging.getLogger(__name__)
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+reload(sys).setdefaultencoding("UTF-8")
+import os
+
+try:
+ from sdist_maemo import sdist_maemo as _sdist_maemo
+ sdist_maemo = _sdist_maemo
+except ImportError:
+ sdist_maemo = None
+ print 'sdist_maemo command not available'
+
+from distutils.core import setup
+
+
+#[[[cog
+# import cog
+# from dialcentral import constants
+# cog.outl('APP_NAME="%s"' % constants.__app_name__)
+# cog.outl('PRETTY_APP_NAME="%s"' % constants.__pretty_app_name__)
+# cog.outl('VERSION="%s"' % constants.__version__)
+# cog.outl('BUILD="%s"' % constants.__build__)
+# cog.outl('DESKTOP_FILE_PATH="%s"' % DESKTOP_FILE_PATH)
+# cog.outl('INPUT_DESKTOP_FILE="%s"' % INPUT_DESKTOP_FILE)
+# cog.outl('ICON_CATEGORY="%s"' % ICON_CATEGORY)
+# cog.outl('ICON_SIZES=[%s]' % ICON_SIZES)
+#]]]
+APP_NAME="dialcentral"
+PRETTY_APP_NAME="DialCentral"
+VERSION="1.3.6"
+BUILD="0"
+DESKTOP_FILE_PATH="/usr/share/applications"
+INPUT_DESKTOP_FILE="data/ubuntu/dialcentral.desktop"
+ICON_CATEGORY="apps"
+ICON_SIZES=[32,48]
+#[[[end]]] (checksum: 6b362845c8509854ec12f330afd9c7b7)
+
+CHANGES = """Switching from py2deb.py to sdist_maemo
+""".strip()
+BUGTRACKER_URL = "https://bugs.maemo.org/enter_bug.cgi?product=Dialcentral"
+
+
+def is_package(path):
+ return (
+ os.path.isdir(path) and
+ os.path.isfile(os.path.join(path, '__init__.py'))
+ )
+
+
+def find_packages(path, base="", includeRoot=False):
+ """ Find all packages in path """
+ if includeRoot:
+ assert not base, "Base not supported with includeRoot: %r" % base
+ rootPath, module_name = os.path.split(path)
+ yield module_name
+ base = module_name
+ for item in os.listdir(path):
+ dir = os.path.join(path, item)
+ if is_package( dir ):
+ if base:
+ module_name = "%(base)s.%(item)s" % vars()
+ else:
+ module_name = item
+ yield module_name
+ for mname in find_packages(dir, module_name):
+ yield mname
+
+
+setup(
+ name=APP_NAME,
+ version=VERSION,
+ description="Touch screen enhanced interface to the GoogleVoice phone service",
+ long_description="Touch screen enhanced interface to the GoogleVoice phone service",
+ author="Ed Page",
+ author_email="eopage@byu.net",
+ maintainer="Ed Page",
+ maintainer_email="eopage@byu.net",
+ url="http://wiki.maemo.org/DialCentral",
+ license="GNU LGPLv2.1",
+ scripts=[
+ "DialCentral",
+ ],
+ packages=list(find_packages(APP_NAME, includeRoot=True)),
+ package_data={
+ "dialcentral": ["data/*.wav", "data/*.png"],
+ },
+ data_files=[
+ (DESKTOP_FILE_PATH, [INPUT_DESKTOP_FILE]),
+ ] +
+ [
+ (
+ "/usr/share/icons/hicolor/%sx%s/%s" % (size, size, ICON_CATEGORY),
+ ["data/icons/%s/%s.png" % (size, APP_NAME)]
+ )
+ for size in ICON_SIZES
+ ],
+ requires=[
+ "PySide",
+ "simplejson",
+ "xml",
+ ],
+ cmdclass={
+ 'sdist_ubuntu': sdist_maemo,
+ 'sdist_diablo': sdist_maemo,
+ 'sdist_fremantle': sdist_maemo,
+ 'sdist_harmattan': sdist_maemo,
+ },
+ options={
+ "sdist_ubuntu": {
+ "debian_package": APP_NAME,
+ "section": "comm",
+ "copyright": "lgpl",
+ "changelog": CHANGES,
+ "buildversion": str(BUILD),
+ "depends": "python, python-pyside.qtcore, python-pyside.qtgui, python-simplejson, python-xml, python-dbus, python-gst0.10",
+ "architecture": "any",
+ },
+ "sdist_diablo": {
+ "debian_package": APP_NAME,
+ "Maemo_Display_Name": PRETTY_APP_NAME,
+ #"Maemo_Upgrade_Description": CHANGES,
+ "Maemo_Bugtracker": BUGTRACKER_URL,
+ "Maemo_Icon_26": "data/icons/26/%s.png" % APP_NAME,
+ "section": "user/network",
+ "copyright": "lgpl",
+ "changelog": CHANGES,
+ "buildversion": str(BUILD),
+ "depends": "python2.5, python2.5-qt4-core, python2.5-qt4-gui, python-simplejson, python-xml | python2.5-xml, python-dbus | python2.5-dbus",
+ "architecture": "any",
+ },
+ "sdist_fremantle": {
+ "debian_package": APP_NAME,
+ "Maemo_Display_Name": PRETTY_APP_NAME,
+ #"Maemo_Upgrade_Description": CHANGES,
+ "Maemo_Bugtracker": BUGTRACKER_URL,
+ "Maemo_Icon_26": "data/icons/48/%s.png" % APP_NAME,
+ "section": "user/network",
+ "copyright": "lgpl",
+ "changelog": CHANGES,
+ "buildversion": str(BUILD),
+ "depends": "python, python-pyside.qtcore, python-pyside.qtgui, python-pyside.qtmaemo5, python-simplejson, python-gst0.10, python-xml | python2.5-xml, python-dbus | python2.5-dbus",
+ "architecture": "any",
+ },
+ "sdist_harmattan": {
+ "debian_package": APP_NAME,
+ "Maemo_Display_Name": PRETTY_APP_NAME,
+ #"Maemo_Upgrade_Description": CHANGES,
+ "Maemo_Bugtracker": BUGTRACKER_URL,
+ "Maemo_Icon_26": "data/icons/48/%s.png" % APP_NAME,
+ "MeeGo_Desktop_Entry_Filename": APP_NAME,
+ #"MeeGo_Desktop_Entry": "",
+ "section": "user/science",
+ "copyright": "lgpl",
+ "changelog": CHANGES,
+ "buildversion": str(BUILD),
+ "depends": "python, python-pyside.qtcore, python-pyside.qtgui, python-simplejson, python-xml",
+ "architecture": "any",
+ },
+ "bdist_rpm": {
+ "requires": "REPLACEME",
+ "icon": "data/icons/48/%s.png" % APP_NAME,
+ "group": "REPLACEME",
+ },
+ },
+)
+++ /dev/null
-#!/usr/bin/python2.5
-
-import os
-import sys
-
-try:
- import py2deb
-except ImportError:
- import fake_py2deb as py2deb
-
-import constants
-
-
-__appname__ = constants.__app_name__
-__description__ = """Touch screen enhanced interface to the GoogleVoice phone service
-Features:
-.
-* Dialpad for quick call
-.
-* Checking voicemails, texts, call history
-.
-* Sending texts
-.
-* Notification support for texts, voicemail, and/or missed calls
-.
-Homepage: http://gc-dialer.garage.maemo.org/
-"""
-__author__ = "Ed Page"
-__email__ = "eopage@byu.net"
-__version__ = constants.__version__
-__build__ = constants.__build__
-__changelog__ = """
-* Adding back in GTalk callback for those who can use it
-* Polishing button sizing and some wording
-* Fixed a bug with alert LED on Maemo 4.1
-""".strip()
-
-
-__postinstall__ = """#!/bin/sh -e
-
-gtk-update-icon-cache -f /usr/share/icons/hicolor
-""" % {"name": constants.__app_name__}
-
-__preremove__ = """#!/bin/sh -e
-
-python /opt/dialcentral/lib/alarm_handler.py -d || true
-"""
-
-
-def find_files(prefix, path):
- for root, dirs, files in os.walk(path):
- for file in files:
- if file.startswith(prefix+"-"):
- fileParts = file.split("-")
- unused, relPathParts, newName = fileParts[0], fileParts[1:-1], fileParts[-1]
- assert unused == prefix
- relPath = os.sep.join(relPathParts)
- yield relPath, file, newName
-
-
-def unflatten_files(files):
- d = {}
- for relPath, oldName, newName in files:
- if relPath not in d:
- d[relPath] = []
- d[relPath].append((oldName, newName))
- return d
-
-
-def build_package(distribution):
- try:
- os.chdir(os.path.dirname(sys.argv[0]))
- 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=Dialcentral"
- p.author = __author__
- p.mail = __email__
- p.license = "lgpl"
- p.depends = ", ".join([
- "python2.6 | python2.5",
- "python-xml | python2.5-xml",
- "python-dbus | python2.5-dbus",
- "python-simplejson",
- ])
- p.depends += {
- "debian": ", python-qt4, python-gst0.10",
- "diablo": ", python2.5-qt4-core, python2.5-qt4-gui",
- "fremantle": ", python2.5-qt4-core, python2.5-qt4-gui, python2.5-qt4-maemo5, python-gst0.10",
- #"fremantle": ", python-pyside.qtgui, python-pyside.qtcore, python-pyside.qtmaemo5, python-qtmobility.contacts",
- }[distribution]
- p.recommends = ", ".join([
- ])
- p.section = {
- "debian": "comm",
- "diablo": "user/network",
- "fremantle": "user/network",
- }[distribution]
- p.arch = "all"
- p.urgency = "low"
- p.distribution = "diablo fremantle debian"
- p.repository = "extras"
- p.changelog = __changelog__
- p.postinstall = __postinstall__
- p.preremove = __preremove__
- p.icon = {
- "debian": "26x26-dialcentral.png",
- "diablo": "26x26-dialcentral.png",
- "fremantle": "64x64-dialcentral.png", # Fremantle natively uses 48x48
- }[distribution]
- p["/opt/%s/bin" % __appname__] = [ "%s.py" % __appname__ ]
- for relPath, files in unflatten_files(find_files("src", ".")).iteritems():
- fullPath = "/opt/%s/lib" % __appname__
- if relPath:
- fullPath += os.sep+relPath
- p[fullPath] = list(
- "|".join((oldName, newName))
- for (oldName, newName) in files
- )
- for relPath, files in unflatten_files(find_files("data", ".")).iteritems():
- fullPath = "/opt/%s/share" % __appname__
- if relPath:
- fullPath += os.sep+relPath
- p[fullPath] = list(
- "|".join((oldName, newName))
- for (oldName, newName) in files
- )
- p["/usr/share/applications/hildon"] = ["dialcentral.desktop"]
- p["/usr/share/icons/hicolor/26x26/hildon"] = ["26x26-dialcentral.png|dialcentral.png"]
- p["/usr/share/icons/hicolor/64x64/hildon"] = ["64x64-dialcentral.png|dialcentral.png"]
- p["/usr/share/icons/hicolor/scalable/hildon"] = ["scale-dialcentral.png|dialcentral.png"]
-
- print p
- if distribution == "debian":
- print p.generate(
- version="%s-%s" % (__version__, __build__),
- changelog=__changelog__,
- build=True,
- tar=False,
- changes=False,
- dsc=False,
- )
- else:
- print p.generate(
- version="%s-%s" % (__version__, __build__),
- changelog=__changelog__,
- build=False,
- tar=True,
- changes=True,
- dsc=True,
- )
- print "Building for %s finished" % distribution
-
-
-if __name__ == "__main__":
- if len(sys.argv) == 1:
- distribution = "fremantle"
- else:
- distribution = sys.argv[1]
- build_package(distribution)
+++ /dev/null
-import pprint
-
-
-class Py2deb(object):
-
- def __init__(self, appName):
- self._appName = appName
- self.description = ""
- self.author = ""
- self.mail = ""
- self.license = ""
- self.depends = ""
- self.section = ""
- self.arch = ""
- self.ugency = ""
- self.distribution = ""
- self.repository = ""
- self.changelog = ""
- self.postinstall = ""
- self.icon = ""
- self._install = {}
-
- def generate(self, appVersion, appBuild, changelog, tar, dsc, changes, build, src):
- return """
-Package: %s
-version: %s-%s
-Changes:
-%s
-
-Build Options:
- Tar: %s
- Dsc: %s
- Changes: %s
- Build: %s
- Src: %s
- """ % (
- self._appName, appVersion, appBuild, changelog, tar, dsc, changes, build, src
- )
-
- def __str__(self):
- parts = []
- parts.append("%s Package Settings:" % (self._appName, ))
- for settingName in dir(self):
- if settingName.startswith("_"):
- continue
- parts.append("\t%s: %s" % (settingName, getattr(self, settingName)))
-
- parts.append(pprint.pformat(self._install))
-
- return "\n".join(parts)
-
- def __getitem__(self, key):
- return self._install[key]
-
- def __setitem__(self, key, item):
- self._install[key] = item
+++ /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")
- # TODO Renable signing
- # 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")
- # TODO Renable signing
- # 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 __getitem__(self, k):
- return self.__files[k]
-
- 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
+from __future__ import division
+
+import os
+import logging
+
+from PIL import Image
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+def main(args):
+ import optparse
+ parser = optparse.OptionParser()
+ parser.add_option(
+ "--input", dest="input",
+ help="Input image to scale", metavar="INPUT"
+ )
+ parser.add_option(
+ "--output", dest="output",
+ help="Scaled image", metavar="OUTPUT"
+ )
+ parser.add_option(
+ "--size", dest="size",
+ help="Icon size", metavar="SIZE"
+ )
+ options, positional = parser.parse_args(args)
+ if positional:
+ parser.error("No positional arguments supported")
+ if None in [options.input, options.output, options.size]:
+ parser.error("Missing argument")
+ if options.size == "guess":
+ parts = reversed(os.path.split(options.output))
+ for part in parts:
+ try:
+ options.size = int(part)
+ _moduleLogger.info("Assuming image size of %r" % options.size)
+ break
+ except ValueError:
+ pass
+
+ icon = Image.open(options.input)
+ icon.thumbnail((options.size, options.size), Image.ANTIALIAS)
+ icon.save(options.output)
+
+
+if __name__ == "__main__":
+ import sys
+ retcode = main(sys.argv[1:])
+ sys.exit(retcode)