Rollback of commit da3cb806351e929becef19652c65d39efa61b9d9.

*** Reason for rollback ***

Breaking builds. []

*** Original change description ***

RELNOTES: actoolzip, momczip and swiftstdlibtoolzip have all been made into bash scripts and have been renamed to actoolwrapper, momcwrapper and swiftstdlibtoolwrapper respectively. The old versions will be deleted in a later change.

--
MOS_MIGRATED_REVID=99742398
diff --git a/.gitignore b/.gitignore
index dc60d27..a9e44e2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,9 +25,6 @@
 /tools/jdk/GenClass_deploy.jar
 /tools/jdk/SingleJar_deploy.jar
 /tools/objc/*.jar
-/tools/objc/actoolwrapper.sh
-/tools/objc/ibtoolwrapper.sh
-/tools/objc/momctoolwrapper.sh
+/tools/objc/ibtoolwrapper
 /tools/objc/realpath
 /tools/objc/StdRedirect.dylib
-/tools/objc/swiftstdlibtoolwrapper.sh
diff --git a/compile.sh b/compile.sh
index b68f343..c863c83 100755
--- a/compile.sh
+++ b/compile.sh
@@ -109,10 +109,13 @@
   bazel_bootstrap //src/java_tools/buildjar/java/com/google/devtools/build/buildjar/genclass:GenClass_deploy.jar \
       tools/jdk/GenClass_deploy.jar
   if [[ $PLATFORM == "darwin" ]]; then
-    bazel_bootstrap //src/tools/xcode/actoolwrapper:actoolwrapper tools/objc/actoolwrapper.sh 0755
-    bazel_bootstrap //src/tools/xcode/ibtoolwrapper:ibtoolwrapper tools/objc/ibtoolwrapper.sh 0755
-    bazel_bootstrap //src/tools/xcode/momcwrapper:momcwrapper tools/objc/momcwrapper.sh 0755
-    bazel_bootstrap //src/tools/xcode/swiftstdlibtoolwrapper:swiftstdlibtoolwrapper tools/objc/swiftstdlibtoolzip.sh 0755
+    bazel_bootstrap //src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip:actoolzip_deploy.jar \
+        tools/objc/precomp_actoolzip_deploy.jar
+    bazel_bootstrap //src/tools/xcode/ibtoolwrapper:ibtoolwrapper tools/objc/ibtoolwrapper 0755
+    bazel_bootstrap //src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip:swiftstdlibtoolzip_deploy.jar \
+        tools/objc/precomp_swiftstdlibtoolzip_deploy.jar
+    bazel_bootstrap //src/objc_tools/momczip:momczip_deploy.jar \
+        tools/objc/precomp_momczip_deploy.jar
     bazel_bootstrap //src/objc_tools/bundlemerge:bundlemerge_deploy.jar \
         tools/objc/precomp_bundlemerge_deploy.jar
     bazel_bootstrap //src/objc_tools/plmerge:plmerge_deploy.jar \
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BundleSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/BundleSupport.java
index 8382ac8..9ace1d3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/BundleSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BundleSupport.java
@@ -200,7 +200,7 @@
       ruleContext.registerAction(
           ObjcRuleClasses.spawnOnDarwinActionBuilder()
               .setMnemonic("StoryboardCompile")
-              .setExecutable(attributes.ibtoolWrapper())
+              .setExecutable(attributes.ibtoolwrapper())
               .setCommandLine(ibActionsCommandLine(archiveRoot, zipOutput, storyboardInput))
               .addOutput(zipOutput)
               .addInput(storyboardInput)
@@ -238,17 +238,15 @@
     for (Xcdatamodel datamodel : xcdatamodels) {
       Artifact outputZip = datamodel.getOutputZip();
       ruleContext.registerAction(
-          ObjcRuleClasses.spawnOnDarwinActionBuilder()
+          ObjcRuleClasses.spawnJavaOnDarwinActionBuilder(attributes.momczipDeployJar())
               .setMnemonic("MomCompile")
-              .setExecutable(attributes.momcWrapper())
               .addOutput(outputZip)
               .addInputs(datamodel.getInputs())
-              // TODO(dmaclach): Adding realpath here should not be required once
-              // https://github.com/google/bazel/issues/285 is fixed.
-              .addInput(attributes.realpath())
               .setCommandLine(CustomCommandLine.builder()
                   .addPath(outputZip.getExecPath())
                   .add(datamodel.archiveRootForMomczip())
+                  .add(IosSdkCommands.MOMC_PATH)
+
                   .add("-XD_MOMC_SDKROOT=" + IosSdkCommands.sdkDir(objcConfiguration))
                   .add("-XD_MOMC_IOS_TARGET_VERSION=" + bundling.getMinimumOsVersion())
                   .add("-MOMC_PLATFORMS")
@@ -271,7 +269,7 @@
       ruleContext.registerAction(
           ObjcRuleClasses.spawnOnDarwinActionBuilder()
               .setMnemonic("XibCompile")
-              .setExecutable(attributes.ibtoolWrapper())
+              .setExecutable(attributes.ibtoolwrapper())
               .setCommandLine(ibActionsCommandLine(archiveRoot, zipOutput, original))
               .addOutput(zipOutput)
               .addInput(original)
@@ -350,15 +348,11 @@
     // zip file will be rooted at the bundle root, and we have to prepend the bundle root to each
     // entry when merging it with the final .ipa file.
     ruleContext.registerAction(
-        ObjcRuleClasses.spawnOnDarwinActionBuilder()
+        ObjcRuleClasses.spawnJavaOnDarwinActionBuilder(attributes.actoolzipDeployJar())
             .setMnemonic("AssetCatalogCompile")
-            .setExecutable(attributes.actoolWrapper())
             .addTransitiveInputs(objcProvider.get(ASSET_CATALOG))
             .addOutput(zipOutput)
             .addOutput(actoolPartialInfoplist)
-            // TODO(dmaclach): Adding realpath here should not be required once
-            // https://github.com/google/bazel/issues/285 is fixed.
-            .addInput(attributes.realpath())
             .setCommandLine(actoolzipCommandLine(
                 objcProvider,
                 zipOutput,
@@ -372,6 +366,9 @@
     CustomCommandLine.Builder commandLine = CustomCommandLine.builder()
         // The next three arguments are positional, i.e. they don't have flags before them.
         .addPath(zipOutput.getExecPath())
+        .add("") // archive root
+        .add(IosSdkCommands.ACTOOL_PATH)
+
         .add("--platform").add(objcConfiguration.getBundlingPlatform().getLowerCaseNameInPlist())
         .addExecPath("--output-partial-info-plist", partialInfoPlist)
         .add("--minimum-deployment-target").add(bundling.getMinimumOsVersion());
@@ -442,7 +439,7 @@
     /**
      * Returns the location of the ibtoolwrapper tool.
      */
