MCPackageLoader.st
author Claus Gittinger <cg@exept.de>
Wed, 22 Nov 2006 14:12:56 +0100
changeset 70 7a1fe064963b
child 213 9babb070c82c
permissions -rw-r--r--
initial checkin

"{ Package: 'stx:goodies/monticello' }"

Object subclass:#MCPackageLoader
	instanceVariableNames:'requirements unloadableDefinitions obsoletions additions removals
		errorDefinitions provisions'
	classVariableNames:''
	poolDictionaries:''
	category:'Monticello-Loading'
!


!MCPackageLoader class methodsFor:'as yet unclassified'!

installSnapshot: aSnapshot
	self new
		installSnapshot: aSnapshot;
		load
!

new
	^ self basicNew initialize
!

unloadPackage: aPackage
	self new
		unloadPackage: aPackage;
		loadWithNameLike: aPackage name, '-unload'
!

updatePackage: aPackage withSnapshot: aSnapshot
	self new
		updatePackage: aPackage withSnapshot: aSnapshot;
		load
! !

!MCPackageLoader methodsFor:'patch ops'!

addDefinition: aDefinition
	additions add: aDefinition
!

modifyDefinition: old to: new
	self addDefinition: new.
	obsoletions at: new put: old.
!

removeDefinition: aDefinition
	removals add: aDefinition
! !

!MCPackageLoader methodsFor:'private'!

analyze
	| sorter |
	sorter _ self sorterForItems: additions.
	additions _ sorter orderedItems.
	requirements _ sorter externalRequirements.
	unloadableDefinitions _ sorter itemsWithMissingRequirements asSortedCollection.
	
	sorter _ self sorterForItems: removals.
	removals _ sorter orderedItems reversed.
!

basicLoad
	errorDefinitions _ OrderedCollection new.
	[[additions do: [:ea | self tryToLoad: ea] displayingProgress: 'Loading...'.
	removals do: [:ea | ea unload] displayingProgress: 'Cleaning up...'.
	self shouldWarnAboutErrors ifTrue: [self warnAboutErrors].
	errorDefinitions do: [:ea | ea loadOver: (self obsoletionFor: ea)] displayingProgress: 'Reloading...'.
	additions do: [:ea | ea postloadOver: (self obsoletionFor: ea)] displayingProgress: 'Initializing...']
		on: InMidstOfFileinNotification 
		do: [:n | n resume: true]]
			ensure: [self flushChangesFile]
!

dependencyWarning
	^ String streamContents:
		[:s |
		s nextPutAll: 'This package depends on the following classes:'; cr.
		requirements do: [:ea | s space; space; nextPutAll: ea; cr].
		s nextPutAll: 'You must resolve these dependencies before you will be able to load these definitions: '; cr.
		unloadableDefinitions do: [:ea | s space; space; nextPutAll: ea summary; cr]] 
!

errorDefinitionWarning
	^ String streamContents:
		[:s |
		s nextPutAll: 'The following definitions had errors while loading.  Press Proceed to try to load them again (they may work on a second pass):'; cr.
		errorDefinitions do: [:ea | s space; space; nextPutAll: ea summary; cr]] 
!

flushChangesFile
	"The changes file is second in the SourceFiles array"

	(SourceFiles at: 2) flush
!

initialize
	additions _ OrderedCollection new.
	removals _ OrderedCollection new.
	obsoletions _ Dictionary new.
!

obsoletionFor: aDefinition
	^ obsoletions at: aDefinition ifAbsent: [nil]
!

orderDefinitionsForLoading: aCollection
	^ (self sorterForItems: aCollection) orderedItems
!

orderedAdditions
	^ additions
!

provisions
	^ provisions ifNil: [provisions _ Set withAll: Smalltalk keys]
!

shouldWarnAboutErrors
	^ errorDefinitions isEmpty not and: [false "should make this a preference"]
!

sorterForItems: aCollection
	| sorter |
	sorter _ MCDependencySorter items: aCollection.
	sorter addExternalProvisions: self provisions.
	^ sorter
!

tryToLoad: aDefinition
	[aDefinition loadOver: (self obsoletionFor: aDefinition)] on: Error do: [errorDefinitions add: aDefinition].
!

useChangeSetNamed: baseName during: aBlock
	"Use the named change set, or create one with the given name."
	| changeHolder oldChanges newChanges |
	changeHolder _ (ChangeSet respondsTo: #newChanges:)
						ifTrue: [ChangeSet]
						ifFalse: [Smalltalk].
	oldChanges _ (ChangeSet respondsTo: #current)
						ifTrue: [ChangeSet current]
						ifFalse: [Smalltalk changes].

	newChanges _ (ChangeSorter changeSetNamed: baseName) ifNil: [ ChangeSet new name: baseName ].
	changeHolder newChanges: newChanges.
	[aBlock value] ensure: [changeHolder newChanges: oldChanges].
!

useNewChangeSetDuring: aBlock
	^self useNewChangeSetNamedLike: 'MC' during: aBlock
!

useNewChangeSetNamedLike: baseName during: aBlock
	^self useChangeSetNamed: (ChangeSet uniqueNameLike: baseName) during: aBlock
!

warnAboutDependencies 
	self notify: self dependencyWarning
!

warnAboutErrors
	self notify: self errorDefinitionWarning.
! !

!MCPackageLoader methodsFor:'public'!

installSnapshot: aSnapshot
	| patch |
	patch _ aSnapshot patchRelativeToBase: MCSnapshot empty.
	patch applyTo: self.
!

load
	self analyze.
	unloadableDefinitions isEmpty ifFalse: [self warnAboutDependencies].
	self useNewChangeSetDuring: [self basicLoad]
!

loadWithName: baseName
	self analyze.
	unloadableDefinitions isEmpty ifFalse: [self warnAboutDependencies].
	self useChangeSetNamed: baseName during: [self basicLoad]
!

loadWithNameLike: baseName
	self analyze.
	unloadableDefinitions isEmpty ifFalse: [self warnAboutDependencies].
	self useNewChangeSetNamedLike: baseName during: [self basicLoad]
!

unloadPackage: aPackage
	self updatePackage: aPackage withSnapshot: MCSnapshot empty
!

updatePackage: aPackage withSnapshot: aSnapshot
	|  patch packageSnap |
	packageSnap _ aPackage snapshot.
	patch _ aSnapshot patchRelativeToBase: packageSnap.
	patch applyTo: self.
	packageSnap definitions do: [:ea | self provisions addAll: ea provisions]
! !

!MCPackageLoader class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/goodies/monticello/MCPackageLoader.st,v 1.1 2006-11-22 13:12:56 cg Exp $'
! !