예제 #1
0
def _open_file_browser_for_folder(path):
    """
    This method will take a path to a folder and open it in
    an OS's file browser.

    :param path: A folder path
    :raises: RuntimeError: If the Platform is not supported or if
        the file browser couldn't be launched.
    :raises: ValueError: If the path is not a valid directory.
    """
    log.debug("Launching file system browser for folder %s" % path)

    # Check that we don't have a file path.
    if not os.path.isdir(path):
        raise ValueError("The path \"%s\" is not a valid directory." % path)

    # get the setting
    system = sys.platform

    # build the commands for opening the folder on the various OS's
    if system.startswith("linux"):
        cmd_args = ["xdg-open", path]
    elif system == "darwin":
        cmd_args = ["open", path]
    elif system == "win32":
        cmd_args = ["cmd.exe", "/C", "start", path]
    else:
        raise RuntimeError("Platform '%s' is not supported." % system)

    log.debug("Executing command '%s'" % cmd_args)
    exit_code = subprocess.call(cmd_args)
    if exit_code != 0:
        raise RuntimeError("Failed to launch a file browser for folder '%s'. "
                           "Error code %s" % (path, exit_code))
예제 #2
0
    def safe_delete_folder(path):
        """
        Deletes a folder and all of its contents recursively, even
        if it has read-only items.

        .. note::
            Problems deleting any items will be reported as warnings in the
            log output but otherwise ignored and skipped; meaning the function
            will continue deleting as much as it can.

        :param path: File system path to location to the folder to be deleted
        """
        def _on_rm_error(func, path, exc_info):
            """
            Error function called whenever shutil.rmtree fails to remove
            a file system item. Exceptions raised by this function will not
            be caught.

            :param func: The function which raised the exception; it will be:
                         os.path.islink(), os.listdir(),
                         os.remove() or os.rmdir().
            :param path: The path name passed to function.
            :param exc_info: The exception information return
                             by sys.exc_info().
            """
            if func == os.unlink or func == os.remove or func == os.rmdir:
                try:
                    attr = get_permissions(path)
                    if not (attr & stat.S_IWRITE):
                        os.chmod(path, stat.S_IWRITE | attr)
                        try:
                            func(path)
                        except Exception as e:
                            log.warning("Couldn't delete %s: %s. Skipping" %
                                        (path, e))
                    else:
                        log.warning("Couldn't delete %s: Skipping" % path)
                except Exception as e:
                    log.warning("Could not delete %s: %s. Skipping" %
                                (path, e))
            else:
                log.warning("Couldn't delete %s. Skipping." % path)

        if os.path.exists(path):
            try:
                # On Windows, Python's shutil can't delete read-only files,
                # so if we were trying to delete one, remove the flag.
                # Inspired by http://stackoverflow.com/a/4829285/1074536
                shutil.rmtree(path, onerror=_on_rm_error)
            except Exception as e:
                log.warning("Could not delete %s: %s" % (path, e))
        else:
            log.warning("Could not delete: %s. Folder does not exist" % path)
예제 #3
0
    def lock_file(self, path, chowned_set=None, utime=False):
        log.debug("Locking %s" % path)
        wm_path = path_utils.conform_path(path, os_name="linux")
        log.debug("stat [%c %#o] %s:%s (%d:%d): %s" % self._curstat(path))

        lock_file(wm_path, preserveTime=not utime)

        # The shared set from the current session should be passed in,
        # to keep track of which files
        # have been chown'd to in watchman case of a rollback.
        # This is a keyword argument to stay compatible
        # with spk.
        if chowned_set is not None:
            chowned_set.add(path)
예제 #4
0
        def _on_rm_error(func, path, exc_info):
            """
            Error function called whenever shutil.rmtree fails to remove
            a file system item. Exceptions raised by this function will not
            be caught.

            :param func: The function which raised the exception; it will be:
                         os.path.islink(), os.listdir(),
                         os.remove() or os.rmdir().
            :param path: The path name passed to function.
            :param exc_info: The exception information return
                             by sys.exc_info().
            """
            if func == os.unlink or func == os.remove or func == os.rmdir:
                try:
                    attr = get_permissions(path)
                    if not (attr & stat.S_IWRITE):
                        os.chmod(path, stat.S_IWRITE | attr)
                        try:
                            func(path)
                        except Exception as e:
                            log.warning("Couldn't delete %s: %s. Skipping" %
                                        (path, e))
                    else:
                        log.warning("Couldn't delete %s: Skipping" % path)
                except Exception as e:
                    log.warning("Could not delete %s: %s. Skipping" %
                                (path, e))
            else:
                log.warning("Couldn't delete %s. Skipping." % path)
