releasing version 1.0.0
authorProgfou <jean-christophe.andre@auf.org>
Sun, 9 Aug 2009 23:39:51 +0000 (06:39 +0700)
committerProgfou <jean-christophe.andre@auf.org>
Sun, 9 Aug 2009 23:40:16 +0000 (06:40 +0700)
13 files changed:
MANIFEST [new file with mode: 0644]
MANIFEST.in [new file with mode: 0644]
Makefile
auf-refer
auf-refer.conf
aufrefer.py [new file with mode: 0755]
debian/auf-refer.8
debian/changelog
debian/control
debian/pycompat [new file with mode: 0644]
debian/pyversions [new file with mode: 0644]
debian/rules
setup.py [new file with mode: 0644]

diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..7032bea
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,22 @@
+MANIFEST.in
+Makefile
+README
+apache.conf
+auf-refer
+auf-refer.conf
+aufrefer.py
+setup.py
+debian/auf-refer.8
+debian/changelog
+debian/compat
+debian/control
+debian/copyright
+debian/cron.d
+debian/dirs
+debian/lintian-overrides
+debian/manpages
+debian/postinst
+debian/postrm
+debian/pycompat
+debian/pyversions
+debian/rules
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644 (file)
index 0000000..77adb19
--- /dev/null
@@ -0,0 +1,6 @@
+include *.txt
+recursive-include examples *.txt *.py
+prune examples/sample?/build
+include auf-refer *.conf README
+include Makefile MANIFEST.in
+recursive-include debian *
index fd55e72..88997ed 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,13 +4,9 @@ DIST = $(shell dpkg-parsechangelog | sed -n 's/^Distribution: //p')
 all: build
 
 build:
+       sed -i "/ version=/s/='[^']*'/='$(VERSION)'/" setup.py
 
 install:
-       install -m 0755 -d $(DESTDIR)/usr/sbin
-       install -m 0755 auf-refer $(DESTDIR)/usr/sbin/
-       install -m 0755 -d $(DESTDIR)/etc/auf-refer
-       install -m 0644 *.conf $(DESTDIR)/etc/auf-refer/
-       install -m 0755 -d $(DESTDIR)/var/lib/auf-refer
 
 clean:
 
index 41a9eb1..73200ba 100755 (executable)
--- a/auf-refer
+++ b/auf-refer
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/python
 # -*- coding: utf-8 -*-
-"""Copie et mise à jour des référentiels AuF.
+"""Outil de copie et mise à jour des référentiels AuF.
 
 Copyright ©2009  Agence universitaire de la Francophonie
 Licence : GPL version 3
@@ -9,190 +9,45 @@ Auteur : Progfou <jean-christophe.andre@auf.org>
 Dépendances Debian : python >= 2.5, python-simplejson
 """
 
-PROG_NAME = 'auf-refer'
 RUN_USER = 'auf-refer'
-DIR_BASE = '/var/lib/auf-refer/'
-URL_BASE = 'http://intranet.auf/auf-refer/'
 
-f = file('/etc/auf-refer/auf-refer.conf')
-lines = filter(lambda l: not l.startswith('#'), f.readlines())
-config = dict(map(lambda l: map(lambda s: s.strip(), l.split('=')), lines))
+__all__ = ( 'RUN_USER' )
 
-URL_BASE = config.get('URL_BASE', URL_BASE).rstrip('/') + '/'
-
-__all__ = ( 'RUN_USER', 'DIR_BASE', 'URL_BASE' )
-
-USAGE = """Usages (à lancer en tant que "root", par exemple via "sudo") :
+USAGE = """Usages (nécessite parfois "root", par exemple via "sudo") :
   auf-refer [-f] -a <ref> - copie un nouveau référentiel
-  auf-refer -d <ref>      - supprime un référentiel
+  auf-refer -r <ref>      - supprime un référentiel
   auf-refer [-f] -u       - met à jour les référentiels
   auf-refer -l            - liste les référentiels copiés
-  auf-refer -L            - liste les référentiels disponibles
+  auf-refer [-f] -L       - liste les référentiels disponibles
   auf-refer [-f] -A       - copie tous les référentiels disponibles
 
 L'option -f permet de forcer le rechargement à travers un proxy/cache.
 """
 
-TIME_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
-
 from sys import argv, exit, stderr
 from getopt import getopt, GetoptError
 from pwd import getpwnam
