diff --git a/commands/make/generate.make.inc b/commands/make/generate.make.inc
index 9225dd7..23deca7 100644
--- a/commands/make/generate.make.inc
+++ b/commands/make/generate.make.inc
@@ -114,6 +114,7 @@ function _drush_make_generate_projects($all_extensions, $version_options) {
       // It is not a project on drupal.org neither an external update service.
       $projects[$name]['type'] = $type;
       $projects[$name]['custom_download'] = TRUE;
+      $projects[$name]['_source_dir'] = DRUPAL_ROOT . '/' . dirname($project->filename);
     }
     // Add 'subdir' if the project is installed in a non-default location.
     if (isset($project['path'])) {
@@ -142,6 +143,7 @@ function _drush_make_generate_projects($all_extensions, $version_options) {
       $project_libraries[$library_name] = array(
         'directory_name' => $path[(count($path) - 1)],
         'custom_download' => TRUE,
+        '_source_dir' => DRUPAL_ROOT . '/' . $library_path,
         'type' => 'library',
         '_type' => 'librarie', // For plural.
       );
@@ -321,6 +323,7 @@ function _drush_make_generate_makefile_contents($projects, $libraries = array())
 }
 
 function _drush_make_generate_makefile_body($projects, $output = array()) {
+  $external_libraries = _drush_generate_get_external_libraries();
   $custom = FALSE;
   $previous_type = 'core';
   foreach ($projects as $name => $project) {
@@ -337,12 +340,41 @@ function _drush_make_generate_makefile_body($projects, $output = array()) {
     $base = $type . '[' . $name . ']';
     if (isset($project['custom_download'])) {
       $custom = TRUE;
-      $output[] = '; Please fill the following out. Type may be one of get, git, bzr or svn,';
-      $output[] = '; and url is the url of the download.';
-      $output[$base . '[download][type]'] = '""';
-      $output[$base . '[download][url]'] = '""';
+      $msg = dt("Please fill the following out. Type may be one of get, git, bzr or svn, and url is the url of the download.");
+      $output_type = '""';
+      $output_url = '""';
+      if (array_key_exists($name, $external_libraries)) {
+        $msg = dt("Please examine the entry below for the !name !type.", array('!name' => $name, '!type' => $project['type']));
+        $best_version = key($external_libraries[$name]['versions']);
+        $found_version = FALSE;
+        if (array_key_exists('_source_dir', $project)) {
+          $md5 = drush_dir_md5($project['_source_dir']);
+          foreach ($external_libraries[$name]['versions'] as $version => $info) {
+            if ($info['md5'] == $md5) {
+              $best_version = $version;
+              $found_version = TRUE;
+              break;
+            }
+          }
+        }
+        if ($found_version) {
+          $msg .= dt(" The installed version, !version, was used below.", array('!version' => $best_version));
+        }
+        else {
+          $msg .= dt(" The installed version could not be determined, so the most recent known version, !version, was used instead.", array('!version' => $best_version));
+        }
+        $msg .= dt(" There may be more recent versions available at the !name project page at !homepage", array('!name' => $name, '!homepage' => $external_libraries[$name]['uri']));
+        $output_type = '"get"';
+        $output_url = '"' . $external_libraries[$name]['versions'][$best_version]['url'] . '"';
+      }
+      foreach (explode("\n", wordwrap($msg, 76)) as $line) {
+        $output[] = '; ' . $line;
+      }
+      $output[$base . '[download][type]'] = $output_type;
+      $output[$base . '[download][url]'] = $output_url;
       unset($project['custom_download']);
     }
+    unset($project['_source_dir']);
     foreach ($project as $key => $value) {
       if (is_array($value)) {
         foreach ($value as $item) {
@@ -370,3 +402,55 @@ function _drush_make_generate_makefile_body($projects, $output = array()) {
   }
   return $string;
 }
+
+function _drush_generate_get_external_libraries() {
+  $items = array();
+
+  $items['ckeditor'] = array(
+    'name' => 'CKEditor',
+    'uri' => 'http://ckeditor.com/',
+    'versions' => array(
+      '3.6.4' => array(
+        'md5' => '752977f71b7a74d80b4f4d21d9d23cb5',
+        'url' => 'http://download.cksource.com/CKEditor/CKEditor/CKEditor 3.6.4/ckeditor_3.6.4.zip',
+      ),
+      '3.3.1' => array(
+        'md5' => '72faa1c49c624c8b8b8131708ff5538a',
+        'url' => 'http://download.cksource.com/CKEditor/CKEditor/CKEditor 3.3.1/ckeditor_3.3.1.zip',
+      ),
+    ),
+  );
+  // Not right?
+  $items['jquery.cycle'] = array(
+    'name' => 'jQuery Cycle',
+    'uri' => 'http://jquery.malsup.com/cycle/',
+    'versions' => array(
+      '2.88' => array(
+        'md5' => '504152bc5c57a275c0909e694c72f7cb',
+        'url' => 'https://github.com/downloads/malsup/cycle/jquery.cycle.all.2.88.min.js',
+      ),
+    ),
+  );
+  $items['superfish'] = array(
+    'name' => 'Superfish for Drupal',
+    'uri' => 'https://github.com/mehrpadin/Superfish-for-Drupal',
+    'versions' => array(
+      '1.1' => array(
+        'md5' => '1b12697d0d7db27479afc6d85be29b33',
+        'url' => 'https://github.com/mehrpadin/Superfish-for-Drupal/zipball/9dbdd14d08200a18cb76a68445c28b26bab16ed6',
+      ),
+    ),
+  );
+  $items['video-js'] = array(
+    'name' => 'Video.js',
+    'uri' => 'http://videojs.com',
+    'versions' => array(
+      '3.2.0' => array(
+        'md5' => '111c226157c2ab8caf79e2e1a9288609',
+        'url' => 'https://github.com/downloads/zencoder/video-js/video-js-3.2.0.zip',
+      ),
+    ),
+  );
+
+  return $items;
+}
diff --git a/commands/make/generate.profile.inc b/commands/make/generate.profile.inc
new file mode 100644
index 0000000..a26ab98
--- /dev/null
+++ b/commands/make/generate.profile.inc
@@ -0,0 +1,563 @@
+<?php
+
+require_once DRUSH_BASE_PATH . '/commands/make/generate.make.inc';
+
+function drush_make_profile_generate($profile_name = 'generated-profile') {
+  // The profile name is used to build function names; if someone uses
+  // dashes, then correct them to underscores.
+  $profile_name = str_replace('-', '_', $profile_name);
+  $final_actions = array();
+
+  // Build a profile_info array containing all of the
+  // different files that will make up the profile.
+  $profile_info = array();
+  $profile_description = drush_get_option('description', 'A profile generated by drush make');
+
+  $profile_info['info'] = array(
+    '#title' => _drush_make_profile_comment(".info file generated by Drush Make."),
+    'name' => $profile_name,
+    'description' => $profile_description,
+    '#major' => drush_drupal_major_version(),
+    'core' => drush_drupal_major_version() . '.x',
+    'dependencies' => array(),
+    'files' => array(),
+  );
+
+  // Set up our filename replacement patterns
+  $profile_info['#filename-replacements']['@profile'] = $profile_name;
+  $profile_info['#filename-replacements']['info'] = $profile_name . '.info';
+
+  // Set up our template replacement patterns
+  $profile_info['#template-replacements']['{$PROFILE}'] = $profile_name;
+
+  // Generate a data structure for a makefile the same way that the generate-makefile command does.
+  $version_options = _drush_make_generate_get_version_options();
+  $all_extensions = drush_get_extensions();
+  list($projects, $libraries) = _drush_make_generate_projects($all_extensions, $version_options);
+
+  $base_profile = drush_get_option('base-profile', 'minimal');
+  $base_profile_info_file = DRUPAL_ROOT . '/profiles/' . $base_profile . '/' . $base_profile . '.info';
+  if (!file_exists($base_profile_info_file)) {
+    return drush_set_error('GENERATE_PROFILE_NO_BASE_PROFILE', dt("The requested base profile !base is not a valid profile.", array('!base' => $base_profile)));
+  }
+  $base_profile_info = parse_ini_file($base_profile_info_file);
+  $profile_dependencies = $base_profile_info['dependencies'];
+  $profile_info['info']['#base_profile'] = $base_profile;
+  $profile_info['info']['#base_profile_info'] = $base_profile_info;
+
+  // Filter out the enabled extensions
+  $enabled_extensions = array();
+  foreach ($all_extensions as $key => $extension) {
+    if ($extension->status) {
+      $enabled_extensions[] = $key;
+    }
+  }
+
+  // Order all of the dependencies for the installation profile
+  $all_dependencies = _drush_make_generate_profile_ordered_modules(array_merge($enabled_extensions, $profile_dependencies), $all_extensions);
+
+  // Collate dependencies into diferent buckets: core, contrib and custom.
+  $core_dependencies = array();
+  $contrib_dependencies = array();
+  $custom_dependencies = array();
+  foreach ($all_dependencies as $key) {
+    $extension = $all_extensions[$key];
+    if ((!array_key_exists('project', $extension->info)) || (isset($projects[$extension->info['project']]['custom_download']))) {
+      $custom_dependencies[] = $key;
+    }
+    elseif ($extension->info['project'] == 'drupal') {
+      $core_dependencies[] = $key;
+    }
+    else {
+      $contrib_dependencies[] = $key;
+    }
+  }
+
+  // Add our dependencies to our .info file
+  if (!empty($core_dependencies)) {
+    $profile_info['info']['dependencies'][] = _drush_make_profile_comment("Core Extensions");
+    $profile_info['info']['dependencies'][] = $core_dependencies;
+  }
+  if (!empty($contrib_dependencies)) {
+    $profile_info['info']['dependencies'][] = _drush_make_profile_comment("Contrib Extensions");
+    $profile_info['info']['dependencies'][] = $contrib_dependencies;
+  }
+  if (!empty($custom_dependencies)) {
+    $profile_info['info']['dependencies'][] = _drush_make_profile_comment("Custom Extensions");
+    $profile_info['info']['dependencies'][] = $custom_dependencies;
+  }
+
+  // Put in a dump of $projects and $all_extensions for debugging purposes.
+  $profile_info['@profile.debug']['dependencies'] = _drush_make_profile_var_debug($profile_info['info']['dependencies'], 'dependencies');
+  $profile_info['@profile.debug']['all_projects'] = _drush_make_profile_var_debug($projects, 'projects');
+  $profile_info['@profile.debug']['all_libraries'] = _drush_make_profile_var_debug($libraries, 'libraries');
+  $profile_info['@profile.debug']['all_extensions'] = _drush_make_profile_var_debug($all_extensions, 'extensions');
+
+  $destination = drush_get_option('destination', $profile_name);
+  // Store the profile at $destination_absolute_path
+  $destination_absolute_path = $destination;
+  if (!drush_is_absolute_path($destination_absolute_path)) {
+    $cwd = drush_get_context('DRUSH_OLDCWD', NULL);
+    if (!isset($cwd)) {
+      $cwd = getcwd();
+    }
+    $destination_absolute_path = $cwd . '/' . $destination_absolute_path;
+  }
+  $profile_info['info']['#destination_absolute_path'] = $destination_absolute_path;
+
+  // First, check to see if the user specified a --git url
+  $git_url = drush_get_option('git', FALSE);
+  // Grab the git origin from $destination if it is a repo
+  // TODO: use git remote show origin too.  We might want to commit even if user
+  // did provide --git=url if the destination is a repo.
+  if (!is_string($git_url) && is_dir($destination)) {
+    $ok = drush_shell_cd_and_exec($destination, 'git rev-parse --git-dir 2> /dev/null');
+    if ($ok) {
+      $output = drush_shell_exec_output();
+      drush_print_r($output);
+      if (!empty($output)) {
+        $git_url = $output[0];
+        $final_actions[] = '_drush_generate_profile_commit_to_git_repository';
+      }
+    }
+  }
+
+  // Split our makefile into two parts.  The 'bootstrap' makefile
+  // will contain Drupal core plus the profile we are generating; the
+  // other makefile will be fore the profile itself.
+  $bootstrap_projects = array();
+  $bootstrap_projects['drupal'] = $projects['drupal'];
+  unset($projects['drupal']);
+  $bootstrap_projects[$profile_name]['type'] =
+  $bootstrap_projects[$profile_name]['_type'] = 'profile';
+  // If the user passed --git, then make a new repository at the destination
+  if ($git_url === TRUE) {
+    $bootstrap_projects[$profile_name]['download][type'] = 'git';
+    $bootstrap_projects[$profile_name]['download][revision'] = 'master';
+    $bootstrap_projects[$profile_name]['download][url'] = $destination_absolute_path;
+    $final_actions[] = '_drush_generate_profile_create_git_repository';
+    $final_actions[] = '_drush_generate_profile_commit_to_git_repository';
+  }
+  // If we have a git url, then pull the profile from there.
+  elseif (!empty($git_url)) {
+    $bootstrap_projects[$profile_name]['download][type'] = 'git';
+    $bootstrap_projects[$profile_name]['download][revision'] = 'master';
+    $bootstrap_projects[$profile_name]['download][url'] = $git_url;
+  }
+  else {
+    // With http://drupal.org/node/1232466, we could copy from the filesystem
+    $bootstrap_projects[$profile_name]['download][type'] = 'get';
+    $bootstrap_projects[$profile_name]['download][url'] = 'file://' . $destination_absolute_path;
+  }
+
+  // If there are any projects in the makefile that have no source URL,
+  // then we will copy them into the generated profile
+  foreach ($projects as $name => $project) {
+    if (isset($project['custom_download'])) {
+      // TODO: perhaps there should be an option that allows the caller to
+      // leave some of the custom download projects in the makefile.
+      $type = $project['type'];
+      if (array_key_exists($name, $all_extensions)) {
+        // TODO: if there is more than one module per project, we must
+        // first separate them by project, and process each prject
+        // individually.
+        $project = array_key_exists('project', $all_extensions[$name]->info) ? $all_extensions[$name]->info['project'] : $name;
+        $dir = $type . "s";
+        $dest = $dir . '/' . $project;
+        /*
+        // TODO: we need project info to get the correct path.
+        $src = DRUPAL_ROOT . '/sites/all/' . $type . 's/' . $name;
+        */
+        $src = DRUPAL_ROOT . '/' . dirname($all_extensions[$name]->filename);
+        $profile_info[$dest] = _drush_make_generate_profile_copy_files($src);
+        // Now that we have made this project part of the generated profile,
+        // remove it from the makefile.
+        unset($projects[$name]);
+      }
+    }
+  }
+
+  // TODO:  call a pre-generate alter hook here
+
+  // Create a bootstrap makefile if we have any bootstrap projects; otherwise,
+  // make only a regular makefile.  n.b. we always generate a bootstrap makefile
+  if (!empty($bootstrap_projects)) {
+    _drush_make_generate_profile_file($profile_info, "@profile.make.bootstrap", _drush_make_generate_makefile_contents($bootstrap_projects));
+  }
+  _drush_make_generate_profile_file($profile_info, "@profile.make", _drush_make_generate_makefile_contents($projects, $libraries));
+
+  // Set up the rest of our template replacement patterns
+  foreach ($profile_info['info'] as $name => $value) {
+    if ($name{0} == '#') {
+      $name = substr($name,1);
+    }
+    if (!is_array($value)) {
+      $profile_info['#template-replacements']['{$PROFILE_INFO_' . strtoupper($name) . '}'] = $value;
+    }
+  }
+
+  // Generate the template-based files that are NOT listed in the files[]
+  // section of the .info file.
+  $template_list = array(
+    'README.txt' => 'README',
+    '@profile.install' => 'profilename.install',
+  );
+  foreach ($template_list as $output_filename => $template_name) {
+    _drush_make_generate_profile_file($profile_info, $output_filename, _drush_make_generate_profile_template($profile_info, $template_name));
+  }
+  // Next, generate those template-based files that ARE listed in files[]
+  $template_list = array(
+    '@profile.profile' => 'profilename.profile',
+  );
+  foreach ($template_list as $output_filename => $template_name) {
+    _drush_make_generate_profile_add_file($profile_info, $output_filename, _drush_make_generate_profile_template($profile_info, $template_name));
+  }
+
+  // TODO:  call a post-generate alter hook here
+
+  // Now that we've generated all of the basic info for the
+  // profile files, go ahead and write them all to disk.
+  foreach ($profile_info as $filename => $info) {
+    // Every entry in $profile_info that does not start with a '#'
+    // will generate a file to write into the profile
+    if ($filename{0} != '#') {
+      $filename = _drush_make_generate_profile_transform_filename($profile_info, $filename);
+      $dir = $destination_absolute_path;
+      if (array_key_exists('#dir', $info)) {
+        $dir .= (empty($dir) ? '' : '/') . $info['#dir'];
+      }
+      $filename = $dir . (empty($dir) ? '' : '/')  . $filename;
+      if (!is_dir(dirname($filename))) {
+        drush_mkdir(dirname($filename));
+      }
+      $contents = _drush_make_profile_render_file($profile_info, $filename, $info);
+      // If any contents were generated, then we will write the file.  If
+      // there are no contents, do nothing.
+      if (!empty($contents)) {
+        file_put_contents($filename, trim($contents));
+      }
+    }
+  }
+
+  // TODO: call a post-write alter hook here
+
+  // Do any final actions
+  foreach ($final_actions as $action) {
+    if (function_exists($action)) {
+      $action($profile_info);
+    }
+  }
+}
+
+function _drush_generate_profile_create_git_repository($profile_info) {
+  $dir = $profile_info['info']['#destination_absolute_path'];
+  $ok = drush_shell_cd_and_exec($dir, 'git init');
+}
+
+function _drush_generate_profile_commit_to_git_repository($profile_info) {
+  $dir = $profile_info['info']['#destination_absolute_path'];
+  $ok = drush_shell_cd_and_exec($dir, 'git add .');
+  $ok = drush_shell_cd_and_exec($dir, 'git commit -m "Commit profile created by Drush generate-profile."');
+}
+
+function _drush_make_profile_section_data_keys_numeric($data) {
+  if (!is_array($data) || empty($data)) {
+    return FALSE;
+  }
+  foreach ($data as $key => $value) {
+    if (!is_numeric($key) || !is_array($value)) {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+function _drush_make_profile_render_file($profile_info, $filename, $info) {
+  if (array_key_exists('#op', $info)) {
+    $info = array($info);
+  }
+  foreach ($info as $section => $data) {
+    $section_data = _drush_make_profile_render_section($profile_info, $filename, $section, $data);
+    if (!empty($section_data)) {
+      if (!array_key_exists('#contents', $info)) {
+        $info['#contents'] = '';
+      }
+      $info['#contents'] .= $section_data;
+    }
+  }
+  return array_key_exists('#contents', $info) ? $info['#contents'] : '';
+}
+
+function _drush_make_profile_render_section($profile_info, $filename, $section, $data) {
+  $section_data = '';
+  $op = '';
+
+  //
+  // "Special" ops:  we want to be able to do both of these
+  // things:
+  //
+  //   $profile_info[$dest] = array( '@op' => ... )
+  //
+  //     - or -
+  //
+  //   $profile_info[$dest][1] = array( '@op' => ... )
+  //   $profile_info[$dest][2] = array( '@op' => ... )
+  //
+  // Check for an op of the second type here.
+  //
+  if (_drush_make_profile_section_data_keys_numeric($data)) {
+    foreach ($data as $numeric_key => $data_subsection) {
+      $section_data .= _drush_make_profile_render_section($profile_info, $filename, $section, $data_subsection);
+    }
+  }
+  else {
+    //
+    // If the section name begins with a '@' then it is an
+    // operation.
+    //
+    if ($section{0} == '@') {
+      $op = substr($section, 1);
+      $section = "#$op";
+    }
+    //
+    // If the contents contains an '#op', then use that as
+    // the operation name.
+    //
+    elseif (is_array($data) && array_key_exists('#op', $data)) {
+      $op = $data['#op'];
+    }
+    //
+    // Supported operations:
+    //
+    //     'copy_files'
+    //       '#src' - path to copy
+    //       (destination is the profile info filename, so it
+    //       is an error to have anything else in a profile file
+    //       that uses the 'copy_files' op.)
+    //
+    //     'comment'
+    //       '#data' - string or section array to place in the file
+    //       '#comment-start' - sequence of characters to put at beginning
+    //         of each comment line
+    //
+    //     'var_export'
+    //       '#data' - an array to export as a php variable
+    //       '#name' - make a php assignment using the given name
+    //
+    //     'var_debug'
+    //       Works just like 'var_export', but emits data in a comment
+    //
+    // The return value from these operations are processed as
+    // described below.  Return an empty array to write nothing,
+    // a string literal to write exactly that string into the
+    // file, and array('#section' => keyword, '#datay' => array(...))
+    // to process a section as described below.
+    //
+    if (!empty($op)) {
+      $function = '_drush_make_generate_profile_op_' . $op;
+      if (function_exists($function . '_d' . $profile_info['info']['#major'])) {
+        $function .= '_d' . $profile_info['info']['#major'];
+      }
+      elseif (!function_exists($function)) {
+        $function = NULL;
+      }
+      if (isset($function)) {
+        $data = $function($profile_info, $filename, $section, $data);
+      }
+    }
+    //
+    // There are a few different forms we support.
+    //
+    // 'keyword' => 'data' generates:
+    // "keyword = data"
+    //
+    // 'keyword' => array('data1', 'data2') generates:
+    // keyword[] = data1
+    // keyword[] = data2
+    //
+    // 'id' => array('#section' => 'keyword', '#contents' => array('data1', 'data2')) generates:
+    // keyword[] = data1
+    // keyword[] = data2
+    //
+    // 'keyword' => array('#contents' => 'data') generates:
+    // data
+    //
+    // '#keyword' => 'data' is ignored.
+    //
+    // 'keyword' => array('#op' => function_name) will
+    // call the named function, if it exists, passing the
+    // keyword (section name) and data as parameters.  The
+    // return value should be an array that will be processed
+    // as described above.
+    //
+    // First check to see if there is a '#section' or '#data'
+    // element in our contents array, and if so, replace $section
+    // and $contents appropriately.
+    //
+    $contents = FALSE;
+    if (is_array($data)) {
+      if (array_key_exists('#contents', $data)) {
+        $contents = $data['#contents'];
+        $section = "#$section";
+      }
+      if (is_array($data) && array_key_exists('#section', $data)) {
+        $section = $data['#section'];
+      }
+    }
+    //
+    // If we have a valid section name, then emit the contents
+    // in as "keyword = data" or "keyword[] = data" as appropriate.
+    //
+    if ($section{0} != '#') {
+      if (is_string($data)) {
+        $section_data = "\n" . $section . ' = ' . $data;
+      }
+      elseif (is_array($data)) {
+        foreach ($data as $line) {
+          /*if (is_array($line)) {
+            drush_print_r($line);
+          }
+          else*/if (!empty($line) && !is_array($line) && ($line[0] != '#')) {
+            $section_data .= "\n" . $section . '[] = ' . $line;
+          }
+        }
+      }
+    }
+    // If there is no section name, then put the contents in
+    // literally
+    else {
+      if (is_string($contents)) {
+        $section_data = "\n" . $contents;
+      }
+      elseif (is_array($contents)) {
+        $section_data = "\n# data for $section is an array: " . var_export($contents,TRUE);
+      }
+    }
+  }
+  return $section_data;
+}
+
+function _drush_make_generate_profile_ordered_modules($extension_list, $extensions, $already_included = array()) {
+  $result = array();
+  foreach ($extension_list as $key) {
+    _drush_make_generate_profile_ordered_modules_fn($result, $key, $extensions, $already_included);
+  }
+  return $result;
+}
+
+function _drush_make_generate_profile_ordered_modules_fn(&$result, $key, $extensions, $already_included = array()) {
+  if (array_key_exists($key, $extensions) && (!array_key_exists('required', $extensions[$key]->info)) && ($extensions[$key]->type == 'module')) {
+    if (!in_array($key, $result) && !in_array($key, $already_included)) {
+      $already_included[] = $key;
+      if (array_key_exists('dependencies', $extensions[$key]->info)) {
+        foreach ($extensions[$key]->info['dependencies'] as $dependant) {
+          _drush_make_generate_profile_ordered_modules_fn($result, $dependant, $extensions, $already_included);
+        }
+      }
+      $result[] = $key;
+    }
+  }
+}
+
+// Usage: $profile_info[$dest] = _drush_make_generate_profile_copy_files($src);
+function _drush_make_generate_profile_copy_files($src) {
+  return array(
+    '#op' => 'copy_files',
+    '#src' => $src,
+  );
+}
+
+// Usage: $profile_info[$dest]['variable_name'] = _drush_make_profile_var_export($variable_data, 'variable_name');
+function _drush_make_profile_var_export($data, $name = NULL) {
+  $result = array(
+    '#op' => 'var_export',
+    '#data' => $data,
+  );
+  if (isset($name)) {
+    $result['#name'] = $name;
+  }
+  return $result;
+}
+
+// Usage: $profile_info[$dest]['variable_name'] = _drush_make_profile_var_debug($variable_data, 'variable_name');
+function _drush_make_profile_var_debug($data, $name = NULL, $comment_start = '# ') {
+  return _drush_make_profile_comment(_drush_make_profile_var_export($data, $name), $comment_start);
+}
+
+function _drush_make_profile_comment($comment, $comment_start = '# ') {
+  return array(
+    '#op' => 'comment',
+    '#data' => $comment,
+    '#comment-start' => $comment_start,
+  );
+}
+
+function _drush_make_generate_profile_op_comment($profile_info, $filename, $section, $contents) {
+  $data = $contents['#data'];
+  $comment_start = $contents['#comment-start'];
+  if (is_array($data)) {
+    $data = _drush_make_profile_render_section($profile_info, $filename, $section, $data);
+  }
+  $data_lines = explode("\n", $data);
+  $reassembled_data = implode("\n$comment_start", $data_lines);
+  return array('#contents' => "\n# " . $reassembled_data);
+}
+
+function _drush_make_generate_profile_op_copy_files($profile_info, $filename, $section, $contents) {
+  // TODO: decide if $overwrite should be TRUE, FALSE, or array_key_exists('#overwrite', $contents).
+  // Overwrite TRUE is convenient if re-creating a profile over an existing profile -- particularly
+  // appropriate if the destination is a git repository.
+  $overwrite = TRUE;
+  drush_copy_dir($contents['#src'], $filename, $overwrite);
+  return array();
+}
+
+function _drush_make_generate_profile_op_var_export($profile_info, $filename, $section, $contents) {
+  $section_data = "";
+  if ($section{0} != '#') {
+    $section_data .= "\n#\n# Export of '$section':\n#";
+  }
+  $variable_assignment = array_key_exists('#name', $contents) ? '$' . $contents['#name'] . ' = ' : '';
+  $exported_data = $variable_assignment . var_export($contents['#data'], TRUE);
+  return array('#contents' => $exported_data);
+}
+
+function _drush_make_generate_profile_transform_filename(&$profile_info, $name) {
+  $name_replacements = $profile_info['#filename-replacements'];
+  return str_replace(array_keys($name_replacements), array_values($name_replacements), $name);
+}
+
+function _drush_make_generate_profile_file(&$profile_info, $name, $data) {
+  if (!empty($data)) {
+    if (!is_array($data)) {
+      $data = array('#contents' => $data);
+    }
+    $profile_info[$name] = $data;
+  }
+}
+
+function _drush_make_generate_profile_add_file(&$profile_info, $name, $data) {
+  if (!empty($data)) {
+    _drush_make_generate_profile_file($profile_info, $name, $data);
+    $profile_info['info']['files'][] = _drush_make_generate_profile_transform_filename($profile_info, $name);
+  }
+}
+
+function _drush_make_generate_profile_template($profile_info, $template_name) {
+  $template_base = dirname(__FILE__) . '/templates/' . $template_name;
+  $version_variant = '_d' . $profile_info['info']['#major'];
+  $template_contents = '';
+  $template_file = '';
+  foreach (array($version_variant, '') as $variant) {
+    $candidate_file = $template_base . $variant . '.tmpl';
+    if (empty($template_file) && file_exists($candidate_file)) {
+      $template_file = $candidate_file;
+    }
+  }
+  if (!empty($template_file)) {
+    $template_contents = file_get_contents($template_file);
+    $template_replacements = $profile_info['#template-replacements'];
+    return str_replace(array_keys($template_replacements), array_values($template_replacements), $template_contents);
+  }
+  return $template_contents;
+}
diff --git a/commands/make/make.download.inc b/commands/make/make.download.inc
index dbf3c3d..4ef8245 100644
--- a/commands/make/make.download.inc
+++ b/commands/make/make.download.inc
@@ -65,7 +65,15 @@ function make_download_pm($name, $download, $download_location) {
  *   The destination directory on success, FALSE on failure.
  */
 function make_download_file($name, $download, $download_location, $cache_duration = DRUSH_CACHE_LIFETIME_DEFAULT) {
-  if ($filename = _make_download_file($download['url'], $cache_duration)) {
+  // If 'type' is 'get' and 'url' points to an existing directory on
+  // the local filesystem rather than to a local or remote .tar.gz file,
+  // then we will simply copy the target to the desired location.
+  if (is_dir($download['url'])) {
+    if (drush_copy_dir($download['url'], $download_location, TRUE)) {
+      return TRUE;
+    }
+  }
+  elseif ($filename = _make_download_file($download['url'], $cache_duration)) {
     if (!drush_get_option('ignore-checksums') && !_make_verify_checksums($download, $filename)) {
       return FALSE;
     }
diff --git a/commands/make/make.drush.inc b/commands/make/make.drush.inc
index 848187f..63a0091 100644
--- a/commands/make/make.drush.inc
+++ b/commands/make/make.drush.inc
@@ -90,7 +90,6 @@ function make_drush_command() {
     'engines' => array('release_info'),
     'aliases' => array('generate-makefile'),
   );
-
   // Hidden command to build a single project.
   $items['make-process'] = array(
     'hidden' => TRUE,
@@ -103,6 +102,21 @@ function make_drush_command() {
     'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
     'engines' => array('release_info'),
   );
+  $items['profile-generate'] = array(
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
+    'description' => 'Generate an installation profile from the current Drupal site.',
+    'examples' => array(
+      'drush generate-profile example-profile' => 'Generate an installation profile called example-profile.',
+    ),
+    'options' => array(
+      'description' => 'Description of the profile, for the profile.info file.',
+      'destination' => 'Directory to write the profile. Defaults to the profile name.',
+      'base-profile' => 'Profile to inherit from, usually "minimal" or "standard". Defaults to "minimal".',
+    ),
+    'aliases' => array('generate-profile'),
+    'allow-additional-options' => 'make-generate',
+    'engines' => array('release_info'),
+  );
 
   // Add docs topic.
   $docs_dir = drush_get_context('DOC_PREFIX', DRUSH_BASE_PATH);
diff --git a/commands/make/templates/README_d7.tmpl b/commands/make/templates/README_d7.tmpl
new file mode 100644
index 0000000..b9a1cac
--- /dev/null
+++ b/commands/make/templates/README_d7.tmpl
@@ -0,0 +1,11 @@
+This installation profile was created via the Drush generate-profile
+command.  To use it:
+
+    drush make {$PROFILE}.make.bootstrap /web/path/{$PROFILE}
+    cd /web/path/{$PROFILE}
+    drush site-install {$PROFILE} --yes --sites-subdir=default --db-url=PUT_YOUR_DB_SPEC_HERE --db-su=DBUSER --db-su-pw=DBPASSWORD --account-name=admin --account-pass=secretsecret
+
+To view your site in a web browser:
+
+    cd sites/default
+    drush runserver /
diff --git a/commands/make/templates/profilename.install_d7.tmpl b/commands/make/templates/profilename.install_d7.tmpl
new file mode 100644
index 0000000..374a6b6
--- /dev/null
+++ b/commands/make/templates/profilename.install_d7.tmpl
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * Implement hook_install().
+ *
+ * Perform actions to set up the site for this profile.
+ */
+function {$PROFILE}_install() {
+  include_once DRUPAL_ROOT . "/profiles/{$PROFILE_INFO_BASE_PROFILE}/{$PROFILE_INFO_BASE_PROFILE}.install";
+  {$PROFILE_INFO_BASE_PROFILE}_install();
+}
diff --git a/commands/make/templates/profilename.profile_d7.tmpl b/commands/make/templates/profilename.profile_d7.tmpl
new file mode 100644
index 0000000..12efb68
--- /dev/null
+++ b/commands/make/templates/profilename.profile_d7.tmpl
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Allows the profile to alter the site configuration form.
+ */
+function {$PROFILE}_form_install_configure_form_alter(&$form, $form_state) {
+  // Pre-populate the site name with the server name.
+  $form["site_information"]["site_name"]["#default_value"] = $_SERVER["SERVER_NAME"];
+}
