"""Basic support for keeping your project files synchronized
with files on disk.
To install:
- Place this file somewhere on your scripts path,
as set in Preferences:Scripting.
To use:
- Bring up the contextual menu for an item in the project pane.
- Select "Add new files" to recursively scan for new files,
If the selected item is a folder, then new files will be searched
for recursively in this folder.
If the selected item is a file, then new files will be searched
for recursively from the parent directory of the file.
- Select "Remove deleted files" to remove any files
from your project that cannot be found on disk.
Output:
- A list of all files added or 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.
Based on projectupkeep 0.2 by Ken Kinder. Changes include:
- Added a script to remove files that are missing on disk
(e.g. have been deleted).
- Runs much faster (but not in the background).
- Uses 3 short lists instead of one long "stop list"
to control which files and directories to include.
- Uses the sets module, so requires Python 2.3 or later.
To Do:
- Use WingIDE's idea of what files to include and exclude
(is it practical to get hold of this information?)
- If there is ever a way to tell if a project
is supposed to include exactly the files in
a particular directory (e.g. a python package)
then scan that entire directory instead of just
the directory the user clicks on.
History:
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 AddNewFilesScript(ProjectScript):
def start(self, begPath):
"""Start scanning for new files.
If begPath is a directory, recursively search the directory.
If begPath is a file, recursively search its parent directory.
"""
if not os.path.isdir(begPath):
begPath = os.path.dirname(begPath)
self.begPath = begPath
self.showMsg('Add new files: scanning: %s' % (begPath,))
self.proj = self.app.GetProject()
self.desFileSet = sets.Set()
self._scanForFiles()
def startAvailable(self, update_path=wingapi.kArgFilename):
return len(update_path) > 0
def _addFiles(self):
"""Add any new files found in self.desFileSet to the project.
"""
currFiles = self.proj.GetAllFiles()
filesToAdd = list(self.desFileSet - sets.Set(currFiles))
filesToAdd.sort()
if len(filesToAdd) > 0:
print "Add new files: adding:"
for fname in filesToAdd:
print fname
self.proj.AddFiles(filesToAdd)
self.showMsg('Add new files: added %s files' % (len(filesToAdd)),)
def _scanForFiles(self):
"""Scan the disk for project files starting from self.begPath
Add all files found to self.desFileSet.
"""
for root, dirs, files in os.walk(self.begPath):
# 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)
self.desFileSet.add(fullPath)
break
self._addFiles()
class RemoveDeletedFilesScript(ProjectScript):
def start(self):
self.showMsg('Remove deleted files: running')
self.proj = self.app.GetProject()
currFiles = self.proj.GetAllFiles()
filesToRemove = []
for filePath in currFiles:
if not os.path.exists(filePath):
filesToRemove.append(filePath)
filesToRemove.sort()
if len(filesToRemove) > 0:
print "Remove deleted files: removing:"
for fname in filesToRemove:
print fname
self.proj.RemoveFiles(filesToRemove)
self.showMsg('Remove deleted files: removed %s files' % (len(filesToRemove),))
_addNewFilesScript = AddNewFilesScript()
def add_new_files(begPath=wingapi.kArgFilename):
_addNewFilesScript.start(begPath[0])
add_new_files.contexts = [
wingapi.kContextProject(10),
]
add_new_files.available = _addNewFilesScript.startAvailable
_removeDeletedFilesScript = RemoveDeletedFilesScript()
def remove_deleted_files(begPath=wingapi.kArgFilename):
_removeDeletedFilesScript.start()
remove_deleted_files.contexts = [
wingapi.kContextProject(10),
]