=== modified file 'modules/system/system.install'
--- modules/system/system.install	2009-08-29 11:00:03 +0000
+++ modules/system/system.install	2009-09-05 13:49:06 +0000
@@ -2459,6 +2459,130 @@
 }
 
 /**
+ * Change profile.module fields into Field API fields.
+ */
+function system_update_7038() {
+  $ret = array();
+  $fields = array();
+  
+  if (!db_table_exists('profile_field')) {
+    return $ret;
+  }
+  // Get all profile fields.
+  $old_fields = db_query('SELECT * FROM {profile_field} ORDER BY category, weight');
+
+  foreach ($old_fields as $old_field) {
+    // Create new fields using the field API.
+    $field = array(
+      'field_name' => strtolower(str_replace('-', '_', $old_field->name)),
+      'cardinality' => 1,
+    );
+
+    // Create field instance on the user bundle.
+    $instance = array(
+      'field_name' => $field['field_name'],
+      'bundle' => 'user',
+      'description' => $old_field->explanation,
+      'label' => $old_field->title,
+      'required' => $old_field->required,
+      'widget' => array(
+        'weight' => $old_field->weight,
+      ),
+      'display' => array(
+        'full' => array(
+          'weight' => $old_field->weight,
+        ),
+      ),
+      'settings' => array(
+        'user_register' => $old_field->register,
+      ),
+    );
+
+    switch ($old_field->type) {
+      case 'textfield':
+        $field['type'] = 'text';
+        $instance['widget']['type'] = 'text_textfield';
+
+        // Only allow plain text.
+        $instance['settings']['text_processing'] = 0;
+        break;
+
+      case 'textarea':
+        $field['type'] = 'text_long';
+        $instance['widget']['type'] = 'text_textarea';
+        // Use the default text format.
+        $instance['settings']['text_processing'] = variable_get('filter_default_format', 1);
+        break;
+
+      case 'checkbox':
+        $field['type'] = 'list_boolean';
+        $instance['widget']['type'] = 'options_onoff';
+        $field['settings']['allowed_values'] = "0\n1|" . $old_field->title;
+        break;
+
+      case 'selection':
+        $field['type'] = 'list_text';
+        $instance['widget']['type'] = 'options_select';
+        $field['settings']['allowed_values'] = $old_field->options;
+        break;
+
+      case 'list':
+        $field['type'] = 'text';
+        $field['cardinality'] = FIELD_CARDINALITY_UNLIMITED;
+        break;
+
+      case 'date':
+        $ret[] = array('success' => TRUE, 'query' => 'To migrate date fields from the profile module, install the <a href="http://drupal.org/project/date">date</a> module.');        
+        continue 2;
+        
+      case 'url':
+        $ret[] = array('success' => TRUE, 'query' => 'To migrate URL fields from the profile module, install the <a href="http://drupal.org/project/link">link</a> module.');
+        continue 2;
+    }
+
+    try {
+      field_create_field($field);
+      field_create_instance($instance);
+      $fields[$old_field->fid] = $field;
+    }
+    catch (Exception $e) {
+      $ret[] = array('success' => FALSE, 'query' => t('There was a problem creating field %label: @message.', array('%label' => $instance['label'], '@message' => $e->getMessage())));
+    }
+  }
+
+  // Get old field values from the profile.module table.
+  $results = db_query('SELECT uid, fid, value FROM {profile_value} WHERE value IS NOT NULL');
+
+  $accounts = array();
+  foreach ($results as $result) {
+    $field_name = $fields[$result->fid]['field_name'];
+    $accounts[$result->uid]['uid'] = $result->uid;
+    
+    if ($fields[$result->fid]['type'] == 'text' && $fields[$result->fid]['cardinality'] == FIELD_CARDINALITY_UNLIMITED) {
+      $values = array_filter(array_map('trim', preg_split("/[,\n\r]/", $result->value)));
+      $delta = 0;
+      foreach ($values as $value) {
+        $accounts[$result->uid][$field_name][FIELD_LANGUAGE_NONE][$delta]['value'] = $value;
+        $delta++;
+      }
+    }
+    else {
+      $accounts[$result->uid][$field_name][FIELD_LANGUAGE_NONE][0]['value'] = $result->value;
+    }
+  }
+
+  // Set new field values using the field API.
+  foreach ($accounts as $account) {
+    $account = (object) $account;
+    field_attach_update('user', $account);
+  }
+    
+  $ret[] = array('success' => TRUE, 'query' => 'The profile module has been replaced by the new Fields UI. For additional functionality such as adding fields to the registration form, install the <a href="http://drupal.org/project/retro_profile">Retro Profile</a> module.');
+  
+  return $ret; 
+}
+
+/**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */

=== modified file 'modules/system/system.test'
--- modules/system/system.test	2009-09-01 17:00:02 +0000
+++ modules/system/system.test	2009-09-05 14:50:52 +0000
@@ -1227,3 +1227,248 @@
     $this->assertFalse(strcmp($generated['[node:title]'], $node->title), t('Unsanitized token generated properly.'));
   }
 }
+
+class SystemUpdateTestCase extends DrupalWebTestCase {
+  /**
+   * Implement getInfo().
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Update path',
+      'description' => 'Test the update path from older version of Drupal.',
+      'group' => 'System'
+    );
+  }
+  
+  function testSystemUpdate7038() {
+    // Create a user and an array for field_attach_load().
+    $profile_user = $this->drupalCreateUser();
+    
+    // Create some old profile field data to test the update.
+    $old_schema = $this->profileSchema();
+    db_create_table($ret, 'profile_field', $old_schema['profile_field']);
+    db_create_table($ret, 'profile_value', $old_schema['profile_value']);
+    
+    $old_fields['textfield'] = array(
+      'title' => $this->randomName(),
+      'name' => $this->randomName(),
+      'explanation' => $this->randomName(50),
+      'category' => $this->randomName(),
+      'page' => NULL,
+      'type' => 'textfield',
+      'weight' => rand(-10, 10),
+      'required' => 1,
+      'register' => 1,
+      'visibility' => 0,
+      'autocomplete' => 0,
+      'options' => NULL,
+    );
+    $old_fields['textarea'] = array(
+      'title' => $this->randomName(),
+      'name' => $this->randomName(),
+      'type' => 'textarea',
+      'required' => 0,
+    );
+    $old_fields['checkbox'] = array(
+      'title' => $this->randomName(),
+      'name' => $this->randomName(),
+      'type' => 'checkbox',
+    );
+    
+    $fid = 1;
+    foreach ($old_fields as $field_name => $old_field) {
+      // Create the configuration for the profile.module field.
+      $old_field['fid'] = $fid;
+      db_insert('profile_field')->fields($old_field)->execute();
+      
+      // Set profile.module field values for $profile_user.
+      $old_field_value = array(
+        'fid' => $fid,
+        'uid' => $profile_user->uid,
+      );
+      switch ($old_field['type']) {
+        case 'textfield':
+        case 'textarea':
+          $old_field_value['value'] = $this->randomName();
+          break;
+          
+        case 'checkbox':
+          $old_field_value['value'] = rand(0, 1);
+          break;
+      }
+      db_insert('profile_value')->fields($old_field_value)->execute();
+      $old_fields[$field_name]['value'] = $old_field_value['value'];
+      $fid++;
+    }
+    
+    // Run the update.
+    system_update_7038();
+    
+    // Reload the user with the new fields.
+    $profile_user = user_load($profile_user->uid, TRUE);
+
+    // Check the migration of textfield fields and well as basic settings.
+    $field_name = strtolower(str_replace('-', '_', $old_fields['textfield']['name']));
+    $field = field_info_field($field_name);
+    $this->assertNotNull($field, t('The user field has been created.'));
+    $this->assertEqual($field['type'], 'text', t('Textfields are mapped to fields of type text.'));
+    
+    $instance = field_info_instance($field_name, 'user');
+    $this->assertNotNull($instance, t('The field has an instance attached to users.'));
+    $this->assertEqual($old_fields['textfield']['title'], $instance['label'], t('Field label is preserved.'));
+    $this->assertEqual($old_fields['textfield']['explanation'], $instance['description'], t('Field description is preserved.'));
+    $this->assertTrue($instance['required'], t('Required fields are preserved.'));
+    $this->assertEqual($old_fields['textfield']['weight'], $instance['widget']['weight'], t('Weight gets preserved for widgets.'));
+    $this->assertEqual($old_fields['textfield']['weight'], $instance['display']['full']['weight'], t('Weight gets preserved when displaying fields.'));
+    $this->assertEqual($old_fields['textfield']['value'], $profile_user->{$field_name}[FIELD_LANGUAGE_NONE][0]['value'], t('Textfield values are migrated.'));
+    
+    // Check the migration of textarea fields.
+    $field_name = strtolower(str_replace('-', '_', $old_fields['textarea']['name']));
+    $field = field_info_field($field_name);
+    $this->assertNotNull($field, t('The user field has been created.'));
+    $this->assertEqual($field['type'], 'text_long', t('Textareas are mapped to fields of type text_long.'));
+    
+    $instance = field_info_instance($field_name, 'user');
+    $this->assertFalse($instance['required'], t('Not required fields are preserved.'));
+    $this->assertEqual($old_fields['textarea']['value'], $profile_user->{$field_name}[FIELD_LANGUAGE_NONE][0]['value'], t('Textarea values are migrated.'));
+
+    // Check the migration of checkbox fields.
+    $field_name = strtolower(str_replace('-', '_', $old_fields['checkbox']['name']));
+    $field = field_info_field($field_name);
+    $this->assertNotNull($field, t('The user field has been created.'));
+    $this->assertEqual($field['type'], 'list_boolean', t('Checkboxes are mapped to fields of type list_boolean.'));
+    $this->assertEqual($old_fields['checkbox']['value'], $profile_user->{$field_name}[FIELD_LANGUAGE_NONE][0]['value'], t('Checkbox values are migrated.'));
+  }
+  
+  // This is an exact copy of the profile_schema.
+  function profileSchema() {
+    $schema['profile_field'] = array(
+      'description' => 'Stores profile field information.',
+      'fields' => array(
+        'fid' => array(
+          'type' => 'serial',
+          'not null' => TRUE,
+          'description' => 'Primary Key: Unique profile field ID.',
+        ),
+        'title' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => FALSE,
+          'description' => 'Title of the field shown to the end user.',
+        ),
+        'name' => array(
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'Internal name of the field used in the form HTML and URLs.',
+        ),
+        'explanation' => array(
+          'type' => 'text',
+          'not null' => FALSE,
+          'description' => 'Explanation of the field to end users.',
+        ),
+        'category' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => FALSE,
+          'description' => 'Profile category that the field will be grouped under.',
+        ),
+        'page' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => FALSE,
+          'description' => "Title of page used for browsing by the field's value",
+        ),
+        'type' => array(
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => FALSE,
+          'description' => 'Type of form field.',
+        ),
+        'weight' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+          'size' => 'tiny',
+          'description' => 'Weight of field in relation to other profile fields.',
+        ),
+        'required' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+          'size' => 'tiny',
+          'description' => 'Whether the user is required to enter a value. (0 = no, 1 = yes)',
+        ),
+        'register' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+          'size' => 'tiny',
+          'description' => 'Whether the field is visible in the user registration form. (1 = yes, 0 = no)',
+        ),
+        'visibility' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+          'size' => 'tiny',
+          'description' => 'The level of visibility for the field. (0 = hidden, 1 = private, 2 = public on profile but not member list pages, 3 = public on profile and list pages)',
+        ),
+        'autocomplete' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+          'size' => 'tiny',
+          'description' => 'Whether form auto-completion is enabled. (0 = disabled, 1 = enabled)',
+        ),
+        'options' => array(
+          'type' => 'text',
+          'not null' => FALSE,
+          'description' => 'List of options to be used in a list selection field.',
+        ),
+      ),
+      'indexes' => array(
+        'category' => array('category'),
+      ),
+      'unique keys' => array(
+        'name' => array('name'),
+      ),
+      'primary key' => array('fid'),
+    );
+  
+    $schema['profile_value'] = array(
+      'description' => 'Stores values for profile fields.',
+      'fields' => array(
+        'fid' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'default' => 0,
+          'description' => 'The {profile_field}.fid of the field.',
+        ),
+        'uid' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'default' => 0,
+          'description' => 'The {users}.uid of the profile user.',
+        ),
+        'value' => array(
+          'type' => 'text',
+          'not null' => FALSE,
+          'description' => 'The value for the field.',
+        ),
+      ),
+      'primary key' => array('uid', 'fid'),
+      'indexes' => array(
+        'fid' => array('fid'),
+      ),
+      'foreign keys' => array(
+        'fid' => array('profile_field' => 'fid'),
+        'uid' => array('users' => 'uid'),
+      ),
+    );
+  
+    return $schema;
+  }
+}

