From 0fb4d1e9a209e380e55d406f121235432d89e37c Mon Sep 17 00:00:00 2001 From: tmont Date: Sat, 13 Jun 2009 06:56:12 +0000 Subject: [PATCH] set up autoload and build script --- build.xml | 60 ++++++++++ properties/build.properties | 1 + properties/dir.properties | 2 + properties/product.properties | 4 + src/TUnit/bootstrap.php | 8 ++ src/TUnit/manifest.php | 34 ++++++ src/TUnit/util/Autoloader.php | 98 ++++++++++++++++ tools/cli.php | 214 ++++++++++++++++++++++++++++++++++ tools/manifester.php | 167 ++++++++++++++++++++++++++ 9 files changed, 588 insertions(+) create mode 100644 build.xml create mode 100644 properties/build.properties create mode 100644 properties/dir.properties create mode 100644 properties/product.properties create mode 100644 src/TUnit/bootstrap.php create mode 100644 src/TUnit/manifest.php create mode 100644 src/TUnit/util/Autoloader.php create mode 100644 tools/cli.php create mode 100644 tools/manifester.php diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..1413350 --- /dev/null +++ b/build.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Beginning build for ${product.name} ${product.version} + ${TIMESTAMP} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/properties/build.properties b/properties/build.properties new file mode 100644 index 0000000..c487882 --- /dev/null +++ b/properties/build.properties @@ -0,0 +1 @@ +base=./build \ No newline at end of file diff --git a/properties/dir.properties b/properties/dir.properties new file mode 100644 index 0000000..7143df7 --- /dev/null +++ b/properties/dir.properties @@ -0,0 +1,2 @@ +tools=tools +src=src \ No newline at end of file diff --git a/properties/product.properties b/properties/product.properties new file mode 100644 index 0000000..d08264a --- /dev/null +++ b/properties/product.properties @@ -0,0 +1,4 @@ +name=TUnit +version=0.1.0 +author=Tommy Montgomery +website=http://tommymontgomery.com/ \ No newline at end of file diff --git a/src/TUnit/bootstrap.php b/src/TUnit/bootstrap.php new file mode 100644 index 0000000..62d850b --- /dev/null +++ b/src/TUnit/bootstrap.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/src/TUnit/manifest.php b/src/TUnit/manifest.php new file mode 100644 index 0000000..9edc797 --- /dev/null +++ b/src/TUnit/manifest.php @@ -0,0 +1,34 @@ + 'TUnit/framework/Assert.php', + 'Autoloader' => 'TUnit/util/Autoloader.php', + 'CombinedCaseResult' => 'TUnit/framework/CombinedTestResult.php', + 'ErredTest' => 'TUnit/framework/FailedTest.php', + 'FailedTest' => 'TUnit/framework/FailedTest.php', + 'FailedTestResult' => 'TUnit/framework/FailedTestResult.php', + 'IgnoredTest' => 'TUnit/framework/FailedTest.php', + 'IgnoredTestResult' => 'TUnit/framework/IgnoredTestResult.php', + 'PassedTestResult' => 'TUnit/framework/PassedTestResult.php', + 'TestCase' => 'TUnit/framework/TestCase.php', + 'TestFailure' => 'TUnit/framework/FailedTest.php', + 'TestListener' => 'TUnit/framework/TestListener.php', + 'TestMethod' => 'TUnit/framework/TestMethod.php', + 'TestReporter' => 'TUnit/framework/TestReporter.php', + 'TestResult' => 'TUnit/framework/TestResult.php', + 'TestRunner' => 'TUnit/framework/TestRunner.php', + 'TestSuite' => 'TUnit/framework/TestSuite.php', + 'Testable' => 'TUnit/framework/Testable.php' + ); + +?> \ No newline at end of file diff --git a/src/TUnit/util/Autoloader.php b/src/TUnit/util/Autoloader.php new file mode 100644 index 0000000..a848118 --- /dev/null +++ b/src/TUnit/util/Autoloader.php @@ -0,0 +1,98 @@ + path map + * + * @version 1.0 + * @since 1.0 + * + * @return array + */ + public static function getClassMap() { + return self::$classMap; + } + + /** + * Loads a class map from an array + * + * @version 1.0 + * @since 1.0 + * @see loadClassMapFromFile() + * + * @param array $classMap Array of classes and the paths they map to + * @param string $override Whether to override previously existing classes + */ + public static function loadClassMap(array $classMap, $override = true) { + if ((bool)$override) { + self::$classMap = array_merge(self::$classMap, $classMap); + } else { + self::$classMap += $classMap; + } + } + + /** + * Loads a class map from a file + * + * @version 1.0 + * @since 1.0 + * @uses loadClassMap() + * + * @param string $file The manifest file to load + * @param string $override Whether to override previously existing classes + * @throws InvalidArgumentException + */ + public static function loadClassMapFromFile($file, $override = true) { + if (!is_string($file) || !is_file($file)) { + throw new InvalidArgumentException('1st argument must be an existing file'); + } + + self::loadClassMap((array)include $file, $override); + } + + /** + * Autoload function used by spl_autoload_call() + * @ignore + */ + public static function autoload($className) { + if (isset(self::$classMap[$className])) { + require_once self::$classMap[$className]; + } + } + + } + +?> \ No newline at end of file diff --git a/tools/cli.php b/tools/cli.php new file mode 100644 index 0000000..d2e2b71 --- /dev/null +++ b/tools/cli.php @@ -0,0 +1,214 @@ + array(), + 'args' => array() + ); + + $last = null; + foreach ($args as $arg) { + if (strpos($arg, '-') === 0) { + $last = (substr($arg, 0, 2) === '--') ? substr($arg, 2) : substr($arg, 1); + $switch = $switches->getSwitch($last); + if ($switch !== null) { + $parsed['switches'][$switch->longName] = true; + } + } else if ($switch !== null) { + if ($switch->value !== null) { + $parsed['switches'][$switch->longName] = $arg; + } else { + $parsed['args'][] = $arg; + } + + $switch = null; + } else { + $parsed['args'][] = $arg; + } + } + + return $parsed; + } + + } + + class CliSwitch { + public $longName; + public $shortName; + public $required; + public $value; + public $description; + + public function __construct($longName, $shortName = '', $required = true, $value = null, $description = '') { + $this->longName = $longName; + $this->shortName = $shortName; + $this->required = $required; + $this->value = $value; + $this->description = $description; + } + } + + class CliSwitchCollection implements IteratorAggregate { + + private $switches; + + public function __construct() { + $this->switches = array(); + } + + public function addSwitch(CliSwitch $switch) { + $this->switches[] = $switch; + return $this; + } + + public function getSwitch($longOrShortName) { + foreach ($this->switches as $switch) { + if ($switch->longName == $longOrShortName || $switch->shortName == $longOrShortName) { + return $switch; + } + } + + return null; + } + + public function segregateSwitches() { + $switches = array( + 'required' => array(), + 'optional' => array() + ); + foreach ($this->switches as $switch) { + if ($switch->required) { + $switches['required'][] = $switch; + } else { + $switches['optional'][] = $switch; + } + } + + return $switches; + } + + public function getIterator() { + return new ArrayIterator($this->switches); + } + + } + + class Usage { + + private $switches; + private $name; + private $script; + private $description; + private $copyright; + private $maxSwitchLength; + + const LINE_LENGTH = 80; + + public function __construct($name, $script, $description, $author = null, $date = null) { + $this->switches = array(array(), array()); + $this->maxSwitchLength = 0; + $this->script = $script; + $this->name = $name; + $this->description = $description; + $this->copyright = + ($date !== null) + ? 'Copyright (c) ' . $date . (($author !== null) ? " $author" : '') + : (($author !== null) ? "by $author" : ''); + } + + public function __get($key) { + if ($key === 'switches') { + return $this->switches; + } + + throw new InvalidArgumentException('Invalid property'); + } + + public function setSwitches(CliSwitchCollection $switches) { + $this->switches = $switches; + + $this->maxSwitchLength = 0; + foreach ($switches->getIterator() as $switch) { + // + 2 for left padding + // + 2 for double-hyphen + $length = 2 + strlen($switch->longName) + 2; + + // + 1 for left padding + // + 1 for hyphen + // + 1 for openening parenthesis + // + 1 for closing parenthesis + $length += (strlen($switch->shortName) > 0) ? 1 + 1 + 1 + strlen($switch->shortName) + 1 : 0; + //echo $length . "\n"; + $this->maxSwitchLength = max($this->maxSwitchLength, $length); + } + + //echo $this->maxSwitchLength; exit; + } + + public function __toString() { + $this->maxSwitchLength += 2; + $usage = $this->name . "\n"; + $usage .= (!empty($this->copyright)) ? ' ' . $this->copyright . "\n" : ''; + $usage .= "\n"; + + $usage .= "USAGE\n"; + $usageData = ' php ' . $this->script; + + $switchData = "REQUIRED\n"; + + $switches = $this->switches->segregateSwitches(); + + foreach ($switches['required'] as $switch) { + $usageData .= ' --' . $switch->longName; + if ($switch->value !== null) { + $usageData .= ' ' . $switch->value; + } + + $x = ' --' . $switch->longName; + if (!empty($switch->shortName)) { + $x .= str_repeat(' ', $this->maxSwitchLength - 5 - strlen($x)) . '(-' . $switch->shortName . ')'; + } + + $x .= str_repeat(' ' , $this->maxSwitchLength - strlen($x)); + $x .= wordwrap($switch->description, self::LINE_LENGTH - strlen($x), "\n" . str_repeat(' ', strlen($x))) . "\n"; + $switchData .= $x; + } + + $switchData .= "\nOPTIONAL\n"; + foreach ($switches['optional'] as $switch) { + $usageData .= ' [--' . $switch->longName; + if ($switch->value !== null) { + $usageData .= ' ' . $switch->value; + } + $usageData .= ']'; + + $x = ' --' . $switch->longName; + if (!empty($switch->shortName)) { + $x .= str_repeat(' ', $this->maxSwitchLength - 5 - strlen($x)) . '(-' . $switch->shortName . ')'; + } + + $x .= str_repeat(' ' , $this->maxSwitchLength - strlen($x)); + $x .= wordwrap($switch->description, self::LINE_LENGTH - strlen($x), "\n" . str_repeat(' ', strlen($x))) . "\n"; + $switchData .= $x; + } + + $usage .= wordwrap($usageData, self::LINE_LENGTH - 2, "\n "); + + $usage .= "\n\n" . $switchData . "\n"; + + return $usage; + } + + } + +?> \ No newline at end of file diff --git a/tools/manifester.php b/tools/manifester.php new file mode 100644 index 0000000..096518f --- /dev/null +++ b/tools/manifester.php @@ -0,0 +1,167 @@ +setSwitches($switches); + + echo $usage; + } + + if (!extension_loaded('tokenizer')) { + throw new Exception('The "tokenizer" extension must be loaded to use this script'); + } + + global $switches; + $switches = new CliSwitchCollection(); + $switches->addSwitch(new CliSwitch('directory', 'd', true, 'dir1,dir2,...', 'Comma-delimited list of directories')) + ->addSwitch(new CliSwitch('version', 'v', true, 'version_number', 'Version number for use in @version tag')) + ->addSwitch(new CliSwitch('package', 'p', true, 'package_name ', 'Name of the package for use in @package tag')) + ->addSwitch(new CliSwitch('output', 'o', false, 'file', 'Name of the output file, defaults to stdout if empty and this is really really really really long')) + ->addSwitch(new CliSwitch('quiet', 'q', false, null, 'Do not print progress messages')) + ->addSwitch(new CliSwitch('recursive', 'r', false, null, 'Recursively walk the directories')) + ->addSwitch(new CliSwitch('base-dir', 'b', true, 'dir', 'Base directory')); + + array_shift($argv); + $args = Cli::parseArgs($argv, $switches); + $args = $args['switches']; //don't care about non-switch stuff + + if (!isset($args['directory'], $args['version'], $args['package'], $args['base-dir'])) { + usage(); + fwrite(STDERR, "Missing a required argument\n"); + exit(1); + } + + $dirs = explode(',', $args['directory']); + + if (!is_dir($args['base-dir'])) { + fwrite(STDERR, $args['base-dir'] . ' is not a directory'); + exit(1); + } + + $args['recursive'] = array_key_exists('recursive', $args); + $args['quiet'] = array_key_exists('quiet', $args); + + $date = date('Y-m-d H:i:s'); + $self = basename(__FILE__); + $data = <<isFile() && strpos($file->getPathName(), DIRECTORY_SEPARATOR . '.') === false && substr($file->getFileName(), -4) === '.php') { + if (!$args['quiet']) { + echo 'Processing ' . $file->getPathName() . "\n"; + } + + $tokens = token_get_all(file_get_contents($file->getPathName())); + $count = count($tokens); + for ($i = 0; $i < $count; $i++) { + if (is_array($tokens[$i])) { + if ($tokens[$i][0] === T_CLASS || $tokens[$i][0] === T_INTERFACE) { + //get class name + if (isset($tokens[$i + 2]) && is_array($tokens[$i + 2]) && $tokens[$i + 2][0] === T_STRING) { + $className = $tokens[$i + 2][1]; + if (isset($classes[$className]) && !$args['quiet']) { + fwrite(STDERR, '******WARNING: FOUND DUPLICATE CLASS (' . $className . ')******' . "\n"); + } + + $classes[$className] = ltrim(str_replace(array($args['base-dir'], DIRECTORY_SEPARATOR), array('', '/'), $file->getPathName()), '/'); + $maxClassNameLength = max($maxClassNameLength, strlen($className)); + $i += 2; //loop unroll FTW! + + if (!$args['quiet']) { + echo 'Added class/interface ' . $className . "\n"; + } + } + } + } + } + + unset($tokens); + } + } + } + + echo "\n" . '# of classes: ' . count($classes) . "\n\n"; + + $func = create_function( + '&$value, $key', + '$value = "\t\t\'$key\'" . str_repeat(\' \', ' . $maxClassNameLength . ' - strlen($key)) . " => \'$value\'";' + ); + + ksort($classes); + array_walk($classes, $func); + + $data .= implode(",\n", $classes) . "\n\t);\n\n?>"; + if (isset($args['output']) && !is_dir(dirname($args['output'])) && !mkdir(dirname($args['output']), 0777, true)) { + fwrite(STDERR, 'Unable to mkdir(): ' . dirname($args['output'])); + exit(1); + } else if (!isset($args['output'])) { + $args['output'] = 'php://stdout'; + } + + if (is_dir($args['output'])) { + $args['output'] .= DIRECTORY_SEPARATOR . 'manifest.php'; + } + + $fp = fopen($args['output'], 'w'); + if (!$fp) { + fwrite(STDERR, 'Unable to open ' . $args['output'] . ' for writing'); + exit(1); + } + + fwrite($fp, $data); + fclose($fp); + echo 'Wrote data to ' . $args['output'] . ' (' . strlen($data) . ' bytes)' . "\n"; + + exit(0); + +?> \ No newline at end of file