-from os import getuid, setgid, setuid, listdir, utime, unlink
-from os.path import join, exists, getmtime
-from time import gmtime, strftime
-from calendar import timegm
-from urllib2 import Request, urlopen, HTTPError, URLError
-from cStringIO import StringIO
-from gzip import GzipFile
-from simplejson import loads
-
-def update_referentiel(referentiel, force=False):
-    headers = {}
-    headers['Accept-Encoding'] = 'x-gzip'
-    if force:
-        headers['Pragma'] = 'no-cache'
-    filename = join(DIR_BASE, referentiel)
-    if exists(filename):
-        # n'effectuer le chargement qu'en cas de nouvelle version
-        mtime = gmtime(getmtime(filename))
-        headers['If-Modified-Since'] = strftime(TIME_FORMAT, mtime)
-    else:
-        # fichier vide à date très ancienne pour déclencher la synchro
-        try:
-            switch_user()
-            file(filename, 'a').close()
-        except IOError, msg:
-            raise RuntimeError, \
-                u"La création du référentiel a été refusée : %s" % msg
-        utime(filename, (0, 0))
-    url = URL_BASE + referentiel
-    req = Request(url, None, headers)
-    try:
-        u = urlopen(req)
-    except HTTPError, e:
-        if e.code == 304:
-            return
-        raise RuntimeError, \
-            u"L'URL suivante renvoie un code d'erreur %s :\n  %s" \
-                                                        % (e.code, url)
-    except URLError:
-        raise RuntimeError, u"L'URL suivante est inaccessible :\n  %s" % url
-    i = u.info()
-    if referentiel.endswith('.json') and i.type != 'application/json':
-        u.close()
-        raise RuntimeError, \
-            u"Le type des données chargées n'est pas JSON mais '%s'." % i.type
-    data = u.read()
-    if i.get('content-encoding') == 'x-gzip':
-        data = GzipFile('', 'r', 0, StringIO(data)).read()
-    u.close()
-    if referentiel.endswith('.json'):
-        try:
-            loads(data, encoding='utf-8')
-        except ValueError:
-            raise RuntimeError, u"Les données ne sont pas au format JSON."
-    # si on est arrivé jusqu'ici c'est que tout va bien... on enregistre !
-    try:
-        switch_user()
-        f = file(filename, 'wb')
-    except IOError, msg:
-        raise RuntimeError, \
-            u"L'écriture du référentiel a été refusée : %s" % msg
-    f.write(data)
-    f.close()
-    # on fixe la date donnée par le serveur, le cas échéant
-    mtime = i.getdate('last-modified')
-    if mtime:
-        mtime = timegm(mtime)
-        utime(filename, (mtime, mtime))
-
-def add_referentiel(referentiel, force=False):
-    if referentiel in listdir(DIR_BASE):
-        raise RuntimeError, \
-            u"Le référentiel '%s' avait déjà été ajouté." % referentiel
-    update_referentiel(referentiel, force)
-
-def delete_referentiel(referentiel):
-    if not referentiel in listdir(DIR_BASE):
-        raise RuntimeError, u"Le référentiel '%s' est absent." % referentiel
-    try:
-        switch_user()
-        unlink(join(DIR_BASE, referentiel))
-    except IOError, msg:
-        raise RuntimeError, \
-            u"La suppression du référentiel '%s' a été refusée :\n  %s" \
-                                                    % (referentiel, msg)
-
-def update_referentiels(force=False):
-    error_messages = []
-    for referentiel in listdir(DIR_BASE):
-        try:
-            update_referentiel(referentiel, force)
-        except Exception, msg:
-            error_messages.append(unicode(msg))
-    if error_messages:
-        raise RuntimeError, u'\n'.join(error_messages)
-
-def list_referentiels():
-    for referentiel in listdir(DIR_BASE):
-        print referentiel
-
-def get_referentiels_available(force=False):
-    referentiel = 'auf-refer.json'
-    filename = join(DIR_BASE, referentiel)
-    if not exists(filename):
-        update_referentiel(referentiel, force)
-    try:
-        f = open(filename, 'rb')
-    except IOError:
-        raise RuntimeError, u"La liste des référentiels est indisponible."
-    try:
-        referentiels = loads(f.read(), encoding='utf-8')
-    except ValueError:
-        raise RuntimeError, \
-            u"La liste des référentiels n'est pas au format JSON.\n" \
-            u"Essayez les options -f et -u pour la mettre à jour."
-    f.close()
-    return referentiels
-
-def list_referentiels_available(force=False):
-    referentiels = get_referentiels_available(force)
-    for referentiel in sorted(referentiels):
-        print "%-16s : %s" % (referentiel, referentiels[referentiel])
-
-def add_referentiels_available(force=False):
-    referentiels = get_referentiels_available(force)
-    referentiels = set(referentiels) - set(listdir(DIR_BASE))
-    for referentiel in referentiels:
-        update_referentiel(referentiel, force)
-
-_user_switched = False
-def switch_user(username=RUN_USER):
-    global _user_switched
-    if _user_switched:
-        return
-    try:
-        pw = getpwnam(username)
-    except KeyError:
-        raise RuntimeError, u"L'utilisateur '%s' n'existe pas." % username
-    try:
-        setgid(pw.pw_gid)
-        setuid(pw.pw_uid)
-    except OSError:
-        raise RuntimeError, \
-            u"Impossible de basculer vers l'utilisateur '%s'.\n" \
-            u"Réessayez avec 'sudo' !" % username
-    _user_switched = True
+from os import getuid, setgid, setuid
+import aufrefer
 
 if __name__ == '__main__':
     # interdiction formelle de tourner sous 'root'
     if getuid() == 0:
