#REFACTORING by cg
authorClaus Gittinger <cg@exept.de>
Fri, 18 Nov 2016 18:04:44 +0100
changeset 4158 9a50fdda2092
parent 4157 3eb587af122a
child 4159 db3bc8f9302d
#REFACTORING by cg class: AbstractSourceCodeManager added: #diffListFor:fileName:directory:module:revision1:revision2: #diffListFor:fileName:directory:module:revision1:revision2:cache: removed: #initialRCSRevisionStringFor:in:container: comment/format in:9 methods category of:6 methods
AbstractSourceCodeManager.st
--- a/AbstractSourceCodeManager.st	Fri Nov 18 18:03:48 2016 +0100
+++ b/AbstractSourceCodeManager.st	Fri Nov 18 18:04:44 2016 +0100
@@ -14,20 +14,20 @@
 "{ NameSpace: Smalltalk }"
 
 Object subclass:#AbstractSourceCodeManager
-	instanceVariableNames:''
-	classVariableNames:'CacheDirectoryName CachingSources DefaultManager ManagerPerModule
-		UseWorkTree Verbose WorkTreeDirectoryName
-		PackagesWithoutExtensionMethodConfirmation
-		SuppressExtensionMethodConfirmation'
-	poolDictionaries:''
-	category:'System-SourceCodeManagement'
+        instanceVariableNames:''
+        classVariableNames:'CacheDirectoryName CachingSources DefaultManager ManagerPerModule
+                UseWorkTree Verbose WorkTreeDirectoryName
+                PackagesWithoutExtensionMethodConfirmation
+                SuppressExtensionMethodConfirmation'
+        poolDictionaries:''
+        category:'System-SourceCodeManagement'
 !
 
 Object subclass:#PackageAndManager
-	instanceVariableNames:'package managerTypeName'
-	classVariableNames:''
-	poolDictionaries:''
-	privateIn:AbstractSourceCodeManager
+        instanceVariableNames:'package managerTypeName'
+        classVariableNames:''
+        poolDictionaries:''
+        privateIn:AbstractSourceCodeManager
 !
 
 !AbstractSourceCodeManager class methodsFor:'documentation'!
@@ -640,7 +640,7 @@
 
      The returned information is a structure (IdentityDictionary)
      filled with:
-            #container          -> the RCS/CVS container file name 
+            #container          -> the container file name (for container-based SCMs)
             #cvsRoot            -> the CVS root (repository) 
             #filename           -> the actual source file name
             #newestRevision     -> the revisionString of the newest revision
@@ -1991,8 +1991,7 @@
 sourceCodeManagerForPackage:aPackageID
     |defaultManager module mgr|
 
-    "JV@2012-01-23: If source code management is disabled, return #(). Following code
-     is hack since there is no global boolean flag, sigh"
+    "JV@2012-01-23: If source code management is disabled, return #()."
     defaultManager := Smalltalk at:#SourceCodeManager.
     defaultManager isNil ifTrue:[ "eg. disabled" ^ nil ].
 
@@ -2601,176 +2600,6 @@
 
 !AbstractSourceCodeManager class methodsFor:'source code administration'!
 
