2 # -*- coding: utf-8 -*-
3 """Librairie de copie et mise à jour des référentiels AuF.
5 Copyright ©2009 Agence universitaire de la Francophonie
6 Licence : LGPL version 3
7 Auteur : Progfou <jean-christophe.andre@auf.org>
9 Dépendances Debian : python >= 2.5, python-simplejson
12 CONFIG_FILE
= '/etc/auf-refer/auf-refer.conf'
14 DIR_BASE
= '/var/lib/auf-refer'
15 URL_BASE
= 'http://intranet.auf/auf-refer'
16 AVAILABLE_LIST
= 'auf-refer.json'
18 lines
= filter(lambda l
: not l
.startswith('#'), file(CONFIG_FILE
))
19 config
= dict(map(lambda l
: map(lambda s
: s
.strip(), l
.split('=')), lines
))
21 DIR_BASE
= config
.get('DIR_BASE', DIR_BASE
).rstrip('/')
22 URL_BASE
= config
.get('URL_BASE', URL_BASE
).rstrip('/')
23 AVAILABLE_LIST
= config
.get('AVAILABLE_LIST', AVAILABLE_LIST
)
25 __all__
= ( 'DIR_BASE', 'URL_BASE', 'AVAILABLE_LIST' )
27 TIME_FORMAT
= '%a, %d %b %Y %H:%M:%S GMT'
29 from os
import listdir
, utime
, unlink
30 from os
.path
import join
, exists
, getmtime
31 from time
import gmtime
, strftime
32 from calendar
import timegm
33 from urllib2
import Request
, urlopen
, HTTPError
, URLError
34 from cStringIO
import StringIO
35 from gzip
import GzipFile
36 from simplejson
import loads
38 def update_referentiel(referentiel
, force
=False):
40 headers
['Accept-Encoding'] = 'x-gzip'
42 headers
['Pragma'] = 'no-cache'
43 filename
= join(DIR_BASE
, referentiel
)
45 # n'effectuer le chargement qu'en cas de nouvelle version
46 mtime
= gmtime(getmtime(filename
))
47 headers
['If-Modified-Since'] = strftime(TIME_FORMAT
, mtime
)
49 # fichier vide à date très ancienne pour déclencher la synchro
51 file(filename
, 'a').close()
54 u
"La création du référentiel '%s' a été refusée :\n %s" \
56 utime(filename
, (0, 0))
57 url
= URL_BASE
+ '/' + referentiel
58 req
= Request(url
, None, headers
)
65 u
"L'URL suivante renvoie un code d'erreur %s :\n %s" \
68 raise RuntimeError, u
"L'URL suivante est inaccessible :\n %s" % url
70 if referentiel
.endswith('.json') and i
.type != 'application/json':
73 u
"Le type des données chargées n'est pas JSON mais '%s'.\n" \
74 u
"URL concernée : %s" % (i
.type, url
)
76 if i
.get('content-encoding') == 'x-gzip':
77 data
= GzipFile('', 'r', 0, StringIO(data
)).read()
79 if referentiel
.endswith('.json'):
81 loads(data
, encoding
='utf-8')
83 raise RuntimeError, u
"Les données ne sont pas au format JSON.\n" \
84 u
"URL concernée : %s" % url
85 # si on est arrivé jusqu'ici c'est que tout va bien... on enregistre !
87 f
= file(filename
, 'wb')
90 u
"L'écriture du référentiel '%s' a été refusée :\n %s" \
94 # on fixe la date donnée par le serveur, le cas échéant
95 mtime
= i
.getdate('last-modified')
98 utime(filename
, (mtime
, mtime
))
100 def add(referentiel
, force
=False):
101 if referentiel
in listdir(DIR_BASE
):
102 raise RuntimeError, \
103 u
"Le référentiel '%s' avait déjà été ajouté." % referentiel
104 update_referentiel(referentiel
, force
)
106 def remove(referentiel
):
107 if not referentiel
in listdir(DIR_BASE
):
108 raise RuntimeError, u
"Le référentiel '%s' est absent." % referentiel
110 unlink(join(DIR_BASE
, referentiel
))
111 except (IOError, OSError), msg
:
112 raise RuntimeError, \
113 u
"La suppression du référentiel '%s' a été refusée :\n %s" \
116 def update(referentiel
=False, force
=False):
118 update_referentiel(referentiel
, force
)
121 for referentiel
in listdir(DIR_BASE
):
123 update_referentiel(referentiel
, force
)
124 except Exception, msg
:
125 error_messages
.append(unicode(msg
))
127 raise RuntimeError, u
'\n'.join(error_messages
)
130 return listdir(DIR_BASE
)
132 def list_available(force
=False):
133 filename
= join(DIR_BASE
, AVAILABLE_LIST
)
134 if not exists(filename
):
135 update_referentiel(AVAILABLE_LIST
, force
)
137 f
= open(filename
, 'rb')
139 raise RuntimeError, u
"La liste des référentiels est indisponible."
141 referentiels
= loads(f
.read(), encoding
='utf-8')
143 raise RuntimeError, \
144 u
"La liste des référentiels n'est pas au format JSON.\n" \
145 u
"Essayez de forcer une mise à jour."
149 def add_available(force
=False):
150 referentiels
= list_available(force
)
151 referentiels
= set(referentiels
) - set(listdir(DIR_BASE
))
152 for referentiel
in referentiels
:
153 update_referentiel(referentiel
, force
)