зеркало из https://github.com/mozilla/pjs.git
373 строки
12 KiB
Plaintext
373 строки
12 KiB
Plaintext
(*
|
||
*
|
||
* 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
|
||
-- property pSourceTree : "Homeward:Work:Raptor:src:"
|
||
property pSourceTree : "Morbeus:Projects:Raptor:src:"
|
||
|
||
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
|
||
|
||
(* uses "sort" scripting addition to sort a list of strings. *)
|
||
on sortList(aList)
|
||
if (aList {}) 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 "") 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
|
||
|
||
(* both of the following depend on ":" as the delimiter character. *)
|
||
|
||
on folderFromPath(filePath)
|
||
return ((filePath's text items 1 thru ((count of filePath's text items) - 1)) as string) & ":"
|
||
end folderFromPath
|
||
|
||
on fileFromPath(filePath)
|
||
return last text item of filePath
|
||
end fileFromPath
|
||
|
||
(* CW Pro IDE Interface Handlers. *)
|
||
|
||
on openProject(aProjectFile)
|
||
tell application "CodeWarrior IDE 3.3"
|
||
-- activate
|
||
open aProjectFile
|
||
end tell
|
||
end openProject
|
||
|
||
(* 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
|
||
|
||
on closeProject(aProjectFile)
|
||
tell application "CodeWarrior IDE 3.3"
|
||
Close Project
|
||
end tell
|
||
end closeProject
|
||
|
||
on getTargets()
|
||
set targetList to {}
|
||
set nameList to {}
|
||
tell application "CodeWarrior IDE 3.3"
|
||
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
|
||
|
||
(* 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. *)
|
||
on getTargetFiles(targetKey)
|
||
set targetFiles to {}
|
||
tell application "CodeWarrior IDE 3.3"
|
||
set currentProject to project document 1
|
||
set currentTarget to (target targetKey of currentProject)
|
||
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
|
||
end tell
|
||
return sortList(targetFiles)
|
||
end getTargetFiles
|
||
|
||
on addTargetFile(targetFile, targetList)
|
||
tell application "CodeWarrior IDE 3.3"
|
||
add (project document 1) new target file with data {targetFile} to targets targetList
|
||
end tell
|
||
end addTargetFile
|
||
|
||
global gCurrentTarget
|
||
|
||
on setCurrentTarget(currentTargetName)
|
||
if (gCurrentTarget currentTargetName) then
|
||
set gCurrentTarget to currentTargetName
|
||
tell application "CodeWarrior IDE 3.3"
|
||
Set Current Target currentTargetName
|
||
end tell
|
||
end if
|
||
end setCurrentTarget
|
||
|
||
on removeTargetFile(targetFile)
|
||
tell application "CodeWarrior IDE 3.3"
|
||
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
|
||
|
||
on ModifyReadOnly(aProjectFile)
|
||
if (not gProjectModified) then
|
||
set gProjectModified to true
|
||
-- so CodeWarrior will notice, must close the file before MROing it.
|
||
closeProject(aProjectFile)
|
||
mro aProjectFile
|
||
openProject(aProjectFile)
|
||
selectProject(aProjectFile)
|
||
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 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)
|
||
selectProject(projectFile)
|
||
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 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.
|
||
tell application "CodeWarrior IDE 3.3"
|
||
-- 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
|
||
set manifestPath to (choose file with prompt "Choose a TOC file to process." of type {"TEXT"}) as text
|
||
ReconcileProject(pSourceTree, projectPath, manifestPath)
|
||
end run
|