001package org.eclipse.aether.internal.impl.synccontext.named; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.eclipse.aether.RepositorySystemSession; 023import org.eclipse.aether.artifact.Artifact; 024import org.eclipse.aether.metadata.Metadata; 025import org.eclipse.aether.named.support.FileSystemFriendly; 026 027import javax.inject.Named; 028import javax.inject.Singleton; 029 030import java.io.File; 031import java.io.IOException; 032import java.io.UncheckedIOException; 033import java.nio.file.Path; 034import java.util.Collection; 035import java.util.TreeSet; 036import java.util.concurrent.ConcurrentHashMap; 037import java.util.concurrent.ConcurrentMap; 038 039/** 040 * A {@link NameMapper} that creates same name mapping as Takari Local Repository does, with 041 * {@code baseDir} (local repo). Part of code blatantly copies parts of the Takari 042 * {@code LockingSyncContext}. 043 * 044 * @see <a href="https://github.com/takari/takari-local-repository/blob/24133e50a0478dccb5620ac2f2255187608f165b/src/main/java/io/takari/aether/concurrency/LockingSyncContext.java">Takari 045 * LockingSyncContext.java</a> 046 */ 047@Singleton 048@Named( FileGAVNameMapper.NAME ) 049public class FileGAVNameMapper 050 implements NameMapper, FileSystemFriendly 051{ 052 public static final String NAME = "file-gav"; 053 054 private static final String LOCK_SUFFIX = ".resolverlock"; 055 056 private static final char SEPARATOR = '~'; 057 058 private final ConcurrentMap<String, Path> baseDirs; 059 060 public FileGAVNameMapper() 061 { 062 this.baseDirs = new ConcurrentHashMap<>(); 063 } 064 065 @Override 066 public TreeSet<String> nameLocks( final RepositorySystemSession session, 067 final Collection<? extends Artifact> artifacts, 068 final Collection<? extends Metadata> metadatas ) 069 { 070 File localRepositoryBasedir = session.getLocalRepository().getBasedir(); 071 // here we abuse concurrent hash map to make sure costly getCanonicalFile is invoked only once 072 Path baseDir = baseDirs.computeIfAbsent( 073 localRepositoryBasedir.getPath(), k -> 074 { 075 try 076 { 077 return new File( localRepositoryBasedir, ".locks" ).getCanonicalFile().toPath(); 078 } 079 catch ( IOException e ) 080 { 081 throw new UncheckedIOException( e ); 082 } 083 } 084 ); 085 086 TreeSet<String> paths = new TreeSet<>(); 087 if ( artifacts != null ) 088 { 089 for ( Artifact artifact : artifacts ) 090 { 091 paths.add( getPath( baseDir, artifact ) + LOCK_SUFFIX ); 092 } 093 } 094 if ( metadatas != null ) 095 { 096 for ( Metadata metadata : metadatas ) 097 { 098 paths.add( getPath( baseDir, metadata ) + LOCK_SUFFIX ); 099 } 100 } 101 return paths; 102 } 103 104 private String getPath( final Path baseDir, final Artifact artifact ) 105 { 106 // NOTE: Don't use LRM.getPath*() as those paths could be different across processes, e.g. due to staging LRMs. 107 String path = artifact.getGroupId() 108 + SEPARATOR + artifact.getArtifactId() 109 + SEPARATOR + artifact.getBaseVersion(); 110 return baseDir.resolve( path ).toAbsolutePath().toString(); 111 } 112 113 private String getPath( final Path baseDir, final Metadata metadata ) 114 { 115 // NOTE: Don't use LRM.getPath*() as those paths could be different across processes, e.g. due to staging. 116 String path = ""; 117 if ( metadata.getGroupId().length() > 0 ) 118 { 119 path += metadata.getGroupId(); 120 if ( metadata.getArtifactId().length() > 0 ) 121 { 122 path += SEPARATOR + metadata.getArtifactId(); 123 if ( metadata.getVersion().length() > 0 ) 124 { 125 path += SEPARATOR + metadata.getVersion(); 126 } 127 } 128 } 129 return baseDir.resolve( path ).toAbsolutePath().toString(); 130 } 131}