-        switch_user()
+        try:
+            pw = getpwnam(RUN_USER)
+        except KeyError:
+            raise RuntimeError, u"L'utilisateur '%s' n'existe pas." % RUN_USER
+        try:
+            setgid(pw.pw_gid)
+            setuid(pw.pw_uid)
+        except OSError:
+            raise RuntimeError, \
+                u"Impossible de basculer vers l'utilisateur '%s'.\n" \
+                u"Réessayez avec 'sudo' !" % RUN_USER
 
     try:
-        opts, args = getopt(argv[1:], 'hfa:d:ulLA', ['help', 'force',
-            'add=', 'delete=', 'update', 'list',
+        opts, args = getopt(argv[1:], 'hfa:r:ulLA', ['help', 'force',
+            'add=', 'remove=', 'update', 'list',
             'list-available', 'add-available'])
     except GetoptError:
         print USAGE
@@ -208,17 +63,20 @@ if __name__ == '__main__':
         else:
             try:
                 if opt in ('-a', '--add'):
-                    add_referentiel(arg, force=force)
-                elif opt in ('-d', '--delete'):
-                    delete_referentiel(arg)
+                    aufrefer.add(arg, force=force)
+                elif opt in ('-r', '--remove'):
+                    aufrefer.remove(arg)
                 elif opt in ('-u', '--update'):
-                    update_referentiels(force=force)
+                    aufrefer.update(force=force)
                 elif opt in ('-l', '--list'):
-                    list_referentiels()
+                    for referentiel in aufrefer.list():
+                        print referentiel
                 elif opt in ('-L', '--list-available'):
-                    list_referentiels_available(force=force)
+                    list = aufrefer.list_available(force=force)
+                    for referentiel in sorted(list):
+                        print "%-16s : %s" % (referentiel, list[referentiel])
                 elif opt in ('-A', '--add-available'):
-                    add_referentiels_available(force=force)
+                    aufrefer.add_available(force=force)
             except RuntimeError, msg:
                 print >>stderr, u'%s' % msg
 
index d617e8d..84491ac 100644 (file)
@@ -1 +1,3 @@
+DIR_BASE=/var/lib/auf-refer
 URL_BASE=http://intranet.auf/auf-refer
+AVAILABLE_LIST=auf-refer.json
diff --git a/aufrefer.py b/aufrefer.py
new file mode 100755 (executable)
index 0000000..70babad
--- /dev/null
@@ -0,0 +1,154 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""Librairie de copie et mise à jour des référentiels AuF.
+
+Copyright ©2009  Agence universitaire de la Francophonie
+Licence : LGPL version 3
+Auteur : Progfou <jean-christophe.andre@auf.org>
+
+Dépendances Debian : python >= 2.5, python-simplejson
+"""
+
+CONFIG_FILE = '/etc/auf-refer/auf-refer.conf'
+
+DIR_BASE = '/var/lib/auf-refer'
+URL_BASE = 'http://intranet.auf/auf-refer'
+AVAILABLE_LIST = 'auf-refer.json'
+
+lines = filter(lambda l: not l.startswith('#'), file(CONFIG_FILE))
+config = dict(map(lambda l: map(lambda s: s.strip(), l.split('=')), lines))
+
+DIR_BASE = config.get('DIR_BASE', DIR_BASE).rstrip('/')
+URL_BASE = config.get('URL_BASE', URL_BASE).rstrip('/')
+AVAILABLE_LIST = config.get('AVAILABLE_LIST', AVAILABLE_LIST)
+
+__all__ = ( 'DIR_BASE', 'URL_BASE', 'AVAILABLE_LIST' )
+
+TIME_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
+
+from os import listdir, utime, unlink
+from os.path import join, exists, getmtime
+from time import gmtime, strftime
+from calendar import timegm
+from urllib2 import Request, urlopen, HTTPError, URLError
+from cStringIO import StringIO
+from gzip import GzipFile
+from simplejson import loads
+
+def update_referentiel(referentiel, force=False):
+    headers = {}
+    headers['Accept-Encoding'] = 'x-gzip'
+    if force:
+        headers['Pragma'] = 'no-cache'
+    filename = join(DIR_BASE, referentiel)
+    if exists(filename):
+        # n'effectuer le chargement qu'en cas de nouvelle version
+        mtime = gmtime(getmtime(filename))
+        headers['If-Modified-Since'] = strftime(TIME_FORMAT, mtime)
+    else:
+        # fichier vide à date très ancienne pour déclencher la synchro
+        try:
+            file(filename, 'a').close()
+        except IOError, msg:
+            raise RuntimeError, \
+                u"La création du référentiel '%s' a été refusée :\n  %s" \
+                                                    % (referentiel, msg)
+        utime(filename, (0, 0))
+    url = URL_BASE + '/' + referentiel
+    req = Request(url, None, headers)
+    try:
+        u = urlopen(req)
+    except HTTPError, e:
+        if e.code == 304:
+            return
+        raise RuntimeError, \
+            u"L'URL suivante renvoie un code d'erreur %s :\n  %s" \
+                                                        % (e.code, url)
+    except URLError:
+        raise RuntimeError, u"L'URL suivante est inaccessible :\n  %s" % url
+    i = u.info()
+    if referentiel.endswith('.json') and i.type != 'application/json':
+        u.close()
+        raise RuntimeError, \
+            u"Le type des données chargées n'est pas JSON mais '%s'.\n" \
+            u"URL concernée : %s" % (i.type, url)
+    data = u.read()
+    if i.get('content-encoding') == 'x-gzip':
+        data = GzipFile('', 'r', 0, StringIO(data)).read()
+    u.close()
+    if referentiel.endswith('.json'):
+        try:
+            loads(data, encoding='utf-8')
+        except ValueError:
+            raise RuntimeError, u"Les données ne sont pas au format JSON.\n" \
+                                u"URL concernée : %s" % url
+    # si on est arrivé jusqu'ici c'est que tout va bien... on enregistre !
+    try:
+        f = file(filename, 'wb')
+    except IOError, msg:
+        raise RuntimeError, \
+            u"L'écriture du référentiel '%s' a été refusée :\n  %s" \
+                                                    % (referentiel, msg)
+    f.write(data)
+    f.close()
+    # on fixe la date donnée par le serveur, le cas échéant
+    mtime = i.getdate('last-modified')
+    if mtime:
+        mtime = timegm(mtime)
+        utime(filename, (mtime, mtime))
+
+def add(referentiel, force=False):
+    if referentiel in listdir(DIR_BASE):
+        raise RuntimeError, \
+            u"Le référentiel '%s' avait déjà été ajouté." % referentiel
+    update_referentiel(referentiel, force)
+
+def remove(referentiel):
+    if not referentiel in listdir(DIR_BASE):
+        raise RuntimeError, u"Le référentiel '%s' est absent." % referentiel
+    try:
+        unlink(join(DIR_BASE, referentiel))
+    except (IOError, OSError), msg:
+        raise RuntimeError, \
+            u"La suppression du référentiel '%s' a été refusée :\n  %s" \
+                                                    % (referentiel, msg)
+
+def update(referentiel=False, force=False):
+    if referentiel:
+        update_referentiel(referentiel, force)
+        return
+    error_messages = []
+    for referentiel in listdir(DIR_BASE):
+        try:
+            update_referentiel(referentiel, force)
+        except Exception, msg:
+            error_messages.append(unicode(msg))
+    if error_messages:
+        raise RuntimeError, u'\n'.join(error_messages)
+
+def list():
+    return listdir(DIR_BASE)
+
+def list_available(force=False):
+    filename = join(DIR_BASE, AVAILABLE_LIST)
+    if not exists(filename):
+        update_referentiel(AVAILABLE_LIST, force)
+    try:
+        f = open(filename, 'rb')
+    except IOError:
+        raise RuntimeError, u"La liste des référentiels est indisponible."
+    try:
+        referentiels = loads(f.read(), encoding='utf-8')
+    except ValueError:
+        raise RuntimeError, \
+            u"La liste des référentiels n'est pas au format JSON.\n" \
+            u"Essayez de forcer une mise à jour."
+    f.close()
+    return referentiels
+
+def add_available(force=False):
+    referentiels = list_available(force)
+    referentiels = set(referentiels) - set(listdir(DIR_BASE))
+    for referentiel in referentiels:
+        update_referentiel(referentiel, force)
+
index 4e2ee3c..1f37cc8 100644 (file)
@@ -15,7 +15,7 @@ auf-refer \- outil de copie et mise à jour des réferentiels AuF
 .SH SYNOPSIS
 \fBauf-refer\fP [\fB-f\fP] \fB-a\fP \fIreferentiel\fP
 .br
-\fBauf-refer\fP \fB-d\fP \fIreferentiel\fP
+\fBauf-refer\fP \fB-r\fP \fIreferentiel\fP
 .br
 \fBauf-refer\fP \fB-h\fP | \fB-l\fP
 .br
@@ -45,7 +45,7 @@ Liste les référentiel copiés.
 .B \-u, \-\-update
 Met à jour les référentiels immédiatement. L'option \fB-f\fP permet de forcer le chargement à travers un proxy/cache.
 .TP
-.B \-d, \-\-delete
+.B \-r, \-\-remove
 Supprime un référentiel.
 .SH FILES
 .TP
index 440b3a8..90964d8 100644 (file)
@@ -1,3 +1,9 @@
+auf-refer (1.0.0) jaunty; urgency=low
+
+  * Réécriture complète dans l'optique d'un module réutilisable.
+
+ -- Progfou <jean-christophe.andre@auf.org>  Mon, 10 Aug 2009 06:34:57 +0700
+
 auf-refer (0.5) jaunty; urgency=low
 
   * Le projet "auf-referentiels" devient "auf-refer", comprend qui peut... ;-)
index 3c5cbad..befc789 100644 (file)
@@ -2,14 +2,13 @@ Source: auf-refer
 Section: auf
 Priority: optional
 Maintainer: Progfou <jean-christophe.andre@auf.org>
-Build-Depends: cdbs, debhelper (>= 5.0.0)
+Build-Depends: cdbs (>= 0.4.49), debhelper (>= 5), python, python-support (>= 0.7)
 Standards-Version: 3.7.3
 Homepage: http://git.auf.org/?p=auf-poste-client;a=tree;f=auf-refer
 
 Package: auf-refer
 Architecture: all
-Depends: ${misc:Depends}, adduser, python (>= 2.5), python-simplejson
-Provides: auf-referentiels
+Depends: adduser, python (>= 2.5), python-simplejson, ${misc:Depends}
 Replaces: auf-referentiels
 Conflicts: auf-referentiels
 Description: outil de copie et mise à jour des réferentiels AuF
diff --git a/debian/pycompat b/debian/pycompat
new file mode 100644 (file)
index 0000000..0cfbf08
--- /dev/null
@@ -0,0 +1 @@
+2
diff --git a/debian/pyversions b/debian/pyversions
new file mode 100644 (file)
index 0000000..b3dc41e
--- /dev/null
@@ -0,0 +1 @@
+2.5-
index b2e6ff1..82697c3 100755 (executable)
@@ -1,6 +1,8 @@
 #!/usr/bin/make -f
+DEB_PYTHON_SYSTEM=pysupport
 
-DEB_MAKE_INSTALL_TARGET=install DESTDIR=$(DEB_DESTDIR)
 include /usr/share/cdbs/1/rules/debhelper.mk
-include /usr/share/cdbs/1/class/makefile.mk
-include /usr/share/cdbs/1/rules/utils.mk
+include /usr/share/cdbs/1/class/python-distutils.mk
+
+# Don't compress .py files
+DEB_COMPRESS_EXCLUDE := .py
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..2f9eb78
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from distutils.core import setup
+
+setup(name='auf-refer',
+    version='1.0.0',
+    author='Progfou',
+    author_email='jean-christophe.andre@auf.org',
+    url='http://git.auf.org/?p=auf-refer.git',
+    description='AuF utility to optimize access to reference data',
+    long_description='Ce paquet fournit un outil permettant de copier puis de mettre régulièrement à jour une sélection des référentiels AuF.',
+    license='LGPL',
+    download_url='git://git.auf.org/auf-refer.git',
+    classifiers=[
+        'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
+        'License :: OSI Approved :: GNU General Public License (GPL)',
+        'Programming Language :: Python',
+        'Topic :: Database :: Database Front-Ends',
+        'Natural Language :: French',
+    ],
+    requires=['simplejson'],
+    py_modules=['aufrefer'],
+    data_files=[
+        ('/etc/auf-refer',['auf-refer.conf','apache.conf']),
+        ('/usr/sbin',['auf-refer']),
+        ],
+    )
+