added entry to read the last N newest revision-log.
--- a/AbstractSourceCodeManager.st Thu Jul 13 17:48:58 2000 +0200
+++ b/AbstractSourceCodeManager.st Thu Jul 13 17:50:03 2000 +0200
@@ -1222,7 +1222,7 @@
^ nil
"
- SourceCodeManager revisionInfoFromString:'$Revision: 1.118 $'
+ SourceCodeManager revisionInfoFromString:'$Revision: 1.119 $'
SourceCodeManager revisionInfoFromString:(SourceCodeManager version)
"
@@ -1397,6 +1397,78 @@
"Modified: 10.1.1997 / 13:30:00 / cg"
!
+revisionLogOf:aClass numberOfRevisions:numRevisions
+ "return info about the repository container and
+ (part of) the revisionlog (numRevisions newest revisions)
+ as a collection of revision entries.
+ Return nil on failure.
+
+ The returned information is a structure (IdentityDictionary)
+ filled with:
+ #container -> the RCS container file name
+ #filename -> the actual source file name
+ #newestRevision -> the revisionString of the newest revision
+ #numberOfRevisions -> the number of revisions in the container
+ #revisions -> collection of per-revision info (see below)
+
+ for some classes, additional info is returned:
+
+ #renamed -> true if the class has been renamed or copied
+ and the sourceInfo is from the previous one
+ #expectedFileName -> the filename we would expect (i.e. for the new class)
+
+ rev1 / rev2 specify from which revisions a logEntry is wanted:
+ If rev1 is nil, the first revision is the initial revision
+ otherwise, the log starts with that revision.
+ If rev2 is nil, the last revision is the newest revision
+ otherwise, the log ends with that revision.
+ If both are nil, no logEntries are extracted (i.e. only the header).
+
+ per revision info consists of one record per revision:
+
+ #revision -> the revision string
+ #author -> who checked that revision into the repository
+ #date -> when was it checked in
+ #state -> the RCS state
+ #numberOfChangedLines -> the number of changed line w.r.t the previous
+ #logMessage -> the checkIn log message
+
+ revisions are ordered newest first
+ (i.e. the last entry is for the initial revision;
+ the first for the most recent one)
+ "
+
+ |sourceInfo packageDir moduleDir classFileName info|
+
+ sourceInfo := self sourceInfoOfClass:aClass.
+ sourceInfo isNil ifTrue:[^ nil].
+
+ packageDir := self packageFromSourceInfo:sourceInfo.
+ moduleDir := self moduleFromSourceInfo:sourceInfo. "/ use the modules name as CVS module
+ classFileName := self containerFromSourceInfo:sourceInfo.
+
+ info := self
+ revisionLogOf:aClass
+ numberOfRevisions:numRevisions
+ fileName:classFileName
+ directory:packageDir
+ module:moduleDir.
+
+ info notNil ifTrue:[
+"/ (sourceInfo includesKey:#renamed) ifTrue:[
+"/ info at:#renamed put:(sourceInfo at:#renamed)
+"/ ].
+ (sourceInfo includesKey:#expectedFileName) ifTrue:[
+ info at:#expectedFileName put:(sourceInfo at:#expectedFileName)
+ ]
+ ].
+ ^ info
+
+ "
+ SourceCodeManager revisionLogOf:Array numberOfRevisions:10
+ "
+!
+
revisionLogOfContainer:classFileName directory:packageDir module:moduleDir
"return info about the repository container and
(part of) the revisionlog as a collection of revision entries.
@@ -1726,6 +1798,6 @@
!AbstractSourceCodeManager class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.118 2000-05-12 11:55:44 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.119 2000-07-13 15:50:03 cg Exp $'
! !
AbstractSourceCodeManager initialize!
--- a/CVSSourceCodeManager.st Thu Jul 13 17:48:58 2000 +0200
+++ b/CVSSourceCodeManager.st Thu Jul 13 17:50:03 2000 +0200
@@ -3151,6 +3151,78 @@
"Modified: / 16.1.1998 / 17:34:13 / stefan"
!
+readRevisionLogEntryFromStream:inStream
+ "read and parse a single revision info-entry from the cvs log output.
+ Return nil on end.
+
+ The returned information is a structure (IdentityDictionary)
+ filled with:
+ #revision -> the revision string
+ #author -> who checked that revision into the repository
+ #date -> when was it checked in
+ #state -> the RCS state
+ #numberOfChangedLines -> the number of changed line w.r.t the previous
+ #logMessage -> the checkIn log message
+ "
+
+ |revLine1 revLine2 record s line atEnd|
+
+ atEnd := false.
+
+ revLine1 := inStream nextLine.
+ [revLine1 notNil and:[(revLine1 startsWith:'revision ') not]]
+ whileTrue:[inStream atEnd ifTrue:[
+ revLine1 := nil
+ ] ifFalse:[
+ revLine1 := inStream nextLine.
+ ]
+ ].
+ revLine2 := inStream nextLine.
+ (revLine1 notNil and:[revLine2 notNil]) ifTrue:[
+ record := IdentityDictionary new.
+ record at:#revision put:(revLine1 asCollectionOfWords at:2).
+ "/ decompose date/author/state etc.
+ (revLine2 asCollectionOfSubstringsSeparatedBy:$;) do:[:info |
+ |subEntry|
+ subEntry := info withoutSeparators.
+ #('date:' #date
+ 'author:' #author
+ 'state:' #state
+ 'lines:' #numberOfChangedLines
+ ) pairWiseDo:[:word :key |
+ s := subEntry restAfter:word withoutSeparators:true.
+ s notNil ifTrue:[record at:key put:s.].
+ ].
+ ].
+
+ "first revision does not hav a 'lines:' entry"
+ (record includesKey:#numberOfChangedLines) ifFalse:[
+ record at:#numberOfChangedLines put:''
+ ].
+
+ s := nil.
+ line := inStream nextLine.
+ [atEnd or:[line isNil or:[line startsWith:'--------']]] whileFalse:[
+ (line startsWith:'==========') ifTrue:[
+ atEnd := true.
+ ] ifFalse:[
+ (line withoutSpaces = '.') ifTrue:[
+ line := '*** empty log message ***'
+ ].
+ s isNil ifTrue:[
+ s := line
+ ] ifFalse:[
+ s := s , Character cr asString , line.
+ ].
+ line := inStream nextLine.
+ ]
+ ].
+ record at:#logMessage put:s.
+ ].
+ ^record.
+
+!
+
removeContainerFor:aClass inModule:moduleDir package:packageDir container:fileName
"remove a container"
@@ -3582,8 +3654,9 @@
s := info at:#numberOfRevisions.
(idx := s indexOf:$;) ~~ 0 ifTrue:[
info at:#numberOfRevisions put:(Integer readFrom:(s copyTo:idx - 1))
+ ] ifFalse:[
+ info at:#numberOfRevisions put:(Integer readFrom:s onError:[1])
].
-
headerOnly ifFalse:[
"/
"/ continue to read the commands pipe output
@@ -3594,53 +3667,60 @@
atEnd := false.
[atEnd or:[inStream atEnd]] whileFalse:[
- revLine1 := inStream nextLine.
- [revLine1 notNil and:[(revLine1 startsWith:'revision ') not]]
- whileTrue:[inStream atEnd ifTrue:[
- revLine1 := nil
- ] ifFalse:[
- revLine1 := inStream nextLine.]].
- revLine2 := inStream nextLine.
- (revLine1 notNil and:[revLine2 notNil]) ifTrue:[
- record := IdentityDictionary new.
- record at:#revision put:(revLine1 asCollectionOfWords at:2).
- "/ decompose date/author/state etc.
- (revLine2 asCollectionOfSubstringsSeparatedBy:$;) do:[:info |
- |subEntry|
- subEntry := info withoutSeparators.
- #('date:' #date
- 'author:' #author
- 'state:' #state
- 'lines:' #numberOfChangedLines
- ) pairWiseDo:[:word :key |
- s := subEntry restAfter:word withoutSeparators:true.
- s notNil ifTrue:[record at:key put:s.].
- ].
- ].
-
- "first revision does not hav a 'lines:' entry"
- (record includesKey:#numberOfChangedLines) ifFalse:[
- record at:#numberOfChangedLines put:''
- ].
-
- s := nil.
- line := inStream nextLine.
- [atEnd or:[line isNil or:[line startsWith:'--------']]] whileFalse:[
- (line startsWith:'==========') ifTrue:[
- atEnd := true.
- ] ifFalse:[
- (line withoutSpaces = '.') ifTrue:[
- line := '*** empty log message ***'
- ].
- s isNil ifTrue:[
- s := line
- ] ifFalse:[
- s := s , Character cr asString , line.
- ].
- line := inStream nextLine.
- ]
- ].
- record at:#logMessage put:s.
+ record := self readRevisionLogEntryFromStream:inStream.
+
+"/ revLine1 := inStream nextLine.
+"/ [revLine1 notNil and:[(revLine1 startsWith:'revision ') not]]
+"/ whileTrue:[inStream atEnd ifTrue:[
+"/ revLine1 := nil
+"/ ] ifFalse:[
+"/ revLine1 := inStream nextLine.]].
+"/ revLine2 := inStream nextLine.
+"/ (revLine1 notNil and:[revLine2 notNil]) ifTrue:[
+"/ record := IdentityDictionary new.
+"/ record at:#revision put:(revLine1 asCollectionOfWords at:2).
+"/ "/ decompose date/author/state etc.
+"/ (revLine2 asCollectionOfSubstringsSeparatedBy:$;) do:[:info |
+"/ |subEntry|
+"/ subEntry := info withoutSeparators.
+"/ #('date:' #date
+"/ 'author:' #author
+"/ 'state:' #state
+"/ 'lines:' #numberOfChangedLines
+"/ ) pairWiseDo:[:word :key |
+"/ s := subEntry restAfter:word withoutSeparators:true.
+"/ s notNil ifTrue:[record at:key put:s.].
+"/ ].
+"/ ].
+"/
+"/ "first revision does not hav a 'lines:' entry"
+"/ (record includesKey:#numberOfChangedLines) ifFalse:[
+"/ record at:#numberOfChangedLines put:''
+"/ ].
+"/
+"/ s := nil.
+"/ line := inStream nextLine.
+"/ [atEnd or:[line isNil or:[line startsWith:'--------']]] whileFalse:[
+"/ (line startsWith:'==========') ifTrue:[
+"/ atEnd := true.
+"/ ] ifFalse:[
+"/ (line withoutSpaces = '.') ifTrue:[
+"/ line := '*** empty log message ***'
+"/ ].
+"/ s isNil ifTrue:[
+"/ s := line
+"/ ] ifFalse:[
+"/ s := s , Character cr asString , line.
+"/ ].
+"/ line := inStream nextLine.
+"/ ]
+"/ ].
+"/ record at:#logMessage put:s.
+"/ revisionRecords add:record.
+"/ ]
+ record isNil ifTrue:[
+ atEnd := true.
+ ] ifFalse:[
revisionRecords add:record.
]
].
@@ -3663,11 +3743,168 @@
"Created: / 16.11.1995 / 13:25:30 / cg"
"Modified: / 29.1.1997 / 16:51:30 / stefan"
"Modified: / 27.8.1998 / 12:40:59 / cg"
+!
+
+revisionLogOf:clsOrNil numberOfRevisions:numRevisions fileName:classFileName directory:packageDir module:moduleDir
+ "return info about the repository container and
+ (part of) the revisionlog (numRevisions newest revisions)
+ as a collection of revision entries.
+ Return nil on failure.
+
+ The returned information is a structure (IdentityDictionary)
+ filled with:
+ #container -> the RCS container file name
+ #filename -> the actual source file name
+ #newestRevision -> the revisionString of the newest revision
+ #numberOfRevisions -> the number of revisions in the container
+ #revisions -> collection of per-revision info (see below)
+
+ rev1 / rev2 specify from which revisions a logEntry is wanted:
+ -If rev1 is nil, the first revision is the initial revision
+ otherwise, the log starts with that revision.
+ -If rev2 is nil, the last revision is the newest revision
+ otherwise, the log ends with that revision.
+
+ -If both are nil, all logEntries are extracted.
+ -If both are 0 (not nil), no logEntries are extracted (i.e. only the header).
+
+ per revision info consists of one record per revision:
+
+ #revision -> the revision string
+ #author -> who checked that revision into the repository
+ #date -> when was it checked in
+ #state -> the RCS state
+ #numberOfChangedLines -> the number of changed line w.r.t the previous
+ #logMessage -> the checkIn log message
+
+ revisions are ordered newest first
+ (i.e. the last entry is for the initial revision; the first for the most recent one)
+ "
+
+ |tempDir cmd fullName modulePath inStream inHeaderInfo atEnd line revArg revLine1 revLine2 idx
+ info record revisionRecords s msg cvsRoot|
+
+ cvsRoot := self getCVSROOTForModule:moduleDir.
+ cvsRoot isNil ifTrue:[
+ 'CVSSourceCodeManager [info]: CVSROOT not set' infoPrintCR.
+ ^ nil
+ ].
+
+ modulePath := moduleDir , '/' , packageDir.
+ fullName := modulePath , '/' , classFileName.
+ tempDir := self createTempDirectory:nil forModule:nil.
+ tempDir isNil ifTrue:[
+ ('CVSSourceCodeManager [error]: no tempDir - cannot extract log') errorPrintCR.
+ ^ nil.
+ ].
+
+ [
+ self createEntryFor:fullName
+ module:moduleDir
+ in:(tempDir construct:modulePath)
+ revision:'1.1'
+ date:'dummy'
+ special:''
+ overwrite:false.
+
+ revArg := ''.
+
+ msg := 'reading revision log '.
+ clsOrNil isNil ifTrue:[
+ msg := msg , 'in ' , fullName.
+ ] ifFalse:[
+ msg := msg , 'of ', clsOrNil name.
+ ].
+ self activityNotification:msg.
+
+ CVSBinDir asFilename isAbsolute ifTrue:[
+ cmd := CVSBinDir , 'cvs -d ', cvsRoot, ' log ' , revArg , ' ' , fullName.
+ ] ifFalse:[
+ cmd := 'cvs -d ', cvsRoot, ' log ' , revArg , ' ' , fullName.
+ ].
+ "/ cmd printNL.
+ inStream := PipeStream readingFrom:cmd inDirectory:tempDir name.
+ inStream isNil ifTrue:[
+ ('CVSSourceCodeManager [error]: cannot open pipe to cvs log ', fullName) errorPrintCR.
+ ^ nil
+ ].
+
+ "/
+ "/ read the commands pipe output and extract the container info
+ "/
+ info := IdentityDictionary new.
+ inHeaderInfo := true.
+ [inHeaderInfo and:[inStream atEnd not]] whileTrue:[
+ line:= inStream nextLine.
+ line notNil ifTrue:[
+ |gotIt|
+
+ gotIt := false.
+ #('RCS file:' #container
+ 'Working file:' #filename
+ 'head:' #newestRevision
+ 'total revisions:' #numberOfRevisions
+ ) pairWiseDo:[:word :key |
+ gotIt ifFalse:[
+ s := line restAfter:word withoutSeparators:true.
+ s notNil ifTrue:[info at:key put:s. gotIt := true].
+ ]
+ ].
+ gotIt ifFalse:[
+ (line startsWith:'description:') ifTrue:[inHeaderInfo := false].
+ ]
+ ]
+ ].
+ inStream nextLine. "/ skip separating line after description.
+
+ info isEmpty ifTrue:[
+ ('CVSSourceCodeManager [warning]: no log for ', fullName) errorPrintCR.
+ ^ nil
+ ].
+
+ "/ strip selected revisions from the total-revisions entry
+ s := info at:#numberOfRevisions.
+ (idx := s indexOf:$;) ~~ 0 ifTrue:[
+ info at:#numberOfRevisions put:(Integer readFrom:(s copyTo:idx - 1))
+ ] ifFalse:[
+ info at:#numberOfRevisions put:(Integer readFrom:s onError:[1])
+ ].
+
+ "/
+ "/ continue to read the commands pipe output
+ "/ and extract revision-info records
+ "/
+ revisionRecords := OrderedCollection new:(info at:#numberOfRevisions).
+ info at:#revisions put:revisionRecords.
+
+ atEnd := false.
+ [atEnd or:[inStream atEnd]] whileFalse:[
+ record := self readRevisionLogEntryFromStream:inStream.
+ record isNil ifTrue:[
+ atEnd := true.
+ ] ifFalse:[
+ revisionRecords add:record.
+ ].
+ revisionRecords size >= numRevisions ifTrue:[
+ atEnd := true
+ ]
+ ].
+ ] valueNowOrOnUnwindDo:[
+ inStream notNil ifTrue:[inStream close].
+ tempDir recursiveRemove
+ ].
+ ^ info
+
+ "
+ SourceCodeManager revisionLogOf:Array
+ SourceCodeManager revisionLogOf:Array numberOfRevisions:5
+
+ "
! !
!CVSSourceCodeManager class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic3/CVSSourceCodeManager.st,v 1.214 2000-05-18 07:17:45 ca Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic3/CVSSourceCodeManager.st,v 1.215 2000-07-13 15:49:41 cg Exp $'
! !
CVSSourceCodeManager initialize!