diff --git a/TODO b/TODO index 0c1b63570..784fe7adf 100644 --- a/TODO +++ b/TODO @@ -3,6 +3,8 @@ TODO list: CLIENT: - trap elogs in reagent - add etc-update alike support + - rewrite the bash stuff in python + - add cached scan stuff - add env-update alike support - add preinst/postinst/prerm/postrm scripts - move branches to version naming (3.5, 3.6, 3.7) instead of using stable, unstable... @@ -24,6 +26,7 @@ TODO list: - world looks inside the latest (if run with "upgrade") - world: add --prune option that removes packages not available anymore - world upgrade should switch python to 2.5 + - if a mirror fails several times, disable it Project Status: diff --git a/client/confTools.py b/client/confTools.py new file mode 100644 index 000000000..d4538467c --- /dev/null +++ b/client/confTools.py @@ -0,0 +1,130 @@ +#!/usr/bin/python +''' + # DESCRIPTION: + # Packages configuration files handling function (etc-update alike) + + Copyright (C) 2007 Fabio Erculiani + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +''' + +import sys +import commands +sys.path.append('../libraries') +from entropyConstants import * +from clientConstants import * +from outputTools import * +import entropyTools +from equoTools import openClientDatabase, closeClientDatabase + +# test if diff is installed +difftest = entropyTools.spawnCommand("diff -v", redirect = "&> /dev/null") +if (difftest): + print "ERROR: diff not found, cannot continue" + +######################################################## +#### +## Configuration Tools +# + +def configurator(options): + + rc = 0 + if len(options) < 1: + return rc + + equoRequestVerbose = False + equoRequestQuiet = False + myopts = [] + for opt in options: + if (opt == "--verbose"): + equoRequestVerbose = True + elif (opt == "--quiet"): + equoRequestQuiet = True + else: + if not opt.startswith("-"): + myopts.append(opt) + + if myopts[0] == "info": + rc = confinfo() + + #elif options[0] == "belongs": + #rc = searchBelongs(myopts[1:], quiet = equoRequestQuiet) + + return rc + +''' + @description: scan for files that need to be merged + @output: dictionary using filename as key +''' +def scanfs(quiet = True): + # load etpConst['dbconfigprotect'] + clientDbconn = openClientDatabase() + closeClientDatabase(clientDbconn) + # etpConst['dbconfigprotect'] + if (not quiet): print_info(yellow(" @@ ")+darkgreen("Scanning filesystem...")) + scandata = {} + counter = 0 + for path in etpConst['dbconfigprotect']: + # it's a file? + deep = True + if os.path.isfile(path): + # find inside basename + path = os.path.basename(path) + deep = False + + for currentdir,subdirs,files in os.walk(path): + for file in files: + filepath = currentdir+"/"+file + if file.startswith("._cfg"): + # further check then + number = file[5:9] + try: + int(number) + except: + continue # not a valid etc-update file + if file[9] != "_": # no valid format provided + continue + # FIXME: add automerging trivial changes + tofile = file[10:] + tofilepath = currentdir+"/"+tofile + scandata[filepath] = {} + scandata[filepath]['revision'] = number + scandata[filepath]['destination'] = tofilepath + if os.path.isfile(tofilepath): + scandata[filepath]['automerge'] = False + else: + scandata[filepath]['automerge'] = True + counter += 1 + try: + if (not quiet): print_info("("+blue(str(counter))+") "+red(" Found file: ")+filepath) + except: + pass # possible encoding issues + return scandata + + + +''' + @description: prints information about config files that should be updated +''' +def confinfo(): + + print_info(yellow(" @@ ")+darkgreen("Loading information..."), back = True) + data = scanfs(quiet = False) + print len(data) + return 0 + + + \ No newline at end of file diff --git a/client/equo b/client/equo index 89b11a2d5..d83326622 100644 --- a/client/equo +++ b/client/equo @@ -47,7 +47,7 @@ def print_help(): print_info(" \t\t"+red("--fetch")+"\t\t\t just download packages without doing the install") print_info(" \t\t"+red("--pretend")+"\t\t just show what would be done") print_info(" \t\t"+red("--verbose")+"\t\t show more details about what's going on") - print_info(" \t"+blue("install")+brown("\t\t install a package")) + print_info(" \t"+blue("install")+brown("\t\t install one or more packages")) print_info(" \t\t"+red("--ask")+"\t\t\t ask before making any changes") print_info(" \t\t"+red("--pretend")+"\t\t just show what would be done") print_info(" \t\t"+red("--fetch")+"\t\t\t just download packages without doing the install") @@ -56,7 +56,7 @@ def print_help(): print_info(" \t\t"+red("--deep")+"\t\t\t analyze dependencies deeply") print_info(" \t\t"+red("--verbose")+"\t\t show more details about what's going on") print_info(" \t\t"+red("--configfiles")+"\t\t also remove old configuration files [use with care]") - print_info(" \t"+blue("remove")+brown("\t\t remove a package")) + print_info(" \t"+blue("remove")+brown("\t\t remove one or more packages")) print_info(" \t\t"+red("--deep")+"\t\t\t also pull unused dependencies where depends list is empty") print_info(" \t\t"+red("--configfiles")+"\t\t also remove configuration files") print_info(" \t"+blue("deptest")+brown("\t\t look for unsatisfied dependencies")) @@ -64,6 +64,9 @@ def print_help(): print_info(" \t\t"+red("--ask")+"\t\t\t ask before making any changes") print_info(" \t\t"+red("--pretend")+"\t\t just show what would be done") + print_info(" \t"+blue("conf")+brown("\t\t configuration files update tool")) + print_info(" \t\t"+darkgreen("info")+red("\t\t\t show info about configuration files that should be updated")) + print_info(" \t"+blue(bold("query"))+brown("\t\t do misc queries on repository and local databases")) print_info(" \t\t"+darkgreen("installed")+red("\t\t search a package into the local database")) print_info(" \t\t"+darkgreen("belongs")+red("\t\t\t search from what package a file belongs")) @@ -83,6 +86,7 @@ def print_help(): print_info(" \t\t"+darkgreen("depends")+red("\t\t\t to regenerate/generate depends caching table")) print_info(" \t"+blue("cleanup")+brown("\t\t remove downloaded packages and clean temporary directories")) print_info(" \t"+blue("--info")+brown("\t\t show Equo System information")) + options = sys.argv[1:] @@ -95,7 +99,6 @@ if len(options) < 1 or string.join(options).find("--help") != -1 or string.join( import equoTools -import queryTools import entropyTools from entropyConstants import * from clientConstants import * @@ -153,9 +156,15 @@ try: sys.exit(rc) elif (options[0] == "query"): + import queryTools rc = queryTools.query(options[1:]) sys.exit(rc) + elif (options[0] == "conf"): + import confTools + rc = confTools.configurator(options[1:]) + sys.exit(rc) + elif (options[0] == "search"): if len(options) > 1: rc = queryTools.searchPackage(options[1:]) diff --git a/client/equoTools.py b/client/equoTools.py index 2d7a22c6d..e0d05e5f5 100644 --- a/client/equoTools.py +++ b/client/equoTools.py @@ -1089,7 +1089,7 @@ def removePackage(infoDict): # collision check if etpConst['collisionprotect'] > 0: if file in contentCache: - print "DEBUG!! [remove]: collision found for "+file.encode(sys.getfilesystemencoding()) #FIXME: beautify + print_warning(yellow(" ## ")+red("Collision found during remove for ")+file.encode(sys.getfilesystemencoding())+" - cannot overwrite") continue try: del contentCache[file] @@ -1099,25 +1099,28 @@ def removePackage(infoDict): protected = False if (not infoDict['removeconfig']): - # -- CONFIGURATION FILE PROTECTION -- - if os.access(file,os.R_OK): - for x in protect: - if file.startswith(x): - protected = True - break - if (protected): - for x in mask: + try: + # -- CONFIGURATION FILE PROTECTION -- + if os.access(file,os.R_OK): + for x in protect: if file.startswith(x): - protected = False - break - if (protected) and os.path.isfile(file): - protected = istextfile(file) - else: - protected = False # it's not a file - # -- CONFIGURATION FILE PROTECTION -- + protected = True + break + if (protected): + for x in mask: + if file.startswith(x): + protected = False + break + if (protected) and os.path.isfile(file): + protected = istextfile(file) + else: + protected = False # it's not a file + # -- CONFIGURATION FILE PROTECTION -- + except: + pass # some filenames are buggy encoded if (protected): - print "DEBUG: PROTECTED -> "+str(file) + print_warning(yellow(" ## ")+red("Protecting config file: ")+str(file)) else: try: os.remove(file) @@ -1214,54 +1217,59 @@ def installPackage(infoDict): if etpConst['collisionprotect'] > 1: if tofile in contentCache: - print "DEBUG!! [install]: collision found for "+file.encode(sys.getfilesystemencoding()) #FIXME: beautify + print_warning(yellow(" ## ")+red("Collision found during install for ")+file.encode(sys.getfilesystemencoding())+" - cannot overwrite") + print_warning(yellow(" ## ")+red("Protecting config file: ")+str(tofile)) continue # -- CONFIGURATION FILE PROTECTION -- - - protected = False - for x in protect: - if tofile.startswith(x): - protected = True - break - if (protected): # check if perhaps, file is masked, so unprotected - for x in mask: + + try: + protected = False + for x in protect: if tofile.startswith(x): - protected = False - break + protected = True + break + if (protected): # check if perhaps, file is masked, so unprotected + for x in mask: + if tofile.startswith(x): + protected = False + break - if os.access(tofile,os.F_OK): - try: - if not protected: os.remove(tofile) - except: - if not protected: - rc = os.system("rm -f "+tofile) - if (rc != 0): - return 3 - else: - protected = False # file doesn't exist + if os.access(tofile,os.F_OK): + try: + if not protected: os.remove(tofile) + except: + if not protected: + rc = os.system("rm -f "+tofile) + if (rc != 0): + return 3 + else: + protected = False # file doesn't exist - # check if it's a text file - if (protected) and os.path.isfile(tofile): - protected = istextfile(tofile) - else: - protected = False # it's not a file + # check if it's a text file + if (protected) and os.path.isfile(tofile): + protected = istextfile(tofile) + else: + protected = False # it's not a file - # check md5 - if (protected) and os.path.isfile(tofile) and os.path.isfile(fromfile): - mymd5 = md5sum(fromfile) - sysmd5 = md5sum(tofile) - if mymd5 == sysmd5: - protected = False # files are the same - else: - protected = False # a broken symlink inside our image dir + # check md5 + if (protected) and os.path.isfile(tofile) and os.path.isfile(fromfile): + mymd5 = md5sum(fromfile) + sysmd5 = md5sum(tofile) + if mymd5 == sysmd5: + protected = False # files are the same + else: + protected = False # a broken symlink inside our image dir - # request new tofile then - if (protected): - print "DEBUG: PROTECTED ->"+str(tofile) - tofile = allocateMaskedFile(tofile) + # request new tofile then + if (protected): + print_warning(yellow(" ## ")+red("Protecting config file: ")+str(tofile)) + tofile = allocateMaskedFile(tofile) - # -- CONFIGURATION FILE PROTECTION -- + # -- CONFIGURATION FILE PROTECTION -- + + except: + pass # some files are buggy encoded try: # this also handles symlinks @@ -1269,7 +1277,7 @@ def installPackage(infoDict): try: packageContent.append(tofile.encode("utf-8")) except: - print_error("DEBUG!!: file error: "+str(tofile)+" cannot be converted into UTF-8, skipping") + print_warning(yellow(" ## ")+red("Cannot convert filename into UTF-8, skipping ")+str(tofile)) pass except IOError,(errno,strerror): if errno == 2: diff --git a/client/queryTools.py b/client/queryTools.py index 6aee0a075..5f4d2a2b0 100644 --- a/client/queryTools.py +++ b/client/queryTools.py @@ -57,32 +57,32 @@ def query(options): if not opt.startswith("-"): myopts.append(opt) - if options[0] == "installed": + if myopts[0] == "installed": rc = searchInstalledPackages(myopts[1:], quiet = equoRequestQuiet) - elif options[0] == "belongs": + elif myopts[0] == "belongs": rc = searchBelongs(myopts[1:], quiet = equoRequestQuiet) - elif options[0] == "depends": + elif myopts[0] == "depends": rc = searchDepends(myopts[1:], verbose = equoRequestVerbose, quiet = equoRequestQuiet) - elif options[0] == "files": + elif myopts[0] == "files": rc = searchFiles(myopts[1:], quiet = equoRequestQuiet) - elif options[0] == "removal": + elif myopts[0] == "removal": rc = searchRemoval(myopts[1:], quiet = equoRequestQuiet, deep = equoRequestDeep) - elif options[0] == "orphans": + elif myopts[0] == "orphans": rc = searchOrphans(quiet = equoRequestQuiet) - elif options[0] == "list": + elif myopts[0] == "list": mylistopts = options[1:] if len(mylistopts) > 0: if mylistopts[0] == "installed": rc = searchInstalled(verbose = equoRequestVerbose, quiet = equoRequestQuiet) # add more here - elif options[0] == "description": + elif myopts[0] == "description": rc = searchDescription(myopts[1:], quiet = equoRequestQuiet) return rc