Пример #1
0
    def symlink(self, src, dst=os.curdir, outside=False):
        """
        Create a symlink to the designated source.

        :param src: The source file the symlink should point to.  If
                    ``outside`` is ``False``, the symlink must point
                    inside the tree, or a ``ValueError`` will be
                    raised.
        :param dst: The destination of the symlink.  If it is a
                    directory, the basename of the source file will be
                    added.
        :param outside: If ``True``, the source filename is not
                        interpreted (unless ``dst`` is a directory).
                        If ``False`` (the default), the source
                        filename must be inside the tree.

        :returns: An ``FSEntry`` instance representing the new
                  symlink.
        """

        # Determine the destination
        dst = self._rel(dst)
        full_dst = self.tree._full(dst)

        # If the destination is a directory, we need to add the source
        # basename
        if os.path.isdir(full_dst):
            basename = os.path.basename(src)
            dst = os.path.join(dst, basename)
            full_dst = os.path.join(full_dst, basename)

        # Figure out the source
        if not outside:
            # Resolve to a tree path
            if isinstance(src, FSEntry):
                src = utils.abspath(src.name, cwd=self.name)
            else:
                src = utils.deroot(utils.abspath(src, cwd=self.path),
                                   self.tree.path)

            # We now have a tree-relative path, convert it into a path
            # relative to the destination
            src = str(utils.RelPath(src, dst))

        # Create the symlink
        os.symlink(src, full_dst)

        # Return a reference to the new file
        return self.tree._get(dst)
Пример #2
0
    def test_relative_with_cwd(self, mock_deroot, mock_getcwd, mock_abspath):
        result = utils.abspath('foo//bar/..///baz', cwd='/curr')

        self.assertEqual(result, '/curr/foo/baz')
        mock_abspath.assert_called_once_with('/')
        self.assertFalse(mock_getcwd.called)
        self.assertFalse(mock_deroot.called)
Пример #3
0
    def test_relative(self, mock_deroot, mock_getcwd, mock_abspath):
        result = utils.abspath('foo//bar/..///baz', root='/root')

        self.assertEqual(result, '/root/foo/baz')
        mock_abspath.assert_called_once_with('/root')
        mock_getcwd.assert_called_once_with()
        mock_deroot.assert_called_once_with('/current/dir', '/root')
Пример #4
0
    def test_absolute(self, mock_deroot, mock_getcwd, mock_abspath):
        result = utils.abspath('/foo//bar/..///baz')

        self.assertEqual(result, '/foo/baz')
        mock_abspath.assert_called_once_with('/')
        self.assertFalse(mock_getcwd.called)
        self.assertFalse(mock_deroot.called)
Пример #5
0
    def _rel(self, path, cross_tree=True):
        """
        A helper method to resolve a provided path relative to this
        filesystem entry.  Returns a relative path against the tree
        root.

        :param path: The path to resolve.
        :param cross_tree: If ``True`` (the default), allow
                           ``FSEntry`` instances that are in different
                           trees, using their name only.  If
                           ``False``, a ``ValueError`` will be raised.

        :returns: The desired tree-relative path.
        """

        # If it's an FSEntry, check if we're in the right tree
        if isinstance(path, FSEntry):
            if not cross_tree and path.tree is not self.tree:
                raise ValueError('path is not in this tree')

            # Grab the path name
            path = path.name

        # Resolve the path with the tree root as the root
        return utils.abspath(path, cwd=self.name)
Пример #6
0
    def _paths(self, src, dst):
        """
        A helper method to resolve provided source and destination
        paths relative to this filesystem entry.

        :param src: The desired source file.
        :param dst: The desired destination.  If the destination is an
                    existing directory, the basename of the source
                    file will be appended to it.

        :returns: A tuple of the absolute source path, a relative
                  destination path, and an absolute destination path.
        """

        # Resolve the source, first
        if isinstance(src, FSEntry):
            # Use the full path when src is an FSEntry instance
            src = src.path
        else:
            # It's a file system path; interpret relative to our
            # location
            src = utils.abspath(src, cwd=self.path)

        # Now the destination...
        dst = self._rel(dst)
        full_dst = self.tree._full(dst)

        # If the destination is a directory, we need to add the source
        # basename
        if os.path.isdir(full_dst):
            basename = os.path.basename(src)
            dst = os.path.join(dst, basename)
            full_dst = os.path.join(full_dst, basename)

        return (src, dst, full_dst)
Пример #7
0
        def test_relative_py2(self, mock_deroot, mock_getcwdu, mock_getcwd,
                              mock_abspath):
            result = utils.abspath(u'foo//bar/..///baz', root='/root')

            self.assertEqual(result, '/root/foo/baz')
            mock_abspath.assert_called_once_with('/root')
            self.assertFalse(mock_getcwd.called)
            mock_getcwdu.assert_called_once_with()
            mock_deroot.assert_called_once_with('/unicode/dir', '/root')
