aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Chabowski <kevin@kch42.de>2012-03-03 21:09:14 +0100
committerKevin Chabowski <kevin@kch42.de>2012-03-03 21:09:14 +0100
commit9f4b3867250cac6fd75cc3e410fbff58f817cf8f (patch)
tree7ee34b729c625aa0ee71e35fe799d9b3da6c4f85
downloadr7r-plugin-packer-9f4b3867250cac6fd75cc3e410fbff58f817cf8f.tar.gz
r7r-plugin-packer-9f4b3867250cac6fd75cc3e410fbff58f817cf8f.tar.bz2
r7r-plugin-packer-9f4b3867250cac6fd75cc3e410fbff58f817cf8f.zip
Initial commit.
-rw-r--r--CONTRIBUTORS6
-rw-r--r--COPYING18
-rw-r--r--README.md4
-rw-r--r--pluginpackage.php288
-rwxr-xr-xr7r-plugin-packer.php101
5 files changed, 417 insertions, 0 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
index 0000000..26812dd
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,6 @@
+People who have worked on r7r-plugin-packer
+===========================================
+
+If you modified something, feel free to append your name to this list.
+
+* Kevin Chabowski <kevin@kch42.de>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..ed13745
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,18 @@
+r7r-plugin-packer: Copyright (c) 2012 The Ratatöskr Team
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e3607a7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+r7r-plugin-packer.php
+=====================
+
+A Command line tool for packing a plugin for Ratatöskr. \ No newline at end of file
diff --git a/pluginpackage.php b/pluginpackage.php
new file mode 100644
index 0000000..cf667cc
--- /dev/null
+++ b/pluginpackage.php
@@ -0,0 +1,288 @@
+<?php
+
+/*
+ * File: ratatoeskr/sys/pluginpackage.php
+ * Handle plugin packages easily.
+ *
+ * License:
+ * This file is part of Ratatöskr.
+ * Unlike the other parts of Ratatöskr, *this* file ist *not* licensed under the
+ * MIT / X11 License, but under the WTFPL, to make it even easier to use this
+ * file in other projects.
+ * See "ratatoeskr/licenses/wtfpl" for more information.
+ */
+
+/*
+ * Function: dir2array
+ * Pack a directory into an array.
+ *
+ * Parameters:
+ * $dir - The directory to pack.
+ *
+ * Returns:
+ * Associative array. Keys are filenames, values are either the file's content as a string or another array, if it's a directory.
+ */
+function dir2array($dir)
+{
+ $rv = array();
+ foreach(scandir($dir) as $fn)
+ {
+ if(($fn == ".") or ($fn == ".."))
+ continue;
+ $fn_new = $dir . "/" . $fn;
+ if(is_dir($fn_new))
+ $rv[$fn] = dir2array($fn_new);
+ elseif(is_file($fn_new))
+ $rv[$fn] = file_get_contents($fn_new);
+ }
+ return $rv;
+}
+
+/*
+ * Function: array2dir
+ * Unpack an array into a directory.
+ *
+ * Parameters:
+ * $a - Array to unpack.
+ * $dir - Directory to unpack to.
+ */
+function array2dir($a, $dir)
+{
+ if(!is_dir($dir))
+ mkdir($dir);
+
+ foreach($a as $k => $v)
+ {
+ $k = "$dir/$k";
+ if(is_array($v))
+ array2dir($v, $k);
+ else
+ file_put_contents($k, $v);
+ }
+}
+
+function validate_url ($u) { return preg_match("/^http[s]{0,1}:\\/\\/.*$/", $u) != 0; }
+function validate_arraydir($a)
+{
+ if(!is_array($a))
+ return False;
+ foreach($a as $k=>$v)
+ {
+ if(!is_string($k))
+ return False;
+ if(is_array($v) and (!validate_arraydir($v)))
+ return False;
+ elseif(!is_string($v))
+ return False;
+ }
+ return True;
+}
+
+/*
+ * Class: InvalidPackage
+ * An Exception that <PluginPackage>'s function can throw, if the package is invalid.
+ */
+class InvalidPackage extends Exception {}
+
+/*
+ * Class: PluginPackage
+ * A plugin package representation.
+ */
+class PluginPackage
+{
+ public static $magic = "R7RPLGPACKV001";
+
+ /*
+ * Variables: Mandatory values
+ *
+ * $code - The plugin code
+ * $classname - The name of the plugins main class
+ * $name - Name of the plugin (must be at least one character, allowed chars: a-z A-Z 0-9 - _)
+ * $author - The author of the plugin (preferably in the format: Name<mail@address>)
+ * $versiontext - A text to describe the current version, something like "1.1 Beta"
+ * $versioncount - A number for this version, should be increased with every release
+ * $api - The used API version
+ * $short_description - A short description.
+ */
+ public $code = NULL;
+ public $classname = NULL;
+ public $name = NULL;
+ public $author = NULL;
+ public $versiontext = NULL;
+ public $versioncount = NULL;
+ public $api = NULL;
+ public $short_description = NULL;
+
+ /*
+ * Variables: Optional values
+ *
+ * $updatepath - A URL that points to a update information resource (serialize'd array("current-version" => VERSIONCOUNT, "dl-path" => DOWNLOAD PATH); will get overwritten/set by the default repository software.
+ * $web - A URL to the webpage for the plugin. If left empty, the default repository software will set this to the description page of your plugin.
+ * $license - The license text of your plugin.
+ * $help - A help / manual (formatted in HTML) for your plugin.
+ * $custompub - <dir2array> 'd directory that contains custom public(i.e. can later be accessed from the web) data.
+ * $custompriv - <dir2array> 'd directory that contains custom private data.
+ * $tpls - <dir2array> 'd directory containing custom STE templates.
+ */
+ public $updatepath = NULL;
+ public $web = NULL;
+ public $license = NULL;
+ public $help = NULL;
+ public $custompub = NULL;
+ public $custompriv = NULL;
+ public $tpls = NULL;
+
+ /*
+ * Function: validate
+ * Validate, if the variables are set correctly.
+ * Will throw an <InvalidPackage> exception if invalid.
+ */
+ public function validate()
+ {
+ if(!is_string($this->code))
+ throw new InvalidPackage("Invalid code value.");
+ if(!is_string($this->classname))
+ throw new InvalidPackage("Invalid classname value.");
+ if(preg_match("/^[a-zA-Z0-9_\\-]+$/", $this->name) == 0)
+ throw new InvalidPackage("Invalid name value (must be at least 1 character, accepted chars: a-z A-Z 0-9 - _).");
+ if(!is_string($this->author))
+ throw new InvalidPackage("Invalid author value.");
+ if(!is_string($this->versiontext))
+ throw new InvalidPackage("Invalid versiontext value.");
+ if(!is_numeric($this->versioncount))
+ throw new InvalidPackage("Invalid versioncount value. Must be a number.");
+ if(!is_numeric($this->api))
+ throw new InvalidPackage("Invalid api value. Must be a number.");
+ if(!is_string($this->short_description))
+ throw new InvalidPackage("Invalid short_description value.");
+
+ if((!empty($this->updatepath)) and (!validate_url($this->updatepath)))
+ throw new InvalidPackage("Invalid updatepath value. Must be an URL. " .$this->updatepath);
+ if((!empty($this->web)) and (!validate_url($this->web)))
+ throw new InvalidPackage("Invalid web value. Must be an URL.");
+ if(($this->license !== NULL) and (!is_string($this->license)))
+ throw new InvalidPackage("Invalid license value.");
+ if(($this->help !== NULL) and (!is_string($this->help)))
+ throw new InvalidPackage("Invalid help value.");
+ if(($this->custompub !== NULL) and (!validate_arraydir($this->custompub)))
+ throw new InvalidPackage("Invalid custompub value.");
+ if(($this->custompriv !== NULL) and (!validate_arraydir($this->custompriv)))
+ throw new InvalidPackage("Invalid custompriv value.");
+ if(($this->tpls !== NULL) and (!validate_arraydir($this->tpls)))
+ throw new InvalidPackage("Invalid tpls value.");
+ return True;
+ }
+
+ /*
+ * Function: load
+ * Load a plugin package from binary data.
+ *
+ * Parameters:
+ * $plugin_raw - The raw package to load.
+ *
+ * Returns:
+ * The <PluginPackage> object.
+ *
+ * Throws:
+ * <InvalidPackage> if package is invalid.
+ */
+ public static function load($plugin_raw)
+ {
+ /* Read and compare magic number */
+ $magic = substr($plugin_raw, 0, strlen(self::$magic));
+ if($magic != self::$magic)
+ throw new InvalidPackage("Wrong magic number");
+
+ /* Read sha1sum and uncompress serialized plugin, then compare the hash */
+ $sha1sum = substr($plugin_raw, strlen(self::$magic), 20);
+ $pluginser = gzuncompress(substr($plugin_raw, strlen(self::$magic) + 20));
+ if(sha1($pluginser, True) != $sha1sum)
+ throw new InvalidPackage("Wrong SHA1 hash");
+
+ $plugin = @unserialize($pluginser);
+ if(!($plugin instanceof self))
+ throw new InvalidPackage("Not the correct class or not unserializeable.");
+
+ $plugin->validate();
+
+ return $plugin;
+ }
+
+ /*
+ * Function: save
+ * Save the plugin.
+ *
+ * Returns:
+ * A binary plugin package.
+ *
+ * Throws:
+ * <InvalidPackage> if package is invalid.
+ */
+ public function save()
+ {
+ $this->validate();
+ $ser = serialize($this);
+ return self::$magic . sha1($ser, True) . gzcompress($ser, 9);
+ }
+
+ /*
+ * Function: extract_meta
+ * Get just the metadata of this package.
+ *
+ * Returns:
+ * A <PluginPackageMeta> object.
+ */
+ public function extract_meta()
+ {
+ $meta = new PluginPackageMeta();
+
+ $meta->name = $this>name;
+ $meta->author = $this>author;
+ $meta->versiontext = $this>versiontext;
+ $meta->versioncount = $this>versioncount;
+ $meta->api = $this>api;
+ $meta->short_description = $this>short_description;
+ $meta->updatepath = $this>updatepath;
+ $meta->web = $this>web;
+ $meta->license = $this>license;
+
+ return $meta;
+ }
+}
+
+/*
+ * Class: PluginPackageMeta
+ * Only the metadata of a <PluginPackage>.
+ */
+class PluginPackageMeta
+{
+ /*
+ * Variables: Mandatory values
+ *
+ * $name - Name of the plugin (must be at least one character, allowed chars: a-z A-Z 0-9 - _)
+ * $author - The author of the plugin (preferably in the format: Name<mail@address>)
+ * $versiontext - A text to describe the current version, something like "1.1 Beta"
+ * $versioncount - A number for this version, should be increased with every release
+ * $api - The used API version
+ * $short_description - A short description.
+ */
+ public $name = NULL;
+ public $author = NULL;
+ public $versiontext = NULL;
+ public $versioncount = NULL;
+ public $api = NULL;
+ public $short_description = NULL;
+
+ /*
+ * Variables: Optional values
+ *
+ * $updatepath - A URL that points to a update information resource (serialize'd array("current-version" => VERSIONCOUNT, "dl-path" => DOWNLOAD PATH); will get overwritten/set by the default repository software.
+ * $web - A URL to the webpage for the plugin. If left empty, the default repository software will set this to the description page of your plugin.
+ * $license - The license text of your plugin.
+ */
+ public $updatepath = NULL;
+ public $web = NULL;
+ public $license = NULL;
+}
+
+?>
diff --git a/r7r-plugin-packer.php b/r7r-plugin-packer.php
new file mode 100755
index 0000000..6baef7a
--- /dev/null
+++ b/r7r-plugin-packer.php
@@ -0,0 +1,101 @@
+#!/usr/bin/env php
+<?php
+
+/*
+ * File: r7r-plugin-packer.php
+ * Packaging a Ratatöskr plugin.
+ */
+
+require_once(dirname(__FILE__) . "/pluginpackage.php");
+
+/* Parse options */
+$options = getopt("", array(
+ "codefile:",
+ "classname:",
+ "pluginname:",
+ "author:",
+ "versiontext:",
+ "versioncount:",
+ "updatepath:",
+ "web:",
+ "api:",
+ "licensefile:",
+ "helpfile:",
+ "shortdesc:",
+ "custompub:",
+ "custompriv:",
+ "tpldir:",
+ "output:"
+));
+
+$usage = <<<USAGE
+Usage:
+${argv[0]} options...
+
+Mandatory options:
+ --output=FILE Where should the output be saved?
+ --codefile=FILE The PHP file with the plugin code.
+ --classname=CLASS The name of the RatatoeskrPlugin implementation.
+ --pluginname=NAME The name of the plugin (it is recommended to use some kind of developer prefix to make the name more unique).
+ --author=AUTHOR Your name (preferably in the form: My Name<my-mail-address@example.com>).
+ --versiontext=VER A short text, that describes this version (something like: 1.0 beta).
+ --versioncount=C A number that increases with every release.
+ --api=APIVER The version number of the plugin API.
+ --shortdesc=DESC A short description of your plugin. You can use #hashtags.
+
+Optional options:
+ --updatepath=URL A URL where Ratatöskr can check, if there is a new version (URL should point to a serialize()'d array("current-version" => VERSIONCOUNT, "dl-path" => DOWNLOAD PATH); Will get overwritten by the default repository software).
+ --web=HOMEPAGE Homepage of the Plugin.
+ --licensefile=FILE Should a license be included?
+ --helpfile=FILE A HTML file that acts as a help/manual for your plugin.
+ --custompub=DIR Directory that contains custom public(i.e. can later be accessed from the web) data.
+ --custompriv=DIR Directory that contains custom private data.
+ --tpldir=DIR Directory that contains templates used by this plugin.
+USAGE
+;
+
+if(!(isset($options["output"]) and isset($options["codefile"]) and isset($options["classname"]) and isset($options["pluginname"]) and isset($options["author"]) and isset($options["versiontext"]) and isset($options["versioncount"]) and isset($options["api"]) and isset($options["shortdesc"])))
+{
+ fprintf(STDERR, "Missing options\n\n" . $usage);
+ exit(1);
+}
+
+$code = file_get_contents($options["codefile"]);
+if($code === FALSE)
+{
+ fprintf(STDERR, "Can not open '${options['codefile']}'.\n");
+ exit(1);
+}
+
+/* Remove trailing <?php ?> delimiters */
+$code = preg_replace("/^\\<\\?php(.*)\\?\\>\\s*?$/s", "\\1", $code);
+
+$plugin = new PluginPackage();
+
+$plugin->code = $code;
+$plugin->classname = $options["classname"];
+$plugin->name = $options["pluginname"];
+$plugin->author = $options["author"];
+$plugin->versiontext = $options["versiontext"];
+$plugin->versioncount = $options["versioncount"];
+$plugin->api = $options["api"];
+$plugin->short_description = $options["shortdesc"];
+
+if(isset($options["updatepath"]))
+ $plugin->updatepath = $options["updatepath"];
+if(isset($options["web"]))
+ $plugin->web = $options["web"];
+if(isset($options["licensefile"]))
+ $plugin->license = @file_get_contents($options["licensefile"]);
+if(isset($options["helpfile"]))
+ $plugin->help = @file_get_contents($options["helpfile"]);
+if(isset($options["custompub"]))
+ $plugin->custompub = dir2array($options["custompub"]);
+if(isset($options["custompriv"]))
+ $plugin->custompriv = dir2array($options["custompriv"]);
+if(isset($options["tpldir"]))
+ $plugin->tpls = dir2array($options["tpldir"]);
+
+file_put_contents($options["output"], $plugin->save());
+
+?>