示例#1
0
    def _comp_dir(self, left, right, ignore):
        """compare a directory"""
        if self.debug:
            self.log.dbg('compare directory {} with {}'.format(left, right))
        if not os.path.exists(right):
            return ''
        if must_ignore([left, right], ignore, debug=self.debug):
            if self.debug:
                self.log.dbg('ignoring diff {} and {}'.format(left, right))
            return ''
        if not os.path.isdir(right):
            return '\"{}\" is a file\n'.format(right)
        if self.debug:
            self.log.dbg('compare {} and {}'.format(left, right))
        ret = []
        comp = filecmp.dircmp(left, right)

        # handle files only in deployed dir
        for i in comp.left_only:
            if must_ignore([os.path.join(left, i)], ignore, debug=self.debug):
                continue
            ret.append('=> \"{}\" does not exist on local\n'.format(i))

        # handle files only in dotpath dir
        for i in comp.right_only:
            if must_ignore([os.path.join(right, i)], ignore, debug=self.debug):
                continue
            ret.append('=> \"{}\" does not exist in dotdrop\n'.format(i))

        # same left and right but different type
        funny = comp.common_funny
        for i in funny:
            lfile = os.path.join(left, i)
            rfile = os.path.join(right, i)
            if must_ignore([lfile, rfile], ignore, debug=self.debug):
                continue
            short = os.path.basename(lfile)
            # file vs dir
            ret.append('=> different type: \"{}\"\n'.format(short))

        # content is different
        funny = comp.diff_files
        funny.extend(comp.funny_files)
        funny = uniq_list(funny)
        for i in funny:
            lfile = os.path.join(left, i)
            rfile = os.path.join(right, i)
            if must_ignore([lfile, rfile], ignore, debug=self.debug):
                continue
            diff = self._diff(lfile, rfile, header=True)
            ret.append(diff)

        # recursively compare subdirs
        for i in comp.common_dirs:
            subleft = os.path.join(left, i)
            subright = os.path.join(right, i)
            ret.extend(self._comp_dir(subleft, subright, ignore))

        return ''.join(ret)
示例#2
0
    def is_template(path, ignore=None, debug=False):
        """recursively check if any file is a template within path"""
        if debug:
            LOG.dbg('is template: {}'.format(path), force=True)
        path = os.path.expanduser(path)

        if not os.path.exists(path):
            # does not exist
            return False

        if utils.must_ignore([path], ignore, debug=debug):
            # must be ignored
            return False

        if os.path.isfile(path):
            # is file
            return Templategen._is_template(path, ignore=ignore, debug=debug)

        # is a directory
        for entry in os.listdir(path):
            fpath = os.path.join(path, entry)
            if not os.path.isfile(fpath):
                # recursively explore directory
                if Templategen.is_template(fpath, ignore=ignore, debug=debug):
                    return True
            else:
                # check if file is a template
                if Templategen._is_template(fpath, ignore=ignore, debug=debug):
                    return True
        return False
示例#3
0
 def _comp_file(self, left, right, ignore):
     """compare a file"""
     if utils.must_ignore([left, right], ignore, debug=self.debug):
         if self.debug:
             self.log.dbg('ignoring diff {} and {}'.format(left, right))
         return ''
     return self._diff(left, right)
示例#4
0
 def _ignore(self, path):
     if must_ignore([path], self.ignore, debug=self.debug):
         if self.debug:
             self.log.dbg('ignoring import of {}'.format(path))
         self.log.warn('{} ignored'.format(path))
         return True
     return False
示例#5
0
    def _comp_dir(self, left, right, ignore):
        """compare a directory"""
        if not os.path.exists(right):
            return ''
        if utils.must_ignore([left, right], ignore, debug=self.debug):
            if self.debug:
                self.log.dbg('ignoring diff {} and {}'.format(left, right))
            return ''
        if self.debug:
            self.log.dbg('compare {} and {}'.format(left, right))
        ret = []
        comp = filecmp.dircmp(left, right)
        # handle files only in deployed file
        for i in comp.left_only:
            if utils.must_ignore([os.path.join(left, i)],
                                 ignore,
                                 debug=self.debug):
                continue
            ret.append('=> \"{}\" does not exist on local\n'.format(i))
        for i in comp.right_only:
            if utils.must_ignore([os.path.join(right, i)],
                                 ignore,
                                 debug=self.debug):
                continue
            ret.append('=> \"{}\" does not exist in dotdrop\n'.format(i))

        # same left and right but different type
        funny = comp.common_funny
        for i in funny:
            lfile = os.path.join(left, i)
            rfile = os.path.join(right, i)
            short = os.path.basename(lfile)
            # file vs dir
            ret.append('different type: \"{}\"\n'.format(short))

        # content is different
        funny = comp.diff_files
        funny.extend(comp.funny_files)
        funny = list(set(funny))
        for i in funny:
            lfile = os.path.join(left, i)
            rfile = os.path.join(right, i)
            diff = self._diff(lfile, rfile, header=True)
            ret.append(diff)

        return ''.join(ret)
