def loadConfigModule(self): try: self._confobj = PyConfParser(getConfigModule(self.name)) except ImportError as e: #if kwargs.pop("warn", True): logMsg(e.message , warning=True) return False
class DamProject(object): _instancesDct = {} @classmethod def fromPath(cls, p, fail=False, **kwargs): sProjName = projectNameFromPath(p) if not sProjName: if fail: raise ValueError("Path NOT part of a KNOWN PROJECT: '{}'" .format(p)) return None return cls(sProjName, **kwargs) def __new__(cls, sProjName, **kwargs): logMsg(cls.__name__ , log='all') sProjName = sProjName.lower() bExists = True proj = cls._instancesDct.get(sProjName) if not proj: bExists = False proj = object.__new__(cls) proj.name = sProjName libClass = DrcLibrary if "maya" in hostApp(): try: from davos_maya.core.mrclibrary import MrcLibrary except ImportError: pass else: libClass = MrcLibrary proj.__libClass = libClass#kwargs.pop("libraryType", DrcLibrary) proj.reset() if not kwargs.pop("empty", False): if not proj.init(**kwargs): return None proj.loadLibraries() if not bExists: cls._instancesDct[sProjName] = proj #print id(proj), proj return proj def reset(self): logMsg(log='all') self._damasdb = None self._shotgundb = None self._db = None self._authobj = None self._itemmodel = None self.__loggedUser = None self.__userid = "" self.__passwd = "" self.__authClass = None self.authenticated = False self.loadedLibraries = {} self.mayaLoadReferences = True self.showPrivateLibraries = os.environ.get("DAVOS_SHOW_PRIV_LIBS", False) self.loadConfigModule() self.__confLibraries = self.getVar("project", "libraries") def init(self, **kwargs): logMsg(log='all') self.__userid = kwargs.pop("user", "") self.__passwd = kwargs.pop("password", "") bShotgun = kwargs.pop("shotgun", True) bDamas = kwargs.pop("damas", True) bExists = self._instanceExists() if bExists and self.isAuthenticated(): return True print "<{}> Initializing...".format(self) if bShotgun: self.__initShotgun() if not bDamas: self.__authClass = ShotgunAuth if bDamas: self.__initDamas() if not bShotgun: self.__authClass = DamasAuth if bShotgun and bDamas: self.__authClass = DualAuth if not self.authenticate(renew=True): return False if inDevMode() and kwargs.pop("checkTemplates", True): sMissingPathList = [] self._checkTemplatePaths(sMissingPathList) if sMissingPathList: msg = "Missing template paths:\n " + '\n '.join(sMissingPathList) logMsg(msg , warning=True) #return False self._db = DrcDb(self) return True def loadConfigModule(self): try: self._confobj = PyConfParser(getConfigModule(self.name)) except ImportError as e: #if kwargs.pop("warn", True): logMsg(e.message , warning=True) return False def _instanceExists(self): return id(self.__class__._instancesDct.get(self.name)) == id(self) def authenticate(self, renew=False): if renew or (not self._authobj): self._authobj = self.getAuthenticator() userData = self._authobj.authenticate(user=self.__userid, password=self.__passwd) if not self.isAuthenticated(): return False self.__loggedUser = DamUser(self, userData) sUsrLogin = self.__loggedUser.loginName self.loadEnviron() self._authobj.userLogin = sUsrLogin return True def getAuthenticator(self): # sAuthFullName = self.getVar("project", "authenticator_class", "") # if not sAuthFullName: # return HellAuth() # else: # sAuthMod, sAuthClass = sAuthFullName.rsplit(".", 1) # exec("from {} import {}".format(sAuthMod, sAuthClass)) # # return eval(sAuthClass)(self) if not self.__authClass: return HellAuth() return self.__authClass(self) def isAuthenticated(self): if not self._authobj: return False bAuth = self._authobj.authenticated if not bAuth: logMsg("The project is not authenticated.", warning=True) return bAuth def loggedUser(self, **kwargs): logMsg(log='all') bForce = kwargs.get("force", False) if bForce and (not self.isAuthenticated()): self.authenticate() return self.__loggedUser def loadLibraries(self, noError=False): logMsg(log='all') bExists = self._instanceExists() if bExists and self.loadedLibraries: return if not self.isAuthenticated(): return if not self._checkLibraryPaths(noError=noError): return print "<{}> Loading libraries...".format(self) for drcLib in self.iterLibraries(dbNode=True, weak=False): if drcLib.primeProperty().viewItems: drcLib.updModelRow() else: drcLib.addModelRow() def iterLibraries(self, dbNode=True, weak=False, remember=True): for sSpace, sLibSection in self._iterLibrariesSpaceAndSection(): drcLib = self.getLibrary(sSpace, sLibSection, dbNode=dbNode, weak=weak, remember=remember) if drcLib: yield drcLib def getLibrary(self, sSpace, sLibSection, owner="", dbNode=True, weak=False, remember=True, tokens=None): logMsg(log='all') self._assertSpaceAndSection(sSpace, sLibSection) sFullLibName = DrcLibrary.makeFullName(owner, sSpace, sLibSection) drcLib = self.loadedLibraries.get(sFullLibName, None) if not drcLib: if tokens: sLibPath = self.getPath(sSpace, sLibSection, resVars=False, tokens=tokens) else: sLibPath = self.getPath(sSpace, sLibSection) drcLib = self.__libClass(sLibSection, sLibPath, sSpace, owner=owner, project=self, dbNode=dbNode, remember=remember) if weak: return drcLib if osp.isdir(sLibPath): return drcLib else: logMsg("No such '{}': '{}'.".format(sFullLibName, sLibPath), warning=True) return None return drcLib def makeCurrent(self): self.loadEnviron(force=True) m = sys.modules["__main__"] m.DAVOS_CURRENT_PROJECT = self def loadEnviron(self, force=False): sMsg = "\nLoading '{}' environment:".format(self.name) envFunc = hostSetEnvFunc() if envFunc: print sMsg, "(using {}.{})".format(envFunc.__module__, envFunc.__name__) else: print sMsg if self.__loggedUser: sUsrLogin = self.__loggedUser.loginName updEnv("DAVOS_USER", sUsrLogin, conflict="replace", usingFunc=envFunc) if inDevMode() and sUsrLogin == "sebastienc": updEnv("ZOMB_TOOL_PATH", r"\\ZOMBIWALK\Z2K_RnD\tool_testing", conflict="replace") updEnv("IN_SEB_MODE", "1", conflict="replace") else: updEnv("IN_SEB_MODE", "", conflict="replace") sConflict = "replace" if force else "keep" for sSpace, sLibSection in self._iterLibrariesSpaceAndSection(): sEnvVars = self.getVar(sLibSection, sSpace + "_" + "path_envars", default=()) for sVar in sEnvVars: updEnv(sVar, self.getPath(sSpace, sLibSection, resEnvs=False), conflict=sConflict, usingFunc=envFunc) self.loadConfigModule() def getAsset(self, sAstName): return DamAsset(self, name=sAstName) def getShot(self, sShotName): return DamShot(self, name=sShotName) def getPath(self, sSpace, sSection, pathVar="", tokens=None, default="NoEntry", **kwargs): bResVars = kwargs.get("resVars", True) bResEnvs = kwargs.get("resEnvs", True) sRcPath = "" if sSpace: sRcPath = self.getVar(sSection, sSpace + "_path", default=default, resVars=bResVars) if not sRcPath: return sRcPath if pathVar: try: sRcPath = pathJoin(sRcPath, self.getVar(sSection, pathVar)) except AttributeError: if default != "NoEntry": return default raise if bResEnvs: sRcPath = pathResolve(sRcPath) sFieldSet = set() if bResVars: # resolve vars from config sFieldSet = set(findFmtFields(sRcPath)) if sFieldSet: confTokens = self.getVar(sSection, pathVar + "_tokens", default={}) sConfFieldSet = set(confTokens.iterkeys()) for sField in sFieldSet: if sField in confTokens: continue value = self.getVar(sSection, sField, "") if value: sConfFieldSet.add(sField) else: value = '{' + sField + '}' confTokens[sField] = value if confTokens: sRcPath = sRcPath.format(**confTokens) sFieldSet -= sConfFieldSet # resolve remaining vars from input tokens if tokens: if not isinstance(tokens, dict): raise TypeError("argument 'tokens' must be of type <dict>. Got {}" .format(type(tokens))) sFieldSet = sFieldSet - set(tokens.iterkeys()) if sFieldSet: msg = ("Cannot resolve path: '{}'. \n\tMissing tokens: {}" .format(sRcPath, list(sFieldSet))) raise RuntimeError(msg) sRcPath = sRcPath.format(**tokens) return pathNorm(sRcPath, keepEndSlash=True) def getVar(self, sSection, sVarName, default="NoEntry", **kwargs): return self._confobj.getVar(sSection, sVarName, default=default, **kwargs) def getRcParam(self, sSection, sRcName, sParam, default="NoEntry"): rcSettings = self.getVar(sSection, "resource_settings", {}) if default == "NoEntry": return rcSettings[sRcName][sParam] else: return rcSettings.get(sRcName, {}).get(sParam, default) def getResource(self, sSpace, sRcSection, sRcName="", tokens=None, default="NoEntry", fail=False, **kwargs): sRcPath = self.getPath(sSpace, sRcSection, pathVar=sRcName, tokens=tokens, default=default, ) drcEntry = self.entryFromPath(sRcPath, **kwargs) if (not drcEntry) and fail: raise RuntimeError("No such resource path: '{}'".format(sRcPath)) return drcEntry def isEditableResource(self, sAbsPath, assertion=False): p = pathNorm(sAbsPath) sFileName = osp.basename(p) if not (sFileName and osp.splitext(p)[1]): if assertion: raise EnvironmentError("Invalid filename: '{}'".format(sFileName)) return False bPatternOk = False sPatrnList = self.getVar("project", "editable_file_patterns", ()) for sPatrn in sPatrnList: if fnmatch(sFileName, sPatrn): bPatternOk = True break if not bPatternOk: if assertion: raise EnvironmentError("Not in project's editable files: {}." .format(" ".join(sPatrnList))) return False drcEntry = self.entryFromPath(sAbsPath, dbNode=False) if drcEntry and drcEntry.isFile(): if drcEntry.parentDir().freeToPublish(): return True ctxData = self.contextFromPath(p) sSection = ctxData.get("section") sRcName = ctxData.get("resource") if not sRcName: if assertion: raise EnvironmentError("Not a configured resource.") return False bEditable = self.getRcParam(sSection, sRcName, "editable", default=True) if not bEditable: if assertion: raise EnvironmentError("Resource configured as non-editable: '{}.{}' ." .format(sSection, sRcName)) return False return True def rcFileFromPath(self, sFilePath, space="", library=None, fail=False, **kwargs): return self.entryFromPath(sFilePath, space=space, library=library, fail=fail, isFile=True, **kwargs) def entryFromPath(self, sEntryPath, space="", library=None, fail=False, **kwargs): bWarn = kwargs.pop("warn", True) bFile = kwargs.pop("isFile", False) bWeak = kwargs.pop("weak", False) if library: drcLib = library else: drcLib = self.libraryFromPath(sEntryPath, space=space) if not drcLib: sLibType = space.upper() if space else "KNOWN" sMsg = "Path NOT from {} library: '{}'".format(sLibType, sEntryPath) if fail: raise ValueError(sMsg) else: if bWarn: logMsg(sMsg, warning=True) return None try: if bFile: rcFile = drcLib._weakFile(sEntryPath, **kwargs) if bWeak: return rcFile return rcFile if rcFile.isFile() else None return drcLib.getEntry(sEntryPath, **kwargs) except Exception as e: if fail: raise else: if bWarn: logMsg(toStr(e), warning=True) return None def entryFromDbNode(self, dbnode, library=None, **kwargs): sDbPath = dbnode.getField('file') if library is None: library = self.libraryFromDbPath(sDbPath) drcEntry = library.entryFromDbPath(sDbPath, dbNode=False, **kwargs) if drcEntry: library._addDbNodeToCache(dbnode) drcEntry.refresh(simple=True, dbNode=False) return drcEntry def libraryFromDbPath(self, sDbPath): pubLibIter = (l for l in self.loadedLibraries.itervalues() if l.isPublic()) for pubLib in pubLibIter: try: pubLib.dbToAbsPath(sDbPath) except ValueError: continue return pubLib return None def libraryFromPath(self, sAbsPath, space="", anyUser=False): sAbsPath = pathNorm(sAbsPath) if space: rcLibIter = (l for l in self.loadedLibraries.itervalues() if (l.space == space)) else: rcLibIter = self.loadedLibraries.itervalues() for rcLib in rcLibIter: if rcLib.contains(sAbsPath): return rcLib if (space != "public") and anyUser: for sSpace, sLibSection in self._iterLibrariesSpaceAndSection(space="private"): sRawLibPath = self.getPath(sSpace, sLibSection, resVars=False) parseRes = pathParse(sRawLibPath, sAbsPath) if parseRes and parseRes.named: sOwner = parseRes.named["user_name"] return self.getLibrary(sSpace, sLibSection, owner=sOwner, tokens=parseRes.named, dbNode=False, weak=True, remember=True) return None def entityFromPath(self, sRcPath, fail=False, library=None): try: ctxData = self.contextFromPath(sRcPath, library=library) return self._entityFromContext(ctxData, fail=fail) except: if fail: raise else: return None def _entityFromContext(self, ctxData, fail=True): err = ValueError("Path does NOT match any entity: '{}'" .format(ctxData["abs_path"])) if "dam_entity" in ctxData: entity = ctxData["dam_entity"] if entity: return entity if fail: raise err else: return None if "section" not in ctxData: if fail: raise err else: return None entity = None sSection = ctxData['section'] if fail: sEntityCls = self.getVar(sSection, "entity_class") else: sEntityCls = self.getVar(sSection, "entity_class", default="") if sEntityCls: cls = importClass(sEntityCls, globals(), locals()) try: entity = cls(self, **ctxData) except: if fail: raise return entity def contextFromPath(self, entryObjOrPath, library=None, warn=True): if isinstance(entryObjOrPath, DrcEntry): drcEntry = entryObjOrPath library = drcEntry.library else: drcEntry = self.entryFromPath(entryObjOrPath, library=library, dbNode=False, weak=True, warn=warn) if not drcEntry: logMsg("no entry found for '{}'".format(entryObjOrPath), log="debug") return {"abs_path":entryObjOrPath, "rc_entry":None} elif not library: library = drcEntry.library sAbsPath = drcEntry.absPath() ctxData = {"abs_path":sAbsPath, "rc_entry":drcEntry} sFoundRcName = "" bExactRc = False if drcEntry == library: sSection = library.sectionName sSpace = library.space else: sSpace, sSection = self.sectionFromPath(sAbsPath, library=library) if not sSection: logMsg("no section found for '{}'".format(sAbsPath), log="debug") return ctxData bIsFile = isinstance(drcEntry, DrcFile) if not drcEntry.isPublic(): if bIsFile: pubEntry = drcEntry.getPublicFile(fail=True, weak=True, dbNode=False) else: pubEntry = drcEntry.getHomonym("public", weak=True) else: pubEntry = drcEntry pubLib = pubEntry.library if bIsFile and pubEntry.isVersionFile(): ctxData["version"] = pubEntry.versionFromName() pubEntry = pubEntry.getHeadFile(fail=True, dbNode=False) sPublicPath = pubEntry.absPath() sPubPathDirs = pathSplitDirs(sPublicPath) numPubDirs = len(sPubPathDirs) def sortValue(sRcPath): n = len(pathSplitDirs(sRcPath)) if n == numPubDirs: return sys.maxint else: return n sRcPathList = sorted(self.iterRcPaths("public", sSection, resVars=True), key=lambda x: sortValue(x[1]), reverse=True) sSectionPath = self.getPath("public", sSection, default="", resVars=False) if sSectionPath: sRcPathList.append(("", sSectionPath)) parseRes = None sCurPubPath = sPublicPath numCurPubDirs = numPubDirs while (not sFoundRcName) and (not pathEqual(sCurPubPath, pubLib.absPath())): for sRcName, sRcPath in sRcPathList: numRcDirs = len(pathSplitDirs(sRcPath)) if numRcDirs != numCurPubDirs: continue parseRes = pathParse(sRcPath, sCurPubPath) #print "\n", sRcPath, sCurPubPath, parseRes, sRcName if parseRes and parseRes.named: sFoundRcName = sRcName if numRcDirs == numPubDirs: bExactRc = True #print sRcName break sCurPubPath = osp.dirname(sCurPubPath) numCurPubDirs = len(pathSplitDirs(sCurPubPath)) if not parseRes: logMsg("no parsing results for '{}'".format(sCurPubPath), log="debug") return ctxData ctxData.update(parseRes.named) ctxData["section"] = sSection ctxData["space"] = sSpace ctxData["library"] = library if sFoundRcName: sRawRcPath = self.getPath("public", sSection, sFoundRcName, resVars=False) parseRes = pathParse(sRawRcPath, sPublicPath) ctxData.update((k, v) for k, v in parseRes.named.iteritems() if k not in ctxData) if bExactRc: ctxData["resource"] = sFoundRcName sStepDir = ctxData.get("step", "") if sStepDir: sSgStepDct = self.getVar(sSection, "sg_step_map", default={}) if sStepDir in sSgStepDct: ctxData['sg_step'] = sSgStepDct[sStepDir] damEntity = None if "name" in ctxData: damEntity = self._entityFromContext(ctxData, fail=False) ctxData["dam_entity"] = damEntity return ctxData def sectionFromPath(self, sEntryPath, library=None): sEntryPath = normCase(sEntryPath) sEntryPathDirs = pathSplitDirs(normCase(sEntryPath)) sectionDataList = sorted(self.iterSectionPaths(library=library), key=lambda x: len(x[2]), reverse=True) for sSpace, sSection, sSectionPath in sectionDataList: if pathStartsWith(sEntryPath, sSectionPath, pathSplits=sEntryPathDirs): return sSpace, sSection return "", "" def iterSectionPaths(self, library=None): sSpaceList = LIBRARY_SPACES #sLibPath = "" if library: sSpaceList = (library.space,) #sLibPath = normCase(library.absPath()) for sSection, _ in self._confobj.listSections(): if sSection == "project": continue for sSpace in sSpaceList: sSectionPath = self.getPath(sSpace, sSection, default="") if sSectionPath: if library: if not library.contains(sSectionPath): continue yield sSpace, sSection, sSectionPath def versionFileFromPrivatePath(self, sPrivFilePath, fail=False): privFile = self.entryFromPath(sPrivFilePath, space="private") if not privFile: raise ValueError("No such private file: '{}'".format(sPrivFilePath)) v = privFile.versionFromName() if v is None: raise ValueError("Could not get version number from filename: '{}'" .format(privFile.name)) pubFile = privFile.getPublicFile(fail=True) return pubFile.getVersionFile(v, fail=fail) def publishEditedVersion(self, sSrcFilePath, **kwargs): bReturnDict = kwargs.pop("returnDict", False) bUploadApart = kwargs.pop("uploadApart", True) res = self.assertEditedVersion(sSrcFilePath) mainPubFile = res["public_file"] mainPrivFile = res["private_file"] privOutcomeDct = dict(res["outcome_files"]) mainPubFile.ensureLocked() privOutcomeList = privOutcomeDct.values() pubOutcomeList = tuple(f.getPublicFile(fail=True) for f in privOutcomeList) outcomePairs = zip(pubOutcomeList, privOutcomeList) sUploadedRc = mainPubFile.getParam("sg_uploaded_movie", "") sMoviePathRc = mainPubFile.getParam("sg_path_to_movie", "") if privOutcomeDct: if sUploadedRc and (sUploadedRc not in privOutcomeDct): sMsg = (u"Resource('{}') to upload to shotgun is NOT in outcomes: {}" .format(sUploadedRc, privOutcomeDct.keys())) logMsg(sMsg, warning=True) if sMoviePathRc and (sMoviePathRc not in privOutcomeDct): sMsg = (u"Resource('{}') to upload to shotgun is NOT in outcomes: {}" .format(sUploadedRc, privOutcomeDct.keys())) logMsg(sMsg, warning=True) sgVersion = None iNxtVers = mainPubFile.currentVersion + 1 try: for pubFile, privFile in outcomePairs: pubFile.assertEditedVersion(privFile, version=iNxtVers, outcomes=False) pubFile.ensureLocked(autoLock=True) mainVersFile, sgVersion = mainPubFile.publishEditedFile(mainPrivFile, checkLock=False, **kwargs) except: for pubFile in pubOutcomeList: pubFile.restoreLockState() raise uploadMovieFile = privOutcomeDct.get(sUploadedRc, None) pathToMovieFile = privOutcomeDct.get(sMoviePathRc, None) for pubFile, privFile in outcomePairs: outcomeVersFile, _ = pubFile.publishEditedFile(privFile, comment=mainPubFile.comment, version=iNxtVers, checkLock=False) if pathToMovieFile and (pathToMovieFile == privFile): pathToMovieFile = outcomeVersFile if sgVersion: if pathToMovieFile: self.updateSgEntity(sgVersion, sg_path_to_movie=pathToMovieFile.envPath()) if uploadMovieFile: self.uploadSgVersion(sgVersion, uploadMovieFile.absPath(), apart=bUploadApart) if not bReturnDict: return mainPrivFile, privOutcomeDct else: return {"private_file":mainPrivFile, "private_outcome_files":privOutcomeDct, "public_file":mainPubFile, "public_outcome_files":pubOutcomeList, "version_file":mainVersFile, "sg_version":sgVersion, } def assertEditedVersion(self, sSrcFilePath, **kwargs): privFile = self.entryFromPath(sSrcFilePath, space="private", fail=True) pubFile = privFile.getPublicFile(fail=True) res = {"private_file":privFile, "public_file":pubFile} res.update(pubFile.assertEditedVersion(privFile, **kwargs)) return res def getDependencyTypes(self, sSection, sRcName=""): dependDct = self.getVar(sSection, "dependency_types", {}) if not sRcName: return dependDct rcsSettings = self.getVar(sSection, "resource_settings") if sRcName in rcsSettings: rcDepDct = rcsSettings[sRcName].get("dependency_types", {}) conflicts = set(dependDct.iterkeys()) & set(rcDepDct.iterkeys()) if conflicts: sMsg = ("Dependencies defined twice for '{}' section and '{}' resource: {}" .format(sSection, sRcName, ", ".join(conflicts))) raise EnvironmentError(sMsg) dependDct.update(rcDepDct) return dependDct def iterSgSteps(self, sEntityType=""): stepList = self._shotgundb.getSteps() for stepInfo in stepList: if sEntityType and (stepInfo['entity_type'] == sEntityType): yield stepInfo def createSgVersion(self, sVersionName, sgEntity, sgTask, sComment, sFilePath, **kwargs): shotgundb = self._shotgundb if not shotgundb: return None sgVersion = shotgundb.createVersion(sgEntity["type"], sgEntity, sVersionName, sgTask, sComment, sFilePath, **kwargs) return sgVersion @setWaitCursor def uploadSgVersion(self, sgVersion, sMediaPath, **kwargs): return self._shotgundb.uploadVersion(sgVersion, sMediaPath, **kwargs) def publishSgVersions(self, versionFilesList): headFileSet = set() for versFile in versionFilesList: headFile = versFile.getHeadFile(fail=True) headFileSet.add(headFile) if len(headFileSet) > 1: raise ValueError("Given files should be versions of the same file ! Got {}." .format(tuple(headFileSet))) headFile = headFileSet.pop() ctxData = headFile.contextFromPath() sSection = ctxData.get("section") sRcName = ctxData.get("resource") if not sRcName: raise AssertionError("No such configured resource: {}".format(headFile)) bSgVersion = self.getRcParam(sSection, sRcName, 'create_sg_version', default=False) if not bSgVersion: raise RuntimeError("Public file not configured to have shotgun versions: {} !" .format(headFile)) damEntity = headFile.getEntity(fail=True, ctxData=ctxData) sgVersList = damEntity.findSgVersions(resourceName=sRcName) sSgVersPathList = tuple(d["sg_source_file"] for d in sgVersList) sgVersionData = headFile._beginPublishSgVersion() sgTask = sgVersionData.get("sg_task") if (not sgTask): raise RuntimeError("No Shotgun Task given or selected !") newSgVersions = versionFilesList[:] for i, versionFile in enumerate(versionFilesList): sgVersionData = headFile._beginPublishSgVersion(versionFile, sgVersionData) sgVersion = None if versionFile.envPath() in sSgVersPathList: print "Shotgun Version already exists for {}.".format(versionFile) else: sgVersion = versionFile.createSgVersion(sgVersionData) print "created shotgun version", sgVersion newSgVersions[i] = sgVersion return newSgVersions def getSgVersion(self, versionFile): shotgundb = self._shotgundb if not shotgundb: return None filters = [['project', 'is', shotgundb.getProjectInfo()], ['sg_source_file', 'is', versionFile.envPath()]] fields = ['code', 'sg_current_release_version', 'sg_task', 'sg_source_file', 'sg_status_list'] return shotgundb.sg.find_one("Version", filters, fields) def findSgVersions(self, sgEntity=None, rcEntry=None, sgTask=None, moreFilters=None, moreFields=None, limit=0): shotgundb = self._shotgundb if rcEntry: assert rcEntry.isPublic(), "Given file must be public." #assert not rcEntry.isVersionFile(), "Given file must not be a version." filters = [['project', 'is', shotgundb.getProjectInfo()], ] if sgEntity is not None: filters.append(['entity', 'is', sgEntity]) order = [{'field_name':'created_at', 'direction':'desc'}] if sgTask: filters.append(['task', 'is', sgTask]) if rcEntry: if rcEntry.isVersionFile(): versFile = rcEntry else: versFile = rcEntry.getVersionFile(0, weak=True) sEnvPath = versFile.envPath() sBasePath, sExt = osp.splitext(sEnvPath) sBasePath = sBasePath.rsplit('-v', 1)[0] + '-v' filters += [['sg_source_file', 'starts_with', sBasePath], ['sg_source_file', 'ends_with', sExt]] order = [{'field_name':'sg_source_file', 'direction':'desc'}] if moreFilters: filters.extend(moreFilters) fields = ['code', 'sg_current_release_version', 'sg_task', 'sg_source_file', 'sg_status_list'] if moreFields: fields.extend(moreFields) return shotgundb.sg.find("Version", filters, fields, order=order, limit=limit) def updateSgEntity(self, sgEntity, **data): return self._shotgundb.updateEntity(sgEntity, **data) def findDbNodes(self, sQuery="", **kwargs): sBaseQuery = u"file:/^{}/i" sDamasPath = self.getVar("project", "damas_root_path") sBaseQuery = sBaseQuery.format(sDamasPath) sFullQuery = " ".join((sBaseQuery, sQuery)) return self._db.findNodes(sFullQuery, **kwargs) def linkResourceFiles(self, targetFile, sourceFileList, data=None): drcFileDct = {} def storeFile(drcFile): drcFileDct[osp.normcase(drcFile.dbPath())] = drcFile drcFileList = [targetFile] + sourceFileList headFileList = drcFileList[:] for i, drcFile in enumerate(drcFileList): if drcFile.isVersionFile(): headFile = None try: headFile = drcFile.getHeadFile(dbNode=False, fail=True) except RuntimeError as e: print toStr(e) headFileList[i] = headFile if headFile: storeFile(headFile) self.dbNodesFromEntries(headFileList) versFileList = drcFileList[:] for i, drcFile in enumerate(drcFileList): if drcFile.isVersionFile(): continue try: versFile = drcFile.assertLatestFile(refresh=False, returnVersion=True) except EnvironmentError as e: logMsg(e.message, warning=True) continue if versFile: versFileList[i] = versFile self.dbNodesFromEntries(versFileList) headTrgtId = headFileList[0]._dbnode.id_ versTrgtId = versFileList[0]._dbnode.id_ targetIds = (headTrgtId, versTrgtId) graphNodes = self._damasdb.graph(targetIds) srcIds = {} for n in graphNodes: if ('src_id' in n) and ('tgt_id' in n): srcIds.setdefault(n['tgt_id'], set()).add(n['src_id']) def prunedDbPaths(fileList): for i, f in enumerate(fileList): dbNode = f.loadDbNode(fromDb=False) if i == 0: trgtId = dbNode.id_ else: if not dbNode: continue if dbNode.id_ in srcIds.get(trgtId, []): print "already linked '{}' -> '{}'".format(dbNode.file, fileList[0]._dbnode.file) continue yield f.dbPath() # linkIds = tuple(n["_id"] for d in graphNodes if ('src_id' in d) and ('tgt_id' in d)) # for id_ in linkIds: # self._damasdb.delete(id_) if data is None: data = {"link_type":"undefined"} links = {} sDbPathList = list(prunedDbPaths(headFileList)) if len(sDbPathList) > 1: res = self._damasdb.link(sDbPathList[0], sDbPathList[1:], data) if res: links.update(res) sDbPathList = list(prunedDbPaths(versFileList)) if len(sDbPathList) > 1: res = self._damasdb.link(sDbPathList[0], sDbPathList[1:], data) if res: links.update(res) print "done", links return targetIds def dbNodesFromEntries(self, rcEntryList, load=True): dbNodeList = len(rcEntryList) * [None] entryDct = {} for i, drcEntry in enumerate(rcEntryList): entryDct.setdefault(drcEntry.dbPath(), []).append((i, drcEntry)) # sQueryList = list("REGEX_^{}".format(p) for p in entryDct.iterkeys()) # for s in sQueryList: # print s sQueryList = entryDct.keys() mgQuery = {"file": {"$in":sQueryList}} ids = self._damasdb.search_mongo(mgQuery, None, None, None) if not ids: return dbNodeList for dbNode in self._db.nodeForIds(ids): for i, each in enumerate(entryDct.get(dbNode.file, [])): inIdx, drcEntry = each if load and i == 0: drcEntry._cacheDbNode(dbNode) dbNodeList[inIdx] = dbNode return dbNodeList def iterConfigOutcomes(self, sSection): rcsSettings = self.getVar(sSection, "resource_settings") for sRcName, settings in rcsSettings.iteritems(): outcomes = settings.get("outcomes") if outcomes: yield sRcName, outcomes def _evalSyncRules(self, in_sRuleList): sAllSites = set(self.listAllSites()) sRuleList = in_sRuleList if len(sRuleList) == 1: sRule = sRuleList[0] if sRule == "all_sites": sRuleList = sAllSites elif sRule == "no_sync": sRuleList = [] elif sRule not in sAllSites: raise ValueError("Invalid rule: '{}'".format(sRule)) sSiteList = set(sRuleList) if sSiteList: sBadSites = sSiteList - sAllSites if sBadSites: raise ValueError("Unknown sites: {}".format(",".join(sBadSites))) syncData = dict((s, "1" if s in sSiteList else None) for s in sAllSites) return syncData def listAllSites(self): return list(self.getVar("project", "all_sync_sites")) def getCurrentSite(self): sSite = os.environ.get("DAVOS_SITE") if not sSite: raise EnvironmentError("DAVOS_SITE not defined.") else: sSiteList = self.listAllSites() if sSite not in sSiteList: raise EnvironmentError("Invalid DAVOS_SITE: '{}'. Expected one of: {}." .format(sSite, ", ".join(sSiteList))) return sSite def listAllSgAssets(self, includeOmitted=False, moreFilters=None, moreFields=None): shotgundb = self._shotgundb sg = shotgundb.sg sSectionList = [] confobj = self._confobj for sSection, _ in confobj.listSections(): if not confobj.getVar(sSection, "template_dir", ""): continue sSectionList.extend(confobj.getVar(sSection, "aliases", ())) filters = [["project", "is", shotgundb.getProjectInfo()], ["sg_asset_type", "in", sSectionList] ] if not includeOmitted: filters += [["sg_status_list", "is_not", "omt"], ] if moreFilters: filters.extend(moreFilters) fields = ["code", "sg_asset_type", "sg_status_list"] if moreFields: fields.extend(moreFields) allSgAstList = sg.find("Asset", filters, fields, [{'field_name':'sg_asset_type', 'direction':'asc'}, {'field_name':'code', 'direction':'asc'}]) return allSgAstList def listAllSgShots(self, includeOmitted=False, moreFilters=None, moreFields=None): shotgundb = self._shotgundb sg = shotgundb.sg filters = [["project", "is", shotgundb.getProjectInfo()], ["sg_sequence", "is_not", None], ] if not includeOmitted: filters += [["sg_status_list", "is_not", "omt"], ["sg_sequence.Sequence.sg_status_list", "is_not", "omt"] ] if moreFilters: filters.extend(moreFilters) fields = ["code", "sg_sequence", "sg_status_list", "sg_cut_in", "sg_cut_out", "sg_cut_duration"] if moreFields: fields.extend(moreFields) allSgShotList = sg.find("Shot", filters, fields, [{'field_name':'sg_sequence', 'direction':'asc'}, {'field_name':'code', 'direction':'asc'}]) return allSgShotList def iterShotDirsNotInSg(self): allSgShots = self.listAllSgShots(includeOmitted=True) sSgShotCodeList = tuple(sh["code"] for sh in allSgShots) shotLib = self.getLibrary("public", "shot_lib") for seqDir in shotLib.iterChildren(): for shotDir in seqDir.iterChildren(): if shotDir.name not in sSgShotCodeList: yield shotDir def iterAssetPrefixes(self): for sSection in self.getVar("asset_lib", "asset_types"): sAstPrefix = self.getVar(sSection, "prefix", "") if sAstPrefix: yield sAstPrefix def listUiClasses(self): return DrcLibrary.listUiClasses() def setItemModel(self, model): self._itemmodel = model def iterChildren(self): return self.loadedLibraries.itervalues() def iterRcPaths(self, sSpace, sSection, tokens=None, **kwargs): allTreeVars = self.getVar(sSection, "all_tree_vars", ()) #print sSection, len(allTreeVars), len(set(allTreeVars)), set(allTreeVars) for sTreeVar in allTreeVars: p = self.getPath(sSpace, sSection, pathVar=sTreeVar, tokens=tokens, **kwargs) if not p: continue yield (sTreeVar, p) def _checkLibraryPaths(self, noError=False): sMissingPathList = [] sSamePathDct = {} for sSpace, sLibSection in self._iterLibrariesSpaceAndSection(): sLibFullName = DrcLibrary.makeFullName(sSpace, sLibSection) sLibPath = self.getPath(sSpace, sLibSection) sSamePathDct.setdefault(normCase(sLibPath), []).append(sLibFullName) if not osp.isdir(sLibPath): if sSpace == "public": msg = u"No such '{}': '{}'.".format(sLibFullName, sLibPath) if noError: logMsg(msg, warning=True) else: raise EnvironmentError(msg) elif sSpace == "private": sMissingPathList.append((sLibFullName, sLibPath)) sSamePathList = tuple((p, libs) for p, libs in sSamePathDct.iteritems() if len(libs) > 1) if sSamePathList: msgIter = (u"'{}': {}".format(p, libs) for p, libs in sSamePathList) msg = u"Libraries using the same path:\n\n " + u"\n ".join(msgIter) raise EnvironmentError(msg) if sMissingPathList: msgIter = (u"'{}': '{}'".format(n, p) for n, p in sMissingPathList) msg = u"No such libraries:\n" + u"\n".join(msgIter) sConfirm = confirmDialog(title='WARNING !', message=msg + u"\n\nShould I create them ?", button=['Yes', 'No'], defaultButton='No', cancelButton='No', dismissString='No', icon="warning") if sConfirm == 'No': return False for _, p in sMissingPathList: os.makedirs(p) return True def getTemplatePath(self, sSection, pathVar="" , **kwargs): sTemplateDir = self.getPath("template", sSection, "template_dir", default="", **kwargs) if not sTemplateDir: return "" sEntityDir = self.getPath("template", sSection, "entity_dir", **kwargs) p = self.getPath("template", sSection, pathVar=pathVar, **kwargs) p = pathRedir(p, sEntityDir, sTemplateDir) return p def _checkTemplatePaths(self, out_invalidPaths, sSection="project"): sTemplateDir = self.getTemplateDir(sSection) if sTemplateDir: sEntityDir = self.getPath("template", sSection, "entity_dir") for _, sRcPath in self.iterRcPaths("template", sSection): if not pathStartsWith(sRcPath, sEntityDir): continue sRcPath = pathRedir(sRcPath, sEntityDir, sTemplateDir) if osp.exists(sRcPath): continue out_invalidPaths.append(sRcPath) for sChildSection in self.getVar(sSection, "child_sections", ()): self._checkTemplatePaths(out_invalidPaths, sChildSection) def getTemplateDir(self, sSection): return self.getPath("template", sSection, "template_dir", default="") def _assertSpaceAndSection(self, sSpace, sLibSection): if sSpace not in LIBRARY_SPACES: raise ValueError("No such space: '{}'. Expected: {}" .format(sSpace, LIBRARY_SPACES)) if sLibSection not in self.__confLibraries: msg = ("No such library: '{}'. \n\n\tKnown libraries: {}" .format(sLibSection, self.__confLibraries)) raise ValueError(msg) def assertMayaVersion(self, iCurMayaVersion): iProjMayaVersion = self.getVar("project", "maya_version") iCurMayaVersion /= 100 if iCurMayaVersion != iProjMayaVersion: sMsg = ("{} requires Maya {}, but you're running Maya {} !" .format(self, iProjMayaVersion, iCurMayaVersion)) raise EnvironmentError(sMsg) def _iterLibrariesSpaceAndSection(self, space=LIBRARY_SPACES, fullName=False): sSpaceList = argToTuple(space) for sLibSection in self.__confLibraries: for sSpace in sSpaceList: if fullName: yield DrcLibrary.makeFullName(sSpace, sLibSection) else: yield (sSpace, sLibSection) def _inSebMode(self): if not self._loggedUser: return False sUsrLogin = self.__loggedUser.loginName return (inDevMode() and sUsrLogin == "sebastienc") def __initShotgun(self): # sFullName = self.getVar("project", "shotgun_class", "") # if not sFullName: # return #sgCls = importClass(sFullName, globals(), locals()) from zomblib.shotgunengine import ShotgunEngine print "connecting to shotgun..." self._shotgundb = ShotgunEngine(self.name) def __initDamas(self): sDamasServerAddr = self.getVar("project", "damas_server_addr", "") from .dbtypes import DummyDbCon dummydb = DummyDbCon(sDamasServerAddr) if not sDamasServerAddr: self._damasdb = dummydb return if inDevMode(): print "connecting to damas server:", sDamasServerAddr else: print "connecting to damas..." import damas damasdb = damas.http_connection(sDamasServerAddr) try: damasdb.verify() except IOError as e: logMsg(toStr(e), warning=True) self._damasdb = dummydb else: self._damasdb = damasdb def __repr__(self): cls = self.__class__ try: sRepr = ("{0}('{1}')".format(cls.__name__, self.name)) except AttributeError: sRepr = cls.__name__ return sRepr