- Reading the ExtensionInfo
- Extension Construction
- Initialize, Start, Stop, and Terminate
- getExtensionId Function (Don't Rename)
- runExtensionBuild Function (Don't Rename, Optional)
- Build Extension
There are a few files that are crucial for an extension. Arguably, the most important one is the extension.cm file. These are the things to do in order to have a functional extension.cm file.
Reading the ExtensionInfo
The function called getExtensionInfo()
will be executed to read the extension's information from the extension.xml file in order to create the ExtensionInfo
object that contains the details of the extension:
/** * Actual extension info, dont change function name */ package ExtensionInfo getExtensionInfo() : referred { ExtensionInfo info = loadExtensionInfoFromXml(#:package); // insert code to modify anything about info here. return info; }
Extension Construction
The getExtension()
is used to construct and return the Extension
object of the extension within the extension.cm file. An example from the free Fika extension:
/** * Fika Office Extension. * Multi Catalog example. */ private class FikaOfficeExtension extends UltraLazyExtension { /** * Start. Place Init code here. */ public void start(ExtensionEnv env) { initFikaOffice(); super(env); } /** * Stop. */ public void stop(ExtensionEnv env) { super(env); cleanupFikaOffice(); } /** * Terminate. */ public void terminate(ExtensionEnv env) { super(env); cleanupFikaOffice(); } } /** * GenericOfficeExtension (dont change function name). */ package Extension getExtension() : referred { return FikaOfficeExtension(#:package); }
Initialize, Start, Stop, and Terminate
The initialize()
in the extension will be executed, then start()
will be executed. The difference is shown in the comments of the file containing the Extension
class:
* Protocol: * extension.initialize(); * extension.start(); * extension.stop(); * extension.start(); * extension.stop(); * extension.terminate();
These methods are supposed to give the extension some flexibility in placing code to execute.
For example, any code which can be cached about the extension is placed in initialize()
. So if the extension is to be quickly restarted by executing stop()
and then start()
, the cached data wouldn't be affected, until terminate()
is called to clear the cached data.
During install of extension updates
When the user's CET is installing a new update of your extension, a background process will download the new build of your extension, loads it and runs the initialize()
of your extension. This is done to verify the sanity of each extension as much as possible during the background install step before the new version is made available to the user.
Since the initialize()
method of your extension is also invoked in this context, it's important to ensure that it doesn't perform any operations that might affect the main CET process of the user, typically anything that affects states outside of runtime memory.
Some examples include:
- Manipulating preferences (Core settings)
- Preferences are stored as files on disk, which is also accessed by the main CET process
- Manipulating files on disk
- It would affect the main CET process if the existing running version of your extension also refers to the same file path.
- Manipulating some server state
- Manipulating any OS-level state, like registries.
In order to correctly exclude any operations above from happening in the context of background install, either consider moving these operations to extension start()
or filter these operations using the flag runningInInstallAndCloseMode
which would be true when it's in background install process.
/** * Initialize. */ public void initialize(ExtensionEnv env) { // Code that runs both during actual CET process and background install process if (!runningInInstallAndCloseMode) { // Code that runs only during actual CET process } }
getExtensionId Function (Don't Rename)
This is a secret unique id tied to the extension. The id must be unique for every extension, so make sure that you generate a new ID for your extension! You do this by calling generateFreeExtensionId()
or generateHardExtensionId()
, like this:
{ // Code used to create the code contents of 'getExtensionId' //generateHardExtensionId(#:package, extName).dumpAsCode();
//generateFreeExtensionId(#:package, extName).dumpAsCode();
// Running this will build the extension. //autoBuildExtension(#:package); }
running generateHardExtensionId(#:package, extName).dumpAsCode();
yields:
// Created 9/16/2020, restriction=hard ExtensionId extensionId(#"custom.fika.office", "Fika: Office"); // ID1=132447573232490000 // ID2=5179679976363646832 // ID3=-8665736940729459908 // ID4=-3542803030890134520 extensionId.id0 = int64(0x1d68c5d, 0xb9e29610); extensionId.id1 = int64(0x47e1eb7e, 0xd15bdf70); extensionId.id2 = int64(0x87bd1e2a, 0x5ad71b3c); extensionId.id3 = int64(0xced56f69, 0xfa9dc408); return extensionId;
which should be copy and pasted into getExtensionId()
like this:
package ExtensionId getExtensionId() : encrypted, referred { // Created 9/16/2020, restriction=hard ExtensionId extensionId(#"custom.fika.office", "Fika: Office"); // ID1=132447573232490000 // ID2=5179679976363646832 // ID3=-8665736940729459908 // ID4=-3542803030890134520 extensionId.id0 = int64(0x1d68c5d, 0xb9e29610); extensionId.id1 = int64(0x47e1eb7e, 0xd15bdf70); extensionId.id2 = int64(0x87bd1e2a, 0x5ad71b3c); extensionId.id3 = int64(0xced56f69, 0xfa9dc408); return extensionId; }
runExtensionBuild Function (Don't Rename, Optional)
This function is responsible for code that is run before your extension is built. For example, code to generate a keyword file, render thumbnails, or more. This function is optional and does not need to be included in the extension.cm file if not needed (not auto-generated on Extension
creation).
Example:
/** * Run extension build (dont change function name). */ package void runExtensionBuild(ExtensionInfo info) : referred { appendLightIcons(info.filesToInclude); symbol pkg = #:package; generateKeywordFile(pkg.str, "stdLightsLibrary", "cet/keys/"); info.filesToInclude << cmWritable("cet/keys/" # pkg.str # ".auto.keys"); reportRsFail++; if (!getFakeExtensionBuildMode()) { renderImagesInLibrary(pkg.str, "stdLightsLibrary"); info.filesToInclude << cmWritable("cm/core/DataSnapper." # pkg # ".*.cmbmp"); info.filesToInclude << cmWritable("custom/accessories/lights/" # "*.cmbmp"); } reportRsFail--; lowLevelBuildExtension(info); }
runExtensionBuild()
, it's not appropriate to call autoBuildExtension()
(because this would end up calling runExtensionBuild()
again recursively), so to perform the actual build, you call lowLevelBuildExtension()
instead.
Build Extension
After all the above is set up, execute autoBuildExtension()
:
/** * Build it! */ { autoBuildExtension(#:package); }
Comments
0 comments
Please sign in to leave a comment.