1998-12-13 21:12:19 +00:00
|
|
|
|
(*
|
|
|
|
|
*
|
|
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
|
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
|
|
|
* http://www.mozilla.org/NPL/
|
|
|
|
|
*
|
|
|
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
|
* NPL.
|
|
|
|
|
*
|
|
|
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
|
|
|
* Reserved.
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
(*
|
|
|
|
|
MANIFESTOLib - Reconciles a CW Project file with an external table of contents file.
|
|
|
|
|
|
|
|
|
|
Uses merge sort, one pass per target.
|
|
|
|
|
|
|
|
|
|
by Patrick C. Beard <beard@netscape.com>
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
(* Global Configuration Properties *)
|
|
|
|
|
|
|
|
|
|
property pShowReport : true
|
1998-12-24 19:30:15 +00:00
|
|
|
|
-- property pSourceTree : "Homeward:Work:Raptor:src:"
|
|
|
|
|
property pSourceTree : "Morbeus:Projects:Raptor:src:"
|
1998-12-13 21:12:19 +00:00
|
|
|
|
|
|
|
|
|
on swapDelimiters(newDelimiters)
|
|
|
|
|
set oldDelimiters to get AppleScript's text item delimiters
|
|
|
|
|
set AppleScript's text item delimiters to newDelimiters
|
|
|
|
|
return oldDelimiters
|
|
|
|
|
end swapDelimiters
|
|
|
|
|
|
|
|
|
|
on setDelimiters(newDelimiters)
|
|
|
|
|
set AppleScript's text item delimiters to newDelimiters
|
|
|
|
|
end setDelimiters
|
|
|
|
|
|
|
|
|
|
-- replaces oldChar with newChar in a string.
|
|
|
|
|
on replace(aString, oldChar, newChar)
|
|
|
|
|
set newString to ""
|
|
|
|
|
repeat with aChar in (every character of aString)
|
|
|
|
|
if (contents of aChar = oldChar) then
|
|
|
|
|
set newString to newString & newChar
|
|
|
|
|
else
|
|
|
|
|
set newString to newString & aChar
|
|
|
|
|
end if
|
|
|
|
|
end repeat
|
|
|
|
|
return newString
|
|
|
|
|
end replace
|
|
|
|
|
|
1998-12-24 19:30:15 +00:00
|
|
|
|
(* uses "sort" scripting addition to sort a list of strings. *)
|
1998-12-13 21:12:19 +00:00
|
|
|
|
on sortList(aList)
|
|
|
|
|
if (aList <20> {}) then
|
|
|
|
|
return sort aList
|
|
|
|
|
else
|
|
|
|
|
return {}
|
|
|
|
|
end if
|
|
|
|
|
end sortList
|
|
|
|
|
|
|
|
|
|
-- reads .toc file into a list.
|
|
|
|
|
on readManifestFile(sourceTree, manifestFile)
|
|
|
|
|
set oldDelimiters to swapDelimiters(return)
|
|
|
|
|
set fileRef to false
|
|
|
|
|
set fileLines to {}
|
|
|
|
|
try
|
|
|
|
|
set fileRef to (open for access manifestFile without write permission)
|
|
|
|
|
-- read entire file into memory, use text items to delimit lines.
|
|
|
|
|
set fileContents to (read fileRef)
|
|
|
|
|
repeat with lineRef in (every text item of fileContents)
|
|
|
|
|
-- ignore lines that start with "#" or are empty.
|
|
|
|
|
set fileLine to (contents of lineRef)
|
|
|
|
|
if (fileLine <20> "") and not (fileLine starts with "#") then
|
|
|
|
|
set fileLines to fileLines & (sourceTree & replace(fileLine, "/", ":"))
|
|
|
|
|
end if
|
|
|
|
|
end repeat
|
|
|
|
|
on error
|
|
|
|
|
-- ignore errors.
|
|
|
|
|
end try
|
|
|
|
|
if (fileRef is not false) then close access fileRef
|
|
|
|
|
setDelimiters(oldDelimiters)
|
|
|
|
|
return sortList(fileLines)
|
|
|
|
|
end readManifestFile
|
|
|
|
|
|
1998-12-24 19:30:15 +00:00
|
|
|
|
(* both of the following depend on ":" as the delimiter character. *)
|
|
|
|
|
|
1998-12-13 21:12:19 +00:00
|
|
|
|
on folderFromPath(filePath)
|
|
|
|
|
return ((filePath's text items 1 thru ((count of filePath's text items) - 1)) as string) & ":"
|
|
|
|
|
end folderFromPath
|
|
|
|
|
|
1998-12-24 19:30:15 +00:00
|
|
|
|
on fileFromPath(filePath)
|
|
|
|
|
return last text item of filePath
|
|
|
|
|
end fileFromPath
|
|
|
|
|
|
1998-12-13 21:12:19 +00:00
|
|
|
|
(* CW Pro IDE Interface Handlers. *)
|
|
|
|
|
|
|
|
|
|
on openProject(aProjectFile)
|
1998-12-24 19:30:15 +00:00
|
|
|
|
tell application "CodeWarrior IDE 3.3"
|
1998-12-13 21:12:19 +00:00
|
|
|
|
-- activate
|
|
|
|
|
open aProjectFile
|
|
|
|
|
end tell
|
|
|
|
|
end openProject
|
|
|
|
|
|
1998-12-24 19:30:15 +00:00
|
|
|
|
(* forces the named project file to be the front window. *)
|
|
|
|
|
on selectProject(aProjectFile)
|
|
|
|
|
set projectName to fileFromPath(aProjectFile as text)
|
|
|
|
|
tell application "CodeWarrior IDE 3.3"
|
|
|
|
|
if (name of window 1 is not projectName) then
|
|
|
|
|
select window projectName
|
|
|
|
|
end if
|
|
|
|
|
end tell
|
|
|
|
|
end selectProject
|
|
|
|
|
|
1998-12-13 21:12:19 +00:00
|
|
|
|
on closeProject(aProjectFile)
|
1998-12-24 19:30:15 +00:00
|
|
|
|
tell application "CodeWarrior IDE 3.3"
|
1998-12-13 21:12:19 +00:00
|
|
|
|
Close Project
|
|
|
|
|
end tell
|
|
|
|
|
end closeProject
|
|
|
|
|
|
|
|
|
|
on getTargets()
|
|
|
|
|
set targetList to {}
|
|
|
|
|
set nameList to {}
|
1998-12-24 19:30:15 +00:00
|
|
|
|
tell application "CodeWarrior IDE 3.3"
|
1998-12-13 21:12:19 +00:00
|
|
|
|
set currentProject to project document 1
|
|
|
|
|
repeat with targetIndex from 1 to (count of targets of currentProject)
|
|
|
|
|
set currentTarget to (target targetIndex of currentProject)
|
|
|
|
|
set targetList to targetList & {currentTarget}
|
|
|
|
|
set nameList to nameList & {name of currentTarget}
|
|
|
|
|
end repeat
|
|
|
|
|
return {target:targetList, names:nameList}
|
|
|
|
|
end tell
|
|
|
|
|
end getTargets
|
|
|
|
|
|
1998-12-24 19:30:15 +00:00
|
|
|
|
(* uses "info for" scripting addition, to return the file type of a path. *)
|
|
|
|
|
on getFileType(aFilePath)
|
|
|
|
|
return file type of (info for alias aFilePath)
|
|
|
|
|
end getFileType
|
|
|
|
|
|
|
|
|
|
(* returns all "TEXT" files of the named target. *)
|
1998-12-13 21:12:19 +00:00
|
|
|
|
on getTargetFiles(targetKey)
|
|
|
|
|
set targetFiles to {}
|
1998-12-24 19:30:15 +00:00
|
|
|
|
tell application "CodeWarrior IDE 3.3"
|
1998-12-13 21:12:19 +00:00
|
|
|
|
set currentProject to project document 1
|
|
|
|
|
set currentTarget to (target targetKey of currentProject)
|
1998-12-24 19:30:15 +00:00
|
|
|
|
try
|
|
|
|
|
-- workaround for CW IDE 3.X bug, loop until error encountered.
|
|
|
|
|
set fileIndex to 1
|
|
|
|
|
repeat until false
|
|
|
|
|
set targetFile to (target file fileIndex of currentTarget)
|
|
|
|
|
-- only consider text files, since other platforms won't be managing binaries.
|
|
|
|
|
-- also, only consider if target file is directly linked.
|
|
|
|
|
if (linked of targetFile) then
|
|
|
|
|
set targetFilePath to (Access Paths of targetFile)
|
|
|
|
|
tell me
|
|
|
|
|
if (getFileType(targetFilePath) = "TEXT") then
|
|
|
|
|
set targetFiles to targetFiles & {targetFilePath}
|
|
|
|
|
end if
|
|
|
|
|
end tell
|
|
|
|
|
end if
|
|
|
|
|
set fileIndex to (fileIndex + 1)
|
|
|
|
|
end repeat
|
|
|
|
|
on error msg
|
|
|
|
|
-- display dialog msg & " file count = " & fileIndex
|
|
|
|
|
end try
|
1998-12-13 21:12:19 +00:00
|
|
|
|
end tell
|
|
|
|
|
return sortList(targetFiles)
|
|
|
|
|
end getTargetFiles
|
|
|
|
|
|
|
|
|
|
on addTargetFile(targetFile, targetList)
|
1998-12-24 19:30:15 +00:00
|
|
|
|
tell application "CodeWarrior IDE 3.3"
|
1998-12-13 21:12:19 +00:00
|
|
|
|
add (project document 1) new target file with data {targetFile} to targets targetList
|
|
|
|
|
end tell
|
|
|
|
|
end addTargetFile
|
|
|
|
|
|
|
|
|
|
global gCurrentTarget
|
|
|
|
|
|
|
|
|
|
on setCurrentTarget(currentTargetName)
|
|
|
|
|
if (gCurrentTarget <20> currentTargetName) then
|
|
|
|
|
set gCurrentTarget to currentTargetName
|
1998-12-24 19:30:15 +00:00
|
|
|
|
tell application "CodeWarrior IDE 3.3"
|
1998-12-13 21:12:19 +00:00
|
|
|
|
Set Current Target currentTargetName
|
|
|
|
|
end tell
|
|
|
|
|
end if
|
|
|
|
|
end setCurrentTarget
|
|
|
|
|
|
|
|
|
|
on removeTargetFile(targetFile)
|
1998-12-24 19:30:15 +00:00
|
|
|
|
tell application "CodeWarrior IDE 3.3"
|
1998-12-13 21:12:19 +00:00
|
|
|
|
Remove Files {targetFile}
|
|
|
|
|
end tell
|
|
|
|
|
end removeTargetFile
|
|
|
|
|
|
|
|
|
|
on quote(aString)
|
|
|
|
|
return "'" & aString & "'"
|
|
|
|
|
end quote
|
|
|
|
|
|
|
|
|
|
on listContains(aList, anItem)
|
|
|
|
|
repeat with listItem in aList
|
|
|
|
|
if (contents of listItem = anItem) then
|
|
|
|
|
return true
|
|
|
|
|
end if
|
|
|
|
|
end repeat
|
|
|
|
|
return false
|
|
|
|
|
end listContains
|
|
|
|
|
|
|
|
|
|
on showList(aList)
|
|
|
|
|
choose from list aList with prompt "List:" with empty selection allowed
|
|
|
|
|
end showList
|
|
|
|
|
|
|
|
|
|
global gProjectModified
|
|
|
|
|
|
1998-12-24 19:30:15 +00:00
|
|
|
|
on ModifyReadOnly(aProjectFile)
|
1998-12-13 21:12:19 +00:00
|
|
|
|
if (not gProjectModified) then
|
|
|
|
|
set gProjectModified to true
|
|
|
|
|
-- so CodeWarrior will notice, must close the file before MROing it.
|
1998-12-24 19:30:15 +00:00
|
|
|
|
closeProject(aProjectFile)
|
|
|
|
|
mro aProjectFile
|
|
|
|
|
openProject(aProjectFile)
|
|
|
|
|
selectProject(aProjectFile)
|
1998-12-13 21:12:19 +00:00
|
|
|
|
end if
|
|
|
|
|
end ModifyReadOnly
|
|
|
|
|
|
|
|
|
|
on makeStream(itemList)
|
|
|
|
|
return {streamList:itemList, streamCount:count itemList, streamIndex:0}
|
|
|
|
|
end makeStream
|
|
|
|
|
|
|
|
|
|
(* true is used as the end of stream value. *)
|
|
|
|
|
property pEOS : true
|
|
|
|
|
|
|
|
|
|
on advanceStream(stream)
|
|
|
|
|
set itemCount to (streamCount of stream)
|
|
|
|
|
set itemIndex to (streamIndex of stream)
|
|
|
|
|
if (itemIndex < itemCount) then
|
|
|
|
|
set itemIndex to (itemIndex + 1)
|
|
|
|
|
set (streamIndex of stream) to itemIndex
|
|
|
|
|
return (item itemIndex of streamList of stream)
|
|
|
|
|
else
|
|
|
|
|
return pEOS
|
|
|
|
|
end if
|
|
|
|
|
end advanceStream
|
|
|
|
|
|
|
|
|
|
-- returns true if str2 is INFINITELY great, or str1 is less than str2.
|
|
|
|
|
on precedes(str1, str2)
|
|
|
|
|
return (str2 = pEOS) or ((str1 <20> pEOS) and (str1 < str2))
|
|
|
|
|
end precedes
|
|
|
|
|
|
|
|
|
|
on get_current_application()
|
|
|
|
|
return last text item of ((path to current application) as text)
|
|
|
|
|
end get_current_application
|
|
|
|
|
|
|
|
|
|
on get_frontmost_application()
|
|
|
|
|
return last text item of ((path to frontmost application) as text)
|
|
|
|
|
end get_frontmost_application
|
|
|
|
|
|
|
|
|
|
on activate_application(applicationName)
|
|
|
|
|
tell application "Finder"
|
|
|
|
|
set applicationProcess to (application process applicationName)
|
|
|
|
|
set frontmost of applicationProcess to true
|
|
|
|
|
end tell
|
|
|
|
|
end activate_application
|
|
|
|
|
|
|
|
|
|
on ReconcileProject(sourceTree, projectPath, manifestoPath)
|
|
|
|
|
-- so we can easily strip off file names from paths.
|
|
|
|
|
set oldDelimiters to swapDelimiters(":")
|
|
|
|
|
|
|
|
|
|
-- initialize globals.
|
|
|
|
|
set gCurrentTarget to ""
|
|
|
|
|
set gProjectModified to false
|
|
|
|
|
|
|
|
|
|
-- convert paths to aliases.
|
|
|
|
|
set projectFile to alias projectPath
|
|
|
|
|
set manifestFile to alias manifestoPath
|
|
|
|
|
|
|
|
|
|
-- read the MANIFESTO file into a list of paths.
|
|
|
|
|
set manifestContents to readManifestFile(sourceTree, manifestFile)
|
|
|
|
|
-- return manifestContents
|
|
|
|
|
|
|
|
|
|
-- now, start processing the file items, ensuring that the project contains all items.
|
|
|
|
|
openProject(projectFile)
|
1998-12-24 19:30:15 +00:00
|
|
|
|
selectProject(projectFile)
|
1998-12-13 21:12:19 +00:00
|
|
|
|
set targetsList to getTargets()
|
|
|
|
|
set targetNames to names of targetsList
|
|
|
|
|
|
|
|
|
|
if (pShowReport) then
|
|
|
|
|
set theReport to ""
|
|
|
|
|
set addedFiles to ""
|
|
|
|
|
set removedFiles to ""
|
|
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
-- push current application to front for speed.
|
|
|
|
|
-- set frontmostApplication to get_frontmost_application()
|
|
|
|
|
-- set currentApplication to get_current_application()
|
|
|
|
|
-- activate_application(currentApplication)
|
|
|
|
|
|
|
|
|
|
-- reconcile all targets with the MANIFEST file.
|
|
|
|
|
-- this loop should be recoded in PERL for speed.
|
|
|
|
|
-- IDEA: with sorted lists, can scan both lists, like a merge sort, and make one pass per target.
|
|
|
|
|
repeat with targetNameRef in targetNames
|
|
|
|
|
-- switch targets because getTargetFiles now checks to see if file is linked in current target.
|
|
|
|
|
set targetName to (contents of targetNameRef)
|
|
|
|
|
set targetFiles to getTargetFiles(targetName)
|
|
|
|
|
-- hopefully, this list test is fast.
|
|
|
|
|
if (targetFiles <20> manifestContents) then
|
|
|
|
|
-- return {count targetFiles, count manifestContents, targetFiles, manifestContents}
|
|
|
|
|
-- make sure the project file is modifiable.
|
|
|
|
|
ModifyReadOnly(projectFile)
|
|
|
|
|
setCurrentTarget(targetName)
|
|
|
|
|
set targetStream to makeStream(targetFiles)
|
|
|
|
|
set targetItem to advanceStream(targetStream)
|
|
|
|
|
set manifestStream to makeStream(manifestContents)
|
|
|
|
|
set manifestItem to advanceStream(manifestStream)
|
|
|
|
|
repeat until (manifestItem is pEOS) and (targetItem is pEOS)
|
|
|
|
|
-- display dialog "m: " & manifestItem & ", t: " & targetFileItem
|
|
|
|
|
if (manifestItem = targetItem) then
|
|
|
|
|
-- items match, advance both.
|
|
|
|
|
set manifestItem to advanceStream(manifestStream)
|
|
|
|
|
set targetItem to advanceStream(targetStream)
|
|
|
|
|
else
|
|
|
|
|
-- return {manifestItem, targetItem}
|
|
|
|
|
if (precedes(manifestItem, targetItem)) then
|
|
|
|
|
-- we have an item in manifest, not in project, so we have to add it to the targets.
|
|
|
|
|
-- display dialog "adding " & manifestItem
|
|
|
|
|
addTargetFile(manifestItem, targetNames)
|
|
|
|
|
if pShowReport then
|
|
|
|
|
set addedFiles to addedFiles & ("# " & (last text item of manifestItem) & return)
|
|
|
|
|
end if
|
|
|
|
|
set manifestItem to advanceStream(manifestStream)
|
|
|
|
|
else
|
|
|
|
|
-- we have an item not in manifest, but in project, so it must be removed from this target.
|
|
|
|
|
-- display dialog "removing " & targetItem
|
|
|
|
|
removeTargetFile(targetItem)
|
|
|
|
|
if pShowReport then
|
|
|
|
|
set removedFiles to removedFiles & ("# " & targetName & " - " & (last text item of targetItem) & return)
|
|
|
|
|
end if
|
|
|
|
|
set targetItem to advanceStream(targetStream)
|
|
|
|
|
end if
|
|
|
|
|
end if
|
|
|
|
|
end repeat
|
|
|
|
|
end if
|
|
|
|
|
end repeat
|
|
|
|
|
|
|
|
|
|
-- activate_application(frontmostApplication)
|
|
|
|
|
|
|
|
|
|
-- commit the project changes, and optionally display a report.
|
1998-12-24 19:30:15 +00:00
|
|
|
|
tell application "CodeWarrior IDE 3.3"
|
1998-12-13 21:12:19 +00:00
|
|
|
|
-- leave project open for compilation phase?
|
|
|
|
|
Close Project
|
|
|
|
|
if pShowReport then
|
|
|
|
|
if addedFiles is not "" then set theReport to ("# Added files: " & return & addedFiles)
|
|
|
|
|
if removedFiles is not "" then set theReport to theReport & ("# Removed files: " & return & removedFiles)
|
|
|
|
|
if (theReport is "") then set theReport to (" # Project is up to date." & return)
|
|
|
|
|
-- display dialog theReport buttons {"OK"} default button "OK"
|
|
|
|
|
end if
|
|
|
|
|
end tell
|
|
|
|
|
|
|
|
|
|
-- restore AppleScript's delimiters.
|
|
|
|
|
setDelimiters(oldDelimiters)
|
|
|
|
|
|
|
|
|
|
-- return 0 to indicate no error.
|
|
|
|
|
return theReport
|
|
|
|
|
end ReconcileProject
|
|
|
|
|
|
|
|
|
|
on run
|
|
|
|
|
-- when run interactively,
|
|
|
|
|
-- ask user which project/MANIFEST files to use.
|
|
|
|
|
set projectPath to (choose file with prompt "Choose a CW Project file." of type {"MMPr"}) as text
|
1998-12-24 19:30:15 +00:00
|
|
|
|
set manifestPath to (choose file with prompt "Choose a TOC file to process." of type {"TEXT"}) as text
|
1998-12-13 21:12:19 +00:00
|
|
|
|
ReconcileProject(pSourceTree, projectPath, manifestPath)
|
|
|
|
|
end run
|