-    FilesToRunProvider ibtoolWrapper() {
+    FilesToRunProvider ibtoolwrapper() {
       return ruleContext.getExecutablePrerequisite("$ibtoolwrapper", Mode.HOST);
     }
 
@@ -456,17 +453,17 @@
     }
 
     /**
-     * Returns the location of the momcwrapper.
+     * Returns the location of the momczip deploy jar.
      */
-    FilesToRunProvider momcWrapper() {
-      return ruleContext.getExecutablePrerequisite("$momcwrapper", Mode.HOST);
+    Artifact momczipDeployJar() {
+      return ruleContext.getPrerequisiteArtifact("$momczip_deploy", Mode.HOST);
     }
 
     /**
-     * Returns the location of the actoolwrapper.
+     * Returns the location of the actoolzip deploy jar.
      */
-    FilesToRunProvider actoolWrapper() {
-      return ruleContext.getExecutablePrerequisite("$actoolwrapper", Mode.HOST);
+    Artifact actoolzipDeployJar() {
+      return ruleContext.getPrerequisiteArtifact("$actoolzip_deploy", Mode.HOST);
     }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosSdkCommands.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosSdkCommands.java
index b10bc05..99a2ad0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosSdkCommands.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosSdkCommands.java
@@ -32,6 +32,8 @@
  */
 public class IosSdkCommands {
   public static final String DEVELOPER_DIR = "/Applications/Xcode.app/Contents/Developer";
+  public static final String ACTOOL_PATH = DEVELOPER_DIR + "/usr/bin/actool";
+  public static final String MOMC_PATH = DEVELOPER_DIR + "/usr/bin/momc";
 
   // There is a handy reference to many clang warning flags at
   // http://nshipster.com/clang-diagnostics/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
index 681ef22..4009d5e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
@@ -65,6 +65,7 @@
   static final PathFragment LIBTOOL = new PathFragment(BIN_DIR + "/libtool");
   static final PathFragment DSYMUTIL = new PathFragment(BIN_DIR + "/dsymutil");
   static final PathFragment LIPO = new PathFragment(BIN_DIR + "/lipo");
+  static final PathFragment SWIFT_STDLIB_TOOL = new PathFragment(BIN_DIR + "/swift-stdlib-tool");
   static final PathFragment STRIP = new PathFragment(BIN_DIR + "/strip");
 
   private static final PathFragment JAVA = new PathFragment("/usr/bin/java");
@@ -454,14 +455,16 @@
       return builder
           .add(attr("$plmerge", LABEL).cfg(HOST).exec()
               .value(env.getLabel("//tools/objc:plmerge")))
-          .add(attr("$actoolwrapper", LABEL).cfg(HOST).exec()
-              .value(env.getLabel("//tools/objc:actoolwrapper")))
+          .add(attr("$actoolzip_deploy", LABEL).cfg(HOST)
+              .value(env.getLabel("//tools/objc:actoolzip_deploy.jar")))
           .add(attr("$ibtoolwrapper", LABEL).cfg(HOST).exec()
               .value(env.getLabel("//tools/objc:ibtoolwrapper")))
           // TODO(dmaclach): Adding realpath here should not be required once
           // https://github.com/google/bazel/issues/285 is fixed.
           .add(attr("$realpath", LABEL).cfg(HOST).exec()
               .value(env.getLabel("//tools/objc:realpath")))
+          .add(attr("$swiftstdlibtoolzip_deploy", LABEL).cfg(HOST)
+              .value(env.getLabel("//tools/objc:swiftstdlibtoolzip_deploy.jar")))
           .build();
     }
     @Override
@@ -808,10 +811,8 @@
         <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
         .add(attr("families", STRING_LIST)
              .value(ImmutableList.of(TargetDeviceFamily.IPHONE.getNameInRule())))
-        .add(attr("$momcwrapper", LABEL).cfg(HOST).exec()
-            .value(env.getLabel("//tools/objc:momcwrapper")))
-        .add(attr("$swiftstdlibtoolwrapper", LABEL).cfg(HOST).exec()
-            .value(env.getLabel("//tools/objc:swiftstdlibtoolwrapper")))
+        .add(attr("$momczip_deploy", LABEL).cfg(HOST)
+            .value(env.getLabel("//tools/objc:momczip_deploy.jar")))
         .build();
     }
     @Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java
index c60f642..f17a8bf 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java
@@ -713,7 +713,9 @@
         .build(ruleContext));
   }
 
