Skip to content

WIP [MRESOLVER-310] Preserve configuration of Enhanced LRM in local repo #248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@
public final class DefaultLocalPathPrefixComposerFactory extends LocalPathPrefixComposerFactorySupport
{
@Override
public LocalPathPrefixComposer createComposer( RepositorySystemSession session )
public LocalPathPrefixComposer createComposer( RepositorySystemSession session,
EnhancedLocalRepositoryConfig repositoryConfig )
{
return new DefaultLocalPathPrefixComposer( isSplit( session ), getLocalPrefix( session ),
return new DefaultLocalPathPrefixComposer( repositoryConfig.isSplit(), getLocalPrefix( session ),
isSplitLocal( session ), getRemotePrefix( session ), isSplitRemote( session ),
isSplitRemoteRepository( session ), isSplitRemoteRepositoryLast( session ),
getReleasesPrefix( session ), getSnapshotsPrefix( session ) );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package org.eclipse.aether.internal.impl;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.util.ConfigUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;

/**
* Enhanced Local Repository configuration holder.
*/
class EnhancedLocalRepositoryConfig
{
private static final Logger LOGGER = LoggerFactory.getLogger( EnhancedLocalRepositoryConfig.class );

private static final String CONFIG_PROP_TRACKING_FILENAME = "aether.enhancedLocalRepository.trackingFilename";

private static final String DEFAULT_TRACKING_FILENAME = "_remote.repositories";

protected static final String CONF_PROP_SPLIT = "aether.enhancedLocalRepository.split";

protected static final String DEFAULT_SPLIT = "false";

private Properties config;

EnhancedLocalRepositoryConfig( RepositorySystemSession session, File basedir )
{
try
{
config = loadConfiguration( basedir );
int configHash0 = configurationHash( config );
populateConfiguration( config, session );
int configHash1 = configurationHash( config );

if ( configHash0 != configHash1 )
{
storeConfig( config, basedir );
}
else
{
LOGGER.debug( "Use saved ELRM configuration" );
}
}
catch ( IOException e )
{
throw new UncheckedIOException( e );
}
}

private static void populateConfiguration( Properties configurations, RepositorySystemSession session )
{
populateConfiguration( configurations, session, CONFIG_PROP_TRACKING_FILENAME, DEFAULT_TRACKING_FILENAME );
populateConfiguration( configurations, session, CONF_PROP_SPLIT, DEFAULT_SPLIT );
}

private static void populateConfiguration( Properties configurations, RepositorySystemSession session, String key,
String defaultValue )
{
String valueConf = configurations.getProperty( key );
String valueSession = ConfigUtils.getString( session, null, key );

if ( StringUtils.isNotBlank( valueConf ) && StringUtils.isNotBlank( valueSession )
&& !valueConf.equals( valueSession ) )
{
LOGGER.debug( "New config {}={} for ELRM will not be used", key, valueSession );
}

if ( StringUtils.isBlank( valueConf ) && StringUtils.isNotBlank( valueSession ) )
{
configurations.setProperty( key, valueSession );
}
else if ( StringUtils.isBlank( valueConf ) && StringUtils.isBlank( valueSession ) )
{
configurations.setProperty( key, defaultValue );
}
}

private static int configurationHash( Properties configurations )
{
return configurations.entrySet().stream()
.mapToInt( e -> Objects.hash( e.getKey(), e.getValue() ) )
.reduce( 1, ( i1, i2 ) -> 31 * i1 * i2 );
}

private static Properties loadConfiguration( File basedir ) throws IOException
{
Properties props = new Properties();
Path configPath = Optional.ofNullable( basedir )
.map( File::toPath )
.map( p -> p.resolve( "elrm.properties" ) )
.filter( Files::isReadable )
.orElse( null );

if ( configPath != null )
{
try ( InputStream inputStream = Files.newInputStream( configPath ) )
{
props.load( inputStream );
}
}
return props;
}

private void storeConfig( Properties configurations, File basedir ) throws IOException
{
Path configPath = Optional.ofNullable( basedir )
.map( File::toPath )
.map( p -> p.resolve( "elrm.properties" ) )
.orElse( null );

if ( configPath != null )
{
Path parent = configPath.getParent();
if ( parent != null )
{
Files.createDirectories( parent );
}

LOGGER.debug( "Create local repository configuration: {}", configPath );
try ( OutputStream outputStream = Files.newOutputStream( configPath, WRITE, TRUNCATE_EXISTING, CREATE ) )
{
configurations.store( outputStream, "Enhanced Local Repository Configuration" );
}
}
}

public String getTrackingFilename()
{
return config.getProperty( CONFIG_PROP_TRACKING_FILENAME );
}

public boolean isSplit()
{
return Boolean.parseBoolean( config.getProperty( CONF_PROP_SPLIT ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory;
import org.eclipse.aether.spi.locator.Service;
import org.eclipse.aether.spi.locator.ServiceLocator;
import org.eclipse.aether.util.ConfigUtils;

import static java.util.Objects.requireNonNull;

Expand Down Expand Up @@ -88,7 +87,10 @@ public LocalRepositoryManager newInstance( RepositorySystemSession session, Loca
requireNonNull( session, "session cannot be null" );
requireNonNull( repository, "repository cannot be null" );

String trackingFilename = ConfigUtils.getString( session, "", CONFIG_PROP_TRACKING_FILENAME );
EnhancedLocalRepositoryConfig repositoryConfig =
new EnhancedLocalRepositoryConfig( session, repository.getBasedir() );

String trackingFilename = repositoryConfig.getTrackingFilename();
if ( trackingFilename.isEmpty() || trackingFilename.contains( "/" ) || trackingFilename.contains( "\\" )
|| trackingFilename.contains( ".." ) )
{
Expand All @@ -102,7 +104,7 @@ public LocalRepositoryManager newInstance( RepositorySystemSession session, Loca
localPathComposer,
trackingFilename,
trackingFileManager,
localPathPrefixComposerFactory.createComposer( session )
localPathPrefixComposerFactory.createComposer( session, repositoryConfig )
);
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ public interface LocalPathPrefixComposerFactory
/**
* Creates {@link LocalPathPrefixComposer} instance out of whatever configuration it finds in passed in session.
*
* @param session The repository session, never {@code null}.
* @param session The repository session, never {@code null}.
* @param repositoryConfig The locla repository configuration
* @return The created instance, never {@code null}.
*/
LocalPathPrefixComposer createComposer( RepositorySystemSession session );
LocalPathPrefixComposer createComposer( RepositorySystemSession session,
EnhancedLocalRepositoryConfig repositoryConfig );
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@
*/
public abstract class LocalPathPrefixComposerFactorySupport implements LocalPathPrefixComposerFactory
{
protected static final String CONF_PROP_SPLIT = "aether.enhancedLocalRepository.split";

protected static final boolean DEFAULT_SPLIT = false;

protected static final String CONF_PROP_LOCAL_PREFIX = "aether.enhancedLocalRepository.localPrefix";

protected static final String DEFAULT_LOCAL_PREFIX = "installed";
Expand Down Expand Up @@ -76,12 +72,6 @@ public abstract class LocalPathPrefixComposerFactorySupport implements LocalPath

protected static final String DEFAULT_SNAPSHOTS_PREFIX = "snapshots";

protected boolean isSplit( RepositorySystemSession session )
{
return ConfigUtils.getBoolean(
session, DEFAULT_SPLIT, CONF_PROP_SPLIT );
}

protected String getLocalPrefix( RepositorySystemSession session )
{
return ConfigUtils.getString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
* UT for {@link DefaultLocalPathPrefixComposerFactory}.
Expand All @@ -51,13 +53,15 @@ public class DefaultLocalPathPrefixComposerFactoryTest

private final RemoteRepository repository = new RemoteRepository.Builder( "my-repo", "default", "https://repo.maven.apache.org/maven2/" ).build();

private final EnhancedLocalRepositoryConfig repositoryConfig = mock( EnhancedLocalRepositoryConfig.class );

@Test
public void defaultConfigNoSplitAllNulls()
{
DefaultRepositorySystemSession session = TestUtils.newSession();

LocalPathPrefixComposerFactory factory = new DefaultLocalPathPrefixComposerFactory();
LocalPathPrefixComposer composer = factory.createComposer( session );
LocalPathPrefixComposer composer = factory.createComposer( session, repositoryConfig );
assertNotNull( composer );

String prefix;
Expand All @@ -78,10 +82,10 @@ public void defaultConfigNoSplitAllNulls()
public void splitEnabled()
{
DefaultRepositorySystemSession session = TestUtils.newSession();
session.setConfigProperty( "aether.enhancedLocalRepository.split", Boolean.TRUE.toString() );
when( repositoryConfig.isSplit() ).thenReturn( true );

LocalPathPrefixComposerFactory factory = new DefaultLocalPathPrefixComposerFactory();
LocalPathPrefixComposer composer = factory.createComposer( session );
LocalPathPrefixComposer composer = factory.createComposer( session, repositoryConfig );
assertNotNull( composer );

String prefix;
Expand All @@ -106,12 +110,12 @@ public void splitEnabled()
public void saneConfig()
{
DefaultRepositorySystemSession session = TestUtils.newSession();
session.setConfigProperty( "aether.enhancedLocalRepository.split", Boolean.TRUE.toString() );
when( repositoryConfig.isSplit() ).thenReturn( true );
session.setConfigProperty( "aether.enhancedLocalRepository.splitLocal", Boolean.TRUE.toString() );
session.setConfigProperty( "aether.enhancedLocalRepository.splitRemoteRepository", Boolean.TRUE.toString() );

LocalPathPrefixComposerFactory factory = new DefaultLocalPathPrefixComposerFactory();
LocalPathPrefixComposer composer = factory.createComposer( session );
LocalPathPrefixComposer composer = factory.createComposer( session, repositoryConfig );
assertNotNull( composer );

String prefix;
Expand Down Expand Up @@ -168,13 +172,13 @@ public void saneConfig()
public void fullConfig()
{
DefaultRepositorySystemSession session = TestUtils.newSession();
session.setConfigProperty( "aether.enhancedLocalRepository.split", Boolean.TRUE.toString() );
when( repositoryConfig.isSplit() ).thenReturn( true );
session.setConfigProperty( "aether.enhancedLocalRepository.splitLocal", Boolean.TRUE.toString() );
session.setConfigProperty( "aether.enhancedLocalRepository.splitRemote", Boolean.TRUE.toString() );
session.setConfigProperty( "aether.enhancedLocalRepository.splitRemoteRepository", Boolean.TRUE.toString() );

LocalPathPrefixComposerFactory factory = new DefaultLocalPathPrefixComposerFactory();
LocalPathPrefixComposer composer = factory.createComposer( session );
LocalPathPrefixComposer composer = factory.createComposer( session, repositoryConfig );
assertNotNull( composer );

String prefix;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -71,6 +72,8 @@ public class EnhancedLocalRepositoryManagerTest

private Metadata noVerMetadata;

private final EnhancedLocalRepositoryConfig repositoryConfig = mock( EnhancedLocalRepositoryConfig.class );

@Before
public void setup()
throws Exception
Expand Down Expand Up @@ -110,7 +113,7 @@ protected EnhancedLocalRepositoryManager getManager()
new DefaultLocalPathComposer(),
"_remote.repositories",
trackingFileManager,
new DefaultLocalPathPrefixComposerFactory().createComposer( session )
new DefaultLocalPathPrefixComposerFactory().createComposer( session, repositoryConfig )
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,25 @@
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class EnhancedSplitLocalRepositoryManagerTest extends EnhancedLocalRepositoryManagerTest
{

private final EnhancedLocalRepositoryConfig repositoryConfig = mock( EnhancedLocalRepositoryConfig.class );

@Override
protected EnhancedLocalRepositoryManager getManager()
{
session.setConfigProperty( "aether.enhancedLocalRepository.split", Boolean.TRUE.toString() );
when( repositoryConfig.isSplit() ).thenReturn( true );

return new EnhancedLocalRepositoryManager(
basedir,
new DefaultLocalPathComposer(),
"_remote.repositories",
trackingFileManager,
new DefaultLocalPathPrefixComposerFactory().createComposer( session )
new DefaultLocalPathPrefixComposerFactory().createComposer( session, repositoryConfig )
);
}

Expand Down