CodeIgniter package management system, Sparks

http://getsparks.org
This commit is contained in:
Ismo Vuorinen
2013-07-11 07:44:42 +03:00
parent c10c9e3131
commit fabd8585ab
19 changed files with 1309 additions and 0 deletions

View File

@@ -0,0 +1,265 @@
<?php if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* Sparks
*
* An open source application development framework for PHP 5.1.6 or newer
*
* @package CodeIgniter
* @author CodeIgniter Reactor Dev Team
* @author Kenny Katzgrau <katzgrau@gmail.com>
* @since CodeIgniter Version 1.0
* @filesource
*/
/**
* Loader Class
*
* Loads views and files
*
* @package CodeIgniter
* @subpackage Libraries
* @author CodeIgniter Reactor Dev Team
* @author Kenny Katzgrau <katzgrau@gmail.com>
* @category Loader
* @link http://codeigniter.com/user_guide/libraries/loader.html
*/
class MY_Loader extends CI_Loader
{
/**
* Keep track of which sparks are loaded. This will come in handy for being
* speedy about loading files later.
*
* @var array
*/
var $_ci_loaded_sparks = array();
/**
* Is this version less than CI 2.1.0? If so, accomodate
* @bubbafoley's world-destroying change at: http://bit.ly/sIqR7H
* @var bool
*/
var $_is_lt_210 = false;
/**
* Constructor. Define SPARKPATH if it doesn't exist, initialize parent
*/
function __construct()
{
if(!defined('SPARKPATH'))
{
define('SPARKPATH', 'sparks/');
}
$this->_is_lt_210 = (is_callable(array('CI_Loader', 'ci_autoloader'))
|| is_callable(array('CI_Loader', '_ci_autoloader')));
parent::__construct();
}
/**
* To accomodate CI 2.1.0, we override the initialize() method instead of
* the ci_autoloader() method. Once sparks is integrated into CI, we
* can avoid the awkward version-specific logic.
* @return Loader
*/
function initialize()
{
parent::initialize();
if(!$this->_is_lt_210)
{
$this->ci_autoloader();
}
return $this;
}
/**
* Load a spark by it's path within the sparks directory defined by
* SPARKPATH, such as 'markdown/1.0'
* @param string $spark The spark path withint he sparks directory
* @param <type> $autoload An optional array of items to autoload
* in the format of:
* array (
* 'helper' => array('somehelper')
* )
* @return <type>
*/
function spark($spark, $autoload = array())
{
if(is_array($spark))
{
foreach($spark as $s)
{
$this->spark($s);
}
}
$spark = ltrim($spark, '/');
$spark = rtrim($spark, '/');
$spark_path = SPARKPATH . $spark . '/';
$parts = explode('/', $spark);
$spark_slug = strtolower($parts[0]);
# If we've already loaded this spark, bail
if(array_key_exists($spark_slug, $this->_ci_loaded_sparks))
{
return true;
}
# Check that it exists. CI Doesn't check package existence by itself
if(!file_exists($spark_path))
{
show_error("Cannot find spark path at $spark_path");
}
if(count($parts) == 2)
{
$this->_ci_loaded_sparks[$spark_slug] = $spark;
}
$this->add_package_path($spark_path);
foreach($autoload as $type => $read)
{
if($type == 'library')
$this->library($read);
elseif($type == 'model')
$this->model($read);
elseif($type == 'config')
$this->config($read);
elseif($type == 'helper')
$this->helper($read);
elseif($type == 'view')
$this->view($read);
else
show_error ("Could not autoload object of type '$type' ($read) for spark $spark");
}
// Looks for a spark's specific autoloader
$this->ci_autoloader($spark_path);
return true;
}
/**
* Pre-CI 2.0.3 method for backward compatility.
*
* @param null $basepath
* @return void
*/
function _ci_autoloader($basepath = NULL)
{
$this->ci_autoloader($basepath);
}
/**
* Specific Autoloader (99% ripped from the parent)
*
* The config/autoload.php file contains an array that permits sub-systems,
* libraries, and helpers to be loaded automatically.
*
* @param array|null $basepath
* @return void
*/
function ci_autoloader($basepath = NULL)
{
if($basepath !== NULL)
{
$autoload_path = $basepath.'config/autoload'.EXT;
}
else
{
$autoload_path = APPPATH.'config/autoload'.EXT;
}
if(! file_exists($autoload_path))
{
return FALSE;
}
include($autoload_path);
if ( ! isset($autoload))
{
return FALSE;
}
if($this->_is_lt_210 || $basepath !== NULL)
{
// Autoload packages
if (isset($autoload['packages']))
{
foreach ($autoload['packages'] as $package_path)
{
$this->add_package_path($package_path);
}
}
}
// Autoload sparks
if (isset($autoload['sparks']))
{
foreach ($autoload['sparks'] as $spark)
{
$this->spark($spark);
}
}
if($this->_is_lt_210 || $basepath !== NULL)
{
if (isset($autoload['config']))
{
// Load any custom config file
if (count($autoload['config']) > 0)
{
$CI =& get_instance();
foreach ($autoload['config'] as $key => $val)
{
$CI->config->load($val);
}
}
}
// Autoload helpers and languages
foreach (array('helper', 'language') as $type)
{
if (isset($autoload[$type]) AND count($autoload[$type]) > 0)
{
$this->$type($autoload[$type]);
}
}
// A little tweak to remain backward compatible
// The $autoload['core'] item was deprecated
if ( ! isset($autoload['libraries']) AND isset($autoload['core']))
{
$autoload['libraries'] = $autoload['core'];
}
// Load libraries
if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)
{
// Load the database driver.
if (in_array('database', $autoload['libraries']))
{
$this->database();
$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
}
// Load all other libraries
foreach ($autoload['libraries'] as $item)
{
$this->library($item);
}
}
// Autoload models
if (isset($autoload['model']))
{
$this->model($autoload['model']);
}
}
}
}