예제 #5
0
    def lock_dir_recursive(self, path, chowned_set=None, utime=False):
        log.debug("Locking recursively %s" % path)
        # wm_path = path_utils.conform_path(path, os_name="linux")
        log.debug("stat [%c %#o] %s:%s (%d:%d): %s" % self._curstat(path))

        file_utils.lock_dir_recursive(path, preserveTime=not utime)

        for root, dirs, files in os.walk(path):
            for d in dirs:
                this_dir = os.path.join(root, d)
                if chowned_set is not None:
                    chowned_set.add(this_dir)
            for f in files:
                this_file = os.path.join(root, f)
                if chowned_set is not None:
                    chowned_set.add(this_file)
예제 #6
0
def auto_created_yml(path):
    """
    A context manager for opening/closing an auto-generated yaml file.

    - clears umask
    - any existing files will be removed
    - the given path will be open for writing in text mode
    - a standard header will be added

    Usage example::

        with filesystem.auto_created_yml(yaml_path) as fh:
            fh.write("foobar: blah")

        # fh is automatically closed upon exiting the context

    :param path: path to yml file to open for writing
    :return: file handle.
    """

    log.debug("Creating auto-generated config file %s" % path)
    # clean out any existing file and replace it with a new one.

    safe_delete_file(path)

    with open(path, "w+") as fh:

        fh.write("# This file was auto generated by the Dsk.\n")
        fh.write("# Please do not modify by hand as it may be ")
        fh.write("# overwritten at any point.\n")
        fh.write("# Created %s\n" %
                 (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
        fh.write("# \n")

        # on entering the context
        yield fh

        # on exiting the context
        fh.write("\n")
        fh.write("# End of file.\n")
예제 #7
0
def _open_file_browser_for_file(path):
    """
    This method will take a path to a file and open it in
    an OS's file browser and attempt to highlight it.

    :param path: A file path
    :raises: RuntimeError: If the Platform is not supported or if
        the file browser couldn't be launched.
    :raises: ValueError: If the path is not a valid file path.
    """
    log.debug("Launching file system browser for file %s" % path)

    if not os.path.isfile(path):
        raise ValueError("The path \"%s\" is not a valid file path." % path)

    # get the setting
    system = sys.platform

    if system.startswith("linux"):
        # note: there isn't a straight forward way to do
        # this on linux, so just open the directory instead.
        cmd_args = ["xdg-open", os.path.dirname(path)]
    elif system == "darwin":
        cmd_args = ["open", "-R", path]
    elif system == "win32":
        # /select makes windows select the file within the explorer window
        # The problem with this approach is that it always returns back an
        # error code of 1 even if it does behave correctly.
        cmd_args = ["explorer", "/select,", path]
    else:
        raise Exception("Platform '%s' is not supported." % system)

    log.debug("Executing command '%s'" % cmd_args)
    exit_code = subprocess.call(cmd_args)

    # cannot trust exit code from windows, see above
    if system != "win32" and exit_code != 0:
        raise RuntimeError("Failed to launch a file browser for file '%s'. "
                           "Error code %s" % (path, exit_code))
예제 #8
0
    def get_unused_path(base_path):
        """
        Return an unused file path from the given base path by appending
        if needed a number at the end of the basename of the path, right
        before the first ".", if any.

        For example, ``/tmp/foo_1.bar.blah`` would be returned for
        ``/tmp/foo.bar.blah`` if it already exists.

        If the given path does not exist, the original path is returned.

        .. note::
            The returned path is not _reserved_, so it is possible that
            other processes could create the returned path before it is used
            by the caller.

        :param str base_path: Target path.
        :returns: A string.
        """
        if not os.path.exists(base_path):
            # Bail out quickly if everything is fine with the path
            return base_path

        # Split the base path and find an unused path
        folder, basename = os.path.split(base_path)

        # two entries.
        base_parts = basename.split(".", 1) + [""]
        numbering = 0
        while True:
            numbering += 1
            name = "%s_%d%s" % (base_parts[0], numbering,
                                ".%s" % base_parts[1] if base_parts[1] else "")
            path = os.path.join(folder, name)
            log.debug("Checking if %s exists..." % path)
            if not os.path.exists(path):
                break
        return path
예제 #9
0
    def safe_delete_file(path):
        """
        Deletes the given file if it exists.

        Ignores any errors raised in the process and logs them as warnings.
        If the user does not have sufficient permissions to
        remove the file, nothing will happen, it will simply
        be skipped over.

        :param path: Full path to file to remove
        """
        try:
            if os.path.exists(path):
                # on windows, make sure file is not read-only
                if sys.platform == "win32":
                    # make sure we have write permission
                    attr = os.stat(path)[0]
                    if not attr & stat.S_IWRITE:
                        os.chmod(path, stat.S_IWRITE)
                os.remove(path)
        except Exception as e:
            log.warning("File '%s' could not be deleted, skipping: %s" %
                        (path, e))
예제 #10
0
 def is_write_permitted(a_top_root):
     api = EnviApi()
     api.reset(a_top_root)
     log.info("Loading %s as user %s" % (a_top_root, getpass.getuser()))
     api.load_data()
     if not api.is_valid():
         log.error("This is not a valid config %s" % a_top_root)
         return False
     varea = api.get_userdev_config_path(getpass.getuser())
     log.info("is_write_permitted: Checking if %s in %s\n" %
              (a_top_root, " ".join(varea)))
     if a_top_root in varea:
         return True
     return False
예제 #11
0
    def move_folder(cls,
                    src,
                    dst,
                    folder_permissions=0o775,
                    rm_dir=False,
                    do_log=True):
        """Moves a directory.
        First copies all content into target. Then deletes
        all content from sources. Skips files that won't delete.

        :param src: Source path to copy from
        :param dst: Destination to copy to
        :param folder_permissions: permissions to use for new folders
        """
        if os.path.exists(src):
            if do_log is True:
                log.debug("Moving directory: %s -> %s" % (src, dst))

            # first copy the content in the core folder
            src_files = cls.copy_folder_nocheck(src, dst, folder_permissions)

            # now clear out the install location
            if do_log is True:
                log.debug("Clearing out source location...")
            for f in src_files:
                try:
                    # on windows, ensure all files are writable
                    if sys.platform == "win32":
                        attr = os.stat(f)[0]
                        if (not attr & stat.S_IWRITE):
                            # file is readonly! - turn off this attribute
                            os.chmod(f, stat.S_IWRITE)
                    os.remove(f)
                except Exception as e:
                    log.error("Could not delete file %s: %s" % (f, e))
            if rm_dir:
                try:
                    all_files = os.listdir(src)
                    if len(all_files) == 0:
                        os.rmdir(src)
                        if do_log is True:
                            log.debug("dir %s: removed" % (src))
                    else:
                        if do_log is True:
                            log.info("no Empty %s" % all_files)
                except Exception as e:
                    log.error("Could not delete dir %s: %s" % (src, e))
예제 #12
0
    def copy_folder(cls, src, dst, folder_permissions=0o775, skip_list=None):
        """
        Alternative implementation to ``shutil.copytree``

        Copies recursively and creates folders if they don't already exist.
        Always skips system files such as ``"__MACOSX"``, ``".DS_Store"``, etc.
        Files will the extension ``.sh``, ``.bat`` or ``.exe`` will be given
        executable permissions.

        Returns a list of files that were copied.

        :param src: Source path to copy from
        :param dst: Destination to copy to
        :param folder_permissions: permissions to use for new folders
        :param skip_list: List of file names to skip. If this parameter is
                        omitted or set to None, common files such as ``.git``,
                          ``.gitignore`` etc will be ignored.
        :returns: List of files copied
        """
        # files or directories to always skip
        SKIP_LIST_ALWAYS = ["__MACOSX", ".DS_Store"]

        # compute full skip list
        # note: we don't do
        # actual_skip_list = skip_list or SKIP_LIST_DEFAULT
        # because we want users to be able to pass in
        # skip_list=[] in order to clear the default skip list.
        if skip_list is None:
            actual_skip_list = SKIP_LIST_DEFAULT
        else:
            actual_skip_list = skip_list

        # add the items we always want to skip
        actual_skip_list.extend(SKIP_LIST_ALWAYS)

        files = []

        if not os.path.exists(dst):
            os.mkdir(dst, folder_permissions)

        names = os.listdir(src)
        for name in names:

            # get rid of system files
            if name in actual_skip_list:
                continue

            srcname = os.path.join(src, name)
            dstname = os.path.join(dst, name)

            try:
                if os.path.isdir(srcname):
                    if os.path.exists(dstname):
                        try:
                            cls.move_folder(dstname,
                                            tempfile.mkdtemp(),
                                            rm_dir=True,
                                            do_log=False)
                        except Exception as e:
                            log.error("Could not delete directory %s: %s" %
                                      (dstname, e))
                            pass  # maybe we should raise
                    files.extend(
                        cls.copy_folder(srcname, dstname, folder_permissions))
                else:
                    shutil.copy(srcname, dstname)
                    files.append(srcname)

            except (IOError, os.error) as e:
                raise IOError("Can't copy %s to %s: %s" %
                              (srcname, dstname, e))
        return files