xref: /JGit/org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ZipFormat.java (revision 6f82690aaf2be783be6d77f0903788ff0832472a)
1 /*
2  * Copyright (C) 2012 Google Inc. and others
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Distribution License v. 1.0 which is available at
6  * https://www.eclipse.org/org/documents/edl-v10.php.
7  *
8  * SPDX-License-Identifier: BSD-3-Clause
9  */
10 package org.eclipse.jgit.archive;
11 
12 import java.io.IOException;
13 import java.io.OutputStream;
14 import java.text.MessageFormat;
15 import java.util.Arrays;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.Map;
19 
20 import org.apache.commons.compress.archivers.ArchiveOutputStream;
21 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
22 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
23 import org.eclipse.jgit.api.ArchiveCommand;
24 import org.eclipse.jgit.archive.internal.ArchiveText;
25 import org.eclipse.jgit.lib.FileMode;
26 import org.eclipse.jgit.lib.ObjectId;
27 import org.eclipse.jgit.lib.ObjectLoader;
28 import org.eclipse.jgit.revwalk.RevCommit;
29 
30 /**
31  * PKWARE's ZIP format.
32  */
33 public final class ZipFormat extends BaseFormat implements
34 		ArchiveCommand.Format<ArchiveOutputStream> {
35 	private static final List<String> SUFFIXES = Collections
36 			.unmodifiableList(Arrays.asList(".zip")); //$NON-NLS-1$
37 
38 	/** {@inheritDoc} */
39 	@Override
createArchiveOutputStream(OutputStream s)40 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s)
41 			throws IOException {
42 		return createArchiveOutputStream(s,
43 				Collections.<String, Object> emptyMap());
44 	}
45 
46 	/** {@inheritDoc} */
47 	@Override
createArchiveOutputStream(OutputStream s, Map<String, Object> o)48 	public ArchiveOutputStream createArchiveOutputStream(OutputStream s,
49 			Map<String, Object> o) throws IOException {
50 		ZipArchiveOutputStream out = new ZipArchiveOutputStream(s);
51 		int compressionLevel = getCompressionLevel(o);
52 		if (compressionLevel != -1) {
53 			out.setLevel(compressionLevel);
54 		}
55 		return applyFormatOptions(out, o);
56 	}
57 
58 	/** {@inheritDoc} */
59 	@Override
putEntry(ArchiveOutputStream out, ObjectId tree, String path, FileMode mode, ObjectLoader loader)60 	public void putEntry(ArchiveOutputStream out,
61 			ObjectId tree, String path, FileMode mode, ObjectLoader loader)
62 			throws IOException {
63 		// ZipArchiveEntry detects directories by checking
64 		// for '/' at the end of the filename.
65 		if (path.endsWith("/") && mode != FileMode.TREE) //$NON-NLS-1$
66 			throw new IllegalArgumentException(MessageFormat.format(
67 					ArchiveText.get().pathDoesNotMatchMode, path, mode));
68 		if (!path.endsWith("/") && mode == FileMode.TREE) //$NON-NLS-1$
69 			path = path + "/"; //$NON-NLS-1$
70 
71 		final ZipArchiveEntry entry = new ZipArchiveEntry(path);
72 
73 		if (tree instanceof RevCommit) {
74 			long t = ((RevCommit) tree).getCommitTime() * 1000L;
75 			entry.setTime(t);
76 		}
77 
78 		if (mode == FileMode.TREE) {
79 			out.putArchiveEntry(entry);
80 			out.closeArchiveEntry();
81 			return;
82 		}
83 
84 		if (mode == FileMode.REGULAR_FILE) {
85 			// ok
86 		} else if (mode == FileMode.EXECUTABLE_FILE
87 				|| mode == FileMode.SYMLINK) {
88 			entry.setUnixMode(mode.getBits());
89 		} else {
90 			// Unsupported mode (e.g., GITLINK).
91 			throw new IllegalArgumentException(MessageFormat.format(
92 					ArchiveText.get().unsupportedMode, mode));
93 		}
94 		entry.setSize(loader.getSize());
95 		out.putArchiveEntry(entry);
96 		loader.copyTo(out);
97 		out.closeArchiveEntry();
98 	}
99 
100 	/** {@inheritDoc} */
101 	@Override
suffixes()102 	public Iterable<String> suffixes() {
103 		return SUFFIXES;
104 	}
105 
106 	/** {@inheritDoc} */
107 	@Override
equals(Object other)108 	public boolean equals(Object other) {
109 		return (other instanceof ZipFormat);
110 	}
111 
112 	/** {@inheritDoc} */
113 	@Override
hashCode()114 	public int hashCode() {
115 		return getClass().hashCode();
116 	}
117 }
118