示例#6
0
    def _handle_file(self,
                     templater,
                     src,
                     dst,
                     actionexec=None,
                     noempty=False,
                     ignore=[]):
        """install src to dst when is a file"""
        if self.debug:
            self.log.dbg('generate template for {}'.format(src))
            self.log.dbg('ignore empty: {}'.format(noempty))
            self.log.dbg('ignore pattern: {}'.format(ignore))

        if utils.must_ignore([src, dst], ignore, debug=self.debug):
            if self.debug:
                self.log.dbg('ignoring install of {} to {}'.format(src, dst))
            return False, None

        if utils.samefile(src, dst):
            # symlink loop
            err = 'dotfile points to itself: {}'.format(dst)
            return False, err
        saved = templater.add_tmp_vars(self._get_tmp_file_vars(src, dst))
        try:
            content = templater.generate(src)
        except UndefinedException as e:
            return False, str(e)
        finally:
            templater.restore_vars(saved)
        if noempty and utils.content_empty(content):
            if self.debug:
                self.log.dbg('ignoring empty template: {}'.format(src))
            return False, None
        if content is None:
            err = 'empty template {}'.format(src)
            return False, err
        if not os.path.exists(src):
            err = 'source dotfile does not exist: {}'.format(src)
            return False, err
        st = os.stat(src)
        ret, err = self._write(src,
                               dst,
                               content,
                               st.st_mode,
                               actionexec=actionexec)
        if ret < 0:
            return False, err
        if ret > 0:
            if self.debug:
                self.log.dbg('ignoring {}'.format(dst))
            return False, None
        if ret == 0:
            if not self.dry and not self.comparing:
                self.log.sub('copied {} to {}'.format(src, dst))
            return True, None
        err = 'installing {} to {}'.format(src, dst)
        return False, err
示例#7
0
 def _comp_file(self, local_path, deployed_path, ignore):
     """compare a file"""
     self.log.dbg('compare file {} with {}'.format(
         local_path,
         deployed_path,
     ))
     if (self.ignore_missing_in_dotdrop and not
             os.path.exists(local_path)) \
             or must_ignore([local_path, deployed_path], ignore,
                            debug=self.debug):
         self.log.dbg('ignoring diff {} and {}'.format(
             local_path,
             deployed_path,
         ))
         return ''
     return self._diff(local_path, deployed_path)
示例#8
0
 def _is_template(path, ignore):
     """test if file pointed by path is a template"""
     if utils.must_ignore([path], ignore, debug=False):
         return False
     if not os.path.isfile(path):
         return False
     if os.stat(path).st_size == 0:
         return False
     markers = [BLOCK_START, VAR_START, COMMENT_START]
     patterns = [re.compile(marker.encode()) for marker in markers]
     try:
         with io.open(path, "r", encoding="utf-8") as f:
             m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
             for pattern in patterns:
                 if pattern.search(m):
                     return True
     except UnicodeDecodeError:
         # is binary so surely no template
         return False
     return False
示例#9
0
    def _comp_dir(self, local_path, deployed_path, ignore):
        """compare a directory"""
        self.log.dbg('compare directory {} with {}'.format(
            local_path,
            deployed_path,
        ))
        if not os.path.exists(deployed_path):
            return ''
        if (self.ignore_missing_in_dotdrop and not
                os.path.exists(local_path)) \
                or must_ignore([local_path, deployed_path], ignore,
                               debug=self.debug):
            self.log.dbg('ignoring diff {} and {}'.format(
                local_path,
                deployed_path,
            ))
            return ''
        if not os.path.isdir(deployed_path):
            return '\"{}\" is a file\n'.format(deployed_path)

        return self._compare_dirs(local_path, deployed_path, ignore)
示例#10
0
    def is_template(path, ignore=[]):
        """recursively check if any file is a template within path"""
        path = os.path.expanduser(path)

        if utils.must_ignore([path], ignore, debug=False):
            return False
        if not os.path.exists(path):
            return False
        if os.path.isfile(path):
            # is file
            return Templategen._is_template(path, ignore=ignore)
        for entry in os.listdir(path):
            fpath = os.path.join(path, entry)
            if not os.path.isfile(fpath):
                # recursively explore directory
                if Templategen.is_template(fpath, ignore=ignore):
                    return True
            else:
                # check if file is a template
                if Templategen._is_template(fpath, ignore=ignore):
                    return True
        return False
