added entry to read the last N newest revision-log.
authorClaus Gittinger <cg@exept.de>
Thu, 13 Jul 2000 17:50:03 +0200
changeset 935 f5a8e98c8730
parent 934 4f06b1db2ca1
child 936 def2b1c81bcf
added entry to read the last N newest revision-log.
AbstractSourceCodeManager.st
CVSSourceCodeManager.st
--- 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!