The script file is what SDM interprets and run to install or uninstall a package.
The script is, basically, a Groovy file that extends one of BinaryPackage or SourcePackage - or simply, implements Package - and implements one or more of the following methods:
void fetch(final String url); void extract(final String artifactName); void build(); void verify(); void prepare(); void install(); void finish(); void cleanup(); void uninstall(final String path);
These are the installation phases, in the order they are executed:
The following variables are exposed to the scripts:
When writing the script, three other variables must be defined as well:
The engine exposes relevant runtime information that can be used for the scripts. They are accessible via the the rdc instance variable.
The code snippet below demonstrates how to access the runtime data container as well as its keys.
String path = rdc.getContainer().get("script.dir"); println "The script directory is ${path}" String resourcesPath = rdc.getContainer().get("script.resources.dir") println "The script resources directory is ${resourcesPath}" String ne = rdc.getContainer().get("doesnotexist") println "No-existent keys return null ${ne}"
The result should be similar to this:
The script directory is /Users/otavio/.sdm/repositories/default/packages/org.apache/apache-maven/3.0.5/pkg The script resources directory is /Users/otavio/.sdm/repositories/default/packages/org.apache/apache-maven/3.0.5/pkg/resources No-existent keys return null null
Finally, you may also access properties set on sdm.properties file provided they start with runtime. For example:
String myVariable = rdc.getContainer().get("runtime.test.variable"); println "The value of my variable is ${myVariable}"
It's safe to assume that you will need to handle package versions with SDM. Hence, it has a feature called version slots. Version slots allow you to define how it will behave regarding upgrades. The slots can be defined in the repository structure by creating a file named package.properties. This file should be within the group id/package name directory. And it should declare the package.default.slot property. Here's an example:
package.default.slot=n.*
The following slots are accepted:
They represent:
Default Slot: declares a single slot for all the versions of a package. Hence, 1.2.0, 1.3.0, 2.0.0, etc all fall within the same slot. Due to that, versions such as 1.2.0 may be upgraded to 2.x.x if packages are available.
Major Slot: this slot considers that versions in different major releases are different. For instance, in this slot definition 1.2.0 is different than 2.3.0. On the other hand, 1.2.0 and 1.3.0 are on the same slot.
Minor Slot: this slot considers that versions in different major and minor releases are different. For instance, in this slot definition 1.2.0 is different than 1.3.0 or 2.3.0. On the other hand, 1.2.0 and 1.2.1 are on the same slot.
You can check the API docs here.
By default, SDM will try to unpack the file for you. It considers that the package will unpack itself to $workDir/$name-$version (ie.: /tmp/work/groovy-2.1.1). If that's not the case for your package, then you need to implement your own unpack method. For instance, a package that extracts the files in the same directory would end up with their files in $workDir instead of $workDir/$name-$version. To resolve this, you would have to create the dir, and then call unpack into that directory. Here's an example:
void extract(String artifactName) { def tempWorkDir = "${workDir}/${name}-${version}" // Creates the ${workDir}/${name}-${version} mkdir("${tempWorkDir}") // Unpacks the artifact straight into the ${workDir}/${name}-${version} unpack(artifactName, ${tempWorkDir}") }
Install copies the files from $workDir/$name-$version into the $installDir. Ideally, it would also create symlinks if required and any other installation step.
The uninstall should cleanup the steps done during install. For instance, if symlinks were created, then they should be removed.
This is what a script looks like:
import net.orpiske.sdm.packages.BinaryPackage; import static net.orpiske.sdm.lib.OsUtils.*; import static net.orpiske.sdm.lib.io.IOUtil.*; import static net.orpiske.sdm.lib.Core.*; import static net.orpiske.sdm.lib.Executable.*; class ApacheMaven extends BinaryPackage { def version = "3.0.5" def name = "apache-maven" def url = "http://apache.mirror.pop-sc.rnp.br/apache/maven/maven-3/${version}/binaries/apache-maven-${version}-bin.tar.gz" void install() { // Protects the file from being overwritten during reinstall shield("${installDir}/${name}-${version}/conf/settings.xml") // Installs ${workDir}/${name}-${version} into ${workDir} performInstall("${name}", "${version}") // If is a Unix-like system ... if (isNix()) { // ... then create symlinks println "Creating symlinks" exec("ln", "-sf ${installDir}/${name}-${version} ${installDir}/${name}") } } void uninstall(String path) { if (isNix()) { println "Removing symlinks" exec("unlink", "${installDir}/${name}") } } }
Currently, there are four package super-classes:
You can declare dependencies of a package by declaring the dependencies variable. For instance, if you have a package that depends on Apache Maven and Apache Ant, an acceptable dependency declaration would be:
def dependencies = [ "org.apache/apache-maven":"(3.0.0, 3.0.99)", "org.apache/apache-ant":"(1.8.4,1.8.99)" ];
The dependencies variables is a Groovy hash map, in the form of a String/String container. The key is the package group id + name and the value is the version range. The range is in the form (minimum acceptable version, maximum acceptable version).
Meta packages are packages that do not contain an artifact, instead they declare a set of packages as a dependency. This is ver useful to group components in a single name. For instance, if you wanted to create a meta package to install both Apache Maven and Apache Ant, you could created it like this:
import net.orpiske.sdm.packages.MetaPackage; import static net.orpiske.sdm.lib.Core.*; class MyMetaPackage extends MetaPackage { def version = "1.0.0" def name = "devevn" def url = "" def dependencies = ["org.apache/apache-maven":"(3.0.0, 3.0.99)", "org.apache/apache-ant":"(1.8.4,1.8.99)"]; }