Skip to content
repository.py 46.7 KiB
Newer Older
            raise ISError(u"No online repository")
        # building payload list
        paylist = {}
        for reponame in self.onlines:
            for md5, info in self[reponame].payloads().items():
                if md5 not in paylist:
                    paylist[md5] = info
                else:
                    paylist[md5]["images"].update(info["images"])
        # check if pattern is md5 startpath
        ans = {}
        for pattern in patterns:
            for md5 in paylist.keys():
                if md5.startswith(pattern):
                    ans[md5] = paylist[md5]
        return ans

    def show_payloads(self, patterns, o_images=False, o_json=False):
        '''
        Show payloads inside manager
        '''
        # get payload list
        payloads = self.select_payloads(patterns)
        # display result
        if o_json:
            s = json.dumps(payloads)
        else:
            l = []
            for payname in sorted(payloads.keys()):
                pay = payloads[payname]
                l.append(u"#l##y#%s#R#" % payname)
                l.append(u" size: %s" % istools.human_size(pay["size"]))
                l.append(u" directory: %s" % bool(pay["isdir"]))
                l.append(u" image count: %d" % len(pay["images"]))
                l.append(u" names: %s" % ", ".join(set((v["payname"] for v in pay["images"].values()))))
                if o_images:
                    l.append(u" images:")
                    for path, obj in pay["images"].items():
                        l.append(u"   %s#R#/#l##b#%s#R#:#p#%s#R# (%s)" % (
                                obj["repo"], obj["imgname"], obj["imgver"], obj["payname"]))
            s = os.linesep.join(l)
        if len(s) > 0:
            out(s)

    def select_repositories(self, patterns):
        '''
        Return a list of repository
        '''
        ans = set()
        uuidb = self.uuids
        for pattern in patterns:
            ans |= set(fnmatch.filter(self.names, pattern))
            if istools.strcspn(pattern, string.hexdigits + "-") == 0:
                for uuid in filter(lambda x: x.startswith(pattern), uuidb.keys()):
                    ans |= set((r.config.name for r in uuidb[uuid]))
        return sorted(ans)

    def purge_repositories(self, patterns):
        '''
        Remove local cached repository files
        '''
        for reponame in self.select_repositories(patterns):
            arrow(u"Purging cache of repository %s" % reponame)
            db = os.path.join(self.cache_path, reponame)
            if os.path.lexists(db):
                try:
                    os.unlink(db)
                    arrow("done", 1)
                except:
                    arrow("failed", 1)
            else:
                arrow("nothing to do", 1)

    def show_repositories(self, patterns, local=None, online=None, o_url=False,
                          o_state=False, o_uuid=False, o_json=False, o_version=False):
        '''
        Show repository inside manager
        if :param online: is true, list only online repositories
        if :param online: is false, list only offline repostiories
        if :param online: is None, list both online and offline repostiories.
        if :param local: is true, list only local repositories
        if :param local: is false, list only remote repostiories
        if :param local: is None, list both local and remote repostiories.
        '''
        # build repositories dict
        repos = {}
        for reponame in self.select_repositories(patterns):
            repo = self[reponame]
            if repo.config.offline and online is True:
                continue
            if not repo.config.offline and online is False:
                continue
            if repo.local and local is False:
                continue
            if not repo.local and local is True:
                continue
            repos[reponame] = dict(repo.config.items())
            repos[reponame]["local"] = repo.local
            if not repo.config.offline:
                repos[reponame]["uuid"] = repo.uuid
                repos[reponame]["version"] = repo.version
        # display result
        if o_json:
            s = json.dumps(repos)
        else:
            l = []
            for name, repo in repos.items():
                ln = ""
                so = "#l##r#Off#R# " if repo["offline"] else "#l##g#On#R#  "
                sl = "#l##y#Local#R#  " if repo["local"] else "#l##c#Remote#R# "
                rc = "#l##r#" if repo["offline"] else "#l##g#"
                if o_state:
                    ln +=  u"%s%s " % (so, sl)
                    rc = "#l##b#"
                ln += u"%s%s#R#"% (rc, name)
                    ln += u"  (%s)" % repo["path"]
                if not repo["offline"]:
                    if o_version:
                        ln += u"  (#p#v%s#R#)" % repo["version"]
                    if o_uuid and repo["uuid"] is not None:
                l.append(ln)
            s = os.linesep.join(l)
        out(s)


