? .git
? .gitignore
? 789556-1_taxonomy.patch
Index: features.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/features/features.module,v
retrieving revision 1.1.2.63
diff -u -p -r1.1.2.63 features.module
--- features.module	7 Feb 2010 05:04:43 -0000	1.1.2.63
+++ features.module	4 May 2010 15:58:25 -0000
@@ -285,7 +285,7 @@ function features_include() {
 
   // Features provides integration on behalf of these modules.
   // Note that ctools is placed last because it implements hooks "dynamically" for other modules.
-  $modules = array('block', 'content', 'context', 'fieldgroup', 'filter', 'imagecache', 'node', 'user', 'views', 'ctools');
+  $modules = array('block', 'content', 'context', 'fieldgroup', 'filter', 'imagecache', 'node', 'taxonomy', 'user', 'views', 'ctools');
 
   foreach (array_filter($modules, 'module_exists') as $module) {
     if (!module_hook($module, 'features_api')) {
Index: includes/features.node.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/features/includes/features.node.inc,v
retrieving revision 1.1.2.17
diff -u -p -r1.1.2.17 features.node.inc
--- includes/features.node.inc	7 Feb 2010 05:04:43 -0000	1.1.2.17
+++ includes/features.node.inc	4 May 2010 15:58:25 -0000
@@ -56,6 +56,14 @@ function node_features_export($data, &$e
         unset($export['features']['node'][$type]);
       }
 
+      // Create a pipe for taxonomy vocabularies.
+      $vocabularies = _taxonomy_features_get_vocabularies();
+      foreach ($vocabularies as $machine_name => $vocabulary) {
+        if (isset($vocabulary->nodes[$type])) {
+          $pipe['taxonomy'][] = $machine_name;
+        }
+      }
+
       // Create a pipe for CCK fields
       if (module_exists('content')) {
         $content_info = content_types($type);
Index: includes/features.taxonomy.inc
===================================================================
RCS file: includes/features.taxonomy.inc
diff -N includes/features.taxonomy.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/features.taxonomy.inc	4 May 2010 15:58:25 -0000
@@ -0,0 +1,128 @@
+<?php
+// $Id$
+
+/**
+ * Implementation of hook_features_api().
+ */
+function taxonomy_features_api() {
+  return array(
+    'taxonomy' => array(
+      'name' => t('Taxonomy'),
+      'feature_source' => TRUE,
+      'default_hook' => 'taxonomy_default_vocabularies',
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_features_export_options().
+ */
+function taxonomy_features_export_options() {
+  $vocabularies = array();
+  foreach (_taxonomy_features_get_vocabularies() as $machine_name => $vocabulary) {
+    $vocabularies[$machine_name] = $vocabulary->name;
+  }
+  return $vocabularies;
+}
+
+/**
+ * Implementation of hook_features_export().
+ *
+ * @todo Test adding existing dependencies.
+ */
+function taxonomy_features_export($data, &$export, $module_name = '') {
+  // taxonomy_default_vocabularies integration is provided by Features.
+  $export['dependencies']['features'] = 'features';
+  $export['dependencies']['taxonomy'] = 'taxonomy';
+
+  // Collect a vocabulary to module map.
+  $map = array();
+  $modules = module_implements('taxonomy_default_vocabularies');
+  foreach ($modules as $module) {
+    $vocabularies = module_invoke($module, 'taxonomy_default_vocabularies');
+    foreach ($vocabularies as $machine_name => $vocabulary) {
+      $map[$machine_name] = $module;
+    }
+  }
+  // Add dependencies for each vocabulary.
+  foreach ($data as $machine_name) {
+    if (isset($map[$machine_name]) && $map[$machine_name] != $module_name) {
+      $export['dependencies'][$map[$machine_name]] = $map[$machine_name];
+    }
+    else {
+      $export['features']['taxonomy'][$machine_name] = $machine_name;
+    }
+  }
+  return array();
+}
+
+/**
+ * Implementation of hook_features_export_render().
+ */
+function taxonomy_features_export_render($module = 'foo', $data) {
+  $vocabularies = _taxonomy_features_get_vocabularies();
+  foreach ($data as $machine_name) {
+    foreach ($vocabularies as $k => $v) {
+      if ($k == $machine_name) {
+        unset($v->vid);
+        $code[$machine_name] = $v;
+      }
+    }
+  }
+  $code = "  return ". features_var_export($code, '  ') .";";
+  return array('taxonomy_default_vocabularies' => $code);
+}
+
+/**
+ * Implementation of hook_features_revert().
+ */
+function taxonomy_features_revert($module) {
+  taxonomy_features_rebuild($module);
+}
+
+/**
+ * Implementation of hook_features_rebuild().
+ *
+ * Rebuilds Taxonomy vocabularies from code defaults.
+ */
+function taxonomy_features_rebuild($module) {
+  $vocabularies = module_invoke($module, 'taxonomy_default_vocabularies');
+  foreach ($vocabularies as $machine_name => $vocabulary) {
+    if ($vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = 'features:%s'", $machine_name))) {
+      $vocabulary['vid'] = $vid;
+    }
+    taxonomy_save_vocabulary($vocabulary);
+  }
+}
+
+/**
+ * Retrieves all vocabularies viable for export.
+ *
+ * All vocabularies owned by the taxonomy module are exportable.
+ *
+ * This function renames the 'module' property of a vocabulary to
+ * features:[machine_name] if it is 'taxonomy'. This way we can keep non-serial
+ * identifiers for taxonomy terms.
+ */
+function _taxonomy_features_get_vocabularies() {
+  $vocabularies = array();
+  foreach (taxonomy_get_vocabularies() as $k => $vocabulary) {
+    if ($vocabulary->module == 'taxonomy') {
+      $machine_name = _taxonomy_features_machine_name($vocabulary->name);
+      $vocabulary->module = 'features:'. $machine_name;
+      drupal_write_record('vocabulary', $vocabulary, 'vid');
+    }
+    if (strpos($vocabulary->module, 'features:') === 0) {
+      // Don't bother site builder with 'features:'.
+      $vocabularies[substr($vocabulary->module, 9)] = $vocabulary;
+    }
+  }
+  return $vocabularies;
+}
+
+/**
+ * Generates a machine name from a human readable name.
+ */
+function _taxonomy_features_machine_name($name) {
+  return strtolower(trim(preg_replace('/[^A-Za-z]+/', '_', $name), '_'));
+}