示例#11
0
 def _ignore(self, paths):
     if utils.must_ignore(paths, self.ignores, debug=self.debug):
         if self.debug:
             self.log.dbg('ignoring update for {}'.format(paths))
         return True
     return False
示例#12
0
    def _install_file(self, templater, src, dst,
                      actionexec=None, noempty=False,
                      ignore=[], template=True):
        """install src to dst when is a file"""
        if self.debug:
            self.log.dbg('deploy file: {}'.format(src))
            self.log.dbg('ignore empty: {}'.format(noempty))
            self.log.dbg('ignore pattern: {}'.format(ignore))
            self.log.dbg('template: {}'.format(template))
            self.log.dbg('no empty: {}'.format(noempty))

        if utils.must_ignore([src, dst], ignore, debug=self.debug):
            if self.debug:
                self.log.dbg('ignoring install of {} to {}'.format(src, dst))
            return False, None

        if utils.samefile(src, dst):
            # symlink loop
            err = 'dotfile points to itself: {}'.format(dst)
            return False, err

        if not os.path.exists(src):
            err = 'source dotfile does not exist: {}'.format(src)
            return False, err

        # handle the file
        content = None
        if template:
            # template the file
            saved = templater.add_tmp_vars(self._get_tmp_file_vars(src, dst))
            try:
                content = templater.generate(src)
            except UndefinedException as e:
                return False, str(e)
            finally:
                templater.restore_vars(saved)
            if noempty and utils.content_empty(content):
                if self.debug:
                    self.log.dbg('ignoring empty template: {}'.format(src))
                return False, None
            if content is None:
                err = 'empty template {}'.format(src)
                return False, err
        ret, err = self._write(src, dst,
                               content=content,
                               actionexec=actionexec,
                               template=template)

        # build return values
        if ret < 0:
            # error
            return False, err
        if ret > 0:
            # already exists
            if self.debug:
                self.log.dbg('ignoring {}'.format(dst))
            return False, None
        if ret == 0:
            # success
            if not self.dry and not self.comparing:
                self.log.sub('copied {} to {}'.format(src, dst))
            return True, None
        # error
        err = 'installing {} to {}'.format(src, dst)
        return False, err
示例#13
0
    def _comp_dir(self, local_path, deployed_path, ignore):
        """compare a directory"""
        if self.debug:
            self.log.dbg('compare directory {} with {}'.format(
                local_path,
                deployed_path,
            ))
        if not os.path.exists(deployed_path):
            return ''
        if (self.ignore_missing_in_dotdrop and not
                os.path.exists(local_path)) \
                or must_ignore([local_path, deployed_path], ignore,
                               debug=self.debug):
            if self.debug:
                self.log.dbg('ignoring diff {} and {}'.format(
                    local_path,
                    deployed_path,
                ))
            return ''
        if not os.path.isdir(deployed_path):
            return '\"{}\" is a file\n'.format(deployed_path)
        if self.debug:
            self.log.dbg('compare {} and {}'.format(local_path, deployed_path))
        ret = []
        comp = filecmp.dircmp(local_path, deployed_path)

        # handle files only in deployed dir
        for i in comp.left_only:
            if self.ignore_missing_in_dotdrop:
                continue
            if must_ignore([os.path.join(local_path, i)],
                           ignore,
                           debug=self.debug):
                continue
            ret.append('=> \"{}\" does not exist on destination\n'.format(i))

        # handle files only in dotpath dir
        for i in comp.right_only:
            if must_ignore([os.path.join(deployed_path, i)],
                           ignore,
                           debug=self.debug):
                continue

            if not self.ignore_missing_in_dotdrop:
                ret.append('=> \"{}\" does not exist in dotdrop\n'.format(i))

        # same local_path and deployed_path but different type
        funny = comp.common_funny
        for i in funny:
            source_file = os.path.join(local_path, i)
            deployed_file = os.path.join(deployed_path, i)
            if self.ignore_missing_in_dotdrop and \
                    not os.path.exists(source_file):
                continue
            if must_ignore([source_file, deployed_file],
                           ignore,
                           debug=self.debug):
                continue
            short = os.path.basename(source_file)
            # file vs dir
            ret.append('=> different type: \"{}\"\n'.format(short))

        # content is different
        funny = comp.diff_files
        funny.extend(comp.funny_files)
        funny = uniq_list(funny)
        for i in funny:
            source_file = os.path.join(local_path, i)
            deployed_file = os.path.join(deployed_path, i)
            if self.ignore_missing_in_dotdrop and \
                    not os.path.exists(source_file):
                continue
            if must_ignore([source_file, deployed_file],
                           ignore,
                           debug=self.debug):
                continue
            ret.append(self._diff(source_file, deployed_file, header=True))

        # recursively compare subdirs
        for i in comp.common_dirs:
            sublocal_path = os.path.join(local_path, i)
            subdeployed_path = os.path.join(deployed_path, i)
            ret.extend(self._comp_dir(sublocal_path, subdeployed_path, ignore))

        return ''.join(ret)
