Index: release/package-release-nodes.php
===================================================================
RCS file: /Users/wright/drupal/local_repo/contributions/modules/project/release/package-release-nodes.php,v
retrieving revision 1.68
diff -u -p -r1.68 package-release-nodes.php
--- release/package-release-nodes.php	30 Jul 2010 20:42:27 -0000	1.68
+++ release/package-release-nodes.php	13 Nov 2010 01:33:18 -0000
@@ -79,6 +79,7 @@ $dest_rel = 'files/projects';
 // the script will find these tools in your PATH.
 $tar = '/usr/bin/tar';
 $gzip = '/usr/bin/gzip';
+$zip = '/usr/bin/zip';
 $cvs = '/usr/bin/cvs';
 $ln = '/bin/ln';
 $rm = '/bin/rm';
@@ -314,7 +315,7 @@ function package_releases($type, $projec
 
 function package_release_core($type, $nid, $project_short_name, $version, $tag) {
   global $tmp_dir, $repositories, $dest_root, $dest_rel;
-  global $cvs, $tar, $gzip, $rm;
+  global $cvs, $tar, $gzip, $zip, $rm;
 
   if (!drupal_chdir($tmp_dir)) {
     return 'error';
@@ -324,6 +325,8 @@ function package_release_core($type, $ni
   $release_node_view_link = l(t('view'), 'node/' . $nid);
   $file_path_tgz = $dest_rel . '/' . $release_file_id . '.tar.gz';
   $full_dest_tgz = $dest_root . '/' . $file_path_tgz;
+  $file_path_zip = $dest_rel . '/' . $release_file_id . '.zip';
+  $full_dest_zip = $dest_root . '/' . $file_path_zip;
 
   // Remember if the tar.gz version of this release file already exists.
   $tgz_exists = is_file($full_dest_tgz);
@@ -353,12 +356,19 @@ function package_release_core($type, $ni
     }
   }
 
+  convert_line_endings("$tmp_dir/$release_file_id", 'UNIX');
   if (!drupal_exec("$tar -c --file=- $release_file_id | $gzip -9 --no-name > $full_dest_tgz")) {
     return 'error';
   }
   $files[] = $file_path_tgz;
 
-  // As soon as the tarball exists, we want to update the DB about it.
+  convert_line_endings("$tmp_dir/$release_file_id", 'DOS');
+  if (!drupal_exec("$zip -rq $full_dest_zip $release_file_id")) {
+    return 'error';
+  }
+  $files[] = $file_path_zip;
+
+  // As soon as the files exist, we want to update the DB about it.
   package_release_update_node($nid, $files);
 
   if ($tgz_exists) {
@@ -375,7 +385,7 @@ function package_release_core($type, $ni
 
 function package_release_contrib($type, $nid, $project_short_name, $version, $tag, $release_dir) {
   global $tmp_dir, $repositories, $dest_root, $dest_rel;
-  global $cvs, $tar, $gzip, $rm, $ln;
+  global $cvs, $tar, $gzip, $zip, $rm, $ln;
   global $drush, $drush_make_dir;
   global $license, $trans_install;
 
@@ -395,6 +405,8 @@ function package_release_contrib($type, 
   $release_node_view_link = l(t('view'), 'node/' . $nid);
   $file_path_tgz = $dest_rel . '/' . $release_file_id . '.tar.gz';
   $full_dest_tgz = $dest_root . '/' . $file_path_tgz;
+  $file_path_zip = $dest_rel . '/' . $release_file_id . '.zip';
+  $full_dest_zip = $dest_root . '/' . $file_path_zip;
 
   // Remember if the tar.gz version of this release file already exists.
   $tgz_exists = is_file($full_dest_tgz);
@@ -438,8 +450,10 @@ function package_release_contrib($type, 
     return 'error';
   }
   // Do we want a subdirectory in the tarball or not?
+  $is_translation = FALSE;
   $tarball_needs_subdir = TRUE;
   if ($contrib_type == 'translations' && $project_short_name != 'drupal-pot') {
+    $is_translation = TRUE;
     // Translation projects are packaged differently based on core version.
     if (intval($version) > 5) {
       if (!($to_tar = package_release_contrib_d6_translation($project_short_name, $version, $release_node_view_link))) {
@@ -464,12 +478,21 @@ function package_release_contrib($type, 
     }
   }
 
+  convert_line_endings("$tmp_dir/$release_file_id", 'UNIX');
   // 'h' is for dereference, we want to include the files, not the links
   if (!drupal_exec("$tar -ch --file=- $to_tar | $gzip -9 --no-name > $full_dest_tgz")) {
     return 'error';
   }
   $files[] = $file_path_tgz;
 
+  if (!$is_translation) { 
+    convert_line_endings("$tmp_dir/$release_file_id", 'DOS');
+    if (!drupal_exec("$zip -rq $full_dest_zip $to_tar")) {
+      return 'error';
+    }
+    $files[] = $file_path_zip;
+  }
+
   // Start with no package contents, since this is only valid for profiles.
   $package_contents = array();
 
@@ -519,9 +542,12 @@ function package_release_contrib($type, 
         // NO-CORE DISTRIBUTION.
 
         $no_core_id = "$release_file_id-no-core";
-        // Build the drupal file path and the full file path.
-        $no_core_file_path = "$dest_rel/$no_core_id.tar.gz";
-        $no_core_full_dest = "$dest_root/$no_core_file_path";
+
+        // Build the drupal file path and the full file path for tgz and zip.
+        $no_core_file_path_tgz = "$dest_rel/$no_core_id.tar.gz";
+        $no_core_full_dest_tgz = "$dest_root/$no_core_file_path_tgz";
+        $no_core_file_path_zip = "$dest_rel/$no_core_id.zip";
+        $no_core_full_dest_zip = "$dest_root/$no_core_file_path_zip";
 
         // Run drush_make to build the profile's contents.
         // --drupal-org: Invoke drupal.org specific validation/processing.
@@ -550,11 +576,18 @@ function package_release_contrib($type, 
         }
 
         // Package the no-core distribution.
+        convert_line_endings($project_short_name, 'UNIX');
         // 'h' is for dereference, we want to include the files, not the links
-        if (!drupal_exec("$tar -ch --file=- $project_short_name | $gzip -9 --no-name > $no_core_full_dest")) {
+        if (!drupal_exec("$tar -ch --file=- $project_short_name | $gzip -9 --no-name > $no_core_full_dest_tgz")) {
+          return 'error';
+        }
+        $files[] = $no_core_file_path_tgz;
+
+        convert_line_endings($project_short_name, 'ZIP');
+        if (!drupal_exec("$zip -rq $no_core_full_dest_tgz $project_short_name")) {
           return 'error';
         }
-        $files[] = $no_core_file_path;
+        $files[] = $no_core_file_path_zip;
 
         // CORE DISTRIBUTION.
 
@@ -577,16 +610,26 @@ function package_release_contrib($type, 
         }
 
         $core_id = "$release_file_id-core";
-        // Build the drupal file path and the full file path.
-        $core_file_path = "$dest_rel/$core_id.tar.gz";
-        $core_full_dest = "$dest_root/$core_file_path";
+
+        // Build the drupal file path and the full file path for tgz and zip.
+        $core_file_path_tgz = "$dest_rel/$core_id.tar.gz";
+        $core_full_dest_tgz = "$dest_root/$core_file_path_tgz";
+        $core_file_path_zip = "$dest_rel/$core_id.zip";
+        $core_full_dest_zip = "$dest_root/$core_file_path_zip";
 
         // Package the core distribution.
+        convert_line_endings($core_build_dir, 'UNIX');
         // 'h' is for dereference, we want to include the files, not the links
-        if (!drupal_exec("$tar -ch --file=- $core_build_dir | $gzip -9 --no-name > $core_full_dest")) {
+        if (!drupal_exec("$tar -ch --file=- $core_build_dir | $gzip -9 --no-name > $core_full_dest_tgz")) {
           return 'error';
         }
-        $files[] = $core_file_path;
+        $files[] = $core_file_path_tgz;
+
+        convert_line_endings($core_build_dir, 'ZIP');
+        if (!drupal_exec("$zip -rq $core_full_dest_zip $core_build_dir")) {
+          return 'error';
+        }
+        $files[] = $core_file_path_zip;
 
         // Development releases may have changed package contents -- clear out
         // their package item summary so a fresh item summary will be inserted.
@@ -606,6 +649,7 @@ function package_release_contrib($type, 
         // Retrieve the package contents for the release.
         $package_contents_file = "$project_build_root/package_contents.txt";
         if (file_exists($package_contents_file)) {
+          convert_file($package_contents_file, 'UNIX');
           $lines = file($package_contents_file, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
           foreach ($lines as $line) {
             if (is_numeric($line)) {
@@ -624,7 +668,7 @@ function package_release_contrib($type, 
     }
   }
 
-  // As soon as the tarball exists, update the DB
+  // Now that all the files exist, update the DB about them.
   package_release_update_node($nid, $files, $package_contents);
 
   if ($tgz_exists) {
@@ -1217,6 +1261,126 @@ function translation_number_of_strings($
   return $number_of_strings[$version];
 }
 
+
+// ------------------------------------------------------------
+// Functions: Line ending conversion
+// ------------------------------------------------------------
+
+
+/**
+ * Recursively convert line endings on all text files in a directory tree.
+ *
+ * @param $dir
+ *   The root of the directory tree to traverse.
+ * @param $target_type
+ *   The kind of line endings to convert the files to (can be 'UNIX' or 'DOS').
+ * @param $exclude
+ *   Optional array of filenames to exclude.
+ */
+function convert_line_endings($dir, $target_type, $exclude = array('.', '..')) {
+  if (is_dir($dir)) {
+    $fp = opendir($dir);
+    while (FALSE !== ($file = readdir($fp))) {
+      if (!in_array($file, $exclude)) {
+        $full_path = "$dir/$file";
+        if (is_dir($full_path)) {
+          convert_line_endings($full_path, $target_type, $exclude);
+        }
+        elseif (needs_line_ending_conversion($full_path)) {
+          convert_file($full_path, $target_type);
+        }
+      }
+    }
+    closedir($fp);
+  }
+}
+ 
+/**
+ * Helper function that decides if a given file needs line ending conversion.
+ *
+ * @param $filename
+ *   Full path to the file to test.
+ * @param $whitelist
+ *   Optional array of filename extensions to always convert.
+ * @param $blacklist
+ *   Optional array of filename extensions to never convert.
+ *
+ * @return
+ *   TRUE if the file should have line endings converted, otherwise FALSE.
+ */
+function needs_line_ending_conversion($filename, $whitelist = array('info'), $blacklist = array()) {
+  $path_info = pathinfo($filename);
+  if (in_array($path_info['extension'], $blacklist)) {
+    return FALSE;
+  }
+  if (in_array($path_info['extension'], $whitelist)) {
+    return TRUE;
+  }
+
+  // If we don't know explicitly from the file extension, try the mime_type.
+  $mime_type = file_get_mimetype($filename);
+  $mime_parts = split('/', $mime_type);
+
+  // text/* should always be converted
+  if ($mime_parts[0] == 'text') {
+    return TRUE;
+  }
+  // Otherwise, check the 2nd part of the mime_type.
+  switch ($mime_parts[1]) {
+    case 'x-httpd-php':
+    case 'x-httpd-php-source':
+    case 'x-httpd-php3':
+    case 'x-httpd-php3-preprocessed':
+    case 'x-httpd-php4':
+    case 'x-httpd-php5':
+    case 'x-httpd-php6':
+    case 'x-javascript':
+    case 'xml':
+      return TRUE;
+  }
+  // Otherwise, better be safe and not convert.
+  return FALSE;
+}
+
+/**
+ * Converts line endings on a single file to the requested target file type.
+ *
+ * @param $file
+ *   Full path to the file to convert.
+ * @param $target_type
+ *   The kind of line endings to convert the file to (can be 'UNIX' or 'DOS').
+ */
+function convert_file($file, $target_type) {
+  rename($file, "$file.convert-orig");
+  $data = file_get_contents("$file.convert-orig");
+  if ($target_type == 'UNIX') {
+    // Converting to UNIX is easy, since we just want everything to end with a
+    // single "\n".  So, we convert "\r\n" (DOS) to "\n", then any single "\r"
+    // (Mac) and we're done.  If the file is already UNIX endings, these are
+    // no-ops.
+    $data = str_replace(array("\r\n", "\r"), "\n", $data);
+  }
+  elseif ($target_type == 'DOS') {
+    // Converting to DOS is more complicated.  If the file already has DOS
+    // line endings, the attempts to replace UNIX or Mac would break them.
+    // Therefore, we first convert any existing DOS line endings ("\r\n") to
+    // UNIX ("\n").
+    $data = str_replace("\r\n", "\n", $data);
+    // After that, we can replace either UNIX ("\n") or Mac ("\r") with DOS:
+    $trans = array(
+      "\n" => "\r\n",
+      "\r" => "\r\n",
+    );
+    $data = strtr($data, $trans);
+  }
+  file_put_contents($file, $data);
+  unlink("$file.convert-orig");
+}
+
+// ------------------------------------------------------------
+// Functions: Packaged distribution helper funcitons
+// ------------------------------------------------------------
+
 /**
  * Construct a .make file which will build Drupal core.
  *