-ensureDollarsInVersionMethod:aString
-    "given the source code of my version method, ensure that it contains dollars for
-     proper keyword expansion"
-
-    |versionString|
-
-    versionString := aString copyWithout: $§.
-    ^ self ensureKeywordExpansionWith: $$ inVersionMethod:versionString.
-
-    "
-     self ensureDollarsInVersionMethod:'foo ^ ''hello'' ' 
-     self ensureDollarsInVersionMethod:'foo ^ ''§hello§'' ' 
-     self ensureDollarsInVersionMethod:'foo ^ ''   hello   '' '    
-     self ensureDollarsInVersionMethod:'foo ^ ''$','Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.228 2009/10/20 09:55:58 fm Exp $'' '      
-    -- errors:
-     self ensureDollarsInVersionMethod:'foo ^ ''$Head'' '    
-     self ensureDollarsInVersionMethod:'foo ^ ''Header$'' '    
-    "
-!
-
-ensureKeyword: keyword inVersionMethod: source
-
-    | startQuote endQuote doubleColon |
-
-    "/nil keyword means that given source code management system
-    "/does not expand keywords (StORE or Monticello, for example)
-    keyword isNil ifTrue:[
-        ^source.
-    ].
-
-    startQuote := source indexOf: $'.
-    startQuote == 0 ifTrue:[
-        self error:'Does not seem to be a valid version method source. Invalid source?'
-    ].
-    (source at: startQuote + 1) == $$ ifFalse:[
-        self error:'Does not seem to be a valid version method source. Invalid source?'
-    ].
-
-    endQuote := source lastIndexOf: $'.
-    startQuote == endQuote ifTrue:[
-        self error:'Does not seem to be a valid version method source. Invalid source?'
-    ].
-    (source at: endQuote - 1) == $$ ifFalse:[
-        self error:'Does not seem to be a valid version method source. Invalid source?'
-    ].
-
-    doubleColon := source indexOf: $: startingAt: startQuote + 2.
-    "/ There may be no double colon at all, if the version method
-    "/ is fresh, like 'dollar-Header-dollar' (no real dollar here, as cvs expands the string)
-    (doubleColon == 0 or:[doubleColon > endQuote]) ifTrue:[
-        doubleColon := endQuote - 1.
-    ].
-
-    (source copyFrom: startQuote + 2 to: doubleColon - 1) = keyword ifTrue:[
-        "/ Good, desired keyword is already there
-        ^source
-    ].
-
-    ^(source copyTo: startQuote + 1) , keyword , (source copyFrom: doubleColon)
-
-    "Created: / 27-09-2011 / 15:00:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified (comment): / 26-01-2012 / 14:52:19 / cg"
-!
-
-ensureKeywordExpansionWith: aCharacter inVersionMethod:aString
-    "given the source code of my version method, ensure that it contains aCharacter for
-     proper keyword expansion"
-
-    |indexOfFirstQuote indexOfNextAfterFirstQuote indexOfSecondDollar indexOfNextAfterSecondDollar indexOfLastQuote|
-
-    indexOfFirstQuote := aString indexOf:$'.
-    indexOfFirstQuote == 0 ifTrue:[
-        "/ no ' found - mhmh is this a valid version method's source ?
-        ^ aString
-    ].
-    indexOfNextAfterFirstQuote := aString indexOfNonSeparatorStartingAt:indexOfFirstQuote+1.
-    (aString at:indexOfNextAfterFirstQuote) = aCharacter ifTrue:[
-        indexOfSecondDollar := aString indexOf:aCharacter startingAt:indexOfNextAfterFirstQuote+1.
-        ((indexOfSecondDollar == 0) 
-        or:[ indexOfNextAfterSecondDollar := aString indexOfNonSeparatorStartingAt:indexOfSecondDollar+1.
-             (aString at:indexOfNextAfterSecondDollar) ~= $' 
-        ]) ifTrue:[ 
-            self error:'invalid source (no valid version method string)' 
-        ].
-        "/ fine
-        ^ aString
-    ].
-
-    indexOfLastQuote := aString lastIndexOf:$'.
-
-    ^ (aString copyTo:indexOfFirstQuote)
-        , aCharacter asString
-        ,(aString copyFrom:indexOfFirstQuote+1 to:indexOfLastQuote-1)
-        ,aCharacter asString ,(aString copyFrom:indexOfLastQuote)
-
-    "
-     self ensureKeywordExpansionWith: $§ inVersionMethod: 'foo ^ ''hello'' '  
-     self ensureKeywordExpansionWith: $§ inVersionMethod: 'foo ^ ''   hello   '' '
-     self ensureKeywordExpansionWith: $§ inVersionMethod: 'foo ^ ''§Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.218 2009/10/07 12:12:30 fm Exp §'' '    
-
-     self ensureKeywordExpansionWith: $$ inVersionMethod: 'foo ^ ''hello'' '  
-     self ensureKeywordExpansionWith: $$ inVersionMethod: 'foo ^ ''   hello   '' '
-     self ensureKeywordExpansionWith: $$ inVersionMethod: 'foo ^ ''$','Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.228 2009/10/20 09:55:58 fm Exp $'' '    
-
-    -- errors:
-     self ensureKeywordExpansionWith: $§ inVersionMethod: 'foo ^ ''§Head'' '  
-     self ensureKeywordExpansionWith: $§ inVersionMethod: 'foo ^ ''Header§'' '   
-    "
-!
-
-ensureKeywordInVersionMethod: source
-
-    ^self ensureKeyword: self versionMethodKeyword inVersionMethod: source
-
-    "Created: / 27-09-2011 / 14:50:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-!
-
-ensureNoDollarsInVersionMethod:aString
-    "given the source code of another manager's version method, ensure that it does NOT
-     contain dollars and add $§ instead, to avoid that CVS expands keywords in it"
-
-    |versionString|
-
-    versionString := aString copyWithout: $$.
-    ^ self ensureKeywordExpansionWith: $§ inVersionMethod:versionString.
-
-    "
-        self ensureNoDollarsInVersionMethod:'foo ^ ''$','Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.228 2009/10/20 09:55:58 fm Exp $'' '           
-        self ensureNoDollarsInVersionMethod:'foo ^ ''$','Head'' '                
-        self ensureNoDollarsInVersionMethod:'foo ^ ''Header$'' '             
-        self ensureNoDollarsInVersionMethod:'foo ^ ''§Header§'' '    
-
-      -- errors:
-
-        self ensureNoDollarsInVersionMethod:'foo ^ ''§Header'' '   
-        self ensureNoDollarsInVersionMethod:'foo ^ ''Header§'' '             
-
-    "
-!
-
-extractKeyValueFor:key fromRevisionString:aString 
-    "{ Pragma: +optSpace }"
-
-    "extract a particular value from a string which has the format:
-        key1: value1, key2: value2, .... keyN: valueN"
-
-    |value idx1 idx2|
-
-    "/ 'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826'
-
-    idx1 := aString indexOfSubCollection:(key,': ').
-    idx1 ~~ 0 ifTrue:[
-        idx1 := idx1 + (key,': ') size.
-        idx2 := aString indexOfSubCollection:', ' startingAt:idx1.
-        idx2 == 0 ifTrue:[ idx2 := aString size + 1 ].
-        value := aString copyFrom:idx1 to:idx2-1.     
-    ].
-    ^ value
-
-    "
-     self 
-        extractKeyValueFor:'Path' 
-        fromRevisionString:'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826'
-
-     self 
-        extractKeyValueFor:'Time' 
-        fromRevisionString:'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826'
-    "
-!
-
 fileOutSourceCodeExtensions: extensions package: package on: stream
     "File out extension methods for given package on stream. 
      Not programming-language safe  - can handle smalltalk methods."
