packages/Packages__VersionHistory.st
branchjv
changeset 3011 1997ff6e7e55
child 4384 e28fcaaf93c7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/packages/Packages__VersionHistory.st	Sun Jan 29 12:51:41 2012 +0000
@@ -0,0 +1,368 @@
+"
+ COPYRIGHT (c) 2003 by eXept Software AG
+              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' }"
+
+"{ NameSpace: Packages }"
+
+Object subclass:#VersionHistory
+	instanceVariableNames:'versions'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'Package-helpers'
+!
+
+VersionHistory comment:'I am a version history.  A version history is a collection of VersionNumbers that together form a tree of versions.  I enforce rules about how versions are added and removed from the history.
+
+To add a new version to a VersionHistory based on an existing version:
+
+  VersionHistory startingAt1 addNewVersionBasedOn: ''1'' asVersion; yourself
+
+If you add 2 new versions based on the same version, a branch will be started:
+
+  VersionHistory startingAt1 
+		addNewVersionBasedOn: ''1'' asVersion;
+		addNewVersionBasedOn: ''1'' asVersion; 
+		yourself
+
+To remove a single version (note: only versions at the tip of a branch, or at the base of the trunk (if it has only one successor) can be individually removed):
+
+  VersionHistory startingAt1 
+		addNewVersionBasedOn: ''1'' asVersion;
+		addNewVersionBasedOn: ''1'' asVersion; 
+		remove: ''1.1'' asVersion;
+		yourself
+
+To remove an entire branch:
+
+  VersionHistory startingAt1 
+		addNewVersionBasedOn: ''1'' asVersion;
+		addNewVersionBasedOn: ''1'' asVersion; 
+		addNewVersionBasedOn: ''1.1'' asVersion; 
+		addNewVersionBasedOn: ''1.2'' asVersion; 
+		removeBranch: ''1.1'' asVersion;
+		yourself
+
+To remove a portion of the trunk:
+
+  VersionHistory startingAt1 
+		addNewVersionBasedOn: ''1'' asVersion;
+		addNewVersionBasedOn: ''2'' asVersion; 
+		addNewVersionBasedOn: ''3'' asVersion; 
+		addNewVersionBasedOn: ''3'' asVersion; 
+		removeTrunk: ''2'' asVersion;
+		yourself
+
+To get a string description of a version history:
+
+  VersionHistory startingAt1 
+		addNewVersionBasedOn: ''1'' asVersion;
+		addNewVersionBasedOn: ''2'' asVersion; 
+		addNewVersionBasedOn: ''3'' asVersion; 
+		addNewVersionBasedOn: ''3'' asVersion; 
+		treeString
+
+Also, the following methods are useful for accessing the versions:
+
+	#firstVersion
+	#versionBefore:
+	#versionsAfter:
+	#mainLineStartingAt:
+	#allVersionsAfter:
+	#allVersionsBefore:
+'
+!
+
+!VersionHistory class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 2003 by eXept Software AG
+              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
+"
+    Taken from KomPackaging in squeak.
+
+    [author:]
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+!
+
+examples
+"
+
+  more examples to be added:
+                                                                [exBegin]
+    ... add code fragment for 
+    ... executable example here ...
+                                                                [exEnd]
+"
+!
+
+history
+    "Created: / 20.5.2003 / 08:28:06 / james"
+! !
+
+!VersionHistory class methodsFor:'as yet unclassified'!
+
+fromCollection: aCollection
+	"Note: this does not validate the continuity of version
+	numbers passed in aCollection...need to add continuity
+	checks in the future"
+
+	^self new
+		initializeVersionsFrom: aCollection;
+		yourself
+!
+
+startingAt1
+
+	^self startingAt: '1' asVersion
+!
+
+startingAt: aVersion
+
+	^self new
+		initializeVersionsAt: aVersion;
+		yourself
+! !
+
+!VersionHistory methodsFor:'accessing'!
+
+allVersionsAfter: aVersion
+	"Answer all the versions based on aVersion."
+
+	| answer |
+	answer := Set new.
+	versions do: [ :ea |
+		((ea inSameBranchAs: aVersion) and: 
+			[ea > aVersion]) ifTrue: [answer add: ea]].
+	^answer
+!
+
+allVersionsBefore: aVersion
+	"Answer all versions that came before aVersion"
+
+	| answer |
+	answer := Set new.
+	versions do: [ :ea |
+		((ea inSameBranchAs: aVersion) and: 
+			[ea < aVersion]) ifTrue: [answer add: ea]].
+	^answer
+!
+
+firstVersion
+	"Answer the first version in the entire version history"
+
+	^versions inject: versions anyOne into: [ :x :ea |
+		(x inSameBranchAs: ea)
+			ifTrue: [(x < ea) ifTrue: [x] ifFalse: [ea]]
+			ifFalse: [ea]]
+!
+
+latestMainLineVersion
+
+	^(self mainLineStartingAt: self firstVersion) last
+!
+
+mainLineStartingAt: aVersion
+	"Answer all versions based on aVersion that are not branches (they have 
+	the same number of digits with the same values, except the last value is
+	greater than the last value of aVersion)."
+
+	| answer tmp |
+	answer := OrderedCollection new.
+	tmp := aVersion.
+	[versions includes: tmp] 
+		whileTrue: 
+			[answer add: tmp.
+			tmp := tmp next].
+	^answer
+!
+
+versionBefore: aVersion
+
+	"Answer the version immediately preceeding aVersion."
+
+	| tmp |
+	(aVersion > '1' asVersion) ifFalse: [^nil].
+	(versions includes: (tmp := aVersion previous)) ifFalse: [^nil].
+	^tmp
+!
+
+versionsAfter: aVersion
+	"Answer all the versions immediately following aVersion."
+
+	| answer tmp |
+	answer := Set new.
+	tmp := aVersion next.
+	(versions includes: aVersion next) ifTrue: [answer add: tmp].
+
+	tmp := aVersion.
+	[versions includes: (tmp := tmp branchNext)] whileTrue:
+		[answer add: tmp].
+	^answer
+! !
+
+!VersionHistory methodsFor:'adding'!
+
+addNewVersionBasedOn: aVersion
+
+	| tmp |
+	(versions includes: aVersion) ifFalse: [^self error: 'Version is not in this history'].
+
+	tmp := aVersion next.
+	(versions includes: tmp) ifFalse: 
+		[versions add: tmp.
+		^tmp].
+
+	tmp := aVersion.
+	[versions includes: (tmp := tmp branchNext)] whileTrue.
+	versions add: tmp.
+	^tmp
+	
+! !
+
+!VersionHistory methodsFor:'initialization'!
+
+initializeVersionsAt: aVersion
+
+	versions := Set new.
+	versions add: aVersion.
+!
+
+initializeVersionsFrom: aCollection
+
+	versions := Set new.
+	aCollection do: [ :ea | versions add: ea ].
+! !
+
+!VersionHistory methodsFor:'printing'!
+
+treeString
+	"Answer a string that show the entire version history with
+	each branch starting on a new line"
+
+	^self treeStringStartingAt: self firstVersion
+!
+
+treeStringOn: strm startingAt: aVersion
+
+	| tmp |
+	tmp := self mainLineStartingAt: aVersion.
+	tmp do: [ :ea | ea versionStringOn: strm. strm space; space ].
+	strm cr.
+	tmp do: 
+		[ :ea | 
+		(versions includes: ea branchNext)
+			ifTrue: [self treeStringOn: strm startingAt: ea branchNext]].
+!
+
+treeStringStartingAt: aVersion
+
+	| strm |
+	strm := WriteStream on: ''.
+	self treeStringOn: strm startingAt: aVersion.
+	^strm contents
+! !
+
+!VersionHistory methodsFor:'removing'!
+
+remove: aVersion
+	"Remove aVersion from this version history."
+
+	^self remove: aVersion ifAbsent: [self error: 'version not found'].
+!
+
+remove: aVersion ifAbsent: aBlock
+	"Remove aVersion from this version history."
+
+	(versions includes: aVersion) ifFalse: [^aBlock value].
+
+	(self canRemove: aVersion) ifFalse:
+		[^self error: 'Only versions at the beginning or end with no more than one follower may be removed'].
+
+	versions remove: aVersion.
+!
+
+removeBranch: aVersion
+	"Remove aVersion and all of it's successors, providing that
+	aVersion is not the first version."
+
+	(self versionBefore: aVersion)
+		ifNil: [^self error: 'version is the first version in the history'].
+
+	versions removeAll: (self allVersionsAfter: aVersion).
+	versions remove: aVersion.
+!
+
+removeTrunk: aVersion
+	"Remove aVersion and all of it's predecessors, providing there
+	are no other branches stemming from the trunk.  Note, a trunk is defined
+	as all versions, starting with the first version, that have only one successor."
+
+	| tmp |
+	(self versionsAfter: aVersion) size > 1 
+		ifTrue: [^self error: 'version is at a fork'].
+
+	tmp := self allVersionsBefore: aVersion.
+	(tmp detect: [ :ea | (self versionsAfter: ea) size > 1 ] ifNone: [nil])
+		ifNotNil: [^self error: 'not a trunk, other branches detected'].
+
+	versions removeAll: tmp.
+	versions remove: aVersion.
+! !
+
+!VersionHistory methodsFor:'testing'!
+
+canRemove: aVersion
+
+	| hasPriors followers |
+	(versions includes: aVersion) ifFalse: [^false].
+	hasPriors := (self versionBefore: aVersion) notNil.
+	followers := self versionsAfter: aVersion.		
+
+	"Don't allow versions in the middle to be extracted"
+	(hasPriors and: [followers size > 0]) ifTrue: [^false].
+	
+	"Don't allow versions with more than one follower to be extracted"
+	(hasPriors not and: [followers size > 1]) ifTrue: [^false].
+	^true
+
+!
+
+includesVersion: aVersion
+
+	^versions includes: aVersion
+! !
+
+!VersionHistory class methodsFor:'documentation'!
+
+version
+    ^ '$Header: /cvs/stx/stx/libbasic3/packages/VersionHistory.st,v 1.2 2006/01/10 09:31:46 cg Exp $'
+! !
\ No newline at end of file