'From Squeakland 3.8.5976 of 25 August 2004 [latest update: #388] on 19 February 2005 at 8:03:20 pm'! "Change Set: Tweak-Updates-Nihongo7 Date: 19 February 2005 Author: Takashi Yamamiya Using multiple update stream for Nihongo7. Say TweakUpdateStreamManager loadUpdates. "! Object subclass: #UpdateManager instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Tweak-Updates'! UpdateManager subclass: #SqueakUpdateStreamManager instanceVariableNames: 'uploadUrl downloadUrl smCard' classVariableNames: '' poolDictionaries: '' category: 'Tweak-Updates'! !SqueakUpdateStreamManager commentStamp: 'ar 5/14/2003 19:55' prior: 0! #(ServerDirectory SystemVersion Utilities ChangeSet ChangeSorter) do:[:each| | binding | binding := Smalltalk associationAt: each. SqueakUpdateStreamManager browseAllCallsOn: binding. ]. | mgr | mgr := TestUpdateStreamManager new. mgr uploadUrl: 'ftp://raab@luxator.cs.uni-magdeburg.de/~/public_html/squeak/updates/test'. mgr downloadUrl: 'http://isgwww.cs.uni-magdeburg.de/~raab/squeak/updates/test'. mgr applyUpdatesFromDisk. mgr highestUpdate. "mgr publishUpdate: (FileStream readOnlyFileNamed: 'test-update')."! SqueakUpdateStreamManager subclass: #DefaultUpdateStreamManager instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Tweak-Updates'! !DefaultUpdateStreamManager commentStamp: 'ar 5/14/2003 19:46' prior: 0! (DefaultUpdateStreamManager new initialize) availableUpdatesDescription HTTPClient httpGet: 'http://squeak.cs.uiuc.edu/Squeak2.0/updates/updates.list'! SqueakUpdateStreamManager subclass: #SMCardUpdateStreamManager instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Tweak-Updates'! SqueakUpdateStreamManager subclass: #SimpleUpdateStreamManager instanceVariableNames: 'packageVersion' classVariableNames: 'Registry' poolDictionaries: '' category: 'Tweak-Updates'! SimpleUpdateStreamManager subclass: #TweakUpdateStreamManager instanceVariableNames: 'highestUpdate' classVariableNames: 'TrackingVersion' poolDictionaries: '' category: 'Tweak-Updates'! !TweakUpdateStreamManager commentStamp: 'ar 12/10/2004 17:24' prior: 0! Useful expressions to do, print, or inspect: * The list of all updates: (HTTPSocket httpGet: TweakUpdateStreamManager default downloadUrl, '/updates.list') contents * The highest loaded update TweakUpdateStreamManager default highestUpdate. * The list of unloaded updates TweakUpdateStreamManager default scanServerUpdates * Please load updates now (same as selecting "Load Updates..." under the ? menu of a Tweak Project Window) TweakUpdateStreamManager default loadUpdates. * Deleting all updates from this stream | list prefix | prefix := TweakUpdateStreamManager default changeSetPrefix. list := ChangeSorter allChangeSets select:[:cs| (cs name beginsWith: prefix) and:[cs okayToRemoveInforming: false]]. list do:[:cs| ChangeSorter removeChangeSet: cs]. You might be interested in the preference "updateSavesFile" which writes all the updates locally and which can then be re-applied using, e.g., TweakUpdateStreamManager default applyUpdatesFromDisk. ! !UpdateManager methodsFor: 'update api' stamp: 'ar 5/15/2003 23:57'! installUpdateStream "Initialize this update location" ^self subclassResponsibility! ! !UpdateManager methodsFor: 'update api' stamp: 'ar 5/14/2003 16:23'! loadUpdates "Load all available updates" ^self subclassResponsibility! ! !UpdateManager methodsFor: 'update api' stamp: 'ar 5/15/2003 23:58'! publishTestUpdate "publish an update for testing" | update | update := FileStream newFileNamed: 'UpdateManagerTestUpdate.cs'. update timeStamp. update nextChunkPut: '"Change Set: UpdateManagerTestUpdate Date: ', Date today printString,' Author: UpdateManager Test update posted from UpdateManager."'. self publishUpdate: update. update close. FileDirectory default deleteFileNamed: update fullName.! ! !UpdateManager methodsFor: 'update api' stamp: 'ar 5/14/2003 16:23'! publishUpdate: aStream "Publish an update from the given stream" ^self subclassResponsibility! ! !UpdateManager methodsFor: 'queries' stamp: 'ar 5/14/2003 21:05'! availableUpdates "Answer the number of available, not yet installed updates. This method may query a server for the availability of updates." ^0! ! !UpdateManager methodsFor: 'queries' stamp: 'ar 5/14/2003 21:06'! highestUpdate "Answer the highest update number (patch level) currently installed." ^0! ! !UpdateManager methodsFor: 'queries' stamp: 'ar 5/14/2003 21:06'! loadedUpdates "Answer the number of updates which have been loaded" ^self highestUpdate! ! !SqueakUpdateStreamManager methodsFor: 'update api' stamp: 'ar 5/14/2003 20:54'! availableUpdates ^self scanServerUpdates size ! ! !SqueakUpdateStreamManager methodsFor: 'update api' stamp: 'ar 5/14/2003 19:42'! highestUpdate "a workaround as we can't keep track of the highest update yet" | prefix | prefix := self changeSetPrefix. ^(ChangeSorter allChangeSetNames select:[:csName| csName beginsWith: prefix]) inject: 0 into:[:highest :csName| ((csName allButFirst: prefix size) initialIntegerOrNil ifNil:[0]) max: highest] ! ! !SqueakUpdateStreamManager methodsFor: 'update api' stamp: 'ar 5/14/2003 19:43'! highestUpdate: updateNum "ignore this for now - we should keep track of it somewhere outside the change sets"! ! !SqueakUpdateStreamManager methodsFor: 'update api' stamp: 'ar 5/14/2003 16:24'! loadUpdates ^self updateFromServer! ! !SqueakUpdateStreamManager methodsFor: 'update api' stamp: 'ar 5/14/2003 20:55'! loadedUpdates "a workaround as we can't keep track of the highest update yet" | prefix | prefix := self changeSetPrefix. ^(ChangeSorter allChangeSetNames select:[:csName| csName beginsWith: prefix]) size! ! !SqueakUpdateStreamManager methodsFor: 'update api' stamp: 'ar 5/14/2003 17:32'! publishUpdate: aStream "Put this file out as an Update on the servers." uploadUrl ifNil:[^self error: 'no upload url']. self putUpdate: aStream on: (ServerDirectory new fullPath: uploadUrl)! ! !SqueakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 20:10'! changeSetPrefix "Argh. This needs to bump periods from the package name." ^'[', (self packageVersion copyReplaceAll: '.' with: '-'),']'.! ! !SqueakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 16:31'! downloadUrl "Answer the upload URL for the update stream." ^downloadUrl! ! !SqueakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 16:31'! downloadUrl: aUrlString "Set the download url for the update stream" downloadUrl := aUrlString! ! !SqueakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 20:52'! name ^self packageVersion! ! !SqueakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/15/2003 23:46'! packageVersion "Answer the full package version" ^self subclassResponsibility! ! !SqueakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 16:07'! updateDownloader "Redirect this to Utilities for now so as to share a common download process" ^Utilities updateDownloader! ! !SqueakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 16:07'! updateDownloader: aProcess "Redirect this to Utilities for now so as to share a common download process" Utilities updateDownloader: aProcess.! ! !SqueakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 18:40'! updateUrlLists "Fake a collection of update urls" downloadUrl ifNil:[^#()]. ^Array with: (Array with: downloadUrl with: (Array with: downloadUrl))! ! !SqueakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 16:31'! uploadUrl "Answer the upload URL for the update stream." ^uploadUrl! ! !SqueakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 16:31'! uploadUrl: aUrlString "Set the upload url for the update stream" uploadUrl := aUrlString! ! !SqueakUpdateStreamManager methodsFor: 'testing' stamp: 'ar 5/14/2003 20:17'! isUpdateLoaded: updateNum "Answer whether this update is already loaded" ^updateNum <= self highestUpdate! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 16:50'! chooseUpdateList "When there is more than one set of update servers, let the user choose which we will update from. Make it so that it will be the first in the updateUrlLists and answer true to proceed, false if user aborts." downloadUrl ifNil:[^false]. ^true! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 16:10'! extractThisVersion: list "Pull out the part of the list that applies to this version." | listContents version versIndex | listContents _ self parseListContents: list. version _ self packageVersion. versIndex _ (listContents collect: [:pair | pair first]) indexOf: version. versIndex = 0 ifTrue: [^ Array new]. "abort" ^ (listContents at: versIndex) last! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 15:47'! lastUpdateNum: updatesFileStrm "Look in the Updates file and see what the last sequence number is. Warn the user if the version it is under is not this image's version." | verIndex seqIndex char ver seqNum | verIndex _ seqIndex _ 0. "last # starting a line and last digit starting a line" seqNum _ 0. updatesFileStrm reset; ascii. [char _ updatesFileStrm next. updatesFileStrm atEnd] whileFalse: [ char == Character cr ifTrue: [ updatesFileStrm peek == $# ifTrue: [verIndex _ updatesFileStrm position +1. seqIndex = 0 ifFalse: ["See if last num of old version if biggest so far" updatesFileStrm position: seqIndex. ver _ SmallInteger readFrom: updatesFileStrm. seqNum _ seqNum max: ver. updatesFileStrm position: verIndex-1]]. updatesFileStrm peek isDigit ifTrue: [seqIndex _ updatesFileStrm position]]]. seqIndex = 0 ifFalse: ["See if last num of old version if biggest so far" updatesFileStrm position: seqIndex. ver _ SmallInteger readFrom: updatesFileStrm. seqNum _ seqNum max: ver. updatesFileStrm setToEnd]. ^ seqNum! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 19:39'! newChangesFromStream: nextDoc named: updateName "for now this is a crude hack" | csName | csName := self changeSetPrefix, updateName sansPeriodSuffix. ^ChangeSorter newChangesFromStream: nextDoc named: csName! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 20:11'! newUpdatesOn: serverList special: indexPrefix throughNumber: aNumber "Return a list of fully formed URLs of update files we do not yet have. Go to the listed servers and look at the file 'updates.list' for the names of the last N update files. We look backwards for the first one we have, and make the list from there. tk 9/10/97 No updates numbered higher than aNumber (if it is not nil) are returned " | doc list out ff raw char maxNumber itsNumber serverUrl | maxNumber _ aNumber ifNil: [99999]. out _ OrderedCollection new. serverList do: [:server | serverUrl := server. server last = $/ ifFalse:[serverUrl := serverUrl,'/']. doc _ HTTPClient httpGet: serverUrl,indexPrefix,'updates.list'. "test here for server being up" doc class == RWBinaryOrTextStream ifTrue: [raw _ doc reset; contents. "one file name per line" list _ self extractThisVersion: raw. list reverseDo: [:fileName | ff _ (fileName findTokens: '/') last. "allow subdirectories" itsNumber _ ff initialIntegerOrNil. (self isUpdateLoaded: itsNumber) ifFalse:[ (itsNumber == nil or: [itsNumber <= maxNumber]) ifTrue: [out addFirst: serverUrl, fileName]] ifTrue: [^ out]]. ((out size > 0) or: [char _ doc reset; skipSeparators; next. (char == $*) | (char == $#)]) ifTrue: [^ out "we have our list"]]. "else got error msg instead of file" "Server was down, try next one"]. self inform: 'The update server for ', self packageVersion,' seems to be unavailable'. ^ out! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 16:14'! objectStrmFromUpdates: fileName "Go to the known servers and look for this file in the updates folder. It is an auxillery file, like .morph or a .gif. Return a RWBinaryOrTextStream on it. Meant to be called from during the getting of updates from the server. That assures that (Utilities serverUrls) returns the right group of servers." | urls doc | Cursor wait showWhile: [urls _ self serverUrls collect: [:url | url, 'updates/', fileName]. urls do: [:aUrl | doc _ HTTPSocket httpGet: aUrl accept: 'application/octet-stream'. "test here for server being up" doc class == RWBinaryOrTextStream ifTrue: [^ doc reset]]]. self inform: 'All update servers are unavailable, or bad file name'. ^ nil! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 15:48'! parseListContents: listContents | sections vers strm line fileNames | "Parse the contents of updates.list into {{vers. {fileNames*}}*}, and return it." sections _ OrderedCollection new. fileNames _ OrderedCollection new: 1000. vers _ nil. strm _ ReadStream on: listContents. [strm atEnd] whileFalse: [line _ strm upTo: Character cr. line size > 0 ifTrue: [line first = $# ifTrue: [vers ifNotNil: [sections addLast: {vers. fileNames asArray}]. "Start a new section" vers _ line allButFirst. fileNames resetTo: 1] ifFalse: [line first = $* ifFalse: [fileNames addLast: line]]]]. vers ifNotNil: [sections addLast: {vers. fileNames asArray}]. ^ sections asArray " TEST: | list | list _ Utilities parseListContents: (FileStream oldFileNamed: 'updates.list') contentsOfEntireFile. list = (Utilities parseListContents: (String streamContents: [:s | Utilities writeList: list toStream: s])) ifFalse: [self error: 'test failed'] ifTrue: [self inform: 'test OK'] "! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 15:48'! position: updateStrm atVersion: version "Set the stream to the end of the last line of updates names for this version. Usually the end of the file. We will add a new update name. Return the contents of the rest of the file." | char foundIt where data | updateStrm reset; ascii. foundIt _ false. [char _ updateStrm next. updateStrm atEnd] whileFalse: [ (char == Character cr or: [char == Character lf]) ifTrue: [ updateStrm peek == $# ifTrue: [ foundIt ifTrue: ["Next section" where _ updateStrm position. data _ updateStrm upTo: (255 asCharacter). updateStrm position: where. ^ data]. "won't be found -- copy all the way to the end" updateStrm next. (updateStrm nextMatchAll: version) ifTrue: [ (updateStrm atEnd or: [(updateStrm peek = Character cr) | (updateStrm peek = Character lf)]) ifTrue: [ foundIt _ true ]]]]]. foundIt ifTrue: [ updateStrm setToEnd. ^ '']. self error: 'The current version does not have a section in the Updates file'. ! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 16:14'! readNextUpdateFromServer "Utilities readNextUpdateFromServer" self updateFromServerThroughUpdateNumber: (self highestUpdate + 1)! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 16:15'! readNextUpdatesFromDisk: n "Read the updates up through the current highest-update-number plus n. Thus, Utilities readNextUpdatesFromDisk: 7 will read the next seven updates from disk" self applyUpdatesFromDiskToUpdateNumber: self highestUpdate + n stopIfGap: false! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 21:42'! readServer: serverList special: indexPrefix updatesThrough: maxNumber saveLocally: saveLocally updateImage: updateImage "Scan the update server(s) for unassimilated updates. If maxNumber is not nil, it represents the highest-numbered update to load. This makes it possible to update only up to a particular point. If saveLocally is true, then save local copies of the update files on disc. If updateImage is true, then absorb the updates into the current image." "UpdateManager default readServer: Utilities serverUrls updatesThrough: 828 saveLocally: true updateImage: true" | urls failed loaded docQueue this nextDoc docQueueSema str updateName | Cursor wait showWhile: [ loaded _ 0. failed _ nil. urls _ self newUpdatesOn: serverList special: indexPrefix throughNumber: maxNumber. urls isEmpty ifTrue:[^Array with: failed with: loaded]. "send downloaded documents throuh this queue" docQueue := SharedQueue new. "this semaphore keeps too many documents from beeing queueed up at a time" docQueueSema := Semaphore new. 5 timesRepeat: [ docQueueSema signal ]. "fork a process to download the updates" self retrieveUrls: urls ontoQueue: docQueue withWaitSema: docQueueSema. "process downloaded updates in the foreground" [ this _ docQueue next. nextDoc _ docQueue next. nextDoc = #failed ifTrue: [ failed _ this ]. (failed isNil and: [ nextDoc ~= #finished ]) ] whileTrue: [ failed ifNil: [ nextDoc reset; text. nextDoc size = 0 ifTrue: [ failed _ this ]. ]. failed ifNil: [ nextDoc peek asciiValue = 4 "pure object file" ifTrue: [failed _ this]]. "Must be fileIn, not pure object file" failed ifNil: [ "(this endsWith: '.html') ifTrue: [doc _ doc asHtml]." "HTML source code not supported here yet" updateImage ifTrue: [ updateName _ (this findTokens: '/') last. self newChangesFromStream: nextDoc named: updateName. self registerUpdate: updateName initialIntegerOrNil]. saveLocally ifTrue: [self saveUpdate: nextDoc onFile: (this findTokens: '/') last]. "if wanted" loaded _ loaded + 1]. docQueueSema signal]. ]. failed ~~ nil & (urls size - loaded > 0) ifTrue: [ str _ loaded printString ,' new update file(s) processed.'. str _ str, '\Could not load ' withCRs, (urls size - loaded) printString ,' update file(s).', '\Starting with "' withCRs, failed, '".'. self inform: str]. ^ Array with: failed with: loaded! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 15:48'! readServerUpdatesSaveLocally: saveLocally updateImage: updateImage ^ self readServerUpdatesThrough: nil saveLocally: saveLocally updateImage: updateImage! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 12/27/2004 10:05'! readServerUpdatesThrough: maxNumber saveLocally: saveLocally updateImage: updateImage "Scan the update server(s) for unassimilated updates. If maxNumber is not nil, it represents the highest-numbered update to load. This makes it possible to update only up to a particular point. If saveLocally is true, then save local copies of the update files on disc. If updateImage is true, then absorb the updates into the current image. A file on the server called updates.list has the names of the last N update files. We look backwards for the first one we do not have, and start there" "* To add a new update: Name it starting with a new two-digit code. * Do not use %, /, *, space, or more than one period in the name of an update file. * The update name does not need to have any relation to the version name. * Figure out which versions of the system the update makes sense for. * Add the name of the file to each version's category below. * Put this file and the update file on all of the servers. * * To make a new version of the system: Pick a name for it (no restrictions) * Put # and exactly that name on a new line at the end of this file. * During the release process, fill in exactly that name in the dialog box. * Put this file on the server." "When two sets of updates need to use the same directory, one of them has a * in its serverUrls description. When that is true, the first word of the description is put on the front of 'updates.list', and that is the index file used." "Utilities readServerUpdatesThrough: 3922 saveLocally: true updateImage: true" | failed loaded str res servers triple tryAgain indexPrefix | self chooseUpdateList ifFalse: [^ self]. "ask the user which kind of updates" servers _ self serverUrls copy. indexPrefix _ (self updateUrlLists first first includes: $*) ifTrue: [(self updateUrlLists first first findTokens: ' ') first] "special for internal updates" ifFalse: ['']. "normal" [servers isEmpty] whileFalse: [ triple _ self readServer: servers special: indexPrefix updatesThrough: maxNumber saveLocally: saveLocally updateImage: updateImage. "report to user" failed _ triple first. loaded _ triple second. tryAgain _ false. failed ifNil: ["is OK" loaded = 0 ifTrue: ["found no updates" servers size > 1 ifTrue: ["not the last server" res _ UIManager default chooseFrom: #('Stop looking' 'Try next server') title: 'No new updates on the server ', servers first, ' Would you like to try the next server? (Normally, all servers are identical, but sometimes a server won''t let us store new files, and gets out of date.)'. res = 2 ifFalse: [^ self] ifTrue: [servers _ servers allButFirst. "try the next server" tryAgain _ true]]]]. tryAgain ifFalse: [ str _ loaded printString ,' new update file(s) processed.'. ^ self inform: str]. ].! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 16:47'! registerUpdate: updateNum updateNum > self highestUpdate ifTrue:[ self highestUpdate: updateNum. ]. ! ! !SqueakUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 5/14/2003 15:49'! retrieveUrls: urls ontoQueue: queue withWaitSema: waitSema "download the given list of URLs. The queue will be loaded alternately with url's and with the retrieved contents. If a download fails, the contents will be #failed. If all goes well, a special pair with an empty URL and the contents #finished will be put on the queue. waitSema is waited on every time before a new document is downloaded; this keeps the downloader from getting too far ahead of the main process" "kill the existing downloader if there is one" | doc canPeek front | self updateDownloader ifNotNil: [self updateDownloader terminate]. "fork a new downloading process" self updateDownloader: [urls do: [:url | waitSema wait. queue nextPut: url. doc _ HTTPClient httpGet: url. doc class == String ifTrue: [queue nextPut: #failed. self updateDownloader: nil. Processor activeProcess terminate] ifFalse: [canPeek _ 120 min: doc size. front _ doc next: canPeek. doc skip: -1 * canPeek. (front beginsWith: ' 1]) size > 0 ifTrue: [self halt: file first , ' has multiple periods']. fileNamesInOrder _ fileNames asSortedCollection: [:a :b | a initialIntegerOrNil < b initialIntegerOrNil]. names _ ServerDirectory groupNames asSortedArray. choice _ (SelectionMenu labelList: names selections: names) startUp. choice == nil ifTrue: [^ self]. self putUpdateMulti: fileNamesInOrder fromDirectory: updateDirectory onto: (ServerDirectory serverInGroupNamed: choice) ! ! !SqueakUpdateStreamManager methodsFor: 'storing updates' stamp: 'ar 5/14/2003 15:53'! checkNames: list "Look at these names for update and see if they are OK" list do: [:local | (local count: [:char | char == $.]) > 1 ifTrue: [ self inform: 'File name ',local,' may not have more than one period'. ^ false]. local size > 26 ifTrue: ["allows for 5 digit update numbers" self inform: 'File name ',local,' is too long. Please rename it.'. ^ false]. (local at: 1) isDigit ifTrue: [ self inform: 'File name ',local,' may not begin with a number'. ^ false]. (local findDelimiters: '%/* ' startingAt: 1) <= local size ifTrue: [ self inform: 'File name ',local,' may not contain % / * or space'. ^ false]]. ^ true ! ! !SqueakUpdateStreamManager methodsFor: 'storing updates' stamp: 'ar 3/27/2004 22:12'! checkServers: aGroup withPrefix: prefix andParseListInto: listBlock "Check that all servers are up and have the latest Updates.list. Warn user when can't write to a server that can still be read. The contents of updates.list is parsed into {{vers. {fileNames*}}*}, and returned via the listBlock." | final fileSize this serverList listContents decided myContents abort | serverList _ aGroup. final _ OrderedCollection new. fileSize _ 0. listContents _ ''. "list of updates" abort _ false. serverList do: [:aServer | decided _ false. this _ [aServer getFileNamed: prefix , 'updates.list'] on: Error do:[:ex| Transcript cr; show: ex. ex return: nil]. this ifNil:[^#()]. (this isKindOf: RWBinaryOrTextStream) ifTrue:[ this := this ascii contents. ]. decided not & (this size > fileSize) ifTrue: ["new has a longer update.list" fileSize _ this size. final do: [:each | abort _ self outOfDate: each]. (final _ OrderedCollection new) add: aServer. listContents _ this. listBlock value: (self parseListContents: listContents). decided _ true]. decided not & (this size < fileSize) ifTrue: [abort _ self outOfDate: aServer. decided _ true]. decided not ifTrue: [myContents _ this. myContents = listContents ifTrue: [final add: aServer] ifFalse: [abort _ self outOfDate: aServer]]. abort ifTrue: [^ Array new]. ]. ^ final ! ! !SqueakUpdateStreamManager methodsFor: 'storing updates' stamp: 'ar 12/27/2004 10:02'! installUpdateStream "Set up a new update stream, e.g., post an update.list with the appropriate contents." | myServers updateStrm listContents version versIndex aServer | aServer := ServerDirectory new fullPath: uploadUrl. myServers _ self checkServers: aServer serversInGroup withPrefix: '' andParseListInto: [:x | listContents _ x]. listContents ifNil:[listContents := #()]. version _ self packageVersion. versIndex _ (listContents collect: [:pair | pair first]) indexOf: version. versIndex = 0 ifFalse:[ self inform: 'An update stream for ', self packageVersion,' already exists at ', self uploadUrl. ^false ]. myServers size = 0 ifFalse:[ | msg | msg := String streamContents:[:s| s nextPutAll: 'It looks as if there is an update stream already at'; cr. s nextPutAll: uploadUrl; cr. s nextPutAll:' It currently contains '. s print: (listContents collect:[:pair| pair first]); cr. ]. (self confirm: msg trueChoice: 'Proceed - add an entry for ', self packageVersion falseChoice: 'Abort - I got something wrong with the location.') ifFalse:[^false]. ]. "Append new version to updates following my version" listContents _ listContents copyWith: {self packageVersion. {}}. updateStrm _ ReadStream on: (String streamContents: [:s | self writeList: listContents toStream: s]). updateStrm reset. aServer putFile: updateStrm named: 'updates.list'. Transcript cr; show: self packageVersion, ': updates.list written on server ', aServer moniker. aServer closeGroup. (self confirm: (self packageVersion,' now has its update stream at\', self uploadUrl, '\Do you want me to post an initial update (for testing)?') withCRs) ifFalse:[^true]. self publishTestUpdate. ^true! ! !SqueakUpdateStreamManager methodsFor: 'storing updates' stamp: 'ar 12/27/2004 10:03'! outOfDate: aServer "Inform the user that this server does not have a current version of 'Updates.list' Return true if the user does not want any updates to happen." | response | response _ UIManager default chooseFrom: #('Install on others' 'Cancel entire update') title: 'The server ', aServer moniker, ' is not up to date. Please store the missing updates maually.'. ^ response ~= 1! ! !SqueakUpdateStreamManager methodsFor: 'storing updates' stamp: 'ar 12/27/2004 10:03'! putUpdate: fileStrm on: aServer "Put this file out as an Update on the servers of my group. Each version of the system may have its own set of update files, or they may all share the same files. 'updates.list' holds the master list. Each update is a fileIn whose name begins with a number. See readServerUpdatesThrough:saveLocally:updateImage:. When two sets of updates are stored on the same directory, one of them has a * in its serverUrls description. When that is true, the first word of the description is put on the front of 'updates.list', and that index file is used." | myServers updateStrm newName response localName seq indexPrefix listContents version versIndex lastNum stripped | localName _ fileStrm localName. fileStrm size = 0 ifTrue: [^ self inform: 'That file has zero bytes!! May have a new name.']. (fileStrm contentsOfEntireFile includes: Character linefeed) ifTrue: [self notifyWithLabel: 'That file contains linefeeds. Proceed if... you know that this is okay (e.g. the file contains raw binary data).']. fileStrm reset. (self checkNames: {localName}) ifFalse: [^ nil]. "illegal characters" response _ UIManager default chooseFrom: #('Install update' 'Cancel update') title: 'Do you really want to broadcast the file ', localName, '\for every user of ' withCRs, self packageVersion, '?'. response = 1 ifFalse: [^ nil]. "abort" aServer openGroup. indexPrefix _ (aServer groupName includes: $*) ifTrue: [(aServer groupName findTokens: ' ') first] "special for internal updates" ifFalse: ['']. "normal" myServers _ self checkServers: aServer serversInGroup withPrefix: indexPrefix andParseListInto: [:x | listContents _ x]. myServers size = 0 ifTrue: [aServer closeGroup. ^ self]. version _ self packageVersion. versIndex _ (listContents collect: [:pair | pair first]) indexOf: version. versIndex = 0 ifTrue: [self inform: 'There is no section in updates.list for your version'. aServer closeGroup. ^ nil]. "abort" "A few affirmations..." versIndex < listContents size ifTrue: [(self confirm: 'This system, ', version , ' is not the latest version.\Make update for an older version?' withCRs) ifFalse: [aServer closeGroup. ^ nil]]. "abort" (listContents at: versIndex) last isEmpty ifTrue: [(self confirm: 'Please confirm that you mean to issue the first update for ' , version , '\(otherwise something is wrong).' withCRs) ifFalse: [aServer closeGroup. ^ nil]]. "We now determine next update number to be max of entire index" lastNum _ listContents inject: 0 into: [:max :pair | pair last isEmpty ifTrue: [max] ifFalse: [max max: (pair last last initialIntegerOrNil ifNil:[0])]]. "Save old copy of updates.list on local disk" FileDirectory default deleteFileNamed: indexPrefix , 'updates.list.bk'. self writeList: listContents toStream: (FileStream fileNamed: self packageVersion,'-',indexPrefix , 'updates.list.bk'). "append name to updates with new sequence number" seq _ (lastNum + 1) printString padded: #left to: 4 with: $0. "strip off any old seq number" stripped _ localName copyFrom: (localName findFirst: [:c | c isDigit not]) to: localName size. newName _ seq , stripped. listContents at: versIndex put: {version. (listContents at: versIndex) last copyWith: newName}. "Write a new copy on all servers..." updateStrm _ ReadStream on: (String streamContents: [:s | self writeList: listContents toStream: s]). myServers do: [:server | fileStrm reset. "reopen" server putFile: fileStrm named: newName retry: true. updateStrm reset. server putFile: updateStrm named: indexPrefix , 'updates.list' retry: true. Transcript show: 'Update succeeded on server ', server moniker; cr]. aServer closeGroup. Transcript cr; show: 'Be sure to test your new update!!'; cr. "rename the file locally (may fail)" [fileStrm directory rename: localName toBe: newName] on: Error do:[:ex| ex return].! ! !SqueakUpdateStreamManager methodsFor: 'storing updates' stamp: 'ar 12/27/2004 10:25'! putUpdateMulti: list fromDirectory: updateDirectory onto: aServer "Put these files out as an Update on the servers of my group. List is an array of local file names with or without number prefixes. Each version of the system has its own set of update files. 'updates.list' holds the master list. Each update is a fileIn whose name begins with a number. See Utilities class absorbUpdatesFromServer." | myServers updateStrm lastNum response newNames file numStr indexPrefix listContents version versIndex seq stripped | (self checkNames: (list collect: "Check the names without their numbers" [:each | each copyFrom: (each findFirst: [:c | c isDigit not]) to: each size])) ifFalse: [^ nil]. response _ UIManager default chooseFrom: #('Install update' 'Cancel update') title: 'Do you really want to broadcast ', list size printString, ' updates', '\to every Squeak user who updates from ' withCRs, aServer groupName, '?'. response = 1 ifFalse: [^ nil]. "abort" aServer openGroup. indexPrefix _ (aServer groupName includes: $*) ifTrue: [(aServer groupName findTokens: ' ') first] "special for internal updates" ifFalse: ['']. "normal" myServers _ self checkServers: aServer serversInGroup withPrefix: indexPrefix andParseListInto: [:x | listContents _ x]. myServers size = 0 ifTrue: [aServer closeGroup. ^ self]. version _ self packageVersion printString. versIndex _ (listContents collect: [:pair | pair first]) indexOf: version. versIndex = 0 ifTrue: [self inform: 'There is no section in updates.list for your version'. aServer closeGroup. ^ nil]. "abort" lastNum _ (listContents at: versIndex) last last initialIntegerOrNil. versIndex < listContents size ifTrue: [response _ UIManager default chooseFrom: #('Make update for an older version' 'Cancel update') title: 'This package, ', version, ' is not the latest version'. response = 1 ifFalse: [aServer closeGroup. ^ nil]. numStr _ self request: 'Please confirm or change the starting update number' initialAnswer: (lastNum+1) printString. lastNum _ numStr asNumber - 1]. "abort" "Save old copy of updates.list on local disk" FileDirectory default deleteFileNamed: indexPrefix , 'updates.list.bk'. self writeList: listContents toStream: (FileStream fileNamed: indexPrefix , 'updates.list.bk'). "Append names to updates with new sequence numbers" newNames _ list with: (lastNum+1 to: lastNum+list size) collect: [:each :num | seq _ num printString padded: #left to: 4 with: $0. "strip off any old seq number" stripped _ each copyFrom: (each findFirst: [:c | c isDigit not]) to: each size. seq , stripped]. listContents at: versIndex put: {version. (listContents at: versIndex) second , newNames}. "Write a new copy on all servers..." updateStrm _ ReadStream on: (String streamContents: [:s | self writeList: listContents toStream: s]). myServers do: [:server | list doWithIndex: [:local :ind | file _ updateDirectory oldFileNamed: local. server putFile: file named: (newNames at: ind) retry: true. file close]. updateStrm reset. server putFile: updateStrm named: indexPrefix , 'updates.list' retry: true. Transcript show: 'Update succeeded on server ', server moniker; cr]. aServer closeGroup. Transcript cr; show: 'Be sure to test your new update!!'; cr. "rename the file locally" list with: newNames do: [:local :newName | updateDirectory rename: local toBe: newName]. ! ! !SqueakUpdateStreamManager methodsFor: 'storing updates' stamp: 'ar 5/14/2003 18:32'! updateInstallVersion: newVersion "For each server group, ask whether we want to put the new version marker (eg 'Squeak2.3') at the end of the file. Current version of Squeak must be the old one when this is done. ServerDirectory new updateInstallVersion: 'Squeak9.9test' " | myServers updateStrm names choice indexPrefix listContents version versIndex | [names _ ServerDirectory groupNames asSortedArray. choice _ (SelectionMenu labelList: names selections: names) startUp. choice == nil] whileFalse: [indexPrefix _ (choice endsWith: '*') ifTrue: [(choice findTokens: ' ') first] "special for internal updates" ifFalse: ['']. "normal" myServers _ self checkServers: (ServerDirectory serverInGroupNamed: choice) serversInGroup withPrefix: indexPrefix andParseListInto: [:x | listContents _ x]. myServers size = 0 ifTrue: [^ self]. version _ self packageVersion printString. versIndex _ (listContents collect: [:pair | pair first]) indexOf: version. versIndex = 0 ifTrue: [^ self inform: 'There is no section in updates.list for your version']. "abort" "Append new version to updates following my version" listContents _ listContents copyReplaceFrom: versIndex+1 to: versIndex with: {{newVersion. {}}}. updateStrm _ ReadStream on: (String streamContents: [:s | self writeList: listContents toStream: s]). myServers do: [:aServer | updateStrm reset. aServer putFile: updateStrm named: indexPrefix ,'updates.list'. Transcript cr; show: indexPrefix ,'updates.list written on server ', aServer moniker]. self closeGroup]! ! !SqueakUpdateStreamManager methodsFor: 'storing updates' stamp: 'ar 3/27/2004 22:28'! writeList: listContents toStream: strm "Write a parsed updates.list out as text. This is the inverse of parseListContents:" | fileNames version | strm reset. listContents do: [:pair | version _ pair first. fileNames _ pair last. strm nextPut: $#; nextPutAll: version; cr. fileNames do: [:fileName | strm nextPutAll: fileName; cr]]. strm close! ! !SqueakUpdateStreamManager methodsFor: 'updates from disk' stamp: 'ar 5/14/2003 19:22'! applyUpdatesFromDisk "Utilities applyUpdatesFromDisk" "compute highest update number" | updateDirectory updateNumbers | updateDirectory _ self getUpdateDirectory. updateNumbers _ updateDirectory fileNames collect: [:fn | fn initialIntegerOrNil] thenSelect: [:fn | fn notNil]. self applyUpdatesFromDiskToUpdateNumber: (updateNumbers inject: 0 into: [:max :num | max max: num]) stopIfGap: false! ! !SqueakUpdateStreamManager methodsFor: 'updates from disk' stamp: 'ar 5/14/2003 19:27'! applyUpdatesFromDiskToUpdateNumber: lastUpdateNumber stopIfGap: stopIfGapFlag "To use this mechanism, be sure all updates you want to have considered are in a folder named 'updates' which resides in the same directory as your image. Having done that, simply evaluate: Utilities applyUpdatesFromDiskToUpdateNumber: 1234 stopIfGap: false and all numbered updates <= lastUpdateNumber not yet in the image will be loaded in numerical order." | previousHighest currentUpdateNumber done fileNames aMessage updateDirectory loaded | updateDirectory _ self getUpdateDirectory. previousHighest _ self highestUpdate. currentUpdateNumber _ previousHighest. done _ false. loaded _ 0. [done] whileFalse: [ currentUpdateNumber _ currentUpdateNumber + 1. currentUpdateNumber > lastUpdateNumber ifTrue: [done _ true] ifFalse: [fileNames _ updateDirectory fileNamesMatching: (currentUpdateNumber printString padded: #left to: 4 with: $0) , '*'. fileNames size > 1 ifTrue: [^ self inform: 'ambiguity -- two files both start with ' , currentUpdateNumber printString , ' (at this point it is probably best to remedy the situation on disk, then try again.)']. fileNames size == 0 ifTrue: [Transcript cr; show: 'gap in updates from disk for update number '; print: currentUpdateNumber; show: ' found...'. done _ stopIfGapFlag] ifFalse: [self newChangesFromStream: (updateDirectory readOnlyFileNamed: fileNames first) named: fileNames first. self registerUpdate: currentUpdateNumber. loaded _ loaded + 1]]]. aMessage _ loaded = 0 ifTrue: ['No new updates found.'] ifFalse: [loaded printString , ' update(s) loaded.']. self inform: aMessage , ' Highest numbered update is now ' , (currentUpdateNumber - 1) printString , '.'! ! !SqueakUpdateStreamManager methodsFor: 'updates from disk' stamp: 'ar 5/14/2003 15:47'! fileInFromUpdatesFolder: numberList "File in a series of updates with the given updates numbers, from the updates folder in the default directory. The file-ins are done in numeric order, even if numberList was not sorted upon entry. This is useful for test-driving the retrofitting of a possibly discontinguous list of updates from an alpha version back to a stable release. Utilities fileInFromUpdatesFolder: #(4745 4746 4747 4748 4749 4750 4751 4752 4754 4755 4761 4762 4767 4769). " | fileNames fileNamesInOrder file updateDirectory | updateDirectory _ FileDirectory default directoryNamed: 'updates'. fileNames _ updateDirectory fileNames select: [:n | n first isDigit and: [numberList includes: n initialIntegerOrNil]]. (file _ fileNames select: [:n | (n occurrencesOf: $.) > 1]) size > 0 ifTrue: [self error: file first , ' has multiple periods']. fileNamesInOrder _ fileNames asSortedCollection: [:a :b | a initialIntegerOrNil < b initialIntegerOrNil]. fileNamesInOrder do: [:aFileName | (updateDirectory readOnlyFileNamed: aFileName) fileIntoNewChangeSet]! ! !SqueakUpdateStreamManager methodsFor: 'updates from disk' stamp: 'ar 5/14/2003 19:22'! getUpdateDirectory ^((FileDirectory default directoryNamed: 'updates') directoryNamed: self packageVersion)! ! !SqueakUpdateStreamManager methodsFor: 'misc' stamp: 'ar 5/14/2003 15:52'! updateComment "The following used to be at the beginning of the update file. Now it is here to simplify parsing the file... * To add a new update: Name it starting with a new four-digit code. * Do not use %, /, *, space, or more than one period in the name of an update file. * The update name does not need to have any relation to the version name. * Figure out which versions of the system the update makes sense for. * Add the name of the file to each version's category below. * Put this file and the update file on all of the servers. * * To make a new version of the system: Pick a name for it (no restrictions) * Put # and exactly that name on a new line at the end of this file. * During the release process, fill in exactly that name in the dialog box. * Put a copy of updates.list on the server. * * Special file with a different name for Disney Internal Updates. * No need to move or rename files to release them to external updates. "! ! !DefaultUpdateStreamManager methodsFor: 'initialize' stamp: 'ar 5/14/2003 19:29'! initialize self updateUrlLists isEmpty ifFalse:[ downloadUrl := self updateUrlLists first first. ]. ! ! !DefaultUpdateStreamManager methodsFor: 'update api' stamp: 'ar 5/14/2003 17:22'! publishUpdate: aStream "Put this file out as an Update on the servers." | names choice | names _ ServerDirectory groupNames asSortedArray. choice _ (SelectionMenu labelList: names selections: names) startUp. choice == nil ifTrue: [^ self]. self putUpdate: aStream on: (ServerDirectory serverInGroupNamed: choice)! ! !DefaultUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 19:39'! changeSetPrefix ^''! ! !DefaultUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 17:01'! downloadUrl: aUrlString "this won't work" self shouldNotImplement.! ! !DefaultUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 16:36'! highestUpdate ^SystemVersion current highestUpdate! ! !DefaultUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 16:43'! highestUpdate: updateNum "This works differently in conjunction with SystemVersion. The highest update is computed automatically." ^self shouldNotImplement! ! !DefaultUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 18:19'! packageVersion ^SystemVersion current version! ! !DefaultUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 16:41'! registerUpdate: updateNum SystemVersion current registerUpdate: updateNum! ! !DefaultUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 19:30'! serverUrls "Redirect this to Utilities where the updates used to live" ^Utilities serverUrls collect:[:each| 'http://',each,'updates/']! ! !DefaultUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 16:45'! setUpdateServer: groupName "Utilities setUpdateServer: 'Squeakland' " | entry index | entry _ self updateUrlLists detect: [:each | each first = groupName] ifNone: [^self]. index _ self updateUrlLists indexOf: entry. self updateUrlLists removeAt: index. self updateUrlLists addFirst: entry! ! !DefaultUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/14/2003 18:42'! updateUrlLists "Redirect this to Utilities where the updates used to live" ^Utilities updateUrlLists collect:[:nameAndList| Array with: nameAndList first with: (nameAndList last collect:[:pseudoUrl| 'http://', pseudoUrl])]! ! !DefaultUpdateStreamManager methodsFor: 'testing' stamp: 'ar 5/14/2003 16:46'! isUpdateLoaded: updateNum "Answer whether this update is already loaded" ^SystemVersion current updates includes: updateNum! ! !DefaultUpdateStreamManager methodsFor: 'loading updates' stamp: 'ar 12/27/2004 09:46'! chooseUpdateList "When there is more than one set of update servers, let the user choose which we will update from. Put it at the front of the list. Return false if the user aborted. If the preference #promptForUpdateServer is false, then suppress that prompt, in effect using the same server choice that was used the previous time (a convenience for those of us who always answer the same thing to the prompt.)" | index him | ((self updateUrlLists size > 1) and: [Preferences promptForUpdateServer]) ifTrue:[ index _ UIManager default chooseFrom: (self updateUrlLists collect: [:each | each first]) title: 'Choose a group of servers from which to fetch updates.'. index > 0 ifTrue: [him _ self updateUrlLists at: index. self updateUrlLists removeAt: index. self updateUrlLists addFirst: him]. ^ index > 0]. ^ true! ! !SMCardUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/15/2003 23:46'! packageVersion "Answer the full package version" ^self smCard name, '-', self smCard currentVersion asString! ! !SMCardUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/15/2003 23:46'! smCard ^smCard! ! !SMCardUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/15/2003 23:46'! smCard: aCard smCard := aCard! ! !SimpleUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/15/2003 23:47'! packageVersion ^packageVersion! ! !SimpleUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 5/15/2003 23:47'! packageVersion: aString packageVersion := aString! ! !TweakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 12/12/2004 10:51'! highestUpdate ^highestUpdate ifNil:[highestUpdate := super highestUpdate]! ! !TweakUpdateStreamManager methodsFor: 'accessing' stamp: 'ar 12/12/2004 10:47'! highestUpdate: updateNum highestUpdate := updateNum! ! !UpdateManager class methodsFor: 'utilities' stamp: 'ar 3/27/2004 22:00'! allRegisteredManagers "UpdateManager allRegisteredManagers" ^self subclasses inject: #() into:[:list :aClass| list, aClass allRegisteredManagers]! ! !SMCardUpdateStreamManager class methodsFor: 'utilities' stamp: 'ar 5/15/2003 23:55'! allRegisteredManagers ^super allRegisteredManagers, self managersForSqueakMap! ! !SMCardUpdateStreamManager class methodsFor: 'utilities' stamp: 'ar 5/15/2003 23:54'! includeUnloadedCardManagers "Answer whether we should include SMCards which haven't been installed in the list of managers. Typically we won't but in some situations we may" ^false! ! !SMCardUpdateStreamManager class methodsFor: 'utilities' stamp: 'ar 5/15/2003 23:55'! managerForCard: smCard "Scan smCard to see if it contains the update manager tags" | uploadUrl downloadUrl mgr | downloadUrl := self valueOfTag: '[loadUpdatesAt:' in: smCard description. downloadUrl ifNil:[^nil]. uploadUrl := self valueOfTag: '[storeUpdatesAt:' in: smCard description. mgr := self new. mgr downloadUrl: downloadUrl. mgr uploadUrl: uploadUrl. mgr smCard: smCard. ^mgr! ! !SMCardUpdateStreamManager class methodsFor: 'utilities' stamp: 'ar 1/17/2005 11:03'! managersForSqueakMap "UpdateManager managersForSqueakMap" "Scan SqueakMap and figure out update managers" | all mgr | all := Array new writeStream. (Smalltalk at: #SMSqueakMap ifAbsent:[^#()]) default cards do:[:smCard| (smCard isInstalled or:[self includeUnloadedCardManagers]) ifTrue:[ mgr := self managerForCard: smCard. mgr ifNotNil:[all nextPut: mgr]. ]. ]. ^all contents! ! !SMCardUpdateStreamManager class methodsFor: 'utilities' stamp: 'ar 5/15/2003 23:54'! valueOfTag: tag in: aString " self valueOfTag: '[foo-bar-baz:' in:' This is some text with a [foo-bar-baz: http://foo.bar.baz/mumble ] thrown in here somewhere' " | startIndex endIndex value | startIndex := aString findString: tag. startIndex = 0 ifTrue:[^nil]. startIndex := startIndex + tag size. endIndex := aString indexOf: $] startingAt: startIndex. endIndex = 0 ifTrue:[^nil]. value := aString copyFrom: startIndex to: endIndex-1. ^value withBlanksTrimmed ! ! !SimpleUpdateStreamManager class methodsFor: 'utilities' stamp: 'ar 3/27/2004 22:01'! allRegisteredManagers self == SimpleUpdateStreamManager ifFalse:[^#()]. ^self registry! ! !SimpleUpdateStreamManager class methodsFor: 'utilities' stamp: 'ar 3/27/2004 22:09'! register: packageVersion uploadUrl: uploadUrl downloadUrl: downloadUrl "register me, e.g., SimpleUpdateStreamManager register: 'Test-2.3' uploadUrl: 'ftp://raab@luxator.cs.uni-magdeburg.de/~/public_html/squeak/updates/test' downloadUrl: 'http://isgwww.cs.uni-magdeburg.de/~raab/squeak/updates/test' " | mgr | self unregister: packageVersion. mgr := self new. mgr packageVersion: packageVersion. mgr uploadUrl: uploadUrl. mgr downloadUrl: downloadUrl. self registry add: mgr. ^mgr! ! !SimpleUpdateStreamManager class methodsFor: 'utilities' stamp: 'ar 5/15/2003 23:56'! registry ^Registry ifNil:[Registry := OrderedCollection new]! ! !SimpleUpdateStreamManager class methodsFor: 'utilities' stamp: 'ar 3/27/2004 22:10'! unregister: packageVersion "register me" Registry := self registry reject:[:any| any packageVersion = packageVersion]. ! ! !TweakUpdateStreamManager class methodsFor: 'initialize' stamp: 'ar 8/10/2004 15:43'! default ^self registry detect:[:any| any packageVersion = TrackingVersion]! ! !TweakUpdateStreamManager class methodsFor: 'initialize' stamp: 'tak 2/19/2005 19:10'! initialize "TweakUpdateStreamManager initialize" "Register the update stream" self register1Point0. self register1Point1Alpha. self registerNihongo7. TrackingVersion ifNil:[TrackingVersion := 'SqueakNihongo7'].! ! !TweakUpdateStreamManager class methodsFor: 'initialize' stamp: 'ar 3/27/2004 22:31'! loadUpdates "Load updates" self default loadUpdates! ! !TweakUpdateStreamManager class methodsFor: 'initialize' stamp: 'ar 12/12/2004 10:48'! register1Point0 "Register the update stream" TweakUpdateStreamManager register: 'Tweak-1.0' uploadUrl: 'ftp://tweak@squeakalpha.org/external/updates' downloadUrl: 'http://squeakalpha.org/tweak/external/updates'. ! ! !TweakUpdateStreamManager class methodsFor: 'initialize' stamp: 'ar 12/12/2004 10:48'! register1Point1Alpha "Register the update stream" TweakUpdateStreamManager register: 'Tweak-1.1-alpha' uploadUrl: 'ftp://tweak@squeakalpha.org/external/updates' downloadUrl: 'http://squeakalpha.org/tweak/external/updates'. ! ! !TweakUpdateStreamManager class methodsFor: 'initialize' stamp: 'tak 2/19/2005 20:01'! registerNihongo7 "Register the update stream" " ServerDirectory addServer: (ServerDirectory new type: #ftp; server: 'squeakland.jp'; directory: 'nihongo7/updates'; user: 'updates'; groupName: 'squeakNihongoUpdates') named: 'SqueakNihongoUpdates'. " TweakUpdateStreamManager register: 'SqueakNihongo7' uploadUrl: 'ftp://updates@squeakland.jp/nihongo7/updates' downloadUrl: 'http://squeakland.jp/nihongo7/updates'. ! ! !TweakUpdateStreamManager class methodsFor: 'initialize' stamp: 'ar 8/10/2004 15:44'! trackingVersion ^TrackingVersion! ! !TweakUpdateStreamManager class methodsFor: 'initialize' stamp: 'ar 8/10/2004 15:44'! trackingVersion: aVersion TrackingVersion := aVersion! ! TweakUpdateStreamManager initialize!