1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codehaus.plexus.archiver.dir;
17
18 import javax.inject.Named;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.nio.file.Files;
24 import java.nio.file.attribute.FileTime;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import org.codehaus.plexus.archiver.AbstractArchiver;
29 import org.codehaus.plexus.archiver.ArchiveEntry;
30 import org.codehaus.plexus.archiver.ArchiverException;
31 import org.codehaus.plexus.archiver.ResourceIterator;
32 import org.codehaus.plexus.archiver.exceptions.EmptyArchiveException;
33 import org.codehaus.plexus.archiver.util.ArchiveEntryUtils;
34 import org.codehaus.plexus.archiver.util.ResourceUtils;
35 import org.codehaus.plexus.components.io.attributes.SymlinkUtils;
36 import org.codehaus.plexus.components.io.functions.SymlinkDestinationSupplier;
37 import org.codehaus.plexus.components.io.resources.PlexusIoResource;
38
39
40
41
42 @Named("dir")
43 public class DirectoryArchiver extends AbstractArchiver {
44
45 private final List<Runnable> directoryChmods = new ArrayList<>();
46 private long filesCopied;
47
48
49
50
51 public DirectoryArchiver() {
52
53 setForced(false);
54 }
55
56 public void resetArchiver() throws IOException {
57 cleanUp();
58 }
59
60 @Override
61 public void execute() throws ArchiverException, IOException {
62
63
64 final ResourceIterator iter = getResources();
65 if (!iter.hasNext()) {
66 throw new EmptyArchiveException("archive cannot be empty");
67 }
68
69 final File destDirectory = getDestFile();
70 if (destDirectory == null) {
71 throw new ArchiverException("You must set the destination directory.");
72 }
73 if (destDirectory.exists() && !destDirectory.isDirectory()) {
74 throw new ArchiverException(destDirectory + " is not a directory.");
75 }
76 if (destDirectory.exists() && !destDirectory.canWrite()) {
77 throw new ArchiverException(destDirectory + " is not writable.");
78 }
79
80 getLogger().info("Copying files to {}", destDirectory.getAbsolutePath());
81
82 try {
83 while (iter.hasNext()) {
84 final ArchiveEntry f = iter.next();
85
86 if (ResourceUtils.isSame(f.getResource(), destDirectory)) {
87 throw new ArchiverException("The destination directory cannot include itself.");
88 }
89 String fileName = f.getName();
90 final String destDir = destDirectory.getCanonicalPath();
91 fileName = destDir + File.separator + fileName;
92 PlexusIoResource resource = f.getResource();
93 if (resource instanceof SymlinkDestinationSupplier) {
94 String dest = ((SymlinkDestinationSupplier) resource).getSymlinkDestination();
95 File target = new File(dest);
96 File symlink = new File(fileName);
97 makeParentDirectories(symlink);
98 SymlinkUtils.createSymbolicLink(symlink, target);
99 } else {
100 copyFile(f, fileName);
101 }
102 }
103
104 directoryChmods.forEach(Runnable::run);
105 directoryChmods.clear();
106
107 if (filesCopied > 0) {
108 getLogger()
109 .info(
110 "{} file{} copied to {}",
111 filesCopied,
112 filesCopied > 0 ? "s" : "",
113 destDirectory.getAbsolutePath());
114 } else {
115 getLogger().info("All files are uptodate in {}", destDirectory.getAbsolutePath());
116 }
117
118 filesCopied = 0;
119
120 } catch (final IOException ioe) {
121 final String message = "Problem copying files : " + ioe.getMessage();
122 throw new ArchiverException(message, ioe);
123 }
124 }
125
126
127
128
129
130
131
132
133
134
135 protected void copyFile(final ArchiveEntry entry, final String vPath) throws ArchiverException, IOException {
136
137 if (vPath.length() <= 0) {
138 return;
139 }
140
141 final PlexusIoResource in = entry.getResource();
142 final File outFile = new File(vPath);
143
144 final long inLastModified = in.getLastModified();
145
146 if (!isForced()) {
147 final long outLastModified = outFile.lastModified();
148 if (ResourceUtils.isUptodate(inLastModified, outLastModified)) {
149 return;
150 }
151 }
152
153 if (!in.isDirectory()) {
154 makeParentDirectories(outFile);
155 try (InputStream input = entry.getInputStream()) {
156 ResourceUtils.copyFile(input, outFile);
157 }
158 filesCopied++;
159 setFileModes(entry, outFile, inLastModified);
160 } else {
161 if (outFile.exists()) {
162 if (!outFile.isDirectory()) {
163
164
165 throw new ArchiverException("Expected directory and found file at copy destination of "
166 + in.getName() + " to " + outFile);
167 }
168 } else if (!outFile.mkdirs()) {
169
170 throw new ArchiverException("Unable to create directory or parent directory of " + outFile);
171 }
172
173 directoryChmods.add(() -> {
174 try {
175 setFileModes(entry, outFile, inLastModified);
176 } catch (IOException e) {
177 throw new ArchiverException("Failed setting file attributes", e);
178 }
179 });
180 }
181 }
182
183 private static void makeParentDirectories(File file) {
184 if (!file.getParentFile().exists()) {
185
186 if (!file.getParentFile().mkdirs()) {
187
188 throw new ArchiverException("Unable to create directory or parent directory of " + file);
189 }
190 }
191 }
192
193 private void setFileModes(ArchiveEntry entry, File outFile, long inLastModified) throws IOException {
194 if (!isIgnorePermissions()) {
195 ArchiveEntryUtils.chmod(outFile, entry.getMode());
196 }
197
198 if (getLastModifiedTime() == null) {
199 FileTime fromMillis = FileTime.fromMillis(
200 inLastModified == PlexusIoResource.UNKNOWN_MODIFICATION_DATE
201 ? System.currentTimeMillis()
202 : inLastModified);
203 Files.setLastModifiedTime(outFile.toPath(), fromMillis);
204 } else {
205 Files.setLastModifiedTime(outFile.toPath(), getLastModifiedTime());
206 }
207 }
208
209 @Override
210 protected void cleanUp() throws IOException {
211 super.cleanUp();
212 setIncludeEmptyDirs(false);
213 setIncludeEmptyDirs(true);
214 }
215
216 @Override
217 protected void close() throws IOException {}
218
219 @Override
220 protected String getArchiveType() {
221 return "directory";
222 }
223
224 @Override
225 public boolean isSupportingForced() {
226 return true;
227 }
228 }