-  /** Registers an action to copy Swift standard library dylibs into app bundle. */
+  /**
+   * Registers an action to copy Swift standard library dylibs into app bundle.
+   */
   private void registerSwiftStdlibActionsIfNecessary() {
     if (!objcProvider.is(USES_SWIFT)) {
       return;
@@ -723,19 +725,17 @@
 
     CustomCommandLine.Builder commandLine = CustomCommandLine.builder()
         .addPath(intermediateArtifacts.swiftFrameworksFileZip().getExecPath())
+        .add("Frameworks")
+        .addPath(ObjcRuleClasses.SWIFT_STDLIB_TOOL)
         .add("--platform").add(IosSdkCommands.swiftPlatform(objcConfiguration))
         .addExecPath("--scan-executable", intermediateArtifacts.strippedSingleArchitectureBinary());
 
     ruleContext.registerAction(
-        ObjcRuleClasses.spawnOnDarwinActionBuilder()
+        ObjcRuleClasses.spawnJavaOnDarwinActionBuilder(attributes.swiftStdlibToolDeployJar())
             .setMnemonic("SwiftStdlibCopy")
-            .setExecutable(attributes.swiftStdlibToolWrapper())
             .setCommandLine(commandLine.build())
             .addOutput(intermediateArtifacts.swiftFrameworksFileZip())
             .addInput(intermediateArtifacts.strippedSingleArchitectureBinary())
-            // TODO(dmaclach): Adding realpath here should not be required once
-            // https://github.com/google/bazel/issues/285 is fixed.
-            .addInput(attributes.realpath())
             .build(ruleContext));
   }
 
@@ -832,18 +832,11 @@
           ruleContext.getPrerequisiteArtifact("$runner_script_template", Mode.HOST));
     }
 
-    /** Returns the location of the swiftstdlibtoolwrapper. */
-    FilesToRunProvider swiftStdlibToolWrapper() {
-      return ruleContext.getExecutablePrerequisite("$swiftstdlibtoolwrapper", Mode.HOST);
-    }
-
     /**
-     * Returns the location of the realpath tool.
-     * TODO(dmaclach): Should not be required once https://github.com/google/bazel/issues/285
-     * is fixed.
+     * Returns the location of the swiftstdlibtoolzip deploy jar.
      */