47
tools/README.md Normal file
View File

@@ -0,0 +1,47 @@
# CodeIgniter Spark
Spark is a way to pull down packages automatically
$ tools/spark install -v1.2 gravatar_helper
And then you can load the package like so:
$this->load->spark('gravatar_helper/1.2');
echo Gravatar_helper::from_email('john.crepezzi@gmail.com');
---
## Adding a package
$ tools/spark install -v1.2 gravatar
$ tools/spark install gravatar # most recent version
## Removing a package
$ tools/spark remove -v1.2 gravatar # remove a specific version
$ tools/spark remove gravatar -f # remove all
## Reinstalling a package
$ tools/spark reinstall -v1.2 gravatar # reinstall a specific version
$ tools/spark reinstall gravatar -f # remove all versions and install latest
## Search for a package
$ tools/spark search gravatar
## List installed packages
$ tools/spark list
## Get Help
$ tools/spark help
---
## Install
Go to your favorite CI project, and run (must have CURL installed):
$ php -r "$(curl -fsSL http://www.getsparks.org/static/install.php)"

4
tools/lib/spark/sources Normal file
View File

@@ -0,0 +1,4 @@
# the main repository
getsparks.org
# list other repositories here

View File

@@ -0,0 +1,269 @@
<?php
require_once dirname(__FILE__) . '/spark_utils.php';
require_once dirname(__FILE__) . '/spark_exception.php';
require_once dirname(__FILE__) . '/spark_source.php';
define('SPARK_VERSION', '0.0.9');
! defined('SPARK_PATH') AND define('SPARK_PATH', './sparks');
class Spark_CLI {
private static $commands = array(
'help' => 'help',
'install' => 'install',
'list' => 'lister',
'reinstall' => 'reinstall',
'remove' => 'remove',
'search' => 'search',
'sources' => 'sources',
'upgrade-system' => 'upgrade_system',
'version' => 'version',
'' => 'index' // default action
);
function __construct($spark_sources)
{
$this->spark_sources = $spark_sources;
}
function execute($command, $args = array())
{
if (!array_key_exists($command, self::$commands))
{
$this->failtown("Unknown action: $command");
return;
}
try
{
$method = self::$commands[$command];
$this->$method($args);
}
catch (Exception $ex)
{
return $this->failtown($ex->getMessage());
}
}
private function index($args)
{
Spark_utils::line('Spark (v' . SPARK_VERSION . ')');
Spark_utils::line('For help: `php tools/spark help`');
}
private function upgrade_system() {
$tool_dir = dirname(__FILE__) . '/../../';
$tool_dir = realpath($tool_dir);
// Get version data
$source = $this->spark_sources[0];
if (!$source) throw new Spark_exception('No sources listed - unsure how to upgrade');
if (!$source->outdated()) // We have an acceptable version
{
Spark_utils::warning('Spark manager is already up to date');
return;
}
// Build a spark and download it
$data = null;
$data->name = 'Spark Manager';
$data->archive_url = $source->version_data->spark_manager_download_url;
$zip_spark = new Zip_spark($data);
$zip_spark->retrieve();
// Download the new version
// Remove the lib directory and the spark
unlink($tool_dir . '/spark');
Spark_utils::remove_full_directory($tool_dir . '/lib');
// Link up the new version
Spark_utils::full_move($zip_spark->temp_path . '/lib', $tool_dir . '/lib');
@rename($zip_spark->temp_path . '/spark', $tool_dir . '/spark');
@`chmod u+x {$tool_dir}/spark`;
// Tell the user the story of what just happened
Spark_utils::notice('Spark manager has been upgraded to ' . $source->version . '!');
}
// list the installed sparks
private function lister()
{
if (!is_dir(SPARK_PATH)) return; // no directory yet
foreach(scandir(SPARK_PATH) as $item)
{
if (!is_dir(SPARK_PATH . "/$item") || $item[0] == '.') continue;
foreach (scandir(SPARK_PATH . "/$item") as $ver)
{
if (!is_dir(SPARK_PATH . "/$item/$ver") || $ver[0] == '.') continue;
Spark_utils::line("$item ($ver)");
}
}
}
private function version()
{
Spark_utils::line(SPARK_VERSION);
}
private function help()
{
Spark_utils::line('install # Install a spark');
Spark_utils::line('reinstall # Reinstall a spark');
Spark_utils::line('remove # Remove a spark');
Spark_utils::line('list # List installed sparks');
Spark_utils::line('search # Search for a spark');
Spark_utils::line('sources # Display the spark source URL(s)');
Spark_utils::line('upgrade-system # Update Sparks Manager to latest version (does not upgrade any of your installed sparks)');
Spark_utils::line('version # Display the installed spark version');
Spark_utils::line('help # Print This message');
}
private function search($args)
{
$term = implode($args, ' ');
foreach($this->spark_sources as $source)
{
$results = $source->search($term);
foreach ($results as $result)
{
$result_line = "\033[33m$result->name\033[0m - $result->summary";
// only show the source information if there are multiple sources
if (count($this->spark_sources) > 1) $result_line .= " (source: $source->url)";
Spark_utils::line($result_line);
}
}
}
private function sources()
{
foreach($this->spark_sources as $source)
{
Spark_utils::line($source->get_url());
}
}
private function failtown($error_message)
{
Spark_utils::error('Uh-oh!');
Spark_utils::error($error_message);
}
private function remove($args)
{
list($flats, $flags) = $this->prep_args($args);
if (count($flats) != 1)
{
return $this->failtown('Which spark do you want to remove?');
}
$spark_name = $flats[0];
$version = array_key_exists('v', $flags) ? $flags['v'] : null;
// figure out what to remove and make sure its isntalled
$dir_to_remove = SPARK_PATH . ($version == null ? "/$spark_name" : "/$spark_name/$version");
if (!file_exists($dir_to_remove))
{
return Spark_utils::warning('Looks like that spark isn\'t installed');
}
if ($version == null && !array_key_exists('f', $flags))
{
throw new Spark_exception("Please specify a version (spark remove -v1.0.0 foo) or remove all with -f");
}
Spark_utils::notice("Removing $spark_name (" . ($version ? $version : 'ALL') . ") from $dir_to_remove");
if (Spark_utils::remove_full_directory($dir_to_remove, true))
{
Spark_utils::notice('Spark removed successfully!');
}
else
{
Spark_utils::warning('Looks like that spark isn\'t installed');
}
// attempt to clean up - will not remove unless empty
@rmdir(SPARK_PATH . "/$spark_name");
}
private function install($args)
{
list($flats, $flags) = $this->prep_args($args);
if (count($flats) != 1)
{
return $this->failtown('format: `spark install -v1.0.0 name`');
}
$spark_name = $flats[0];
$version = array_key_exists('v', $flags) ? $flags['v'] : 'HEAD';
// retrieve the spark details
foreach ($this->spark_sources as $source)
{
Spark_utils::notice("Retrieving spark detail from " . $source->get_url());
$spark = $source->get_spark_detail($spark_name, $version);
if ($spark != null) break;
}
// did we find the details?
if ($spark == null)
{
throw new Spark_exception("Unable to find spark: $spark_name ($version) in any sources");
}
// verify the spark, and put out warnings if needed
$spark->verify();
// retrieve the spark
Spark_utils::notice("From Downtown! Retrieving spark from " . $spark->location_detail());
$spark->retrieve();
// Install it
$spark->install();
Spark_utils::notice('Spark installed to ' . $spark->installed_path() . ' - You\'re on fire!');
}
private function reinstall($args)
{
list($flats, $flags) = $this->prep_args($args);
if (count($flats) != 1)
{
return $this->failtown('format: `spark reinstall -v1.0.0 name`');
}
$spark_name = $flats[0];
$version = array_key_exists('v', $flags) ? $flags['v'] : null;
if ($version == null && !array_key_exists('f', $flags))
{
throw new Spark_exception("Please specify a version to reinstall, or use -f to remove all versions and install latest.");
}
$this->remove($args);
$this->install($args);
}
/**
* Prepares the command line arguments for use.
*
* Usage:
* list($flats, $flags) = $this->prep_args($args);
*
* @param array the arguments array
* @return array the flats and flags
*/
private function prep_args($args)
{
$flats = array();
$flags = array();
foreach($args as $arg)
{
preg_match('/^(\-?[a-zA-Z])([^\s]*)$/', $arg, $matches);
if (count($matches) != 3) continue;
$matches[0][0] == '-' ? $flags[$matches[1][1]] = $matches[2] : $flats[] = $matches[0];
}
return array($flats, $flags);
}
}

