DataBaseSourceCodeManager.st
author Claus Gittinger <cg@exept.de>
Thu, 22 Dec 2011 14:03:16 +0100
changeset 2674 7612087d1a82
child 2684 4fed20db7ecb
permissions -rw-r--r--
initial checkin

"
 COPYRIGHT (c) 2011 by Claus Gittinger
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
"{ Package: 'stx:libbasic3' }"

AbstractSourceCodeManager subclass:#DataBaseSourceCodeManager
	instanceVariableNames:''
	classVariableNames:'Verbose RepositoryPath ModulePathes'
	poolDictionaries:''
	category:'System-SourceCodeManagement'
!

!DataBaseSourceCodeManager class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 2011 by Claus Gittinger
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

documentation
"
    A simple file based sourceCodeManager, which saves versions in a local directory.
    Versions will be stored as filename.st.vNr (i.e. Foo.st.1, Foo.st.2, etc.)

    This is more an example of the protocol which needs to be implemented,
    than a real manager (although it may be useful for tiny private projects or classroom examples)

    [author:]
        Claus Gittinger
"
! !

!DataBaseSourceCodeManager class methodsFor:'accessing'!

getRepositoryPathForModule:aModuleName
    "internal: used when accessing a source repository.
     Return the path to the top directory for a particular module.
     If no specific path was defined for that module, return the value of
     the global (fallBack) repositoryPath.
     Nil is returned if no repository is available." 

    ModulePathes isNil ifTrue:[^ RepositoryPath].
    aModuleName isNil ifTrue:[^ RepositoryPath].
    ^ ModulePathes at:aModuleName ifAbsent:RepositoryPath.

    "Modified: / 20-05-1998 / 16:30:12 / cg"
    "Created: / 21-12-2011 / 23:05:51 / cg"
!

knownModules
    "return the modules, we currently know"

    ^ ModulePathes keys

    "Modified: / 21-12-2011 / 14:54:53 / cg"
!

repositoryPath
    "return the path of the default repository"

    ^ RepositoryPath

    "Created: / 21-12-2011 / 14:55:12 / cg"
! !

!DataBaseSourceCodeManager class methodsFor:'queries'!

defaultRepositoryName
    "/ '<db-type>:[<user>[.<password>]@][<host>]<db-name>[:<table-name>]'

    ^ 'sqlite:repository.db'

    "Created: / 22-12-2011 / 00:19:43 / cg"
!

enabled
    ^ true "/ false.

    "Created: / 21-12-2011 / 17:53:34 / cg"
!

isContainerBased
    "true, if the SCM uses some kind of source container (,v files).
     False, if it is like a database or filesystem."

    ^ false

    "Created: / 21-12-2011 / 18:53:55 / cg"
!

isResponsibleForPackage:aString
    ^ true.

    "Created: / 09-07-2011 / 14:32:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (format): / 22-12-2011 / 00:05:39 / cg"
!

managerTypeName
    ^ 'DBRepository'

    "Created: / 16-08-2006 / 11:05:56 / cg"
!

nameOfVersionMethodForExtensions
    ^ #'extensionsVersion_DB'

    "Modified: / 22-12-2011 / 00:06:15 / cg"
!

nameOfVersionMethodInClasses
    ^ #'version_DB'

    "Modified: / 22-12-2011 / 00:06:21 / cg"
!

repositoryNameForPackage:packageId 
    "superclass AbstractSourceCodeManager class says that I am responsible to implement this method"

    ^ self getDBNameForModule:(packageId upTo:$: )

    "Created: / 21-12-2011 / 23:07:02 / cg"
!

settingsApplicationClass
    "link to my settings application (needed for the settings dialog"

    ^ DataBaseSourceCodeManagementSettingsAppl

    "Created: / 19-04-2011 / 12:43:29 / cg"
    "Modified: / 22-12-2011 / 00:06:53 / cg"
! !

!DataBaseSourceCodeManager class methodsFor:'saving'!

savePreferencesOn:aStream
    aStream nextPutLine:'DataBaseSourceCodeManager notNil ifTrue:['.
    self repositoryInfoPerModule notEmptyOrNil ifTrue:[
        aStream nextPutLine:'    DataBaseSourceCodeManager repositoryInfoPerModule:' , self repositoryInfoPerModule storeString , '.'.
    ].
    (Smalltalk at:#SourceCodeManager) == self ifTrue:[
        aStream nextPutLine:'    Smalltalk at:#SourceCodeManager put:DataBaseSourceCodeManager.'.
    ].
    aStream nextPutLine:'    DataBaseSourceCodeManager repositoryPath:' , self repositoryPath storeString , '.'.
    aStream nextPutLine:'].'.

    "Created: / 09-11-2006 / 15:09:25 / cg"
    "Modified: / 22-12-2011 / 00:48:25 / cg"
