Package entropy :: Package client :: Module misc

Source Code for Module entropy.client.misc

  1  # -*- coding: utf-8 -*- 
  2  ''' 
  3      # DESCRIPTION: 
  4      # Entropy Object Oriented Interface 
  5   
  6      Copyright (C) 2007-2009 Fabio Erculiani 
  7   
  8      This program is free software; you can redistribute it and/or modify 
  9      it under the terms of the GNU General Public License as published by 
 10      the Free Software Foundation; either version 2 of the License, or 
 11      (at your option) any later version. 
 12   
 13      This program is distributed in the hope that it will be useful, 
 14      but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16      GNU General Public License for more details. 
 17   
 18      You should have received a copy of the GNU General Public License 
 19      along with this program; if not, write to the Free Software 
 20      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 21  ''' 
 22   
 23  import os 
 24  import sys 
 25  import shutil 
 26  import subprocess 
 27  from entropy.client.interfaces import Client 
 28  from entropy.exceptions import * 
 29  from entropy.const import etpConst, etpCache 
 30  from entropy.output import darkred, darkgreen, red, brown, blue 
 31  from entropy.tools import getstatusoutput 
 32  from entropy.i18n import _ 
 33   
34 -class FileUpdates:
35
36 - def __init__(self, EquoInstance):
37 if not isinstance(EquoInstance,Client): 38 mytxt = _("A valid Client instance or subclass is needed") 39 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,)) 40 self.Entropy = EquoInstance 41 from entropy.cache import EntropyCacher 42 from entropy.core import SystemSettings 43 self.Cacher = EntropyCacher() 44 self.SystemSettings = SystemSettings() 45 self.scandata = None
46
47 - def merge_file(self, key):
48 self.scanfs(dcache = True) 49 self.do_backup(key) 50 source_file = etpConst['systemroot'] + self.scandata[key]['source'] 51 dest_file = etpConst['systemroot'] + self.scandata[key]['destination'] 52 if os.access(source_file, os.R_OK): 53 shutil.move(source_file, dest_file) 54 self.remove_from_cache(key)
55
56 - def remove_file(self, key):
57 self.scanfs(dcache = True) 58 source_file = etpConst['systemroot'] + self.scandata[key]['source'] 59 if os.access(source_file, os.F_OK) and os.access(source_file, os.W_OK): 60 os.remove(source_file) 61 self.remove_from_cache(key)
62
63 - def do_backup(self, key):
64 self.scanfs(dcache = True) 65 sys_set_plg_id = \ 66 etpConst['system_settings_plugins_ids']['client_plugin'] 67 files_backup = self.Entropy.SystemSettings[sys_set_plg_id]['misc']['filesbackup'] 68 dest_file = etpConst['systemroot'] + self.scandata[key]['destination'] 69 if files_backup and os.path.isfile(dest_file): 70 bcount = 0 71 backupfile = etpConst['systemroot'] + \ 72 os.path.dirname(self.scandata[key]['destination']) + \ 73 "/._entropy_backup." + unicode(bcount) + "_" + \ 74 os.path.basename(self.scandata[key]['destination']) 75 while os.path.lexists(backupfile): 76 bcount += 1 77 backupfile = etpConst['systemroot'] + \ 78 os.path.dirname(self.scandata[key]['destination']) + \ 79 "/._entropy_backup." + unicode(bcount) + "_" + \ 80 os.path.basename(self.scandata[key]['destination']) 81 try: 82 shutil.copy2(dest_file, backupfile) 83 except IOError: 84 pass
85
86 - def scanfs(self, dcache = True, quiet = False):
87 88 if dcache: 89 90 if self.scandata != None: 91 return self.scandata 92 93 # can we load cache? 94 try: 95 z = self.load_cache() 96 if z != None: 97 self.scandata = z 98 return self.scandata 99 except (CacheCorruptionError, KeyError, IOError, OSError,): 100 pass 101 102 scandata = {} 103 counter = 0 104 name_cache = set() 105 client_conf_protect = self.Entropy.get_system_config_protect() 106 107 for path in client_conf_protect: 108 109 # this avoids encoding issues hands down 110 path = path.encode(sys.getfilesystemencoding()) 111 # it's a file? 112 scanfile = False 113 if os.path.isfile(path): 114 # find inside basename 115 path = os.path.dirname(path) 116 scanfile = True 117 118 for currentdir,subdirs,files in os.walk(path): 119 for item in files: 120 121 if scanfile: 122 if path != item: 123 continue 124 125 filepath = os.path.join(currentdir,item) 126 if item.startswith("._cfg"): 127 128 # further check then 129 number = item[5:9] 130 try: 131 int(number) 132 except ValueError: 133 continue # not a valid etc-update file 134 if item[9] != "_": # no valid format provided 135 continue 136 137 if filepath in name_cache: 138 continue # skip, already done 139 name_cache.add(filepath) 140 141 mydict = self.generate_dict(filepath) 142 if mydict['automerge']: 143 if not quiet: 144 mytxt = _("Automerging file") 145 self.Entropy.updateProgress( 146 darkred("%s: %s") % ( 147 mytxt, 148 darkgreen(etpConst['systemroot'] + mydict['source']), 149 ), 150 importance = 0, 151 type = "info" 152 ) 153 if os.path.isfile(etpConst['systemroot']+mydict['source']): 154 try: 155 os.rename(etpConst['systemroot']+mydict['source'], 156 etpConst['systemroot']+mydict['destination']) 157 except (OSError, IOError,), e: 158 if not quiet: 159 mytxt = "%s :: %s: %s. %s: %s" % ( 160 red(_("System Error")), 161 red(_("Cannot automerge file")), 162 brown(etpConst['systemroot'] + mydict['source']), 163 blue("error"), 164 e, 165 ) 166 self.Entropy.updateProgress( 167 mytxt, 168 importance = 1, 169 type = "warning" 170 ) 171 continue 172 else: 173 counter += 1 174 scandata[counter] = mydict.copy() 175 176 if not quiet: 177 try: 178 self.Entropy.updateProgress( 179 "("+blue(str(counter))+") " + red(" file: ") + \ 180 os.path.dirname(filepath) + "/" + os.path.basename(filepath)[10:], 181 importance = 1, 182 type = "info" 183 ) 184 except: 185 pass # possible encoding issues 186 # store data 187 self.Cacher.push(etpCache['configfiles'],scandata) 188 self.scandata = scandata.copy() 189 return scandata
190
191 - def load_cache(self):
192 sd = self.Cacher.pop(etpCache['configfiles']) 193 if not isinstance(sd,dict): 194 raise CacheCorruptionError("CacheCorruptionError") 195 # quick test if data is reliable 196 try: 197 name_cache = set() 198 199 for x in sd: 200 mysource = sd[x]['source'] 201 # filter dupies 202 if mysource in name_cache: 203 sd.pop(x) 204 continue 205 if not os.path.isfile(etpConst['systemroot']+mysource): 206 raise CacheCorruptionError("CacheCorruptionError") 207 name_cache.add(mysource) 208 209 return sd 210 except (KeyError,EOFError,IOError,): 211 raise CacheCorruptionError("CacheCorruptionError")
212
213 - def add_to_cache(self, filepath, quiet = False):
214 self.scanfs(dcache = True, quiet = quiet) 215 keys = self.scandata.keys() 216 try: 217 for key in keys: 218 if self.scandata[key]['source'] == filepath[len(etpConst['systemroot']):]: 219 del self.scandata[key] 220 except: 221 pass 222 # get next counter 223 if keys: 224 keys = sorted(keys) 225 index = keys[-1] 226 else: 227 index = 0 228 index += 1 229 mydata = self.generate_dict(filepath) 230 self.scandata[index] = mydata.copy() 231 self.Cacher.push(etpCache['configfiles'],self.scandata)
232
233 - def remove_from_cache(self, key):
234 self.scanfs(dcache = True) 235 try: 236 del self.scandata[key] 237 except: 238 pass 239 self.Cacher.push(etpCache['configfiles'],self.scandata) 240 return self.scandata
241
242 - def generate_dict(self, filepath):
243 244 item = os.path.basename(filepath) 245 currentdir = os.path.dirname(filepath) 246 tofile = item[10:] 247 number = item[5:9] 248 try: 249 int(number) 250 except: 251 mytxt = _("Invalid config file number") 252 raise InvalidDataType("InvalidDataType: %s '0000->9999'." % (mytxt,)) 253 tofilepath = currentdir+"/"+tofile 254 mydict = {} 255 mydict['revision'] = number 256 mydict['destination'] = tofilepath[len(etpConst['systemroot']):] 257 mydict['source'] = filepath[len(etpConst['systemroot']):] 258 mydict['automerge'] = False 259 if not os.path.isfile(tofilepath): 260 mydict['automerge'] = True 261 if (not mydict['automerge']): 262 # is it trivial? 263 try: 264 if not os.path.lexists(filepath): # if file does not even exist 265 return mydict 266 if os.path.islink(filepath): 267 # if it's broken, skip diff and automerge 268 if not os.path.exists(filepath): 269 return mydict 270 result = getstatusoutput('diff -Nua "%s" "%s" | grep "^[+-][^+-]" | grep -v \'# .Header:.*\'' % (filepath,tofilepath,))[1] 271 if not result: 272 mydict['automerge'] = True 273 except: 274 pass 275 # another test 276 if (not mydict['automerge']): 277 try: 278 if not os.path.lexists(filepath): # if file does not even exist 279 return mydict 280 if os.path.islink(filepath): 281 # if it's broken, skip diff and automerge 282 if not os.path.exists(filepath): 283 return mydict 284 result = subprocess.call('diff -Bbua "%s" "%s" | egrep \'^[+-]\' | egrep -v \'^[+-][\t ]*#|^--- |^\+\+\+ \' | egrep -qv \'^[-+][\t ]*$\'' % (filepath,tofilepath,), shell = True) 285 if result == 1: 286 mydict['automerge'] = True 287 except: 288 pass 289 return mydict
290