"""Keep your project files synchronized with files on disk. WARNING: this script requires the following layout: 1) Your project file (.wpu) must be in the root directory of your project. 2) Your project must consist of all "valid" files in that root directory (including any "valid" subdirectories), where "valid" is controlled by ExclDirs, ExclFiles and InclFiles, set below. IF YOUR PROJECTS ARE NOT LAID OUT LIKE THIS THEN DO NOT USE THIS SCRIPT. You might wish to try my script "addremovefiles.py" instead; it makes no assumptions about your project layout. To install: - Place this file somewhere on your scripts path (see Preferences:Scripting for the path). To use: - Bring up the contextual menu in the project pane. - Select "Synch files". Output: - A list of all files added and removed appears in the Messages panel. Warning: you may have to select "Scripts" instead of "All" to see these messages (due to a known bug in WingIDE 2.0.3). - Brief messages appear in the status bar at the bottom of the window. Thanks to Ken Kinder for giving me the idea with projectupkeep 0.2. To Do: - Use WingIDE's idea of what files to include and exclude (is it practical to get hold of this information?) - It would be safer to not rely on the project file to locate the root directory, but I'm not sure what to do about it. History: 2005-06-22 Stephan Deibel corrected so Project context menu item appears 2005-05-25 Russell Owen based on projectupkeep 0.2 by Ken Kinder I am not sure if Ken Kinder would claim copyright for this code, since it is so loosely based on projectupkeep. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------- With minor modifications by Wingware """ import glob import os import sets import wingapi # The following lists control which directories are excluded # which files are excluded and which files are included. # They are applied in order, thus: # - Files in excluded directories are never examined # - Excluded files are never checked for inclusion # # The entries are fnmatch patterns: # * matches everything # ? matches any single character # [seq] matches any character in seq # [!seq] matches any character not in seq # for more details see the fnmatch module # # ExclFiles can be left blank unless you want # to excluded particular source files for some reason) ExclDirs = [ '*.svn', 'CVS', '#*#', '.#*', 'build', ] ExclFiles = [ ] InclFiles = [ '*.py', '*.c', '*.c++', '*.cpp', '*.h', '*.htm', '*.html', '*.sh', '*.txt', ] class ProjectScript: def __init__(self): self.app = wingapi.gApplication def showMsg(self, msg): print msg self.app.SetStatusMessage(msg) class SynchFilesScript(ProjectScript): def __call__(self): """Synchronize the files in a project to the files on disk. """ self.proj = self.app.GetProject() try: filesAdded = self._addFiles() nAdded = len(filesAdded) filesRemoved = self._removeFiles() nRemoved = len(filesRemoved) self.showMsg("Synch files: added %s and removed %s files" % (nAdded, nRemoved)) except RuntimeError, e: self.showMsg("Synch files failed: %s" % (e,)) def _addFiles(self): """Scan the disk for project files and add any files that are not currently in the project. Return the list of files added. """ desFileSet = sets.Set() projFile = self.proj.GetFilename() if not projFile: raise RuntimeError("No project file") startPath = os.path.dirname(projFile) self.showMsg("Synch files: scanning \"%s\" for files to add" % startPath) for root, dirs, files in os.walk(startPath): # Remove directories we don't want to walk. # Warning: we must actually modify the list "dirs" # for the exclusion to have any effect. dirsCopy = dirs[:] for d in dirsCopy: for exclPattern in ExclDirs: if glob.fnmatch.fnmatch(d, exclPattern): dirs.remove(d) break # add desired files to desFileSet for f in files: for exclPattern in ExclFiles: if glob.fnmatch.fnmatch(f, exclPattern): # excluded file; on to the next break else: # not exluded; see if included for inclPattern in InclFiles: if glob.fnmatch.fnmatch(f, inclPattern): # included file; add full path to desFileSet fullPath = os.path.join(root, f) desFileSet.add(fullPath) break currFiles = self.proj.GetAllFiles() filesToAdd = list(desFileSet - sets.Set(currFiles)) filesToAdd.sort() if len(filesToAdd) > 0: self.showMsg("Synch files: adding %s files" % (len(filesToAdd)),) for fname in filesToAdd: print fname self.proj.AddFiles(filesToAdd) else: self.showMsg("Synch files: no files to add") return filesToAdd def _removeFiles(self): """Check the current project files and remove any that are not on disk. Return the list of files removed. """ self.showMsg("Synch files: scanning for files to remove") currFiles = self.proj.GetAllFiles() filesToRemove = [] for filePath in currFiles: if not os.path.exists(filePath): filesToRemove.append(filePath) filesToRemove.sort() if len(filesToRemove) > 0: self.showMsg("Synch files: removing %s files" % (len(filesToRemove),)) for fname in filesToRemove: print fname self.proj.RemoveFiles(filesToRemove) else: self.showMsg("Synch files: no files to remove") return filesToRemove sfs = SynchFilesScript() def synch_files(): sfs() synch_files.contexts = [ wingapi.kContextProject(10), ]