Пример #8
0
    def _abs(self, path):
        """
        A helper method to resolve a provided path relative to this
        filesystem entry.  Returns an absolute path against the
        underlying filesystem.

        :param path: The path to resolve.

        :returns: The resolved, absolute path.
        """

        # If it's an FSEntry, use the name
        if isinstance(path, FSEntry):
            path = path.name

        return self.tree._full(utils.abspath(path, cwd=self.name))
Пример #9
0
    def __init__(self, path, mode=0o777):
        """
        Initialize an ``FSTree`` instance.

        :param path: The path to the root of the tree.  If the path
                     does not exist, it will be created.
        :param mode: The mode for the root directory, if it does not
                     exist.  If the directory exists, the mode is
                     ignored.
        """

        # Make sure the path is absolute, then create it if it doesn't
        # exist
        path = utils.abspath(path)
        if not os.path.isdir(path):
            os.makedirs(path, mode)

        # Initialize the entry
        super(FSTree, self).__init__(self, '/', path)

        # Keep a weak dictionary of the entries
        self._entries = weakref.WeakValueDictionary()
Пример #10
0
    def relpath(self, start, absolute=False):
        """
        Compute the relative path from the designated start directory
        to this entry.

        :param start: The starting directory.  May be another
                      ``FSEntry`` or a string.  If this is another
                      ``FSEntry``, and ``absolute`` is ``False``, only
                      the tree-relative entry name will be used; if
                      ``absolute`` is ``True``, the starting point
                      will be the full path name of the other
                      ``FSEntry``.
        :param absolute: If ``True``, the starting point may be
                         outside the tree, and the relative path may
                         exit the tree in that case.  If ``False``
                         (the default), the starting point is
                         interpreted as being relative to the root of
                         the tree.

        :returns: The relative path from ``start`` to this entry.
        """

        # Which is our path for this computation?
        path = self.path if absolute else self.name

        # Figure out which value to use for start
        if isinstance(start, FSEntry):
            start = start.path if absolute else start.name
        else:
            # Interpret start relative to this directory
            start = utils.abspath(start, cwd=path)

        # OK, now compute the relative path
        rel_path = utils.RelPath(path, start)

        return str(rel_path)
Пример #11
0
    def tar(self, filename, start=os.curdir, compression=utils.unset,
            hasher=None):
        """
        Create a tar file with the given filename.

        :param filename: The filename of the tar file to create.  If
                         ``compression`` is not given, it will be
                         inferred from the filename.  The appropriate
                         extensions will be added to the filename, if
                         necessary.  If a compression extension on the
                         filename does not match the specified
                         compression, a ``ValueError`` will be raised.
        :param start: The directory from which to start the tar
                      process.  If not given, starts from the current
                      directory and includes all files in the
                      directory.  If it is a parent of the current
                      directory, only the current directory will be
                      included in the tarball.  A ``ValueError`` will
                      be raised if the tar process cannot start from
                      the given location.
        :param compression: If given, specifies the compression to
                            use.  The ``filename`` will be modified to
                            include the appropriate extension.  A
                            ``ValueError`` will be raised if the given
                            compression is not supported or if a
                            compression was inferred from the
                            filename.
        :param hasher: If given, requests that a hash of the resulting
                       tar file be computed.  May be a ``True`` value
                       to use the default hasher; a string to specify
                       a hasher; or a tuple of hashers.

        :returns: The final filename that was created.  If ``hasher``
                  was specified, a tuple will be returned, with the
                  second element consisting of the hex digest of the
                  tar file.
        """

        # If the filename is a FSEntry, use its path
        if isinstance(filename, FSEntry):
            filename = filename.path

        # Parse the file name and set the compression
        filename = tarname.TarFileName(utils.abspath(filename, cwd=self.path))
        if compression is not utils.unset:
            filename.compression = compression

        # Determine the starting location and file list
        start = self._rel(start, False)
        filelist = None
        rel_path = utils.RelPath(start, self.name)
        if rel_path.parents and rel_path.remainder:
            raise ValueError("cannot start tar-ing from '%s'" % rel_path)
        elif not rel_path.parents and not rel_path.remainder:
            start = self.path
        elif rel_path.parents:
            start = os.path.normpath(
                os.path.join(self.path, [os.pardir] * rel_path.parents))
            filelist = [os.path.join(*rel_path.path_list[-rel_path.parents:])]
        start = self.tree._full(start)
        if filelist is None:
            filelist = os.listdir(start)

        # OK, let's build the tarball
        tar = tarfile.open(str(filename), 'w:%s' % filename.compression or '')
        try:
            with utils.workdir(start):
                for fname in filelist:
                    try:
                        tar.add(fname)
                    except Exception:
                        pass
        finally:
            tar.close()

        # Begin building the result
        result = str(filename)

        # If a hash was requested, generate it
        if hasher:
            # Select the hasher(s)
            if hasher is True:
                hasher = (utils.get_hasher(utils.DEFAULT_HASHER)(),)
            elif isinstance(hasher, six.string_types):
                hasher = (utils.get_hasher(hasher)(),)
            elif not isinstance(hasher, tuple):
                hasher = (hasher,)

            # Open the file
            with open(result) as f:
                result = (result, utils.digest(f, hasher))

        return result