/** * 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(); } }
/** * 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; // automatically start the auto-refresh tool // DEPRECATED /*if ($reload) { $path = str_replace("lib".DIRECTORY_SEPARATOR."PatternLab","autoReloadServer.php",__DIR__); $fp = popen("php ".$path." -s", "r"); Console::writeLine("starting page auto-reload..."); }*/ if ($noCacheBuster) { Config::updateOption("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"); $ignoreExts = Config::getOption("ie"); $ignoreDirs = Config::getOption("id"); $patternExt = Config::getOption("patternExtension"); // 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($sourceDir . "/_patterns/"), \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($sourceDir . "/_patterns" . DIRECTORY_SEPARATOR, "", $name); $fileNameClean = str_replace(DIRECTORY_SEPARATOR . "_", DIRECTORY_SEPARATOR, $fileName); if ($object->isFile() && ($object->getExtension() == $patternExt || $object->getExtension() == "json" || $object->getExtension() == "md")) { // 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 . "/_*", GLOB_ONLYDIR); foreach ($watchDirs as $watchDir) { if (str_replace($sourceDir . "/", "", $watchDir) != "_patterns") { // 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 . "/", "", $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 . "/"), \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(); } // output anything the reload server might send our way // DEPRECATED /* if ($reload) { $output = fgets($fp, 100); if ($output != "\n") print $output; } */ // pause for .05 seconds to give the CPU a rest usleep(50000); } // close the auto-reload process, this shouldn't do anything // DEPRECATED // fclose($fp); }