md5_match_hash[conf] = conf
todo_cnt -= 1
if todo_cnt == 0:
- raise "Break"
- except "Break":
+ raise StopIteration()
+ except StopIteration:
pass
for conf in args:
from portage.output import *
-from getopt import getopt, GetoptError
+from optparse import OptionGroup, OptionParser
__program__ = "glsa-check"
__author__ = "Marius Mauch <genone@gentoo.org>"
__version__ = "1.0"
-optionmap = [
-["-l", "--list", "list all unapplied GLSA"],
-["-d", "--dump", "--print", "show all information about the given GLSA"],
-["-t", "--test", "test if this system is affected by the given GLSA"],
-["-p", "--pretend", "show the necessary commands to apply this GLSA"],
-["-f", "--fix", "try to auto-apply this GLSA (experimental)"],
-["-i", "--inject", "inject the given GLSA into the checkfile"],
-["-n", "--nocolor", "disable colors (option)"],
-["-e", "--emergelike", "do not use a least-change algorithm (option)"],
-["-h", "--help", "show this help message"],
-["-V", "--version", "some information about this tool"],
-["-v", "--verbose", "print more information (option)"],
-["-c", "--cve", "show CAN ids in listing mode (option)"],
-["-m", "--mail", "send a mail with the given GLSAs to the administrator"]
-]
+def cb_version(*args, **kwargs):
+ """Callback for --version"""
+ sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n")
+ sys.stderr.write("Author: " + __author__ + "\n")
+ sys.stderr.write("This program is licensed under the GPL, version 2\n\n")
+ sys.exit(0)
# option parsing
-args = []
-params = []
-try:
- args, params = getopt(sys.argv[1:], "".join([o[0][1] for o in optionmap]), \
- [x[2:] for x in reduce(lambda x,y: x+y, [z[1:-1] for z in optionmap])])
-# ["dump", "print", "list", "pretend", "fix", "inject", "help", "verbose", "version", "test", "nocolor", "cve", "mail"])
- args = [a for a,b in args]
-
- for option in ["--nocolor", "-n"]:
- if option in args:
- nocolor()
- args.remove(option)
-
- verbose = False
- for option in ["--verbose", "-v"]:
- if option in args:
- verbose = True
- args.remove(option)
-
- list_cve = False
- for option in ["--cve", "-c"]:
- if option in args:
- list_cve = True
- args.remove(option)
-
- least_change = True
- for option in ["--emergelike", "-e"]:
- if option in args:
- least_change = False
- args.remove(option)
-
- # sanity checking
- if len(args) <= 0:
- sys.stderr.write("no option given: what should I do ?\n")
- mode="help"
- elif len(args) > 1:
- sys.stderr.write("please use only one command per call\n")
- mode = "help"
- else:
- # in what mode are we ?
- args = args[0]
- for m in optionmap:
- if args in [o for o in m[:-1]]:
- mode = m[1][2:]
-
-except GetoptError, e:
- sys.stderr.write("unknown option given: ")
- sys.stderr.write(str(e)+"\n")
- mode = "help"
-
-# we need a set of glsa for most operation modes
-if len(params) <= 0 and mode in ["fix", "test", "pretend", "dump", "inject", "mail"]:
+parser = OptionParser(usage="%prog <option> [glsa-list]",
+ version="%prog "+ __version__)
+parser.epilog = "glsa-list can contain an arbitrary number of GLSA ids," \
+ " filenames containing GLSAs or the special identifiers" \
+ " 'all', 'new' and 'affected'"
+
+modes = OptionGroup(parser, "Modes")
+modes.add_option("-l", "--list", action="store_const",
+ const="list", dest="mode",
+ help="List all unapplied GLSA")
+modes.add_option("-d", "--dump", action="store_const",
+ const="dump", dest="mode",
+ help="Show all information about the given GLSA")
+modes.add_option("", "--print", action="store_const",
+ const="dump", dest="mode",
+ help="Alias for --dump")
+modes.add_option("-t", "--test", action="store_const",
+ const="test", dest="mode",
+ help="Test if this system is affected by the given GLSA")
+modes.add_option("-p", "--pretend", action="store_const",
+ const="pretend", dest="mode",
+ help="Show the necessary commands to apply this GLSA")
+modes.add_option("-f", "--fix", action="store_const",
+ const="fix", dest="mode",
+ help="Try to auto-apply this GLSA (experimental)")
+modes.add_option("-i", "--inject", action="store_const", dest="mode",
+ help="Inject the given GLSA into the checkfile")
+modes.add_option("-m", "--mail", action="store_const",
+ const="mail", dest="mode",
+ help="Send a mail with the given GLSAs to the administrator")
+parser.add_option_group(modes)
+
+parser.remove_option("--version")
+parser.add_option("-V", "--version", action="callback",
+ callback=cb_version, help="Some information about this tool")
+parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
+ help="Print more information")
+parser.add_option("-n", "--nocolor", action="callback",
+ callback=lambda *args, **kwargs: nocolor(),
+ help="Disable colors")
+parser.add_option("-e", "--emergelike", action="store_false", dest="least_change",
+ help="Do not use a least-change algorithm")
+parser.add_option("-c", "--cve", action="store_true", dest="list_cve",
+ help="Show CAN ids in listing mode")
+
+options, params = parser.parse_args()
+
+mode = options.mode
+least_change = options.least_change
+list_cve = options.list_cve
+verbose = options.verbose
+
+# Sanity checking
+if mode is None:
+ sys.stderr.write("No mode given: what should I do?\n")
+ parser.print_help()
+ sys.exit(1)
+elif mode != "list" and not params:
sys.stderr.write("\nno GLSA given, so we'll do nothing for now. \n")
sys.stderr.write("If you want to run on all GLSA please tell me so \n")
sys.stderr.write("(specify \"all\" as parameter)\n\n")
- mode = "help"
-elif len(params) <= 0 and mode == "list":
- params.append("new")
-
-# show help message
-if mode == "help":
- sys.stderr.write("\nSyntax: glsa-check <option> [glsa-list]\n\n")
- for m in optionmap:
- sys.stderr.write(m[0] + "\t" + m[1] + " \t: " + m[-1] + "\n")
- for o in m[2:-1]:
- sys.stderr.write("\t" + o + "\n")
- sys.stderr.write("\nglsa-list can contain an arbitrary number of GLSA ids, \n")
- sys.stderr.write("filenames containing GLSAs or the special identifiers \n")
- sys.stderr.write("'all', 'new' and 'affected'\n")
+ parser.print_help()
sys.exit(1)
-
-# we need root priviledges for write access
-if mode in ["fix", "inject"] and os.geteuid() != 0:
- sys.stderr.write("\nThis tool needs root access to "+mode+" this GLSA\n\n")
+elif mode in ["fix", "inject"] and os.geteuid() != 0:
+ # we need root priviledges for write access
+ sys.stderr.write("\nThis tool needs root access to "+options.mode+" this GLSA\n\n")
sys.exit(2)
-
-# show version and copyright information
-if mode == "version":
- sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n")
- sys.stderr.write("Author: " + __author__ + "\n")
- sys.stderr.write("This program is licensed under the GPL, version 2\n\n")
- sys.exit(0)
+elif mode == "list" and not params:
+ params.append("new")
# delay this for speed increase
from portage.glsa import *
# 14 is the length of DESCRIPTION=""
max_desc_len = 100
allowed_filename_chars="a-zA-Z0-9._-+:"
-allowed_filename_chars_set = {}
-map(allowed_filename_chars_set.setdefault, map(chr, range(ord('a'), ord('z')+1)))
-map(allowed_filename_chars_set.setdefault, map(chr, range(ord('A'), ord('Z')+1)))
-map(allowed_filename_chars_set.setdefault, map(chr, range(ord('0'), ord('9')+1)))
-map(allowed_filename_chars_set.setdefault, map(chr, map(ord, [".", "-", "_", "+", ":"])))
+disallowed_filename_chars_re = re.compile(r'[^a-zA-Z0-9._\-+:]')
bad = create_color_func("BAD")
# A sane umask is needed for files that portage creates.
valid_profile_types = frozenset(["dev", "exp", "stable"])
descfile=portdir+"/profiles/profiles.desc"
if os.path.exists(descfile):
- for i, x in enumerate(open(descfile, 'rb')):
+ for i, x in enumerate(open(descfile)):
if x[0]=="#":
continue
arch=x.split()
continue
for y in checkdirlist:
- for c in y.strip(os.path.sep):
- if c not in allowed_filename_chars_set:
- stats["file.name"] += 1
- fails["file.name"].append("%s/%s: char '%s'" % (checkdir, y, c))
- break
+ m = disallowed_filename_chars_re.search(y.strip(os.sep))
+ if m is not None:
+ stats["file.name"] += 1
+ fails["file.name"].append("%s/%s: char '%s'" % \
+ (checkdir, y, m.group(0)))
if not (y in ("ChangeLog", "metadata.xml") or y.endswith(".ebuild")):
continue
stats["file.size"] += 1
fails["file.size"].append("("+ str(mystat.st_size/1024) + "K) "+x+"/files/"+y)
- for c in os.path.basename(y.rstrip(os.path.sep)):
- if c not in allowed_filename_chars_set:
- stats["file.name"] += 1
- fails["file.name"].append("%s/files/%s: char '%s'" % (checkdir, y, c))
- break
+ m = disallowed_filename_chars_re.search(
+ os.path.basename(y.rstrip(os.sep)))
+ if m is not None:
+ stats["file.name"] += 1
+ fails["file.name"].append("%s/files/%s: char '%s'" % \
+ (checkdir, y, m.group(0)))
if desktop_file_validate and desktop_pattern.match(y):
status, cmd_output = commands.getstatusoutput(
# Syntax Checks
relative_path = os.path.join(x, y + ".ebuild")
full_path = os.path.join(repodir, relative_path)
- f = open(full_path, 'rb')
+ f = open(full_path)
try:
for check_name, e in run_checks(f, pkg):
stats[check_name] += 1
def _load(self):
try:
- f = open(self._cache_filename)
+ f = open(self._cache_filename, mode='rb')
mypickle = pickle.Unpickler(f)
- mypickle.find_global = None
self._cache_data = mypickle.load()
f.close()
del f
- except (IOError, OSError, EOFError, pickle.UnpicklingError), e:
+ except (IOError, OSError, EOFError, ValueError, pickle.UnpicklingError), e:
if isinstance(e, pickle.UnpicklingError):
writemsg("!!! Error loading '%s': %s\n" % \
(self._cache_filename, str(e)), noiselevel=-1)
if len(self._modified) >= self._cache_threshold and \
secpass >= 2:
try:
- f = portage.util.atomic_ofstream(self._cache_filename)
+ f = portage.util.atomic_ofstream(self._cache_filename, mode='wb')
pickle.dump(self._cache_data, f, -1)
f.close()
portage.util.apply_secpass_permissions(
for k, capname in self._termcap_name_map.iteritems():
term_codes[k] = self._default_term_codes[capname]
object.__setattr__(self, "_term_codes", term_codes)
+ for k, v in self._term_codes.items():
+ if not isinstance(v, str):
+ self._term_codes[k] = v.decode()
def _init_term(self):
"""
log_path = self._locate_failure_log(failed_pkg)
if log_path is not None:
try:
- log_file = open(log_path, 'rb')
+ log_file = open(log_path)
except IOError:
pass
success, mydepgraph, dropped_tasks = resume_depgraph(
self.settings, self.trees, self._mtimedb, self.myopts,
myparams, self._spinner)
- except depgraph.UnsatisfiedResumeDep, e:
+ except depgraph.UnsatisfiedResumeDep, exc:
+ # rename variable to avoid python-3.0 error:
+ # SyntaxError: can not delete variable 'e' referenced in nested
+ # scope
+ e = exc
mydepgraph = e.depgraph
dropped_tasks = set()
_flush_elog_mod_echo()
counter_hash = settings.get("PORTAGE_COUNTER_HASH")
- if counter_hash is not None and \
- counter_hash == vardbapi._counter_hash():
+ if "--pretend" in myopts or (counter_hash is not None and \
+ counter_hash == vardbapi._counter_hash()):
display_news_notification(root_config, myopts)
# If vdb state has not changed then there's nothing else to do.
sys.exit(retval)
unsatisfied_parents[parent_node] = parent_node
unsatisfied_stack.append(parent_node)
- pruned_mergelist = [x for x in mergelist \
+ pruned_mergelist = []
+ for x in mergelist:
if isinstance(x, list) and \
- tuple(x) not in unsatisfied_parents]
+ tuple(x) not in unsatisfied_parents:
+ pruned_mergelist.append(x)
# If the mergelist doesn't shrink then this loop is infinite.
if len(pruned_mergelist) == len(mergelist):
# a list type for options.
mtimedb["resume"]["myopts"] = myopts.copy()
- # Convert Atom instances to plain str since the mtimedb loader
- # sets unpickler.find_global = None which causes unpickler.load()
- # to raise the following exception:
- #
- # cPickle.UnpicklingError: Global and instance pickles are not supported.
- #
- # TODO: Maybe stop setting find_global = None, or find some other
- # way to avoid accidental triggering of the above UnpicklingError.
+ # Convert Atom instances to plain str.
mtimedb["resume"]["favorites"] = [str(x) for x in favorites]
if ("--digest" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
mysettings = trees[myroot]["vartree"].settings
mysettings.unlock()
adjust_config(myopts, mysettings)
- mysettings["PORTAGE_COUNTER_HASH"] = \
- trees[myroot]["vartree"].dbapi._counter_hash()
- mysettings.backup_changes("PORTAGE_COUNTER_HASH")
+ if "--pretend" not in myopts:
+ mysettings["PORTAGE_COUNTER_HASH"] = \
+ trees[myroot]["vartree"].dbapi._counter_hash()
+ mysettings.backup_changes("PORTAGE_COUNTER_HASH")
mysettings.lock()
del myroot, mysettings
if logfile is None:
return
try:
- f = open(logfile, 'rb')
+ f = open(logfile)
except EnvironmentError:
return
d = {} # for full backward compat, pickle it as a plain dict object.
d.update(mydict)
try:
- f = atomic_ofstream(filename)
+ f = atomic_ofstream(filename, mode='wb')
pickle.dump(d, f, -1)
f.close()
portage.util.apply_secpass_permissions(filename, uid=uid, gid=portage_gid, mode=0664)
def _load(self, filename):
try:
- f = open(filename)
+ f = open(filename, 'rb')
mypickle = pickle.Unpickler(f)
- mypickle.find_global = None
d = mypickle.load()
f.close()
del f
- except (IOError, OSError, EOFError, pickle.UnpicklingError), e:
+ except (IOError, OSError, EOFError, ValueError, pickle.UnpicklingError), e:
if isinstance(e, pickle.UnpicklingError):
writemsg("!!! Error loading '%s': %s\n" % \
(filename, str(e)), noiselevel=-1)
# import pdb;pdb.set_trace()
s = cpv.rfind("/")
fp = os.path.join(self.location,cpv[:s],".update.%i.%s" % (os.getpid(), cpv[s+1:]))
- try: myf=open(fp, "w")
+ try:
+ myf = open(fp, 'w')
except (IOError, OSError), e:
if errno.ENOENT == e.errno:
try:
#update written. now we move it.
new_fp = os.path.join(self.location,cpv)
- try: os.rename(fp, new_fp)
+ try:
+ os.rename(fp, new_fp)
except (OSError, IOError), e:
os.remove(fp)
raise cache_errors.CacheCorruption(cpv, e)
if other is None:
pass
elif hasattr(other, 'iteritems'):
- for k, v in other.iteritems():
+ # Use getattr to avoid interference from 2to3.
+ for k, v in getattr(other, 'iteritems')():
+ self[k] = v
+ elif hasattr(other, 'items'):
+ # Use getattr to avoid interference from 2to3.
+ for k, v in getattr(other, 'items')():
self[k] = v
elif hasattr(other, 'keys'):
for k in other.keys():
self[key] = default
return default
- def update(self, d):
- i = getattr(d, "iteritems", None)
- if i is None:
- i = d
+ def update(self, other=None, **kwargs):
+ if other is None:
+ pass
+ elif hasattr(other, 'iteritems'):
+ # Use getattr to avoid interference from 2to3.
+ for k, v in getattr(other, 'iteritems')():
+ self[k] = v
+ elif hasattr(other, 'items'):
+ # Use getattr to avoid interference from 2to3.
+ for k, v in getattr(other, 'items')():
+ self[k] = v
+ elif hasattr(other, 'keys'):
+ for k in other.keys():
+ self[k] = other[k]
else:
- i = i()
- for k, v in i:
- self[k] = v
+ for k, v in other:
+ self[k] = v
+ if kwargs:
+ self.update(kwargs)
def __getitem__(self, k):
try:
def load(self):
""" Reload the registry data from file """
try:
- self._data = pickle.load(open(self._filename, "r"))
+ self._data = pickle.load(open(self._filename, 'rb'))
except (EOFError, IOError), e:
if isinstance(e, EOFError) or e.errno == errno.ENOENT:
self._data = {}
self._data == self._data_orig:
return
try:
- f = atomic_ofstream(self._filename)
+ f = atomic_ofstream(self._filename, 'wb')
pickle.dump(self._data, f)
f.close()
except EnvironmentError, e:
counter, = self.aux_get(cpv, aux_keys)
except KeyError:
continue
- h.update(counter)
+ h.update(counter.encode())
return h.hexdigest()
def cpv_inject(self, mycpv):
del self._aux_cache["packages"][cpv]
del self._aux_cache["modified"]
try:
- f = atomic_ofstream(self._aux_cache_filename)
+ f = atomic_ofstream(self._aux_cache_filename, 'wb')
pickle.dump(self._aux_cache, f, -1)
f.close()
apply_secpass_permissions(
def _aux_cache_init(self):
aux_cache = None
try:
- f = open(self._aux_cache_filename)
+ f = open(self._aux_cache_filename, 'rb')
mypickle = pickle.Unpickler(f)
- mypickle.find_global = None
aux_cache = mypickle.load()
f.close()
del f
- except (IOError, OSError, EOFError, pickle.UnpicklingError), e:
+ except (IOError, OSError, EOFError, ValueError, pickle.UnpicklingError), e:
if isinstance(e, pickle.UnpicklingError):
writemsg("!!! Error loading '%s': %s\n" % \
(self._aux_cache_filename, str(e)), noiselevel=-1)
def _hash_str(self, s):
h = self._new_hash()
- h.update(s)
+ h.update(s.encode())
h = h.hexdigest()
h = h[-self._hex_chars:]
h = int(h, 16)
logentries[msgfunction] = []
lastmsgtype = None
msgcontent = []
- for l in open(filename, "rb"):
+ for l in open(filename):
if not l:
continue
try:
# once, which may be expensive due to digging in child classes.
func = self.lineParser
for fn in RecursiveFileLoader(self.fname):
- f = open(fn, 'rb')
+ f = open(fn)
for line_num, line in enumerate(f):
func(line, line_num, data, errors)
return (data, errors)
else:
keepconnection = 1
- cache_path = "/var/cache/edb"
+ cache_path = CACHE_PATH
+ metadatafilename = os.path.join(cache_path, 'remote_metadata.pickle')
if makepickle is None:
makepickle = CACHE_PATH+"/metadata.idx.most_recent"
out = sys.stdout
try:
- metadatafile = open(CACHE_PATH+"/remote_metadata.pickle")
+ metadatafile = open(metadatafilename, 'rb')
metadata = pickle.load(metadatafile)
out.write("Loaded metadata pickle.\n")
out.flush()
metadatafile.close()
- except (pickle.UnpicklingError, OSError, IOError, EOFError):
+ except (IOError, OSError, EOFError, ValueError, pickle.UnpicklingError):
metadata = {}
if baseurl not in metadata:
metadata[baseurl]={}
sys.stderr.write("!!! "+str(e)+"\n")
sys.stderr.flush()
try:
- metadatafile = open(CACHE_PATH+"/remote_metadata.pickle", "w+")
+ metadatafile = open(metadatafilename, 'wb')
pickle.dump(metadata,metadatafile)
metadatafile.close()
except SystemExit, e:
try:
if "modified" in metadata[baseurl] and metadata[baseurl]["modified"]:
metadata[baseurl]["timestamp"] = int(time.time())
- metadatafile = open(CACHE_PATH+"/remote_metadata.pickle", "w+")
+ metadatafile = open(metadatafilename, 'wb')
pickle.dump(metadata,metadatafile)
metadatafile.close()
if makepickle:
- metadatafile = open(makepickle, "w")
+ metadatafile = open(makepickle, 'wb')
pickle.dump(metadata[baseurl]["data"],metadatafile)
metadatafile.close()
except SystemExit, e:
return 0
return 1
+class ObjectProxy(object):
+
+ """
+ Object that acts as a proxy to another object, forwarding
+ attribute accesses and method calls. This can be useful
+ for implementing lazy initialization.
+ """
+
+ def _get_target(self):
+ raise NotImplementedError(self)
+
+ def __getattribute__(self, attr):
+ result = object.__getattribute__(self, '_get_target')()
+ return getattr(result, attr)
+
+ def __setattr__(self, attr, value):
+ result = object.__getattribute__(self, '_get_target')()
+ setattr(result, attr, value)
+
+ def __call__(self, *args, **kwargs):
+ result = object.__getattribute__(self, '_get_target')()
+ return result(*args, **kwargs)
+
+ def __setitem__(self, key, value):
+ object.__getattribute__(self, '_get_target')()[key] = value
+
+ def __getitem__(self, key):
+ return object.__getattribute__(self, '_get_target')()[key]
+
+ def __delitem__(self, key):
+ del object.__getattribute__(self, '_get_target')()[key]
+
+ def __contains__(self, key):
+ return key in object.__getattribute__(self, '_get_target')()
+
+ def __iter__(self):
+ return iter(object.__getattribute__(self, '_get_target')())
+
+ def __len__(self):
+ return len(object.__getattribute__(self, '_get_target')())
+
+ def __repr__(self):
+ return repr(object.__getattribute__(self, '_get_target')())
+
+ def __str__(self):
+ return str(object.__getattribute__(self, '_get_target')())
+
+ def __hash__(self):
+ return hash(object.__getattribute__(self, '_get_target')())
+
+ def __eq__(self, other):
+ return object.__getattribute__(self, '_get_target')() == other
+
+ def __ne__(self, other):
+ return object.__getattribute__(self, '_get_target')() != other
+
+ def __nonzero__(self):
+ return bool(object.__getattribute__(self, '_get_target')())
+
class _tolerant_shlex(shlex.shlex):
def sourcehook(self, newfile):
try:
(self.infile, str(e)), noiselevel=-1)
return (newfile, StringIO.StringIO())
-class _insert_newline_eof(file):
+class _insert_newline_eof(ObjectProxy):
"""
Read functions insert anywhere from 0 and 2 newlines just before eof.
This is useful as a workaround for avoiding a silent error in shlex that
trailing newline after the source statement.
"""
+ def __init__(self, *pargs, **kargs):
+ ObjectProxy.__init__(self)
+ object.__setattr__(self, '_file', open(*pargs, **kargs))
+
+ def _get_target(self):
+ return object.__getattribute__(self, '_file')
+
+ def __getattribute__(self, attr):
+ if attr in ('read', 'readline', 'readlines'):
+ return object.__getattribute__(self, attr)
+ return getattr(object.__getattribute__(self, '_file'), attr)
+
def read(self, *args):
- if hasattr(self, "_got_eof"):
+ try:
+ object.__getattribute__(self, '_got_eof')
return ""
- rval = file.read(self, *args)
+ except AttributeError:
+ pass
+ rval = object.__getattribute__(self, '_file').read(*args)
if rval and not args and rval[-1:] != "\n":
rval += "\n"
if not rval:
- self._got_eof = True
+ object.__setattr__(self, '_got_eof', True)
return "\n"
return rval
def readline(self, *args):
- if hasattr(self, "_got_eof"):
+ try:
+ object.__getattribute__(self, '_got_eof')
return ""
- rval = file.readline(self, *args)
+ except AttributeError:
+ pass
+ rval = object.__getattribute__(self, '_file').readline(*args)
if rval and rval[-1:] != "\n":
rval += "\n"
if not rval:
- self._got_eof = True
+ object.__setattr__(self, '_got_eof', True)
rval = "\n"
return rval
def readlines(self, *args):
- if hasattr(self, "_got_eof"):
+ try:
+ object.__getattribute__(self, '_got_eof')
return []
- lines = file.readlines(self, *args)
+ except AttributeError:
+ pass
+ lines = object.__getattribute__(self, '_file').readlines(*args)
if lines and lines[-1][-1:] != "\n":
lines[-1] += "\n"
return lines
expand_map = {}
mykeys = {}
try:
- f = _insert_newline_eof(mycfg, 'rb')
+ f = _insert_newline_eof(mycfg)
except IOError, e:
if e.errno == PermissionDenied.errno:
raise PermissionDenied(mycfg)
# only joins relative paths when the infile
# attribute is properly set.
lex = shlex_class(f, infile=mycfg, posix=True)
- lex.wordchars=string.digits+string.letters+"~!@#$%*_\:;?,./-+{}"
+ lex.wordchars += "~!@#$%*_\:;?,./-+{}"
lex.quotes="\"'"
if allow_sourcing:
lex.source="source"
return default
data = None
try:
- myf = open(filename)
+ myf = open(filename, 'rb')
mypickle = pickle.Unpickler(myf)
- mypickle.find_global = None
data = mypickle.load()
myf.close()
del mypickle,myf
stat_cached=stat_cached, follow_links=follow_links)
return all_applied
-class atomic_ofstream(file):
+class atomic_ofstream(ObjectProxy):
"""Write a file atomically via os.rename(). Atomic replacement prevents
interprocess interference and prevents corruption of the target
file when the write is interrupted (for example, when an 'out of space'
def __init__(self, filename, mode='w', follow_links=True, **kargs):
"""Opens a temporary filename.pid in the same directory as filename."""
- self._aborted = False
+ ObjectProxy.__init__(self)
+ object.__setattr__(self, '_aborted', False)
if follow_links:
canonical_path = os.path.realpath(filename)
- self._real_name = canonical_path
+ object.__setattr__(self, '_real_name', canonical_path)
tmp_name = "%s.%i" % (canonical_path, os.getpid())
try:
- super(atomic_ofstream, self).__init__(tmp_name, mode=mode, **kargs)
+ object.__setattr__(self, '_file',
+ open(tmp_name, mode=mode, **kargs))
return
- except (OSError, IOError), e:
+ except IOError, e:
if canonical_path == filename:
raise
writemsg("!!! Failed to open file: '%s'\n" % tmp_name,
noiselevel=-1)
writemsg("!!! %s\n" % str(e), noiselevel=-1)
- self._real_name = filename
+ object.__setattr__(self, '_real_name', filename)
tmp_name = "%s.%i" % (filename, os.getpid())
- super(atomic_ofstream, self).__init__(tmp_name, mode=mode, **kargs)
+ object.__setattr__(self, '_file', open(tmp_name, mode=mode, **kargs))
+
+ def _get_target(self):
+ return object.__getattribute__(self, '_file')
+
+ def __getattribute__(self, attr):
+ if attr in ('close', 'abort', '__del__'):
+ return object.__getattribute__(self, attr)
+ return getattr(object.__getattribute__(self, '_file'), attr)
def close(self):
"""Closes the temporary file, copies permissions (if possible),
and performs the atomic replacement via os.rename(). If the abort()
method has been called, then the temp file is closed and removed."""
- if not self.closed:
+ f = object.__getattribute__(self, '_file')
+ real_name = object.__getattribute__(self, '_real_name')
+ if not f.closed:
try:
- super(atomic_ofstream, self).close()
- if not self._aborted:
+ f.close()
+ if not object.__getattribute__(self, '_aborted'):
try:
- apply_stat_permissions(self.name, os.stat(self._real_name))
+ apply_stat_permissions(f.name, os.stat(real_name))
except OperationNotPermitted:
pass
except FileNotFound:
pass
else:
raise
- os.rename(self.name, self._real_name)
+ os.rename(f.name, real_name)
finally:
# Make sure we cleanup the temp file
# even if an exception is raised.
try:
- os.unlink(self.name)
+ os.unlink(f.name)
except OSError, oe:
pass
"""If an error occurs while writing the file, the user should
call this method in order to leave the target file unchanged.
This will call close() automatically."""
- if not self._aborted:
- self._aborted = True
+ if not object.__getattribute__(self, '_aborted'):
+ object.__setattr__(self, '_aborted', True)
self.close()
def __del__(self):
"""If the user does not explicitely call close(), it is
assumed that an error has occurred, so we abort()."""
- if not self.closed:
+ f = object.__getattribute__(self, '_file')
+ if not f.closed:
self.abort()
# ensure destructor from the base class is called
- base_destructor = getattr(super(atomic_ofstream, self), '__del__', None)
+ base_destructor = getattr(ObjectProxy, '__del__', None)
if base_destructor is not None:
- base_destructor()
+ base_destructor(self)
def write_atomic(file_path, content):
f = None
perms_modified = apply_permissions(dir_path, *args, **kwargs)
return created_dir or perms_modified
-class ObjectProxy(object):
-
- """
- Object that acts as a proxy to another object, forwarding
- attribute accesses and method calls. This can be useful
- for implementing lazy initialization.
- """
-
- def _get_target(self):
- raise NotImplementedError(self)
-
- def __getattribute__(self, attr):
- result = object.__getattribute__(self, '_get_target')()
- return getattr(result, attr)
-
- def __setattr__(self, attr, value):
- result = object.__getattribute__(self, '_get_target')()
- setattr(result, attr, value)
-
- def __call__(self, *args, **kwargs):
- result = object.__getattribute__(self, '_get_target')()
- return result(*args, **kwargs)
-
- def __setitem__(self, key, value):
- object.__getattribute__(self, '_get_target')()[key] = value
-
- def __getitem__(self, key):
- return object.__getattribute__(self, '_get_target')()[key]
-
- def __delitem__(self, key):
- del object.__getattribute__(self, '_get_target')()[key]
-
- def __contains__(self, key):
- return key in object.__getattribute__(self, '_get_target')()
-
- def __iter__(self):
- return iter(object.__getattribute__(self, '_get_target')())
-
- def __len__(self):
- return len(object.__getattribute__(self, '_get_target')())
-
- def __repr__(self):
- return repr(object.__getattribute__(self, '_get_target')())
-
- def __str__(self):
- return str(object.__getattribute__(self, '_get_target')())
-
- def __hash__(self):
- return hash(object.__getattribute__(self, '_get_target')())
-
- def __eq__(self, other):
- return object.__getattribute__(self, '_get_target')() == other
-
- def __ne__(self, other):
- return object.__getattribute__(self, '_get_target')() != other
-
- def __nonzero__(self):
- return bool(object.__getattribute__(self, '_get_target')())
-
class LazyItemsDict(dict):
"""A mapping object that behaves like a standard dict except that it allows
for lazy initialization of values via callable objects. Lazy items can be