diff options
Diffstat (limited to 'geneticone/backend/flags.py')
-rw-r--r-- | geneticone/backend/flags.py | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/geneticone/backend/flags.py b/geneticone/backend/flags.py new file mode 100644 index 0000000..8899fc5 --- /dev/null +++ b/geneticone/backend/flags.py @@ -0,0 +1,525 @@ +# +# 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. <necoro@necoro.net> + +import os +import os.path +from subprocess import Popen, PIPE # needed for grep + +import geneticone +from helper import * +import portage +from portage_util import unique_array + +### GENERAL PART ### + +def grep (pkg, path): + """Grep runs "egrep" on a given path and looks for occurences of a given package. + @param pkg: the package + @type pkg: string (cpv) or L{geneticone.Package}-object + @param path: path to look in + @type path: string + + @returns: occurences of pkg in the format: "file:line-no:complete_line_found" + @rtype: string""" + + if not isinstance(pkg, geneticone.Package): + pkg = geneticone.Package(pkg) # 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 % (pkg.get_cp(), path)), shell = True, stdout = PIPE).communicate()[0].splitlines() + +def get_data(pkg, path): + """This splits up the data of L{grep} and builds tuples in the format (file,line,criterion,list_of_flags). + @param pkg: package to find + @type pkg: string (cpv) or L{geneticone.Package}-object + @param path: path to look in + @type path: string + + @returns: a list of tuples in the form (file,line,criterion,list_of_flags) + @rtype: list""" + + 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): + """Invertes a flag. + + >>> invert_use_flag("foo") + -foo + >>> invert_use_flag("-bar") + bar + + @param flag: the flag + @type flag: string + @returns: inverted flag + @rtype: string + """ + if flag[0] == "-": + return flag[1:] + else: + return "-"+flag + +def set_use_flag (pkg, flag): + """Sets the useflag for a given package. + + @param pkg: the package + @type pkg: string (cpv) or L{geneticone.Package}-object + @param flag: the flag to set + @type flag: string""" + + 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] = [] + + debug("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]) + debug("newUseFlags: "+str(newUseFlags)) + +def remove_new_use_flags (cpv): + """Removes all new use-flags for a specific package. + @param cpv: the package for which to remove the flags + @type cpv: string (cpv) or L{geneticone.Package}-object""" + if isinstance(cpv, geneticone.Package): + cpv = cpv.get_cpv() + + try: + del newUseFlags[cpv] + except KeyError: + pass + +def get_new_use_flags (cpv): + """Gets all the new use-flags for a specific package. + @param cpv: the package for which to remove the flags + @type cpv: string (cpv) or L{geneticone.Package}-object + @returns: list of flags + @rtype: list""" + + 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 = {} + +# +# +# NOTHING IS WORKING / IN USE BELOW THIS LINE +# +# +### MASKING PART ### +MASK_PATH = os.path.join(portage.USER_CONFIG_PATH,"package.mask") +UNMASK_PATH = os.path.join(portage.USER_CONFIG_PATH,"package.unmask") +MASK_PATH_IS_DIR = os.path.isdir(MASK_PATH) +UNMASK_PATH_IS_DIR = os.path.isdir(UNMASK_PATH) + +new_masked = {} +new_unmasked = {} + +def set_masked (pkg): + global new_masked, newunmasked + if not isinstance(pkg, geneticone.Package): + pkg = geneticone.Package(pkg) + + cpv = pkg.get_cpv() + + if not cpv in new_unmasked: + new_unmasked[cpv] = [] + if not cpv in new_masked: + new_masked[cpv] = [] + + nu = new_unmasked[cpv][:] + for file, line in nu: + if line == "-1": + new_unmasked[cpv].remove(file, line) + + nm = new_masked[cpv][:] + for file, line in nm: + if line != "-1": + new_masked[cpv].remove(file, line) + + if pkg.is_masked(): + return + + unmasked = get_data(pkg, UNMASK_PATH) + debug("data (unmasked): "+str(unmasked)) + done = False + for file, line, crit, flags in unmasked: + if pkg.matches(crit): + new_unmasked[cpv].append((file, line)) + done = True + + if done: return + + if MASK_PATH_IS_DIR: + file = os.path.join(MASK_PATH, "geneticone") + else: + file = MASK_PATH + + new_masked[cpv].append((file, "-1")) + new_masked[cpv] = unique_array(new_masked[cpv]) + debug("new_masked: "+str(new_masked)) + +def set_unmasked (pkg): + global new_masked, new_unmasked + if not isinstance(pkg, geneticone.Package): + pkg = geneticone.Package(pkg) + + cpv = pkg.get_cpv() + + if not cpv in new_unmasked: + new_unmasked[cpv] = [] + if not cpv in new_masked: + new_masked[cpv] = [] + + nu = new_unmasked[cpv][:] + for file, line in nu: + if line != "-1": + new_unmasked[cpv].remove(file, line) + + nm = new_masked[cpv][:] + for file, line in nm: + if line == "-1": + new_masked[cpv].remove(file, line) + + if not pkg.is_masked(): + return + + masked = get_data(pkg, MASK_PATH) + debug("data (masked): "+str(masked)) + done = False + for file, line, crit, fl in masked: + if pkg.matches(crit): + new_masked[cpv].append((file, line)) + done = True + + if done: return + + if UNMASK_PATH_IS_DIR: + file = os.path.join(UNMASK_PATH, "geneticone") + else: + file = UNMASK_PATH + + new_unmasked[cpv].append((file, "-1")) + new_unmasked[cpv] = unique_array(new_unmasked[cpv]) + debug("new_unmasked: "+str(new_unmasked)) + +def write_masked_unmasked (): + global new_unmasked, new_masked + file_cache = {} + + def write(cpv, file, line): + line = int(line) + # add new line + if line == -1: + msg = "\n#geneticone update#\n=%s\n" % cpv + 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 + # delete + l = f.readline() + l = "#"+l[:-1]+" # removed by geneticone\n" + lines.append(l) + + # read the rest + lines.extend(f.readlines()) + + file_cache[file] = lines + f.close() + else: # in cache + l = file_cache[file][line-1] + # delete: + l = "#"+l[:-1]+" # removed by geneticone\n" + file_cache[file][line-1] = l + + + for cpv in new_masked: + for file, line in new_masked[cpv]: + write(cpv, file, line) + + for cpv in new_unmasked: + for file, line in new_unmasked[cpv]: + write(cpv, file, line) + + # write to disk + for file in file_cache.keys(): + f = open(file, "w") + f.writelines(file_cache[file]) + f.close() + # reset + new_masked = {} + new_unmasked = {} + +### TESTING PART ### +TESTING_PATH = os.path.join(portage.USER_CONFIG_PATH, "package.keywords") +TESTING_PATH_IS_DIR = os.path.isdir(TESTING_PATH) +newTesting = {} +arch = "" + +def set_testing (pkg, enable): + """Enables the package for installing when it is marked as testing (~ARCH). + @param pkg: the package + @type pkg: string (cpv) or L{geneticone.Package}-object + @param enable: controls whether to enable (True) or disable (False) for test-installing + @type enable: boolean""" + + global arch, newTesting + if not isinstance(pkg, geneticone.Package): + pkg = geneticone.Package(pkg) + + arch = pkg.get_settings("ARCH") + cpv = pkg.get_cpv() + if not cpv in newTesting: + newTesting[cpv] = [] + + debug("arch: "+arch) + for file, line in newTesting[cpv]: + if (enable and line != "-1") or (not enable and line == "-1"): + newTesting[cpv].remove((file, line)) + + if (enable and (pkg.get_mask_status() % 3 == 0)) or (not enable and (pkg.get_mask_status() % 3 != 0)): + return + + if not enable: + test = get_data(pkg, TESTING_PATH) + debug("data (test): "+str(test)) + for file, line, crit, flags in test: + if pkg.matches(crit) and flags[0] == "~"+arch: + newTesting[cpv].append((file, line)) + else: + if TESTING_PATH_IS_DIR: + file = os.path.join(TESTING_PATH, "geneticone") + else: + file = TESTING_PATH + newTesting[cpv].append((file, "-1")) + + newTesting[cpv] = unique_array(newTesting[cpv]) + debug("newTesting: "+str(newTesting)) + +def write_testing (): + global arch, newTesting + file_cache = {} + + for cpv in newTesting: + for file, line in newTesting[cpv]: + line = int(line) + # add new line + if line == -1: + msg = "\n#geneticone update#\n=%s ~%s\n" % (cpv, arch) + 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 + # delete + l = f.readline() + l = "#"+l[:-1]+" # removed by geneticone\n" + lines.append(l) + + # read the rest + lines.extend(f.readlines()) + + file_cache[file] = lines + f.close() + else: # in cache + l = file_cache[file][line-1] + # delete: + l = "#"+l[:-1]+" # removed by geneticone\n" + file_cache[file][line-1] = l + + # write to disk + for file in file_cache.keys(): + f = open(file, "w") + f.writelines(file_cache[file]) + f.close() + # reset + newTesting = {} |