? features_map_user_permissions.patch
? features_test
? tests
Index: includes/features.user.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/features/includes/Attic/features.user.inc,v
retrieving revision 1.1.2.10
diff -u -p -r1.1.2.10 features.user.inc
--- includes/features.user.inc	18 Nov 2009 04:36:36 -0000	1.1.2.10
+++ includes/features.user.inc	21 Dec 2009 16:29:07 -0000
@@ -64,16 +64,10 @@ function user_features_export_render($mo
   $permissions = _user_features_get_permissions();
 
   foreach ($data as $perm_name) {
-    $permission = array();
-    $permission['name'] = $perm_name;
-    if (isset($permissions[$perm_name])) {
-      sort($permissions[$perm_name]);
-      $permission['roles'] = $permissions[$perm_name];
-    }
-    else {
-      $permission['roles'] = array();
-    }
-
+    $permission = array(
+      'name' => $perm_name,
+      'roles' => isset($permissions[$perm_name]) ? $permissions[$perm_name] : _user_features_no_roles(),
+    );
     $code[] = '  // Exported permission: '. $perm_name;
     $code[] = '  $permissions[] = '. features_var_export($permission, '  ') .';';
     $code[] = '';
@@ -105,8 +99,14 @@ function user_features_rebuild($module) 
     foreach ($defaults as $permission) {
       $perm = $permission['name'];
 
-      // Add permissions for any roles that should have them.
-      foreach ($permission['roles'] as $role) {
+      // Update permissions for roles described by exported permissions.
+      foreach ($permission['roles'] as $role => $granted) {
+        // If the role key is numeric, the feature is using a deprecated
+        // export format. Skip.
+        if (is_numeric($role)) {
+          continue;
+        }
+
         // Ensure that each role exists. If it does not, create it and store the rid.
         if (!isset($roles[$role])) {
           $record = array('name' => $role);
@@ -116,14 +116,12 @@ function user_features_rebuild($module) 
             'perm' => array(),
           );
         }
-        if (!in_array($perm, $roles[$role]['perm'])) {
+
+        // Add/remove permissions for the specified roles.
+        if ($granted && !in_array($perm, $roles[$role]['perm'])) {
           $roles[$role]['perm'][] = $perm;
         }
-      }
-
-      // Remove permissions for any roles that shouldn't have them.
-      foreach (array_keys($roles) as $role) {
-        if (in_array($perm, $roles[$role]['perm']) && !in_array($role, $permission['roles'])) {
+        if (!$granted && in_array($perm, $roles[$role]['perm'])) {
           $position = array_search($perm, $roles[$role]['perm']);
           unset($roles[$role]['perm'][$position]);
         }
@@ -163,9 +161,9 @@ function _user_features_get_permissions(
     $role_perms = explode(', ', $row->perm);
     foreach ($role_perms as $perm) {
       if (!isset($permissions[$perm])) {
-        $permissions[$perm] = array();
+        $permissions[$perm] = _user_features_no_roles();
       }
-      $permissions[$perm][] = $role;
+      $permissions[$perm][$role] = TRUE;
     }
   }
   return $permissions;
@@ -182,3 +180,13 @@ function _user_features_save_roles($role
     drupal_write_record('permission', $role);
   }
 }
+
+/**
+ * Returns an array filled with [role_name] => FALSE, useful for filling the
+ * perm state of a given permission before assigning it values.
+ */
+function _user_features_no_roles() {
+  $all_roles = array_keys(_features_get_roles());
+  sort($all_roles);
+  return array_combine($all_roles, array_fill(0, count($all_roles), FALSE));
+}