! !

!DataBaseSourceCodeManager class methodsFor:'source code administration'!

checkForExistingContainer:fileName inModule:moduleName directory:dirName
    ^ self checkForExistingModule:moduleName directory:dirName

    "Created: / 21-12-2011 / 17:56:23 / cg"
!

checkForExistingModule:moduleDir
    "check for a package directory to be present"

    self halt.
"/
"/    dir := self moduleDirectoryFor:moduleDir.
"/    ^ dir exists

    "Created: / 21-12-2011 / 18:37:28 / cg"
!

checkForExistingModule:moduleDir directory:packageDir
    "check for a package directory to be present"

    self halt.
"/    |dir|
"/
"/    dir := self packageDirectoryForModule:moduleDir package:packageDir.
"/    ^ dir exists
"/
"/

    "Created: / 21-12-2011 / 18:03:33 / cg"
!

checkinClass:aClass fileName:classFileName directory:packageDir module:moduleDir source:sourceFile logMessage:logMessage force:force
    "Return true if ok, false if not."

    self halt.
"/    |targetDir newestRevision newRevision newFile packageMode filter outStream|
"/
"/    targetDir := self packageDirectoryForModule:moduleDir package:packageDir.
"/
"/    (targetDir filesMatching:(classFileName,'_*')) do:[:eachVersionFile |
"/        |versionString|
"/
"/        versionString := eachVersionFile copyFrom:(classFileName size + 2).
"/        (newestRevision isNil 
"/        or:[ self isRevision:versionString after:newestRevision ]) ifTrue:[
"/            newestRevision := versionString
"/        ].
"/    ].
"/
"/    newestRevision isNil ifTrue:[
"/        newRevision := '1'
"/    ] ifFalse:[
"/        newRevision := self revisionAfter:newestRevision
"/    ].
"/    newFile := (targetDir construct:classFileName,'_',newRevision printString).
"/
"/    self updateVersionMethodOf:aClass for:(self revisionStringFor:aClass inModule:moduleDir directory:packageDir container:classFileName revision:newRevision).
"/
"/    packageMode := self checkMethodPackagesOf:aClass.
"/    packageMode == #base ifTrue:[
"/        filter := [:mthd | mthd package = aClass package].
"/    ].
"/
"/    [
"/        outStream := newFile writeStream.
"/    ] on:FileStream openErrorSignal do:[:ex|
"/        self reportError:('fileout failed').
"/        ^ false
"/    ].
"/
"/    Method flushSourceStreamCache.
"/    Class fileOutErrorSignal handle:[:ex |
"/        outStream close.
"/        newFile delete.
"/        self reportError:('fileout failed (',ex description,')').
"/        ^ false
"/    ] do:[
"/        self 
"/            fileOutSourceCodeOf:aClass 
"/            on:outStream 
"/            withTimeStamp:false 
"/            withInitialize:true 
"/            withDefinition:true
"/            methodFilter:filter.
"/    ].
"/    outStream close.
"/
"/    newFile exists ifFalse:[
"/        self reportError:'fileout failed'.
"/        ^ false.
"/    ].
"/
"/    ^ true
"/
"/

    "Created: / 21-12-2011 / 19:01:07 / cg"
!

createModule:moduleDir
    "create a module directory"

    self halt.
"/    |dir|
"/
"/    dir := self moduleDirectoryFor:moduleDir.
"/    dir recursiveMakeDirectory.
"/    ^ dir exists.

    "Created: / 21-12-2011 / 18:38:22 / cg"
!

createModule:moduleDir directory:packageDir
    "create a package directory"

    self halt.
"/    |dir|
"/
"/    dir := self packageDirectoryForModule:moduleDir package:packageDir.
"/    dir recursiveMakeDirectory.
"/    ^ dir exists.

    "Created: / 21-12-2011 / 18:44:20 / cg"
!

initialRevisionStringFor:aClass inModule:moduleDir directory:packageDir container:fileName
    "return a string usable as initial revision string"

    ^ self 
        revisionStringFor:aClass 
        inModule:moduleDir 
        directory:packageDir 
        container:fileName 
        revision:'1'

    "Created: / 21-12-2011 / 18:14:03 / cg"
!

moduleDirectoryFor:moduleDir
    "a modules directory as filename"

    self halt.
"/    |root|
"/
"/    root := self getRepositoryPathForModule:moduleDir.
"/    root isNil ifTrue:[
"/        RepositoryPath := root := self defaultRepositoryPath.
"/    ].
"/
"/    ^ (root asFilename construct:moduleDir)

    "Created: / 21-12-2011 / 18:38:38 / cg"
!

packageDirectoryForModule:moduleDir package:package
    "a packages directory as filename"

    self halt.
