def replace_objects_newer_on_remote(self, obj_type):
        locals = utils.lod_to_dod(self.local_data[obj_type], "uid")
        remotes = utils.lod_to_dod(self.remote_data[obj_type], "uid")

        for (ruid, rdata) in remotes.iteritems():
            # do not add the system if it is not on the transfer list
            if not rdata["name"] in self.must_include[obj_type]:
                continue

            if ruid in locals:
                ldata = locals[ruid]
                if ldata["mtime"] < rdata["mtime"]:

                    if ldata["name"] != rdata["name"]:
                        self.logger.info("removing %s %s" % (obj_type, ldata["name"]))
                        self.api.remove_item(obj_type, ldata["name"], recursive=True, logger=self.logger)
                    creator = getattr(self.api, "new_%s" % obj_type)
                    newobj = creator()
                    newobj.from_dict(rdata)
                    try:
                        self.logger.info("updating %s %s" % (obj_type, rdata["name"]))
                        if not self.api.add_item(obj_type, newobj):
                            self.logger.error("failed to update %s %s" % (obj_type, rdata["name"]))
                    except Exception:
                        utils.log_exc(self.logger)
    def remove_objects_not_on_master(self, obj_type):
        locals = utils.lod_to_dod(self.local_data[obj_type], "uid")
        remotes = utils.lod_to_dod(self.remote_data[obj_type], "uid")

        for (luid, ldata) in locals.iteritems():
            if luid not in remotes:
                try:
                    self.logger.info("removing %s %s" % (obj_type, ldata["name"]))
                    self.api.remove_item(obj_type, ldata["name"], recursive=True, logger=self.logger)
                except Exception:
                    utils.log_exc(self.logger)
    def remove_objects_not_on_master(self, obj_type):
        locals = utils.lod_to_dod(self.local_data[obj_type], "uid")
        remotes = utils.lod_to_dod(self.remote_data[obj_type], "uid")

        obj_pattern = getattr(self, "%s_patterns" % obj_type)
        if obj_pattern and self.prune:
            self.logger.info("Found pattern for %s. Pruning non-matching items" % obj_type)
            keep_obj = {}
            remote_names = utils.loh_to_hoh(self.remote_data[obj_type], "name")
            for name in remote_names.keys():
                if name in self.must_include[obj_type] and remote_names[name]["uid"] in remotes:
                    self.logger.info("Adding %s:%s to keep list" % (name, remote_names[name]["uid"]))
                    keep_obj[remote_names[name]["uid"]] = remotes[remote_names[name]["uid"]]
            remotes = keep_obj

        for (luid, ldata) in locals.iteritems():
            if luid not in remotes:
                try:
                    self.logger.info("removing %s %s" % (obj_type, ldata["name"]))
                    self.api.remove_item(obj_type, ldata["name"], recursive=True, logger=self.logger)
                except Exception:
                    utils.log_exc(self.logger)
    def add_objects_not_on_local(self, obj_type):
        locals = utils.lod_to_dod(self.local_data[obj_type], "uid")
        remotes = utils.lod_sort_by_key(self.remote_data[obj_type], "depth")

        for rdata in remotes:

            # do not add the system if it is not on the transfer list
            if not rdata["name"] in self.must_include[obj_type]:
                continue

            if not rdata["uid"] in locals:
                creator = getattr(self.api, "new_%s" % obj_type)
                newobj = creator()
                newobj.from_dict(rdata)
                try:
                    self.logger.info("adding %s %s" % (obj_type, rdata["name"]))
                    if not self.api.add_item(obj_type, newobj, logger=self.logger):
                        self.logger.error("failed to add %s %s" % (obj_type, rdata["name"]))
                except Exception:
                    utils.log_exc(self.logger)
    def generate_include_map(self):

        self.remote_names = {}
        self.remote_dict = {}
        self.must_include = {
            "distro": {},
            "profile": {},
            "system": {},
            "image": {},
            "repo": {},
            "mgmtclass": {},
            "package": {},
            "file": {}
        }

        for ot in OBJ_TYPES:
            self.remote_names[ot] = utils.lod_to_dod(self.remote_data[ot], "name").keys()
            self.remote_dict[ot] = utils.lod_to_dod(self.remote_data[ot], "name")
            if self.sync_all:
                for names in self.remote_dict[ot]:
                    self.must_include[ot][names] = 1

        self.logger.debug("remote names struct is %s" % self.remote_names)

        if not self.sync_all:
            # include all profiles that are matched by a pattern
            for obj_type in OBJ_TYPES:
                patvar = getattr(self, "%s_patterns" % obj_type)
                self.logger.debug("* Finding Explicit %s Matches" % obj_type)
                for pat in patvar:
                    for remote in self.remote_names[obj_type]:
                        self.logger.debug("?: seeing if %s looks like %s" % (remote, pat))
                        if fnmatch.fnmatch(remote, pat):
                            self.logger.debug("Adding %s for pattern match %s." % (remote, pat))
                            self.must_include[obj_type][remote] = 1

            # include all profiles that systems require
            # whether they are explicitly included or not
            self.logger.debug("* Adding Profiles Required By Systems")
            for sys in self.must_include["system"].keys():
                pro = self.remote_dict["system"][sys].get("profile", "")
                self.logger.debug("?: system %s requires profile %s." % (sys, pro))
                if pro != "":
                    self.logger.debug("Adding profile %s for system %s." % (pro, sys))
                    self.must_include["profile"][pro] = 1

            # include all profiles that subprofiles require
            # whether they are explicitly included or not
            # very deep nesting is possible
            self.logger.debug("* Adding Profiles Required By SubProfiles")
            while True:
                loop_exit = True
                for pro in self.must_include["profile"].keys():
                    parent = self.remote_dict["profile"][pro].get("parent", "")
                    if parent != "":
                        if parent not in self.must_include["profile"]:
                            self.logger.debug("Adding parent profile %s for profile %s." % (parent, pro))
                            self.must_include["profile"][parent] = 1
                            loop_exit = False
                if loop_exit:
                    break

            # require all distros that any profiles in the generated list requires
            # whether they are explicitly included or not
            self.logger.debug("* Adding Distros Required By Profiles")
            for p in self.must_include["profile"].keys():
                distro = self.remote_dict["profile"][p].get("distro", "")
                if not distro == "<<inherit>>" and not distro == "~":
                    self.logger.debug("Adding distro %s for profile %s." % (distro, p))
                    self.must_include["distro"][distro] = 1

            # require any repos that any profiles in the generated list requires
            # whether they are explicitly included or not
            self.logger.debug("* Adding Repos Required By Profiles")
            for p in self.must_include["profile"].keys():
                repos = self.remote_dict["profile"][p].get("repos", [])
                if repos != "<<inherit>>":
                    for r in repos:
                        self.logger.debug("Adding repo %s for profile %s." % (r, p))
                        self.must_include["repo"][r] = 1

            # include all images that systems require
            # whether they are explicitly included or not
            self.logger.debug("* Adding Images Required By Systems")
            for sys in self.must_include["system"].keys():
                img = self.remote_dict["system"][sys].get("image", "")
                self.logger.debug("?: system %s requires image %s." % (sys, img))
                if img != "":
                    self.logger.debug("Adding image %s for system %s." % (img, sys))
                    self.must_include["image"][img] = 1

        # FIXME: remove debug
        for ot in OBJ_TYPES:
            self.logger.debug("transfer list for %s is %s" % (ot, self.must_include[ot].keys()))