示例#14
0
    def _copy_file(self,
                   templater,
                   src,
                   dst,
                   actionexec=None,
                   noempty=False,
                   ignore=[],
                   is_template=True,
                   chmod=None):
        """
        install src to dst when is a file

        return
        - True, None        : success
        - False, error_msg  : error
        - False, None       : ignored
        - False, 'aborted'    : user aborted
        """
        if self.debug:
            self.log.dbg('deploy file: {}'.format(src))
            self.log.dbg('ignore empty: {}'.format(noempty))
            self.log.dbg('ignore pattern: {}'.format(ignore))
            self.log.dbg('is_template: {}'.format(is_template))
            self.log.dbg('no empty: {}'.format(noempty))

        # check no loop
        if utils.samefile(src, dst):
            err = 'dotfile points to itself: {}'.format(dst)
            return False, err

        if utils.must_ignore([src, dst], ignore, debug=self.debug):
            if self.debug:
                self.log.dbg('ignoring install of {} to {}'.format(src, dst))
            return False, None

        if utils.samefile(src, dst):
            # loop
            err = 'dotfile points to itself: {}'.format(dst)
            return False, err

        if not os.path.exists(src):
            err = 'source dotfile does not exist: {}'.format(src)
            return False, err

        # handle the file
        content = None
        if is_template:
            # template the file
            saved = templater.add_tmp_vars(self._get_tmp_file_vars(src, dst))
            try:
                content = templater.generate(src)
            except UndefinedException as e:
                return False, str(e)
            finally:
                templater.restore_vars(saved)
            # test is empty
            if noempty and utils.content_empty(content):
                if self.debug:
                    self.log.dbg('ignoring empty template: {}'.format(src))
                return False, None
            if content is None:
                err = 'empty template {}'.format(src)
                return False, err

        # write the file
        ret, err = self._write(src,
                               dst,
                               content=content,
                               actionexec=actionexec,
                               chmod=chmod)
        if ret and not err:
            if not self.dry and not self.comparing:
                self.log.sub('install {} to {}'.format(src, dst))
        return ret, err
示例#15
0
    def _link_children(self,
                       templater,
                       src,
                       dst,
                       actionexec=None,
                       is_template=True,
                       ignore=[]):
        """
        install link:link_children

        return
        - True, None        : success
        - False, error_msg  : error
        - False, None       : ignored
        - False, 'aborted'    : user aborted
        """
        parent = os.path.join(self.base, src)
        if not os.path.lexists(dst):
            if self.dry:
                self.log.dry('would create directory "{}"'.format(dst))
            else:
                if not self.comparing:
                    self.log.sub('creating directory "{}"'.format(dst))
                self._create_dirs(dst)

        if os.path.isfile(dst):
            msg = ''.join([
                'Remove regular file {} and ',
                'replace with empty directory?',
            ]).format(dst)

            if self.safe and not self.log.ask(msg):
                return False, 'aborted'
            os.unlink(dst)
            self._create_dirs(dst)

        children = os.listdir(parent)
        srcs = [
            os.path.normpath(os.path.join(parent, child)) for child in children
        ]
        dsts = [
            os.path.normpath(os.path.join(dst, child)) for child in children
        ]

        installed = 0
        for i in range(len(children)):
            subsrc = srcs[i]
            subdst = dsts[i]

            if utils.must_ignore([subsrc, subdst], ignore, debug=self.debug):
                if self.debug:
                    self.log.dbg(
                        'ignoring install of {} to {}'.format(src, dst), )
                continue

            if self.debug:
                self.log.dbg('symlink child {} to {}'.format(subsrc, subdst))

            if is_template:
                if self.debug:
                    self.log.dbg('child is a template')
                    self.log.dbg('install to {} and symlink'.format(
                        self.workdir))
                tmp = self._pivot_path(subdst, self.workdir, striphome=True)
                r, e = self.install(templater,
                                    subsrc,
                                    tmp,
                                    LinkTypes.NOLINK,
                                    actionexec=actionexec,
                                    is_template=is_template)
                if not r and e and not os.path.exists(tmp):
                    continue
                subsrc = tmp

            ret, err = self._symlink(subsrc, subdst, actionexec=actionexec)
            if ret:
                installed += 1
                # void actionexec if dotfile installed
                # to prevent from running actions multiple times
                actionexec = None
            else:
                if err:
                    return ret, err

        return installed > 0, None