set up autoload and build script
This commit is contained in:
parent
e3469385a3
commit
0fb4d1e9a2
60
build.xml
Normal file
60
build.xml
Normal file
@ -0,0 +1,60 @@
|
||||
<project name="TUnit" basedir="." default="help">
|
||||
|
||||
<property file="./properties/product.properties" prefix="product"/>
|
||||
<property file="./properties/build.properties" prefix="build"/>
|
||||
<property file="./properties/dir.properties" prefix="dir"/>
|
||||
|
||||
<target name="clean" depends="init" description="Cleans up artifacts created by the build">
|
||||
<delete dir="${build.base}"/>
|
||||
</target>
|
||||
|
||||
<target name="help" depends="set-exe-suffix" description="Displays information about available targets">
|
||||
<exec executable="ant${exe.suffix}" failonerror="true">
|
||||
<arg value="-p"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="lint" depends="init" description="Scans for parse errors">
|
||||
<apply executable="php">
|
||||
<arg line="-l"/>
|
||||
<fileset dir=".">
|
||||
<include name="${dir.src}/**/*.php"/>
|
||||
</fileset>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
<target name="manifest" depends="init" description="Builds the manifest file for the autoload mechanism (to ./inc/manifest.php)">
|
||||
<exec executable="php">
|
||||
<arg line="${dir.tools}/manifester.php"/>
|
||||
<arg line="-d ${dir.src}/${ant.project.name}"/>
|
||||
<arg line="-v ${product.version}"/>
|
||||
<arg line="-p ${ant.project.name}"/>
|
||||
<arg line="-o ${dir.src}/${ant.project.name}/manifest.php"/>
|
||||
<arg line="-r"/>
|
||||
<arg line="-b ${dir.src}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!--
|
||||
INTERNAL TARGETS
|
||||
-->
|
||||
<target name="init">
|
||||
<tstamp>
|
||||
<format property="TIMESTAMP" pattern="yyyy-MM-dd HH:mm:ss"/>
|
||||
</tstamp>
|
||||
<echo level="info">Beginning build for ${product.name} ${product.version}</echo>
|
||||
<echo level="info"> ${TIMESTAMP}</echo>
|
||||
<echo level="info"/>
|
||||
</target>
|
||||
|
||||
<target name="prepare-build">
|
||||
<mkdir dir="${build.base}"/>
|
||||
</target>
|
||||
|
||||
<target name="set-exe-suffix">
|
||||
<condition property="exe.suffix" value=".bat" else="">
|
||||
<os family="winnt"/>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
</project>
|
1
properties/build.properties
Normal file
1
properties/build.properties
Normal file
@ -0,0 +1 @@
|
||||
base=./build
|
2
properties/dir.properties
Normal file
2
properties/dir.properties
Normal file
@ -0,0 +1,2 @@
|
||||
tools=tools
|
||||
src=src
|
4
properties/product.properties
Normal file
4
properties/product.properties
Normal file
@ -0,0 +1,4 @@
|
||||
name=TUnit
|
||||
version=0.1.0
|
||||
author=Tommy Montgomery
|
||||
website=http://tommymontgomery.com/
|
8
src/TUnit/bootstrap.php
Normal file
8
src/TUnit/bootstrap.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
require_once 'util/Autoloader.php';
|
||||
|
||||
Autoloader::loadClassMap(dirname(__FILE__) . '/manifest.php');
|
||||
spl_autoload_register('Autoloader::autoload');
|
||||
|
||||
?>
|
34
src/TUnit/manifest.php
Normal file
34
src/TUnit/manifest.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Autoload manifest
|
||||
*
|
||||
* Autogenerated by manifester.php on 2009-06-12 23:55:38
|
||||
*
|
||||
* @package TUnit
|
||||
* @version 0.1.0
|
||||
* @since 0.1.0
|
||||
*/
|
||||
|
||||
return array(
|
||||
'Assert' => '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'
|
||||
);
|
||||
|
||||
?>
|
98
src/TUnit/util/Autoloader.php
Normal file
98
src/TUnit/util/Autoloader.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Autoloader
|
||||
*
|
||||
* @package Library
|
||||
* @subpackage Utilities
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bootstraps each NowhereConcave package via autoload
|
||||
*
|
||||
* @package Library
|
||||
* @subpackage Utilities
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
*/
|
||||
final class Autoloader {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $classMap = array();
|
||||
|
||||
//@codeCoverageIgnoreStart
|
||||
/**
|
||||
* Not instantiable
|
||||
* @ignore
|
||||
*/
|
||||
private function __construct() {
|
||||
|
||||
}
|
||||
//@codeCoverageIgnoreEnd
|
||||
|
||||
/**
|
||||
* Gets the current class -> 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];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
214
tools/cli.php
Normal file
214
tools/cli.php
Normal file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
class Cli {
|
||||
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Parses command line arguments
|
||||
*
|
||||
* @param array $args
|
||||
* @return array
|
||||
*/
|
||||
public static function parseArgs(array $args, CliSwitchCollection $switches) {
|
||||
$parsed = array(
|
||||
'switches' => 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
167
tools/manifester.php
Normal file
167
tools/manifester.php
Normal file
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Command line interface for generating autoload manifests
|
||||
*
|
||||
* @package Tools
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Command line tools
|
||||
*/
|
||||
require_once 'cli.php';
|
||||
|
||||
/**
|
||||
* Prints usage
|
||||
*/
|
||||
function usage() {
|
||||
$usage = new Usage(
|
||||
'Manifest Builder 1.0',
|
||||
basename(__FIlE__),
|
||||
'Builds a manifest file suitable for use by Autoloader',
|
||||
'Tommy Montgomery',
|
||||
'2009'
|
||||
);
|
||||
|
||||
global $switches;
|
||||
$usage->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 = <<<ENDDATA
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Autoload manifest
|
||||
*
|
||||
* Autogenerated by $self on $date
|
||||
*
|
||||
* @package $args[package]
|
||||
* @version $args[version]
|
||||
* @since $args[version]
|
||||
*/
|
||||
|
||||
return array(
|
||||
|
||||
ENDDATA;
|
||||
|
||||
$classes = array();
|
||||
$maxClassNameLength = 0;
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
if (!is_dir($dir)) {
|
||||
fwrite(STDERR, $dir . ' is not a directory... skipping');
|
||||
continue;
|
||||
}
|
||||
|
||||
$iterator = $args['recursive'] ? new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) : new DirectoryIterator($dir);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->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);
|
||||
|
||||
?>
|
Loading…
Reference in New Issue
Block a user