|
7 | 7 | import java.net.URI; |
8 | 8 | import java.nio.file.Files; |
9 | 9 | import java.nio.file.Path; |
| 10 | +import java.util.ArrayList; |
| 11 | +import java.util.LinkedHashMap; |
| 12 | +import java.util.List; |
| 13 | +import java.util.Map; |
10 | 14 | import java.util.zip.ZipEntry; |
11 | 15 | import java.util.zip.ZipOutputStream; |
12 | 16 |
|
|
19 | 23 |
|
20 | 24 | public class MavenFileRepository extends MavenBackingRepository { |
21 | 25 |
|
22 | | - private final File remote; |
| 26 | + private final File remote; |
23 | 27 | private HttpClient client = null; |
24 | 28 |
|
25 | 29 | public MavenFileRepository(File localRepo, File remote, Reporter reporter) throws Exception { |
@@ -89,62 +93,160 @@ public boolean isRemote() { |
89 | 93 | return false; |
90 | 94 | } |
91 | 95 |
|
92 | | - /** |
93 | | - * Creates a ZIP archive containing all files from the remote repository directory. |
94 | | - * |
95 | | - * @param outputFile the destination file for the ZIP archive |
96 | | - * @return the created ZIP file |
97 | | - * @throws IOException if an error occurs during ZIP creation |
98 | | - */ |
99 | | - public File createZipArchive(File outputFile) throws IOException { |
100 | | - if (!remote.exists() || !remote.isDirectory()) { |
101 | | - throw new IllegalStateException("Remote directory does not exist or is not a directory: " + remote); |
102 | | - } |
103 | | - |
104 | | - IO.mkdirs(outputFile.getParentFile()); |
105 | | - |
106 | | - try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outputFile))) { |
107 | | - Path remotePath = remote.toPath(); |
108 | | - |
109 | | - Files.walk(remotePath) |
110 | | - .filter(path -> !Files.isDirectory(path)) |
111 | | - .forEach(path -> { |
112 | | - try { |
113 | | - Path relativePath = remotePath.relativize(path); |
114 | | - ZipEntry zipEntry = new ZipEntry(relativePath.toString().replace("\\", "/")); |
115 | | - |
116 | | - zos.putNextEntry(zipEntry); |
117 | | - |
118 | | - try (FileInputStream fis = new FileInputStream(path.toFile())) { |
119 | | - byte[] buffer = new byte[4096]; |
120 | | - int len; |
121 | | - while ((len = fis.read(buffer)) > 0) { |
122 | | - zos.write(buffer, 0, len); |
123 | | - } |
124 | | - } |
125 | | - |
126 | | - zos.closeEntry(); |
127 | | - } catch (IOException e) { |
128 | | - reporter.error("Error adding file %s to ZIP archive: %s", path, e.getMessage()); |
129 | | - } |
130 | | - }); |
131 | | - } |
132 | | - |
133 | | - return outputFile; |
134 | | - } |
135 | | - |
136 | | - /** |
137 | | - * Creates a ZIP archive containing all files from the remote repository directory. |
138 | | - * The ZIP file will be created in the system temp directory with a generated name. |
139 | | - * |
140 | | - * @return the created ZIP file |
141 | | - * @throws IOException if an error occurs during ZIP creation |
142 | | - */ |
143 | | - public File createZipArchive() throws IOException { |
144 | | - File tempFile = File.createTempFile("sonatype-bundle-", ".zip"); |
145 | | - tempFile.deleteOnExit(); |
146 | | - return createZipArchive(tempFile); |
147 | | - } |
| 96 | + /** |
| 97 | + * Discovers all groupIds in the Maven repository by analyzing the directory |
| 98 | + * structure. |
| 99 | + * |
| 100 | + * @return map of groupId to its directory path |
| 101 | + * @throws IOException if an error occurs reading the directory |
| 102 | + */ |
| 103 | + private Map<String, File> discoverGroupIds() throws IOException { |
| 104 | + Map<String, File> groupIds = new LinkedHashMap<>(); |
| 105 | + if (!remote.exists() || !remote.isDirectory()) { |
| 106 | + return groupIds; |
| 107 | + } |
| 108 | + |
| 109 | + // Walk the directory tree to find all groupIds |
| 110 | + Files.walk(remote.toPath()) |
| 111 | + .filter(Files::isDirectory) |
| 112 | + .forEach(dir -> { |
| 113 | + File dirFile = dir.toFile(); |
| 114 | + File[] children = dirFile.listFiles(); |
| 115 | + if (children != null && children.length > 0) { |
| 116 | + // Look for artifact directories (contain version |
| 117 | + // subdirectories with artifacts) |
| 118 | + for (File child : children) { |
| 119 | + if (child.isDirectory()) { |
| 120 | + File[] versionDirs = child.listFiles(); |
| 121 | + if (versionDirs != null) { |
| 122 | + for (File versionDir : versionDirs) { |
| 123 | + if (versionDir.isDirectory() && containsArtifacts(versionDir)) { |
| 124 | + // Found a groupId directory |
| 125 | + Path relativePath = remote.toPath() |
| 126 | + .relativize(dir); |
| 127 | + String groupId = relativePath.toString() |
| 128 | + .replace(File.separatorChar, '.'); |
| 129 | + if (!groupId.isEmpty() && !groupIds.containsKey(groupId)) { |
| 130 | + groupIds.put(groupId, dirFile); |
| 131 | + } |
| 132 | + return; |
| 133 | + } |
| 134 | + } |
| 135 | + } |
| 136 | + } |
| 137 | + } |
| 138 | + } |
| 139 | + }); |
| 140 | + |
| 141 | + return groupIds; |
| 142 | + } |
| 143 | + |
| 144 | + /** |
| 145 | + * Checks if a directory contains Maven artifacts (JAR, POM, WAR, AAR |
| 146 | + * files). |
| 147 | + */ |
| 148 | + private boolean containsArtifacts(File dir) { |
| 149 | + File[] files = dir.listFiles(); |
| 150 | + if (files == null) { |
| 151 | + return false; |
| 152 | + } |
| 153 | + for (File file : files) { |
| 154 | + if (file.isFile()) { |
| 155 | + String name = file.getName(); |
| 156 | + if (name.endsWith(".jar") || name.endsWith(".pom") || name.endsWith(".war") || name.endsWith(".aar")) { |
| 157 | + return true; |
| 158 | + } |
| 159 | + } |
| 160 | + } |
| 161 | + return false; |
| 162 | + } |
| 163 | + |
| 164 | + /** |
| 165 | + * Creates ZIP archives, one for each Maven namespace/groupId in the |
| 166 | + * repository. Each archive contains all files for that specific groupId. |
| 167 | + * |
| 168 | + * @return list of created ZIP files with groupId information |
| 169 | + * @throws IOException if an error occurs during ZIP creation |
| 170 | + */ |
| 171 | + public List<GroupIdArchive> createZipArchive() throws IOException { |
| 172 | + if (!remote.exists() || !remote.isDirectory()) { |
| 173 | + throw new IllegalStateException("Remote directory does not exist or is not a directory: " + remote); |
| 174 | + } |
| 175 | + |
| 176 | + List<GroupIdArchive> archives = new ArrayList<>(); |
| 177 | + Map<String, File> groupIds = discoverGroupIds(); |
| 178 | + |
| 179 | + if (groupIds.isEmpty()) { |
| 180 | + reporter.warning("No groupIds found in repository: %s", remote); |
| 181 | + return archives; |
| 182 | + } |
| 183 | + |
| 184 | + reporter.trace("Found %d groupId(s) in repository: %s", groupIds.size(), groupIds.keySet()); |
| 185 | + |
| 186 | + // Create a separate ZIP archive for each groupId |
| 187 | + for (Map.Entry<String, File> entry : groupIds.entrySet()) { |
| 188 | + String groupId = entry.getKey(); |
| 189 | + File groupDir = entry.getValue(); |
| 190 | + |
| 191 | + String sanitizedGroupId = groupId.replace('.', '_'); |
| 192 | + File tempFile = File.createTempFile("sonatype-bundle-" + sanitizedGroupId + "-", ".zip"); |
| 193 | + tempFile.deleteOnExit(); |
| 194 | + |
| 195 | + try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tempFile))) { |
| 196 | + Path groupDirPath = groupDir.toPath(); |
| 197 | + Path remotePath = remote.toPath(); |
| 198 | + |
| 199 | + Files.walk(groupDirPath) |
| 200 | + .filter(path -> !Files.isDirectory(path)) |
| 201 | + .forEach(path -> { |
| 202 | + try { |
| 203 | + // Use path relative to remote root (includes |
| 204 | + // groupId path) |
| 205 | + Path relativePath = remotePath.relativize(path); |
| 206 | + ZipEntry zipEntry = new ZipEntry(relativePath.toString() |
| 207 | + .replace("\\", "/")); |
| 208 | + |
| 209 | + zos.putNextEntry(zipEntry); |
| 210 | + |
| 211 | + try (FileInputStream fis = new FileInputStream(path.toFile())) { |
| 212 | + byte[] buffer = new byte[4096]; |
| 213 | + int len; |
| 214 | + while ((len = fis.read(buffer)) > 0) { |
| 215 | + zos.write(buffer, 0, len); |
| 216 | + } |
| 217 | + } |
| 218 | + |
| 219 | + zos.closeEntry(); |
| 220 | + } catch (IOException e) { |
| 221 | + reporter.error("Error adding file %s to ZIP archive for groupId %s: %s", path, groupId, |
| 222 | + e.getMessage()); |
| 223 | + } |
| 224 | + }); |
| 225 | + } |
| 226 | + |
| 227 | + archives.add(new GroupIdArchive(groupId, tempFile)); |
| 228 | + reporter.trace("Created ZIP archive for groupId %s: %s", groupId, tempFile); |
| 229 | + } |
| 230 | + |
| 231 | + return archives; |
| 232 | + } |
| 233 | + |
| 234 | + /** |
| 235 | + * Container class for a groupId and its corresponding archive file. |
| 236 | + */ |
| 237 | + public static class GroupIdArchive { |
| 238 | + public final String groupId; |
| 239 | + public final File archiveFile; |
| 240 | + |
| 241 | + public GroupIdArchive(String groupId, File archiveFile) { |
| 242 | + this.groupId = groupId; |
| 243 | + this.archiveFile = archiveFile; |
| 244 | + } |
| 245 | + |
| 246 | + public String getSanitizedGroupId() { |
| 247 | + return groupId.replace('.', '_'); |
| 248 | + } |
| 249 | + } |
148 | 250 |
|
149 | 251 | protected HttpClient getClient() { |
150 | 252 | return client; |
|
0 commit comments