'drush_patterns_enable', 'description' => 'Enable the specified pattern name', 'examples' => array( 'drush patterns enable pattern_name' => 'Enable the named pattern' ), 'arguments' => array( 'pattern_name' => 'A pattern name', ), 'drupal dependencies' => array('patterns', 'token'), 'core' => array('6'), ); $items['patterns-import'] = array( 'callback' => 'drush_patterns_import', 'description' => 'Import the specified pattern file.', 'examples' => array( 'drush patterns import path/to/patterns/file.[xml/yaml]' => 'Import the specified pattern file.', 'drush patterns import path/to/pattern/file.[xml/yaml] pattern_name' => 'Import the specified pattern file and give it a machine readable name' ), 'arguments' => array( 'pattern_file' => 'The path to a pattern file, beginning from the Drupal base directory', 'pattern_name' => 'Enter a pattern name if you wish to override the title field entered in a pattern.' ), 'drupal dependencies' => array('patterns', 'token'), 'core' => array('6'), ); $items['patterns-run'] = array( 'callback' => 'drush_patterns_run', 'description' => 'Import and enable the specified pattern file', 'examples' => array( 'drush patterns run path/to/patterns/file.[xml/yaml]' => 'Import and enable the specified pattern file', 'drush patterns import path/to/pattern/file.[xml/yaml] pattern_name' => 'Import and enable the specified pattern file and give it a machine readable name' ), 'arguments' => array( 'pattern_file' => 'The path to a pattern file', 'pattern_name' => 'An optional machine-readable pattern name to override the title field of the pattern' ), 'drupal dependencies' => array('patterns', 'token'), 'core' => array('6'), ); return $items; } /** * Imports, Enables, and Runs the specified pattern file * @param string pattern file pathname * @param string optional machine readable pattern name */ function drush_patterns_run($pattern_file, $pattern_name='') { /** Since I want to be able to specify a file name in my interface, in * order to use the patterns_get_pattern() logic as is, I need to * standardize on pattern name, and fire off this "redundant" query to do * so. I'm trading off efficiency for ensuring future compatibility with * patterns module.*/ $name = db_result(db_query("SELECT name FROM {patterns} WHERE `file` LIKE '%s'", "%$pattern_file")); $result = FALSE; if (!$name) { if (drush_confirm(dt("Pattern '$pattern_file' has not been imported. Do you want to import it now? "))) { $name = drush_patterns_import($pattern_file); } } if ($name) { $result = drush_patterns_enable($name); } if (!$result) { drush_set_error(dt("Failed to run pattern '$name' from pattern file '$pattern_file'")); return FALSE; } return TRUE; } /** * Imports the specified patterns file * @param string path to the patterns file * @param string optional machine readable name for the pattern you are importing * @return mixed bool|string FALSE upon failure; the name of the imported * pattern upon success */ function drush_patterns_import($pattern_file, $pattern_name='') { static $patterns_dir = NULL; drush_print(dt("Importing new pattern file '$pattern_file'")); if (!file_exists($pattern_file)) { drush_set_error(dt("File '$pattern_file' does not exist.")); return FALSE; } $form_state = array(); $form_state['values'] = array(); $pattern_path_info = pathinfo($pattern_file); $result = TRUE; $err_msg = ''; if ($pattern_path_info['extension']=='yaml') { //only do this lookup once, and only if someone passes yaml if (is_null($patterns_dir)) { $patterns_dir = drupal_get_path('module', 'patterns'); } //@todo hardcoded, make this definable require_once "$patterns_dir/spyc/spyc.php"; $Data = Spyc::YAMLLoad($pattern_file); if (!$Data) { drush_set_error(dt("Yaml pattern file '$pattern_file' is unreadable.")); $result = FALSE; } else { $xml = drush_patterns_arr_to_xml($Data, 'pattern'); } } else { //assume xml $xml = file_get_contents($pattern_file); if (!$xml) { drush_set_error(dt("XML pattern file '$pattern_file' is unreadable.")); $result = FALSE; } } if (!$result) { drush_set_error(dt("Failed to import '$pattern_file'.")); return FALSE; } $xmldoc = new DOMDocument(); $xmldoc->formatOutput = TRUE; $xmldoc->loadXML($xml); $pattern_source = $xmldoc->saveXML(); if (empty($pattern_name)) { $xpath = new DOMXpath($xmldoc); $query = 'info/title'; $entries = $xpath->query($query);//returns DOMNodeList foreach($entries as $entry) { $title = $entry->textContent; } /** * convert pattern title to machine readable identifier * would rather do this all in one go, but I can't seem to make the order * of the replacements work right. */ $pattern_name = preg_replace(array('/^_/', '/[^a-zA-Z0-9\s_]+/'), '', $title); $pattern_name = preg_replace('/\s+/', '_', $pattern_name); } $form_state['post'] = TRUE; $form_state['values']['xmlsource'] = $pattern_source; $form_state['values']['xmlname'] = $pattern_name; $return = $pattern_name; //Ok. so let's use the patterns API for executing this ad hoc form. patterns_execute_action('patterns_import_source', $form_state, array()); $errors = form_get_errors(); if ($errors) { $output = ''; while(list($field, $err) = each($errors)) { $output .= "[$field]:\t$err\n"; } drush_set_error(dt($output)); $return = FALSE; } $msgs = drupal_get_messages(); if ($msgs) { $output = ''; while(list($type, $ms) = each($msgs)) { $output .= "[$type]:\n\t". implode("\n", $ms) ."\n\n"; } drush_print(dt($output)); } //give back the name of the pattern upon success, FALSE on errors return $return; } /** * Enables the specified pattern * @param string pattern name * * @todo Currently the function will barge through and run all sub-patterns by * default. will want to revisit this and perhaps implement a second parameter * to handle whether to do so or not. */ function drush_patterns_enable($pattern_name) { drush_print(dt("Enabling pattern '$pattern_name'")); $pattern = patterns_get_pattern($pattern_name); if (!$pattern) { drush_set_error(dt("Cannot enable pattern '$pattern_name' as it could not be found in the list of registered patterns. Did you import it first?")); return FALSE; } $result = patterns_execute_pattern($pattern, array('run-subpatterns')); if (!$result) { drush_set_error(dt("Enabling pattern '$pattern->name' failed")); return FALSE; } drush_print(dt("Success! Enabled pattern '$pattern->name'")); return TRUE; } /** * Spit and tape version of an an array to xml converter specifically for yaml * to xml pattern conversion */ function drush_patterns_arr_to_xml($data, $rootNodeName = 'root', $xml = NULL) { static $i = 0; $i++; if ($xml == null) { switch($rootNodeName) { case 'pattern': $encoding = 'ISO-8859-1'; break; default: $encoding = 'utf-8'; break; } $xml = simplexml_load_string("<$rootNodeName />"); } // loop through the data passed in. foreach($data as $key => $value) { // no numeric keys in our xml please! $unknown = FALSE; if (is_numeric($key)) { $unknown = TRUE; if (is_array($value)) { $first_child_key = key($value); $first_child_val = current($value); if ($first_child_key=='tag') { $key = $first_child_val; array_shift($value);//get rid of it. $unknown = FALSE; } } } // replace anything not alpha numeric $key = preg_replace('/[^a-z_]/i', '', $key); if ($unknown) { // make string key... $key = "unknownNode_". (string) $key; } // if there is another array found recursively call this function if (is_array($value)) { $node = $xml->addChild($key); //exception for modules listing if ($key=='modules') { //error_log("$i: we are where we want to be: ". current($value)); reset($value); while(list($key, $val) = each($value)) { //error_log("adding module $val as child"); $node->addChild('module', $val); } } else { // recursive call. drush_patterns_arr_to_xml($value, $rootNodeName, $node); } } else { // add single node. $xml->addChild($key, $value); } } // pass back as string. or simple xml object if you want! return $xml->asXML(); }