Package entropy :: Package client :: Module misc

Source Code for Module entropy.client.misc

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