From d2fcbba230d222d6419c89a20e9f7bf711e10b6b Mon Sep 17 00:00:00 2001 From: "kenton@google.com" Date: Mon, 4 Jan 2010 19:47:18 +0000 Subject: Improve zip/jar support: - Don't support par or war since par is not a standard format and outputting to war doesn't make sense. - Add boilerplate manifest when outputting to Jar. - Remove "XXX check conversion" comments because I don't care. - Add a test. --- .../protobuf/compiler/command_line_interface.cc | 20 ++++- .../protobuf/compiler/zip_output_unittest.sh | 85 ++++++++++++++++++++++ src/google/protobuf/compiler/zip_writer.cc | 15 ++-- 3 files changed, 108 insertions(+), 12 deletions(-) create mode 100755 src/google/protobuf/compiler/zip_output_unittest.sh (limited to 'src/google/protobuf/compiler') diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index c266766c..1bc4ce89 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -227,6 +227,7 @@ class CommandLineInterface::MemoryOutputDirectory : public OutputDirectory { bool WriteAllToDisk(const string& prefix); bool WriteAllToZip(const string& filename); + void AddJarManifest(); // implements OutputDirectory -------------------------------------- io::ZeroCopyOutputStream* Open(const string& filename); @@ -393,6 +394,16 @@ bool CommandLineInterface::MemoryOutputDirectory::WriteAllToZip( return true; } +void CommandLineInterface::MemoryOutputDirectory::AddJarManifest() { + string** map_slot = &files_["META-INF/MANIFEST.MF"]; + if (*map_slot == NULL) { + *map_slot = new string( + "Manifest-Version: 1.0\n" + "Created-By: 1.6.0 (protoc)\n" + "\n"); + } +} + io::ZeroCopyOutputStream* CommandLineInterface::MemoryOutputDirectory::Open( const string& filename) { return new MemoryOutputStream(this, filename); @@ -594,11 +605,8 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { if (mode_ == MODE_COMPILE) { for (int i = 0; i < output_directives_.size(); i++) { string output_location = output_directives_[i].output_location; - cout << "location: " << output_location << endl; if (!HasSuffixString(output_location, ".zip") && - !HasSuffixString(output_location, ".jar") && - !HasSuffixString(output_location, ".war") && - !HasSuffixString(output_location, ".par")) { + !HasSuffixString(output_location, ".jar")) { AddTrailingSlash(&output_location); } MemoryOutputDirectory** map_slot = &output_directories_[output_location]; @@ -624,6 +632,10 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { return 1; } } else { + if (HasSuffixString(location, ".jar")) { + directory->AddJarManifest(); + } + if (!directory->WriteAllToZip(location)) { return 1; } diff --git a/src/google/protobuf/compiler/zip_output_unittest.sh b/src/google/protobuf/compiler/zip_output_unittest.sh new file mode 100755 index 00000000..76b24089 --- /dev/null +++ b/src/google/protobuf/compiler/zip_output_unittest.sh @@ -0,0 +1,85 @@ +#!/bin/sh +# +# Protocol Buffers - Google's data interchange format +# Copyright 2009 Google Inc. All rights reserved. +# http://code.google.com/p/protobuf/ +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Author: kenton@google.com (Kenton Varda) +# +# Test protoc's zip output mode. + +function fail() { + echo "$@" >&2 + exit 1 +} + +echo ' + option java_multiple_files = true; + option java_package = "test.jar"; + option java_outer_classname = "Outer"; + message Foo {} + message Bar {} +' > testzip.proto + +./protoc --cpp_out=testzip.zip --python_out=testzip.zip --java_out=testzip.jar \ + testzip.proto || fail 'protoc failed.' + +echo "Testing output to zip..." +if unzip -h > /dev/null; then + unzip -t testzip.zip > testzip.list || fail 'unzip failed.' + + grep 'testing: testzip\.pb\.cc *OK$' testzip.list > /dev/null \ + || fail 'testzip.pb.cc not found in output zip.' + grep 'testing: testzip\.pb\.h *OK$' testzip.list > /dev/null \ + || fail 'testzip.pb.h not found in output zip.' + grep 'testing: testzip_pb2\.py *OK$' testzip.list > /dev/null \ + || fail 'testzip_pb2.py not found in output zip.' + grep -i 'manifest' testzip.list > /dev/null \ + && fail 'Zip file contained manifest.' +else + echo "Warning: 'unzip' command not available. Skipping test." +fi + +echo "Testing output to jar..." +if jar c testzip.proto > /dev/null; then + jar tf testzip.jar > testzip.list || fail 'jar failed.' + + grep '^test/jar/Foo\.java$' testzip.list > /dev/null \ + || fail 'Foo.java not found in output jar.' + grep '^test/jar/Bar\.java$' testzip.list > /dev/null \ + || fail 'Bar.java not found in output jar.' + grep '^test/jar/Outer\.java$' testzip.list > /dev/null \ + || fail 'Outer.java not found in output jar.' + grep '^META-INF/MANIFEST\.MF$' testzip.list > /dev/null \ + || fail 'Manifest not ofund in output jar.' +else + echo "Warning: 'jar' command not available. Skipping test." +fi + +echo PASS diff --git a/src/google/protobuf/compiler/zip_writer.cc b/src/google/protobuf/compiler/zip_writer.cc index 2bb648b0..53c18771 100644 --- a/src/google/protobuf/compiler/zip_writer.cc +++ b/src/google/protobuf/compiler/zip_writer.cc @@ -86,7 +86,6 @@ static const uint32 kCRC32Table[256] = { 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; -// XXX this appears to be broken, but unzip -t accepts it anyway? wtff? static uint32 ComputeCRC32(const string &buf) { uint32 x = ~0U; for (int i = 0; i < buf.size(); ++i) { @@ -111,9 +110,9 @@ bool ZipWriter::Write(const string& filename, const string& contents) { FileInfo info; info.name = filename; - uint16 filename_size = filename.size(); // XXX check conversion - info.offset = raw_output_->ByteCount(); // XXX check conversion - info.size = contents.size(); // XXX check conversion + uint16 filename_size = filename.size(); + info.offset = raw_output_->ByteCount(); + info.size = contents.size(); info.crc32 = ComputeCRC32(contents); files_.push_back(info); @@ -138,14 +137,14 @@ bool ZipWriter::Write(const string& filename, const string& contents) { } bool ZipWriter::WriteDirectory() { - uint16 num_entries = files_.size(); // XXX check conversion - uint32 dir_ofs = raw_output_->ByteCount(); // XXX check conversion + uint16 num_entries = files_.size(); + uint32 dir_ofs = raw_output_->ByteCount(); // write central directory io::CodedOutputStream output(raw_output_); for (int i = 0; i < num_entries; ++i) { const string &filename = files_[i].name; - uint16 filename_size = filename.size(); // XXX check conversion + uint16 filename_size = filename.size(); uint32 crc32 = files_[i].crc32; uint32 size = files_[i].size; uint32 offset = files_[i].offset; @@ -169,7 +168,7 @@ bool ZipWriter::WriteDirectory() { output.WriteLittleEndian32(offset); // local header offset output.WriteString(filename); // file name } - uint32 dir_len = output.ByteCount(); // XXX check conversion + uint32 dir_len = output.ByteCount(); // write end of central directory marker output.WriteLittleEndian32(0x06054b50); // magic -- cgit v1.2.3