MOO Package Manager (MPM) 1.5
About
The MOO Package Manager is a configurable package manager written in MOO code and designed for ToastStunt (a LambdaMOO fork). It allows you to:
- download packages and automatically install them
- package code up on one MOO and make it available for installation on another MOO also using MPM
- package code up and make it avialable online to other MPM users by URL
- package code up and add it to a code repository which can be registered with any MPM
Change Log
All changes to this repo or MOO Package Manager are logged in CHANGELOG.md
Requirements
- ToastStunt 2.7+ (it may work on older versions, perhaps even Stunt, with some modifications)
- Ability to make outgoing network connections (the package manager uses the
curlbuiltin from ToastStunt for these connections) - A wizard bit
- LamdaCore or ToastCore derived MOO (or you'll need to do some hacking!)
- $string_utils, $object_utils, $command_utils, @program
- $diff_utils (this is available through the package manager, and the package manager can install it without it existing)
Warnings
- The MOO Package Manager is in
open betaand should be considered only mildly stable. You use this code at your own risk. - You should always test install new packages on a dev server to make sure nothing breaks.
- After loading a package but prior to installing, you should
@view-package loadedand review the verbs it will touch, and possibly review the code being to ensure you are OK with what you are installing. - By default the MOO Package Manager comes with one registered package repository which points to this repos /packages directory. You can add others at your own discresion, and at your own risk.
Installation
Hopefully, this will be the last time you need to manually install MOO code! At least, that's the goal. In order to install the MOO Package Manager you will need to copy and paste some code. The package manager code itself is quite long, so including it in this README is not effective. The code is stored in files, linked below.
Installing The Package Manager
@create #78 named MOO Package Manager@corify newObj# as $mpm- Open the MOO Package Manager Code
- Copy and paste the code into your MOO
- Open the MOO Package Manager Wizard Verbs Code
- Copy and paste the code into your MOO
- @create $waif named Memory Waif
- @corify newObj# as $memory_waif
- @prop $memory_waif.":data" [] rw
Note:
#78is typically the Generic Utility object, the same parent that $string_utils has. It may differ on your MOO.
Note:
@corifyadds a new property to$sysobj(#0on most systems). If you don't have this verb for some reason you can just@prop $sysobj.mpm newObj#
Note: If you have an issue copying the MOO Package Manager Wizard Verbs because
meis not defined, just change all references tometo the object# of your player bit (yourself).
Note: If you have trouble creating a property with [] (map) then create it with any value and then evaluate
;$memory_waif.:data = []
You will now have an $mpm object which encapsulates the majority of the MOO Package Manager's code. You will also have several helper verbs on your player bit that will allow you to interact with the package manager. For now, we are concerned with two of these: @load-package and @install-package.
Installing Your First Package
The MOO Package Manager is mostly self contained. However, it does rely on a package called Diff Utilities which it uses to present code diffs. The Diff Utilities is a repackage / update of the original Stunt utility that came bundled with the Improvise.db. We need to install this package in order for the MOO Package Manager to operate properly when it needs to update an existing verb (fourtunately, this won't be an issue, as Diff Utils is a brand new utility that you don't have on your MOO).
To install the Diff Utility follow these steps:
@load-package- Select
View Available Packages - Select
Slither's MOO Packages - Select the lastest version of
Diff Utilities - Review the package data and select
yeswhen ready @view-package loadedto see what the package will install@install-packageto kick off the package installation- Review the data presented and enter
yeswhen ready to install. - Follow the prompts to create a new object and install the package.
Note: For more information on installing a package see the Installing a Package section.
You should now have a working package manager, and a working Diff Utilities which you can reference with $diff_utils.
Upgrading MOO Package Manager
Upgrading MPM is straight-forward. Just run @load-package and check for an available update in Slither's MOO Packages. If there is an update available, you can install it. The version you install with the install instructions above may be out of date.
When you update, MPM will create a new version of itself. This is just in case there is an issue with the installation, you'll still have a working copy of MPM.
Upgrading MOO Package Manager Wizard Verbs
Whenever a new release of MPM comes out there will be an accompanying update to the wizard verbs. You should install the MPM update first (unless the MPM description specifies otherwise), and then update the MPM Wizard Verbs, to avoid backwards compatibility issues.
Loading a Package
The @load-package verb is used to browse packages/package info in registered package repositories and download a package into the MOO Package Manager, thus preparing it for installation. It also provides the option of specifying a package's URL directly, allowing you to load a package from anywhere.
Note: Only one package can be loaded at a time. Loading a new package will overwrite the previously loaded package.
Viewing a Package
@view-package will display a pretty printed dump of the package, which you can use to review. You will be given the option to view the property data and verb code included in the package.
After creating a package you can view it with @view-package created.
After you have loaded a package, you can view it with @view-package loaded.
Installing a Package
Warning: Seriously, you should test install packages on a dev server and not on production. Especially if you are installing a package that updates commonly used verbs on commonly used objects such as $object_utils, $string_utils, etc.
Warning: If you're going to YOLO it and install an untested package on production, please dump your database
@dump-databasefirst and make a copy of it on your server (in case you checkpoint after installing a package that breaks your MOO).
After loading and viewing a package you can @install-package to kick off the installation process. Installation is an interactive process that will require you to make decisions about how your new package is installed. There a number of decision points during the installation process which are outlined below.
When you first @install-package the package manager checks to see if the package hash matches the hashed version of the package map. If this fails, the package installation is aborted.
Note: If you are seeing a hash mismatch, it doesn't mean there is something wrong with the package. I have been seeing issues with this and I'm looking into why it is happening.
It will then check to see if this package has already been installed (by checking $mpm.installed_packages for a matching package id. If the package has already been installed, you will see a message alerting you of this, but you may continue your installation.
The package meta data (such as name, description, version, created at, etc.) will then be displayed and you will be prompted to confirm you want to install the package.
The package manager will then attempt to find a version of the object already existing on your server. It will check the obj# that was included in the hash (since many MOOs have the same obj# for utility packages like #20 (String Utils)). We then check if the name matches that of the package. If we are unable to find a matching object, we will check if the package has a cored reference, and if found, check their name against the package. You will then be prompted to decide if you want to update the existing object or create a new object.
Creating a new object is a good way to test a package that would otherwise make in-place updates to an existing object on your MOO. However, there are a few caveats. Even if you choose to create a new object, the dependencies of that object (IE: $string_utils, $object_utils, etc) will still be in place updates, as you are not given the option to create new versions of dependencies that exist on your MOO, as the packages code will be making cored references to those objects. However, you can always decline to make the in-place updates to the verbs.
Note: If you are creating a test object, and are prompted to update cored references, you should decline to update those references. You can always reinstall the package on top of your existing test object, and update the cored references on the second go around.
If the package manager cannot find a matching object, it will search for the closest ancestor of the origin object that it can find on your MOO, and offer to recreate the object from that ancestor. This will create not only a new origin object but potentially new ancestors. For example if the package has an origin object with ancestors like this:
#1
#78
#200
#500 (origin object)
And your MOO only has:
#1
#78
Then a new version of #200 and #500 will be created (with different object numbers most likely). And then package creation will continue.
At this point, the verbs, properties, and cored references of the objects in the package will begin to be created. Verbs and properties will be created if they do not exist.
If a verb exists and is different, you will be shown a diff and given the option to update or decline the update.
If a property exists and is different, you will be shown both property values and given the option to update or decline the update.
If a cored reference doesn't exist, it will be created.
If a cored reference exists and doesn't match, you will be propmted and given the option to accept or decline the update.
Warning: Take care when updating cored references, as they PROBABLY exist on your moo for a reason. If you are replacing an entire utility object it is probably OK to update its cored reference, but if the cored reference you are updating is for a dependency of the package you are installing, BEWARE! We are only installing the verbs USED BY THE PACKAGE. This means if you decided to create a new instance of String Utilities as part of this package, only a few verbs are likely being installed. You should NOT update your cored reference, or you'll be getting tons of tracebacks. Instead, choose NOT to update it, and then update the code from this package that is referencing the cored reference (IE: $widget_utils) to point to the NEW OBJECT you may have created. Remember that failing to do so when needed could result in a broken package.
If at any point, an object that is needed doesn't exist (if for example the package needed $widget_utils, which your MOO didn't have), the package manager will find the closest ancestor that your MOO does have, and offer to create the parent from that, in the same way it did with the origin object.
Note: Any property/verb additions or updates are logged in
$mpm.logalong with the old/new verb/prop values and any other data associated with the change. While the package manager doesn't currently offer a rollback option, if the worst happens, you'll have an audit log of the changes made and can attempt to manually fix/revert.
Warning: the
$mpm.logcan get really long. You may want to clear it from time to time.
What's in a package?
A package is a collection of everything needed to recreate an object and its dependencies on another MOO.
Origin Object
The origin object is the most important piece of your package. It serves as the starting point in building the dependency graph. By default all the verbs/props of the origin object are serialied. However, this behavior can be over-ridden.
| Serialized | Description | State |
|---|---|---|
| Cored References | Any props on $sysobj that have a value matching this object | Always Serialized |
| Verbs | The verbs defined on the object | All verbs serialized by default, but you can override and provide a list of verbs |
| Verb Supplementary Data | verb_args(), verb_info(), verb owned by a wizard |
Serialized for every included verb |
| Properties | The properties defiend on the object & their value | All props serialized by default, but you can override and ignore properties |
| Property Supplementary Data | Permissions | Serialized for every included prop |
Ancestor Objects
Ancestors are the parent(s) of the origin object. We serialize each of the ancestors but unlike the origin object we only serialize what we need from the ancestor.
| Serialized | Description | State |
|---|---|---|
| Cored References | Any props on $sysobj that have a value matching this object | Always Serialized |
| Properties | The properties defiend on the object & their value | All props serialized by default, but you can override and ignore properties |
| Property Supplementary Data | Permissions | Serialized for every included prop |
pass()ed verbs |
The verbs on the origin object that pass() to an ancestor |
Always Serialized |
| Verb Supplementary Data | verb_args(), verb_info(), verb owned by a wizard |
Serialized for every included verb |
Other Objects
A package may rely on more than it's ancestors. The dependency graph that is built scans for cored references to other objects that are defined in the code. For example if your origin object defines a verb that makes a call to $string_utils:name_and_number() then we will include $string_utils. This inclusion essentially creates a sub package, treating $string_utils as the origin object but serializing only the verbs on $string_utils that are called elsewhere in the package. If a verb in the $string_utils sub package calls $command_utils:suspend_if_needed then another sub package is created within the $string_utils sub package, treating $command_utils as the origin object, and so on and so forth, until all of the dependencies have been serialized throughout the graph.
| Serialized | Description | State |
|---|---|---|
| Cored References | Any props on $sysobj that have a value matching this object | Always Serialized |
| Properties | The properties defiend on the object & their value | All props serialized by default, but you can override and ignore properties |
| Property Supplementary Data | Permissions | Serialized for every included prop |
| referenced verbs | The verbs on this object that are referenced elsewhere in the package code | Always Serialized |
| Verb Supplementary Data | verb_args(), verb_info(), verb owned by a wizard |
Serialized for every included verb |
Not Included
Code referenced on objects such as player/dobj/iobj is deliberately not included in the package as this would create a gigantic dependency graph and essentially requrie updating a huge number of verbs just because a verb calls player:tell() once.
Note: It should technically be possible to make a package out of an object like Generic Player (#6) but experiences may vary. That has not been tested at this point. Feel free to ping me if you do it and let me know how it goes!
Making a Package
To make a package, you use the @make-package command and provide arguments. For example:
@make-package -> show the argument options
@make-package #20 -> start creating a package out of #20
Warning: The more complicated your code is, and the more reliant it is on other utilities/objects the larger your package is going to be.
When your package is finished, the package map and serialized package maps will be stored in the $mpm.last_created_package_map and $mpm.last_created_package_hash properties respectively. You will be given an option to display the encoded package to the screen so you can copy and paste it.
Warning: If your package is larger than your servers
MAX_QUEUED_OUTPUT(set in options.h or overridden with$server_options.max_queued_outputyou won't be able to print the entire package using@showor even a singlenotify(). In these cases$mpm:display_encoded_package()should help. Just make sure there are no extra spaces or non base64 characters at the end of the string after copy and pasting. If you get a network buffer error, try running the eval again.
Note: See the section on Making Packages Available Online for more information on how to make your package available online.
Package Creation Caveats
The package manager works best with mostly self contained code that doesn't rely on verbs across your entire MOO. In general, MOO code is pretty coupled, and so you may end up with a large dependency graph. If you are making a package, please consider how this might affect the usability of your package and consider decoupling your code, or creating smaller packages.
Note: Since the package manager is still beta, lots of experimentation, testing, and updates to the package manager will likely be needed to make it as robust as possible and capable of handling dependencies more smartly. Suggestions are welcome!
It is currently not possible to serialize a package which contains binary data such as ~1E. This is due to how we are currently encoding the packages. If you have suggestions for how we can do encode better, please reach out.
It is currently not possible to serialize packages that reference object numbers in their code. Use cored references instead.
It is currently not possible to serialize packages that make dynamic verb or property references such as:
verbname = "nn";
propname = "apropnamehere";
$string_utils:(verbname)(player);
$widget_utils.(propname);
$string_utils:("left")();
$widget_utils.("someprop");
This is due to the fact that we can't smartly serialize these references without actually parsing all the verb code to figure out what it is trying to call.
Note: If you are sure the dynamic prop or verb references will not break the functionality of your package (for instance if they just dynamically call verbs on the object being packaged) you can override the abortion of your package creation with the
--allow-dynamic-verb-callsand--allow-dynamic-prop-callsoptions.
Call to Action: Suggestions for how to deal with this are welcome. I'm considering just prompting the user to provide the verbs/props manually instead of failing the package creation entirely like we are doing now.
Multiple inheritance is not supported.
Package Creation Options
@make-package accepts a number of arguments outlined below:
| Argument | Description | Required |
|---|---|---|
| object number | the object number of the origin object, must be first argument provided |
yes |
| --select-verbs | enable dynamic selection of verbs on origin object to include via interactive prompt |
no |
| --fully-serialize-ancestry | enable full serialization of ancestors verbs (excluding objects whose parent is $nothing) | no |
| --serialize-#1 | enable full serialization of ancestors whose parent is $nothing | no |
| --verb-list=verbname1,verbname2,... | only serialize origin object verbs in this comma seperated list (no space after the ,!). Will still serailiaze cored obj/verbs that are referenced (IE: $string_utils:nn) |
no |
| --ignore-prop-list=propname1,propname2,#20.propname,... | if no obj# is provided, ignores any prop on any object with specified propname, if obj# is provided, ignores that prop on only that obj# | no |
| --reset-prop-value-list=obj.prop,obj.prop,... | if provided, when serializing obj.prop it will be reset to an empty/false version of whatever value it holds | no |
| --only-origin-object | Ignore all package dependencies and only serialize the origin object + ancestry | no |
| --ignore-all-cored-props | Ignore all cored properties, meaning the props & objects they reference will not be serialized in the package | no |
| --ignore-all-cored-verbs | Ignore all cored verbs, meaning the verbs and objects (ie: $string_utils:nn) that are referenced in code will not be serialized in the package | no |
| --dont-serialize-cored-aliases | If any object being serialized has cored aliases, such as $string_utils, they will not be included | |
| --ignore-all-non-cored-props | Ignores any properties defined on objects, causing them to not be serialized in the package | |
| --only-include-prop-list=obj.prop1,prop2,... | if obj# is provided, it will only include that prop on the specified obj, if no obj# provided it will include any matching prop on any obj being included in the package | no |
| --post-install-verb=verbname | Specify a verb that will be automatically run after a successful installation. Verb must exist on origin object and cannot accept any arguments. |
no |
| --target-self | this option overrides the default behavior and forces the package to be installed on the player installing it. Must be used in conjunction with --only-origin-object |
no |
| --allow-dynamic-verb-calls | this will prevent package creation from aborting when a dynamic verb call is detected. use with care. | no |
| --allow-dynamic-prop-calls | this will prevent package creation from aborting when a dynamic prop call is detected. use with care. | no |
| --dont-serialize-ancestry | This will prevent ancestors from being serialized, essentially setting the parent of all serialized objects to $nothing, and avoiding the need to rewire ancestors. useful if you aren't relying on ancestors verbs | no |
| --strip-trailing-comments | Strips any trailing comments (string literals) from the end of serialized verbs | no |
| --skip-generic-dependencies | Skips serializing known verbs on Utility Objects (think $string_utils:left or $object_utils:has_property) that are present in any ToastCore/LambdaCore db. Use with care as just because they are present doesn't mean changes may not have been made to them on source or target MOO | no |
| --convert-short-cored-to-long | This will auto convert short cored references like $lu or $su to $list_utils and $string_utils before doing any serializing or processing on them. Use this option if you have short cored references in your code | no |
| --dry-run | generates the package but does not save it, instead offers to display the generated package map | no |
Note: Arguments can be provided in any order, except for the object number, which must be first.
Below is an example of using --reset-prop-value-list to @make-package a new version of the MOO Package Manager (in this case, the obj# for the package manager is #24836).
@make-package $mpm --reset-prop-value-list=#24836.log,#24836.created_packages,#24836.installed_packages,#24836.loaded_package,#24836.last_created_package_map,#24836.last_created_package_encoded --only-origin-object --ignore-prop-list=object_size,last_location,realname,weight,movement_queue,debug,type_history,create_data,instance_id,create_date --allow-dynamic-prop-calls --allow-dynamic-verb-calls --strip-trailing-comments --post-install-verb=handle_post_install --ignore-all-cored-props --dry-run
--reset-prop-value-listto reset props specific to the instance of the object and that are not needed in the package.--only-origin-objectargument to only serialize the MPM itself.--ignore-prop-listand passes in some properties to ignore completely on all objects in the package.--allow-dynamic-prop-callsand dynamic verb calls via--allow-dynamic-verb-callspecifies we should allow serializing to continue when we detect dynamic prop calls--strip-trailing-commentsto strip off any commit messages that may have been added by a modified@programverb, common on some MOOs--dry-runto avoid saving the package map.
The --reset-prop-value-list argument can only reset certain properties:
| Type | Reset Value |
|---|---|
| INT | 0 |
| STR | "" |
| LIST | {} |
| MAP | [] |
| BOOL | false |
| FLOAT | 0.0 |
| OBJ | #-1 |
All other property values (such as WAIF, ANON, ERR) will throw E_ARGS with the value it failed to reset, and package creation will be aborted.
An example of serializing the MPM Helper Verbs that a wizard uses to make/load/install/view packages:
@make-package #22664 --verb-list=@make-package,@view-package,@install-package,@load-package,@manage-packages --only-origin-object --ignore-all-cored-props --dont-serialize-cored-aliases --dont-serialize-ancestry --allow-dynamic-verb-calls --ignore-all-non-cored-props --target-self --strip-trailing-comments --dry-run
In the above example we made use of a variety of command-line options:
--verb-listto specify the ONLY verbs on the object we wanted to serialize--only-origin-objectto only serialize theorigin objectthus MPM does not to dive into the dependency graph--ignore-all-cored-propsso we don't get cored references in our package map, that we wouldn't be using anyway--dont-serialize-cored-aliasesso we don't serialize any props on $sysobj that point to theorigin object--dont-serialize-ancestryso we don't package up the parents of theorigin object--allow-dynamic-verb-callsso that@install-package(which can dynamically call a verb on the installed package when install completes) doesn't raise an error when MPM detects the dynamic verb call--ignore-all-non-cored-propsso that we don't serialize any of the props on #22664 (good thing too, sinceplayerbits typically have a lot of props--target-selfto make this package install on theplayerwho runs@install-package--strip-trailing-commentsto strip off any commit messages that may have been added by a modified@programverb, common on some MOOs--dry-runso we can test out packaging without saving the package to.created_packages.
** Example: Serializing Some Updated String Utils Verbs **
Let's say you have some great $string_utils verbs that you want to make a package of and make available. Here is an example of how you might do that:
@make-package $string_utils --verb-list=names_of_indented,name_of_single --ignore-all-non-cored-props --ignore-all-cored-props --dry-run --dont-serialize-ancestry
In the above example we made use of a variety of command-line options:
--verb-listto define the verbs we want included--ignore-all-non-cored-propsand--ignore-all-cored-propsbecause our new verbs don't rely on any properties so we don't need to serialize any--dont-serialize-ancestrysince we only care about the verbs on $string_utils and we are sure they don't rely on any verbs on the parents--dry-runto generate and display the package without saving ti
Package Object Hierarchy
Different MOOs have different object heirarchies. When a hierarchy is different on the MOO installing the package than it was on the MOO where the package was created, the wizard installing the package will be prompted to rewire the ancestry, where possible.
//TODO OUTLINE AN EXAMPLE HIERARCHY AND WHAT MIGHT HAPPEN HERE
The --dont-serialize-ancestry option is very valuable when you really don't care about the object heierarchy. For example, if you are packaging up an object and its dependencies and you know that nothing in the ancestors matters to your packaged code, using this option will allow for a faster and less interactive installation due to fewer objects needing to be rewired on insetallation.
Package Meta Data
There are a number of meta data fields associated with your package. These fields are serialized with your package, and also make up the package header information that can be made available in a package_list inside a package repository. The meta data is mainly collected by prompting the user during the package creation process, but some is autogenrated as well. The meta data saved for a package is outlined below:
| Name | Description | Required |
|---|---|---|
| Package Name | Name of your package, this should NOT include a version number | yes |
| Package Id | The id of your package. This will carry over each time you create a new version of the package | yes |
| Package Version | A float. Like 1.0 or 1.1, the version of your package | yes |
| Package Hash | An md5 hash of your package map, auto generated when you create a package | yes |
| Package Description | The description of your package. This is shown when browsing a package repository and when viewing/installing a package | yes |
| Package Created At | An autogenerated timestamp of when the package was created | yes |
| Package Created By | The name and number of the programmer who created the package | yes |
| Package URL | The url where the package can be found online. | no |
| Package Changelog | Holds the most recent updates to the package, for when you are updating an existing package | no |
| Package Post Install Note | A note shown to the user when the package is finished installing. Good for any additional setup options, or pointing to help files | no |
| Package Options | The options that the package was created using. | no |
| Package Post Install Verb | (DEPRECATED, included in package options now) A verb that gets run when the package finishes installing | no |
| Package Target Self | (DEPRECATED, included in package options now) Notifies the package manager that the target of this package is the wizard installing the package |
no |
| MPM Version | The version of MPM that was used to create the package | yes |
Self Targeted Packages
It is possible to create packages targeted at the wizard installing the package via MPM. This is a great way to package up cool verbs that you use and think others will find useful, such as a version of @verbs or @parents that displays information in a well formatted way.
Care should be taken when creating self targeted packages. You need to make sure you aren't packaging up an entire player bit. Use the command line arugments to filter out or ignore properties and cored references that your package doesn't need to include and that might interfere with or alter the wizard installing the package.
Testing a Created Package
It's important that you test your newly created package on a dev server before making it available to the public. It would be preferable to test the package with a stock ToastCore database. This will ensure it works as expected without any potential hidden dependencies that cause it to function properly on your MOO, that were some how not serialized as part of the package.
Managing Packages
The @manage-packages wizard verb will drop you into a menu where you can manage your installed and created packages.
Manage Packages
1. Installed Packages
2. Created Packages
3. Dump Package Headers
4. Exit
[Type a number for your selection or `@abort' to abort the command.]
Managing Installed Packages
Choosing the Installed Packages menu item by selection 1, will display a list of objects you have installed packages on (or that have been created as the origin object of a package.
1: string utilities (#20)
2: command utilities (#56)
3: Diff Utils (#26942)
4: Map Utilities (#88222)
[Type a number for your selection or `@abort' to abort the command.]
Selecting an object by entering the corresponding number will display a list of the installed packages from that object.
# PACKAGE NAME @ VERSION INSTALLED BY INSTALLED DATE
1: String Utils Expanded @ 1.0 #22664 Thu Jan 20 15:08:46 2022 PST
[Type a number for your selection or `@abort' to abort the command.]
Entering the number of the package you want to examine will display the details stored about that package:
Name: String Utils Expanded
Package Version: 1.0
Package Id: None
Hash: C2F77FDA0D9D8712544E2FB1DBAA8C43
Installed At: Thu Jan 20 15:08:46 2022 PST
Installed By: #22664
Description: This package adds two verbs to $string_utils: names_of_indented and name_of_single which are used for pretty printing objects with indentation.
Changelog: None
Post Install Note: None
(R)emove package (M)ain menu
[Type a selection or `@abort' to abort the command.]
You can then choose to enter R to remove the package, or M to return to the main menu.
Warning: The
Roption deletes the package from your.installed_packages. It does NOT remove or otherwise rollback changes to your MOO made when installing the package.
Managing Created Packages
Selecting the Created Packages option by entering 2 from the @manage-packages menu works in a similar way as Installed Packages. You are dropped into a list of objects you have created packages from. You then select the object you want to view the packages for. You are them presented with a list of packages you've created with this origin object.
# PACKAGE NAME @ VERSION STATUS CREATED BY CREATE DATE
1: String Utils Enhanced @ 1.0 DEPRECATED Slither (#2) Thu Jan 20 16:58:54 2022 PST
2: String Utils Enhanced @ 1.1 LIVE Fengshui (#22664) Sun Jan 23 11:24:18 2022 PST
[Type a number for your selection or `@abort' to abort the command.]
You will notice this list looks similar to the Installed Packages list, with the exception of the STATUS column. This column shows if a package is considered live or deprecated.
Packages are live by default. Any package marked as live will be included when you dump package headers for your package_list. See the Making Packages Available section for more information on the package_list.
Packages that are deprecated will not be included when you dump package headers. It is good practice to mark packages as deprecated when you release a new version that is intended to fully replace an old version, and you no longer wish to make the older version available. Deprecated packages can be undeprecated in the same way they are deprecated.
Note: It is still a good practice to leave your old packages online, as folx may wish to run an older version of your package. Marking is as deprecated will serve to not have your package repository advertise the package, which means new people will not find it.
Making Packages Available
The MOO Package Manager makes it easy to copy packages from one MOO to another, or to make your packages available online. There is one way to copy your package directly to another MOO and two ways of making your package available online that will be discussed below.
First, let's discuss the relevant pieces of data that are created when you generate package.
Package Map
This is a map containing the meta data about your package as well as the package data (your actual package objects/verbs/props/etc). When the package is created, the package map is stored as a map in $mpm.last_created_package_map. This is useful for you if you want to explore the created package map or copy it to another MOO.
Copying the Package Map
You can also choose to copy this map over to another MOO with the MOO Package Manager, but the data must be converted to json when you are setting the $mpm.loaded_package property with the data:
;$mpm.loaded_package = generate_json(copiedPackageMap, "embedded-types")
It will now be available to @view-package and @install-package. This is the basic way of moving a package from one MOO to another.
Encoded Package Map
The $mpm.last_created_package_encoded property will contain your encoded package. This is the package map after bering converted to json, encoded in binary, and then base64 encoded.
Making a Single Package Available
If you would like to make a single package available online, you can copy the contents of $mpm.last_created_package_encoded into a plaintext file and upload it to a website, commit it to a Git Repository, or place it wherever you want online. You can then provide the URL to the file to anyone who would like to install it and they can use the @load-package command and select the Load package directly from URL option, specifying the URL and loading the package.
Note: If you are using Github, you need the URL to the 'raw' version of your file. You can find this by opening the file in Github, then clicking the 'raw' button. The url will look something like:
https://raw.githubusercontent.com/sevenecks/moo-package-manager/master/packages/diff_utils_1_0.
Making a Package Repository
Alternatively, you can make a package repository. A package repository contains a package_list with package headers. The package headers contain the meta data about packages (name, version, links to where the package can be downloaded, etc). A package repository can have as many packages in it as you like. Those packages must have package headers listed for each of the packages.
Note: For an example of how a package repository might look, look no further than this git repository, which also acts as the
Slither's MOO Packagesrepository. Thepackage_listcontaining thepackage headersalong with all the package code files is located in the packages directory.
Generating Package Headers
package headers are generated from the package meta data stored in your instance of the $mpm. When you create a package, the $mpm.created_packages map is updated with the newly created package. This stores every package you have created, including the multiple different versions of a package you may have created (for instance if you are updating your packages as you fix bugs or add functionality).
To generate package headers for your package_list you can @manage-packages and choose 'Dump Package Headers' or execute:
;$mpm:dump_package_headers()
This will display your package headers. Now just simply copy and paste (ensuring one package per line) into a package_list file, and place the package list as well as your code, online (we recommend in a GitHub Repo).
You have created a package repository. This package repository will not be available to any MOO Package Manager by default and will need to be added by anyone who wishes to download packages from your repository.
Adding Package Repositories
By default the only package repository the MOO Package Manager has point's to this Github Repo, and is registered as Slither's MOO Packages..
If you would like to add another package repository to your MOO Package Manager, you can register that repository by executing:
;$mpm:register_package_repository(name, url);
Warning: Please take care when adding package repositories. You should review any code you are adding to your MOO before using
@install-package.
Upgrading MPM
If a new version of MPM is available, you'll be able to use @load-package and find it in Slither's MOO Packages. If you are unsure of what version you are currently running check $mpm.package_manager_version. Typically there will also be a new version of MOO Package Manager Wizard Verbs available as well. You should update MPM first, and then update the wizard verbs package.
Warning: There is a bug where MPM will detect invalid objects on ToastCore. If you are prompted to use an invalid object during installation JUST SAY NO.
Caveats
- By default MPM will not serialize verbs/props on ancestors who have a parent of $nothing (IE: #1), as this can make a package huge. This can be overridden with command arguments.
Unsupported
- Does not support unwinding dynamic verb or prop references (IE: $string_utils:("verbname") or $string_utils.(propvar))
- Does not support serializing verbs/props that have binary data in them (IE: ~OE)
Known Issues
- If you use GitHub to host your packages, be aware that the
raw.githubusercontent.comversion of your file may be cached for ~5 minutes, so if you update it, you may need to wait a bit after pushing changes. - If you are using ToastCore, it may detect an invalid object and prompt you to use it during package creation. Just say NO!
Contributing
Opening Issues
If you have an issue with using the package manager, feel free to open an issue.
Contributing a Package
For now reach out to Slither on the ToastStunt Discord.
Contributing to the Package Manager Source
- If you would like to contribute the best way to do so is by joining the ToastStunt Discord.
- Pull requests are also welcome
Contributing a Package Repository
For now reach out to Slither on the ToastStunt Discord.