-    Artifact realpath() {
-      return ruleContext.getPrerequisiteArtifact("$realpath", Mode.HOST);
+    Artifact swiftStdlibToolDeployJar() {
+      return ruleContext.getPrerequisiteArtifact("$swiftstdlibtoolzip_deploy", Mode.HOST);
     }
 
     String bundleId() {
@@ -938,7 +931,9 @@
       return true;
     }
 
-    /** Returns the configuration distinguisher for this transition instance. */
+    /**
+     * Returns the configuration distinguisher for this transition instance.
+     */
     protected ConfigurationDistinguisher getConfigurationDistinguisher() {
       return ConfigurationDistinguisher.APPLICATION;
     }
diff --git a/src/objc_tools/momczip/BUILD b/src/objc_tools/momczip/BUILD
new file mode 100644
index 0000000..a2ae946
--- /dev/null
+++ b/src/objc_tools/momczip/BUILD
@@ -0,0 +1,11 @@
+package(default_visibility = ["//visibility:public"])
+
+java_binary(
+    name = "momczip",
+    srcs = glob(["java/**/*.java"]),
+    main_class = "com.google.devtools.build.xcode.momczip.MomcZip",
+    deps = [
+        "//src/tools/xcode-common/java/com/google/devtools/build/xcode/zippingoutput",
+        "//third_party:guava",
+    ],
+)
diff --git a/src/objc_tools/momczip/README b/src/objc_tools/momczip/README
new file mode 100644
index 0000000..1c87f43
--- /dev/null
+++ b/src/objc_tools/momczip/README
@@ -0,0 +1,2 @@
+momczip invokes momc ("Managed object model compiler") and zips up the output,
+as the number of output files is unpredictable.
diff --git a/src/objc_tools/momczip/java/com/google/devtools/build/xcode/momczip/MomcZip.java b/src/objc_tools/momczip/java/com/google/devtools/build/xcode/momczip/MomcZip.java
new file mode 100644
index 0000000..2134440
--- /dev/null
+++ b/src/objc_tools/momczip/java/com/google/devtools/build/xcode/momczip/MomcZip.java
@@ -0,0 +1,56 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.xcode.momczip;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.xcode.zippingoutput.Arguments;
+import com.google.devtools.build.xcode.zippingoutput.Wrapper;
+import com.google.devtools.build.xcode.zippingoutput.Wrappers;
+
+import java.io.IOException;
+
+/**
+ * A tool which wraps momc, by running momc and zipping its output. See the JavaDoc for
+ * {@link Wrapper} for more information.
+ */
+public class MomcZip implements Wrapper {
+  @Override
+  public String name() {
+    return "MomcZip";
+  }
+
+  @Override
+  public String subtoolName() {
+    return "momc";
+  }
+
+  @Override
+  public Iterable<String> subCommand(Arguments args, String outputDirectory) {
+    return new ImmutableList.Builder<String>()
+        .add(args.subtoolCmd())
+        .addAll(args.subtoolExtraArgs())
+        .add(outputDirectory)
+        .build();
+  }
+
+  public static void main(String[] args) throws IOException, InterruptedException {
+    Wrappers.executePipingOutput(args, new MomcZip());
+  }
+
+  @Override
+  public boolean outputDirectoryMustExist() {
+    return false;
+  }
+}
diff --git a/src/test/shell/bazel/BUILD b/src/test/shell/bazel/BUILD
index 8289816..3cd1ea0 100644
--- a/src/test/shell/bazel/BUILD
+++ b/src/test/shell/bazel/BUILD
@@ -19,14 +19,14 @@
     srcs = select({
         ":darwin": [
             "//src/objc_tools/bundlemerge:bundlemerge_deploy.jar",
+            "//src/objc_tools/momczip:momczip_deploy.jar",
             "//src/objc_tools/plmerge:plmerge_deploy.jar",
             "//src/objc_tools/xcodegen:xcodegen_deploy.jar",
-            "//src/tools/xcode/actoolwrapper",
+            "//src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip:actoolzip_deploy.jar",
+            "//src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip:swiftstdlibtoolzip_deploy.jar",
             "//src/tools/xcode/ibtoolwrapper",
-            "//src/tools/xcode/momcwrapper",
             "//src/tools/xcode/realpath",
             "//src/tools/xcode/stdredirect:StdRedirect.dylib",
-            "//src/tools/xcode/swiftstdlibtoolwrapper",
             "//third_party/iossim",
         ],
         "//conditions:default": [],
diff --git a/src/test/shell/bazel/test-setup.sh b/src/test/shell/bazel/test-setup.sh
index b35ba08..8f45de6 100755
--- a/src/test/shell/bazel/test-setup.sh
+++ b/src/test/shell/bazel/test-setup.sh
@@ -196,14 +196,14 @@
 # Sets up Objective-C tools. Mac only.
 function setup_objc_test_support() {
   mkdir -p tools/objc
-  [ -e tools/objc/actoolwrapper.jar ] || ln -sv ${actoolwrapper_path} tools/objc/actoolwrapper.sh
+  [ -e tools/objc/precomp_actoolzip_deploy.jar ] || ln -sv ${actoolzip_path} tools/objc/precomp_actoolzip_deploy.jar
   [ -e tools/objc/ibtoolwrapper.sh ] || ln -sv ${ibtoolwrapper_path} tools/objc/ibtoolwrapper.sh
-  [ -e tools/objc/momcwrapper.sh ] || ln -sv ${momcwrapper_path} tools/objc/momcwrapper.sh
+  [ -e tools/objc/precomp_swiftstdlibtoolzip_deploy.jar ] || ln -sv ${swiftstdlibtoolzip_path} tools/objc/precomp_swiftstdlibtoolzip_deploy.jar
+  [ -e tools/objc/precomp_momczip_deploy.jar ] || ln -sv ${momczip_path} tools/objc/precomp_momczip_deploy.jar
   [ -e tools/objc/precomp_bundlemerge_deploy.jar ] || ln -sv ${bundlemerge_path} tools/objc/precomp_bundlemerge_deploy.jar
   [ -e tools/objc/precomp_plmerge_deploy.jar ] || ln -sv ${plmerge_path} tools/objc/precomp_plmerge_deploy.jar
   [ -e tools/objc/precomp_xcodegen_deploy.jar ] || ln -sv ${xcodegen_path} tools/objc/precomp_xcodegen_deploy.jar
   [ -e tools/objc/StdRedirect.dylib ] || ln -sv ${stdredirect_path} tools/objc/StdRedirect.dylib
-  [ -e tools/objc/swiftstdlibtoolwrapper.sh ] || ln -sv ${swiftstdlibtoolwrapper_path} tools/objc/swiftstdlibtoolwrapper.sh
   [ -e tools/objc/realpath ] || ln -sv ${realpath_path} tools/objc/realpath
 
   mkdir -p third_party/iossim
@@ -294,7 +294,7 @@
 # Simples assert to make the tests more readable
 #
 function assert_build() {
-  bazel build -s --verbose_failures $* || fail "Failed to build $*"
+  bazel build -s $* || fail "Failed to build $*"
 }
 
 function assert_build_output() {
diff --git a/src/test/shell/bazel/testenv.sh b/src/test/shell/bazel/testenv.sh
index c0db17d..ec485ff 100755
--- a/src/test/shell/bazel/testenv.sh
+++ b/src/test/shell/bazel/testenv.sh
@@ -46,10 +46,10 @@
 
 # iOS and Objective-C tooling
 iossim_path="${TEST_SRCDIR}/third_party/iossim/iossim"
-actoolwrapper_path="${TEST_SRCDIR}/src/tools/xcode/actoolwrapper/actoolwrapper.sh"
+actoolzip_path="${TEST_SRCDIR}/src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip/actoolzip_deploy.jar"
 ibtoolwrapper_path="${TEST_SRCDIR}/src/tools/xcode/ibtoolwrapper/ibtoolwrapper.sh"
-swiftstdlibtoolwrapper_path="${TEST_SRCDIR}/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh"
-momcwrapper_path="${TEST_SRCDIR}/src/tools/xcode/momcwrapper/momcwrapper.sh"
+swiftstdlibtoolzip_path="${TEST_SRCDIR}/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/swiftstdlibtoolzip_deploy.jar"
+momczip_path="${TEST_SRCDIR}/src/objc_tools/momczip/momczip_deploy.jar"
 bundlemerge_path="${TEST_SRCDIR}/src/objc_tools/bundlemerge/bundlemerge_deploy.jar"
 plmerge_path="${TEST_SRCDIR}/src/objc_tools/plmerge/plmerge_deploy.jar"
 xcodegen_path="${TEST_SRCDIR}/src/objc_tools/xcodegen/xcodegen_deploy.jar"
diff --git a/src/tools/xcode-common/BUILD b/src/tools/xcode-common/BUILD
index bfd7849..639c621 100644
--- a/src/tools/xcode-common/BUILD
+++ b/src/tools/xcode-common/BUILD
@@ -3,7 +3,9 @@
 filegroup(
     name = "srcs",
     srcs = [
+        "//src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip:srcs",
         "//src/tools/xcode-common/java/com/google/devtools/build/xcode/common:srcs",
+        "//src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip:srcs",
         "//src/tools/xcode-common/java/com/google/devtools/build/xcode/util:srcs",
         "//src/tools/xcode-common/java/com/google/devtools/build/xcode/zip:srcs",
         "//src/tools/xcode-common/java/com/google/devtools/build/xcode/zippingoutput:srcs",
diff --git a/src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip/ActoolZip.java b/src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip/ActoolZip.java
new file mode 100644
index 0000000..cd44667
--- /dev/null
+++ b/src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip/ActoolZip.java
@@ -0,0 +1,116 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.xcode.actoolzip;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.xcode.zippingoutput.Arguments;
+import com.google.devtools.build.xcode.zippingoutput.Wrapper;
+import com.google.devtools.build.xcode.zippingoutput.Wrappers;
+import com.google.devtools.build.xcode.zippingoutput.Wrappers.CommandFailedException;
+import com.google.devtools.build.xcode.zippingoutput.Wrappers.OutErr;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ * A tool which wraps actool by running actool and zipping its output. See the JavaDoc for
+ * {@link Wrapper} for more information.
+ */
+public class ActoolZip implements Wrapper {
+
+  @Override
+  public String name() {
+    return "ActoolZip";
+  }
+
+  @Override
+  public String subtoolName() {
+    return "actool";
+  }
+
+  @Override
+  public Iterable<String> subCommand(Arguments args, String outputDirectory) {
+    return new ImmutableList.Builder<String>()
+        .add(args.subtoolCmd())
+        .add("--output-format").add("human-readable-text")
+        .add("--notices")
+        .add("--warnings")
+        .add("--errors")
+        .add("--compress-pngs")
+        .add("--compile")
+        .add(outputDirectory)
+        // actool munges paths in some way which doesn't work if one of the directories in the path
+        // is a symlink.
+        .addAll(Iterables.transform(args.subtoolExtraArgs(), Wrappers.CANONICALIZE_IF_PATH))
+        .build();
+  }
+
+  public static void main(String[] args) throws IOException, InterruptedException {
+    Optional<File> infoPlistPath = replaceInfoPlistPath(args);
+    try {
+      OutErr outErr = Wrappers.executeCapturingOutput(args, new ActoolZip());
+      if (infoPlistPath.isPresent() && !infoPlistPath.get().exists()) {
+        outErr.print();
+        System.exit(1);
+      }
+    } catch (CommandFailedException e) {
+      Wrappers.handleException(e);
+    }
+  }
+
+  /**
+   * Absolute-ify output partial info plist's path.
+   *
+   * <p>actool occasionally writes the partial info plist file to the wrong directory if a
+   * non-absolute path is passed as --output-partial-info-plist, so we optimistically try to
+   * absolute-ify its path. This isn't caught by the "CANONICAL_PATH" transform above, because the
+   * file doesn't exist at the time of flag parsing.
+   *
+   * <p>Modifies args in-place.
+   *
+   * @return new value of the output-partial-info-plist flag.
+   */
+  private static Optional<File> replaceInfoPlistPath(String[] args) {
+    String flag = "output-partial-info-plist";
+    Set<String> flagOptions = ImmutableSet.of(
+        "-" + flag,
+        "--" + flag);
+    Optional<File> newPath = Optional.absent();
+    for (int i = 0; i < args.length; ++i) {
+      for (String flagOption : flagOptions) {
+        String arg = args[i];
+        String flagEquals = flagOption + "=";
+        if (arg.startsWith(flagEquals)) {
+          newPath = Optional.of(new File(arg.substring(flagEquals.length())));
+          args[i] = flagEquals + newPath.get().getAbsolutePath();
+        }
+        if (arg.equals(flagOption) && i + 1 < args.length) {
+          newPath = Optional.of(new File(args[i + 1]));
+          args[i + 1] = newPath.get().getAbsolutePath();
+        }
+      }
+    }
+    return newPath;
+  }
+
+  @Override
+  public boolean outputDirectoryMustExist() {
+    return true;
+  }
+}
diff --git a/src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip/BUILD b/src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip/BUILD
new file mode 100644
index 0000000..8e08b62
--- /dev/null
+++ b/src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip/BUILD
@@ -0,0 +1,17 @@
+package(default_visibility = ["//src:__subpackages__"])
+
+filegroup(
+    name = "srcs",
+    srcs = glob(["**"]),
+)
+
+java_binary(
+    name = "actoolzip",
+    srcs = ["ActoolZip.java"],
+    main_class = "com.google.devtools.build.xcode.actoolzip.ActoolZip",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//src/tools/xcode-common/java/com/google/devtools/build/xcode/zippingoutput",
+        "//third_party:guava",
+    ],
+)
diff --git a/src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip/README b/src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip/README
new file mode 100644
index 0000000..7aaae16
--- /dev/null
+++ b/src/tools/xcode-common/java/com/google/devtools/build/xcode/actoolzip/README
@@ -0,0 +1,4 @@
+actoolzip runs actool, which compiles asset catalog files and zips up the
+output, because actool returns an unpredictable number of output files.
+
+actool only runs on Darwin, so actoolzip only runs on Darwin.
diff --git a/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/BUILD b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/BUILD
new file mode 100644
index 0000000..b429688
--- /dev/null
+++ b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/BUILD
@@ -0,0 +1,17 @@
+package(default_visibility = ["//src:__subpackages__"])
+
+filegroup(
+    name = "srcs",
+    srcs = glob(["**"]),
+)
+
+java_binary(
+    name = "swiftstdlibtoolzip",
+    srcs = ["SwiftStdlibToolZip.java"],
+    main_class = "com.google.devtools.build.xcode.swiftstdlibtoolzip.SwiftStdlibToolZip",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//src/tools/xcode-common/java/com/google/devtools/build/xcode/zippingoutput",
+        "//third_party:guava",
+    ],
+)
diff --git a/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/README b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/README
new file mode 100644
index 0000000..0c8b3f0
--- /dev/null
+++ b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/README
@@ -0,0 +1,4 @@
+swiftstdlibtoolzip runs swift-stdlib-tool, which scans executables and copies required Swift
+framework dylibs to the specified path, then zips up the output for further bundle merging.
+
+swift-stdlib-tool only runs on Darwin, so swiftstdlibtoolzip only runs on Darwin.
diff --git a/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/SwiftStdlibToolZip.java b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/SwiftStdlibToolZip.java
new file mode 100644
index 0000000..2043a08
--- /dev/null
+++ b/src/tools/xcode-common/java/com/google/devtools/build/xcode/swiftstdlibtoolzip/SwiftStdlibToolZip.java
@@ -0,0 +1,59 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.xcode.swiftstdlibtoolzip;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.xcode.zippingoutput.Arguments;
+import com.google.devtools.build.xcode.zippingoutput.Wrapper;
+import com.google.devtools.build.xcode.zippingoutput.Wrappers;
+
+import java.io.IOException;
+
+/**
+ * A tool which wraps swift-stdlib-tool by running and zipping its output. See {@link Wrapper} for
+ * more information.
+ */
+public class SwiftStdlibToolZip implements Wrapper {
+
+  @Override
+  public String name() {
+    return "SwiftStdlibToolZip";
+  }
+
+  @Override
+  public String subtoolName() {
+    return "swift-stdlib-tool";
+  }
+
+  @Override
+  public Iterable<String> subCommand(Arguments arguments, String outputDirectory) {
+    return new ImmutableList.Builder<String>()
+        .add(arguments.subtoolCmd())
+        .addAll(arguments.subtoolExtraArgs())
+        .add("--copy")
+        .add("--verbose")
+        .add("--destination").add(outputDirectory)
+        .build();
+  }
+
+  @Override
+  public boolean outputDirectoryMustExist() {
+    return true;
+  }
+
+  public static void main(String[] args) throws IOException, InterruptedException {
+    Wrappers.executePipingOutput(args, new SwiftStdlibToolZip());
+  }
+}
diff --git a/src/tools/xcode/actoolwrapper/BUILD b/src/tools/xcode/actoolwrapper/BUILD
deleted file mode 100644
index 79bfdd6..0000000
--- a/src/tools/xcode/actoolwrapper/BUILD
+++ /dev/null
@@ -1,12 +0,0 @@
-package(default_visibility = ["//src/test:__subpackages__"])
-
-filegroup(
-    name = "srcs",
-    srcs = glob(["**"]),
-)
-
-sh_binary(
-    name = "actoolwrapper",
-    srcs = ["actoolwrapper.sh"],
-    data = ["//src/tools/xcode/realpath:realpath_genrule"],
-)
diff --git a/src/tools/xcode/actoolwrapper/README b/src/tools/xcode/actoolwrapper/README
deleted file mode 100644
index d274e63..0000000
--- a/src/tools/xcode/actoolwrapper/README
+++ /dev/null
@@ -1,6 +0,0 @@
-actoolwrapper runs actool, which compiles asset catalog files.
-actoolwrapper then zips up the output, because actool returns an unpredictable
-number of output files.
-
-actool only runs on Darwin, so actoolwrapper only runs on Darwin.
-
diff --git a/src/tools/xcode/actoolwrapper/actoolwrapper.sh b/src/tools/xcode/actoolwrapper/actoolwrapper.sh
deleted file mode 100755
index 7191583..0000000
--- a/src/tools/xcode/actoolwrapper/actoolwrapper.sh
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/bin/bash
-# Copyright 2015 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# actoolwrapper runs actool and zips up the output.
-# This script only runs on darwin and you must have Xcode installed.
-#
-# $1 OUTZIP - the path to place the output zip file.
-
-set -eu
-
-OUTZIP=$(tools/objc/realpath "$1")
-shift 1
-TEMPDIR=$(mktemp -d -t ZippingOutput)
-trap "rm -rf \"$TEMPDIR\"" EXIT
-
-# actool needs to have absolute paths sent to it, so we call realpaths on
-# on all arguments seeing if we can expand them.
-# actool and ibtool appear to depend on the same code base.
-# --output-partial-info-plist gives actool real troubles
-# so we create a file where we expect the plist to be so we can get a full
-# path to it.
-# Radar 21045660 ibtool has difficulty dealing with relative paths.
-TOOLARGS=()
-LASTARG=""
-for i in $@; do
-  if [ "$LASTARG" = "--output-partial-info-plist" ]; then
-    PARENTDIR=$(dirname "$i")
-    mkdir -p "$PARENTDIR"
-    touch "$i"
-  fi
-  if [ -e "$i" ]; then
-    TOOLARGS+=($(tools/objc/realpath "$i"))
-  else
-    TOOLARGS+=("$i")
-  fi
-  LASTARG="$i"
-done
-
-# If we are running into problems figuring out actool issues, there are a couple
-# of env variables that may help. Both of the following must be set to work.
-#   IBToolDebugLogFile=<OUTPUT FILE PATH>
-#   IBToolDebugLogLevel=4
-# you may also see if
-#   IBToolNeverDeque=1
-# helps.
-# Yes IBTOOL appears to be correct here due to actool and ibtool being based
-# on the same codebase.
-/usr/bin/xcrun actool --errors --warnings --notices \
-    --compress-pngs --output-format human-readable-text \
-    --compile "$TEMPDIR" "${TOOLARGS[@]}"
-
-# Need to push/pop tempdir so it isn't the current working directory
-# when we remove it via the EXIT trap.
-pushd "$TEMPDIR" > /dev/null
-# Reset all dates to Unix Epoch so that two identical zips created at different
-# times appear the exact same for comparison purposes.
-find . -exec touch -h -t 197001010000 {} \;
-zip --symlinks --recurse-paths --quiet "$OUTZIP" .
-popd > /dev/null
diff --git a/src/tools/xcode/ibtoolwrapper/ibtoolwrapper.sh b/src/tools/xcode/ibtoolwrapper/ibtoolwrapper.sh
index 968e0bb..7cc4be3 100755
--- a/src/tools/xcode/ibtoolwrapper/ibtoolwrapper.sh
+++ b/src/tools/xcode/ibtoolwrapper/ibtoolwrapper.sh
@@ -29,7 +29,6 @@
 shift 2
 TEMPDIR=$(mktemp -d -t ZippingOutput)
 trap "rm -rf \"$TEMPDIR\"" EXIT
-
 FULLPATH="$TEMPDIR/$ARCHIVEROOT"
 PARENTDIR=$(dirname "$FULLPATH")
 mkdir -p "$PARENTDIR"
@@ -38,12 +37,12 @@
 # IBTool needs to have absolute paths sent to it, so we call realpaths on
 # on all arguments seeing if we can expand them.
 # Radar 21045660 ibtool has difficulty dealing with relative paths.
-TOOLARGS=()
+IBTOOLARGS=()
 for i in $@; do
   if [ -e "$i" ]; then
-    TOOLARGS+=($(tools/objc/realpath "$i"))
+    IBTOOLARGS+=($(tools/objc/realpath "$i"))
   else
-    TOOLARGS+=("$i")
+    IBTOOLARGS+=($i)
   fi
 done
 
@@ -56,13 +55,10 @@
 # helps.
 /usr/bin/xcrun ibtool --errors --warnings --notices \
     --auto-activate-custom-fonts --output-format human-readable-text \
-    --compile "$FULLPATH" "${TOOLARGS[@]}"
+    --compile "$FULLPATH" ${IBTOOLARGS[@]}
 
 # Need to push/pop tempdir so it isn't the current working directory
 # when we remove it via the EXIT trap.
 pushd "$TEMPDIR" > /dev/null
-# Reset all dates to Unix Epoch so that two identical zips created at different
-# times appear the exact same for comparison purposes.
-find . -exec touch -h -t 197001010000 {} \;
-zip --symlinks --recurse-paths --quiet "$OUTZIP" .
+zip -y -r -q "$OUTZIP" .
 popd > /dev/null
diff --git a/src/tools/xcode/momcwrapper/BUILD b/src/tools/xcode/momcwrapper/BUILD
deleted file mode 100644
index 61acf80..0000000
--- a/src/tools/xcode/momcwrapper/BUILD
+++ /dev/null
@@ -1,12 +0,0 @@
-package(default_visibility = ["//src/test:__subpackages__"])
-
-filegroup(
-    name = "srcs",
-    srcs = glob(["**"]),
-)
-
-sh_binary(
-    name = "momcwrapper",
-    srcs = ["momcwrapper.sh"],
-    data = ["//src/tools/xcode/realpath:realpath_genrule"],
-)
diff --git a/src/tools/xcode/momcwrapper/README b/src/tools/xcode/momcwrapper/README
deleted file mode 100644
index 37654de..0000000
--- a/src/tools/xcode/momcwrapper/README
+++ /dev/null
@@ -1,6 +0,0 @@
-momcwrapper runs momc, which compiles xcdatamodels.
-momcwrapper then zips up the output, because momc returns an unpredictable
-number of output files.
-
-momc only runs on Darwin, so momcwrapper only runs on Darwin.
-
diff --git a/src/tools/xcode/momcwrapper/momcwrapper.sh b/src/tools/xcode/momcwrapper/momcwrapper.sh
deleted file mode 100755
index 5523a3f..0000000
--- a/src/tools/xcode/momcwrapper/momcwrapper.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/bash
-# Copyright 2015 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# momcwrapper runs momc and zips up the output.
-# This script only runs on darwin and you must have Xcode installed.
-#
-# $1 OUTZIP - the path to place the output zip file.
-
-
-set -eu
-
-OUTZIP=$(tools/objc/realpath "$1")
-shift 1
-TEMPDIR=$(mktemp -d -t ZippingOutput)
-trap "rm -rf \"$TEMPDIR\"" EXIT
-
-/usr/bin/xcrun momc "$@" "$TEMPDIR"
-
-# Need to push/pop tempdir so it isn't the current working directory
-# when we remove it via the EXIT trap.
-pushd "$TEMPDIR" > /dev/null
-# Reset all dates to Unix Epoch so that two identical zips created at different
-# times appear the exact same for comparison purposes.
-find . -exec touch -h -t 197001010000 {} \;
-zip --symlinks --recurse-paths "$OUTZIP" .
-popd > /dev/null
diff --git a/src/tools/xcode/swiftstdlibtoolwrapper/BUILD b/src/tools/xcode/swiftstdlibtoolwrapper/BUILD
deleted file mode 100644
index 1a98848..0000000
--- a/src/tools/xcode/swiftstdlibtoolwrapper/BUILD
+++ /dev/null
@@ -1,12 +0,0 @@
-package(default_visibility = ["//src/test:__subpackages__"])
-
-filegroup(
-    name = "srcs",
-    srcs = glob(["**"]),
-)
-
-sh_binary(
-    name = "swiftstdlibtoolwrapper",
-    srcs = ["swiftstdlibtoolwrapper.sh"],
-    data = ["//src/tools/xcode/realpath:realpath_genrule"],
-)
diff --git a/src/tools/xcode/swiftstdlibtoolwrapper/README b/src/tools/xcode/swiftstdlibtoolwrapper/README
deleted file mode 100644
index e99ff4e..0000000
--- a/src/tools/xcode/swiftstdlibtoolwrapper/README
+++ /dev/null
@@ -1,6 +0,0 @@
-swiftstdlibtoolwrapper runs swift-stdlib-tool, which scans executables and
-copies required Swift framework dylibs to the specified path, then zips up
-the output for further bundle merging.
-
-swift-stdlib-tool only runs on Darwin, so swiftstdlibtoolwrapper only runs on
-Darwin.
diff --git a/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh b/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh
deleted file mode 100755
index f036b93..0000000
--- a/src/tools/xcode/swiftstdlibtoolwrapper/swiftstdlibtoolwrapper.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash
-# Copyright 2015 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# swiftstdlibtoolwrapper runs swift-stdlib-tool and zips up the output.
-# This script only runs on darwin and you must have Xcode installed.
-#
-# $1 OUTZIP - the path to place the output zip file.
-
-set -eu
-
-OUTZIP=$(tools/objc/realpath "$1")
-shift 1
-TEMPDIR=$(mktemp -d -t ZippingOutput)
-trap "rm -rf \"$TEMPDIR\"" EXIT
-
-FULLPATH="$TEMPDIR/Frameworks"
-
-/usr/bin/xcrun swift-stdlib-tool --copy --verbose --destination "$FULLPATH" "$@"
-
-# Need to push/pop tempdir so it isn't the current working directory
-# when we remove it via the EXIT trap.
-pushd "$TEMPDIR" > /dev/null
-# Reset all dates to Unix Epoch so that two identical zips created at different
-# times appear the exact same for comparison purposes.
-find . -exec touch -h -t 197001010000 {} \;
-zip --symlinks --recurse-paths --quiet "$OUTZIP" .
-popd > /dev/null