HADOOP-5470. RunJar.unJar() should write the last modified time found in the jar entry to the uncompressed file. (Contributed by Andras Bakor)

This commit is contained in:
Arpit Agarwal 2016-04-27 10:06:54 -07:00
parent dd7c9f5b8f
commit 7cd0177310
2 changed files with 33 additions and 2 deletions

View File

@ -43,12 +43,16 @@ import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileUtil; import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Run a Hadoop job jar. */ /** Run a Hadoop job jar. */
@InterfaceAudience.Private @InterfaceAudience.Private
@InterfaceStability.Unstable @InterfaceStability.Unstable
public class RunJar { public class RunJar {
private static final Logger LOG = LoggerFactory.getLogger(RunJar.class);
/** Pattern that matches any string */ /** Pattern that matches any string */
public static final Pattern MATCH_ANY = Pattern.compile(".*"); public static final Pattern MATCH_ANY = Pattern.compile(".*");
@ -93,6 +97,7 @@ public class RunJar {
throws IOException { throws IOException {
JarFile jar = new JarFile(jarFile); JarFile jar = new JarFile(jarFile);
try { try {
int numOfFailedLastModifiedSet = 0;
Enumeration<JarEntry> entries = jar.entries(); Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) { while (entries.hasMoreElements()) {
final JarEntry entry = entries.nextElement(); final JarEntry entry = entries.nextElement();
@ -108,11 +113,18 @@ public class RunJar {
} finally { } finally {
out.close(); out.close();
} }
if (!file.setLastModified(entry.getTime())) {
numOfFailedLastModifiedSet++;
}
} finally { } finally {
in.close(); in.close();
} }
} }
} }
if (numOfFailedLastModifiedSet > 0) {
LOG.warn("Could not set last modfied time for {} file(s)",
numOfFailedLastModifiedSet);
}
} finally { } finally {
jar.close(); jar.close();
} }

View File

@ -41,6 +41,8 @@ public class TestRunJar extends TestCase {
private static final String TEST_JAR_NAME="test-runjar.jar"; private static final String TEST_JAR_NAME="test-runjar.jar";
private static final String TEST_JAR_2_NAME = "test-runjar2.jar"; private static final String TEST_JAR_2_NAME = "test-runjar2.jar";
private static final long MOCKED_NOW = 1_460_389_972_000L;
private static final long MOCKED_NOW_PLUS_TWO_SEC = MOCKED_NOW + 2_000;
@Override @Override
@Before @Before
@ -70,9 +72,13 @@ public class TestRunJar extends TestCase {
File jarFile = new File(TEST_ROOT_DIR, TEST_JAR_NAME); File jarFile = new File(TEST_ROOT_DIR, TEST_JAR_NAME);
JarOutputStream jstream = JarOutputStream jstream =
new JarOutputStream(new FileOutputStream(jarFile)); new JarOutputStream(new FileOutputStream(jarFile));
jstream.putNextEntry(new ZipEntry("foobar.txt")); ZipEntry zipEntry1 = new ZipEntry("foobar.txt");
zipEntry1.setTime(MOCKED_NOW);
jstream.putNextEntry(zipEntry1);
jstream.closeEntry(); jstream.closeEntry();
jstream.putNextEntry(new ZipEntry("foobaz.txt")); ZipEntry zipEntry2 = new ZipEntry("foobaz.txt");
zipEntry2.setTime(MOCKED_NOW_PLUS_TWO_SEC);
jstream.putNextEntry(zipEntry2);
jstream.closeEntry(); jstream.closeEntry();
jstream.close(); jstream.close();
} }
@ -115,6 +121,19 @@ public class TestRunJar extends TestCase {
} }
public void testUnJarDoesNotLooseLastModify() throws Exception {
File unjarDir = new File(TEST_ROOT_DIR, "unjar-lastmod");
assertFalse("unjar dir shouldn't exist at test start",
new File(unjarDir, "foobar.txt").exists());
// Unjar everything
RunJar.unJar(new File(TEST_ROOT_DIR, TEST_JAR_NAME),
unjarDir);
assertEquals("Last modify time was lost during unJar", MOCKED_NOW, new File(unjarDir, "foobar.txt").lastModified());
assertEquals("Last modify time was lost during unJar", MOCKED_NOW_PLUS_TWO_SEC, new File(unjarDir, "foobaz.txt").lastModified());
}
/** /**
* Tests the client classloader to verify the main class and its dependent * Tests the client classloader to verify the main class and its dependent
* class are loaded correctly by the application classloader, and others are * class are loaded correctly by the application classloader, and others are