From: "André Erdmann" <dywi@mailerd.de>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/
Date: Fri, 20 Sep 2013 15:57:23 +0000 (UTC) [thread overview]
Message-ID: <1379688461.b26619285c74e85a7db260834da7cdda3bab0e2d.dywi@gentoo> (raw)
commit: b26619285c74e85a7db260834da7cdda3bab0e2d
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Sep 20 14:47:41 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Sep 20 14:47:41 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=b2661928
roverlay/fsutil: comments, cleanup
Also contains some fixes, e.g. handle "/" properly in walk_up().
---
roverlay/fsutil.py | 668 ++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 565 insertions(+), 103 deletions(-)
diff --git a/roverlay/fsutil.py b/roverlay/fsutil.py
index 7fede96..309aadc 100644
--- a/roverlay/fsutil.py
+++ b/roverlay/fsutil.py
@@ -4,6 +4,7 @@
# Distributed under the terms of the GNU General Public License;
# either version 2 of the License, or (at your option) any later version.
+import abc
import errno
import functools
import itertools
@@ -21,24 +22,54 @@ _OS_CHMOD = getattr ( os, 'lchmod', os.chmod )
def walk_up ( dirpath, topdown=False, max_iter=None ):
- path_elements = os.path.normpath ( dirpath ).split ( os.sep )
+ """Generator that yields all (partial..full) filesystem paths contained
+ in dirpath.
- if path_elements:
- p_start = 0 if path_elements[0] else 1
+ Examples:
+ walk_up (
+ "/a/b/c/d", topdown=False, max_iter=None
+ ) -> ( "/a/b/c/d", "/a/b/c", "/a/b", "/a", "/" )
- if max_iter is None:
- high = len ( path_elements )
- else:
- high = min ( max_iter + p_start, len ( path_elements ) )
+ walk_up ( "/" ) -> ( "/" )
+ walk_up ( "/b", topdown=True ) -> ( "/", "/b" )
- if topdown:
- for k in range ( p_start+1, high+1 ):
- yield os.sep.join ( path_elements[:k] )
- else:
- for k in range ( high, p_start, -1 ):
- yield os.sep.join ( path_elements[:k] )
+ arguments:
+ * topdown -- Defaults to False.
+ * max_iter -- max number of paths to generate (None for unlimited)
+ Defaults to None.
+ """
+ def iter_partial_paths ( _join_path=os.sep.join ):
+ fspath = os.path.normpath ( dirpath ).rstrip ( os.sep )
+ path_elements = fspath.split ( os.sep )
+
+ if path_elements:
+ p_start = 0 if path_elements[0] else 1
+ high = len ( path_elements )
+
+ if topdown:
+ if not path_elements[0]:
+ yield os.sep
+
+ for k in range ( p_start+1, high+1 ):
+ yield _join_path ( path_elements[:k] )
+ else:
+ for k in range ( high, p_start, -1 ):
+ yield _join_path ( path_elements[:k] )
+
+ if not path_elements[0]:
+ yield os.sep
+ # --- end of iter_partial_paths (...) ---
+ if max_iter is None:
+ for path in iter_partial_paths():
+ yield path
+ else:
+ for n, path in enumerate ( iter_partial_paths() ):
+ if n < max_iter:
+ yield path
+ else:
+ return
# --- end of walk_up (...) ---
def get_fs_dict (
@@ -46,7 +77,40 @@ def get_fs_dict (
dirname_filter=None, filename_filter=None,
include_root=False, prune_empty=False, file_key=None,
):
- # http://code.activestate.com/recipes/577879-create-a-nested-dictionary-from-oswalk/
+ """Creates a dictionary-like object representing the filesystem structure
+ starting at the given root directory.
+
+ arguments:
+ * initial_root -- root directory where os.walk should start
+ * create_item -- Either a function that accepts 3 args (absolute file-
+ system path, filename, absolute dirpath) and returns
+ an object representing a file entry or None (resulting
+ in None being the object). Defaults to None.
+ * dict_cls -- dictionary class. Defaults to dict.
+ Has to have a constructor accepting an iterable
+ of 2-tuples (key,file entry or dict_cls object)
+ if create_item is set, or a .fromkeys() method
+ accepting an iterable of keys.
+ Additionally, has to provide a __setitem__ method.
+ * dirname_filter -- Either a function that returns True if a directory
+ name is allowed and False if not, or None (do not
+ restrict dirnames). Defaults to None.
+ This also affects which directory paths are traversed.
+ * filename_filter -- Similar to dirname_filter, but can be used to ignore
+ files. Defaults to None.
+ * include_root -- Whether to make initial_root the dict root (False)
+ or an item in the dict (True). In other words,
+ controls whether the return value should be a dict
+ starting at initial_root or a dict containing the
+ initial_root dict. Defaults to False.
+ * prune_empty -- Whether to remove directory entries without any items.
+ Defaults to False.
+ * file_key -- Either a function that returns the dict key for a
+ file name or None (idendity, key==filename).
+
+ Inspired by http://code.activestate.com/recipes/577879-create-a-nested-dictionary-from-oswalk/
+ """
+ # TODO(could-do): max_depth=N
fsdict = dict_cls()
my_root = os.path.abspath ( initial_root )
@@ -88,15 +152,38 @@ def get_fs_dict (
# --- end of get_fs_dict (...) ---
def create_subdir_check ( parent, fs_sep=os.sep ):
+ """Returns a function that checks whether a given filesystem path is a
+ subpath of parent (where parent is a subpath of itself).
+
+ arguments:
+ * parent -- parent filesystem path for which a subdir_check should be
+ created
+ * fs_sep -- defaults to os.sep
+ """
PARENT_PATH = parent.rstrip ( fs_sep ).split ( fs_sep )
- def is_subdir ( dirpath ):
- return all (
- this == expect for this, expect in zip (
- dirpath.rstrip ( fs_sep ).split ( fs_sep ),
- PARENT_PATH
+ def is_subdir ( dirpath,
+ _path_el=PARENT_PATH, _path_len=len( PARENT_PATH ), _fs_sep=fs_sep
+ ):
+ """Returns True if the given filesystem path is a subpath of the
+ (predefined) parent path, else False.
+
+ arguments:
+ * dirpath -- filesystem path to be checked
+ * _path_el -- local variable containing information about the parent
+ path. Shouldn't be set manually.
+ * _path_len -- local variable containing information about the length
+ of the parent path. Shouldn't be set manually.
+ * _fs_sep -- local variable that is a copy of fs_sep.
+ Shouldn't be set manually.
+ """
+ dirpath_el = dirpath.rstrip ( _fs_sep ).split ( _fs_sep )
+ if len ( dirpath_el ) < _path_len:
+ return False
+ else:
+ return all (
+ this == expect for this, expect in zip ( dirpath_el, _path_el )
)
- )
# --- end of is_subdir (...) ---
return is_subdir
@@ -104,6 +191,15 @@ def create_subdir_check ( parent, fs_sep=os.sep ):
def pwd_expanduser ( fspath, uid ):
+ """Expands "~" in a filesystem path to the given user's home directory.
+ Uses pwd to get that directory.
+
+ Returns: expanded path
+
+ arguments:
+ * fspath --
+ * uid --
+ """
if not fspath or fspath[0] != '~':
return fspath
elif len ( fspath ) < 2:
@@ -115,6 +211,32 @@ def pwd_expanduser ( fspath, uid ):
# --- end of pwd_expanduser (...) ---
def walk_copy_tree ( source, dest, subdir_root=False, **walk_kwargs ):
+ """Generator that iterates over the content of a filesystem tree starting
+ at source and compares it to the filesystem tree starting at dest (which
+ doesn't have to exist). The subdir_root can be used to control whether
+ source should be a subdir of dest or not (which means that
+ walk_copy_tree (source, dest, subdir_root=True) is identical to
+ walk_copy_tree (source, dest + os.sep + os.path.basename(source),
+ subdir_root=False)).
+
+ The items are 6-tuples (absolute path to the source directory,
+ absolute path to the dest dir, dir path relative to the source root,
+ list of directories, list of files, list of dirnames).
+
+ The dirnames list can be modified (slice assignment) in order to affect
+ the directories visited by os.walk().
+
+ The directories/files lists are lists of 2x2-tuples (
+ (abspath in source, stat in source), (abspath in dest, stat in dest)
+ ).
+
+ arguments:
+ * source -- absolute path to the source root
+ * dest -- absolute path to the dest root
+ * subdir_root -- whether source should be a subdir of dest root or not
+ Defaults to False.
+ * **walk_kwargs -- additional keyword arguments for os.walk()
+ """
source_path = os.path.abspath ( source )
dest_path = os.path.abspath ( dest )
relpath_begin = 1 + (
@@ -139,9 +261,21 @@ def walk_copy_tree ( source, dest, subdir_root=False, **walk_kwargs ):
# --- end of walk_copy_tree (...) ---
class RWX ( object ):
+ """An object representing read/write/execute permissions."""
@classmethod
def from_str ( cls, s, strict=False ):
+ """Parses the given string and returns a new RWX object.
+
+ arguments:
+ * s -- a string, e.g. "rwx" or "r-x"
+ * strict -- if True: expect that is a string with length >= 3, where
+ read/write/executable is set to True if the
+ first/second/third char is r/w/x and False
+ otherwise.
+ else : set read/write/executable to True if s contains
+ r/w/x and False otherwise
+ """
readable, writable, executable = False, False, False
if strict:
@@ -166,12 +300,27 @@ class RWX ( object ):
@classmethod
def from_bitmask ( cls, mode, rwx_bits ):
+ """Compares the given mode with a list of r/w/x bits and creates a
+ RWX object for it.
+
+ arguments:
+ * mode -- integer containing r/w/x (and possible other) bits
+ * rwx_bits -- a list/tuple with at least three elements, where the
+ first/second/third element is the read/write/executable bit
+ """
return cls (
mode & rwx_bits[0], mode & rwx_bits[1], mode & rwx_bits[2],
)
# --- end of from_bitmask (...) ---
def __init__ ( self, readable, writable, executable ):
+ """RWX Constructor.
+
+ arguments:
+ * readable -- bool
+ * writable -- bool
+ * executable -- bool
+ """
super ( RWX, self ).__init__()
self.readable = bool ( readable )
self.writable = bool ( writable )
@@ -179,6 +328,7 @@ class RWX ( object ):
# --- end of __init__ (...) ---
def __hash__ ( self ):
+ # could be removed (or replaced by a more proper __hash__ func)
return id ( self )
# --- end of __hash__ (...) ---
@@ -190,17 +340,30 @@ class RWX ( object ):
)
# --- end of __repr__ (...) ---
- def get_str ( self, fillchar='-' ):
+ def get_str ( self, fillchar='-', rwx_chars="rwx" ):
+ """Returns a string similar to what ls would show ("rwx","r--",...).
+
+ arguments:
+ * fillchar -- char that is used to express absense of read/write/exe
+ Defaults to "-".
+ * rwx_chars -- a sequence of at least three chars. Defaults to "rwx."
+
+ """
return (
- ( 'r' if self.readable else fillchar ) +
- ( 'w' if self.writable else fillchar ) +
- ( 'x' if self.executable else fillchar )
+ ( rwx_chars[0] if self.readable else fillchar ) +
+ ( rwx_chars[1] if self.writable else fillchar ) +
+ ( rwx_chars[2] if self.executable else fillchar )
)
# --- end of get_str (...) ---
__str__ = get_str
def get_bitmask ( self, rwx_bits ):
+ """Returns an integer representing the rwx mode for the given rwx bits.
+
+ arguments:
+ * rwx_bits -- a list/tuple with at least three elements (r,w,x)
+ """
ret = 0
if self.readable:
ret |= rwx_bits[0]
@@ -218,6 +381,8 @@ class RWX ( object ):
class FsPermissions ( object ):
+ """An object representing read/write/execute permissions for users, groups
+ and others."""
USR_BITS = ( stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR )
GRP_BITS = ( stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP )
@@ -225,6 +390,13 @@ class FsPermissions ( object ):
@classmethod
def from_str ( cls, s, strict=False ):
+ """Returns a new permissions object for the given string.
+
+ arguments:
+ * s -- the string, e.g. "rwxr-x---" or "r---x---w"
+ * strict -- affects how strings are parsed.
+ see RWX.from_str() for details. Defaults to False.
+ """
rwx_user = RWX.from_str ( s[0:3], strict=strict )
rwx_group = RWX.from_str ( s[3:6], strict=strict )
rwx_others = RWX.from_str ( s[6:9], strict=strict )
@@ -233,6 +405,11 @@ class FsPermissions ( object ):
@classmethod
def from_stat_mode ( cls, stat_mode ):
+ """Creates a permissions object for the given stat mode.
+
+ arguments:
+ * stat_mode -- stat mode as its returned by os.stat() (and others)
+ """
return cls (
RWX.from_bitmask ( stat_mode, cls.USR_BITS ),
RWX.from_bitmask ( stat_mode, cls.GRP_BITS ),
@@ -241,6 +418,13 @@ class FsPermissions ( object ):
# --- end of from_stat_mode (...) ---
def __init__ ( self, rwx_user, rwx_group, rwx_others ):
+ """FsPermissions constructor.
+
+ arguments:
+ * rwx_user -- RWX object
+ * rwx_group -- RWX object
+ * rwx_others -- RWX object
+ """
super ( FsPermissions, self ).__init__()
self.user = rwx_user
self.group = rwx_group
@@ -256,6 +440,11 @@ class FsPermissions ( object ):
# --- end of __repr__ (...) ---
def get_str ( self, fillchar='-' ):
+ """Returns an ls-like string.
+
+ arguments:
+ * fillchar -- defaults to "-"
+ """
return "".join (
rwx.get_str ( fillchar=fillchar )
for rwx in ( self.user, self.group, self.others )
@@ -265,6 +454,7 @@ class FsPermissions ( object ):
__str__ = get_str
def get_stat_mode ( self ):
+ """Returns an integer that can be used for os.[l]chmod()."""
return (
self.user.get_bitmask ( self.USR_BITS ) |
self.group.get_bitmask ( self.GRP_BITS ) |
@@ -278,12 +468,29 @@ class FsPermissions ( object ):
# --- end of FsPermissions ---
def get_stat_mode ( mode_str ):
+ """Converts a permissions string into an integer.
+
+ arguments:
+ * mode_str -- "rwx------" etc.
+ """
return FsPermissions.from_str ( mode_str ).get_stat_mode()
# --- end of get_stat_mode (...) ---
class ChownChmod ( object ):
+ """An object for chown()/chmod() operations."""
+ # COULDFIX: remove / merge with AbstractFsOperations
+ # this allows to recursively chmod files and dirs
def __init__ ( self, uid=None, gid=None, mode=None, pretend=False ):
+ """ChownChmod constructor.
+
+ arguments:
+ * uid -- uid for chown() or None (keep uid). Defaults to None.
+ * gid -- gid for chown() or None (keep gid). Defaults to None.
+ * mode -- int mode for chmod() or None (keep mode). Defaults to None.
+ * pretend -- whether to actually chown/chmod (False) or just print
+ what would be done (True). Defaults to False.
+ """
super ( ChownChmod, self ).__init__()
self.pretend = bool ( pretend )
@@ -324,17 +531,37 @@ class ChownChmod ( object ):
# --- end of __init__ (...) ---
def _nullfunc ( self, fspath ):
+ """No-op replacement for chown()/chmod().
+
+ arguments:
+ * fspath -- ignore
+ """
return None
def _do_chown ( self, fspath, _chown=_OS_CHOWN ):
+ """Calls chown(fspath)
+
+ arguments:
+ * fspath --
+ """
_chown ( fspath, self.uid, self.gid )
return self.chown_str.format ( fspath )
def _do_chmod ( self, fspath, _chmod=_OS_CHMOD ):
+ """Calls chmod(fspath).
+
+ arguments:
+ * fspath --
+ """
_chmod ( fspath, self.mode )
return self.chmod_str.format ( fspath )
def chown_chmod ( self, fspath ):
+ """Calls chmod(fspath) and chown(fspath).
+
+ arguments:
+ * fspath --
+ """
# should be renamed to chmod_chown()
return (
self.chmod ( fspath ),
@@ -342,48 +569,50 @@ class ChownChmod ( object ):
)
# --- end of chown_chmod (...) ---
- def chown_chmod_recursive ( self, root ):
- chown = self.chown
- chmod = self.chmod
-
- if os.path.isfile ( root ):
- yield chmod ( root )
- yield chown ( root )
-
- else:
- for current_root, dirnames, filenames in os.walk ( root ):
- yield chmod ( current_root )
- yield chown ( current_root )
-
- for filename in filenames:
- fpath = current_root + os.sep + filename
- yield chmod ( fpath )
- yield chown ( fpath )
- # --- end of chown_chmod_recursive (...) ---
-
# --- end of ChownChmod ---
-def chown_chmod ( root, uid=None, gid=None, mode=None, pretend=False ):
- return ChownChmod ( uid, gid, mode, pretend ).chown_chmod ( root )
-# --- end of chown_chmod (...) ---
+def chown_chmod ( fspath, uid=None, gid=None, mode=None, pretend=False ):
+ """Calls chmod(fspath) and chown(fspath) after creating an intermediate
+ ChownChmod instance.
-def chown_chmod_recursive (
- root, uid=None, gid=None, mode=None, pretend=False
-):
- return ChownChmod (
- uid, gid, mode, pretend ).chown_chmod_recursive ( root )
-# --- end of chown_chmod_recursive (...) ---
+ arguments:
+ * fspath --
+ * uid --
+ * gid --
+ * mode --
+ * pretend --
+ """
+ return ChownChmod ( uid, gid, mode, pretend ).chown_chmod ( fspath )
+# --- end of chown_chmod (...) ---
-class AbstractFsOperations ( object ):
+class AbstractFsOperations ( roverlay.util.objects.AbstractObject ):
+ """Base object for performing filesystem operations."""
- PRETEND = None
+ @abc.abstractproperty
+ def PRETEND ( self ):
+ """A bool that indicates whether fs operations should be fully virtual
+ (print what would be done) or not.
+ Needs to be set by derived classes (as class-wide attribute).
+ """
+ return None
def __init__ ( self,
stdout=None, stderr=None, uid=None, gid=None,
file_mode=None, dir_mode=None
):
+ """AbstractFsOperations constructor.
+
+ arguments:
+ * stdout -- stdout stream. Defaults to sys.stdout
+ * stderr -- stderr stream. Defaults to sys.stderr
+ * uid -- uid for chown(). Defaults to None (keep uid).
+ * gid -- gid for chown(). Defaults to None (keep gid).
+ * file_mode -- mode for chmod(<file>). Defaults to None (don't change
+ mode). Can also be an ls-like str, e.g. "rwxr-x---".
+ * dir_mode -- mode for chmod(<file>). Defaults to None.
+ """
if self.__class__.PRETEND is None:
raise AssertionError ( "derived classes have to set PRETEND." )
@@ -400,23 +629,42 @@ class AbstractFsOperations ( object ):
self.info = self._stdout.write
self.error = self._stderr.write
-
- self._setup()
# --- end of __init__ (...) ---
- def _setup ( self ):
- pass
- # --- end of _setup (...) ---
-
- @roverlay.util.objects.abstractmethod
+ @abc.abstractmethod
def _dodir ( self, dirpath, mkdir_p ):
- pass
+ """Ensures that a directory exists, by creating it if necessary.
+ Also creates parent directories if mkdir_p evaluates to True.
+
+ Returns: success (True/False)
- @roverlay.util.objects.abstractmethod
+ arguments:
+ * dirpath
+ * mkdir_p
+ """
+ return
+
+ @abc.abstractmethod
def do_touch ( self, fspath ):
- pass
+ """Similar to "touch <fspath>".
+
+ Returns: success (True/False)
+
+ Raises: IOError, OSError
+ """
+ return
def chown ( self, fspath ):
+ """Calls chown_dir(fspath) or chown_file(fspath), depending on whether
+ fspath is a directory or not.
+
+ Returns: success (passed from chown_dir()/chown_file())
+
+ Raises: OSError
+
+ arguments:
+ * fspath --
+ """
if os.path.isdir ( fspath ):
return self.chown_dir ( fspath )
else:
@@ -424,21 +672,60 @@ class AbstractFsOperations ( object ):
# --- end of chown (...) ---
def chown_stat ( self, fspath, mode ):
+ """Similar to chown(fspath), but checks the given mode in order to
+ decide whether fspath is a dir.
+
+ Returns: success (True/False)
+
+ Raises: OSError
+
+ arguments:
+ * fspath --
+ * mode -- stat mode
+ """
if stat.S_ISDIR ( mode ):
return self.chown_dir ( fspath )
else:
return self.chown_file ( fspath )
# --- end of chown_stat (...) ---
- @roverlay.util.objects.abstractmethod
+ @abc.abstractmethod
def chown_dir ( self, fspath ):
- pass
+ """Changes the owner of a directory.
+
+ Returns: success (True/False)
- @roverlay.util.objects.abstractmethod
+ Raises: OSError
+
+ arguments:
+ * fspath --
+ """
+ return
+
+ @abc.abstractmethod
def chown_file ( self, fspath ):
- pass
+ """Changes the owner of a file.
+
+ Returns: success (True/False)
+
+ Raises: OSError
+
+ arguments:
+ * fspath --
+ """
+ return
def chmod ( self, fspath ):
+ """Calls chmod_dir(fspath) or chmod_file(fspath), depending on whether
+ fspath is a directory or not.
+
+ Returns: success (passed from chmod_dir()/chmod_file())
+
+ Raises: OSError
+
+ arguments:
+ * fspath --
+ """
if os.path.isdir ( fspath ):
return self.chmod_dir ( fspath )
else:
@@ -446,25 +733,59 @@ class AbstractFsOperations ( object ):
# --- end of chmod (...) ---
def chmod_stat ( self, fspath, mode ):
+ """Similar to chmod(fspath), but checks the given mode in order to
+ decide whether fspath is a dir.
+
+ Returns: success (True/False)
+
+ Raises: OSError
+
+ arguments:
+ * fspath --
+ * mode -- stat mode
+ """
if stat.S_ISDIR ( mode ):
return self.chmod_dir ( fspath )
else:
return self.chmod_file ( fspath )
# --- end of chmod_stat (...) ---
- @roverlay.util.objects.abstractmethod
+ @abc.abstractmethod
def chmod_dir ( self, fspath ):
- pass
+ """Changes the mode of a directory.
+
+ Returns: success (True/False)
+
+ Raises: OSError
+
+ arguments:
+ * fspath --
+ """
+ return
- @roverlay.util.objects.abstractmethod
+ @abc.abstractmethod
def chmod_file ( self, fspath ):
- pass
+ """Changes the mode of a file.
- def chmod_chown ( self, fspath ):
- self.chmod ( fspath )
- self.chown ( fspath )
+ Returns: success (True/False)
+
+ Raises: OSError
+
+ arguments:
+ * fspath --
+ """
+ return
def chmod_chown ( self, fspath ):
+ """Performs both chmod(fspath) and chown(fspath).
+
+ Returns: 2-tuple ( chmod_success, chown_success )
+
+ Raises: OSError
+
+ arguments:
+ * fspath --
+ """
if os.path.isdir ( fspath ):
return (
self.chmod_dir ( fspath ), self.chown_dir ( fspath )
@@ -476,6 +797,17 @@ class AbstractFsOperations ( object ):
# --- end of chmod (...) ---
def chmod_chown_stat ( self, fspath, mode ):
+ """Similar to chmod_chown(), but checks mode in order to decide whether
+ fspath is a dir.
+
+ Returns: 2-tuple ( chmod_success, chown_success )
+
+ Raises: OSError
+
+ arguments:
+ * fspath --
+ * mode -- stat mode
+ """
if stat.S_ISDIR ( mode ):
return (
self.chmod_dir ( fspath ), self.chown_dir ( fspath )
@@ -486,16 +818,37 @@ class AbstractFsOperations ( object ):
)
# --- end of chmod_stat (...) ---
- @roverlay.util.objects.abstractmethod
- def chmod_chown_recursive ( self, root ):
- pass
-
- @roverlay.util.objects.abstractmethod
+ @abc.abstractmethod
def _copy_file ( self, source, dest ):
- pass
+ """Copies a file from source to dest.
+
+ Returns: success (True/False)
+
+ Raises: undefined, IOError/OSError are likely
+
+ arguments:
+ * source --
+ * dest --
+ """
+ return
# --- end of _copy_file (...) ---
def copy_file ( self, source, dest, chown=True, chmod=True ):
+ """Copies a file from source to dest and calls chmod(),chown()
+ afterwards.
+
+ Returns: success (True/False)
+
+ Raises: OSError
+
+ arguments:
+ * source --
+ * dest --
+ * chown -- bool that controls whether chown() should be called.
+ Defaults to True.
+ * chmod -- bool that controls whether chmod() should be called.
+ Defaults to True.
+ """
if self._copy_file ( source, dest ):
if chmod:
self.chmod_file ( dest )
@@ -508,6 +861,23 @@ class AbstractFsOperations ( object ):
# --- end of copy_file (...) ---
def dodir ( self, dirpath, mkdir_p=True, chown=True, chmod=True ):
+ """Ensures that a directory exists by creating it if necessary.
+ Also calls chmod(), chown() afterwards.
+
+ Returns: success (True/False)
+
+ Raises: OSError
+
+ arguments:
+ * dirpath --
+ * mkdir_p -- whether to create parent directories as well (if necessary)
+ Defaults to True.
+ * chown -- bool that controls whether chown() should be called.
+ Defaults to True.
+ * chmod -- bool that controls whether chmod() should be called.
+ Defaults to True.
+ """
+
if self._dodir ( dirpath, mkdir_p=mkdir_p ):
if chmod:
self.chmod_dir ( dirpath )
@@ -520,30 +890,80 @@ class AbstractFsOperations ( object ):
# --- end of dodir (...) ---
def dodirs ( self, *dirs, **kwargs ):
+ """Calls dodir(dir) for each dir in dirs.
+
+ arguments:
+ * *dirs --
+ * **kwargs -- keyword arguments for dodir()
+ """
for dirpath in dirs:
self.dodir ( dirpath, **kwargs )
# --- end of dodirs (...) ---
- @roverlay.util.objects.abstractmethod
+ @abc.abstractmethod
def rmdir ( self, dirpath ):
- pass
+ """Removes an empty directory.
+
+ Returns: success (True/False)
+
+ arguments:
+ * dirpath --
+ """
+ return
- @roverlay.util.objects.abstractmethod
+ @abc.abstractmethod
def unlink ( self, fspath ):
- pass
+ """Removes a file (or link).
+
+ Returns: success (True/False)
+
+ arguments:
+ * fspath --
+ """
+ return
def wipe ( self, fspath ):
+ """Removes fspath if it is an empty directory or a file (or link).
+
+ Returns: success (True/False)
+
+ arguments:
+ * fspath --
+ """
return self.rmdir ( fspath ) or self.unlink ( fspath )
- @roverlay.util.objects.abstractmethod
+ @abc.abstractmethod
def symlink ( self, source, link_name ):
- pass
+ """Creates a symlink.
+
+ Returns: success (True/False)
+
+ arguments:
+ * source --
+ * link_name --
+ """
+ return
def check_writable ( self,
fspath, mkdir_chown=False, mkdir_chmod=False, mkdir_p=True
):
"""Checks whether fspath can be written. This creates all necessary
- directories."""
+ directories and creates fspath as empty file.
+
+ Returns: success (True/False)
+
+ Raises: passes IOError,OSError unless its error code is related to
+ missing write permissions
+
+ arguments:
+ * fspath --
+ * mkdir_chown -- bool that controls whether created directories should
+ be chown()-ed. Defaults to False.
+ * mkdir_chmod -- bool that controls whether created directories should
+ be chmod()-ed. Defaults to False.
+ * mkdir_p -- whether dodir() should create parent dirs as well.
+ Defaults to True.
+ """
success = False
ERRNOS_IGNORE = { errno.EACCES, }
@@ -595,6 +1015,21 @@ class AbstractFsOperations ( object ):
def copy_tree ( self,
source_root, dest_root, overwrite=True, followlinks=False
):
+ """Recursively copies files from source_root to dest_root (while keeping
+ its directory structure). Ownership and permissions are not preserved,
+ instead copied files and created dirs will have to permissions set
+ during initialization of this object.
+
+ Returns: None (implicit)
+
+ arguments:
+ * source_root -- directory from which files should be copied
+ * dest_root -- directory to which files should be copied
+ * overwrite -- whether to overwrite files that already exist in
+ dest_root. Defaults to True(!).
+ * followlinks -- whether to follow symbolic links in os.walk().
+ Defaults to False.
+ """
dodir = self.dodir
copy_file = self.copy_file
@@ -629,6 +1064,18 @@ class AbstractFsOperations ( object ):
def copy_dirlink_tree ( self,
source_root, dest_root, overwrite=False, followlinks=False
):
+ """Creates symlinks to source_root's content in dest_root.
+
+ Returns: None (implicit)
+
+ arguments:
+ * source_root --
+ * dest_root --
+ * overwrite --
+ * followlinks --
+ """
+
+ unlink = self.unlink
symlink = self.symlink
source, dest, relpath, dirs, files, dirnames = next (
@@ -641,6 +1088,8 @@ class AbstractFsOperations ( object ):
for ( my_source, my_source_stat ), ( my_dest, my_dest_stat ) in (
itertools.chain ( dirs, files )
):
+ if my_dest_stat is not None:
+ unlink ( my_dest )
symlink ( my_source, my_dest )
else:
for ( my_source, my_source_stat ), ( my_dest, my_dest_stat ) in (
@@ -653,7 +1102,17 @@ class AbstractFsOperations ( object ):
def copy_filelink_tree ( self,
source_root, dest_root, overwrite=False, followlinks=False
):
- dodir = self.dodir
+ """Like copy_tree(), but creates symlinks to files in source_root
+ instead of copying them.
+
+ arguments:
+ * source_root --
+ * dest_root --
+ * overwrite --
+ * followlinks --
+ """
+ dodir = self.dodir
+ unlink = self.unlink
symlink = self.symlink
if overwrite:
@@ -667,6 +1126,8 @@ class AbstractFsOperations ( object ):
if followlinks and stat.S_ISLINK ( source_stat ):
dodir ( dest_file )
else:
+ if dest_stat is not None:
+ unlink ( dest_file )
symlink ( source_file, dest_file )
else:
for source, dest, relpath, dirs, files, dirnames in (
@@ -684,19 +1145,27 @@ class AbstractFsOperations ( object ):
symlink ( source_file, dest_file )
# --- end of copy_filelink_tree (...) ---
-
# --- end of AbstractFsOperations ---
+
class FsOperations ( AbstractFsOperations ):
PRETEND = False
- def _setup ( self ):
+ # this is necessary because the abstract are overridden during __init__()
+ # (which doesn't get recognized by @abc.abstractmethod)
+ chmod_file = None
+ chown_file = None
+ chmod_dir = None
+ chown_dir = None
+
+ def __init__ ( self, *args, **kwargs ):
+ super ( FsOperations, self ).__init__ ( *args, **kwargs )
self.chmod_file = self.perm_env_file.chmod
self.chown_file = self.perm_env_file.chown
self.chmod_dir = self.perm_env_dir.chmod
self.chown_dir = self.perm_env_dir.chown
- # --- end of _setup (...) ---
+ # --- end of __init__ (...) ---
def _copy_file ( self, source, dest ):
shutil.copyfile ( source, dest )
@@ -709,11 +1178,6 @@ class FsOperations ( AbstractFsOperations ):
)
# --- end of _dodir (...) ---
- def chmod_chown_recursive ( self, root ):
- raise Exception("broken.")
- for ret in self.perm_env.chown_chmod_recursive ( root ):
- pass
-
def rmdir ( self, dirpath ):
try:
os.rmdir ( dirpath )
@@ -767,27 +1231,25 @@ class VirtualFsOperations ( AbstractFsOperations ):
ret = self.perm_env_file.chown ( fspath )
if ret is not None:
self.info ( ret + "\n" )
+ return True
def chown_dir ( self, fspath ):
ret = self.perm_env_dir.chown ( fspath )
if ret is not None:
self.info ( ret + "\n" )
+ return True
def chmod_file ( self, fspath ):
ret = self.perm_env_file.chmod ( fspath )
if ret is not None:
self.info ( ret + "\n" )
+ return True
def chmod_dir ( self, fspath ):
ret = self.perm_env_dir.chmod ( fspath )
if ret is not None:
self.info ( ret + "\n" )
-
- def chmod_chown_recursive ( self, root ):
- raise Exception("BROKEN.")
- for word in self.perm_env.chown_chmod_recursive ( root ):
- if word is not None:
- self.info ( word + "\n" )
+ return True
def unlink ( self, fspath ):
self.info ( "rm {!r}\n".format ( fspath ) )
next reply other threads:[~2013-09-20 15:57 UTC|newest]
Thread overview: 159+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-20 15:57 André Erdmann [this message]
-- strict thread matches above, loose matches on Subject: below --
2015-01-26 17:41 [gentoo-commits] proj/R_overlay:master commit in: roverlay/ André Erdmann
2015-01-26 17:41 André Erdmann
2014-07-18 16:20 André Erdmann
2014-07-18 2:50 [gentoo-commits] proj/R_overlay:wip/addition_control " André Erdmann
2014-07-18 16:20 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2014-07-18 2:28 [gentoo-commits] proj/R_overlay:wip/addition_control " André Erdmann
2014-07-18 16:20 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2014-07-16 15:14 André Erdmann
2014-06-05 22:09 André Erdmann
2014-04-01 16:38 André Erdmann
2014-02-16 16:30 André Erdmann
2014-02-15 19:49 André Erdmann
2014-02-15 19:49 André Erdmann
2014-01-25 18:14 André Erdmann
2013-12-11 18:40 André Erdmann
2013-12-11 18:40 André Erdmann
2013-09-23 15:30 André Erdmann
2013-09-19 15:00 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-16 13:43 André Erdmann
2013-09-13 15:10 André Erdmann
2013-09-12 16:36 André Erdmann
2013-09-12 16:36 André Erdmann
2013-09-12 16:36 André Erdmann
2013-09-11 11:14 André Erdmann
2013-09-11 10:19 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-06 17:27 André Erdmann
2013-09-06 17:27 André Erdmann
2013-09-03 15:50 André Erdmann
2013-09-02 12:27 André Erdmann
2013-09-02 8:44 André Erdmann
2013-08-30 14:49 André Erdmann
2013-08-30 14:49 André Erdmann
2013-08-29 12:36 André Erdmann
2013-08-29 12:36 André Erdmann
2013-08-28 15:54 André Erdmann
2013-08-27 15:39 André Erdmann
2013-08-23 13:52 André Erdmann
2013-08-23 13:52 André Erdmann
2013-08-23 13:52 André Erdmann
2013-08-19 15:42 André Erdmann
2013-08-16 14:05 André Erdmann
2013-08-16 11:02 André Erdmann
2013-08-16 10:43 André Erdmann
2013-08-16 10:43 André Erdmann
2013-08-14 14:56 André Erdmann
2013-08-14 14:56 André Erdmann
2013-08-13 8:56 André Erdmann
2013-08-13 8:56 André Erdmann
2013-08-13 8:56 André Erdmann
2013-08-12 8:28 André Erdmann
2013-08-12 8:18 André Erdmann
2013-08-07 16:10 André Erdmann
2013-08-02 14:30 André Erdmann
2013-08-02 10:34 André Erdmann
2013-08-02 10:34 André Erdmann
2013-08-01 12:44 André Erdmann
2013-08-01 12:44 André Erdmann
2013-07-29 14:56 André Erdmann
2013-07-29 8:55 André Erdmann
2013-07-26 13:02 André Erdmann
2013-07-23 7:51 André Erdmann
2013-07-23 7:51 André Erdmann
2013-07-19 18:00 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-23 7:51 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-17 18:05 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-17 18:05 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-15 22:31 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-16 16:36 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-12 13:57 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-19 18:58 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-22 15:24 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-19 18:58 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-19 18:59 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-13 16:34 André Erdmann
2013-06-05 18:08 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-05 18:08 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-04 21:06 André Erdmann
2013-04-25 16:44 André Erdmann
2013-04-25 16:44 André Erdmann
2013-03-05 11:27 André Erdmann
2013-02-09 20:45 André Erdmann
2013-02-05 17:48 André Erdmann
2013-02-05 17:48 André Erdmann
2013-01-30 20:16 André Erdmann
2013-01-30 20:16 André Erdmann
2013-01-28 23:54 André Erdmann
2013-01-28 23:54 André Erdmann
2013-01-28 23:54 André Erdmann
2012-10-02 10:04 André Erdmann
2012-08-20 11:16 André Erdmann
2012-08-13 18:07 André Erdmann
2012-08-09 9:26 André Erdmann
2012-08-08 23:46 André Erdmann
2012-08-08 23:46 André Erdmann
2012-08-07 8:50 André Erdmann
2012-08-02 15:14 André Erdmann
2012-08-01 7:25 André Erdmann
2012-07-31 17:51 André Erdmann
2012-07-30 8:52 André Erdmann
2012-07-30 8:52 André Erdmann
2012-07-24 16:59 [gentoo-commits] proj/R_overlay:overlay_wip " André Erdmann
2012-07-30 8:52 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2012-07-18 16:49 [gentoo-commits] proj/R_overlay:overlay_wip " André Erdmann
2012-07-30 8:52 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2012-07-16 16:15 André Erdmann
2012-07-16 16:15 André Erdmann
2012-07-16 16:15 [gentoo-commits] proj/R_overlay:depres_wip " André Erdmann
2012-07-16 16:15 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2012-07-10 17:43 André Erdmann
2012-07-09 17:19 André Erdmann
2012-07-04 18:21 André Erdmann
2012-07-04 18:21 André Erdmann
2012-07-03 17:48 André Erdmann
2012-06-28 13:29 André Erdmann
2012-06-26 15:42 André Erdmann
2012-06-25 18:19 André Erdmann
2012-06-21 16:55 André Erdmann
2012-06-20 19:03 André Erdmann
2012-06-20 19:03 André Erdmann
2012-06-18 16:27 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-12 17:17 André Erdmann
2012-06-06 19:52 André Erdmann
2012-06-06 19:52 André Erdmann
2012-06-06 19:52 André Erdmann
2012-06-05 17:30 André Erdmann
2012-06-04 19:07 André Erdmann
2012-06-04 19:07 André Erdmann
2012-06-04 15:43 André Erdmann
2012-06-01 16:19 André Erdmann
2012-06-01 16:19 André Erdmann
2012-06-01 15:46 André Erdmann
2012-05-31 18:24 André Erdmann
2012-05-30 20:15 André Erdmann
2012-05-30 19:36 André Erdmann
2012-05-30 19:36 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-26 13:14 André Erdmann
2012-05-26 13:14 André Erdmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1379688461.b26619285c74e85a7db260834da7cdda3bab0e2d.dywi@gentoo \
--to=dywi@mailerd.de \
--cc=gentoo-commits@lists.gentoo.org \
--cc=gentoo-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox