/** * Set-up default vars */ public static function init() { // make sure config vars exist if (!Config::getOption("patternExtension")) { Console::writeError("the pattern extension config option needs to be set..."); } if (!Config::getOption("styleguideKit")) { Console::writeError("the styleguideKit config option needs to be set..."); } // set-up config vars $patternExtension = Config::getOption("patternExtension"); $pluginDir = Config::getOption("packagesDir"); $sourceDir = Config::getOption("sourceDir"); $styleguideKit = Config::getOption("styleguideKit"); // load pattern-lab's resources $partialPath = $pluginDir . "/" . $styleguideKit . "/views/partials"; self::$htmlHead = file_get_contents($partialPath . "/general-header." . $patternExtension); self::$htmlFoot = file_get_contents($partialPath . "/general-footer." . $patternExtension); // gather the user-defined header and footer information $patternHeadPath = $sourceDir . "/_meta/_00-head." . $patternExtension; $patternFootPath = $sourceDir . "/_meta/_01-foot." . $patternExtension; self::$patternHead = file_exists($patternHeadPath) ? file_get_contents($patternHeadPath) : ""; self::$patternFoot = file_exists($patternFootPath) ? file_get_contents($patternFootPath) : ""; // add the filesystemLoader $patternEngineBasePath = PatternEngine::getInstance()->getBasePath(); $filesystemLoaderClass = $patternEngineBasePath . "\\Loaders\\FilesystemLoader"; $options = array(); $options["templatePath"] = $pluginDir . "/" . $styleguideKit . "/views"; $options["partialsPath"] = $pluginDir . "/" . $styleguideKit . "/views/partials"; self::$filesystemLoader = new $filesystemLoaderClass($options); $stringLoaderClass = $patternEngineBasePath . "\\Loaders\\StringLoader"; self::$stringLoader = new $stringLoaderClass(); // i can't remember why i chose to implement the pattern loader directly in classes // i figure i had a good reason which is why it's not showing up here }
/** * Write out the time tracking file so the content sync service will work. A holdover * from how I put together the original AJAX polling set-up. */ public static function updateChangeTime() { if (is_dir(Config::getOption("publicDir"))) { file_put_contents(Config::getOption("publicDir") . "/latest-change.txt", time()); } else { Console::writeError("the public directory for Pattern Lab doesn't exist..."); } }
public function run() { if (Console::findCommandOption("list")) { // get all of the options $options = Config::getOptions(); // sort 'em alphabetically ksort($options); // find length of longest option $lengthLong = 0; foreach ($options as $optionName => $optionValue) { $lengthLong = strlen($optionName) > $lengthLong ? strlen($optionName) : $lengthLong; } // iterate over each option and spit it out foreach ($options as $optionName => $optionValue) { $optionValue = is_array($optionValue) ? implode(", ", $optionValue) : $optionValue; $optionValue = !$optionValue ? "false" : $optionValue; $spacer = Console::getSpacer($lengthLong, strlen($optionName)); Console::writeLine("<info>" . $optionName . ":</info>" . $spacer . $optionValue); } } else { if (Console::findCommandOption("get")) { // figure out which optino was passed $searchOption = Console::findCommandOptionValue("get"); $optionValue = Config::getOption($searchOption); // write it out if (!$optionValue) { Console::writeError("the --get value you provided, <info>" . $searchOption . "</info>, does not exists in the config..."); } else { $optionValue = is_array($optionValue) ? implode(", ", $optionValue) : $optionValue; $optionValue = !$optionValue ? "false" : $optionValue; Console::writeInfo($searchOption . ": <ok>" . $optionValue . "</ok>"); } } else { if (Console::findCommandOption("set")) { // find the value that was passed $updateOption = Console::findCommandOptionValue("set"); $updateOptionBits = explode("=", $updateOption); if (count($updateOptionBits) == 1) { Console::writeError("the --set value should look like <info>optionName=\"optionValue\"</info>. nothing was updated..."); } // set the name and value that were passed $updateName = $updateOptionBits[0]; $updateValue = $updateOptionBits[1][0] == "\"" || $updateOptionBits[1][0] == "'" ? substr($updateOptionBits[1], 1, strlen($updateOptionBits[1]) - 1) : $updateOptionBits[1]; // make sure the option being updated already exists $currentValue = Config::getOption($updateName); if (!$currentValue) { Console::writeError("the --set option you provided, <info>" . $updateName . "</info>, does not exists in the config. nothing will be updated..."); } else { Config::updateConfigOption($updateName, $updateValue); } } else { // no acceptable options were passed so write out the help Console::writeHelpCommand($this->command); } } } }
/** * Pulls together a bunch of functions from builder.lib.php in an order that makes sense * @param {Boolean} decide if CSS should be parsed and saved. performance hog. * @param {Boolean} decide if static files like CSS and JS should be moved */ public function generate($options = array()) { // double-checks options was properly set if (empty($options)) { Console::writeError("need to pass options to generate..."); } // set the default vars $moveStatic = isset($options["moveStatic"]) ? $options["moveStatic"] : true; $noCacheBuster = isset($options["noCacheBuster"]) ? $options["noCacheBuster"] : false; $exportFiles = isset($options["exportFiles"]) ? $options["exportFiles"] : false; $exportClean = isset($options["exportClean"]) ? $options["exportClean"] : false; $watchMessage = isset($options["watchMessage"]) ? $options["watchMessage"] : false; $watchVerbose = isset($options["watchVerbose"]) ? $options["watchVerbose"] : false; $update = isset($options["update"]) ? $options["update"] : false; Config::setOption("update", $update); if ($noCacheBuster) { Config::updateOption("cacheBuster", 0); } FileChangeList::init(Config::getOption("publicDir") . DIRECTORY_SEPARATOR . "fileChangeList.csv"); // gather up all of the data to be used in patterns Data::gather(); // gather all of the various pattern info $options = array(); $options["exportClean"] = $exportClean; $options["exportFiles"] = $exportFiles; PatternData::gather($options); // gather the annotations Annotations::gather(); // clean the public directory to remove old files if (Config::getOption("cleanPublic") == "true" && $moveStatic) { FileUtil::cleanPublic(); } // render out the index and style guide $this->generateIndex(); $this->generateStyleguide(); $this->generateViewAllPages(); // render out the patterns and move them to public/patterns $options = array(); $options["exportFiles"] = $exportFiles; $this->generatePatterns($options); // render the annotations as a js file $this->generateAnnotations(); // move all of the files unless pattern only is set if ($moveStatic) { $this->moveStatic(); } // update the change time so the auto-reload will fire (doesn't work for the index and style guide) Util::updateChangeTime(); FileChangeList::write(); if ($watchVerbose && $watchMessage) { Console::writeLine($watchMessage); } else { Console::writeLine("your site has been generated..."); Timer::stop(); } }
/** * Make a directory * @param {String} directory to be made */ public static function makeDir($dir) { $fs = new Filesystem(); try { $fs->mkdir($dir); } catch (IOExceptionInterface $e) { Console::writeError("an error occurred while creating your directory at <path>" . $e->getPath() . "</path>..."); } unset($fs); }
/** * Returns the last error message when building a JSON file. Mimics json_last_error_msg() from PHP 5.5 * @param {String} the file that generated the error */ public static function lastErrorMsg($file, $message, $data) { Console::writeLine(PHP_EOL . "<error>The JSON file, " . $file . ", wasn't loaded. The error: " . $message . "</error>"); if ($message == "Syntax error, malformed JSON") { Console::writeLine(""); $parser = new JsonLint\JsonParser(); $error = $parser->lint($data); Console::writeError($error->getMessage(), false, true); } }
/** * Spawn the passed commands and those collected from plugins * @param {Array} a list of commands to spawn * @param {Boolean} if this should be run in quiet mode */ public function spawn($commands = array(), $quiet = false) { // set-up a default $processes = array(); // add the default processes sent to the spawner if (!empty($commands)) { foreach ($commands as $command) { $processes[] = $this->buildProcess($command); } } // add the processes sent to the spawner from plugins foreach ($this->pluginProcesses as $pluginProcess) { $processes[] = $this->buildProcess($pluginProcess); } // if there are processes to spawn do so if (!empty($processes)) { // start the processes foreach ($processes as $process) { $process["process"]->start(); } // check on them and produce output while (true) { foreach ($processes as $process) { try { if ($process["process"]->isRunning()) { $process["process"]->checkTimeout(); if (!$quiet && $process["output"]) { print $process["process"]->getIncrementalOutput(); $cmd = $process["process"]->getCommandLine(); if (strpos($cmd, "router.php") != strlen($cmd) - 10) { print $process["process"]->getIncrementalErrorOutput(); } } } } catch (ProcessTimedOutException $e) { if ($e->isGeneralTimeout()) { Console::writeError("pattern lab processes should never time out. yours did..."); } else { if ($e->isIdleTimeout()) { Console::writeError("pattern lab processes automatically time out if their is no command line output in 30 minutes..."); } } } } usleep(100000); } } }
/** * Load all of the rules related to Pattern Engines. They're located in the plugin dir */ public static function loadRules() { // default var $configDir = Config::getOption("configDir"); // make sure the pattern engine data exists if (file_exists($configDir . "/patternengines.json")) { // get pattern engine list data $patternEngineList = json_decode(file_get_contents($configDir . "/patternengines.json"), true); // get the pattern engine info foreach ($patternEngineList["patternengines"] as $patternEngineName) { self::$rules[] = new $patternEngineName(); } } else { Console::writeError("The pattern engines list isn't available in <path>" . $configDir . "</path>..."); } }
/** * Load all of the rules related to Pattern Engines. They're located in the plugin dir */ public static function loadRules() { // default var $packagesDir = Config::getOption("packagesDir"); // see if the package dir exists. if it doesn't it means composer hasn't been run if (!is_dir($packagesDir)) { Console::writeError("you haven't fully set-up Pattern Lab yet. please add a pattern engine..."); } // make sure the pattern engine data exists if (file_exists($packagesDir . "/patternengines.json")) { // get pattern engine list data $patternEngineList = json_decode(file_get_contents($packagesDir . "/patternengines.json"), true); // get the pattern engine info foreach ($patternEngineList["patternengines"] as $patternEngineName) { self::$rules[] = new $patternEngineName(); } } else { Console::writeError("The pattern engines list isn't available in <path>" . $packagesDir . "</path>..."); } }
/** * Set-up default vars */ public static function init() { // make sure config vars exist if (!Config::getOption("patternExtension")) { Console::writeError("the pattern extension config option needs to be set..."); } if (!Config::getOption("styleguideKit")) { Console::writeError("the styleguideKit config option needs to be set..."); } // set-up config vars $patternExtension = Config::getOption("patternExtension"); $metaDir = Config::getOption("metaDir"); $styleguideKit = Config::getOption("styleguideKit"); $styleguideKitPath = Config::getOption("styleguideKitPath"); if (!$styleguideKitPath || !is_dir($styleguideKitPath)) { Console::writeError("your styleguide won't render because i can't find your styleguide files. are you sure they're at <path>" . Console::getHumanReadablePath($styleguideKitPath) . "</path>? you can fix this in <path>./config/config.yml</path> by editing styleguideKitPath..."); } // load pattern-lab's resources $partialPath = $styleguideKitPath . DIRECTORY_SEPARATOR . "views" . DIRECTORY_SEPARATOR . "partials"; $generalHeaderPath = $partialPath . DIRECTORY_SEPARATOR . "general-header." . $patternExtension; $generalFooterPath = $partialPath . DIRECTORY_SEPARATOR . "general-footer." . $patternExtension; self::$htmlHead = file_exists($generalHeaderPath) ? file_get_contents($generalHeaderPath) : ""; self::$htmlFoot = file_exists($generalFooterPath) ? file_get_contents($generalFooterPath) : ""; // gather the user-defined header and footer information $patternHeadPath = $metaDir . DIRECTORY_SEPARATOR . "_00-head." . $patternExtension; $patternFootPath = $metaDir . DIRECTORY_SEPARATOR . "_01-foot." . $patternExtension; self::$patternHead = file_exists($patternHeadPath) ? file_get_contents($patternHeadPath) : ""; self::$patternFoot = file_exists($patternFootPath) ? file_get_contents($patternFootPath) : ""; // add the filesystemLoader $patternEngineBasePath = PatternEngine::getInstance()->getBasePath(); $filesystemLoaderClass = $patternEngineBasePath . "\\Loaders\\FilesystemLoader"; $options = array(); $options["templatePath"] = $styleguideKitPath . DIRECTORY_SEPARATOR . "views"; $options["partialsPath"] = $options["templatePath"] . DIRECTORY_SEPARATOR . "partials"; self::$filesystemLoader = new $filesystemLoaderClass($options); $stringLoaderClass = $patternEngineBasePath . "\\Loaders\\StringLoader"; self::$stringLoader = new $stringLoaderClass(); // i can't remember why i chose to implement the pattern loader directly in classes // i figure i had a good reason which is why it's not showing up here }
public function run() { // find the value given to the command $package = Console::findCommandOptionValue("p|package"); if ($package) { // if <prompt> was passed ask the user for the package name if ($package == "prompt") { $prompt = "what is the name of the package you want to fetch?"; $options = "(ex. pattern-lab/plugin-kss)"; $package = Console::promptInput($prompt, $options); } // make sure it looks like a valid package if (strpos($package, "/") === false) { Console::writeError("that wasn't a valid package name. it should look like <info>pattern-lab/plugin-kss</info>..."); } // run composer via fetch $f = new Fetch(); $f->fetchPackage($package); } else { Console::writeHelpCommand($this->command); } }
public function run() { // load default vars $patternExtension = Config::getOption("patternExtension"); $patternSourceDir = Config::getOption("patternSourceDir"); // load the pattern data $store = PatternData::get(); // iterate to get raw data loaded into the PatternData Store foreach ($store as $patternStoreKey => $patternStoreData) { if ($patternStoreData["category"] == "pattern" && !$patternStoreData["hidden"]) { // figure out the source path for the pattern to render $srcPath = isset($patternStoreData["pseudo"]) ? PatternData::getPatternOption($patternStoreData["original"], "pathName") : $patternStoreData["pathName"]; // load the raw data so it can be modified/rendered $path = $patternSourceDir . "/" . $srcPath . "." . $patternExtension; if (file_exists($path)) { PatternData::setPatternOption($patternStoreKey, "patternRaw", file_get_contents($path)); } else { Console::writeError($patternStoreData["partial"] . " wasn't found for loading. the given path: " . $path); } } } }
/** * Stop the timer */ public static function stop() { // make sure start time is set if (empty(self::$startTime)) { Console::writeError("the timer wasn't started..."); } // get the current time $endTime = self::getTime(); // get the data for the output $totalTime = $endTime - self::$startTime; $mem = round(memory_get_peak_usage(true) / 1024 / 1024, 2); // figure out what tag to show $timeTag = "info"; if ($totalTime > 0.5) { $timeTag = "error"; } else { if ($totalTime > 0.3) { $timeTag = "warning"; } } // write out time/mem stats Console::writeLine("site generation took <" . $timeTag . ">" . $totalTime . "</" . $timeTag . "> seconds and used <info>" . $mem . "MB</info> of memory..."); }
/** * Break up the package path * @param {String} path of the GitHub repo * * @return {Array} the parts of the package path */ protected function getPackageInfo($package) { $org = ""; $repo = ""; $tag = "master"; if (strpos($package, "#") !== false) { list($package, $tag) = explode("#", $package); } if (strpos($package, "/") !== false) { list($org, $repo) = explode("/", $package); } else { Console::writeError("please provide a real path to a package..."); } return array($org, $repo, $tag); }
/** * Write out the new config option value * @param {String} the name of the option to be changed * @param {String} the new value of the option to be changed */ protected static function writeUpdateConfigOption($optionName, $optionValue) { // parse the YAML options try { $options = Yaml::parse(file_get_contents(self::$userConfigPath)); } catch (ParseException $e) { Console::writeError("Config parse error in <path>" . self::$userConfigPath . "</path>: " . $e->getMessage()); } if (isset($options[$optionName]) && is_array($options[$optionName])) { $optionValue = is_array($optionValue) ? $optionValue : array($optionValue); $options[$optionName] = array_merge($options[$optionName], $optionValue); } else { $options[$optionName] = $optionValue; } // dump the YAML $configOutput = Yaml::dump($options, 3); // write out the new config file file_put_contents(self::$userConfigPath, $configOutput); }
/** * Write out the new config option value * @param {String} the name of the option to be changed * @param {String} the new value of the option to be changed */ protected static function writeUpdateConfigOption($optionName, $optionValue) { // parse the YAML options try { $options = Yaml::parse(file_get_contents(self::$userConfigPath)); } catch (ParseException $e) { Console::writeError("Config parse error in <path>" . self::$userConfigPath . "</path>: " . $e->getMessage()); } // set this option for the current running of the app self::setOption($optionName, $optionValue); // modify the yaml file results $arrayFinder = new ArrayFinder($options); $arrayFinder->set($optionName, $optionValue); $options = $arrayFinder->get(); // dump the YAML $configOutput = Yaml::dump($options, 3); // write out the new config file file_put_contents(self::$userConfigPath, $configOutput); }
protected function starterKitSuggestions() { Console::writeLine(""); $composerPath = Config::getOption("baseDir") . "/composer.json"; if (file_exists($composerPath)) { $json = file_get_contents($composerPath); $data = json_decode($json, true); if ($jsonErrorMessage = JSON::hasError()) { JSON::lastErrorMsg(Console::getHumanReadablePath($oldStyleAnnotationsPath), $jsonErrorMessage, $data); } if (isset($data["extra"]) && isset($data["extra"]["patternlab"]) && isset($data["extra"]["patternlab"]["starterKitSuggestions"])) { $starterKitSuggestions = $data["extra"]["patternlab"]["starterKitSuggestions"]; Console::writeInfo("suggested starterkits that work with this edition:", false, true); foreach ($starterKitSuggestions as $i => $suggestion) { $num = $i + 1; Console::writeLine($num . ": " . $suggestion, true); } // hack around installer util feature in Console::promptInput InstallerUtil::$isInteractive = true; // prompt for input on the suggestions Console::writeLine(""); $prompt = "choose an option or hit return to cancel:"; $options = "(ex. 1)"; $input = Console::promptInput($prompt, $options, "1"); $result = (int) $input - 1; if (isset($starterKitSuggestions[$result])) { Console::writeLine(""); $f = new Fetch(); $result = $f->fetchStarterKit($starterKitSuggestions[$result]); } } else { Console::writeWarning("this edition has no starterkits to suggested...", false, true); } } else { Console::writeError("can't find composer.json to get suggestions...", false, true); } }
/** * Watch the source/ directory for any changes to existing files. Will run forever if given the chance. * @param {Boolean} decide if the reload server should be turned on * @param {Boolean} decide if static files like CSS and JS should be moved */ public function watch($options = array()) { // double-checks options was properly set if (empty($options)) { Console::writeError("need to pass options to generate..."); } // set default attributes $moveStatic = isset($options["moveStatic"]) ? $options["moveStatic"] : true; $noCacheBuster = isset($options["noCacheBuster"]) ? $options["noCacheBuster"] : false; // make sure a copy of the given options are saved for using when running generate $this->options = $options; // set-up the Dispatcher $dispatcherInstance = Dispatcher::getInstance(); $dispatcherInstance->dispatch("watcher.start"); if ($noCacheBuster) { Config::setOption("cacheBuster", 0); } $c = false; // track that one loop through the pattern file listing has completed $o = new \stdClass(); // create an object to hold the properties $cp = new \stdClass(); // create an object to hold a clone of $o $o->patterns = new \stdClass(); Console::writeLine("watching your site for changes..."); // default vars $publicDir = Config::getOption("publicDir"); $sourceDir = Config::getOption("sourceDir"); $patternSourceDir = Config::getOption("patternSourceDir"); $ignoreExts = Config::getOption("ie"); $ignoreDirs = Config::getOption("id"); $patternExt = Config::getOption("patternExtension"); // build the file extensions based on the rules $fileExtensions = array(); $patternRules = PatternData::getRules(); foreach ($patternRules as $patternRule) { $extensions = $patternRule->getProp("extProp"); if (strpos($extensions, "&&") !== false) { $extensions = explode("&&", $extensions); } else { if (strpos($extensions, "||") !== false) { $extensions = explode("||", $extensions); } else { $extensions = array($extensions); } } foreach ($extensions as $extension) { if (!in_array($extension, $fileExtensions)) { $fileExtensions[] = $extension; } } } // run forever while (true) { // clone the patterns so they can be checked in case something gets deleted $cp = clone $o->patterns; // iterate over the patterns & related data and regenerate the entire site if they've changed $patternObjects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($patternSourceDir), \RecursiveIteratorIterator::SELF_FIRST); // make sure dots are skipped $patternObjects->setFlags(\FilesystemIterator::SKIP_DOTS); foreach ($patternObjects as $name => $object) { // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored $fileName = str_replace($patternSourceDir . DIRECTORY_SEPARATOR, "", $name); $fileNameClean = str_replace(DIRECTORY_SEPARATOR . "_", DIRECTORY_SEPARATOR, $fileName); if ($object->isFile() && in_array($object->getExtension(), $fileExtensions)) { // make sure this isn't a hidden pattern $patternParts = explode(DIRECTORY_SEPARATOR, $fileName); $pattern = isset($patternParts[2]) ? $patternParts[2] : $patternParts[1]; // make sure the pattern still exists in source just in case it's been deleted during the iteration if (file_exists($name)) { $mt = $object->getMTime(); if (isset($o->patterns->{$fileName}) && $o->patterns->{$fileName} != $mt) { $o->patterns->{$fileName} = $mt; $this->updateSite($fileName, "changed"); } else { if (!isset($o->patterns->{$fileName}) && $c) { $o->patterns->{$fileName} = $mt; $this->updateSite($fileName, "added"); if ($object->getExtension() == $patternExt) { $patternSrcPath = str_replace("." . $patternExt, "", $fileName); $patternDestPath = str_replace("/", "-", $patternSrcPath); $render = $pattern[0] != "_" ? true : false; $this->patternPaths[$patternParts[0]][$pattern] = array("patternSrcPath" => $patternSrcPath, "patternDestPath" => $patternDestPath, "render" => $render); } } else { if (!isset($o->patterns->{$fileName})) { $o->patterns->{$fileName} = $mt; } } } if ($c && isset($o->patterns->{$fileName})) { unset($cp->{$fileName}); } } else { // the file was removed during the iteration so remove references to the item unset($o->patterns->{$fileName}); unset($cp->{$fileName}); unset($this->patternPaths[$patternParts[0]][$pattern]); $this->updateSite($fileName, "removed"); } } } // make sure old entries are deleted // will throw "pattern not found" errors if an entire directory is removed at once but that shouldn't be a big deal if ($c) { foreach ($cp as $fileName => $mt) { unset($o->patterns->{$fileName}); $patternParts = explode(DIRECTORY_SEPARATOR, $fileName); $pattern = isset($patternParts[2]) ? $patternParts[2] : $patternParts[1]; unset($this->patternPaths[$patternParts[0]][$pattern]); $this->updateSite($fileName, "removed"); } } // iterate over annotations, data, meta and any other _ dirs $watchDirs = glob($sourceDir . DIRECTORY_SEPARATOR . "_*", GLOB_ONLYDIR); foreach ($watchDirs as $watchDir) { if ($watchDir != $patternSourceDir) { // iterate over the data files and regenerate the entire site if they've changed $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($watchDir), \RecursiveIteratorIterator::SELF_FIRST); // make sure dots are skipped $objects->setFlags(\FilesystemIterator::SKIP_DOTS); foreach ($objects as $name => $object) { $fileName = str_replace($sourceDir . DIRECTORY_SEPARATOR, "", $name); $mt = $object->getMTime(); if (!isset($o->{$fileName})) { $o->{$fileName} = $mt; if ($c) { $this->updateSite($fileName, "added"); } } else { if ($o->{$fileName} != $mt) { $o->{$fileName} = $mt; if ($c) { $this->updateSite($fileName, "changed"); } } } } } } // iterate over all of the other files in the source directory and move them if their modified time has changed if ($moveStatic) { $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($sourceDir . DIRECTORY_SEPARATOR), \RecursiveIteratorIterator::SELF_FIRST); // make sure dots are skipped $objects->setFlags(\FilesystemIterator::SKIP_DOTS); foreach ($objects as $name => $object) { // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored $fileName = str_replace($sourceDir . DIRECTORY_SEPARATOR, "", $name); if ($fileName[0] != "_" && !in_array($object->getExtension(), $ignoreExts) && !in_array($object->getFilename(), $ignoreDirs)) { // catch directories that have the ignored dir in their path $ignoreDir = FileUtil::ignoreDir($fileName); // check to see if it's a new directory if (!$ignoreDir && $object->isDir() && !isset($o->{$fileName}) && !is_dir($publicDir . "/" . $fileName)) { mkdir($publicDir . "/" . $fileName); $o->{$fileName} = "dir created"; // placeholder Console::writeLine($fileName . "/ directory was created..."); } // check to see if it's a new file or a file that has changed if (file_exists($name)) { $mt = $object->getMTime(); if (!$ignoreDir && $object->isFile() && !isset($o->{$fileName}) && !file_exists($publicDir . "/" . $fileName)) { $o->{$fileName} = $mt; FileUtil::moveStaticFile($fileName, "added"); if ($object->getExtension() == "css") { $this->updateSite($fileName, "changed", 0); // make sure the site is updated for MQ reasons } } else { if (!$ignoreDir && $object->isFile() && isset($o->{$fileName}) && $o->{$fileName} != $mt) { $o->{$fileName} = $mt; FileUtil::moveStaticFile($fileName, "changed"); if ($object->getExtension() == "css") { $this->updateSite($fileName, "changed", 0); // make sure the site is updated for MQ reasons } } else { if (!isset($o->fileName)) { $o->{$fileName} = $mt; } } } } else { unset($o->{$fileName}); } } } } $c = true; // taking out the garbage. basically killing mustache after each run. if (gc_enabled()) { gc_collect_cycles(); } // pause for .05 seconds to give the CPU a rest usleep(50000); } }
/** * Set the given option to the given value */ protected function setOption() { // find the value that was passed $updateOption = Console::findCommandOptionValue("set"); $updateOptionBits = explode("=", $updateOption); if (count($updateOptionBits) == 1) { Console::writeError("the --set value should look like <info>optionName=\"optionValue\"</info>. nothing was updated..."); } // set the name and value that were passed $updateName = $updateOptionBits[0]; $updateValue = $updateOptionBits[1][0] == "\"" || $updateOptionBits[1][0] == "'" ? substr($updateOptionBits[1], 1, strlen($updateOptionBits[1]) - 1) : $updateOptionBits[1]; // make sure the option being updated already exists $currentValue = Config::getOption($updateName); if (!$currentValue) { Console::writeError("the --set option you provided, <info>" . $updateName . "</info>, does not exists in the config. nothing will be updated..."); } else { Config::updateConfigOption($updateName, $updateValue); Console::writeInfo("config option updated..."); } }
public function watchStarterKit() { // double-checks options was properly set $starterKit = Config::getOption("starterKit"); if (!$starterKit) { Console::writeError("need to have a starterkit set in the config..."); } // set-up the full starterkit path $starterKitPath = Config::getOption("packagesDir") . DIRECTORY_SEPARATOR . $starterKit . DIRECTORY_SEPARATOR . "dist"; if (!is_dir($starterKitPath)) { Console::writeError("the starterkit doesn't seem to exist..."); } // default vars $sourceDir = Config::getOption("sourceDir"); $packagesDir = Config::getOption("packagesDir"); $fs = new Filesystem(); $c = false; // track that one loop through the pattern file listing has completed $o = new \stdClass(); // create an object to hold the properties $cp = new \stdClass(); // create an object to hold a clone of $o $o->patterns = new \stdClass(); Console::writeLine("watching your starterkit for changes..."); // run forever while (true) { // clone the patterns so they can be checked in case something gets deleted $cp = clone $o->patterns; $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($starterKitPath), \RecursiveIteratorIterator::SELF_FIRST); // make sure dots are skipped $objects->setFlags(\FilesystemIterator::SKIP_DOTS); foreach ($objects as $name => $object) { // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored $fileName = str_replace($starterKitPath . DIRECTORY_SEPARATOR, "", $name); // check to see if it's a new directory if ($object->isDir() && !isset($o->{$fileName}) && !is_dir($starterKitPath . "/" . $fileName)) { mkdir($sourceDir . "/" . $fileName); $o->{$fileName} = "dir created"; // placeholder Console::writeLine($fileName . "/ directory was created..."); } // check to see if it's a new file or a file that has changed if (file_exists($name)) { $mt = $object->getMTime(); if ($object->isFile() && !isset($o->{$fileName}) && !file_exists($sourceDir . DIRECTORY_SEPARATOR . $fileName)) { $o->{$fileName} = $mt; $fs->copy($starterKitPath . DIRECTORY_SEPARATOR . $fileName, $sourceDir . DIRECTORY_SEPARATOR . $fileName); Console::writeInfo($fileName . " added..."); } else { if ($object->isFile() && isset($o->{$fileName}) && $o->{$fileName} != $mt) { $o->{$fileName} = $mt; $fs->copy($starterKitPath . DIRECTORY_SEPARATOR . $fileName, $sourceDir . DIRECTORY_SEPARATOR . $fileName); Console::writeInfo($fileName . " changed..."); } else { if (!isset($o->fileName)) { $o->{$fileName} = $mt; } } } } else { unset($o->{$fileName}); } } $c = true; // taking out the garbage. basically killing mustache after each run. if (gc_enabled()) { gc_collect_cycles(); } // pause for .05 seconds to give the CPU a rest usleep(50000); } }
/** * Gather all of the information related to the patterns */ public static function gather($options = array()) { // set default vars $exportClean = isset($options["exportClean"]) ? $options["exportClean"] : false; $exportFiles = isset($options["exportClean"]) ? $options["exportFiles"] : false; $dispatcherInstance = Dispatcher::getInstance(); // cleaning the var for use below, i know this is stupid $options = array(); // dispatch that the data gather has started $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.gatherStart", $event); // load up the rules for parsing patterns and the directories self::loadRules($options); // dispatch that the rules are loaded $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.rulesLoaded", $event); // iterate over the patterns & related data and regenerate the entire site if they've changed // seems a little silly to use symfony finder here. not really giving me any power if (!is_dir(Config::getOption("patternSourceDir"))) { Console::writeError("having patterns is important. please make sure you've installed a starterkit and/or that " . Console::getHumanReadablePath(Config::getOption("patternSourceDir")) . " exists..."); } $patternObjects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(Config::getOption("patternSourceDir")), \RecursiveIteratorIterator::SELF_FIRST); $patternObjects->setFlags(\FilesystemIterator::SKIP_DOTS); // sort the returned objects $patternObjects = iterator_to_array($patternObjects); ksort($patternObjects); $patternSourceDir = Config::getOption("patternSourceDir"); foreach ($patternObjects as $name => $object) { $ext = $object->getExtension(); $isDir = $object->isDir(); $isFile = $object->isFile(); $path = str_replace($patternSourceDir . DIRECTORY_SEPARATOR, "", $object->getPath()); $pathName = str_replace($patternSourceDir . DIRECTORY_SEPARATOR, "", $object->getPathname()); $name = $object->getFilename(); $depth = substr_count($pathName, DIRECTORY_SEPARATOR); // iterate over the rules and see if the current file matches one, if so run the rule foreach (self::$rules as $rule) { if ($rule->test($depth, $ext, $isDir, $isFile, $name)) { $rule->run($depth, $ext, $path, $pathName, $name); } } } // dispatch that the data is loaded $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.dataLoaded", $event); // make sure all of the appropriate pattern data is pumped into $this->d for rendering patterns $dataLinkExporter = new DataLinkExporter(); $dataLinkExporter->run(); // make sure all of the appropriate pattern data is pumped into $this->d for rendering patterns $dataMergeExporter = new DataMergeExporter(); $dataMergeExporter->run(); // dispatch that the raw pattern helper is about to start $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.rawPatternHelperStart", $event); // add the lineage info to PatternData::$store $rawPatternHelper = new RawPatternHelper(); $rawPatternHelper->run(); // dispatch that the raw pattern helper is ended $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.rawPatternHelperEnd", $event); // dispatch that the lineage helper is about to start $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.lineageHelperStart", $event); // add the lineage info to PatternData::$store $lineageHelper = new LineageHelper(); $lineageHelper->run(); // dispatch that the lineage helper is ended $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.lineageHelperEnd", $event); // dispatch that the pattern state helper is about to start $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.patternStateHelperStart", $event); // using the lineage info update the pattern states on PatternData::$store $patternStateHelper = new PatternStateHelper(); $patternStateHelper->run(); // dispatch that the pattern state helper is ended $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.patternStateHelperEnd", $event); // set-up code pattern paths $ppdExporter = new PatternPathSrcExporter(); $patternPathSrc = $ppdExporter->run(); $options = array(); $options["patternPaths"] = $patternPathSrc; // dispatch that the code helper is about to start $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.codeHelperStart", $event); // render out all of the patterns and store the generated info in PatternData::$store $options["exportFiles"] = $exportFiles; $options["exportClean"] = $exportClean; $patternCodeHelper = new PatternCodeHelper($options); $patternCodeHelper->run(); // dispatch that the pattern code helper is ended $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.patternCodeHelperEnd", $event); // dispatch that the gather has ended $event = new PatternDataEvent($options); $dispatcherInstance->dispatch("patternData.gatherEnd", $event); }
/** * Generates the data that powers the index page */ protected function generateIndex() { // bomb if missing index.html if (!file_exists(Config::getOption("publicDir") . "/index.html")) { $index = Console::getHumanReadablePath(Config::getOption("publicDir")) . DIRECTORY_SEPARATOR . "index.html"; Console::writeError("<path>" . $index . "</path> is missing. grab a copy from your StyleguideKit..."); } // set-up the dispatcher $dispatcherInstance = Dispatcher::getInstance(); // note the start of the operation $dispatcherInstance->dispatch("builder.generateIndexStart"); // default var $dataDir = Config::getOption("publicDir") . "/styleguide/data"; // double-check that the data directory exists if (!is_dir($dataDir)) { FileUtil::makeDir($dataDir); } $output = ""; // load and write out the config options $config = array(); $exposedOptions = Config::getOption("exposedOptions"); foreach ($exposedOptions as $exposedOption) { $config[$exposedOption] = Config::getOption($exposedOption); } $output .= "var config = " . json_encode($config) . ";\n"; // load the ish Controls $ishControls = array(); $controlsToHide = array(); $ishControlsHide = Config::getOption("ishControlsHide"); if ($ishControlsHide) { foreach ($ishControlsHide as $controlToHide) { $controlsToHide[$controlToHide] = "true"; } } $ishControls["ishControlsHide"] = $controlsToHide; $output .= "var ishControls = " . json_encode($ishControls) . ";\n"; // load and write out the items for the navigation $niExporter = new NavItemsExporter(); $navItems = $niExporter->run(); $output .= "var navItems = " . json_encode($navItems) . ";\n"; // load and write out the items for the pattern paths $patternPaths = array(); $ppdExporter = new PatternPathDestsExporter(); $patternPaths = $ppdExporter->run(); $output .= "var patternPaths = " . json_encode($patternPaths) . ";\n"; // load and write out the items for the view all paths $viewAllPaths = array(); $vapExporter = new ViewAllPathsExporter(); $viewAllPaths = $vapExporter->run($navItems); $output .= "var viewAllPaths = " . json_encode($viewAllPaths) . ";\n"; // gather plugin package information $packagesInfo = array(); $componentDir = Config::getOption("componentDir"); if (!is_dir($componentDir)) { mkdir($componentDir); } $componentPackagesDir = $componentDir . "/packages"; if (!is_dir($componentDir . "/packages")) { mkdir($componentDir . "/packages"); } $finder = new Finder(); $finder->files()->name("*.json")->in($componentPackagesDir); $finder->sortByName(); foreach ($finder as $file) { $filename = $file->getFilename(); if ($filename[0] != "_") { $javascriptPaths = array(); $packageInfo = json_decode(file_get_contents($file->getPathname()), true); foreach ($packageInfo["templates"] as $templateKey => $templatePath) { $templatePathFull = $componentDir . "/" . $packageInfo["name"] . "/" . $templatePath; $packageInfo["templates"][$templateKey] = file_exists($templatePathFull) ? file_get_contents($templatePathFull) : ""; } foreach ($packageInfo["javascripts"] as $key => $javascriptPath) { $javascriptPaths[] = "patternlab-components/" . $packageInfo["name"] . "/" . $javascriptPath; } $packageInfo["javascripts"] = $javascriptPaths; $packagesInfo[] = $packageInfo; } } $output .= "var plugins = " . json_encode($packagesInfo) . ";"; // write out the data file_put_contents($dataDir . "/patternlab-data.js", $output); // note the end of the operation $dispatcherInstance->dispatch("builder.generateIndexEnd"); }
/** * Prompt the user for some input * @param {String} the text for the prompt * @param {String} the text for the options * @param {Boolean} if we should lowercase the input before sending it back * @param {String} the tag that should be used when drawing the content * * @return {String} trimmed input given by the user */ public static function promptInput($prompt = "", $options = "", $lowercase = true, $tag = "info") { // check prompt if (empty($prompt)) { Console::writeError("an input prompt requires prompt text..."); } // if there are suggested options add them if (!empty($options)) { $prompt .= " <options>" . $options . "</options> >"; } // make sure no end-of-line is added $prompt .= " <nophpeol>"; // open the terminal and wait for feedback $stdin = fopen("php://stdin", "r"); Console::writeTag($tag, $prompt); $input = trim(fgets($stdin)); fclose($stdin); // check to see if it should be lowercased before sending back return $lowercase ? strtolower($input) : $input; }