@@ -2884,43 +2713,6 @@
     "Created: / 20.5.1998 / 19:38:23 / cg"
 !
 
-initialRCSRevisionStringFor:aClass in:dir container:fileName
-    "return a string usable as initial revision string"
-
-    "/ do not make the string below into one string;
-    "/ RCS would expand it into a wrong rev-string
-
-    |nm oldRev idx special|
-
-    nm := fileName.
-    (nm endsWith:',v') ifTrue:[
-        nm := nm copyButLast:2
-    ].
-    (nm endsWith:'.st') ifFalse:[
-        nm := nm , '.st'
-    ].
-
-    oldRev := aClass revisionString.
-    special := ''.
-
-    oldRev notNil ifTrue:[
-        idx := oldRev lastIndexOf:$[.
-        idx ~~ 0 ifTrue:[
-            idx := oldRev indexOf:$[ startingAt:idx+1.
-            idx ~~ 0 ifTrue:[
-                special := ' ' , (oldRev copyFrom:idx).
-            ]
-        ]
-    ].
-
-
-    ^ '$' , 'Header: ' , dir , '/' , fileName , ',v $'
-      , special
-
-    "Modified: 17.9.1996 / 15:57:15 / cg"
-    "Created: 14.2.1997 / 20:59:28 / cg"
-!
-
 knownTagsAndRevisionsFor:aClass
     "retrieve a list of symbolic tags -> versionNr associations
      known for that class.
@@ -3118,7 +2910,7 @@
      Return nil on failure.
      The returned information is a structure (IdentityDictionary)
      filled with:
-            #container          -> the RCS container file name
+            #container          -> the container file name (for container-based SCMs)
             #filename           -> the actual source file name
             #newestRevision     -> the revisionString of the newest revision
             #numberOfRevisions  -> the number of revisions in the container
@@ -3154,7 +2946,7 @@
 
      The returned information is a structure (IdentityDictionary)
      filled with:
-            #container          -> the RCS container file name 
+            #container          -> the container file name (for container-based SCMs)
             #filename           -> the actual source file name
             #newestRevision     -> the revisionString of the newest revision
             #numberOfRevisions  -> the number of revisions in the container
@@ -3200,7 +2992,7 @@
 
      The returned information is a structure (IdentityDictionary)
      filled with:
-            #container          -> the RCS container file name 
+            #container          -> the container file name (for container-based SCMs)
             #filename           -> the actual source file name
             #newestRevision     -> the revisionString of the newest revision
             #numberOfRevisions  -> the number of revisions in the container
@@ -3244,7 +3036,7 @@
 
      The returned information is a structure (IdentityDictionary)
      filled with:
-            #container          -> the RCS container file name 
+            #container          -> the container file name (for container-based SCMs)
             #filename           -> the actual source file name
             #newestRevision     -> the revisionString of the newest revision
             #numberOfRevisions  -> the number of revisions in the container
@@ -3321,7 +3113,7 @@
 
      The returned information is a structure (IdentityDictionary)
      filled with:
-            #container          -> the RCS container file name 
+            #container          -> the container file name (for container-based SCMs)
             #filename           -> the actual source file name
             #newestRevision     -> the revisionString of the newest revision
             #numberOfRevisions  -> the number of revisions in the container (nil for all)
@@ -3405,7 +3197,7 @@
 
      The returned information is a structure (IdentityDictionary)
      filled with:
-            #container          -> the RCS container file name 
+            #container          -> the container file name (for container-based SCMs)
             #filename           -> the actual source file name
             #newestRevision     -> the revisionString of the newest revision
             #numberOfRevisions  -> the number of revisions in the container
@@ -3447,7 +3239,7 @@
 
      The returned information is a structure (IdentityDictionary)
      filled with:
-            #container          -> the RCS container file name 
+            #container          -> the container file name (for container-based SCMs)
             #filename           -> the actual source file name
             #newestRevision     -> the revisionString of the newest revision
             #numberOfRevisions  -> the number of revisions in the container
@@ -3923,6 +3715,279 @@
     "
 ! !
 
+!AbstractSourceCodeManager class methodsFor:'source code utilities'!
+
+diffListFor:clsOrNil fileName:classFileName directory:packageDir module:moduleDir revision1:rev1 revision2:rev2
+    "return diff info. This is supposed to return a standard diff-like
+     list of lines, representing the diffs between two revisions.
+     experimental (for ownershipGraph)"
+
+    ^  self
+        diffListFor:clsOrNil fileName:classFileName directory:packageDir module:moduleDir revision1:rev1 revision2:rev2 
+        cache:true
+!
+
+diffListFor:clsOrNil fileName:classFileNameArg directory:packageDirArg module:moduleDirArg revision1:rev1 revision2:rev2 cache:cacheIt
+    "return diff info. This is supposed to return a standard diff-like
+     list of lines, representing the diffs between two revisions.
+     experimental (for ownershipGraph).
+     This fallback retrieves the two versions and calls a diff"
+
+    |fullName modulePath inStream list msg cacheDir cachedFile classFileName diffDir
+     sourceStream1 sourceStream2 source1 source2 tmpSource1 tmpSource2
+     moduleDir packageDir|
+
+    moduleDir := moduleDirArg.
+    packageDir := packageDirArg.
+    
+    clsOrNil notNil ifTrue:[
+        modulePath :=  clsOrNil package copyReplaceAll:$: with:$/.
+        moduleDir := clsOrNil package asPackageId module.
+        packageDir := clsOrNil package asPackageId directory.
+        fullName :=  modulePath , '/' , (classFileName := clsOrNil classFilename).
+    ] ifFalse:[
+        modulePath :=  moduleDir , '/' , packageDir. 
+        fullName :=  modulePath , '/' , (classFileName := classFileNameArg).
+    ].
+
+   (cacheIt) ifTrue:[
+        (cacheDir := self sourceCacheDirectory) isNil ifTrue:[
+            ('SourceCodeManager [warning]: no source cache directory') infoPrintCR.
+        ] ifFalse:[
+            diffDir := (cacheDir / modulePath / '.diffs').
+            diffDir exists ifFalse:[
+                diffDir recursiveMakeDirectory.
+            ].
+            cachedFile := diffDir / (classFileName,'_',rev1,'_',rev2).
+            cachedFile exists ifTrue:[
+                ^ cachedFile contents
+            ].
+        ].
+    ].
+
+    msg := 'SourceCodeManager: Fetching diff list of '.
+    clsOrNil isNil ifTrue:[
+        msg := msg , fullName.
+    ] ifFalse:[
+        msg := msg , clsOrNil name.
+    ].
+    msg := msg , ' ' , rev1 , ' vs. ' , rev2.
+    self activityNotification:msg.
+
+    sourceStream1 := self 
+                        streamForClass:clsOrNil
+                        fileName:classFileName 
+                        revision:rev1 
+                        directory:packageDir 
+                        module:moduleDir
+                        cache:cacheIt.
+    source1 := sourceStream1 contents.
+    sourceStream1 close.
+    tmpSource1 := Filename newTemporary.
+    tmpSource1 contents:source1.
+    
+    sourceStream2 := self 
+                        streamForClass:clsOrNil
+                        fileName:classFileName 
+                        revision:rev2 
+                        directory:packageDir 
+                        module:moduleDir
+                        cache:cacheIt.
+    source2 := sourceStream2 contents.
+    sourceStream2 close.
+    tmpSource2 := Filename newTemporary.
+    tmpSource2 contents:source2.
+    
+    [
+        inStream := PipeStream readingFrom:('diff %1 %2' bindWith:tmpSource1 pathName with:tmpSource1 pathName ). 
+        inStream isNil ifTrue:[
+            ('SourceCodeManager [error]: cannot open pipe to diff ', fullName) errorPrintCR.
+            ^ nil
+        ].
+        list := inStream contents.
+    ] ensure:[
+        inStream close.
+        tmpSource1 remove.
+        tmpSource2 remove.
+    ].
+    list := list reject:[:line | line startsWith:'\ '].
+
+    cachedFile notNil ifTrue:[
+        cachedFile contents:list.
+    ].
+    ^ list
+!
+
+ensureDollarsInVersionMethod:aString
+    "given the source code of my version method, ensure that it contains dollars for
+     proper keyword expansion"
+
+    |versionString|
+
+    versionString := aString copyWithout: $§.
+    ^ self ensureKeywordExpansionWith: $$ inVersionMethod:versionString.
+
+    "
+     self ensureDollarsInVersionMethod:'foo ^ ''hello'' ' 
+     self ensureDollarsInVersionMethod:'foo ^ ''§hello§'' ' 
+     self ensureDollarsInVersionMethod:'foo ^ ''   hello   '' '    
+     self ensureDollarsInVersionMethod:'foo ^ ''$','Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.228 2009/10/20 09:55:58 fm Exp $'' '      
+    -- errors:
+     self ensureDollarsInVersionMethod:'foo ^ ''$Head'' '    
+     self ensureDollarsInVersionMethod:'foo ^ ''Header$'' '    
+    "
+!
+
+ensureKeyword: keyword inVersionMethod: source
+
+    | startQuote endQuote doubleColon |
+
+    "/nil keyword means that given source code management system
+    "/does not expand keywords (StORE or Monticello, for example)
+    keyword isNil ifTrue:[
+        ^source.
+    ].
+
+    startQuote := source indexOf: $'.
+    startQuote == 0 ifTrue:[
+        self error:'Does not seem to be a valid version method source. Invalid source?'
+    ].
+    (source at: startQuote + 1) == $$ ifFalse:[
+        self error:'Does not seem to be a valid version method source. Invalid source?'
+    ].
+
+    endQuote := source lastIndexOf: $'.
+    startQuote == endQuote ifTrue:[
+        self error:'Does not seem to be a valid version method source. Invalid source?'
+    ].
+    (source at: endQuote - 1) == $$ ifFalse:[
+        self error:'Does not seem to be a valid version method source. Invalid source?'
+    ].
+
+    doubleColon := source indexOf: $: startingAt: startQuote + 2.
+    "/ There may be no double colon at all, if the version method
+    "/ is fresh, like 'dollar-Header-dollar' (no real dollar here, as cvs expands the string)
+    (doubleColon == 0 or:[doubleColon > endQuote]) ifTrue:[
+        doubleColon := endQuote - 1.
+    ].
+
+    (source copyFrom: startQuote + 2 to: doubleColon - 1) = keyword ifTrue:[
+        "/ Good, desired keyword is already there
+        ^source
+    ].
+
+    ^(source copyTo: startQuote + 1) , keyword , (source copyFrom: doubleColon)
+
+    "Created: / 27-09-2011 / 15:00:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified (comment): / 26-01-2012 / 14:52:19 / cg"
+!
+
+ensureKeywordExpansionWith: aCharacter inVersionMethod:aString
+    "given the source code of my version method, ensure that it contains aCharacter for
+     proper keyword expansion"
+
+    |indexOfFirstQuote indexOfNextAfterFirstQuote indexOfSecondDollar indexOfNextAfterSecondDollar indexOfLastQuote|
+
+    indexOfFirstQuote := aString indexOf:$'.
+    indexOfFirstQuote == 0 ifTrue:[
+        "/ no ' found - mhmh is this a valid version method's source ?
+        ^ aString
+    ].
+    indexOfNextAfterFirstQuote := aString indexOfNonSeparatorStartingAt:indexOfFirstQuote+1.
+    (aString at:indexOfNextAfterFirstQuote) = aCharacter ifTrue:[
+        indexOfSecondDollar := aString indexOf:aCharacter startingAt:indexOfNextAfterFirstQuote+1.
+        ((indexOfSecondDollar == 0) 
+        or:[ indexOfNextAfterSecondDollar := aString indexOfNonSeparatorStartingAt:indexOfSecondDollar+1.
+             (aString at:indexOfNextAfterSecondDollar) ~= $' 
+        ]) ifTrue:[ 
+            self error:'invalid source (no valid version method string)' 
+        ].
+        "/ fine
+        ^ aString
+    ].
+
+    indexOfLastQuote := aString lastIndexOf:$'.
+
+    ^ (aString copyTo:indexOfFirstQuote)
+        , aCharacter asString
+        ,(aString copyFrom:indexOfFirstQuote+1 to:indexOfLastQuote-1)
+        ,aCharacter asString ,(aString copyFrom:indexOfLastQuote)
+
+    "
+     self ensureKeywordExpansionWith: $§ inVersionMethod: 'foo ^ ''hello'' '  
+     self ensureKeywordExpansionWith: $§ inVersionMethod: 'foo ^ ''   hello   '' '
+     self ensureKeywordExpansionWith: $§ inVersionMethod: 'foo ^ ''§Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.218 2009/10/07 12:12:30 fm Exp §'' '    
+
+     self ensureKeywordExpansionWith: $$ inVersionMethod: 'foo ^ ''hello'' '  
+     self ensureKeywordExpansionWith: $$ inVersionMethod: 'foo ^ ''   hello   '' '
+     self ensureKeywordExpansionWith: $$ inVersionMethod: 'foo ^ ''$','Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.228 2009/10/20 09:55:58 fm Exp $'' '    
+
+    -- errors:
+     self ensureKeywordExpansionWith: $§ inVersionMethod: 'foo ^ ''§Head'' '  
+     self ensureKeywordExpansionWith: $§ inVersionMethod: 'foo ^ ''Header§'' '   
+    "
+!
+
+ensureKeywordInVersionMethod: source
+
+    ^self ensureKeyword: self versionMethodKeyword inVersionMethod: source
+
+    "Created: / 27-09-2011 / 14:50:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+ensureNoDollarsInVersionMethod:aString
+    "given the source code of another manager's version method, ensure that it does NOT
+     contain dollars and add $§ instead, to avoid that CVS expands keywords in it"
+
+    |versionString|
+
+    versionString := aString copyWithout: $$.
+    ^ self ensureKeywordExpansionWith: $§ inVersionMethod:versionString.
+
+    "
+        self ensureNoDollarsInVersionMethod:'foo ^ ''$','Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.228 2009/10/20 09:55:58 fm Exp $'' '           
+        self ensureNoDollarsInVersionMethod:'foo ^ ''$','Head'' '                
+        self ensureNoDollarsInVersionMethod:'foo ^ ''Header$'' '             
+        self ensureNoDollarsInVersionMethod:'foo ^ ''§Header§'' '    
+
+      -- errors:
+
+        self ensureNoDollarsInVersionMethod:'foo ^ ''§Header'' '   
+        self ensureNoDollarsInVersionMethod:'foo ^ ''Header§'' '             
+
+    "
+!
+
+extractKeyValueFor:key fromRevisionString:aString 
+    "{ Pragma: +optSpace }"
+
+    "extract a particular value from a string which has the format:
+        key1: value1, key2: value2, .... keyN: valueN"
+
+    |value idx1 idx2|
+
+    "/ 'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826'
+
+    idx1 := aString indexOfSubCollection:(key,': ').
+    idx1 ~~ 0 ifTrue:[
+        idx1 := idx1 + (key,': ') size.
+        idx2 := aString indexOfSubCollection:', ' startingAt:idx1.
+        idx2 == 0 ifTrue:[ idx2 := aString size + 1 ].
+        value := aString copyFrom:idx1 to:idx2-1.     
+    ].
+    ^ value
+
+    "
+     self 
+        extractKeyValueFor:'Path' 
+        fromRevisionString:'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826'
+
+     self 
+        extractKeyValueFor:'Time' 
+        fromRevisionString:'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826'
+    "
+! !
+
 !AbstractSourceCodeManager class methodsFor:'subclass responsibility'!
 
 reportHistoryLogSince:timeGoal filterSTSources:filter filterUser:userFilter 
@@ -4067,13 +4132,15 @@
 !AbstractSourceCodeManager::PackageAndManager methodsFor:'queries'!
 
 match: packageId
-    | manager |
+    | manager packageMatches|
 
     manager := self manager.
     manager isNil ifTrue:[^false].
 
-    ^ (package match: packageId) 
-        and: [manager isResponsibleForPackage: packageId]
+    packageMatches := package includesMatchCharacters
+                        ifTrue:[ package match: packageId ]
+                        ifFalse:[ packageId startsWith:(package,':') ].
+    ^ packageMatches and: [manager isResponsibleForPackage: packageId]
 
     "
      self managerForModule:'stx:libbasic'