View File

@@ -0,0 +1,5 @@
<?php
class Spark_exception extends Exception {
}

View File

@@ -0,0 +1,99 @@
<?php
require_once 'spark_type.php';
require_once 'spark_types/git_spark.php';
require_once 'spark_types/hg_spark.php';
require_once 'spark_types/zip_spark.php';
class Spark_source {
public $url;
public $version_data;
public $version;
function __construct($url)
{
$this->url = $url;
$this->version_data = json_decode(@file_get_contents("http://$this->url/api/system/latest"));
$this->version = $this->version_data->spark_manager;
$this->warn_if_outdated();
}
function get_url()
{
return $this->url;
}
// get details on an individual spark
function get_spark_detail($spark_name, $version = 'HEAD')
{
$json_data = @file_get_contents("http://$this->url/api/packages/$spark_name/versions/$version/spec");
if (!$json_data) return null; // no such spark here
$data = json_decode($json_data);
// if we don't succeed - throw an error
if ($data == null || !$data->success)
{
$message = "Error retrieving spark detail from source: $this->url";
if ($data != null) $message .= " ($data->message)";
throw new Spark_exception($message);
}
// Get the detail for this spark
return $this->get_spark($data->spec);
}
// get details on multiple sparks by search term
function search($term)
{
$json_data = @file_get_contents("http://$this->url/api/packages/search?q=" . urlencode($term));
$data = json_decode($json_data);
// if the data isn't around of success is false, return a warning for this source
if ($data == null || !$data->success)
{
$message = "Error searching source: $this->url";
if ($data != null) $message .= " ($data->message)";
Spark_utils::warning($message);
return array();
}
// Get sparks for each one
$results = array();
foreach($data->results as $data)
{
$results[] = $this->get_spark($data);
}
return $results;
}
private function warn_if_outdated()
{
if ($this->outdated())
{
Spark_utils::warning("Your installed version of spark is outdated (current version: " . $this->outdated() . " / latest: " . $this->version . ")");
Spark_utils::warning("To upgrade now, use `php tools/spark upgrade-system`");
}
}
function outdated() {
// Get the version for this source
if (!$this->version) return; // no version found
// Split versions
list($self_major, $self_minor, $self_patch) = explode('.', SPARK_VERSION);
list($source_major, $source_minor, $source_patch) = explode('.', $this->version);
// Compare
if ($self_major < $source_major ||
$self_major == $source_major && $self_minor < $source_minor ||
$self_major == $source_major && $self_minor == $source_minor && $self_patch < $source_patch)
{
return SPARK_VERSION;
}
}
private function get_spark($data)
{
if ($data->repository_type == 'hg') return Mercurial_spark::get_spark($data);
else if ($data->repository_type == 'git') return Git_spark::get_spark($data);
else if ($data->repository_type == 'zip') return new Zip_spark($data);
else throw new Exception('Unknown repository type: ' . $data->repository_type);
}
}

