#!/usr/bin/python # # File: geneticone/flags.py # This file is part of the Genetic/One-Project, a graphical portage-frontend. # # Copyright (C) 2006 Necoro d.M. # This is free software. You may redistribute copies of it under the terms of # the GNU General Public License version 2. # There is NO WARRANTY, to the extent permitted by law. # # Written by Necoro d.M. import os import os.path from subprocess import Popen, PIPE import geneticone import portage from portage_util import unique_array ### GENERAL PART ### def grep (p, path): """Grep runs "egrep" on a given path and looks for occurences of a given package.""" if not isinstance(p, geneticone.Package): p = geneticone.Package(p) # assume it is a cpv or a gentoolkit.Package command = "egrep -x -n -r -H '^[<>!=~]{0,2}%s(-[0-9].*)?[[:space:]].*$' %s" return Popen((command % (p.get_cp(), path)), shell = True, stdout = PIPE).communicate()[0].splitlines() def get_data(pkg, path): """This splits up the data of grep() and builds tuples in the format (file,line,criterion,list_of_flags).""" flags = [] # do grep list = grep(pkg, path) for i in range(len(list)): file, line, fl = tuple(list[i].split(":")) # get file, line and flag-list fl = fl.split() crit = fl[0] fl = fl[1:] # stop after first comment for i in range(len(fl)): if fl[i][0] == "#": #comment - stop here fl = fl[:i] break flags.append((file,line,crit,fl)) return flags ### USE FLAG PART ### USE_PATH = os.path.join(portage.USER_CONFIG_PATH,"package.use") USE_PATH_IS_DIR = os.path.isdir(USE_PATH) useFlags = {} # useFlags in the file newUseFlags = {} # useFlags as we want them to be: format: cpv -> [(file, line, useflag, (true if removed from list / false if added))] def invert_use_flag (_flag): if _flag[0] == "-": return _flag[1:] else: return "-"+_flag def set_use_flag (pkg, flag): """Sets the useflag for a given package.""" global useFlags, newUseFlags if not isinstance(pkg, geneticone.Package): pkg = geneticone.Package(pkg) # assume cpv or gentoolkit.Package cpv = pkg.get_cpv() invFlag = invert_use_flag(flag) # if not saved in useFlags, get it by calling get_data() which calls grep() data = None if not cpv in useFlags: data = get_data(pkg, USE_PATH) useFlags[cpv] = data else: data = useFlags[cpv] if not cpv in newUseFlags: newUseFlags[cpv] = [] print "data: "+str(data) # add a useflag / delete one added = False for file, line, crit, flags in data: if pkg.matches(crit): # we have the inverted flag in the uselist/newuselist --> delete it if invFlag in flags or (file, line, invFlag, False) in newUseFlags[cpv] or (file, line, flag, True) in newUseFlags[cpv]: if added: del newUseFlags[-1] # we currently added it as an extra option - delete it added = True jumpOut = False for t in [(file, line, invFlag, False),(file, line, flag, True)]: if t in newUseFlags[cpv]: newUseFlags[cpv].remove(t) jumpOut = True break if not jumpOut: newUseFlags[cpv].append((file, line, invFlag, True)) break # we want to duplicate the flag --> ignore elif flag in flags: added = True # emulate adding break # add as an extra flag else: if not added: newUseFlags[cpv].append((file, line, flag, False)) added = True # create a new line if not added: path = USE_PATH if USE_PATH_IS_DIR: path = os.path.join(USE_PATH,"geneticone") try: newUseFlags[cpv].remove((path, -1, invFlag, False)) except ValueError: # not in UseFlags newUseFlags[cpv].append((path, -1, flag, False)) newUseFlags[cpv] = unique_array(newUseFlags[cpv]) print "newUseFlags: "+str(newUseFlags) def remove_new_use_flags (cpv): if isinstance(cpv, geneticone.Package): cpv = cpv.get_cpv() try: del newUseFlags[cpv] except KeyError: pass def get_new_use_flags (cpv): if isinstance(cpv, geneticone.Package): cpv = cpv.get_cpv() list2return = [] try: for file, line, flag, remove in newUseFlags[cpv]: if remove: list2return.append(invert_use_flag(flag)) else: list2return.append(flag) except KeyError: pass return list2return def write_use_flags (): """This writes our changed useflags into the file.""" global newUseFlags, useFlags def insert (flag, list): """Shortcut for inserting a new flag right after the package-name.""" list.insert(1,flag) def remove (flag, list): """Removes a flag.""" try: list.remove(flag) except ValueError: # flag is given as flag\n list.remove(flag+"\n") list.append("\n") #re-insert the newline # no more flags there - comment it out if len(list) == 1 or list[1][0] in ("#","\n"): list[0] = "#"+list[0] insert("#removed by geneticone#",list) file_cache = {} # cache for having to read the file only once: name->[lines] for cpv in newUseFlags: for file, line, flag, delete in newUseFlags[cpv]: line = int(line) # it is saved as a string so far! # add new line if line == -1: msg = "\n#geneticone update#\n=%s %s\n" % (cpv, flag) if not file in file_cache: f = open(file, "a") f.write(msg) f.close() else: file_cache[file].append(msg) # change a line else: if not file in file_cache: # read file f = open(file, "r") lines = [] i = 1 while i < line: # stop at the given line lines.append(f.readline()) i = i+1 l = f.readline().split(" ") # delete or insert if delete: remove(flag,l) else: insert(flag,l) lines.append(" ".join(l)) # read the rest lines.extend(f.readlines()) file_cache[file] = lines f.close() else: # in cache l = file_cache[file][line-1].split(" ") if delete: remove(flag,l) else: insert(flag,l) file_cache[file][line-1] = " ".join(l) # write to disk for file in file_cache.keys(): f = open(file, "w") f.writelines(file_cache[file]) f.close() # reset useFlags = {} newUseFlags = {}