Skip to content

Commit 52ec6f7

Browse files
#89 Add file or folder to specific path in zip
1 parent 38f8d50 commit 52ec6f7

39 files changed

+548
-578
lines changed

src/main/java/ru/olegcherednik/zip4jvm/ZipFile.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import ru.olegcherednik.zip4jvm.model.settings.ZipSettings;
3030
import ru.olegcherednik.zip4jvm.model.src.SrcZip;
3131
import ru.olegcherednik.zip4jvm.utils.EmptyInputStreamSupplier;
32-
import ru.olegcherednik.zip4jvm.utils.PathUtils;
3332
import ru.olegcherednik.zip4jvm.utils.quitely.Quietly;
3433
import ru.olegcherednik.zip4jvm.utils.quitely.functions.InputStreamSupplier;
3534

@@ -125,11 +124,11 @@ public InputStream getInputStream() {
125124

126125
public interface Writer extends Closeable {
127126

128-
default void add(Path path) {
129-
add(path, PathUtils.getName(path));
130-
}
127+
void add(Path path);
128+
129+
void addWithRename(Path path, String name);
131130

132-
void add(Path path, String name);
131+
void addWithMove(Path path, String dir);
133132

134133
void add(ZipFile.Entry entry);
135134

src/main/java/ru/olegcherednik/zip4jvm/ZipIt.java

+23-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import ru.olegcherednik.zip4jvm.model.settings.ZipEntrySettings;
2323
import ru.olegcherednik.zip4jvm.model.settings.ZipEntrySettingsProvider;
2424
import ru.olegcherednik.zip4jvm.model.settings.ZipSettings;
25-
import ru.olegcherednik.zip4jvm.utils.ValidationUtils;
2625

2726
import lombok.AccessLevel;
2827
import lombok.RequiredArgsConstructor;
@@ -128,7 +127,7 @@ public void add(Collection<Path> paths) throws IOException {
128127
if (CollectionUtils.isEmpty(paths))
129128
return;
130129

131-
paths.forEach(ValidationUtils::requireExists);
130+
requireExists(paths);
132131

133132
// TODO check that path != zip
134133
try (ZipFile.Writer zipFile = ZipFile.writer(zip, settings)) {
@@ -137,6 +136,28 @@ public void add(Collection<Path> paths) throws IOException {
137136
}
138137
}
139138

139+
/**
140+
* Add regular file or directory (keeping initial structure) to the new or existed zip archive under give
141+
* {@code name}.<br>
142+
* In case given {@code path} is a directory (or symlink to directory), then this directory will be renamed.<br>
143+
* In case given {@code path} is a regular file (or symlink to the file), then this file will be renamed.
144+
*
145+
* @param path path to the regular file or directory
146+
* @param name not {@literal null} name to be used for the {@code path}
147+
* @throws IOException in case of any problem with file access
148+
*/
149+
public void addWithRename(Path path, String name) throws IOException {
150+
try (ZipFile.Writer zipFile = ZipFile.writer(zip, settings)) {
151+
zipFile.addWithRename(path, name);
152+
}
153+
}
154+
155+
public void addWithMove(Path path, String dir) throws IOException {
156+
try (ZipFile.Writer zipFile = ZipFile.writer(zip, settings)) {
157+
zipFile.addWithMove(path, dir);
158+
}
159+
}
160+
140161
/**
141162
* Creates instance of zip file stream. It could be used to add multiple entries to the zip archive. It should be
142163
* correctly closed to flush all data.

src/main/java/ru/olegcherednik/zip4jvm/engine/ZipEngine.java

+47-22
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import ru.olegcherednik.zip4jvm.utils.function.Writer;
4040

4141
import lombok.extern.slf4j.Slf4j;
42+
import org.apache.commons.lang3.StringUtils;
4243

4344
import java.io.IOException;
4445
import java.nio.file.Files;
@@ -74,35 +75,59 @@ public ZipEngine(Path zip, ZipSettings settings) throws IOException {
7475
}
7576

7677
@Override
77-
public void add(Path path, String name) {
78+
public void add(Path path) {
79+
add(path, PathUtils.getName(path), "");
80+
}
81+
82+
@Override
83+
public void addWithRename(Path path, String name) {
84+
add(path, name, "");
85+
}
86+
87+
@Override
88+
public void addWithMove(Path path, String dir) {
89+
add(path, PathUtils.getName(path), dir);
90+
}
91+
92+
private void add(Path path, String name, String dir) {
7893
if (!Files.exists(path))
7994
return;
8095

8196
if (Files.isSymbolicLink(path))
8297
path = ZipSymlinkEngine.getSymlinkTarget(path);
8398

99+
for (NamedPath namedPath : getNamedPaths(path, name, dir)) {
100+
String entryName = namedPath.getEntryName();
101+
ZipEntrySettings entrySettings = settings.getEntrySettings(entryName);
102+
add(namedPath.createZipEntry(entrySettings));
103+
}
104+
}
105+
106+
private List<NamedPath> getNamedPaths(Path path, String name, String dir) {
84107
if (Files.isDirectory(path))
85-
zipSymlinkEngine.list(getDirectoryNamedPaths(path, name)).stream()
86-
.map(namedPath -> {
87-
String entryName = namedPath.getEntryName();
88-
ZipEntrySettings entrySettings = settings.getEntrySettings(entryName);
89-
return namedPath.createZipEntry(entrySettings);
90-
})
91-
.forEach(this::add);
92-
else if (Files.isRegularFile(path)) {
93-
ZipEntrySettings entrySettings = settings.getEntrySettings(name);
94-
ZipEntry zipEntry = ZipEntryBuilder.regularFile(path, name, entrySettings);
95-
add(zipEntry);
96-
} else
97-
log.warn("Unknown path type '{}'; ignore it", path);
98-
}
99-
100-
private List<NamedPath> getDirectoryNamedPaths(Path path, String name) {
101-
return settings.isRemoveRootDir() ? PathUtils.list(path).stream()
102-
.map(NamedPath::create)
103-
.sorted(NamedPath.SORT_BY_NAME_ASC)
104-
.collect(Collectors.toList())
105-
: Collections.singletonList(NamedPath.create(path, name));
108+
return zipSymlinkEngine.list(getDirectoryNamedPaths(path, name, dir));
109+
110+
if (Files.isRegularFile(path)) {
111+
if (StringUtils.isNotBlank(dir))
112+
name = dir + '/' + name;
113+
114+
return Collections.singletonList(NamedPath.create(path, name));
115+
}
116+
117+
log.warn("Unknown path type '{}'; ignore it", path);
118+
return Collections.emptyList();
119+
}
120+
121+
private List<NamedPath> getDirectoryNamedPaths(Path path, String name, String dir) {
122+
if (settings.isRemoveRootDir())
123+
return PathUtils.list(path).stream()
124+
.map(p -> StringUtils.isNotBlank(dir)
125+
? NamedPath.create(p, dir + '/' + PathUtils.getName(p))
126+
: NamedPath.create(p))
127+
.sorted(NamedPath.SORT_BY_NAME_ASC)
128+
.collect(Collectors.toList());
129+
130+
return Collections.singletonList(NamedPath.create(path, name));
106131
}
107132

108133
@Override

src/main/java/ru/olegcherednik/zip4jvm/model/settings/ZipEntrySettings.java

+25
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,26 @@ public static Builder builder() {
5454
return new Builder();
5555
}
5656

57+
public static ZipEntrySettings of(Compression compression) {
58+
if (compression == DEFAULT.getCompression())
59+
return DEFAULT;
60+
return builder().compression(compression).build();
61+
}
62+
63+
public static ZipEntrySettings of(Compression compression, Encryption encryption, char[] password) {
64+
if (encryption == Encryption.OFF)
65+
return of(compression);
66+
return builder()
67+
.compression(compression)
68+
.encryption(encryption, password).build();
69+
}
70+
71+
public static ZipEntrySettings of(Encryption encryption, char[] password) {
72+
if (encryption == Encryption.OFF)
73+
return of(DEFAULT.getCompression());
74+
return builder().encryption(encryption, password).build();
75+
}
76+
5777
public Builder toBuilder() {
5878
return new Builder(this);
5979
}
@@ -73,6 +93,7 @@ private ZipEntrySettings(Builder builder) {
7393
@SuppressWarnings("PMD.UnusedAssignment")
7494
public static final class Builder {
7595

96+
7697
private Compression compression = Compression.DEFLATE;
7798
private CompressionLevel compressionLevel = CompressionLevel.NORMAL;
7899
private Encryption encryption = Encryption.OFF;
@@ -100,6 +121,10 @@ public ZipEntrySettings build() {
100121
return new ZipEntrySettings(this);
101122
}
102123

124+
public ZipEntrySettings.Builder compression(Compression compression) {
125+
return compression(compression, CompressionLevel.NORMAL);
126+
}
127+
103128
public ZipEntrySettings.Builder compression(Compression compression, CompressionLevel compressionLevel) {
104129
this.compression = compression;
105130
this.compressionLevel = compressionLevel;

src/main/java/ru/olegcherednik/zip4jvm/model/settings/ZipEntrySettingsProvider.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ public final class ZipEntrySettingsProvider {
3333

3434
public static final ZipEntrySettingsProvider DEFAULT = of(ZipEntrySettings.DEFAULT);
3535

36-
private final Function<String, ZipEntrySettings> func;
36+
private final Function<String, ZipEntrySettings> entryNameSettings;
3737

38-
public static ZipEntrySettingsProvider of(ZipEntrySettings zipEntrySettings) {
39-
return new ZipEntrySettingsProvider(entryName -> zipEntrySettings);
38+
public static ZipEntrySettingsProvider of(ZipEntrySettings entrySettings) {
39+
return new ZipEntrySettingsProvider(entryName -> entrySettings);
4040
}
4141

42-
public static ZipEntrySettingsProvider of(Function<String, ZipEntrySettings> func) {
43-
return new ZipEntrySettingsProvider(func);
42+
public static ZipEntrySettingsProvider of(Function<String, ZipEntrySettings> entryNameSettings) {
43+
return new ZipEntrySettingsProvider(entryNameSettings);
4444
}
4545

4646
// @NotNull
4747
public ZipEntrySettings getEntrySettings(String entryName) {
48-
return Optional.ofNullable(func.apply(entryName))
48+
return Optional.ofNullable(entryNameSettings.apply(entryName))
4949
.orElse(ZipEntrySettings.DEFAULT);
5050
}
5151

src/main/java/ru/olegcherednik/zip4jvm/model/settings/ZipSettings.java

+38-8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919
package ru.olegcherednik.zip4jvm.model.settings;
2020

21+
import ru.olegcherednik.zip4jvm.model.Compression;
22+
import ru.olegcherednik.zip4jvm.model.Encryption;
2123
import ru.olegcherednik.zip4jvm.model.ZipModel;
2224
import ru.olegcherednik.zip4jvm.model.ZipSymlink;
2325
import ru.olegcherednik.zip4jvm.utils.ValidationUtils;
@@ -45,9 +47,20 @@ public final class ZipSettings {
4547
private final ZipSymlink zipSymlink;
4648
private final boolean removeRootDir;
4749

48-
// @NotNull
49-
public ZipEntrySettings getEntrySettings(String entryName) {
50-
return entrySettingsProvider.getEntrySettings(entryName);
50+
public static ZipSettings of(Compression compression) {
51+
return of(ZipEntrySettings.of(compression));
52+
}
53+
54+
public static ZipSettings of(Compression compression, Encryption encryption, char[] password) {
55+
return of(ZipEntrySettings.of(compression, encryption, password));
56+
}
57+
58+
public static ZipSettings of(Encryption encryption, char[] password) {
59+
return of(ZipEntrySettings.of(encryption, password));
60+
}
61+
62+
public static ZipSettings of(ZipEntrySettings entrySettings) {
63+
return entrySettings == ZipEntrySettings.DEFAULT ? DEFAULT : builder().entrySettings(entrySettings).build();
5164
}
5265

5366
public static Builder builder() {
@@ -71,6 +84,11 @@ public Builder toBuilder() {
7184
.entrySettingsProvider(entrySettingsProvider);
7285
}
7386

87+
// @NotNull
88+
public ZipEntrySettings getEntrySettings(String entryName) {
89+
return entrySettingsProvider.getEntrySettings(entryName);
90+
}
91+
7492
@NoArgsConstructor(access = AccessLevel.PRIVATE)
7593
@SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
7694
public static final class Builder {
@@ -109,15 +127,27 @@ public Builder zip64(boolean zip64) {
109127
return this;
110128
}
111129

130+
public Builder entrySettings(Compression compression) {
131+
return entrySettings(ZipEntrySettings.of(compression));
132+
}
133+
134+
public Builder entrySettings(Compression compression, Encryption encryption, char[] password) {
135+
return entrySettings(ZipEntrySettings.of(compression, encryption, password));
136+
}
137+
138+
public Builder entrySettings(Encryption encryption, char[] password) {
139+
return entrySettings(ZipEntrySettings.of(encryption, password));
140+
}
141+
112142
/**
113-
* Apply given {@code zipEntrySettings} to all entries.
143+
* Apply given {@code entrySettings} to all entries.
114144
*
115-
* @param zipEntrySettings not {@literal null} zip entry settings
145+
* @param entrySettings not {@literal null} zip entry settings
116146
* @return this builder
117147
*/
118-
public Builder entrySettings(ZipEntrySettings zipEntrySettings) {
119-
ValidationUtils.requireNotNull(zipEntrySettings, "ZipSettings.entrySettings");
120-
entrySettingsProvider = ZipEntrySettingsProvider.of(zipEntrySettings);
148+
public Builder entrySettings(ZipEntrySettings entrySettings) {
149+
ValidationUtils.requireNotNull(entrySettings, "ZipSettings.entrySettings");
150+
entrySettingsProvider = ZipEntrySettingsProvider.of(entrySettings);
121151
return this;
122152
}
123153

src/main/java/ru/olegcherednik/zip4jvm/utils/ValidationUtils.java

+4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ public static void requireExists(Path path) {
6666
throw new PathNotExistsException(path);
6767
}
6868

69+
public static void requireExists(Collection<Path> paths) {
70+
paths.forEach(ValidationUtils::requireExists);
71+
}
72+
6973
public static void requireRegularFile(Path path, String name) {
7074
if (Files.exists(path) && !Files.isRegularFile(path))
7175
throw new IllegalArgumentException("Path should be a regular file: " + name);

src/test/java/ru/olegcherednik/zip4jvm/ModifyCommentTest.java

+1-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
package ru.olegcherednik.zip4jvm;
2020

2121
import ru.olegcherednik.zip4jvm.model.Compression;
22-
import ru.olegcherednik.zip4jvm.model.CompressionLevel;
2322
import ru.olegcherednik.zip4jvm.model.ZipModel;
2423
import ru.olegcherednik.zip4jvm.model.settings.ZipEntrySettings;
2524
import ru.olegcherednik.zip4jvm.model.settings.ZipSettings;
@@ -60,9 +59,7 @@ public static void removeDir() throws IOException {
6059
}
6160

6261
public void shouldCreateNewZipWithComment() throws IOException {
63-
ZipEntrySettings entrySettings = ZipEntrySettings.builder()
64-
.compression(Compression.DEFLATE, CompressionLevel.NORMAL)
65-
.build();
62+
ZipEntrySettings entrySettings = ZipEntrySettings.of(Compression.DEFLATE);
6663

6764
ZipSettings settings = ZipSettings.builder()
6865
.entrySettings(entrySettings)

src/test/java/ru/olegcherednik/zip4jvm/TestData.java

-9
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,6 @@ public final class TestData {
5454
public static final String dirNameCars = "cars";
5555
public static final String dirNameEmpty = "empty_dir";
5656

57-
public static final String zipDirNameBikes = dirNameBikes + '/';
58-
public static final String zipDirNameCars = dirNameCars + '/';
59-
public static final String zipDirNameEmpty = dirNameEmpty + '/';
60-
6157
public static final String fileNameZipSrc = "src.zip";
6258
public static final String fileNameDataSrc = "src.data";
6359
public static final String fileNameDucati = "ducati-panigale-1199.jpg";
@@ -86,11 +82,6 @@ public final class TestData {
8682
public static final String symlinkAbsFileNameHonda = getAbsoluteSymlinkName(fileNameHonda);
8783
public static final String symlinkAbsDirNameData = getAbsoluteSymlinkName(dirNameSrcData);
8884

89-
public static final String zipSymlinkRelDirNameData = symlinkRelDirNameData + '/';
90-
public static final String zipSymlinkRelDirNameCars = symlinkRelDirNameCars + '/';
91-
public static final String zipSymlinkAbsDirNameData = symlinkAbsDirNameData + '/';
92-
public static final String zipSymlinkTrnDirNameData = symlinkTrnDirNameData + '/';
93-
9485
public static final Path dirBikes = dirSrcData.resolve(dirNameBikes);
9586
public static final Path dirCars = dirSrcData.resolve(dirNameCars);
9687
public static final Path dirEmpty = dirSrcData.resolve(dirNameEmpty);

src/test/java/ru/olegcherednik/zip4jvm/TestDataAssert.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
import java.nio.file.Path;
3333
import java.util.function.Consumer;
3434

35+
import static ru.olegcherednik.zip4jvm.TestData.dirNameBikes;
36+
import static ru.olegcherednik.zip4jvm.TestData.dirNameCars;
37+
import static ru.olegcherednik.zip4jvm.TestData.dirNameEmpty;
3538
import static ru.olegcherednik.zip4jvm.TestData.fileNameBentley;
3639
import static ru.olegcherednik.zip4jvm.TestData.fileNameDucati;
3740
import static ru.olegcherednik.zip4jvm.TestData.fileNameEmpty;
@@ -43,9 +46,6 @@
4346
import static ru.olegcherednik.zip4jvm.TestData.fileNameSigSauer;
4447
import static ru.olegcherednik.zip4jvm.TestData.fileNameSuzuki;
4548
import static ru.olegcherednik.zip4jvm.TestData.fileNameWiesmann;
46-
import static ru.olegcherednik.zip4jvm.TestData.zipDirNameBikes;
47-
import static ru.olegcherednik.zip4jvm.TestData.zipDirNameCars;
48-
import static ru.olegcherednik.zip4jvm.TestData.zipDirNameEmpty;
4949

5050
/**
5151
* @author Oleg Cherednik
@@ -102,9 +102,9 @@ public final class TestDataAssert {
102102
public static final Consumer<IDirectoryAssert<?>> rootAssert = dir -> {
103103
dir.exists().hasEntries(8).hasDirectories(3).hasRegularFiles(5);
104104

105-
dirBikesAssert.accept(dir.directory(zipDirNameBikes));
106-
dirCarsAssert.accept(dir.directory(zipDirNameCars));
107-
dirEmptyAssert.accept(dir.directory(zipDirNameEmpty));
105+
dirBikesAssert.accept(dir.directory(dirNameBikes));
106+
dirCarsAssert.accept(dir.directory(dirNameCars));
107+
dirEmptyAssert.accept(dir.directory(dirNameEmpty));
108108

109109
fileMcdonnelDouglasAssert.accept(dir.regularFile(fileNameMcdonnelDouglas));
110110
fileSaintPetersburgAssert.accept(dir.regularFile(fileNameSaintPetersburg));

0 commit comments

Comments
 (0)