get($key); } return false; } /** * Get the options set in the config * * @return {Array} the options from the config */ public static function getOptions() { return self::$options; } /** * Review the given styleguideKitPath to handle pre-2.1.0 backwards compatibility * @param {String} styleguideKitPath from config.yml * * @return {String} the final, post-2.1.0-style styleguideKitPath */ protected static function getStyleguideKitPath($styleguideKitPath = "") { $styleguideKitPathFinal = ""; if (isset($styleguideKitPath[0]) && ($styleguideKitPath[0] == DIRECTORY_SEPARATOR)) { if (strpos($styleguideKitPath, DIRECTORY_SEPARATOR."vendor".DIRECTORY_SEPARATOR === 0)) { $styleguideKitPathFinal = $styleguideKitPath; // mistaken set-up, pass to final for clean-up } else if (strpos($styleguideKitPath, self::$options["baseDir"]) === 0) { $styleguideKitPathFinal = str_replace(self::$options["baseDir"], "", $styleguideKitPath); // just need to peel off the base } else if (strpos($styleguideKitPath, DIRECTORY_SEPARATOR."vendor") !== false) { $parts = explode(DIRECTORY_SEPARATOR."vendor".DIRECTORY_SEPARATOR, $styleguideKitPath); // set on another machine's config.yml? try to be smart about it $styleguideKitPathFinal = "vendor".DIRECTORY_SEPARATOR.$parts[1]; Console::writeInfo("Please double-check the styleguideKitPath option in ./config/config.yml. It should be a path relative to the root of your Pattern Lab project..."); } } else { $styleguideKitPathFinal = $styleguideKitPath; // fingers crossed everything is fine } return $styleguideKitPathFinal; } /** * Adds the config options to a var to be accessed from the rest of the system * If it's an old config or no config exists this will update and generate it. * @param {Boolean} whether we should print out the status of the config being loaded */ public static function init($baseDir = "", $verbose = true) { // make sure a base dir was supplied if (empty($baseDir)) { Console::writeError("need a base directory to initialize the config class..."); } // normalize the baseDir $baseDir = FileUtil::normalizePath($baseDir); // double-check the default config file exists if (!is_dir($baseDir)) { Console::writeError("make sure ".$baseDir." exists..."); } // set the baseDir option self::$options["baseDir"] = ($baseDir[strlen($baseDir)-1] == DIRECTORY_SEPARATOR) ? $baseDir : $baseDir.DIRECTORY_SEPARATOR; // set-up the paths self::$userConfigDirClean = self::$options["baseDir"].self::$userConfigDirClean; self::$userConfigDirDash = self::$options["baseDir"].self::$userConfigDirDash; self::$userConfigDir = (is_dir(self::$userConfigDirDash)) ? self::$userConfigDirDash : self::$userConfigDirClean; self::$userConfigPath = self::$userConfigDir.DIRECTORY_SEPARATOR.self::$userConfig; self::$plConfigPath = self::$options["baseDir"]."vendor/pattern-lab/core/".self::$plConfigPath; // can't add __DIR__ above so adding here if (!is_dir(self::$userConfigDir)) { mkdir(self::$userConfigDir); } // check to see if the user config exists, if not create it if ($verbose) { Console::writeLine("configuring pattern lab..."); } // make sure migrate doesn't happen by default $migrate = false; $diffVersion = false; $defaultOptions = array(); $userOptions = array(); // double-check the default config file exists if (!file_exists(self::$plConfigPath)) { Console::writeError("the default options for Pattern Lab don't seem to exist at ".Console::getHumanReadablePath(self::$plConfigPath).". please check on the install location of pattern lab..."); } // set the default config using the pattern lab config try { $defaultOptions = Yaml::parse(file_get_contents(self::$plConfigPath)); self::$options = array_merge(self::$options, $defaultOptions); } catch (ParseException $e) { Console::writeError("Config parse error in ".Console::getHumanReadablePath(self::$plConfigPath).": ".$e->getMessage()); } // double-check the user's config exists. if not mark that we should migrate the default one if (file_exists(self::$userConfigPath)) { try { $userOptions = Yaml::parse(file_get_contents(self::$userConfigPath)); self::$options = array_merge(self::$options, $userOptions); } catch (ParseException $e) { Console::writeError("Config parse error in ".Console::getHumanReadablePath(self::$userConfigPath).": ".$e->getMessage()); } } else { $migrate = true; } // compare version numbers $diffVersion = (isset($userOptions["v"]) && ($userOptions["v"] == $defaultOptions["v"])) ? false : true; // run an upgrade and migrations if necessary if ($migrate || $diffVersion) { if ($verbose) { Console::writeInfo("upgrading your version of pattern lab..."); } if ($migrate) { if (!@copy(self::$plConfigPath, self::$userConfigPath)) { Console::writeError("make sure that Pattern Lab can write a new config to ".self::$userConfigPath."..."); exit; } } else { self::$options = self::writeNewConfigFile(self::$options, $defaultOptions); } } // making sure the config isn't empty if (empty(self::$options) && $verbose) { Console::writeError("a set of configuration options is required to use Pattern Lab..."); exit; } // set-up the various dirs self::$options["configDir"] = self::$userConfigDir; self::$options["configPath"] = self::$userConfigPath; self::$options["coreDir"] = is_dir(self::$options["baseDir"]."_core") ? self::$options["baseDir"]."_core" : self::$options["baseDir"]."core"; self::$options["exportDir"] = isset(self::$options["exportDir"]) ? self::$options["baseDir"].self::cleanDir(self::$options["exportDir"]) : self::$options["baseDir"]."exports"; self::$options["publicDir"] = isset(self::$options["publicDir"]) ? self::$options["baseDir"].self::cleanDir(self::$options["publicDir"]) : self::$options["baseDir"]."public"; self::$options["scriptsDir"] = isset(self::$options["scriptsDir"]) ? self::$options["baseDir"].self::cleanDir(self::$options["scriptsDir"]) : self::$options["baseDir"]."scripts"; self::$options["sourceDir"] = isset(self::$options["sourceDir"]) ? self::$options["baseDir"].self::cleanDir(self::$options["sourceDir"]) : self::$options["baseDir"]."source"; self::$options["componentDir"] = isset(self::$options["componentDir"]) ? self::$options["publicDir"].DIRECTORY_SEPARATOR.self::cleanDir(self::$options["componentDir"]) : self::$options["publicDir"].DIRECTORY_SEPARATOR."patternlab-components"; self::$options["dataDir"] = isset(self::$options["dataDir"]) ? self::$options["sourceDir"].DIRECTORY_SEPARATOR.self::cleanDir(self::$options["dataDir"]) : self::$options["sourceDir"].DIRECTORY_SEPARATOR."_data"; self::$options["patternExportDir"] = isset(self::$options["patternExportDir"]) ? self::$options["exportDir"].DIRECTORY_SEPARATOR.self::cleanDir(self::$options["patternExportDir"]) : self::$options["exportDir"].DIRECTORY_SEPARATOR."patterns"; self::$options["patternPublicDir"] = isset(self::$options["patternPublicDir"]) ? self::$options["publicDir"].DIRECTORY_SEPARATOR.self::cleanDir(self::$options["patternPublicDir"]) : self::$options["publicDir"].DIRECTORY_SEPARATOR."patterns"; self::$options["patternSourceDir"] = isset(self::$options["patternSourceDir"]) ? self::$options["sourceDir"].DIRECTORY_SEPARATOR.self::cleanDir(self::$options["patternSourceDir"]) : self::$options["sourceDir"].DIRECTORY_SEPARATOR."_patterns"; self::$options["metaDir"] = isset(self::$options["metaDir"]) ? self::$options["sourceDir"].DIRECTORY_SEPARATOR.self::cleanDir(self::$options["metaDir"]) : self::$options["sourceDir"].DIRECTORY_SEPARATOR."_meta/"; self::$options["annotationsDir"] = isset(self::$options["annotationsDir"]) ? self::$options["sourceDir"].DIRECTORY_SEPARATOR.self::cleanDir(self::$options["annotationsDir"]) : self::$options["sourceDir"].DIRECTORY_SEPARATOR."_annotations/"; // set-up outputFileSuffixes self::$options["outputFileSuffixes"]["rendered"] = isset(self::$options["outputFileSuffixes"]["rendered"]) ? self::$options["outputFileSuffixes"]["rendered"] : ''; self::$options["outputFileSuffixes"]["rawTemplate"] = isset(self::$options["outputFileSuffixes"]["rawTemplate"]) ? self::$options["outputFileSuffixes"]["rawTemplate"] : ''; self::$options["outputFileSuffixes"]["markupOnly"] = isset(self::$options["outputFileSuffixes"]["markupOnly"]) ? self::$options["outputFileSuffixes"]["markupOnly"] : '.markup-only'; // handle a pre-2.1.0 styleguideKitPath before saving it if (isset(self::$options["styleguideKitPath"])) { self::$options["styleguideKitPath"] = self::$options["baseDir"].self::cleanDir(self::getStyleguideKitPath(self::$options["styleguideKitPath"])); } // double-check a few directories are real and set-up FileUtil::checkPathFromConfig(self::$options["sourceDir"], self::$userConfigPath, "sourceDir"); FileUtil::checkPathFromConfig(self::$options["publicDir"], self::$userConfigPath, "publicDir"); // make sure styleguideExcludes is set to an array even if it's empty if (is_string(self::$options["styleGuideExcludes"])) { self::$options["styleGuideExcludes"] = array(); } // set the cacheBuster self::$options["cacheBuster"] = (self::$options["cacheBusterOn"] == "false") ? 0 : time(); // provide the default for enable CSS. performance hog so it should be run infrequently self::$options["enableCSS"] = false; // which of these should be exposed in the front-end? self::$options["exposedOptions"] = array(); self::setExposedOption("cacheBuster"); self::setExposedOption("defaultPattern"); self::setExposedOption("defaultShowPatternInfo"); self::setExposedOption("ishFontSize"); self::setExposedOption("ishMaximum"); self::setExposedOption("ishMinimum"); self::setExposedOption("outputFileSuffixes"); self::setExposedOption("plugins"); } /** * Check to see if the given array is an associative array * @param {Array} the array to be checked * * @return {Boolean} whether it's an associative array */ protected static function isAssoc($array) { return (bool) count(array_filter(array_keys($array), 'is_string')); } /** * Add an option and associated value to the base Config * @param {String} the name of the option to be added * @param {String} the value of the option to be added * * @return {Boolean} whether the set was successful */ public static function setOption($optionName = "", $optionValue = "") { if (empty($optionName) || empty($optionValue)) { return false; } $arrayFinder = new ArrayFinder(self::$options); $arrayFinder->set($optionName, $optionValue); self::$options = $arrayFinder->get(); } /** * Add an option to the exposedOptions array so it can be exposed on the front-end * @param {String} the name of the option to be added to the exposedOption arrays * * @return {Boolean} whether the set was successful */ public static function setExposedOption($optionName = "") { if (!empty($optionName) && isset(self::$options[$optionName])) { if (!in_array($optionName,self::$options["exposedOptions"])) { self::$options["exposedOptions"][] = $optionName; } return true; } return false; } /** * Update a single config option based on a change in composer.json * @param {String} the name of the option to be changed * @param {String} the new value of the option to be changed * @param {Boolean} whether to force the update of the option */ public static function updateConfigOption($optionName,$optionValue, $force = false) { if (is_string($optionValue) && strpos($optionValue,"") !== false) { // prompt for input using the supplied query $options = ""; $default = ""; $prompt = str_replace("","",str_replace("","",$optionValue)); if (strpos($prompt, "") !== false) { $default = explode("",$prompt); $default = explode("",$default[1]); $default = $default[0]; } $input = Console::promptInput($prompt,$options,$default,false); self::writeUpdateConfigOption($optionName,$input); Console::writeTag("ok","config option ".$optionName." updated...", false, true); } else if (!isset(self::$options[$optionName]) || (self::$options["overrideConfig"] == "a") || $force) { // if the option isn't set or the config is always to override update the config self::writeUpdateConfigOption($optionName,$optionValue); } else if (self::$options["overrideConfig"] == "q") { // standardize the values for comparison $currentOption = self::getOption($optionName); $currentOptionValue = $currentOption; $newOptionValue = $optionValue; $optionNameOutput = $optionName; // dive into plugins to do a proper comparison to if ($optionName == "plugins") { // replace the data in anticipation of it being used $optionValue = array_replace_recursive($currentOption, $newOptionValue); // get the key of the plugin that is being added/updated reset($newOptionValue); $newOptionKey = key($newOptionValue); if (!array_key_exists($newOptionKey, $currentOptionValue)) { // if the key doesn't exist just write out the new config and move on self::writeUpdateConfigOption($optionName,$optionValue); return; } else { // see if the existing configs for the plugin exists. if so just return with no changes if ($newOptionValue[$newOptionKey] == $currentOptionValue[$newOptionKey]) { return; } else { $optionNameOutput = $optionName.".".$newOptionKey; } } } if ($currentOptionValue != $newOptionValue) { // prompt for input if (is_array($currentOptionValue)) { $prompt = "update the config option ".$optionNameOutput." with the value from the package install?"; } else { $prompt = "update the config option ".$optionNameOutput." (".$currentOptionValue.") with the value ".$newOptionValue."?"; }$options = "Y/n"; $input = Console::promptInput($prompt,$options,"Y"); if ($input == "y") { // update the config option self::writeUpdateConfigOption($optionName,$optionValue); Console::writeInfo("config option ".$optionNameOutput." updated...", false, true); } else { Console::writeWarning("config option ".$optionNameOutput." not updated...", false, true); } } } } /** * Add an option and associated value to the base Config. BC wrap for setOption * @param {String} the name of the option to be added * @param {String} the value of the option to be added * * @return {Boolean} whether the set was successful */ public static function updateOption($optionName = "", $optionValue = "") { return self::setOption($optionName, $optionValue); } /** * 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 ".self::$userConfigPath.": ".$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); } /** * Use the default config as a base and update it with old config options. Write out a new user config. * @param {Array} the old configuration file options * @param {Array} the default configuration file options * * @return {Array} the new configuration */ protected static function writeNewConfigFile($oldOptions,$defaultOptions) { // iterate over the old config and replace values in the new config foreach ($oldOptions as $key => $value) { if ($key != "v") { $defaultOptions[$key] = $value; } } // dump the YAML $configOutput = Yaml::dump($defaultOptions, 3); // write out the new config file file_put_contents(self::$userConfigPath,$configOutput); return $defaultOptions; } }