. .

smalltalk

More Predictable than RTP

January 14, 2011 9:47:24.364

I've been building BottomFeeder without RTP for awhile now, but until I started looking at build automation for this new job, I hadn't fully automated it. That's something I've done now, and one thing that I really like about the process I use is the predictability.

With RTP, if you let it scan and strip, you're never really sure what it took out. Oh, sure, there's a report it generates, and you can go through that - but it's not easy to digest. Instead, I have a script that pulls out a set of named packages - this is one of the advantages to the newer releases of VW, btw - having defined blobs of code that have structure not only makes loading easier, it makes unloading easier. Here's what I have my script do:

"Unload the debugger and other tools"
(Store.Registry pundleNamed: 'Tools-Debugger')  ifNotNil: [:pundle |
	pundle leafItems do: [:each | each markNotModified].
	[pundle markNotModified; unloadFromImage] on: Warning do: [:ex | ex
	resume: true]].
(Store.Registry pundleNamed: 'Tools-Refactoring Browser')  ifNotNil: [:pundle |
	pundle leafItems do: [:each | each markNotModified].
	[pundle markNotModified; unloadFromImage] on: Warning do: [:ex | ex
	resume: true]].
(Store.Registry pundleNamed: 'Tools-Parcel Manager')  ifNotNil: [:pundle |
	pundle leafItems do: [:each | each markNotModified].
	[pundle markNotModified; unloadFromImage] on: Warning do: [:ex | ex
	resume: true]].
(Store.Registry pundleNamed: 'Tools-Changes')  ifNotNil: [:pundle |
	pundle leafItems do: [:each | each markNotModified].
	[pundle markNotModified; unloadFromImage] on: Warning do: [:ex | ex
	resume: true]].
(Store.Registry pundleNamed: 'Tools-File Browser')  ifNotNil: [:pundle |
	pundle leafItems do: [:each | each markNotModified].
	[pundle markNotModified; unloadFromImage] on: Warning do: [:ex | ex
	resume: true]].
(Store.Registry pundleNamed: 'UIPainter')  ifNotNil: [:pundle |
	pundle leafItems do: [:each | each markNotModified].
	[pundle markNotModified; unloadFromImage] on: Warning do: [:ex | ex
	resume: true]].
(Store.Registry pundleNamed: 'StoreForPostgreSQL')  ifNotNil: [:pundle |
	pundle leafItems do: [:each | each markNotModified].
	[pundle markNotModified; unloadFromImage] on: Warning do: [:ex | ex
	resume: true]].

The handler block allows the script to proceed if anything odd happens; I should probably be logging those events. The larger point is this: I know exactly what got pulled, and, more importantly - what didn't. Unless you're really careful (and you have to be careful every time code has changed), RTP will strip code from your application. That's usually safe, but if you use constructed message sends for any reason (good or bad), you can get smacked. I think this approach is vastly safer.

I've posted before on how I put the image into a runtime state, but it's worth going over again:

  • Have a subclass of UserApplication. Specify your prereq subsystems, and implement #main. In that method, start your application. It'll get called when it's safe to do so at startup, based on the prereqs you specified
  • Execute the following code after you do whatever other image prep is necessary:

"set up logging and exception handling"
DeploymentOptionsSystem current startInRuntime: true.
Notifier current: RuntimePackager.RuntimeEmergencyNotifier.
RuntimePackager.RuntimeManager errorLogPath: 'error.log'.
Notifier logToFile: true.
"set up runtime state"
UI.WindowManager noWindowBlock: [:windowManager | ].
stream := WriteStream on: String new.
stream nextPutAll: 'changeRequest'; cr; cr; tab.
stream nextPutAll: '^true'.
VisualLauncher compile: stream contents.
VisualLauncher allInstances do: [:each | each closeAndUnschedule.  each release].
ObjectMemory garbageCollect.
Workbook allInstances do: [:each | each closeRequest].
(Delay forSeconds: 20) wait.
Parcel searchPathModel value: (List with: (PortableFilename named: '.')).
SourceFileManager default discardSources.

"Now save the image such that this file doesn't get looked for at startup"
[ObjectMemory permSaveAs: runtime' thenQuit: false] fork.
[(Delay forSeconds: 25) wait.
RuntimeSystem isRuntime ifFalse: [ObjectMemory quit]] fork.

I actually use some of the RTP infrastructure (the runtime exception handler and logging) - I just don't use it to create the image. It's a pretty simple process, and once you have the script created, it's easy to have a "one button click" UI drive it - from another image

posted by James Robertson

 Share Tweet This