View File

@@ -0,0 +1,138 @@
<?php
class Spark_type {
function __construct($data)
{
$this->data = $data;
$this->name = $this->data->name;
$this->spark_id = property_exists($this->data, 'id') ? $this->data->id : null;
$this->version = property_exists($this->data, 'version') ? $this->data->version : null;
$this->tag = property_exists($this->data, 'tag') ? $this->data->tag : $this->version;
$this->base_location = property_exists($this->data, 'base_location') ? $this->data->base_location : null;
// Load the dependencies
$this->dependencies = property_exists($this->data, 'dependencies') ? $this->data->dependencies : array();
// Assign other data we don't have
foreach ($this->data as $k=>$v)
{
if (!property_exists($this, $k)) $this->$k = $v;
}
// used internally
$this->temp_token = 'spark-' . $this->spark_id . '-' . time();
$this->temp_path = sys_get_temp_dir() . '/' . $this->temp_token;
}
final function installed_path()
{
return $this->installed_path;
}
function location_detail() { }
function retrieve() { }
function install()
{
foreach ($this->dependencies as $dependency)
{
if ($dependency->is_direct)
{
$this->install_dependency($dependency);
}
}
@mkdir(SPARK_PATH); // Two steps for windows
@mkdir(SPARK_PATH . "/$this->name");
Spark_utils::full_move($this->temp_path, $this->installation_path);
Spark_utils::remove_full_directory($this->temp_path);
$this->installed_path = $this->installation_path;
}
private function recurseMove($src,$dst)
{
$dir = opendir($src);
@mkdir($dst);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
$this->recurseMove($src . '/' . $file,$dst . '/' . $file);
}
else {
rename($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
private function rrmdir($dir)
{
if (is_dir($dir)) {
$files = scandir($dir);
foreach ($files as $file) {
if ($file != "." && $file != "..") {
if (is_dir($dir . "/" . $file)) {
$this->rrmdir($dir . "/" . $file);
}
else {
unlink($dir . "/" . $file);
}
}
}
reset($files);
rmdir($dir);
}
}
function install_dependency($dependency_data) {
// Get the spark object
$spark = null;
if ($dependency_data->repository_type == 'hg') $spark = Mercurial_spark::get_spark($dependency_data);
else if ($dependency_data->repository_type == 'git') $spark = Git_spark::get_spark($dependency_data);
else if ($dependency_data->repository_type == 'zip') $spark = new Zip_spark($dependency_data);
else throw new Exception('Unknown repository type: ' . $dependency_data->repository_type);
// Install the spark
if ($spark->verify(false)) { // if not installed, install
$spark->retrieve();
$spark->install();
Spark_utils::notice("Installed dependency: $spark->name to " . $spark->installed_path());
}
else {
Spark_utils::warning("Dependency $spark->name is already installed.");
}
}
function verify($break_on_already_installed = true)
{
// see if this is deactivated
if ($this->data->is_deactivated)
{
$msg = 'Woah there - it seems the spark you want has been deactivated';
if ($this->data->spark_home) $msg .= "\nLook for different versions at: " . $this->data->spark_home;
throw new Spark_exception($msg);
}
// see if this is unsupported
if ($this->data->is_unsupported)
{
Spark_utils::warning('This spark is no longer supported.');
Spark_utils::warning('You can keep using it, or look for an alternate');
}
// tell the user if its already installed and throw an error
$this->installation_path = SPARK_PATH . "/$this->name/$this->version";
if (is_dir($this->installation_path))
{
if ($break_on_already_installed)
{
throw new Spark_exception("Already installed. Try `php tools/spark reinstall $this->name`");
}
return false;
}
else
{
return true;
}
}
}

View File

@@ -0,0 +1,53 @@
<?php
class Git_spark extends Spark_type {
function __construct($data)
{
if (!self::git_installed())
{
throw new Spark_exception('You have to have git to install this spark.');
}
parent::__construct($data);
$this->tag = $this->tag;
}
static function get_spark($data)
{
if (self::git_installed())
{
return new Git_spark($data);
}
else
{
Spark_utils::warning('Git not found - reverting to archived copy');
return new Zip_spark($data);
}
}
private static function git_installed()
{
return !!`git`;
}
function location_detail()
{
return "Git repository at $this->base_location";
}
function retrieve()
{
// check out the right tag
`git clone --recursive $this->base_location $this->temp_path`;
`cd $this->temp_path; git checkout $this->tag -b $this->temp_token`;
// remove the git directory
Spark_utils::remove_full_directory("$this->temp_path/.git");
if (!file_exists($this->temp_path))
{
throw new Spark_exception('Failed to retrieve the spark ;(');
}
return true;
}
}

View File

@@ -0,0 +1,47 @@
<?php
class Mercurial_spark extends Spark_type {
function __construct($data)
{
parent::__construct($data);
$this->tag = $this->tag;
}
static function get_spark($data)
{
if (self::hg_installed())
{
return new Mercurial_spark($data);
}
else
{
Spark_utils::warning('Mercurial not found - reverting to archived copy');
return new Zip_spark($data);
}
}
private static function hg_installed()
{
return !!`hg`;
}
function location_detail()
{
return "Mercurial repository at $this->base_location";
}
function retrieve()
{
`hg clone -r$this->tag $this->base_location $this->temp_path`;
// remove the mercurial directory
Spark_utils::remove_full_directory("$this->temp_path/.hg");
if (!file_exists($this->temp_path))
{
throw new Spark_exception('Failed to retrieve the spark ;(');
}
return true;
}
}

View File

@@ -0,0 +1,49 @@
<?php
class Zip_spark extends Spark_type {
function __construct($data)
{
parent::__construct($data);
$this->temp_file = $this->temp_path . '.zip';
$this->archive_url = property_exists($this->data, 'archive_url') ? $this->data->archive_url : null;
}
function location_detail()
{
return "ZIP archive at $this->archive_url";
}
private static function unzip_installed()
{
return !!`unzip`;
}
function retrieve()
{
file_put_contents($this->temp_file, file_get_contents($this->archive_url));
// Try a few ways to unzip
if (class_exists('ZipArchive'))
{
$zip = new ZipArchive;
$zip->open($this->temp_file);
$zip->extractTo($this->temp_path);
$zip->close();
}
else
{
if (!self::unzip_installed())
{
throw new Spark_exception('You have to install PECL ZipArchive or `unzip` to install this spark.');
}
`unzip $this->temp_file -d $this->temp_path`;
}
if (!file_exists($this->temp_path))
{
throw new Spark_exception('Failed to retrieve the spark ;(');
}
return true;
}
}

View File

@@ -0,0 +1,108 @@
<?php
// backward compatibility
if ( !function_exists('sys_get_temp_dir'))
{
function sys_get_temp_dir()
{
if ($temp = getenv('TMP')) return $temp;
if ($temp = getenv('TEMP')) return $temp;
if ($temp = getenv('TMPDIR')) return $temp;
$temp = tempnam(__FILE__, '');
if (file_exists($temp))
{
unlink($temp);
return dirname($temp);
}
return '/tmp'; // the best we can do
}
}
class Spark_utils {
private static $buffer = false;
private static $lines = array();
static function get_lines()
{
return self::$lines;
}
static function buffer()
{
self::$buffer = true;
}
static function full_move($src, $dst)
{
$dir = opendir($src);
@mkdir($dst);
while(false !== ($file = readdir($dir))) {
if (($file != '.') && ($file != '..')) {
if (is_dir($src . '/' . $file)) {
self::full_move($src . '/' . $file,$dst . '/' . $file);
}
else {
rename($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
static function remove_full_directory($dir, $vocally = false)
{
if (is_dir($dir))
{
$objects = scandir($dir);
foreach ($objects as $object)
{
if ($object != '.' && $object != '..')
{
if (filetype($dir . '/' . $object) == "dir")
{
self::remove_full_directory($dir . '/' . $object, $vocally);
}
else
{
if ($vocally) self::notice("Removing $dir/$object");
unlink($dir . '/' . $object);
}
}
}
reset($objects);
return rmdir($dir);
}
}
static function notice($msg)
{
self::line($msg, 'SPARK', '[1;36m');
}
static function error($msg)
{
self::line($msg, 'ERROR', '[1;31m');
}
static function warning($msg)
{
self::line($msg, 'WARNING', '[1;33m');
}
static function line($msg = '', $s = null, $color = null)
{
foreach(explode("\n", $msg) as $line)
{
if (self::$buffer)
{
self::$lines[] = $line;
}
else
{
echo !$s ? "$line\n" : chr(27) . $color . "[ $s ]" . chr(27) . "[0m" . " $line\n";
}
}
}
}

32
tools/spark Normal file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/env php
<?php
require_once 'lib/spark/spark_source.php';
require_once 'lib/spark/spark_cli.php';
// define a source
$sources = array();
if ($fh = @fopen(dirname(__FILE__) . '/lib/spark/sources', 'r'))
{
while ($line = fgets($fh))
{
$line = trim($line);
if ($line && $line[0] != '#') $sources[] = new Spark_source($line);
}
fclose($fh);
}
if (count($sources) == 0)
{
$default_source = 'sparks.oconf.org';
Spark_utils::warning("No sources found, using $default_source");
$sources[] = new Spark_source($default_source);
}
// take commands
$cli = new Spark_CLI($sources);
$cmd = $argc > 1 ? $argv[1] : null;
$args = $argc > 2 ? array_slice($argv, 2) : array();
$cli->execute($cmd, $args);

View File

@@ -0,0 +1,49 @@
<?php
class Install_test extends Spark_test_case {
function test_install_with_version()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('install', array('-v1.0', 'example-spark'));
});
$success = (bool) (strpos(end($clines), chr(27) . '[1;36m[ SPARK ]' .
chr(27) . '[0m Spark installed') === 0);
Spark_utils::remove_full_directory(SPARK_PATH . '/example-spark');
$this->assertEquals(true, $success);
}
function test_install_without_version()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('install', array('example-spark'));
});
$success = (bool) (strpos(end($clines), chr(27) . '[1;36m[ SPARK ]' .
chr(27) . '[0m Spark installed') === 0);
Spark_utils::remove_full_directory(SPARK_PATH . '/example-spark');
$this->assertEquals(true, $success);
}
function test_install_with_invalid_spark()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('install', array('jjks7878erHjhsjdkksj'));
});
$success = (bool) (strpos(end($clines), chr(27) . '[1;31m[ ERROR ]' .
chr(27) . '[0m Unable to find spark') === 0);
Spark_utils::remove_full_directory(SPARK_PATH . '/example-spark');
$this->assertEquals(true, $success);
}
function test_install_with_invalid_spark_version()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('install', array('v9.4', 'example-spark'));
});
$success = (bool) (strpos(reset($clines), chr(27) . '[1;31m[ ERROR ]' .
chr(27) . '[0m Uh-oh!') === 0);
Spark_utils::remove_full_directory(SPARK_PATH . '/example-spark');
$this->assertEquals(true, $success);
}
}