"/    |dir|
"/
"/    dir := self moduleDirectoryFor:moduleDir.
"/    ^ dir construct:package

    "Created: / 21-12-2011 / 18:43:27 / cg"
!

revisionInfoFromString:aString 
    "{ Pragma: +optSpace }"

    "return a VersionInfo object filled with revision info.
     This extracts the relevant info from aString."

    |info path version user ts timeStamp idx1 idx2|

    "/ '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 notNil ifTrue:[ info fileName:(path asFilename baseName) ].
    info revision:version.
    user notNil ifTrue:[ info user:user ].
    timeStamp notNil ifTrue:[ info timeStamp:timeStamp ].
    ^ info

    "
     self revisionInfoFromString:'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826' 
    "

    "Created: / 21-12-2011 / 14:50:12 / cg"
!

revisionLogOf:clsOrNil fromRevision:rev1OrNil toRevision:rev2OrNil numberOfRevisions:limitOrNil fileName:classFileName directory:packageDir module:moduleDir 
    "Return true if ok, false if not."

    self halt.
"/    |info log targetDir count newestRevision|
"/
"/    targetDir := self packageDirectoryForModule:moduleDir package:packageDir.
"/    targetDir exists ifFalse:[^ nil ].
"/
"/    info := IdentityDictionary new.
"/    log := OrderedCollection new.
"/    count := 0.
"/
"/    (targetDir filesMatching:(classFileName,'_*')) do:[:eachVersionFile |
"/        |versionString cs versionChange info|
"/
"/        versionString := eachVersionFile copyFrom:(classFileName size + 2).
"/        count := count + 1.
"/        (newestRevision isNil 
"/        or:[ self isRevision:versionString after:newestRevision ]) ifTrue:[
"/            newestRevision := versionString
"/        ].
"/
"/        (rev1OrNil isNil 
"/            or:[ rev1OrNil = 0
"/            or:[ versionString = rev1OrNil
"/            or:[ self isRevision:versionString after:rev1OrNil ]]])
"/        ifTrue:[
"/            (rev2OrNil isNil 
"/                or:[ rev2OrNil = 0
"/                or:[ versionString = rev2OrNil
"/                or:[ self isRevision:rev2OrNil after:versionString ]]])
"/            ifTrue:[
"/                (limitOrNil isNil
"/                or:[ log size < limitOrNil ])
"/                ifTrue:[
"/                    cs := ChangeSet fromFile:(targetDir construct:eachVersionFile).
"/                    versionChange := cs detect:[:chg | chg isMethodChange
"/                                                       and:[chg selector = self nameOfVersionMethodInClasses]]
"/                                        ifNone:nil.
"/                    versionChange notNil ifTrue:[
"/                        info := self revisionInfoFromString:versionChange source.
"/                    ] ifFalse:[
"/                        info := VersionInfo new.
"/                    ].
"/
"/                    info revision:versionString.
"/                    log add:info.
"/                ]
"/            ].
"/        ].
"/    ].
"/    log sort:[:a :b | self isRevision:b revision after:a revision].
"/
"/    info at:#revisions put:log.
"/    info at:#numberOfRevisions put:count.
"/    info at:#newestRevision put:newestRevision.
"/
"/    ^ info
"/
"/

    "Created: / 21-12-2011 / 20:39:31 / cg"
!

revisionStringFor:aClass inModule:moduleDir directory:packageDir container:fileName revision:revisionString
    "return a string usable as initial revision string"

    ^ 'Path: %1/%2/%3, Version: %4, User: %5, Time: %6'
        bindWith:moduleDir
        with:packageDir
        with:fileName
        with:revisionString
        with:(OperatingSystem getLoginName)
        with:(Timestamp now printStringIso8601Format)

    "
     self revisionStringFor:Array inModule:'stx' directory:'libbasic' container:'Array.st' revision:'123'
    "

    "Created: / 21-12-2011 / 19:33:33 / cg"
!

streamForClass:aClass fileName:classFileName revision:revision directory:packageDir module:moduleDir cache:doCache
    self halt.
"/    |targetDir oldFile|
"/
"/    targetDir := self packageDirectoryForModule:moduleDir package:packageDir.
"/    oldFile := (targetDir construct:classFileName,'_',revision).
"/    ^ oldFile readStream

    "Created: / 21-12-2011 / 20:49:01 / cg"
! !

!DataBaseSourceCodeManager class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic3/DataBaseSourceCodeManager.st,v 1.1 2011-12-22 13:03:16 cg Exp $'
!

version_CVS
    ^ '$Header: /cvs/stx/stx/libbasic3/DataBaseSourceCodeManager.st,v 1.1 2011-12-22 13:03:16 cg Exp $'
! !