--- a/AbstractSourceCodeManager.st Tue Feb 04 21:01:56 2014 +0100
+++ b/AbstractSourceCodeManager.st Wed Apr 01 10:37:40 2015 +0100
@@ -11,6 +11,8 @@
"
"{ Package: 'stx:libbasic3' }"
+"{ NameSpace: Smalltalk }"
+
Object subclass:#AbstractSourceCodeManager
instanceVariableNames:''
classVariableNames:'DefaultManager CachingSources CacheDirectoryName UseWorkTree
@@ -91,11 +93,26 @@
CachingSources isNil ifTrue:[CachingSources := false].
UseWorkTree isNil ifTrue:[UseWorkTree := false].
- CacheDirectoryName isNil ifTrue:[
- self initCacheDirPath.
- ].
+
+ self validateCacheDirPath.
+ Smalltalk addDependent:self
"Modified: / 02-03-2012 / 17:00:11 / cg"
+!
+
+update:something with:aParameter from:changedObject
+ "flush resources on language changes"
+
+ something == #returnFromSnapshot ifTrue:[
+ self validateCacheDirPath
+ ]
+!
+
+validateCacheDirPath
+ (CacheDirectoryName isNil
+ or:[CacheDirectoryName asFilename exists not]) ifTrue:[
+ self initCacheDirPath
+ ].
! !
!AbstractSourceCodeManager class methodsFor:'accessing'!
@@ -565,7 +582,10 @@
"Created: / 23-08-2006 / 14:05:42 / cg"
!
-revisionLogOf:clsOrNil fromRevision:firstRev toRevision:lastRef fileName:classFileName directory:packageDir module:moduleDir
+revisionLogOf:clsOrNil
+ fromRevision:firstRev toRevision:lastRef
+ fileName:classFileName directory:packageDir module:moduleDir
+
^ self
revisionLogOf:clsOrNil
fromRevision:firstRev
@@ -576,14 +596,55 @@
module:moduleDir
!
-revisionLogOf:clsOrNil fromRevision:rev1OrNil toRevision:rev2OrNil numberOfRevisions:limitOrNil fileName:classFileName directory:packageDir module:moduleDir
- "actually do return a revisionLog. The main worker method.
- This must be implemented by a concrete source-code manager"
-
- ^ self subclassResponsibility.
-
- "Created: 15.11.1995 / 18:12:51 / cg"
- "Modified: 14.2.1997 / 21:14:01 / cg"
+revisionLogOf:clsOrNil
+ fromRevision:rev1OrNil toRevision:rev2OrNil numberOfRevisions:limitOrNil
+ fileName:classFileName directory:packageDir module:moduleDir
+
+ "Return info about the repository container and (part of) the revisionlog as a collection
+ of revision entries. Return nil on failure.
+
+ This must be implemented by a concrete source-code manager
+
+ If numRevisionsOrNil is notNil, it limits the number of revision records returned -
+ only numRevions of the newest revision infos will be collected.
+
+ The returned information is a structure (IdentityDictionary)
+ filled with:
+ #container -> the RCS/CVS container file name
+ #cvsRoot -> the CVS root (repository)
+ #filename -> the actual source file name
+ #newestRevision -> the revisionString of the newest revision
+ #numberOfRevisions -> the number of revisions in the container (nil for all)
+ #revisions -> collection of per-revision info (see below)
+
+ firstRevOrNil / lastRevOrNil specify from which revisions a logEntry is wanted:
+ -If firstRevOrNil is nil, the first revision is the initial revision
+ otherwise, the log starts with that revision.
+ -If lastRevOrNil 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)
+ Attention: if state = 'dead' that revision is no longer valid.
+ "
+
+ self subclassResponsibility
+
+ "Created: / 15-11-1995 / 18:12:51 / cg"
+ "Modified: / 14-02-1997 / 21:14:01 / cg"
+ "Modified: / 11-02-2014 / 13:03:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!AbstractSourceCodeManager class methodsFor:'cache administration'!
@@ -593,7 +654,9 @@
|extractBaseAndVersion versionIsGreater vsnNumberString baseName|
- CacheDirectoryName isNil ifTrue:[^ self].
+ (CacheDirectoryName isNil or:[CacheDirectoryName asFileName isDirectory not]) ifTrue:[
+ ^ self
+ ].
extractBaseAndVersion :=
[:filenameString |
@@ -910,7 +973,7 @@
SourceCodeManagerUtilities yesToAllNotification isHandled
ifTrue:[
- labels := #('Cancel' 'No' 'Browse' 'Yes to all' 'Yes').
+ labels := #('Cancel' 'No' 'Browse' 'Yes to All' 'Yes').
actions := #(#cancel false #browse #yesToAll true).
] ifFalse:[
labels := #('Cancel' 'No' 'Browse' 'Yes').
@@ -989,6 +1052,12 @@
More precisely, this checks that each line starts with zero or more
tabs (16r9) followed by 0-7 spaces (16r32) followed by non-space non-tab
character.
+ This is done for two reasons:
+ 1) Makefiles (and Make.proto/Make.spec) files MUST not have leading spaces in their rules, but tabs.
+ otherwise, make fails badly.
+
+ 2) for diff-comparison, a consisten tab/space discipline avoids false diff-positivies, which resulted from simple
+ edititing with different editors with different tab conventions.
"
| checkStream |
@@ -1284,7 +1353,7 @@
lastTop := '/' , top asFilename baseName, '/'.
idx := containerPath indexOfSubCollection:lastTop.
idx ~~ 0 ifTrue:[
- ('SourceCodeManager [warning]: warning: repository path mismatch: ' , (containerPath copyTo:idx-1) , lastTop , ' vs. ' , top , '/') infoPrintCR.
+ ('SourceCodeManager [warning]: repository path mismatch: ' , (containerPath copyTo:idx-1) , lastTop , ' vs. ' , top , '/') infoPrintCR.
'SourceCodeManager [info]: warning: assuming that mismatch is ok.' infoPrintCR.
^ containerPath copyFrom:(idx + lastTop size).
]
@@ -1565,7 +1634,7 @@
^ newInfo
"
- self sourceInfoOfClass:Array
+ SourceCodeManager sourceInfoOfClass:Array
"
"Modified: / 22-10-2008 / 20:49:15 / cg"
@@ -1621,6 +1690,12 @@
"Created: / 19-01-2012 / 10:39:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
+initialRevisionString
+ "redefinable in subclasses"
+
+ ^ '1.0'
+!
+
isContainerBased
"true, if the SCM uses some kind of source container (,v files).
False, if it is like a database or filesystem."
@@ -1637,7 +1712,7 @@
!
isExtensionsVersionMethodSelector: selector
- "true if the given selector is for one of the manager's extensions version methods.
+ "true if the given selector is for ANY of the manager's extensions version methods.
These are all named extensionVersion_XXX, where XXX is manager-specific (CVS, P4, SVN etc.).
For backward compatibility (times, when there was only one CVS sourcecode manager,
the selector named 'extensionsVersion' alone also counts as a version method
@@ -1828,20 +1903,21 @@
!
sourceCodeManagerForPackage:aPackageID
- |module mgr|
+ |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"
- (Smalltalk at:#SourceCodeManager) isNil ifTrue:[ ^ nil ].
+ defaultManager := Smalltalk at:#SourceCodeManager.
+ defaultManager isNil ifTrue:[ "eg. disabled" ^ nil ].
aPackageID notNil ifTrue:[
"/ see if there is a package-specific manager
(mgr := self managerForPackage:aPackageID) notNil ifTrue:[^ mgr].
- "/ more or less obsolete now - I know which manager is to be used per package
-"/ self availableManagers do:[:mgr |
-"/ (mgr isResponsibleForPackage:aPackageID) ifTrue:[^ mgr ].
-"/ ].
+ "/ more or less obsolete now - I know which manager is to be used per package
+ "/ self availableManagers do:[:mgr |
+ "/ (mgr isResponsibleForPackage:aPackageID) ifTrue:[^ mgr ].
+ "/ ].
"/ old stuff: see if there is a module-specific manager
module := aPackageID upTo:$:.
@@ -1849,7 +1925,7 @@
(mgr isResponsibleForModule:module) ifTrue:[^ mgr ].
]
].
- ^ Smalltalk at:#SourceCodeManager
+ ^ defaultManager
"
self sourceCodeManagerForPackage:'stx:libbasic'.
@@ -1871,6 +1947,11 @@
"Created: / 21-12-2011 / 18:02:34 / cg"
!
+versionInfoClass
+
+ ^VersionInfo
+!
+
versionMethodKeyword
"Answers the keyword used by the version management system to
@@ -1955,10 +2036,14 @@
!AbstractSourceCodeManager class methodsFor:'source code access'!
basicCheckinClass:aClass fileName:classFileName directory:packageDir module:moduleDir logMessage:logMessage force:force
- "low level checkin of a class into the source repository. Does not deal with anz version method updates,
+ "low level checkin of a class into the source repository. Does not deal with any version method updates,
only does the checkin, using a temporary file.
Return true if ok, false if not."
+ aClass isPrivate ifTrue:[
+ self reportError:'refuse to check in private classes.'.
+ ^ false.
+ ].
^ self
withClass:aClass
classFileName:classFileName
@@ -2001,12 +2086,12 @@
Return true if ok, false if not."
|className answer allLabel allValue
- nameOfVersionMethodInClasses|
+ nameOfVersionMethodInClasses revision|
className := aClass name.
nameOfVersionMethodInClasses := self nameOfVersionMethodInClasses.
- aClass revision isNil ifTrue:[
+ (revision := aClass revisionOfManager:self "revision") isNil ifTrue:[
force ifFalse:[
('SourceCodeManager [warning]: class ' , className, ' has no revision string') errorPrintCR.
@@ -2027,32 +2112,32 @@
values:(allValue , #(false #checkIn))
default:#checkIn.
] ifFalse:[
- answer := OptionBox
- request:('Class %1 has no revision string.\\Check in as newest ?' bindWith:className allBold) withCRs
- label:'Confirm'
- buttonLabels:(allLabel , #('Cancel' 'CheckIn' 'Create & CheckIn'))
- values:(allValue , #(false #checkIn #create))
- default:#create.
+ force ifTrue:[
+ revision := self newestRevisionInFile:classFileName directory:packageDir module:moduleDir.
+ revision isNil ifTrue:[
+ revision := self initialRevisionString "/ initial checkin
+ ].
+ ] ifFalse:[
+ revision := self initialRevisionString "/ initial checkin
+ ].
+ answer := #create.
+"/ answer := OptionBox
+"/ request:('Class %1 has no revision string.\\Check in as newest ?' bindWith:className allBold) withCRs
+"/ label:'Confirm'
+"/ buttonLabels:(allLabel , #('Cancel' 'CheckIn' 'Create & CheckIn'))
+"/ values:(allValue , #(false #checkIn #create))
+"/ default:#create.
].
answer == false ifTrue:[ AbortOperationRequest raise. ^ false ].
answer == #cancelAll ifTrue:[ AbortAllOperationRequest raise. ^ false ].
answer == #create ifTrue:[
- self updateVersionMethodOf:aClass for:'$' , 'Header' , '$'. "/ concatenated to avoid RCS expansion
+ self updateVersionMethodOf:aClass for:(self revisionStringFor:aClass inModule:moduleDir directory:packageDir container:classFileName revision:revision).
].
]
].
"Ensure that the method #version_XXX is present before checking in XXX.
It will be missing when checking in classes with only the old method #version"
-"/ this is wrong - it would add the SVN-id as CVS id...
-"/ (aClass theMetaclass includesSelector: nameOfVersionMethodInClasses) ifFalse: [
-"/ versionAsKnownBefore := aClass revisionString. "/ looks in the old version (non-repository based)
-"/
-"/ self
-"/ compileVersionMethod:nameOfVersionMethodInClasses
-"/ of:aClass
-"/ for:(versionAsKnownBefore ? ('$' , 'Header' , '$')). "/ concatenated to avoid RCS expansion
-"/ ].
^ self basicCheckinClass:aClass fileName:classFileName directory:packageDir module:moduleDir logMessage:logMessage force:force.
@@ -2106,7 +2191,7 @@
directory:packageDir
module:moduleDir.
s isNil ifTrue:[^ nil].
- contents := s contentsOfEntireFile.
+ contents := s contentsAsString.
s close.
^ contents
@@ -2332,12 +2417,11 @@
"Modified: / 29-09-2011 / 22:02:55 / cg"
!
-loadPackageWithId: aPackageId fromRepositoryAsAutoloaded: doLoadAsAutoloaded
-
+loadPackageWithId:aPackageId fromRepositoryAsAutoloaded: doLoadAsAutoloaded
"Should be redefined by sub classes.
- Return true if loaded, false otherwise."
-
- ^ false
+ Raise an exception, if load failed."
+
+ PackageLoadError raiseRequestWith:aPackageId.
!
streamForFile:fileName revision:revision directory:packageDir module:moduleDir
@@ -2560,6 +2644,36 @@
"
!
+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."
@@ -2618,16 +2732,28 @@
].
self withSourceRewriteHandlerDo:[
- aClass fileOutOn:aStream
- withTimeStamp:withTimeStamp
- withInitialize:withInitialize
- withDefinition:withDefinition
- methodFilter:filter.
+ | writer |
+
+ writer := aClass programmingLanguage sourceFileWriterClass new.
+ writer generatingSourceForOriginal:true.
+ writer
+ fileOut:aClass
+ on:aStream
+ withTimeStamp:withTimeStamp
+ withInitialize:withInitialize
+ withDefinition:withDefinition
+ methodFilter:methodFilter
+
+"/ aClass fileOutOn:aStream
+"/ withTimeStamp:withTimeStamp
+"/ withInitialize:withInitialize
+"/ withDefinition:withDefinition
+"/ methodFilter:filter.
].
self checkTabSpaceConventionIn: aStream.
- "Modified: / 29-11-2013 / 12:01:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 22-01-2015 / 09:39:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
getExistingContainersInModule:aModule directory:aPackage
@@ -2847,57 +2973,24 @@
This extracts the relevant info from aString which is in the format as created
by standardRevisionStringFor:...."
- |info path version user ts timeStamp idx1 idx2|
+ |info path version user timeStamp|
"/ 'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826'
- idx1 := aString indexOfSubCollection:'Path: '.
- idx1 ~~ 0 ifTrue:[
- idx1 := idx1 + 'Path: ' size.
- idx2 := aString indexOfSubCollection:', ' startingAt:idx1.
- path := aString copyFrom:idx1 to:idx2-1.
- ].
- idx1 := aString indexOfSubCollection:'Version: '.
- idx1 ~~ 0 ifTrue:[
- idx1 := idx1 + 'Version: ' size.
- idx2 := aString indexOfSubCollection:', ' startingAt:idx1.
- idx2 == 0 ifTrue:[
- version := aString copyFrom:idx1
- ] ifFalse:[
- version := aString copyFrom:idx1 to:idx2-1.
- ].
- ].
- idx1 := aString indexOfSubCollection:'User: '.
- idx1 ~~ 0 ifTrue:[
- idx1 := idx1 + 'User: ' size.
- idx2 := aString indexOfSubCollection:', ' startingAt:idx1.
- idx2 == 0 ifTrue:[
- user := aString copyFrom:idx1
- ] ifFalse:[
- user := aString copyFrom:idx1 to:idx2-1.
- ].
- ].
- idx1 := aString indexOfSubCollection:'Time: '.
- idx1 ~~ 0 ifTrue:[
- idx1 := idx1 + 'Time: ' size.
- idx2 := aString indexOfSubCollection:', ' startingAt:idx1.
- idx2 == 0 ifTrue:[
- ts := aString copyFrom:idx1
- ] ifFalse:[
- ts := aString copyFrom:idx1 to:idx2-1.
- ].
- timeStamp := Timestamp readIso8601FormatFrom:ts
- ].
-
- info := VersionInfo new.
+ path := self extractKeyValueFor:'Path' fromRevisionString:aString.
+ version := self extractKeyValueFor:'Version' fromRevisionString:aString.
+ user := self extractKeyValueFor:'User' fromRevisionString:aString.
+ timeStamp := self extractKeyValueFor:'Time' fromRevisionString:aString.
+
+ info := self versionInfoClass new.
path notNil ifTrue:[ info fileName:(path asFilename baseName) ].
info revision:version.
user notNil ifTrue:[ info user:user ].
- timeStamp notNil ifTrue:[ info timeStamp:timeStamp ].
+ timeStamp notNil ifTrue:[ info timeStamp:(Timestamp readFrom:timeStamp) ].
^ info
"
- self revisionInfoFromString:'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826'
+ self revisionInfoFromStandardVersionString:'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826'
"
"Created: / 23-07-2012 / 18:45:41 / cg"
@@ -3313,6 +3406,22 @@
"Created: / 23-08-2006 / 14:14:59 / cg"
!
+revisionStringFor:aClass inModule:moduleDir directory:packageDir container:fileName revision:revisionString
+ "utility function: return a string usable as initial revision string.
+ Can be redefined in subclasses"
+
+ ^ self standardRevisionStringFor:aClass inModule:moduleDir directory:packageDir container:fileName revision:revisionString
+
+ "
+ self
+ revisionStringFor:Array
+ inModule:'stx'
+ directory:'libbasic'
+ container:'Array.st'
+ revision:'123'
+ "
+!
+
revisionsOf:aClass
"return a collection of revisions (as strings) found in the repository.
The most recent (newest) revision will be the first in the list.
@@ -3360,7 +3469,8 @@
withSourceRewriteHandlerDo:aBlock
"hook for just-in-time rewriting of a method's sourceCode while filing out
- used when saving version_XXX methods in a non-XXX sourceCodeManager"
+ used when saving version_XXX methods in a non-XXX sourceCodeManager,
+ or when generating sourcecode for another Smalltalk system (VSE fileout)"
AbstractSourceFileWriter methodSourceRewriteQuery handle:[:rewriteQuery |
|m newSource selector|
@@ -3391,7 +3501,9 @@
"Modified: / 27-09-2011 / 16:48:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
-writeHistoryLogSince:timeGoal filterSTSources:filterSTSourcesBoolean filterUser:userFilter filterRepository:repositoryFilter filterModules:moduleFilter filterProjects:projectFilterArg to:aStream
+writeHistoryLogSince:timeGoal filterSTSources:filterSTSourcesBoolean
+ filterUser:userFilter filterRepository:repositoryFilter filterModules:moduleFilter
+ filterProjects:projectFilterArg to:aStream
"send a full historyLog to some stream.
This walks over all possible repository roots."
@@ -3448,7 +3560,8 @@
pkg := (PackageId module:module directory:directory) asString.
(projectFilter isEmptyOrNil
- or:[ projectFilter includes:pkg ]) ifTrue:[
+ or:[ projectFilter contains:[:pat | pat match:pkg caseSensitive:false] ]
+ ) ifTrue:[
user := info at:#user ifAbsent:'?'.
recordType := info at:#cvsRecordType ifAbsent:'?'.
@@ -3873,20 +3986,15 @@
!AbstractSourceCodeManager class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.318 2013-11-14 15:34:21 stefan Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.341 2015-02-28 23:42:40 cg Exp $'
!
version_CVS
- ^ '$Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.318 2013-11-14 15:34:21 stefan Exp $'
-!
-
-version_HG
-
- ^ '$Changeset: <not expanded> $'
+ ^ '$Header: /cvs/stx/stx/libbasic3/AbstractSourceCodeManager.st,v 1.341 2015-02-28 23:42:40 cg Exp $'
!
version_SVN
- ^ '$Id: AbstractSourceCodeManager.st,v 1.318 2013-11-14 15:34:21 stefan Exp $'
+ ^ '$Id: AbstractSourceCodeManager.st,v 1.341 2015-02-28 23:42:40 cg Exp $'
! !