View File

@@ -0,0 +1,34 @@
<?php
define('SPARK_PATH', __DIR__ . '/test-sparks');
require __DIR__ . '/../../lib/spark/spark_cli.php';
class Spark_test_case extends PHPUnit_Framework_TestCase {
function setUp()
{
$this->source_names[] = 'getsparks.org';
$this->sources = array_map(function($n) {
return new Spark_source($n);
}, $this->source_names);
$this->cli = new Spark_CLI($this->sources);
}
function tearDown()
{
if (is_dir(SPARK_PATH . '/example-spark'))
{
Spark_utils::remove_full_directory(SPARK_PATH . '/example-spark');
}
}
protected function capture_buffer_lines($func) {
ob_start();
$func($this->cli);
$t = ob_get_contents();
ob_end_clean();
if ($t == '') return array(); // empty
return explode("\n", substr($t, 0, count($t) - 2));
}
}

View File

9
tools/test/phpunit.xml Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" stopOnFailure="false" bootstrap="lib/bootstrap.php">
<testsuites>
<testsuite name="SparkTests">
<directory suffix="_test.php">./</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@@ -0,0 +1,50 @@
<?php
class Remove_test extends Spark_test_case {
function test_remove_with_version()
{
// Test install with a version specified
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('install', array('-v1.0', 'example-spark')); // Spark needs installed first
$cli->execute('remove', array('-v1.0', 'example-spark'));
});
$success = (bool) (strpos(end($clines), chr(27) . '[1;36m[ SPARK ]' . chr(27) . '[0m Spark removed') === 0 && ! is_dir(SPARK_PATH.'/example-spark'));
$this->assertEquals(true, $success);
Spark_utils::remove_full_directory(SPARK_PATH . '/example-spark');
}
function test_remove_without_flags()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('install', array('-v1.0', 'example-spark')); // Spark needs installed first
$cli->execute('remove', array('example-spark'));
});
$success = (bool) (strpos(end($clines), chr(27) . '[1;31m[ ERROR ]' . chr(27) . '[0m Please specify') === 0 && is_dir(SPARK_PATH.'/example-spark'));
$this->assertEquals(true, $success);
Spark_utils::remove_full_directory(SPARK_PATH . '/example-spark');
}
function test_remove_with_f_flag()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('install', array('-v1.0', 'example-spark')); // Spark needs installed first
$cli->execute('remove', array('-f', 'example-spark'));
});
$success = (bool) (strpos(end($clines), chr(27) . '[1;36m[ SPARK ]' . chr(27) . '[0m Spark removed') === 0 && ! is_dir(SPARK_PATH.'/example-spark'));
$this->assertEquals(true, $success);
Spark_utils::remove_full_directory(SPARK_PATH . '/example-spark');
}
function test_remove_with_invalid_version()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('install', array('-v1.0', 'example-spark')); // Spark needs installed first
$cli->execute('remove', array('-v9.4', 'example-spark'));
});
$success = (bool) (strpos(end($clines), chr(27) . '[1;36m[ SPARK ]' . chr(27) . '[0m Looks like that spark isn\'t installed') === 0 && is_dir(SPARK_PATH.'/example-spark'));
$this->assertEquals(true, $success);
Spark_utils::remove_full_directory(SPARK_PATH . '/example-spark');
}
}

View File

@@ -0,0 +1,14 @@
<?php
class Search_test extends Spark_test_case {
function test_search()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('search', array('markdown'));
});
// Less than ideal, I know
$this->assertEquals(array("\033[33mmarkdown\033[0m - A markdown helper for easy parsing of markdown"), $clines);
}
}

View File

@@ -0,0 +1,37 @@
<?php
class Version_test extends Spark_test_case {
function test_version()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('version');
});
$this->assertEquals(array(SPARK_VERSION), $clines);
}
function test_sources()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('sources');
});
$this->assertEquals($this->source_names, $clines);
}
function test_bad_command()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('fake');
});
$this->assertEquals(array(chr(27) . '[1;31m[ ERROR ]' . chr(27) . '[0m Uh-oh!', chr(27) . '[1;31m[ ERROR ]' . chr(27) . '[0m Unknown action: fake'), $clines);
}
function test_search_empty()
{
$clines = $this->capture_buffer_lines(function($cli) {
$cli->execute('search', array('nothing_found_here'));
});
$this->assertEquals(array(), $clines);
}
}