[squeak-dev] [proposal] migrating preferences to new images: UndefinedClass
Lauren Pullen
drurowin at gmail.com
Mon Apr 18 21:49:23 UTC 2022
Hi Marcel,
On 4/4/22 09:20, Marcel Taeumel wrote:
> If you could share more details on this issue, we might be able to re-configure the loading code for those (missing) classes. Otherwise, a generic "[ ... ] on: Error do: [:ex | ...]" might also help for a more robust "stream next" in Preferences class >> #loadPreferencesFrom:.
Take Metacello-GitHub. It defines a pragma preference on
MCGitHubRepository. If you try loading a my.prefs in an image where
Metacello-GitHub isn't loaded, preference loading will abruptly end.
> For more info on data streams, see implementors of:
>
> #classVersion
>
> #readDataFrom:size:
> #objectForDataStream:
> #withClassVersion:
I looked through ReferenceStream and followed along in the debugger and
some inspectors to get a feel for how it all worked.
Back to the MCGitHubRepository example, the ReferenceStream will try to
instantiate a MCGitHubRepository to fill the value for the 'provider'
instance variable of PragmaPreference... which rapidly fails unless it's
loaded.
I've got a quick version saved in the attached file, but it's only a
partial fix and is likely full of issues and not stable enough to
introduce to the inbox, to see if I'm on the right track.
( I changed the error class in the failing portion from Error to
KeyNotFound to match the class that SmalltalkImage>>at: signals to make
it easier to detect.
If this looks like a good direction to you, I'll proceed work on it.
-------------- next part --------------
'From Squeak5.3 of 30 November 2021 [latest update: #19461] on 15 April 2022 at 2:39:21 pm'!
!DiskProxy methodsFor: 'i/o' stamp: 'lrnp 4/15/2022 13:22'!
comeFullyUpOnReload: smartRefStream
"Internalize myself into a fully alive object after raw loading from a DataStream. (See my class comment.) DataStream will substitute the object from this eval for the DiskProxy."
| globalObj symbol pr nn arrayIndex env |
symbol := globalObjectName.
"See if class is mapped to another name"
(smartRefStream respondsTo: #renamed) ifTrue:
[| maybeReadDataFromContext maybeReadArrayContext |
"Ugh; so ugly and brittle. If there were pragmas in the relevant methods we could search, etc. eem 7/3/2017 15:54"
maybeReadArrayContext := thisContext sender sender sender sender.
maybeReadDataFromContext := maybeReadArrayContext sender sender sender sender.
"If in outPointers in an ImageSegment, remember original class name.
See mapClass:installIn:. Would be lost otherwise." "Anyone know where mapClass:installIn: is/was? eem 7/3/2017 15:55"
(maybeReadDataFromContext method selector == #readDataFrom:size:
and: [maybeReadDataFromContext receiver class == NativeImageSegment
and: [maybeReadArrayContext method == (DataStream compiledMethodAt: #readArray)]]) ifTrue:
[arrayIndex := maybeReadArrayContext tempAt: 4.
"index var in readArray. Later safer to find i on stack of context."
smartRefStream renamedConv at: arrayIndex put: symbol]. "save original name"
symbol := smartRefStream renamed at: symbol ifAbsent: [symbol]]. "map"
env := Environment current.
globalObj := env valueOf: symbol ifAbsent: [
preSelector == nil & (constructorSelector = #yourself) ifTrue: [
Transcript cr; show: symbol, ' is undeclared.'.
env undeclare: symbol.
^ nil].
^ (KeyNotFound key: symbol) messageText: 'Global "', symbol, '" not found'; signal].
((symbol == #World) and: [Smalltalk isMorphic not]) ifTrue: [
self inform: 'These objects will work better if opened in a Morphic World.
Dismiss and reopen all menus.'].
preSelector ifNotNil: [
Symbol hasInterned: preSelector ifTrue: [:selector |
[globalObj := globalObj perform: selector] on: Error do: [:ex |
ex messageText = 'key not found' ifTrue: [^ nil].
^ ex signal]]
].
symbol == #Project ifTrue: [
(constructorSelector = #fromUrl:) ifTrue: [
nn := (constructorArgs first findTokens: '/') last.
nn := (nn findTokens: '.|') first.
pr := Project named: nn.
^ pr ifNil: [self] ifNotNil: [pr]].
pr := globalObj perform: constructorSelector withArguments: constructorArgs.
^ pr ifNil: [self] ifNotNil: [pr]]. "keep the Proxy if Project does not exist"
constructorSelector ifNil: [^ globalObj].
Symbol hasInterned: constructorSelector ifTrue: [:selector |
[^ globalObj perform: selector withArguments: constructorArgs] on: Error do: [:ex |
ex messageText = 'key not found' ifTrue: [^ nil].
^ ex signal]
].
"args not checked against Renamed"
^ nil "was not in proper form"! !
!Preferences class methodsFor: 'initialization - save/load' stamp: 'lrnp 4/15/2022 14:21'!
restorePreferencesFromDisk
(FileDirectory default fileExists: 'my.prefs')
ifTrue: [ Cursor wait showWhile: [
[[ self loadPreferencesFrom: 'my.prefs' ]
on: KeyNotFound
do: [:ex | Transcript showln: 'Skipped preference for unloaded class ', ex key; flush. ex return: nil]]
on: Error
do: [ :ex | self inform: 'there was an error restoring the preferences' ]
] ]
ifFalse: [ self inform: 'you haven''t saved your preferences yet!!' ].
! !
More information about the Squeak-dev
mailing list
|