Package zephir :: Module entpool
[frames] | no frames]

Source Code for Module zephir.entpool

  1  #!/bin/env python 
  2  # -*- coding: UTF-8 -*- 
  3  ########################################################################### 
  4  # Eole NG - 2007   
  5  # Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon) 
  6  # Licence CeCill  cf /root/LicenceEole.txt 
  7  # eole@ac-dijon.fr  
  8  #   
  9  # entpool.py 
 10  #   
 11  # Classes utilitaires pour la gestion d'un pool d'identifiants ENT 
 12  # sur un serveur client de Zephir 
 13  #        
 14  ########################################################################### 
 15   
 16  import os, re 
 17   
18 -class Error(Exception):
19 """Erreur interne 20 """
21
22 -class OutOfRangeError(Error):
23 """valeur hors de la plage 24 """
25
26 -class IdPool(object):
27 """classe représentant un ensemble d'identifiants spécifiques à un ENT 28 les ids ont la forme suivante: LxxCiiii 29 L/C : code ENT défini dans le SDET (cf annexes) et dépendant de l'entité porteuse du projet 30 xx/iiii : 2 lettres et 4 chiffres identifiant un utilisateur 31 """ 32 33 digits = (26, 26, 10, 10, 10, 10) 34
35 - def __init__(self, code_ent):
36 max_id = 1 37 for digit in self.digits: 38 max_id = max_id * digit 39 self.max_id = max_id - 1 40 self.code_ent = code_ent 41 self.digit_vals = self._def_digit_vals() 42 self.regexp = re.compile('^\w[a-z]{2,2}\w\d{4,4}')
43
44 - def _def_digit_vals(self):
45 """définit le poids de chaque caractère dans un identifiant 46 """ 47 digit_vals = [] 48 for num_digit in range(len(self.digits)): 49 val = 1 50 for digit in self.digits[num_digit+1:]: 51 val = val * digit 52 digit_vals.append(val) 53 return digit_vals
54
55 - def id_to_string(self, num_id):
56 """renvoie la représentation au format SDET d'un identifiant numérique 57 """ 58 sdet_id = [] 59 sdet_id.append(self.code_ent[0]) 60 if type(num_id) != int: 61 raise TypeError("type integer requis : %s" % str(num_id)) 62 if 0 > num_id or num_id > self.max_id: 63 raise OutOfRangeError("Valeur incompatible : %s" % str(num_id)) 64 for car in range(2): 65 sdet_id.append(chr(ord('a') + (num_id / self.digit_vals[car]))) 66 num_id = num_id.__mod__(self.digit_vals[car]) 67 sdet_id.append(self.code_ent[1]) 68 for car in range(2, 5): 69 sdet_id.append(str(num_id / self.digit_vals[car])) 70 num_id = num_id.__mod__(self.digit_vals[car]) 71 sdet_id.append(str(num_id)) 72 return "".join(sdet_id)
73
74 - def string_to_id(self, string_id):
75 """renvoie la représentation numérique d'un identifiant au format SDET 76 """ 77 if type(string_id) not in (str, unicode): 78 raise TypeError("Chaine requise : %s" % str(string_id)) 79 string_id = string_id.lower() 80 if not self.regexp.match(string_id): 81 raise ValueError("Chaine au mauvais format : %s" % string_id) 82 num_id = 0 83 for car in range(2): 84 num_id += (ord(string_id[car + 1]) - ord('a')) * self.digit_vals[car] 85 for car in range(2, 5): 86 num_id += int(string_id[car + 2]) * self.digit_vals[car] 87 num_id += int(string_id[7]) 88 return num_id
89
90 -class ClientIdPool(IdPool):
91 """Adaptation de la classe IdPool pour le côté client 92 (maintient la liste des identifiants disponibles et 93 permet leur affectation séquencielle) 94 """ 95
96 - def __init__(self, code_ent, state_dir="/etc/sysconfig/eole"):
97 """initialise un pool sans identifiant disponibles 98 """ 99 super(ClientIdPool, self).__init__(code_ent) 100 self.state_file = os.path.join(state_dir, "ent_ids_%s" % code_ent) 101 self.load_state()
102
103 - def load_state(self):
104 """charge la liste des plages disponibles 105 """ 106 self.free = [] 107 self.free_space = 0 108 if os.path.isfile(self.state_file): 109 data = file(self.state_file).read().strip() 110 # lecture des plages correspondant au code ent 111 for line in data.split('\n'): 112 if line != '': 113 minid, maxid = line.split(',') 114 self._add_free_range(int(minid), int(maxid))
115
116 - def save_state(self):
117 """sauvegarde les plages disponibles 118 """ 119 try: 120 f_state = file(self.state_file, 'w') 121 except IOError: 122 return False 123 for minid, maxid in self.free: 124 f_state.write('%s,%s\n' % (minid, maxid)) 125 f_state.close() 126 return True
127
128 - def __repr__(self):
129 """représentation par défaut de l'objet 130 """ 131 descr = "ENT %s" % self.code_ent 132 descr += " - %d identifiant(s) disponible(s)" % self.free_space 133 if self.free: 134 descr += " - prochain : %s" % self.id_to_string(self.free[0][0]) 135 return descr
136
137 - def add_free_range(self, minid, maxid):
138 """ajoute une plage d'identifiants disponibles 139 minid, maxid : identifiants au format ent 140 """ 141 # recherche de l'emplacement où insérer la plage 142 minid = self.string_to_id(minid) 143 maxid = self.string_to_id(maxid) 144 self._add_free_range(minid, maxid)
145
146 - def _add_free_range(self, minid, maxid):
147 """ajoute une plage d'identifiants disponibles 148 """ 149 insert_index = 0 150 # mise à jour des plages libres 151 if self.free: 152 for rng in self.free: 153 if rng[0] > maxid: 154 # on est sur la plage précédent celle à insérer 155 break 156 insert_index += 1 157 # ajout de la plage réservée avant insert_index 158 self.free.insert(insert_index, (minid, maxid)) 159 self.free_space += maxid - minid + 1 160
161 - def get_next_id(self):
162 """renvoie le prochain identifiant disponible 163 """ 164 if self.free: 165 first_range = self.free[0] 166 new_id = first_range[0] 167 # mise à jour de la plage utilisée 168 if first_range[0] != first_range[1]: 169 self.free[0] = (first_range[0] + 1, first_range[1]) 170 else: 171 self.free.remove(first_range) 172 self.free_space -= 1 173 return self.id_to_string(new_id) 174 return None
175