class RepositoryConfig(object):
    '''
    Repository configuration container
    '''

    def __init__(self, name, **kwargs):
        # set default value for arguments
        self._valid_param = ("name", "path", "dbpath", "lastpath",
                             "uid", "gid", "fmod", "dmod", "offline")
        self.name = Repository.check_repository_name(name)
        self.path = ""
        self._dbpath = None
        self.dbname = "db"
        self._lastpath = None
        self.lastname = "last"
        self._uid = os.getuid()
        self._gid = os.getgid()
        umask = os.umask(0)
        os.umask(umask)
        self._fmod =  0666 & ~umask
        self._dmod =  0777 & ~umask
        self.update(**kwargs)

    def __str__(self):
        l = []
        for k, v in self.items():
            l.append(u"%s: %s" % (k, v))
        return os.linesep.join(l)

    def __eq__(self, other):
        return vars(self) == vars(other)

    def __ne__(self, other):
        return not (self == other)

    def __contains__(self, key):
        return key in self.__dict__

    def __getitem__(self, key):
        if key not in self._valid_param:
            raise IndexError(key)
        return getattr(self, key)

    def __iter__(self):
        for p in self._valid_param:
            yield p

    def items(self):
        for p in self:
            yield p, self[p]

    @property
    def lastpath(self):
        '''
        Return the last file complete path
        '''
        if self._lastpath is None:
            return os.path.join(self.path, self.lastname)
        return self._lastpath

    @lastpath.setter
    def lastpath(self, value):
        '''
        Set last path
        '''
        self._lastpath = value

    @property
    def dbpath(self):
        '''
        Return the db complete path
        '''
        if self._dbpath is None:
            return os.path.join(self.path, self.dbname)
        return self._dbpath

    @dbpath.setter
    def dbpath(self, value):
        '''
        Set db path
        '''
Aurélien Dunand's avatar
Aurélien Dunand committed
        # dbpath must be local, sqlite3 requirement
        if not istools.isfile(value):
            raise ValueError("Database path must be local")
        self._dbpath = os.path.abspath(value)

    @property
    def uid(self):
        '''
        Return owner of repository
        '''
        return self._uid

    @uid.setter
    def uid(self, value):
        '''
        Define user name owning repository
        '''
        if not value.isdigit():
            self._uid = pwd.getpwnam(value).pw_uid
        else:
            self._uid = int(value)

    @property
    def gid(self):
        '''
        Return group of the repository
        '''
        return self._gid

    @gid.setter
    def gid(self, value):
        '''
        Define group owning repository
        '''
        if not value.isdigit():
            self._gid = grp.getgrnam(value).gr_gid
        else:
            self._gid = int(value)

    @property
    def fmod(self):
        '''
        Return new file mode
        '''
        return self._fmod

    @fmod.setter
    def fmod(self, value):
        '''
        Define new file mode
        '''
        if value.isdigit():
            self._fmod = int(value, 8)
        else:
            raise ValueError("File mode must be an integer")

    @property
    def dmod(self):
        '''
        Return new directory mode
        '''
        return self._dmod

    @dmod.setter
    def dmod(self, value):
        '''
        Define new directory mode
        '''
        if value.isdigit():
            self._dmod = int(value, 8)
        else:
            raise ValueError("Directory mode must be an integer")

    @property
    def offline(self):
        '''
        Get the offline state of a repository
        '''
        return self._offline

    @offline.setter
    def offline(self, value):
        if type(value) in (str, unicode):
            value = value.lower() not in ("false", "no", "0")
        elif type(value) is not bool:
            value = bool(value)
        self._offline = value

    def update(self, *args, **kwargs):
        '''
        Update attribute with checking value
        All attribute must already exists
        '''
        # autoset parameter in cmdline
        for k in kwargs:
            if hasattr(self, k):
                try:
                    setattr(self, k, kwargs[k])
                except Exception as e:
                    warn(u"Unable to set config parameter %s in repository %s: %s" %
                         (k, self.name, e))
                debug(u"No such repository parameter: %s" % k)