Repository: aws/aws-cli

Issue:
[BUG] [aws deploy push] The Destination Bundle Type Does not Perform Compression (Zipping/Tarring)
When specifying a destination with a suffix of ".zip" or ".tar" or ".tar.gz" for use with the `aws deploy push` command ... which are all allowed revisions ... the resulting bundle is not compressed.

Either the extension of the bundle could automatically determine the desired compression or an alternate flag could be specified which determines that the actual file should be compressed using that appropriate mechanism.

I noticed this testing large deployments that  were filling up S3 very fast --- when compressed it would have been not noticeable.

Additionally, directories with no files in them do not appear in the resulting bundle.



Discussion:
Thanks for reporting. We are looking into this.


Resolving patch:
diff --git a/awscli/compat.py b/awscli/compat.py
--- a/awscli/compat.py
+++ b/awscli/compat.py
@@ -12,6 +12,7 @@
 # language governing permissions and limitations under the License.
 import sys
 import os
+import zipfile
 
 from botocore.compat import six
 #import botocore.compat
@@ -26,6 +27,15 @@
 StringIO = six.StringIO
 urlopen = six.moves.urllib.request.urlopen
 
+# Most, but not all, python installations will have zlib. This is required to
+# compress any files we send via a push. If we can't compress, we can still
+# package the files in a zip container.
+try:
+    import zlib
+    ZIP_COMPRESSION_MODE = zipfile.ZIP_DEFLATED
+except ImportError:
+    ZIP_COMPRESSION_MODE = zipfile.ZIP_STORED
+
 
 class BinaryStdout(object):
     def __enter__(self):
diff --git a/awscli/customizations/codedeploy/push.py b/awscli/customizations/codedeploy/push.py
--- a/awscli/customizations/codedeploy/push.py
+++ b/awscli/customizations/codedeploy/push.py
@@ -22,6 +22,7 @@
 from awscli.customizations.codedeploy.utils import validate_s3_location
 from awscli.customizations.commands import BasicCommand
 from awscli.errorhandler import ServerError, ClientError
+from awscli.compat import ZIP_COMPRESSION_MODE
 
 
 ONE_MB = 1 << 20
@@ -199,7 +200,7 @@ def _compress(self, source, ignore_hidden_files=False):
                         arcname = filename[len(source_path) + 1:]
                         if filename == appspec_path:
                             contains_appspec = True
-                        zf.write(filename, arcname)
+                        zf.write(filename, arcname, ZIP_COMPRESSION_MODE)
                 if not contains_appspec:
                     raise RuntimeError(
                         '{0} was not found'.format(appspec_path)


Test patch:
diff --git a/tests/unit/customizations/codedeploy/test_push.py b/tests/unit/customizations/codedeploy/test_push.py
--- a/tests/unit/customizations/codedeploy/test_push.py
+++ b/tests/unit/customizations/codedeploy/test_push.py
@@ -20,6 +20,7 @@
 from awscli.customizations.codedeploy.push import Push
 from awscli.errorhandler import ClientError
 from awscli.testutils import unittest
+from awscli.compat import ZIP_COMPRESSION_MODE
 
 
 class TestPush(unittest.TestCase):
@@ -218,7 +219,8 @@ def test_compress_writes_to_zip_file(self, walk, path, tf, zf):
                 self.args.ignore_hidden_files):
             zf().write.assert_called_with(
                 '/tmp/appspec.yml',
-                self.appspec
+                self.appspec,
+                ZIP_COMPRESSION_MODE
             )
 
     def test_upload_to_s3_with_put_object(self):