+ def MoveFile(self, file, newFolderPath):
+ return self.MoveFiles([file], newFolderPath)
+
+
+ def MoveFiles(self, files, newFolderPath):
+ filePaths = []
+ isArray = isinstance(newFolderPath, type([]))
+ for i in range(len(files)):
+ if isArray:
+ files[i].logicalFolder = newFolderPath[i]
+ else:
+ files[i].logicalFolder = newFolderPath
+ filePaths.append(files[i].filePath)
+
+ self.UpdateAllViews(hint = ("remove", self, filePaths))
+ self.UpdateAllViews(hint = ("add", self, filePaths, []))
+ self.Modify(True)
+ return True
+
+
+ def UpdateFilePath(self, oldFilePath, newFilePath):
+ file = self.GetModel().FindFile(oldFilePath)
+ self.RemoveFile(oldFilePath)
+ if file:
+ self.AddFile(newFilePath, file.logicalFolder, file.type, file.name)
+ else:
+ self.AddFile(newFilePath)
+
+
+ def RemoveInvalidPaths(self):
+ """Makes sure all paths project knows about are valid and point to existing files. Removes and returns list of invalid paths."""
+
+ invalidFileRefs = []
+
+ fileRefs = self.GetFileRefs()
+
+ for fileRef in fileRefs:
+ if not os.path.exists(fileRef.filePath):
+ invalidFileRefs.append(fileRef)
+
+ for fileRef in invalidFileRefs:
+ fileRefs.remove(fileRef)
+
+ return [fileRef.filePath for fileRef in invalidFileRefs]
+
+ def SetStageProjectFile(self):
+ self._stageProjectFile = True
+
+ def ArchiveProject(self, zipdest, tmpdir=None, stagedir=None):
+ """Stages the application files in tmpdir, and zips the stagedir, creating a zipfile that has the projectname, in zipdest. Returns path to zipfile. Optionally, pass in stagedir and we assume the app is already staged at stagedir (we don't stage again in that case)."""
+ if not stagedir:
+ if not tmpdir:
+ raise AssertionError("'tmpdir' must be set when not passing 'stagedir' so we know where to stage the app")
+ stagedir = self.StageProject(tmpdir)
+ if os.path.exists(zipdest):
+ raise AssertionError("Cannot archive project, %s already exists" % zipdest)
+ fileutils.zip(zipdest, stagedir)
+
+ return zipdest
+
+
+ def StageProject(self, tmpdir):
+ """ Copies all files that project knows about into staging location. Files that live outside of the project dir are copied into the root of the stage dir, and their recorded file path is updated. Files that live inside of the project dir keep their relative path. Generates .dpl file into staging dir. Returns path to staging dir."""
+
+ projname = self.GetProjectName()
+ stagedir = os.path.join(tmpdir, projname)
+ fileutils.remove(stagedir)
+ os.makedirs(stagedir)
+
+ # remove invalid files from project
+ self.RemoveInvalidPaths()
+
+ # required so relative paths are written correctly when .dpl file is
+ # generated below.
+ self.SetFilename(os.path.join(stagedir,
+ os.path.basename(self.GetFilename())))
+ projectdir = self.GetModel().homeDir
+
+ # Validate paths before actually copying, and populate a dict
+ # with src->dest so copying is easy.
+ # (fileDict: ProjectFile instance -> dest path (string))
+ fileDict = self._ValidateFilePaths(projectdir, stagedir)
+
+ # copy files to staging dir
+ self._StageFiles(fileDict)
+
+ # it is unfortunate we require this. it would be nice if filepaths
+ # were only in the project
+ self._FixWsdlAgFiles(stagedir)
+
+ # generate .dpl file
+ dplfilename = projname + deploymentlib.DEPLOYMENT_EXTENSION
+ dplfilepath = os.path.join(stagedir, dplfilename)
+ self.GenerateDeployment(dplfilepath, productionDeployment=True)
+
+ if self._stageProjectFile:
+ # save project so we get the .agp file. not required for deployment
+ # but convenient if user wants to open the deployment in the IDE
+ agpfilename = projname + PROJECT_EXTENSION
+ agpfilepath = os.path.join(stagedir, agpfilename)
+ f = None
+ try:
+ f = open(agpfilepath, "w")
+ # setting homeDir correctly is required for the "figuring out
+ # relative paths" logic when saving the project
+ self.GetModel().homeDir = stagedir
+ projectlib.save(f, self.GetModel(), productionDeployment=True)
+ finally:
+ try:
+ f.close()
+ except: pass
+
+ return stagedir
+
+
+ def _FixWsdlAgFiles(self, stagedir):
+ """For each wsdlag file in the stagedir:
+ Ensure the referenced wsdl file lives in root of stagedir. This
+ should be the case if wsdl is part of project (and staging has run).
+ If it is not at root of stagedir, copy it. Then update path in
+ wsdlag."""
+ files = os.listdir(stagedir)
+ for f in files:
+ if f.endswith(WsdlAgEditor.WsdlAgDocument.WSDL_AG_EXT):
+ wsdlagpath = os.path.join(stagedir, f)
+ fileObject = None
+ mod = False
+ try:
+ fileObject = open(wsdlagpath)
+ serviceref = WsdlAgEditor.load(fileObject)
+ if hasattr(serviceref, "filePath") and serviceref.filePath:
+ mod = self.UpdateServiceRefFilePath(stagedir,serviceref)
+ finally:
+ try:
+ fileObject.close()
+ except:
+ pass
+
+ # no need to save the file if we did not change anything
+ if not mod: continue
+
+ # write the wsdlag file
+ fileObject = open(wsdlagpath)
+ try:
+ serviceref = WsdlAgEditor.save(fileObject, serviceref)
+ finally:
+ try:
+ fileObject.close()
+ except:
+ pass
+
+
+ def UpdateServiceRefFilePath(self, stagedir, serviceref):
+ """Returns True if serviceref.filePath has been updated, False otherwise."""
+ if not os.path.exists(serviceref.filePath):
+ # should be an error? wrong place to
+ # validate that referenced file exists
+ # could print warning
+ return False
+
+ # If the referenced file is in stagedir already, there's nothing to do
+ if fileutils.hasAncestorDir(serviceref.filePath, stagedir):
+ return False
+
+ # The path points outside of stagedir.
+
+ # Check if we already have the referenced wsdl file at root, should be
+ # the case if the referenced wsdl is part of project
+ # Copy it if we don't have it
+ relPath = os.path.basename(serviceref.filePath)
+ stagepath = os.path.join(stagedir, relPath)
+ if not os.path.exists(stagepath):
+ fileutils.copyFile(serviceref.filePath, stagepath)
+
+ serviceref.filePath = relPath
+
+ return True
+
+
+ def _StageFiles(self, fileDict):
+ """Copy files to staging directory, update filePath attr of project's ProjectFile instances."""
+
+ # fileDict: ProjectFile instance -> dest path (string)
+
+ for fileRef, fileDest in fileDict.items():
+ fileutils.copyFile(fileRef.filePath, fileDest)
+ fileRef.filePath = fileDest
+
+ def _ValidateFilePaths(self, projectdir, stagedir):
+ """If paths validate, returns a dict mapping ProjectFile to destination path. Destination path is the path the file needs to be copied to for staging. If paths don't validate, throws an IOError.
+ With our current slightly simplistic staging algorithm, staging will not work iff the project has files outside of the projectdir with names (filename without path) that:
+ - match filenames of files living at the root of the project.
+ - are same as those of any other file that lives outside of the projectdir.
+
+ We have this limitation because we move any file that lives outside of the project dir into the root of the stagedir (== copied project dir). We could make this smarter by either giving files unique names if we detect a collistion, or by creating some directory structure instead of putting all files from outside of the projectdir into the root of the stagedir (== copied projectdir)."""
+
+ # ProjectFile instance -> dest path (string)
+ rtn = {}
+
+ projectRootFiles = sets.Set() # live at project root
+ foreignFiles = sets.Set() # live outside of project
+
+ fileRefsToDeploy = self.GetFileRefs()
+
+ for fileRef in fileRefsToDeploy:
+ relPath = fileutils.getRelativePath(fileRef.filePath, projectdir)
+ filename = os.path.basename(fileRef.filePath)
+ if not relPath: # file lives outside of project dir...
+
+ # do we have another file with the same name already?
+ if filename in foreignFiles:
+ raise IOError("More than one file with name \"%s\" lives outside of the project. These files need to have unique names" % filename)
+ foreignFiles.add(filename)
+ fileDest = os.path.join(stagedir, filename)
+ else:
+ # file lives somewhere within the project dir
+ fileDest = os.path.join(stagedir, relPath)
+ if not os.path.dirname(relPath):
+ projectRootFiles.add(filename)
+
+ rtn[fileRef] = fileDest
+
+ # make sure we won't collide with a file that lives at root of
+ # projectdir when moving files into project
+ for filename in foreignFiles:
+ if filename in projectRootFiles:
+ raise IOError("File outside of project, \"%s\", cannot have same name as file at project root" % filename)
+
+ # REVIEW stoens@activegrid.com 19-Oct-05 --
+ # We could also validate that user does not already have a .dpl file
+ # since we're going to generate one...
+
+ return rtn
+
+
+ def RenameFolder(self, oldFolderPath, newFolderPath):
+ for file in self.GetModel()._files:
+ if file.logicalFolder == oldFolderPath:
+ file.logicalFolder = newFolderPath
+ self.UpdateAllViews(hint = ("rename folder", self, oldFolderPath, newFolderPath))
+ self.Modify(True)
+ return True
+
+