Index: drush_mm/drush_mm.inc =================================================================== RCS file: drush_mm/drush_mm.inc diff -N drush_mm/drush_mm.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ drush_mm/drush_mm.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,296 @@ +0){ + // TODO place a warning somehow ... see NOTE + + // NOTE : some modules have faulty dependencies + // This makes a corrupt dot file. + $_drush_mm_module_info[ $base_name]['depends'][]=$depends; + } + } + } + } +} + +/** + * get the first matching line of trimmed value out of name = value constructs + * + * @param $name string to match before = sign + * @param $lines to search for the first occurence + * + * @return trimmed value of "name = value" + * + */ +function _drush_mm_get_named_value( $name, $lines){ + $result = preg_grep("/\s*$name\s*=/", $lines); + if( count( $result)){ + // get first matching line only + $result = array_shift( $result); + // return only value + return array_pop(split("=",$result, 2)); + } + return; +} + +function _drush_mm_list_modules( $modules_info){ + $list = array(); + + foreach( $modules_info as $key=>$value){ + if( $value['name']){ + $list[ $value['status']][]= $key; + } else { + $list['error'][]= $key; + } + } + + sort( $list['error']); + sort( $list[0]); + sort( $list[1]); + + if( count($list['error'])){ + echo "According to the system table available modules but not installed!\n"; + echo " ERROR : " . implode( " ", $list['error']) . "\n"; + } + echo "enabled :\n " . implode( " ", $list[1]) . "\n"; + echo "disabled :\n " . implode( " ", $list[0]) . "\n"; + +} + +function _drush_mm_generate_dot( $modules_info){ + // print_r( $modules_info); + echo "digraph {\n"; + + // make this a two pass + // 1. nodes + // 1.1 use subgraphs for same package based modules + // 1.2 use colors + // 2. connections + foreach( $modules_info as $key=>$value){ + echo ' "'.$key .'" [ style=filled, color=' + . ( isset( $value['name']) ? ($value['status'] ? 'green' : 'yellow') : 'red') + ." ];"; + + if( isset( $value['depends'])){ + foreach( $value['depends'] as $dep){ + echo " \"$key\" -> \"$dep\" \n"; + } + } else { + echo " \"$key\" \n"; + } + } + echo "}"; +} + +function _drush_mm_get_modules_info(){ + // storage for all module info + global $_drush_mm_module_info; + $_drush_mm_module_info= array(); + + foreach( $paths= _drush_mm_get_module_paths() as $path){ + $tree = _drush_mm_get_recursive_folder_list( $path); + array_walk_recursive( $tree, '_drush_mm_get_module_info'); + } + + // TODO: add the system settings + $result= db_query("SELECT name, status FROM {system} WHERE type = 'module'"); + while( $module= db_fetch_object($result)){ + $_drush_mm_module_info[$module->name]['status']= $module->status; + } + + // fill in the rdepends + foreach( $_drush_mm_module_info as $key=>$module){ + foreach( $module['depends'] as $depend){ + // registrer the reverse dependencies + $_drush_mm_module_info[$depend]['rdepends'][]= $key; + } + } + //print_r($_drush_mm_module_info); +} + +/** + * based on the modules at hand the depends list is generated + * + */ +function _drush_mm_get_module_list( $modules, $enable){ + global $_drush_mm_module_info; + _drush_mm_get_modules_info(); + + // Test the given list + $missing_modules= array(); + foreach( $modules as $module){ + if( !array_key_exists( $module, $_drush_mm_module_info)){ + $missing_modules[]= $module; + } + } + + if( count( $missing_modules)){ + drush_die(t("The following modules where not found. '!modules'" , array( "!modules"=> implode( ", ", $missing_modules)))); + } + + // Generate the list + $modules_to_use = array(); + + foreach( $modules as $module){ + $modules_to_use[$module]= $_drush_mm_module_info[$module]; + } + + $dependency_key = $enable ? 'depends' : 'rdepends'; + + // add dependencies + $more= TRUE; + while( $more){ + $more= FALSE; + foreach( $modules_to_use as $key=>$module){ + // add all (r)depends to the list + foreach( $module[ $dependency_key] as $depend){ + if( !array_key_exists( $depend, $modules_to_use)){ + $modules_to_use[$depend]= $_drush_mm_module_info[$depend]; + $more= TRUE; + } + } + } + } + + $graph= _drush_mm_build_graph( $modules_to_use, $dependency_key); + + $result= _drush_mm_graph_tsl( $graph); + + if( array_shift($result) != "_drupal_"){ + drush_die(t("Unexpected result for '!modules'." , array( "!modules"=> implode( ", ", $result)))); + } + if( array_pop($result) != "_root_"){ + drush_die(t("Unexpected result for '!modules'." , array( "!modules"=> implode( ", ", $result)))); + } + + return $result; + +} + +function _drush_mm_build_graph( $modules_to_use, $dependency_key){ + // build graph + $graph= array(); + foreach($modules_to_use as $key => $module){ + // make undependants dependant + if( count($module[ $dependency_key])){ + foreach( $module[$dependency_key] as $depend){ + $graph[$key][$depend]++; + } + } else { + // we make the independant 'drupal' dependent + $graph[$key]['_drupal_']++; + } + } + + // make all rdepend-less rdepend to _root_ + foreach( $graph as $key=>$node){ + if( !count( $modules_to_use[$key]['rdepend'])){ + $graph['_root_'][$key]++; + } + } + return $graph; +} + +function _drush_mm_get_module_paths(){ + $paths = array(); + + if (DRUSH_URI) { + $path = conf_path(); + $paths['site'] = DRUSH_DRUPAL_ROOT .'/'. $path .'/modules/'; + } + + if (file_exists(DRUSH_DRUPAL_ROOT .'/sites/all/modules/')) { + $paths['all'] = DRUSH_DRUPAL_ROOT .'/sites/all/modules/'; + } + + $paths['core'] = DRUSH_DRUPAL_ROOT .'/modules/'; + + return $paths; +} + +/** + * Generares a topological sorted list + * + * @param $graph + * the graph to get a TSL from + */ +function _drush_mm_graph_tsl( $graph){ + $result= array(); + + $reset = TRUE; + foreach( $graph as $key=>$value){ + $result= _drush_mm_graph_df($graph, $key, $reset); + $reset= FALSE; + } + + return $result; +} + +/** + * do a depth first search + * + * Each node will be visited. The more depth first. + */ +function _drush_mm_graph_df( $graph, $node, $reset=false){ + static $visited; + static $result; + + if( !isset( $visited) || $reset){ + $visited= array(); + $result= array(); + } + + if( !isset($visited[$node])){ + $visited[$node]=TRUE; + foreach( $graph[$node] as $key=> $_node){ + _drush_mm_graph_df( $graph, $key); + } + array_push($result, $node); + } + + return $result; +} Index: drush_mm/drush_mm.info =================================================================== RCS file: drush_mm/drush_mm.info diff -N drush_mm/drush_mm.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ drush_mm/drush_mm.info 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,5 @@ +; $Id$ +name = Drush Module Manager +description = Allows you to enable/disable modules and generated a graph from the command line. +dependencies = drush +package = drush Index: drush_mm/README.txt =================================================================== RCS file: drush_mm/README.txt diff -N drush_mm/README.txt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ drush_mm/README.txt 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,23 @@ +// $Id$ + +DESCRIPTION +----------- + +drush_mm.module (The Drupal Shell Module Manager) allows you to enable and disable modules from the command line. + +It provides three commands +- enable : enabled the given module and all modules it depends on +- disable : disable the given module and all modules depending on +- dot : generated a dot file for further processing into a webpage + +Run these as "drush mm " + +Run "drush help mm " to see supported command line options and arguments. + +REQUIREMENTS +------------ +none + +------------ +Written by Clemens Tolboom (ngnp) . +No warranties of any kind. Use with care. Index: drush_mm/drush_mm.module =================================================================== RCS file: drush_mm/drush_mm.module diff -N drush_mm/drush_mm.module --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ drush_mm/drush_mm.module 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,160 @@ + ... + is the computer readable name of one of the installed modules.\n +After enabling, you still have to configure the modules through the modules +administration page\n\n"); + case 'drush:mm disable': + return t("Warning: do not disable required core modules!!!\n\n +Usage: drush [options] mm disable ... + is the computer readable name of one of the modules to install.\n\n"); + case 'drush:mm uninstall': + return t("Warning: do not uninstall required core modules!!!\n\n +Usage: drush [options] mm uninstall ... + is the computer readable name of one of the modules to uninstall.\n\n"); + case 'drush:mm dot': + return t("Usage: drush [options] mm dot ... +generated a graphviz dot file for further processing.\n\n"); + } +} + +/** + * Implementation of hook_drush_command(). + */ +function drush_mm_drush_command() { + $items['mm list'] = array( + 'callback' => 'drush_mm_list_modules', + 'description' => 'Lists the available modules' + ); + + $items['mm enable'] = array( + 'callback' => 'drush_mm_enable_module', + 'description' => 'Enables (and if necessary installs) the given modules and depend' + ); + + $items['mm disable'] = array( + 'callback' => 'drush_mm_disable_module', + 'description' => 'Disable the given modules and reverse dependants' + ); + + $items['mm uninstall'] = array( + 'callback' => 'drush_mm_uninstall_module', + 'description' => 'Uninstalls the given modules and reverse dependants' + ); + + $items['mm dot'] = array( + 'callback' => 'drush_mm_dot', + 'description' => 'Generates a dot file of all modules' + ); + return $items; +} + +function drush_mm_list_modules() { + require_once "drush_mm.inc"; + global $_drush_mm_module_info; + _drush_mm_get_modules_info(); + + _drush_mm_list_modules($_drush_mm_module_info); +} + +function drush_mm_dot() { + require_once "drush_mm.inc"; + global $_drush_mm_module_info; + _drush_mm_get_modules_info(); + + + _drush_mm_generate_dot($_drush_mm_module_info); +} +/** + * enables the given modules + * + * If all modules are present the are enabled + */ +function drush_mm_enable_module() { + $modules = func_get_args(); + _drush_mm_endis_module( TRUE, $modules); +} + +function drush_mm_uninstall_module(){ + $modules = func_get_args(); + + if( empty($modules)){ + drush_die(t("No modules specified.\n\nRun drush help mm uninstall for more information.")); + } + + drush_verbose( t("First disabling modules ...")); + call_user_func_array( 'drush_mm_disable_module', $modules); + + drush_verbose( t("Now uninstalling modules ...")); + + $enable= FALSE; + require_once "drush_mm.inc"; + $result= _drush_mm_get_module_list( $modules, $enable); + + foreach( $result as $module){ + if( !DRUSH_SIMULATE){ + include_once './includes/install.inc'; + drush_verbose( t("Uninstalling module $module")); + drupal_uninstall_module( $module); + } + } +} + +function _drush_mm_endis_module( $enable, $modules){ + if (empty($modules)) { + if( $enable){ + drush_die(t("No modules specified.\n\nRun drush help mm enable for more information.")); + } else { + drush_die(t("No modules specified.\n\nRun drush help mm disable for more information.")); + } + } + + require_once "drush_mm.inc"; + $result= _drush_mm_get_module_list( $modules, $enable); + + if( $enable){ + drush_verbose(t("The following modules will be enabled: '!modules'" , array( "!modules"=> implode( ", ", $result)))); + //module_enable( $result); + include_once './includes/install.inc'; + drush_verbose( t("Installing modules")); + foreach( $result as $module){ + drush_verbose( t("Enabling (and mayby installing) module: $module")); + if( !DRUSH_SIMULATE){ + // only FRESH installed modules gets enabled + drupal_install_modules( array($module)); + // enable for sure + // TODO: this will not solve the 'failed install' scenario + module_enable( array($module)); + } + } + } else { + drush_verbose(t("The following modules will be disabled: '!modules'" , array( "!modules"=> implode( ", ", $result)))); + foreach( $result as $module){ + drush_verbose( t("Disabling module: $module")); + if( !DRUSH_SIMULATE){ + module_disable( $result); + } + } + } +} + +function drush_mm_disable_module() { + $modules = func_get_args(); + _drush_mm_endis_module( FALSE, $modules); +} +?>