rm "$PORTAGE_BUILDDIR/.ebuild_changed"
fi
- # This next line is not the same as export RDEPEND=${RDEPEND:-${DEPEND}}
- # That will test for unset *or* NULL (""). We want just to set for unset...
- # turn off glob expansion from here on in to prevent *'s and ? in the
- # DEPEND syntax from getting expanded :)
- set -f
- if [ "${RDEPEND-unset}" == "unset" ] ; then
- export RDEPEND=${DEPEND}
+ [[ -n $EAPI ]] || EAPI=0
+
+ if has "$EAPI" 0 1 2 ; then
+ export RDEPEND=${RDEPEND-${DEPEND}}
debug-print "RDEPEND: not set... Setting to: ${DEPEND}"
fi
PDEPEND="${PDEPEND} ${E_PDEPEND}"
unset ECLASS E_IUSE E_DEPEND E_RDEPEND E_PDEPEND
- set +f
-
- [[ -n $EAPI ]] || EAPI=0
# alphabetically ordered by $EBUILD_PHASE value
local f valid_phases
\fB\-\-search\fR \fIsomestring\fR
.TP
.BR emerge
-\fB\-\-help\fR [\fB\-\-sync\fR]
+\fB\-\-help\fR [\fB\-\-verbose\fR]
.SH "DESCRIPTION"
\fBemerge\fR is the definitive command\-line interface to the Portage
system. It is primarily used for installing packages, and \fBemerge\fR
to the \fBworld\fR file at the end, so that they are considered for
later updating.
.TP
-.BR "\-\-avoid\-update "
-Tries to prevent package updates. This may not always be
-possible since new packages or new dependencies due to USE
-flag changes may require a newer version of an installed
-package. Furthermore, this option may lead to slot conflicts
-(Multiple package instances within a single package slot
-have been pulled into the dependency graph). It is not
-possible to use this option in such a case.
-.TP
.BR "\-\-clean " (\fB\-c\fR)
Cleans up the system by examining the installed packages and removing older
packages. This is accomplished by looking at each installed package and separating
USE flags may be toggled by your profile as well as your USE and package.use
settings.
-
-\fB\-\-avoid\-update\fR may prevent updates of installed packages without
-use flag changes. Note that \fB\-\-avoid-\update\fR may lead to slot conflicts.
.TP
.BR "\-\-noconfmem"
Causes portage to disregard merge records indicating that a config file
# Distributed under the terms of the GNU General Public License v2
# $Id$
+import copy
from _emerge.SlotObject import SlotObject
+
class AbstractDepPriority(SlotObject):
__slots__ = ("buildtime", "runtime", "runtime_post")
return self.__int__() >= other
def copy(self):
- import copy
return copy.copy(self)
-
from _emerge.countdown import countdown
from _emerge.create_depgraph_params import create_depgraph_params
from _emerge.Dependency import Dependency
-from _emerge.depgraph import depgraph, resume_depgraph
+from _emerge.depgraph import depgraph, resume_depgraph, _frozen_depgraph_config
from _emerge.DepPrioritySatisfiedRange import DepPrioritySatisfiedRange
from _emerge.emergelog import emergelog
from _emerge.is_valid_package_atom import is_valid_package_atom
print darkgreen("emerge: It seems we have nothing to resume...")
return os.EX_OK
- myparams = create_depgraph_params(myopts, myaction)
if "--quiet" not in myopts and "--nodeps" not in myopts:
print "Calculating dependencies ",
sys.stdout.flush()
- mydepgraph = depgraph(settings, trees, myopts, myparams, spinner)
- try:
- retval, favorites = mydepgraph.select_files(myfiles)
- except portage.exception.PackageNotFound, e:
- portage.writemsg("\n!!! %s\n" % str(e), noiselevel=-1)
- return 1
- except portage.exception.PackageSetNotFound, e:
- root_config = trees[settings["ROOT"]]["root_config"]
- display_missing_pkg_set(root_config, e.value)
- return 1
+
+ runtime_pkg_mask = None
+ allow_backtracking = True
+ backtracked = False
+ frozen_config = _frozen_depgraph_config(settings, trees,
+ myopts, spinner)
+ myparams = create_depgraph_params(myopts, myaction)
+ while True:
+ mydepgraph = depgraph(settings, trees, myopts, myparams, spinner,
+ frozen_config=frozen_config,
+ allow_backtracking=allow_backtracking,
+ runtime_pkg_mask=runtime_pkg_mask)
+ try:
+ retval, favorites = mydepgraph.select_files(myfiles)
+ except portage.exception.PackageNotFound, e:
+ portage.writemsg("\n!!! %s\n" % str(e), noiselevel=-1)
+ return 1
+ except portage.exception.PackageSetNotFound, e:
+ root_config = trees[settings["ROOT"]]["root_config"]
+ display_missing_pkg_set(root_config, e.value)
+ return 1
+ if not retval:
+ if mydepgraph.need_restart():
+ runtime_pkg_mask = mydepgraph.get_runtime_pkg_mask()
+ backtracked = True
+ elif backtracked and allow_backtracking:
+ # Backtracking failed, so disable it and do
+ # a plain dep calculation + error message.
+ allow_backtracking = False
+ runtime_pkg_mask = None
+ else:
+ if show_spinner:
+ print "\b\b... done!"
+ mydepgraph.display_problems()
+ return 1
+ else:
+ break
+
+ del frozen_config, runtime_pkg_mask
+
if show_spinner:
print "\b\b... done!"
- if not retval:
- mydepgraph.display_problems()
- return 1
if "--pretend" not in myopts and \
("--ask" in myopts or "--tree" in myopts or \
class _dynamic_depgraph_config(object):
- def __init__(self, depgraph, myparams):
- self.myparams = myparams
+ def __init__(self, depgraph, myparams, allow_backtracking,
+ runtime_pkg_mask):
+ self.myparams = myparams.copy()
+ self._allow_backtracking = allow_backtracking
# Maps slot atom to package for each Package added to the graph.
self._slot_pkg_map = {}
# Maps nodes to the reasons they were selected for reinstallation.
self._initially_unsatisfied_deps = []
self._ignored_deps = []
self._highest_pkg_cache = {}
+ if runtime_pkg_mask is None:
+ runtime_pkg_mask = {}
+ else:
+ runtime_pkg_mask = dict((k, v.copy()) for (k, v) in \
+ runtime_pkg_mask.iteritems())
+ self._runtime_pkg_mask = runtime_pkg_mask
+ self._need_restart = False
for myroot in depgraph._frozen_config.trees:
self._slot_pkg_map[myroot] = {}
_dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
def __init__(self, settings, trees, myopts, myparams, spinner,
- frozen_config=None):
+ frozen_config=None, runtime_pkg_mask=None, allow_backtracking=False):
if frozen_config is None:
frozen_config = _frozen_depgraph_config(settings, trees,
myopts, spinner)
self._frozen_config = frozen_config
- self._dynamic_config = _dynamic_depgraph_config(self, myparams)
+ self._dynamic_config = _dynamic_depgraph_config(self, myparams,
+ allow_backtracking, runtime_pkg_mask)
self._select_atoms = self._select_atoms_highest_available
self._select_package = self._select_pkg_highest_available
+ def _show_missed_update(self):
+
+ if '--quiet' in self._frozen_config.myopts and \
+ '--debug' not in self._frozen_config.myopts:
+ return
+
+ missed_updates = {}
+ for pkg, mask_reasons in \
+ self._dynamic_config._runtime_pkg_mask.iteritems():
+ if mask_reasons.get("slot conflict"):
+ if pkg.slot_atom in missed_updates:
+ other_pkg, parent_atoms = missed_updates[pkg.slot_atom]
+ if other_pkg > pkg:
+ continue
+ missed_updates[pkg.slot_atom] = \
+ (pkg, mask_reasons["slot conflict"])
+
+ if not missed_updates:
+ return
+
+ msg = []
+ msg.append("\n!!! One or more updates have been skipped due to " + \
+ "a dependency conflict:\n\n")
+
+ indent = " "
+ for pkg, parent_atoms in missed_updates.itervalues():
+ msg.append(str(pkg.slot_atom))
+ msg.append("\n\n")
+
+ for parent, atom in parent_atoms:
+ msg.append(indent)
+ msg.append(str(pkg))
+
+ msg.append(" conflicts with\n")
+ for parent, atom in parent_atoms:
+ msg.append(2*indent)
+ if isinstance(parent,
+ (PackageArg, AtomArg)):
+ # For PackageArg and AtomArg types, it's
+ # redundant to display the atom attribute.
+ msg.append(str(parent))
+ else:
+ # Display the specific atom from SetArg or
+ # Package types.
+ msg.append("%s required by %s" % (atom, parent))
+ msg.append("\n")
+ msg.append("\n")
+ sys.stderr.write("".join(msg))
+ sys.stderr.flush()
+
def _show_slot_collision_notice(self):
"""Show an informational message advising the user to mask one of the
the packages. In some cases it may be possible to resolve this
(dep.parent, dep.atom))
return 1
else:
+ # A slot conflict has occurred.
+ if self._dynamic_config._allow_backtracking and \
+ not self._accept_blocker_conflicts():
+ self._add_slot_conflict(pkg)
+ if dep.atom is not None and dep.parent is not None:
+ self._add_parent_atom(pkg, (dep.parent, dep.atom))
+ if arg_atoms:
+ for parent_atom in arg_atoms:
+ parent, atom = parent_atom
+ self._add_parent_atom(pkg, parent_atom)
+ self._process_slot_conflicts()
+
+ parent_atoms = \
+ self._dynamic_config._parent_atoms.get(pkg, set())
+ if parent_atoms:
+ parent_atoms = self._dynamic_config._slot_conflict_parent_atoms.intersection(parent_atoms)
+ if pkg >= existing_node:
+ # We only care about the parent atoms
+ # when they trigger a downgrade.
+ parent_atoms = set()
+
+ self._dynamic_config._runtime_pkg_mask.setdefault(
+ existing_node, {})["slot conflict"] = parent_atoms
+ self._dynamic_config._need_restart = True
+ return 0
# A slot collision has occurred. Sometimes this coincides
# with unresolvable blockers, so the slot collision will be
if isinstance(arg, PackageArg):
if not self._add_pkg(arg.package, dep) or \
not self._create_graph():
- sys.stderr.write(("\n\n!!! Problem resolving " + \
- "dependencies for %s\n") % arg.arg)
+ if not self._dynamic_config._need_restart:
+ sys.stderr.write(("\n\n!!! Problem " + \
+ "resolving dependencies for %s\n") % \
+ arg.arg)
return 0, myfavorites
continue
if debug:
# so that later dep_check() calls can use it as feedback
# for making more consistent atom selections.
if not self._add_pkg(pkg, dep):
- if isinstance(arg, SetArg):
+ if self._dynamic_config._need_restart:
+ pass
+ elif isinstance(arg, SetArg):
sys.stderr.write(("\n\n!!! Problem resolving " + \
"dependencies for %s from %s\n") % \
(atom, arg.arg))
selective = "selective" in self._dynamic_config.myparams
reinstall = False
noreplace = "--noreplace" in self._frozen_config.myopts
- avoid_update = "--avoid-update" in self._frozen_config.myopts
+ avoid_update = "--update" not in self._frozen_config.myopts
# Behavior of the "selective" parameter depends on
# whether or not a package matches an argument atom.
# If an installed package provides an old-style
for pkg in self._iter_match_pkgs(root_config, pkg_type, atom,
onlydeps=onlydeps):
+ if pkg in self._dynamic_config._runtime_pkg_mask:
+ # The package has been masked by the backtracking logic
+ continue
cpv = pkg.cpv
# Make --noreplace take precedence over --newuse.
if not pkg.installed and noreplace and \
if self._dynamic_config._unsatisfied_blockers_for_display is not None:
self._show_unsatisfied_blockers(
self._dynamic_config._unsatisfied_blockers_for_display)
- else:
+ elif self._dynamic_config._slot_collision_info:
self._show_slot_collision_notice()
+ else:
+ self._show_missed_update()
# TODO: Add generic support for "set problem" handlers so that
# the below warnings aren't special cases for world only.
graph in order to avoid making a potentially unsafe decision.
"""
+ def need_restart(self):
+ return self._dynamic_config._need_restart
+
+ def get_runtime_pkg_mask(self):
+ return self._dynamic_config._runtime_pkg_mask.copy()
+
class _dep_check_composite_db(portage.dbapi):
"""
A dbapi-like interface that is optimized for use in dep_check() calls.
print " "+turquoise("emerge")+" [ "+green("options")+" ] [ "+green("action")+" ] < "+turquoise("system")+" | "+turquoise("world")+" >"
print " "+turquoise("emerge")+" < "+turquoise("--sync")+" | "+turquoise("--metadata")+" | "+turquoise("--info")+" >"
print " "+turquoise("emerge")+" "+turquoise("--resume")+" [ "+green("--pretend")+" | "+green("--ask")+" | "+green("--skipfirst")+" ]"
- print " "+turquoise("emerge")+" "+turquoise("--help")+" [ "+green("system")+" | "+green("world")+" | "+green("--sync")+" ] "
+ print " "+turquoise("emerge")+" "+turquoise("--help")+" [ "+green("--verbose")+" ] "
print bold("Options:")+" "+green("-")+"["+green("abBcCdDefgGhjkKlnNoOpqPsStuvV")+"]"
print " [ " + green("--color")+" < " + turquoise("y") + " | "+ turquoise("n")+" > ] [ "+green("--columns")+" ]"
print " [ "+green("--complete-graph")+" ] [ "+green("--deep")+" ]"
print " [ "+green("--reinstall ")+turquoise("changed-use")+" ] [ " + green("--with-bdeps")+" < " + turquoise("y") + " | "+ turquoise("n")+" > ]"
print bold("Actions:")+" [ "+green("--depclean")+" | "+green("--list-sets")+" | "+green("--search")+" | "+green("--sync")+" | "+green("--version")+" ]"
-def help(myaction,myopts,havecolor=1):
+def help(myopts, havecolor=1):
# TODO: Implement a wrap() that accounts for console color escape codes.
from textwrap import wrap
desc_left_margin = 14
desc_indent = desc_left_margin * " "
desc_width = 80 - desc_left_margin - 5
- if not myaction and ("--verbose" not in myopts):
+ if "--verbose" not in myopts:
shorthelp()
print
print " For more help try 'emerge --help --verbose' or consult the man page."
- elif not myaction:
+ else:
shorthelp()
print
print turquoise("Help (this screen):")
print " emerge -S applet"
print " emerge -S 'perl.*module'"
print
+ print " "+green("--sync")
+ print " Tells emerge to update the Portage tree as specified in"
+ print " The SYNC variable found in /etc/make.conf. By default, SYNC instructs"
+ print " emerge to perform an rsync-style update with rsync.gentoo.org."
+ print
+ print " 'emerge-webrsync' exists as a helper app to emerge --sync, providing a"
+ print " method to receive the entire portage tree as a tarball that can be"
+ print " extracted and used. First time syncs would benefit greatly from this."
+ print
+ print " "+turquoise("WARNING:")
+ print " If using our rsync server, emerge will clean out all files that do not"
+ print " exist on it, including ones that you may have created. The exceptions"
+ print " to this are the distfiles, local and packages directories."
+ print
print " "+green("--unmerge")+" ("+green("-C")+" short option)"
print " "+turquoise("WARNING: This action can remove important packages!")
print " Removes all matching packages. This does no checking of"
print " to the prompt, so an accidental press of the \"Enter\" key at any"
print " time prior to the prompt will be interpreted as a choice!"
print
- print " "+green("--avoid-update")
- desc = "Tries to prevent package updates. This may not always be" + \
- " possible since new packages or new dependencies due to USE" + \
- " flag changes may require a newer version of an installed" + \
- " package. Furthermore, this option may lead to slot conflicts" + \
- " (Multiple package instances within a single package slot" + \
- " have been pulled into the dependency graph). It is not" + \
- " possible to use this option in such a case."
- for line in wrap(desc, desc_width):
- print desc_indent + line
- print
print " "+green("--buildpkg")+" ("+green("-b")+" short option)"
desc = "Tells emerge to build binary packages for all ebuilds processed in" + \
" addition to actually merging the packages. Useful for maintainers" + \
print " added to EMERGE_DEFAULT_OPTS (see make.conf(5)) and later"
print " overridden via the command line."
print
- elif myaction == "sync":
- print
- print bold("Usage: ")+turquoise("emerge")+" "+turquoise("--sync")
- print
- print " 'emerge --sync' tells emerge to update the Portage tree as specified in"
- print " The SYNC variable found in /etc/make.conf. By default, SYNC instructs"
- print " emerge to perform an rsync-style update with rsync.gentoo.org."
- print
- print " 'emerge-webrsync' exists as a helper app to emerge --sync, providing a"
- print " method to receive the entire portage tree as a tarball that can be"
- print " extracted and used. First time syncs would benefit greatly from this."
- print
- print " "+turquoise("WARNING:")
- print " If using our rsync server, emerge will clean out all files that do not"
- print " exist on it, including ones that you may have created. The exceptions"
- print " to this are the distfiles, local and packages directories."
- print
"--emptytree",
"--fetchonly", "--fetch-all-uri",
"--getbinpkg", "--getbinpkgonly",
-"--help", "--ignore-default-opts",
+"--ignore-default-opts",
"--keep-going",
"--noconfmem",
"--newuse",
"--searchdesc", "--selective",
"--skipfirst",
"--tree",
-"--avoid-update",
"--update",
"--usepkg", "--usepkgonly",
"--verbose",
if icount > 0:
out.einfo("Processed %d info files." % (icount,))
-
def display_preserved_libs(vardbapi):
MAX_DISPLAY = 3
print colorize("WARN", " * ") + " used by %d other files" % (len(consumers) - MAX_DISPLAY)
print "Use " + colorize("GOOD", "emerge @preserved-rebuild") + " to rebuild packages using these libraries"
-
def post_emerge(root_config, myopts, mtimedb, retval):
"""
Misc. things to run at the end of a merge session.
-
+
Update Info Files
Update Config Files
Update News Items
portage.locks.unlockdir(vdb_lock)
chk_updated_cfg_files(target_root + EPREFIX, config_protect)
-
+
display_news_notification(root_config, myopts)
if retval in (None, os.EX_OK) or (not "--pretend" in myopts):
display_preserved_libs(vardbapi)
sys.exit(retval)
-
def multiple_actions(action1, action2):
sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n")
sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2))
global options, shortmapping
actions = frozenset([
- "clean", "config", "depclean",
+ "clean", "config", "depclean", "help",
"info", "list-sets", "metadata",
"prune", "regen", "search",
"sync", "unmerge", "version",
IS_OPERATOR = "/@"
DIFF_OPERATOR = "-@"
UNION_OPERATOR = "+@"
-
+
for i in range(0, len(myfiles)):
if myfiles[i].startswith(SETPREFIX):
start = 0
if start > 0 and start < end:
namepart = x[:start]
argpart = x[start+1:end]
-
+
# TODO: implement proper quoting
args = argpart.split(",")
options = {}
newset += x
x = ""
myfiles[i] = SETPREFIX+newset
-
+
sets = setconfig.getSets()
# display errors that occured while loading the SetConfig instance
for e in setconfig.errors:
print colorize("BAD", "Error during set creation: %s" % e)
-
+
# emerge relies on the existance of sets with names "world" and "system"
required_sets = ("world", "system")
missing_sets = []
msg += " for '%s'" % root
writemsg_level(msg, level=logging.WARN, noiselevel=-1)
-def profile_check(trees, myaction, myopts):
- if myaction in ("info", "sync"):
- return os.EX_OK
- elif "--version" in myopts or "--help" in myopts:
+def profile_check(trees, myaction):
+ if myaction in ("help", "info", "sync", "version"):
return os.EX_OK
for root, root_trees in trees.iteritems():
if root_trees["root_config"].settings.profiles:
os.umask(022)
settings, trees, mtimedb = load_emerge_config()
portdb = trees[settings["ROOT"]]["porttree"].dbapi
- rval = profile_check(trees, myaction, myopts)
+ rval = profile_check(trees, myaction)
if rval != os.EX_OK:
return rval
noiselevel=-1)
return 1
- if "--avoid-update" in myopts and "--update" in myopts:
- writemsg("!!! conflicting options given: " + \
- "--update and --avoid-update\n", noiselevel=-1)
- return 1
-
if settings.get("PORTAGE_DEBUG", "") == "1":
spinner.update = spinner.update_quiet
portage.debug=1
settings.profile_path, settings["CHOST"],
trees[settings["ROOT"]]["vartree"].dbapi)
return 0
- elif "--help" in myopts:
- _emerge.help.help(myaction, myopts, portage.output.havecolor)
+ elif myaction == "help":
+ _emerge.help.help(myopts, portage.output.havecolor)
return 0
if "--debug" in myopts:
print "myopts", myopts
if not myaction and not myfiles and "--resume" not in myopts:
- _emerge.help.help(myaction, myopts, portage.output.havecolor)
+ _emerge.help.help(myopts, portage.output.havecolor)
return 1
pretend = "--pretend" in myopts
if k not in internal_columns:
d[k] = result[0][column_index]
- # As a temporary workaround for bug #263081, convert unicode strings
- # to raw byte strings. This avoids potential unicode errors that can
- # be triggered elsewhere when attempting to join unicode strings with
- # raw byte strings. TODO: Convert all string handling code to use
- # unicode strings instead of raw byte strings (required for py3k
- # compatibility).
- for k, v in d.iteritems():
- try:
- d[k] = str(v)
- except UnicodeEncodeError:
- pass
-
return d
def _setitem(self, cpv, values):
'unique_array', 'varexpand', 'write_atomic', 'writedict', 'writemsg',
'writemsg_level', 'writemsg_stdout']
+import codecs
import os
import errno
import logging
import portage.exception
from portage.dep import isvalidatom
from portage.proxy.objectproxy import ObjectProxy
+from portage.cache.mappings import UserDict
from portage.const import EPREFIX, EPREFIX_LSTRIP
try:
os.path.join(myfilename, f), recursive))
else:
try:
- myfile = open(myfilename, "r")
+ myfile = codecs.open(myfilename, mode='r', errors='replace')
mylines = myfile.readlines()
myfile.close()
except IOError, e:
(self.infile, str(e)), noiselevel=-1)
return (newfile, StringIO())
-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
- is triggered by a source statement at the end of the file without a
- 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):
- try:
- object.__getattribute__(self, '_got_eof')
- return ""
- except AttributeError:
- pass
- rval = object.__getattribute__(self, '_file').read(*args)
- if rval and not args and rval[-1:] != "\n":
- rval += "\n"
- if not rval:
- object.__setattr__(self, '_got_eof', True)
- return "\n"
- return rval
-
- def readline(self, *args):
- try:
- object.__getattribute__(self, '_got_eof')
- return ""
- except AttributeError:
- pass
- rval = object.__getattribute__(self, '_file').readline(*args)
- if rval and rval[-1:] != "\n":
- rval += "\n"
- if not rval:
- object.__setattr__(self, '_got_eof', True)
- rval = "\n"
- return rval
-
- def readlines(self, *args):
- try:
- object.__getattribute__(self, '_got_eof')
- return []
- except AttributeError:
- pass
- lines = object.__getattribute__(self, '_file').readlines(*args)
- if lines and lines[-1][-1:] != "\n":
- lines[-1] += "\n"
- return lines
-
def getconfig(mycfg, tolerant=0, allow_sourcing=False, expand=True):
if isinstance(expand, dict):
# Some existing variable definitions have been
expand_map = {}
mykeys = {}
try:
- f = _insert_newline_eof(mycfg)
+ # Workaround for avoiding a silent error in shlex that
+ # is triggered by a source statement at the end of the file without a
+ # trailing newline after the source statement
+ content = codecs.open(mycfg, mode='r', errors='replace').read()
+ if content and content[-1] != u'\n':
+ content += u'\n'
+ f = StringIO(content)
except IOError, e:
if e.errno == PermissionDenied.errno:
raise PermissionDenied(mycfg)
"""Opens a temporary filename.pid in the same directory as filename."""
ObjectProxy.__init__(self)
object.__setattr__(self, '_aborted', False)
+ if 'b' in mode:
+ open_func = open
+ else:
+ open_func = codecs.open
+ kargs.setdefault('errors', 'replace')
if follow_links:
canonical_path = os.path.realpath(filename)
tmp_name = "%s.%i" % (canonical_path, os.getpid())
try:
object.__setattr__(self, '_file',
- open(tmp_name, mode=mode, **kargs))
+ open_func(tmp_name, mode=mode, **kargs))
return
except IOError, e:
if canonical_path == filename:
object.__setattr__(self, '_real_name', filename)
tmp_name = "%s.%i" % (filename, os.getpid())
- object.__setattr__(self, '_file', open(tmp_name, mode=mode, **kargs))
+ object.__setattr__(self, '_file',
+ open_func(tmp_name, mode=mode, **kargs))
def _get_target(self):
return object.__getattribute__(self, '_file')
if base_destructor is not None:
base_destructor(self)
-def write_atomic(file_path, content):
+def write_atomic(file_path, content, **kwargs):
f = None
try:
- f = atomic_ofstream(file_path)
+ f = atomic_ofstream(file_path, **kwargs)
f.write(content)
f.close()
except (IOError, OSError), e:
perms_modified = apply_permissions(dir_path, *args, **kwargs)
return created_dir or perms_modified
-class LazyItemsDict(dict):
+class LazyItemsDict(UserDict):
"""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
overwritten and deleted just as normal items."""
def __init__(self, *args, **kwargs):
- if len(args) > 1:
- raise TypeError(
- "expected at most 1 positional argument, got " + \
- repr(len(args)))
-
- dict.__init__(self)
self.lazy_items = {}
-
- if args:
- self.update(args[0])
-
- if kwargs:
- self.update(kwargs)
+ UserDict.__init__(self, *args, **kwargs)
def addLazyItem(self, item_key, value_callable, *pargs, **kwargs):
"""Add a lazy item for the given key. When the item is requested,
self.lazy_items[item_key] = \
self._LazyItem(value_callable, pargs, kwargs, False)
# make it show up in self.keys(), etc...
- dict.__setitem__(self, item_key, None)
+ UserDict.__setitem__(self, item_key, None)
def addLazySingleton(self, item_key, value_callable, *pargs, **kwargs):
"""This is like addLazyItem except value_callable will only be called
self.lazy_items[item_key] = \
self._LazyItem(value_callable, pargs, kwargs, True)
# make it show up in self.keys(), etc...
- dict.__setitem__(self, item_key, None)
+ UserDict.__setitem__(self, item_key, None)
def update(self, *args, **kwargs):
if len(args) > 1:
elif isinstance(map_obj, LazyItemsDict):
for k in map_obj:
if k in map_obj.lazy_items:
- dict.__setitem__(self, k, None)
+ UserDict.__setitem__(self, k, None)
else:
- dict.__setitem__(self, k, map_obj[k])
+ UserDict.__setitem__(self, k, map_obj[k])
self.lazy_items.update(map_obj.lazy_items)
else:
- dict.update(self, map_obj)
+ UserDict.update(self, map_obj)
if kwargs:
- dict.update(self, kwargs)
+ UserDict.update(self, kwargs)
def __getitem__(self, item_key):
if item_key in self.lazy_items:
return result
else:
- return dict.__getitem__(self, item_key)
+ return UserDict.__getitem__(self, item_key)
def __setitem__(self, item_key, value):
if item_key in self.lazy_items:
del self.lazy_items[item_key]
- dict.__setitem__(self, item_key, value)
+ UserDict.__setitem__(self, item_key, value)
+
def __delitem__(self, item_key):
if item_key in self.lazy_items:
del self.lazy_items[item_key]
- dict.__delitem__(self, item_key)
+ UserDict.__delitem__(self, item_key)
def clear(self):
self.lazy_items.clear()
- dict.clear(self)
+ UserDict.clear(self)
def copy(self):
return self.__copy__()
except TypeError:
if not lazy_item.singleton:
raise
- dict.__setitem__(result, k_copy, deepcopy(self[k], memo))
+ UserDict.__setitem__(result,
+ k_copy, deepcopy(self[k], memo))
else:
- dict.__setitem__(result, k_copy, None)
+ UserDict.__setitem__(result, k_copy, None)
else:
- dict.__setitem__(result, k_copy, deepcopy(self[k], memo))
+ UserDict.__setitem__(result, k_copy, deepcopy(self[k], memo))
return result
class _LazyItem(object):