├── .github └── workflows │ ├── build-and-test.yml │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── pom.xml ├── project-info.json └── src ├── main └── java │ └── org │ └── nixos │ └── mvn2nix │ ├── Mvn2NixMojo.java │ ├── ParentPOMPropagatingArtifactDescriptorReaderDelegate.java │ └── URIBuilder.java └── test └── java └── org └── nixos └── mvn2nix └── URIBuilderTest.java /.github/workflows/build-and-test.yml: -------------------------------------------------------------------------------- 1 | name: Build and test mvn2nix-maven-plugin 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Set up JDK 17 15 | uses: actions/setup-java@v3 16 | with: 17 | java-version: '17' 18 | distribution: 'adopt' 19 | cache: maven 20 | - name: Build with Maven 21 | run: mvn --batch-mode package --file pom.xml 22 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Master 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | build: 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v3 13 | - name: Set up JDK 17 14 | uses: actions/setup-java@v3 15 | with: 16 | java-version: '17' 17 | distribution: 'adopt' 18 | cache: maven 19 | - name: Build with Maven 20 | run: mvn --batch-mode package --file pom.xml 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Shea Levy 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mvn2nix 2 | ======== 3 | 4 | **Archived**: see 5 | 6 | ![master](https://github.com/NixOS/mvn2nix-maven-plugin/actions/workflows/main.yml/badge.svg) 7 | 8 | Generate `project-info.json` for use with nix's Maven repository generation 9 | functions. 10 | 11 | Note: This is slower than anyone would like and not expected to be perfect. 12 | Please open issues if something isn't working for you! 13 | 14 | Appears to require maven 3.2.5 to build locally. 15 | 16 | Usage 17 | ------ 18 | 19 | `mvn org.nixos.mvn2nix:mvn2nix-maven-plugin:mvn2nix` 20 | 21 | System properties 22 | ------------------ 23 | 24 | * `mvn2nixOutputFile`: Change the name of the file generated by mvn2nix 25 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.nixos.mvn2nix 6 | mvn2nix-maven-plugin 7 | 1.2.1 8 | maven-plugin 9 | 10 | mvn2nix 11 | Generate project-info.json for use with nix's Maven 12 | repository generation functions. 13 | https://github.com/NixOS/mvn2nix-maven-plugin 14 | 15 | 16 | 17 | MIT License 18 | http://www.opensource.org/license/mit-license.php 19 | 20 | 21 | 22 | 23 | 24 | Shea Levy 25 | shea@shealevy.com 26 | 27 | 28 | 29 | 30 | scm:git:git://github.com/NixOS/mvn2nix-maven-plugin.git 31 | scm:git:git@github.com:NixOS/mvn2nix-maven-plugin.git 32 | https://github.com/NixOS/mvn2nix-maven-plugin 33 | 34 | 35 | 36 | UTF-8 37 | 38 | 39 | 40 | 41 | org.apache.maven 42 | maven-plugin-api 43 | 3.3.3 44 | 45 | 46 | org.apache.maven 47 | maven-core 48 | 3.3.3 49 | 50 | 51 | org.eclipse.aether 52 | aether-api 53 | 1.0.2.v20150114 54 | provided 55 | 56 | 57 | org.apache.maven.plugin-tools 58 | maven-plugin-annotations 59 | 3.4 60 | provided 61 | 62 | 63 | javax.json 64 | javax.json-api 65 | 1.0 66 | 67 | 68 | org.glassfish 69 | javax.json 70 | 1.0.4 71 | runtime 72 | 73 | 74 | org.junit.jupiter 75 | junit-jupiter-engine 76 | 5.6.0 77 | test 78 | 79 | 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-compiler-plugin 85 | 3.3 86 | 87 | 1.7 88 | 1.7 89 | 90 | 91 | 92 | org.apache.maven.plugins 93 | maven-surefire-plugin 94 | 2.22.2 95 | 96 | 97 | 98 | 99 | 100 | release 101 | 102 | 103 | 104 | org.apache.maven.plugins 105 | maven-source-plugin 106 | 2.4 107 | 108 | 109 | attach-sources 110 | 111 | jar-no-fork 112 | 113 | 114 | 115 | 116 | 117 | org.apache.maven.plugins 118 | maven-javadoc-plugin 119 | 2.10.3 120 | 121 | 122 | attach-javadocs 123 | 124 | jar 125 | 126 | 127 | 128 | 129 | 130 | org.apache.maven.plugins 131 | maven-gpg-plugin 132 | 1.6 133 | 134 | 135 | sign-artifacts 136 | verify 137 | 138 | sign 139 | 140 | 141 | 142 | 143 | 144 | org.sonatype.plugins 145 | nexus-staging-maven-plugin 146 | 1.6.3 147 | true 148 | 149 | ossrh 150 | https://oss.sonatype.org/ 151 | true 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | ossrh 161 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/mvn2nix/Mvn2NixMojo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Shea Levy 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package org.nixos.mvn2nix; 25 | 26 | import java.util.List; 27 | import java.util.ArrayList; 28 | import java.util.Set; 29 | import java.util.HashSet; 30 | import java.util.Collection; 31 | import java.util.Iterator; 32 | import java.io.FileNotFoundException; 33 | import java.io.FileOutputStream; 34 | import java.io.UnsupportedEncodingException; 35 | import java.net.URI; 36 | import java.net.URISyntaxException; 37 | 38 | import javax.json.Json; 39 | import javax.json.stream.JsonGenerator; 40 | 41 | import org.apache.maven.plugin.AbstractMojo; 42 | import org.apache.maven.plugin.MojoExecutionException; 43 | import org.apache.maven.plugins.annotations.Mojo; 44 | import org.apache.maven.plugins.annotations.Parameter; 45 | import org.apache.maven.plugins.annotations.Component; 46 | import org.apache.maven.project.MavenProject; 47 | import org.apache.maven.repository.internal.ArtifactDescriptorReaderDelegate; 48 | import org.apache.maven.model.Plugin; 49 | 50 | import org.eclipse.aether.RepositorySystem; 51 | import org.eclipse.aether.DefaultRepositorySystemSession; 52 | import org.eclipse.aether.resolution.ArtifactDescriptorRequest; 53 | import org.eclipse.aether.resolution.ArtifactDescriptorResult; 54 | import org.eclipse.aether.resolution.ArtifactDescriptorException; 55 | import org.eclipse.aether.graph.Dependency; 56 | import org.eclipse.aether.graph.Exclusion; 57 | import org.eclipse.aether.artifact.Artifact; 58 | import org.eclipse.aether.artifact.DefaultArtifact; 59 | import org.eclipse.aether.metadata.Metadata; 60 | import org.eclipse.aether.metadata.DefaultMetadata; 61 | import org.eclipse.aether.resolution.VersionResult; 62 | import org.eclipse.aether.resolution.VersionRequest; 63 | import org.eclipse.aether.resolution.VersionResolutionException; 64 | import org.eclipse.aether.repository.RemoteRepository; 65 | import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider; 66 | import org.eclipse.aether.spi.connector.layout.RepositoryLayout; 67 | import org.eclipse.aether.spi.connector.transport.GetTask; 68 | import org.eclipse.aether.spi.connector.transport.Transporter; 69 | import org.eclipse.aether.spi.connector.transport.TransporterProvider; 70 | import org.eclipse.aether.transfer.NoRepositoryLayoutException; 71 | import org.eclipse.aether.transfer.NoTransporterException; 72 | 73 | /** 74 | * A Mojo to generate JSON for use with nix's Maven repository generation 75 | * functions 76 | * 77 | * @author Shea Levy 78 | */ 79 | @Mojo(name = "mvn2nix") 80 | public class Mvn2NixMojo extends AbstractMojo 81 | { 82 | @Component 83 | private MavenProject project; 84 | 85 | @Component 86 | private RepositorySystem repoSystem; 87 | 88 | @Component 89 | private RepositoryLayoutProvider layoutProvider; 90 | 91 | @Component 92 | private TransporterProvider transporterProvider; 93 | 94 | @Parameter(property="repositorySystemSession", readonly=true) 95 | private DefaultRepositorySystemSession repoSession; 96 | 97 | @Parameter(property="reactorProjects", readonly=true) 98 | private List reactorProjects; 99 | 100 | @Parameter(property="mvn2nixOutputFile", 101 | defaultValue="project-info.json") 102 | private String outputFile; 103 | 104 | private Exclusion mavenExclusionToExclusion( 105 | org.apache.maven.model.Exclusion excl) { 106 | return new Exclusion(excl.getGroupId(), 107 | excl.getArtifactId(), 108 | null, 109 | null); 110 | } 111 | 112 | private Dependency mavenDependencyToDependency( 113 | org.apache.maven.model.Dependency dep) { 114 | Artifact art = new DefaultArtifact(dep.getGroupId(), 115 | dep.getArtifactId(), 116 | dep.getClassifier(), 117 | dep.getType(), 118 | dep.getVersion()); 119 | Collection excls = new HashSet(); 120 | for (org.apache.maven.model.Exclusion excl : 121 | dep.getExclusions()) { 122 | excls.add(mavenExclusionToExclusion(excl)); 123 | } 124 | return new Dependency(art, 125 | dep.getScope(), 126 | new Boolean(dep.isOptional()), 127 | excls); 128 | } 129 | 130 | private Artifact mavenArtifactToArtifact( 131 | org.apache.maven.artifact.Artifact art) { 132 | return new DefaultArtifact(art.getGroupId(), 133 | art.getArtifactId(), 134 | art.getClassifier(), 135 | art.getType(), 136 | art.getVersion()); 137 | } 138 | 139 | private void emitArtifactBody(Artifact art, Collection deps, 140 | JsonGenerator gen) { 141 | gen.write("artifactId", art.getArtifactId()); 142 | gen.write("groupId", art.getGroupId()); 143 | gen.write("version", art.getVersion()); 144 | gen.write("classifier", art.getClassifier()); 145 | gen.write("extension", art.getExtension()); 146 | 147 | if (deps != null) { 148 | gen.writeStartArray("dependencies"); 149 | for (Dependency dep : deps) { 150 | gen.writeStartObject(); 151 | 152 | emitArtifactBody(dep.getArtifact(), null, gen); 153 | 154 | gen.write("scope", dep.getScope()); 155 | gen.write("optional", dep.isOptional()); 156 | 157 | gen.writeStartArray("exclusions"); 158 | for (Exclusion excl : dep.getExclusions()) { 159 | gen.writeStartObject(); 160 | gen.write("artifactId", 161 | excl.getArtifactId()); 162 | gen.write("classifier", 163 | excl.getClassifier()); 164 | gen.write("extension", 165 | excl.getExtension()); 166 | gen.write("groupId", 167 | excl.getGroupId()); 168 | gen.writeEnd(); 169 | } 170 | gen.writeEnd(); 171 | 172 | gen.writeEnd(); 173 | } 174 | gen.writeEnd(); 175 | } 176 | } 177 | 178 | private class ArtifactDownloadInfo 179 | { 180 | public String url; 181 | public String hash; 182 | } 183 | 184 | private ArtifactDownloadInfo getDownloadInfoImpl(String base, 185 | URI fileLoc, 186 | List checksums, 187 | String desc, 188 | Transporter transport) throws MojoExecutionException { 189 | 190 | URI abs; 191 | try { 192 | abs = URIBuilder.build(base, fileLoc); 193 | } catch (URISyntaxException e) { 194 | throw new MojoExecutionException( 195 | "Parsing repository URI", 196 | e); 197 | } 198 | 199 | ArtifactDownloadInfo res = new ArtifactDownloadInfo(); 200 | res.url = abs.toString(); 201 | 202 | GetTask task = null; 203 | for (RepositoryLayout.Checksum ck : checksums) { 204 | if (ck.getAlgorithm().equals("SHA-1")) { 205 | task = new GetTask(ck.getLocation()); 206 | break; 207 | } 208 | } 209 | 210 | if (task == null) { 211 | throw new MojoExecutionException( 212 | "No SHA-1 for " + desc); 213 | } 214 | 215 | try { 216 | transport.get(task); 217 | } catch (Exception e) { 218 | throw new MojoExecutionException( 219 | "Downloading SHA-1 for " + desc, 220 | e); 221 | } 222 | 223 | try { 224 | res.hash = new String(task.getDataBytes(), 225 | 0, 226 | 40, 227 | "UTF-8"); 228 | } catch (UnsupportedEncodingException e) { 229 | throw new MojoExecutionException( 230 | "Your jvm doesn't support UTF-8, fix that", 231 | e); 232 | } 233 | return res; 234 | } 235 | 236 | private ArtifactDownloadInfo getDownloadInfo(Artifact art, 237 | RepositoryLayout layout, 238 | String base, 239 | Transporter transport) throws MojoExecutionException { 240 | URI fileLoc = layout.getLocation(art, false); 241 | List checksums = 242 | layout.getChecksums(art, false, fileLoc); 243 | return getDownloadInfoImpl(base, 244 | fileLoc, 245 | checksums, 246 | art.toString(), 247 | transport); 248 | } 249 | 250 | private ArtifactDownloadInfo getDownloadInfo(Metadata m, 251 | RepositoryLayout layout, 252 | String base, 253 | Transporter transport) throws MojoExecutionException { 254 | URI fileLoc = layout.getLocation(m, false); 255 | List checksums = 256 | layout.getChecksums(m, false, fileLoc); 257 | return getDownloadInfoImpl(base, 258 | fileLoc, 259 | checksums, 260 | m.toString(), 261 | transport); 262 | } 263 | 264 | private void handleDependency(Dependency dep, 265 | List repos, 266 | Set work, 267 | Set printed, 268 | JsonGenerator gen) throws MojoExecutionException { 269 | Artifact art = dep.getArtifact(); 270 | 271 | ArtifactDownloadInfo metadataInfo = null; 272 | String unresolvedVersion = art.getVersion(); 273 | if (art.isSnapshot()) { 274 | VersionRequest vReq = new VersionRequest(art, 275 | repos, 276 | null); 277 | VersionResult res; 278 | try { 279 | res = repoSystem.resolveVersion( 280 | repoSession, 281 | vReq); 282 | } catch (VersionResolutionException e) { 283 | throw new MojoExecutionException( 284 | "Resolving version of " + 285 | art.toString(), 286 | e); 287 | } 288 | 289 | if (!res.getVersion().equals(art.getVersion())) { 290 | art = new DefaultArtifact( 291 | art.getGroupId(), 292 | art.getArtifactId(), 293 | art.getClassifier(), 294 | art.getExtension(), 295 | res.getVersion()); 296 | if (res.getRepository() instanceof 297 | RemoteRepository) { 298 | RemoteRepository repo = 299 | (RemoteRepository) res 300 | .getRepository(); 301 | Metadata m = 302 | new DefaultMetadata( 303 | art.getGroupId(), 304 | art.getArtifactId(), 305 | unresolvedVersion, 306 | "maven-metadata.xml", 307 | Metadata.Nature.RELEASE_OR_SNAPSHOT); 308 | RepositoryLayout layout; 309 | try { 310 | layout = layoutProvider 311 | .newRepositoryLayout( 312 | repoSession, 313 | repo); 314 | } catch (NoRepositoryLayoutException e) { 315 | throw new MojoExecutionException( 316 | "Getting repository layout", 317 | e); 318 | } 319 | String base = repo.getUrl(); 320 | /* TODO: Open the transporters all at 321 | * once */ 322 | try (Transporter transport = 323 | transporterProvider 324 | .newTransporter( 325 | repoSession, 326 | repo)) { 327 | metadataInfo = getDownloadInfo( 328 | m, 329 | layout, 330 | base, 331 | transport); 332 | } catch (NoTransporterException e) { 333 | throw new 334 | MojoExecutionException( 335 | "No transporter for " + 336 | art.toString(), 337 | e); 338 | } 339 | } 340 | } 341 | } 342 | ArtifactDescriptorRequest req = new ArtifactDescriptorRequest( 343 | art, 344 | repos, 345 | null); 346 | ArtifactDescriptorResult res; 347 | try { 348 | res = repoSystem.readArtifactDescriptor(repoSession, 349 | req); 350 | } catch (ArtifactDescriptorException e) { 351 | throw new MojoExecutionException( 352 | "getting descriptor for " + art.toString(), 353 | e); 354 | } 355 | 356 | /* Ensure we're keying on the things we care about */ 357 | Artifact artKey = new DefaultArtifact(art.getGroupId(), 358 | art.getArtifactId(), 359 | art.getClassifier(), 360 | art.getExtension(), 361 | unresolvedVersion); 362 | if (printed.add(artKey)) { 363 | gen.writeStartObject(); 364 | emitArtifactBody(art, 365 | res.getDependencies(), 366 | gen); 367 | if (metadataInfo != null) { 368 | gen.write("unresolved-version", 369 | unresolvedVersion); 370 | gen.write("repository-id", 371 | res.getRepository().getId()); 372 | gen.writeStartObject("metadata"); 373 | gen.write("url", metadataInfo.url); 374 | gen.write("sha1", metadataInfo.hash); 375 | gen.writeEnd(); 376 | } 377 | if (res.getRepository() instanceof RemoteRepository) { 378 | RemoteRepository repo = (RemoteRepository) res 379 | .getRepository(); 380 | gen.write("authenticated", 381 | repo.getAuthentication() != null); 382 | RepositoryLayout layout; 383 | try { 384 | layout = layoutProvider 385 | .newRepositoryLayout( 386 | repoSession, 387 | repo); 388 | } catch (NoRepositoryLayoutException e) { 389 | throw new MojoExecutionException( 390 | "Getting repository layout", 391 | e); 392 | } 393 | 394 | String base = repo.getUrl(); 395 | /* TODO: Open the transporters all at once */ 396 | try (Transporter transport = 397 | transporterProvider.newTransporter( 398 | repoSession 399 | , repo)) { 400 | ArtifactDownloadInfo info = 401 | getDownloadInfo(art, 402 | layout, 403 | base, 404 | transport); 405 | gen.write("url", info.url); 406 | gen.write("sha1", info.hash); 407 | 408 | gen.writeStartArray("relocations"); 409 | for (Artifact rel : 410 | res.getRelocations()) { 411 | Artifact relPom = 412 | new DefaultArtifact( 413 | rel.getGroupId(), 414 | rel.getArtifactId(), 415 | rel.getClassifier(), 416 | "pom", 417 | rel.getVersion()); 418 | gen.writeStartObject(); 419 | info = getDownloadInfo(art, 420 | layout, 421 | base, 422 | transport); 423 | gen.write("url", info.url); 424 | gen.write("sha1", info.hash); 425 | gen.writeEnd(); 426 | } 427 | gen.writeEnd(); 428 | } catch (NoTransporterException e) { 429 | throw new MojoExecutionException( 430 | "No transporter for " + 431 | art.toString(), 432 | e); 433 | } 434 | } 435 | gen.writeEnd(); 436 | } 437 | 438 | if (!art.getExtension().equals("pom")) { 439 | Artifact pomArt = new DefaultArtifact(art.getGroupId(), 440 | art.getArtifactId(), 441 | null, 442 | "pom", 443 | unresolvedVersion); 444 | Dependency pomDep = new Dependency(pomArt, 445 | "compile", 446 | new Boolean(false), 447 | dep.getExclusions()); 448 | work.add(pomDep); 449 | } 450 | 451 | for (Dependency subDep : res.getDependencies()) { 452 | if (subDep.isOptional()) { 453 | continue; 454 | } 455 | String scope = subDep.getScope(); 456 | if (scope != null && (scope.equals("provided") 457 | || scope.equals("test") 458 | || scope.equals("system"))) { 459 | continue; 460 | } 461 | Artifact subArt = subDep.getArtifact(); 462 | HashSet excls = new HashSet(); 463 | boolean excluded = false; 464 | for (Exclusion excl : dep.getExclusions()) { 465 | if (excl.getArtifactId().equals( 466 | subArt.getArtifactId()) && 467 | excl.getGroupId().equals( 468 | subArt.getGroupId())) { 469 | excluded = true; 470 | break; 471 | } 472 | excls.add(excl); 473 | } 474 | if (excluded) { 475 | continue; 476 | } 477 | for (Exclusion excl : subDep.getExclusions()) { 478 | excls.add(excl); 479 | } 480 | 481 | Dependency newDep = new Dependency(subArt, 482 | dep.getScope(), 483 | dep.getOptional(), 484 | excls); 485 | work.add(newDep); 486 | } 487 | } 488 | 489 | static Set work = new HashSet(); 490 | static Set seen = new HashSet(); 491 | static Set printed = new HashSet(); 492 | 493 | @Override 494 | public void execute() throws MojoExecutionException 495 | { 496 | repoSession = new DefaultRepositorySystemSession(repoSession); 497 | ParentPOMPropagatingArtifactDescriptorReaderDelegate d = new 498 | ParentPOMPropagatingArtifactDescriptorReaderDelegate(); 499 | repoSession.setConfigProperty( 500 | ArtifactDescriptorReaderDelegate.class.getName(), 501 | d); 502 | repoSession.setReadOnly(); 503 | 504 | MavenProject parent = project.getParent(); 505 | while(parent != null){ 506 | Artifact art = new DefaultArtifact(parent.getGroupId(), 507 | parent.getArtifactId(), 508 | "pom", 509 | parent.getVersion()); 510 | Dependency dep = new Dependency(art, "compile"); 511 | work.add(dep); 512 | parent = parent.getParent(); 513 | } 514 | for (Plugin p : project.getBuildPlugins()) { 515 | Artifact art = new DefaultArtifact(p.getGroupId(), 516 | p.getArtifactId(), 517 | null, 518 | "jar", 519 | p.getVersion()); 520 | Dependency dep = new Dependency(art, "compile"); 521 | work.add(dep); 522 | for (org.apache.maven.model.Dependency subDep : 523 | p.getDependencies()) { 524 | work.add(mavenDependencyToDependency(subDep)); 525 | } 526 | } 527 | for (org.apache.maven.model.Dependency dep : 528 | project.getDependencies()) { 529 | work.add(mavenDependencyToDependency(dep)); 530 | } 531 | if (reactorProjects.get(reactorProjects.size() -1) == project) { 532 | /* This is the last project, now all the dependencies have been accumulated 533 | * and we can generate project info. 534 | */ 535 | 536 | try (JsonGenerator gen = Json.createGenerator(new FileOutputStream(outputFile))) { 537 | gen.writeStartObject(); 538 | 539 | gen.writeStartObject("project"); 540 | emitArtifactBody( 541 | mavenArtifactToArtifact(project.getArtifact()), 542 | work, 543 | gen); 544 | gen.writeEnd(); 545 | 546 | gen.writeStartArray("dependencies"); 547 | List repos = 548 | new ArrayList( 549 | project.getRemoteProjectRepositories()); 550 | repos.addAll(project.getRemotePluginRepositories()); 551 | while (!work.isEmpty()) { 552 | Iterator it = work.iterator(); 553 | Dependency dep = it.next(); 554 | it.remove(); 555 | 556 | if (seen.add(dep)) { 557 | handleDependency(dep, 558 | repos, 559 | work, 560 | printed, 561 | gen); 562 | } 563 | } 564 | gen.writeEnd(); 565 | 566 | gen.writeEnd(); 567 | } catch (FileNotFoundException e) { 568 | throw new MojoExecutionException( 569 | "Opening " + outputFile, 570 | e); 571 | } 572 | } 573 | } 574 | } 575 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/mvn2nix/ParentPOMPropagatingArtifactDescriptorReaderDelegate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Shea Levy 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package org.nixos.mvn2nix; 25 | 26 | import org.apache.maven.model.Model; 27 | import org.apache.maven.model.Parent; 28 | import org.apache.maven.repository.internal.ArtifactDescriptorReaderDelegate; 29 | 30 | import org.eclipse.aether.RepositorySystemSession; 31 | import org.eclipse.aether.resolution.ArtifactDescriptorResult; 32 | import org.eclipse.aether.artifact.DefaultArtifact; 33 | import org.eclipse.aether.graph.Dependency; 34 | 35 | /** 36 | * An ArtifactDescriptorReaderDelegate that adds any 37 | * <parent> POMs as dependencies. 38 | * 39 | * @author Shea Levy 40 | */ 41 | public class ParentPOMPropagatingArtifactDescriptorReaderDelegate 42 | extends ArtifactDescriptorReaderDelegate 43 | { 44 | @Override 45 | public void populateResult(RepositorySystemSession session, 46 | ArtifactDescriptorResult result, 47 | Model model) { 48 | super.populateResult(session, result, model); 49 | Parent parent = model.getParent(); 50 | if (parent != null) { 51 | DefaultArtifact art = 52 | new DefaultArtifact(parent.getGroupId(), 53 | parent.getArtifactId(), 54 | "pom", 55 | parent.getVersion()); 56 | Dependency dep = new Dependency(art, "compile"); 57 | result.addDependency(dep); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/mvn2nix/URIBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Benjamin Asbach 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package org.nixos.mvn2nix; 25 | 26 | import java.net.URI; 27 | import java.net.URISyntaxException; 28 | 29 | public final class URIBuilder { 30 | 31 | private URIBuilder() { 32 | } 33 | 34 | /** 35 | * Combines and normalizes an URI base with a suffix. 36 | * 37 | * @param base 38 | * @param baseSuffix 39 | * @return 40 | * @throws URISyntaxException 41 | */ 42 | public static URI build(String base, URI baseSuffix) throws URISyntaxException { 43 | return new URI(base + "/" + baseSuffix).normalize(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/mvn2nix/URIBuilderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Benjamin Asbach 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | package org.nixos.mvn2nix; 25 | 26 | import java.net.URI; 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | import org.junit.jupiter.api.Test; 29 | 30 | public class URIBuilderTest { 31 | 32 | @Test 33 | public void shouldBuildURI() throws Exception { 34 | assertEquals( 35 | new URI("https://repo.maven.apache.org/maven2/org/assertj/assertj-core/3.16.1/assertj-core-3.16.1.jar"), 36 | URIBuilder.build("https://repo.maven.apache.org/maven2", new URI("org/assertj/assertj-core/3.16.1/assertj-core-3.16.1.jar")) 37 | ); 38 | } 39 | 40 | @Test 41 | public void shouldNotDoubleSlashWhenBaseEndsWithSlash() throws Exception { 42 | assertEquals( 43 | new URI("https://repo.maven.apache.org/maven2/org/assertj/assertj-core/3.16.1/assertj-core-3.16.1.jar"), 44 | URIBuilder.build("https://repo.maven.apache.org/maven2/", new URI("org/assertj/assertj-core/3.16.1/assertj-core-3.16.1.jar")) 45 | ); 46 | } 47 | 48 | @Test 49 | public void shouldNotDoubleSlashWhenPathSuffixStartsWithSlash() throws Exception { 50 | assertEquals( 51 | new URI("https://repo.maven.apache.org/maven2/org/assertj/assertj-core/3.16.1/assertj-core-3.16.1.jar"), 52 | URIBuilder.build("https://repo.maven.apache.org/maven2", new URI("/org/assertj/assertj-core/3.16.1/assertj-core-3.16.1.jar")) 53 | ); 54 | } 55 | } 56 | --------------------------------------------------------------------------------