MakeDoCmdUtilsImpl.Mesa
Copyright Ó 1991 by Xerox Corporation. All rights reserved.
Mike Spreitzer, February 9, 1987 2:28:06 pm PST
Last tweaked by Mike Spreitzer on November 6, 1990 5:04 pm PST
Eduardo Pelegri-Llopart May 22, 1989 2:34:55 pm PDT
JKF January 11, 1989 10:33:06 am PST
Willie-s, December 6, 1991 6:04 pm PST
Michael Plass, November 27, 1991 10:32 am PST
DIRECTORY
BasicTime,
Commander,
DFCachingUtilities USING [CreateEnumerationCache, EnumerationCache, FileSpec, FSErrorOnDF, FullEnumerateDFContents, Miss, NestItem],
DFUtilities,
FileNames USING [StripVersionNumber],
FS USING [ComponentPositions, Error, ErrorGroup, ExpandName, FileInfo, GetWDir],
IO,
MakeDo,
MakeDoPorting USING [verifyAttachments],
MakeDoPrivate USING [NodeClassRep],
Process USING [CheckForAbort],
RefTab USING [Create, Erase, Fetch, Pairs, Ref, Store],
Rope,
RopeHash,
SymTab USING [Create, Erase, Fetch, Insert, Pairs, Ref, Store];
MakeDoCmdUtilsImpl:
CEDAR
PROGRAM
IMPORTS BasicTime, DFCachingUtilities, DFUtilities, FileNames, FS, IO, MakeDo, MakeDoPorting, Process, RefTab, Rope, RopeHash, SymTab
EXPORTS MakeDo, MakeDoPrivate
SHARES MakeDoPrivate =
BEGIN
ROPE: TYPE = Rope.ROPE;
RefTable: TYPE = MakeDo.RefTable;
AnaCacheKey: TYPE ~ REF AnaCacheKeyPrivate;
AnaCacheKeyPrivate:
TYPE
~ RECORD [wDir, fullDF: ROPE, created: BasicTime.GMT];
AnaCacheEntry: TYPE ~ REF AnaCacheEntryPrivate;
AnaCacheEntryPrivate:
TYPE ~
RECORD [
deps: ACDepList,
verifyGoals, imports, others: MakeDo.RefTable
];
ACDepList: TYPE ~ LIST OF RECORD [dfName: ROPE, created: BasicTime.GMT];
anaCache: PUBLIC RefTab.Ref ¬ RefTab.Create[hash: ACKHash, equal: ACKEqual];
ACKHash:
PROC [key:
REF
ANY]
RETURNS [hash:
CARDINAL]
--RefTab.HashProc-- ~ {
ack: AnaCacheKey ~ NARROW[key];
hash ¬ LOOPHOLE[ack.created, CARD] MOD 65536;
hash ¬ RopeHash.FromRope[rope: ack.wDir, case: TRUE, seed: hash];
hash ¬ RopeHash.FromRope[rope: ack.fullDF, case: TRUE, seed: hash];
RETURN};
ACKEqual:
PROC [key1, key2:
REF
ANY]
RETURNS [
BOOL]
--RefTab.EqualProc-- ~ {
ack1: AnaCacheKey ~ NARROW[key1];
ack2: AnaCacheKey ~ NARROW[key2];
IF ack1.created # ack2.created THEN RETURN [FALSE];
IF NOT ack1.wDir.Equal[ack2.wDir] THEN RETURN [FALSE];
IF NOT ack1.fullDF.Equal[ack2.fullDF] THEN RETURN [FALSE];
RETURN [TRUE]};
EmptyCmdUtils:
PUBLIC
PROC ~ {
anaCache.Erase[];
RETURN};
AnalyzeDFFile:
PUBLIC
PROC [dfName:
ROPE, goals, supportFiles: MakeDo.RefTable, modifiable: MakeDo.ModifiabilitySpec, doToVerifyGoals, doToOtherOwns, doToImports: MakeDo.DoToFile] = {
ack: AnaCacheKey ¬ NEW [AnaCacheKeyPrivate ¬ [FS.GetWDir[], NIL, BasicTime.nullGMT]];
ace: AnaCacheEntry;
need: BOOL;
Pass:
PROC [table: MakeDo.RefTable, do: MakeDo.DoToFile] ~ {
PassFile:
PROC [key, val:
REF
ANY]
RETURNS [stop:
BOOL ¬
FALSE] ~ {
n: MakeDo.Node ~ MakeDo.NarrowToNode[key];
[] ¬ RefTab.Store[
SELECT do FROM makeGoal => goals, makeModifiable => modifiable, makeSupport => supportFiles, ENDCASE => ERROR,
n,
$T];
IF do=makeGoal THEN [] ¬ modifiable.Store[n, $T];
RETURN [FALSE]};
IF do#ignore AND table.Pairs[PassFile] THEN ERROR;
RETURN};
[fullFName: ack.fullDF, created: ack.created] ¬ FS.FileInfo[dfName];
ace ¬ NARROW[anaCache.Fetch[ack].val];
need ¬ ace=NIL;
IF debugLog#NIL THEN debugLog.PutFL["Ana[%g, %g, %g] => %g\n", LIST[[rope[ack.wDir]], [rope[ack.fullDF]], [time[ack.created]], [boolean[ace#NIL]]]];
IF
NOT need
THEN {
FOR acds: ACDepList ¬ ace.deps, acds.rest
WHILE acds#
NIL
AND
NOT need
DO
created: BasicTime.GMT ¬ BasicTime.nullGMT;
[created: created] ¬ FS.FileInfo[acds.first.dfName !FS.Error => CONTINUE];
IF created # acds.first.created
THEN {
IF debugLog#NIL THEN debugLog.PutFL["Ana[%g].%g = %g # %g\n", LIST[[rope[dfName]], [rope[acds.first.dfName]], [rope[MakeDo.FmtTime[acds.first.created]]], [rope[MakeDo.FmtTime[created]]]]];
need ¬ TRUE};
ENDLOOP};
IF need THEN [] ¬ anaCache.Store[ack, ace ¬ MakeACE[ack.fullDF, ack.created]];
Pass[ace.verifyGoals, doToVerifyGoals];
Pass[ace.imports, doToImports];
Pass[ace.others, doToOtherOwns];
RETURN};
MakeACE:
PROC [dfName:
ROPE, dfCreated: BasicTime.
GMT]
RETURNS [ace: AnaCacheEntry] = {
start: BasicTime.GMT ~ BasicTime.Now[];
Do:
PROC [verless:
ROPE, table: RefTab.Ref] ~ {
n: MakeDo.Node ~ MakeDo.GetNode[verless, MakeDo.fileClass, TRUE];
[] ¬ table.Store[n, $T];
RETURN};
Recurse:
PROC [dfName:
ROPE, wanted: DFUtilities.Date, privates, imported:
BOOL] ~ {
readonly: BOOL ¬ FALSE;
created: BasicTime.GMT ¬ wanted.gmt;
Consume:
PROC [item:
REF
ANY]
RETURNS [stop:
BOOL ¬
FALSE] ~ {
Process.CheckForAbort[];
WITH item
SELECT
FROM
di: REF DFUtilities.DirectoryItem => readonly ¬ di.readOnly;
fi:
REF DFUtilities.FileItem => {
table: RefTab.Ref ~ IF readonly OR imported THEN ace.imports ELSE IF fi.verifyRoot THEN ace.verifyGoals ELSE ace.others;
Do[FileNames.StripVersionNumber[fi.name], table];
};
ii:
REF DFUtilities.ImportsItem =>
SELECT ii.form
FROM
exports => IF recurseOnExports[ii.exported] THEN Recurse[VerlessShort[ii.path1], ii.date, FALSE, TRUE];
all => Recurse[VerlessShort[ii.path1], ii.date, TRUE, TRUE];
list => {
FOR i:
NAT
IN [0 .. ii.list.nEntries)
DO
Do[ii.list[i].name, ace.imports];
ENDLOOP};
ENDCASE => ERROR;
ii: REF DFUtilities.IncludeItem => Recurse[VerlessShort[ii.path1], ii.date, TRUE, imported];
ci: REF DFUtilities.CommentItem => NULL;
wi: REF DFUtilities.WhiteSpaceItem => NULL;
ENDCASE => ERROR;
RETURN};
IF wanted.format#explicit
THEN {
[created: created] ¬ FS.FileInfo[dfName !FS.Error => CONTINUE];
ace.deps ¬ CONS[[dfName, created], ace.deps]};
DFUtilities.ParseFromFile[dfName, Consume, [filterB:
IF privates
THEN all
ELSE public, filterC: all], created !
DFUtilities.FileSyntaxError => {
MakeDo.Warning[IO.PutFR["DF syntax error (%g) near %g; parsing of %g abandoned", [rope[reason]], [integer[position]], [rope[dfName]] ]];
CONTINUE};
FS.Error => {
MakeDo.Warning[IO.PutFLR["FS.Error[%g, %g] while analyzing %g%g - skipping the rest of that DF", LIST[[atom[error.code]], [rope[error.explanation]], [rope[IF privates THEN IF imported THEN "" ELSE "private part of " ELSE IF imported THEN "imported part of " ELSE "none(!) of "]], [rope[dfName]]]]];
CONTINUE}
];
RETURN};
stop: BasicTime.GMT;
ace ¬
NEW [AnaCacheEntryPrivate ¬ [
deps: NIL,
verifyGoals: RefTab.Create[],
imports: RefTab.Create[],
others: RefTab.Create[] ]];
Recurse[dfName, [explicit, dfCreated], TRUE, FALSE];
stop ¬ BasicTime.Now[];
IF debugLog#NIL THEN debugLog.PutF["MakeACE[%g] took %gs\n", [rope[dfName]], [integer[BasicTime.Period[start, stop]]] ];
RETURN};
recurseOnExports: ARRAY BOOL OF BOOL ¬ [FALSE: TRUE, TRUE: FALSE];
VerlessShort:
PROC [given:
ROPE]
RETURNS [
ROPE] ~ {
full: ROPE;
cp: FS.ComponentPositions;
[full, cp, ] ¬ FS.ExpandName[given];
RETURN full.Substr[start: cp.base.start, len: cp.ext.start+cp.ext.length-cp.base.start]};
NodeClass: PUBLIC TYPE = REF NodeClassRep;
NodeClassRep: PUBLIC TYPE = MakeDoPrivate.NodeClassRep;
Verify:
PUBLIC
PROC [pkgList:
LIST
OF
ROPE] ~ {
doneDFs: SymTab.Ref ~ SymTab.Create[case: FALSE];
dfdRels: SymTab.Ref ~ SymTab.Create[case: FALSE]; --imported with UsingForm=list
eiRels: SymTab.Ref ~ SymTab.Create[case: FALSE]; --imported with UsingForm=exported or all
extraRels: SymTab.Ref ~ SymTab.Create[case: FALSE];
goals: MakeDo.RefTable ~ MakeDo.MakeRefTable[];
modifiable: MakeDo.RefTable ~ MakeDo.MakeRefTable[];
modRels: SymTab.Ref ~ SymTab.Create[case:
FALSE];
Same as modifiable, but just relative names
neededLeaves: MakeDo.RefTable ~ MakeDo.MakeRefTable[];
hids: RefTab.Ref ~ RefTab.Create[];
optionalLeaves: MakeDo.RefTable ~ MakeDo.MakeRefTable[];
determinerLeaves: MakeDo.RefTable ~ MakeDo.MakeRefTable[];
brokenGoals: MakeDo.RefTable ~ MakeDo.MakeRefTable[];
myFileClass: NodeClass ~ MakeDo.fileClass;
CanonizeFileName: PROC [ROPE] RETURNS [ROPE] ~ myFileClass.CanonizeName;
wDir: ROPE ~ CanonizeFileName[FS.GetWDir[]];
wDir: ROPE ~ FS.ExpandName[FS.GetWDir[]].fullFName;
wDirLen: INT ~ wDir.Length;
{
Inner block here
curDir: ROPE ¬ NIL;
readonly: BOOL ¬ FALSE;
ownedDF: LIST OF BOOL ¬ NIL;
ei: LIST OF BOOL ¬ NIL;
pushOwn: BOOL;
pushEI: BOOL;
dfStack: LIST OF DFCachingUtilities.FileSpec ¬ NIL;
localEIRels: SymTab.Ref ~ SymTab.Create[case:FALSE];
localDfdRels: SymTab.Ref ~ SymTab.Create[case:FALSE];
localModRels: SymTab.Ref ~ SymTab.Create[case:FALSE];
pkg: ROPE;
SeeDFContent:
PROC [item:
REF
ANY]
RETURNS [stop, clip, dontCache:
BOOL ¬
FALSE] ~ {
WITH item
SELECT
FROM
x: REF DFUtilities.DirectoryItem => {readonly ¬ x.readOnly; curDir ¬ x.path1};
x:
REF DFUtilities.FileItem => {
ownedFile: BOOL ~ ownedDF.first AND NOT readonly;
cand: ROPE ~ CanonizeFileName[x.name];
rel: ROPE ~ RelativeName[cand, wDirLen];
IF ownedFile
THEN {
n: MakeDo.Node ~ MakeDo.FindNode[cand, MakeDo.fileClass];
MakeDo.EnsureRefInTable[n, modifiable];
[] ¬ localModRels.Insert[rel, $T];
IF x.verifyRoot THEN MakeDo.EnsureRefInTable[n, goals];
}
ELSE {
full: ROPE ~ FS.ExpandName[rel, curDir].fullFName;
actualFull, actualAttach: ROPE;
actualCreate: BasicTime.GMT;
created: BasicTime.GMT ¬ IF x.date.format=explicit THEN x.date.gmt ELSE BasicTime.nullGMT;
relsTabl: SymTab.Ref ~ IF ei.first THEN localEIRels ELSE localDfdRels;
<<No longer needed, because we clip DFs:
IF modRels.Fetch[rel].found THEN RETURN;
to avoid confusing messages.
>>
IF dfStack=NIL THEN ERROR;
IF NOT relsTabl.Insert[rel, dfStack] THEN MakeDo.Warning[IO.PutFR["Multiple attachments for %g (%g and %g).", [rope[rel]], [rope[FmtDfs[NARROW[relsTabl.Fetch[rel].val]]]], [rope[FmtDfs[dfStack]]] ]];
IF created=BasicTime.nullGMT THEN created ¬ FS.FileInfo[name: full !FS.Error => {MakeDo.Warning[IO.PutFR["FS.Error[%g, %g, %g].", [rope[groupNames[error.group]]], [atom[error.code]], [rope[error.explanation]] ]]; GOTO DontCheck}].created;
[fullFName: actualFull, attachedTo: actualAttach, created: actualCreate] ¬ FS.FileInfo[name: rel !FS.Error => {MakeDo.Warning[IO.PutFR["FS.Error[%g, %g, %g].", [rope[groupNames[error.group]]], [atom[error.code]], [rope[error.explanation]] ]]; GOTO DontCheck}];
IF MakeDoPorting.verifyAttachments
THEN {
IF NOT (full.Equal[actualAttach.Substr[len: full.Length], FALSE] AND actualCreate=created) THEN MakeDo.Warning[IO.PutFLR["Bad attachment for %g (attached to %g of %g instead of %g of %g).", LIST[[rope[rel]], [rope[actualAttach]], [time[actualCreate]], [rope[full]], [time[created]]]]];
}
ELSE {
IF NOT (actualCreate = created) THEN MakeDo.Warning[IO.PutFLR["Bad create date for %g (%g instead of %g, as %g).", LIST[[rope[rel]], [time[actualCreate]], [time[created]], [rope[FmtDfs[dfStack]]]]]];
}
EXITS DontCheck => pkg ¬ pkg};
stop ¬ stop};
x:
REF DFUtilities.ImportsItem => {
pushOwn ¬ FALSE;
pushEI ¬ ei.first OR ownedDF.first AND x.form#list;
IF x.list#
NIL
THEN
FOR i:
NAT
IN [0 .. x.list.nEntries)
DO
rel: ROPE ~ RelativeName[full: CanonizeFileName[x.list[i].name], baseLen: wDirLen];
IF x.list[i].verifyRoot THEN [] ¬ extraRels.Store[rel, $T];
ENDLOOP;
};
x:
REF DFUtilities.IncludeItem => {
pushOwn ¬ ownedDF.first;
pushEI ¬ ei.first};
x:
REF DFCachingUtilities.NestItem =>
SELECT x.bracket
FROM
begin => {short:
ROPE ~ VerlessShort[x.df.name];
ownedDF ¬ CONS[pushOwn, ownedDF];
ei ¬ CONS[pushEI, ei]; dfStack ¬ CONS[x.df, dfStack];
IF doneDFs.Fetch[short].found THEN RETURN [clip: TRUE];
IF pushOwn THEN IF NOT doneDFs.Insert[key: short, val: $T] THEN ERROR;
};
end => {ownedDF ¬ ownedDF.rest; ei ¬ ei.rest; dfStack ¬ dfStack.rest};
ENDCASE => ERROR;
x: REF DFUtilities.CommentItem => NULL;
x: REF DFUtilities.WhiteSpaceItem => NULL;
ENDCASE => ERROR;
};
AddToSymTable:
PROC [global, local: SymTab.Ref] ~ {
InnerAdd:
PROC [key:
ROPE, val:
REF
ANY]
RETURNS [
BOOL] ~ {
[] ¬ global.Store[key: key, val: val];
RETURN [FALSE];
};
[] ¬ local.Pairs[InnerAdd];
};
dfName: ROPE; cp: FS.ComponentPositions;
dfCache: DFCachingUtilities.EnumerationCache ~ DFCachingUtilities.CreateEnumerationCache[];
FOR pkgRest:
LIST
OF
ROPE ¬ pkgList, pkgRest.rest
WHILE pkgRest #
NIL
DO
pkg ¬ pkgRest.first;
pushOwn ¬ TRUE;
pushEI ¬ FALSE;
[dfName, cp, ] ¬ FS.ExpandName[pkg];
IF cp.ext.length=0 AND cp.ext.start=cp.base.start+cp.base.length THEN dfName ¬ dfName.Concat[".df"];
[] ¬ DFCachingUtilities.FullEnumerateDFContents[df: [dfName], side: local,
Consumer: SeeDFContent, cache: dfCache !
DFCachingUtilities.FSErrorOnDF => {
MakeDo.Warning[IO.PutFR["FS.Error[%g, %g, %g].", [rope[groupNames[error.group]]], [atom[error.code]], [rope[error.explanation]] ]];
RESUME};
DFCachingUtilities.Miss => {
MakeDo.Warning[IO.PutFR["%g not found in %g", [rope[dataFileName]], [rope[dfFileName]] ]];
RESUME} ];
IF ownedDF#NIL THEN ERROR;
IF ei#NIL THEN ERROR;
{
For the loop
AddToSymTable[eiRels, localEIRels];
AddToSymTable[dfdRels, localDfdRels];
AddToSymTable[modRels, localModRels];
localEIRels.Erase[];
localDfdRels.Erase[];
localModRels.Erase[];
};
ENDLOOP;
};
{actions: MakeDo.ActionList ¬ MakeDo.GetActions[goals, modifiable, toBeDone, neededLeaves, optionalLeaves, determinerLeaves, brokenGoals];
wronglyUnlisted: RefTab.Ref ~ RefTab.Create[];
wronglyListed: RefTab.Ref ~ RefTab.Create[];
CheckLeafIsListed:
PROC [key, val:
REF
ANY]
RETURNS [stop:
BOOL] ~ {
n: MakeDo.Node ~ MakeDo.NarrowToNode[key];
CheckListness[n, NIL, TRUE];
RETURN [FALSE]};
CheckLeafMaybeListed:
PROC [key, val:
REF
ANY]
RETURNS [stop:
BOOL] ~ {
n: MakeDo.Node ~ MakeDo.NarrowToNode[key];
CheckListness[n, NIL, FALSE];
RETURN [FALSE]};
CheckHidListed:
PROC [key, val:
REF
ANY]
RETURNS [
BOOL] ~ {
n: MakeDo.Node ~ MakeDo.NarrowToNode[key];
refs: MakeDo.ActionList ~ NARROW[val];
CheckListness[n, refs, TRUE];
RETURN [FALSE]};
CheckListness:
PROC [n: MakeDo.Node, refs: MakeDo.ActionList, required:
BOOL] ~ {
name: ROPE;
class: MakeDo.NodeClass;
[name, class] ¬ MakeDo.PublicPartsOfNode[n];
IF class # MakeDo.fileClass THEN RETURN;
IF
NOT wDir.Equal[name.Substr[len: wDirLen],
FALSE]
THEN {
MakeDo.Warning[IO.PutFR1["Dependency on %g can't be handled by DFs.", [rope[name]] ]];
RETURN};
required ¬ required OR hids.Fetch[n].found OR neededLeaves.Fetch[n].found;
{rel: ROPE ~ RelativeName[full: name, baseLen: wDirLen];
shouldBeListed: BOOL ~ required OR n.Exists[];
isListed: BOOL ~ modifiable.Fetch[n].found OR dfdRels.Fetch[rel].found OR eiRels.Fetch[rel].found;
IF shouldBeListed=isListed THEN RETURN;
{wrongTable: RefTab.Ref ~ IF isListed THEN wronglyListed ELSE wronglyUnlisted;
needs: RefTab.Ref ¬ NARROW[wrongTable.Fetch[n].val];
NoteRef:
PROC [a: MakeDo.Action, ad: MakeDo.ActionDep] ~ {
[] ¬ needs.Store[a, $T];
RETURN};
IF needs=NIL THEN [] ¬ wrongTable.Store[n, needs ¬ RefTab.Create[]];
IF refs#
NIL
THEN
FOR refs ¬ refs, refs.rest
WHILE refs#
NIL
DO
NoteRef[refs.first, data]; ENDLOOP
ELSE {
n.EnumerateConsumers[data, NoteRef];
n.EnumerateConsumers[cmd, NoteRef]};
[] ¬ needs.Store[$Fmt,
IF isListed
THEN IO.PutFR1["File %g (affects %%g) doesn't exist but is in DF(s).", [rope[rel]]]
ELSE IO.PutFR1["File %g (needed by %%g) missing from DF(s).", [rope[rel]]] ];
RETURN}}};
ReportWrong:
PROC [key, val:
REF
ANY]
RETURNS [
BOOL] ~ {
n: MakeDo.Node ~ MakeDo.NarrowToNode[key];
needs: RefTab.Ref ~ NARROW[val];
fmt, nr: ROPE ¬ NIL;
PerAction:
PROC [key, val:
REF
ANY]
RETURNS [
BOOL] ~ {
IF key=$Fmt
THEN fmt ¬
NARROW[val]
ELSE {
a: MakeDo.Action ~ MakeDo.NarrowToAction[key];
IF nr#NIL THEN nr ¬ nr.Concat["; "];
nr ¬ nr.Concat[MakeDo.PublicPartsOfAction[a].cmd]};
RETURN [FALSE]};
IF needs.Pairs[PerAction] THEN ERROR;
MakeDo.Warning[IO.PutFR1[fmt, [rope[nr]] ]];
RETURN [FALSE]};
CheckDfdRel:
PROC [key:
ROPE, val:
REF
ANY]
RETURNS [
BOOL] ~ {
IF extraRels.Fetch[key].found THEN RETURN [FALSE];
{n: MakeDo.Node ~ MakeDo.FindNode[key, MakeDo.fileClass];
IF NOT (neededLeaves.Fetch[n].found OR hids.Fetch[n].found OR optionalLeaves.Fetch[n].found OR determinerLeaves.Fetch[n].found) THEN MakeDo.Warning[IO.PutFR1["Imported file %g not needed.", [rope[key]] ]];
RETURN [FALSE]}};
ReportBadGoal:
PROC [key, val:
REF
ANY]
RETURNS [
BOOL] ~ {
n: MakeDo.Node ~ MakeDo.NarrowToNode[key];
name: ROPE ~ MakeDo.PublicPartsOfNode[n].name;
MakeDo.Warning[IO.PutFR1["Goal %g not happy.", [rope[name]] ]];
RETURN [FALSE]};
seen: RefTab.Ref ~ RefTab.Create[];
toDo: LIST OF REF ANY ¬ NIL;
StartFromGoal:
PROC [key, val:
REF
ANY]
RETURNS [stop:
BOOL]
~ {IF seen.Store[key, $T] THEN toDo ¬ CONS[key, toDo]; RETURN [FALSE]};
IF brokenGoals.Pairs[ReportBadGoal] THEN ERROR;
IF goals.Pairs[StartFromGoal] THEN ERROR;
WHILE toDo#
NIL
DO
this: REF ANY ~ toDo.first;
toDo ¬ toDo.rest;
IF MakeDo.IsNode[this]
THEN {
n: MakeDo.Node ~ MakeDo.NarrowToNode[this];
a: MakeDo.Action ~ MakeDo.GetProducer[n];
IF a#NIL AND seen.Store[a, $T] THEN toDo ¬ CONS[a, toDo]}
ELSE {a: MakeDo.Action ~ MakeDo.NarrowToAction[this];
ac: MakeDo.ActionClass ~ MakeDo.PublicPartsOfAction[a].class;
CheckHidden:
PROC [n: MakeDo.Node] ~ {
IF (
NOT modifiable.Fetch[n].found)
AND n.PublicPartsOfNode[].class=MakeDo.fileClass
THEN {
refs: MakeDo.ActionList ¬ NARROW[hids.Fetch[n].val];
refs ¬ CONS[a, refs];
[] ¬ hids.Store[n, refs]}};
PerSource:
PROC [n: MakeDo.Node, which: MakeDo.ActionDep, optional:
BOOL] ~ {
IF modifiable.Fetch[n].found
AND seen.Store[n, $T]
THEN toDo ¬ CONS[n, toDo]};
MakeDo.EnumerateSources[a, cmd, PerSource];
MakeDo.EnumerateSources[a, data, PerSource];
IF ac.EnumHiddenDeps#NIL THEN ac.EnumHiddenDeps[a, CheckHidden];
toDo ¬ toDo};
ENDLOOP;
IF dfdRels.Pairs[CheckDfdRel] THEN ERROR;
IF hids.Pairs[CheckHidListed] THEN ERROR;
IF neededLeaves.Pairs[CheckLeafIsListed] THEN ERROR;
IF optionalLeaves.Pairs[CheckLeafMaybeListed] THEN ERROR;
IF determinerLeaves.Pairs[CheckLeafMaybeListed] THEN ERROR;
IF wronglyUnlisted.Pairs[ReportWrong] THEN ERROR;
IF wronglyListed.Pairs[ReportWrong] THEN ERROR;
IF actions#
NIL
THEN {
msg: ROPE ¬ NIL;
FOR actions ¬ actions, actions.rest
WHILE actions#
NIL
DO
msg ¬ msg.Cat["\n\t", MakeDo.PublicPartsOfAction[actions.first].cmd];
ENDLOOP;
MakeDo.Warning[Rope.Cat["Need to:", msg, "."]];
};
RETURN}};
FmtDfs:
PROC [dfStack:
LIST
OF DFCachingUtilities.FileSpec]
RETURNS [ans:
ROPE ¬
NIL] ~ {
FOR dfStack ¬ dfStack, dfStack.rest
WHILE dfStack#
NIL
DO
step: ROPE ~ dfStack.first.name;
IF ans#NIL THEN ans ¬ ans.Cat[" in ", step] ELSE ans ¬ Rope.Concat["in ", step];
ENDLOOP;
RETURN};
RelativeName:
PROC [full:
ROPE, baseLen:
INT]
RETURNS [rel:
ROPE] ~ {
IF full.Length>baseLen AND full.Fetch[baseLen]='< THEN baseLen ¬ baseLen.SUCC;
rel ¬ full.Substr[start: baseLen];
RETURN};
groupNames:
ARRAY
FS.ErrorGroup
OF
ROPE ~ [
ok: "ok",
bug: "bug",
environment: "environment",
client: "client",
user: "user"
];
MakeDoCmdUtilsImplDebug: Commander.CommandProc ~ {debugLog ¬ cmd.out};
MakeDoCmdUtilsImplDontDebug: Commander.CommandProc ~ {debugLog ¬ NIL};
debugLog: IO.STREAM ¬ NIL;
Commander.Register["MakeDoCmdUtilsImplDebug", MakeDoCmdUtilsImplDebug];
Commander.Register["MakeDoCmdUtilsImplDontDebug", MakeDoCmdUtilsImplDontDebug];
END.