Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright 2015-2019 Maven Source Dependencies
* Plugin contributors as indicated by the @author tags.
*
* Licensed 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.
*/
package org.srcdeps.mvn.localrepo;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Predicate;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.metadata.Metadata;
import org.eclipse.aether.repository.LocalArtifactRegistration;
import org.eclipse.aether.repository.LocalArtifactRequest;
import org.eclipse.aether.repository.LocalArtifactResult;
import org.eclipse.aether.repository.LocalMetadataRegistration;
import org.eclipse.aether.repository.LocalMetadataRequest;
import org.eclipse.aether.repository.LocalMetadataResult;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.LocalRepositoryManager;
import org.eclipse.aether.repository.RemoteRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.srcdeps.core.BuildException;
import org.srcdeps.core.BuildMetadataStore;
import org.srcdeps.core.BuildRequest;
import org.srcdeps.core.BuildService;
import org.srcdeps.core.ConfigurationQueryService;
import org.srcdeps.core.ConfigurationQueryService.ScmRepositoryResult;
import org.srcdeps.core.FetchId;
import org.srcdeps.core.FetchLog;
import org.srcdeps.core.Ga;
import org.srcdeps.core.Gav;
import org.srcdeps.core.GavSet;
import org.srcdeps.core.GavSetWalker;
import org.srcdeps.core.MavenSourceTree;
import org.srcdeps.core.MavenSourceTree.ActiveProfiles;
import org.srcdeps.core.MavenSourceTree.Module.Profile;
import org.srcdeps.core.ScmService;
import org.srcdeps.core.SrcVersion;
import org.srcdeps.core.config.BuilderIo;
import org.srcdeps.core.config.Configuration;
import org.srcdeps.core.config.ScmRepository;
import org.srcdeps.core.config.ScmRepositoryMaven;
import org.srcdeps.core.fs.BuildDirectoriesManager;
import org.srcdeps.core.fs.PathLock;
import org.srcdeps.core.fs.PathLocker;
import org.srcdeps.core.fs.PersistentBuildMetadataStore;
import org.srcdeps.core.shell.IoRedirects;
import org.srcdeps.core.util.SrcdepsCoreUtils;
import org.srcdeps.mvn.config.ConfigurationProducer;
/**
* A {@link LocalRepositoryManager} able to build the requested artifacts from their sources.
*
* @author Peter Palaga
*/
public class SrcdepsLocalRepositoryManager implements LocalRepositoryManager {
private static final Logger log = LoggerFactory.getLogger(SrcdepsLocalRepositoryManager.class);
private static List enhanceBuildArguments(List buildArguments, String localRepo) {
List result = new ArrayList<>();
for (String arg : buildArguments) {
if (arg.startsWith("-Dmaven.repo.local=")) {
/* We won't touch maven.repo.local set in the user's config */
log.debug("srcdeps: Forwarding [{}] to the nested build as set in srcdeps.yaml file", arg);
return buildArguments;
}
result.add(arg);
}
String arg = "-Dmaven.repo.local=" + localRepo;
log.debug("srcdeps: Forwarding [{}] from the outer Maven build to the nested build", arg);
result.add(arg);
return Collections.unmodifiableList(result);
}
void uninstallGavSet(ScmRepository currentRepo, GavSetWalker gavSetWalker) throws IOException {
final GavSetWalker.GavPathCollector paths = new GavSetWalker.GavPathCollector();
gavSetWalker.walk(paths);
final Map gavPaths = paths.getGavPaths();
log.debug("srcdeps: Uninstalling [{}] GAVs before rebuilding them", gavPaths.size());
final List repos = configuration.getRepositories();
for (Entry en : gavPaths.entrySet()) {
final Path gavDir = en.getKey();
final Gav gav = en.getValue();
for (ScmRepository repo : repos) {
if (currentRepo != repo) {
if (repo.getGavSet().contains(gav.getGroupId(), gav.getArtifactId(), gav.getVersion())) {
log.error(
"srcdeps: Cannot rebuild SCM repository [{}] because it includes artifact [{}] that is included by another SCM repository [{}]. Adjust includes/excludes of those repositories in srcdeps.yaml and retry",
currentRepo.getId(), gav.toString(), repo.getId());
}
}
}
log.debug("srcdeps: Uninstalling [{}]", gavDir);
SrcdepsCoreUtils.deleteDirectory(gavDir);
}
}
private final BuildDirectoriesManager buildDirectoriesManager;
private final BuildMetadataStore buildMetadataStore;
private final BuildService buildService;
private final Configuration configuration;
private final ConfigurationProducer configurationProducer;
private final ConfigurationQueryService configurationQueryService;
private final LocalRepositoryManager delegate;
private final FetchLog fetchLog;
private final ScmService scmService;
private final Path scrdepsDir;
public SrcdepsLocalRepositoryManager(LocalRepositoryManager delegate, BuildService buildService,
ScmService scmService, PathLocker pathLocker, ConfigurationProducer configurationProducer) {
super();
this.delegate = delegate;
this.buildService = buildService;
this.scmService = scmService;
this.scrdepsDir = delegate.getRepository().getBasedir().toPath().getParent().resolve("srcdeps");
this.buildMetadataStore = new PersistentBuildMetadataStore(scrdepsDir.resolve("build-metadata"));
this.buildDirectoriesManager = new BuildDirectoriesManager(scrdepsDir, pathLocker);
this.configurationProducer = configurationProducer;
this.fetchLog = new FetchLog();
this.configuration = configurationProducer.getConfiguration();
this.configurationQueryService = new ConfigurationQueryService(this.configuration);
}
/**
* Delegated to {@link #delegate}
*
* @see org.eclipse.aether.repository.LocalRepositoryManager#add(org.eclipse.aether.RepositorySystemSession,
* org.eclipse.aether.repository.LocalArtifactRegistration)
*/
@Override
public void add(RepositorySystemSession session, LocalArtifactRegistration request) {
delegate.add(session, request);
}
/**
* Delegated to {@link #delegate}
*
* @see org.eclipse.aether.repository.LocalRepositoryManager#add(org.eclipse.aether.RepositorySystemSession,
* org.eclipse.aether.repository.LocalMetadataRegistration)
*/
@Override
public void add(RepositorySystemSession session, LocalMetadataRegistration request) {
delegate.add(session, request);
}
private LocalArtifactResult buildDependency(Artifact artifact, ScmRepository scmRepo, LocalArtifactResult result,
SrcVersion srcVersion, RepositorySystemSession session, LocalArtifactRequest request) {
final FetchId fetchId = new FetchId(scmRepo.getId(), scmRepo.getUrls());
if (fetchLog.contains(fetchId)) {
log.debug(
"srcdeps: SCM repository [{}] has been marked as built and up-to-date in this JVM. The artifact [{}] must be there in the local maven repository",
fetchId, artifact);
return result;
}
String scmRepoId = null;
try (PathLock projectBuildDir = buildDirectoriesManager.openBuildDirectory(scmRepo.getIdAsPath(), srcVersion)) {
/* query the delegate again, because things may have changed since we requested the lock */
final LocalArtifactResult result2 = delegate.find(session, request);
final String version = artifact.getVersion();
if (fetchLog.contains(fetchId)) {
log.debug(
"srcdeps: SCM repository [{}] has been marked as built and up-to-date in this JVM. The artifact [{}] must be there in the local maven repository",
fetchId, artifact);
return result2;
} else {
/* The repo has not been fetched in the current JVM yet */
BuilderIo builderIo = scmRepo.getBuilderIo();
IoRedirects ioRedirects = IoRedirects.builder() //
.stdin(IoRedirects.parseUri(builderIo.getStdin())) //
.stdout(IoRedirects.parseUri(builderIo.getStdout())) //
.stderr(IoRedirects.parseUri(builderIo.getStderr())) //
.build();
List buildArgs = enhanceBuildArguments(scmRepo.getBuildArguments(),
delegate.getRepository().getBasedir().getAbsolutePath());
scmRepoId = scmRepo.getId();
final ScmRepositoryMaven maven = scmRepo.getMaven();
final Predicate isProfileActive = ActiveProfiles.ofArgs(buildArgs);
final Set buildIncludes = collectBuildIncludes(
configurationProducer.getMultimoduleProjectRootDirectory(), scmRepo.getEncoding(), scmRepo.getGavSet(),
maven.isIncludeRequired(), maven.getIncludes(), isProfileActive);
BuildRequest buildRequest = BuildRequest.builder() //
.scmRepositoryId(scmRepo.getId()) //
.encoding(scmRepo.getEncoding()) //
.dependentProjectRootDirectory(configurationProducer.getMultimoduleProjectRootDirectory()) //
.projectRootDirectory(projectBuildDir.getPath()) //
.scmUrls(scmRepo.getUrls()) //
.srcVersion(srcVersion) //
.version(version) //
.buildArguments(buildArgs) //
.timeoutMs(scmRepo.getBuildTimeout().toMilliseconds()) //
.skipTests(scmRepo.isSkipTests()) //
.forwardPropertyNames(configuration.getForwardProperties()) //
.forwardPropertyValues(configuration.getForwardPropertyValues()) //
.addDefaultBuildArguments(scmRepo.isAddDefaultBuildArguments()) //
.verbosity(scmRepo.getVerbosity()) //
.ioRedirects(ioRedirects) //
.versionsMavenPluginVersion(maven.getVersionsMavenPluginVersion()) //
.buildIncludes(buildIncludes)
.excludeNonRequired(maven.isExcludeNonRequired())
.gradleModelTransformer(scmRepo.getGradle().getModelTransformer()) //
.build();
final String buildRequestHash = buildRequest.getHash();
final String sourceTreeCommitId = scmService.checkout(buildRequest);
log.info("srcdeps: Mapped artifact [{}] to revision [{}] via [{}]", artifact, sourceTreeCommitId,
srcVersion);
fetchLog.add(fetchId);
final String pastCommitId = buildMetadataStore.retrieveCommitId(buildRequestHash);
final Path localMavenRepoPath = delegate.getRepository().getBasedir().toPath();
final GavSet gavSet = scmRepo.getGavSet();
final GavSetWalker gavSetWalker = new GavSetWalker(localMavenRepoPath, gavSet, version);
if (result2.isAvailable() && sourceTreeCommitId.equals(pastCommitId)) {
BuildMetadataStore.CheckSha1Consumer checkSha1Consumer = buildMetadataStore
.createCheckSha1Checker(buildRequestHash);
gavSetWalker.walk(checkSha1Consumer);
if (!checkSha1Consumer.isAnyArtifactChanged()) {
/*
* The artifact installed in the local Maven repo is the same as we built in the past hence
* there is no need to rebuild it
*/
log.info(
"srcdeps: The artifact in the local Maven repo has not changed since we built it in the past: [{}]",
artifact);
return result2;
}
}
/* We need to rebuild from sources for whatever reason */
log.debug("srcdeps: A rebuild of [{}] was triggered by [{}] lookup", fetchId, artifact);
/* Uninstall all matching artifacts */
uninstallGavSet(scmRepo, gavSetWalker);
/* Reduce the build tree if the user wants */
final Path pomXml = projectBuildDir.getPath().resolve("pom.xml");
if (Files.exists(pomXml)) {
final MavenSourceTree depTree = MavenSourceTree.of(pomXml , StandardCharsets.UTF_8);
if (!buildIncludes.isEmpty() && buildRequest.isExcludeNonRequired()) {
Set includesClosure = depTree.computeModuleClosure(buildIncludes, isProfileActive);
depTree.unlinkUneededModules(includesClosure, isProfileActive);
}
}
buildService.build(buildRequest);
buildMetadataStore.storeCommitId(buildRequestHash, sourceTreeCommitId);
BuildMetadataStore.StoreSha1Consumer gavtcPathConsumer = buildMetadataStore
.createStoreSha1Consumer(buildRequestHash);
gavSetWalker.walk(gavtcPathConsumer);
log.debug("srcdeps: Installed [{}] artifacts to [{}]", gavtcPathConsumer.getCount(), localMavenRepoPath);
/* check once again if the delegate sees the newly built artifact */
final LocalArtifactResult newResult = delegate.find(session, request);
if (!newResult.isAvailable()) {
throw new RuntimeException(String.format(
"srcdeps: Build succeeded but the artifact [%s] is still not available in the local repository",
artifact));
}
return newResult;
}
} catch (BuildException | IOException e) {
log.error("srcdeps: Could not build [" + scmRepoId + "] using request [" + request + "]", e);
}
return result;
}
private Set collectBuildIncludes(Path dependentProjectRoot, Charset encoding, GavSet gavSet, boolean includeRequired, List includes, Predicate isProfileActive) {
final Set result = new TreeSet<>();
includes.stream().map(Ga::of).forEach(result::add);
final Path pomXml = dependentProjectRoot.resolve("pom.xml");
if (includeRequired && Files.exists(pomXml)) {
final MavenSourceTree mst = MavenSourceTree.of(pomXml, encoding);
result.addAll(mst.filterDependencies(gavSet, isProfileActive));
}
return result;
}
/**
* In case the {@link #delegate} does not find the given artifact and the given artifact's version string is a
* srcdeps version string, then the version is built from source and returned.
*
* @see org.eclipse.aether.repository.LocalRepositoryManager#find(org.eclipse.aether.RepositorySystemSession,
* org.eclipse.aether.repository.LocalArtifactRequest)
*/
@Override
public LocalArtifactResult find(RepositorySystemSession session, LocalArtifactRequest request) {
Artifact artifact = request.getArtifact();
log.trace("srcdeps: Looking up locally [{}]", artifact);
final LocalArtifactResult result = delegate.find(session, request);
final String version = artifact.getVersion();
if (SrcVersion.isSrcVersion(version)) {
/* A source dependency defined in pom.xml */
final SrcVersion srcVersion = SrcVersion.parse(version);
if (srcVersion.isImmutable() && result.isAvailable()) {
/* Only tags and revisions do not need to get rebuilt once there in the local repo */
log.debug("srcdeps: Found [{}] in the local maven repository; no need to rebuild",
request.getArtifact());
return result;
}
if (configuration.isSkip()) {
log.debug("srcdeps: srcdeps is configured to be skipped");
} else {
final ScmRepository scmRepo = configurationQueryService
.findScmRepo(artifact.getGroupId(), artifact.getArtifactId(), version).assertSuccess()
.getRepository();
/* Ensure that we fetch and build a branch just once per outer build */
return buildDependency(artifact, scmRepo, result, srcVersion, session, request);
}
} else {
final ScmRepositoryResult queryResult = configurationQueryService.findScmRepo(artifact.getGroupId(),
artifact.getArtifactId(), version);
if (queryResult.getRepository() != null && queryResult.matchesBuildVersionPattern()) {
/* A source dependency defined in srcdeps.yaml */
if (configuration.isSkip()) {
log.debug("srcdeps: srcdeps is configured to be skipped");
} else {
final ScmRepository scmRepo = queryResult.getRepository();
return buildDependency(artifact, scmRepo, result, scmRepo.getBuildRef(), session, request);
}
}
}
return result;
}
@Override
public LocalMetadataResult find(RepositorySystemSession session, LocalMetadataRequest request) {
return delegate.find(session, request);
}
@Override
public String getPathForLocalArtifact(Artifact artifact) {
return delegate.getPathForLocalArtifact(artifact);
}
@Override
public String getPathForLocalMetadata(Metadata metadata) {
return delegate.getPathForLocalMetadata(metadata);
}
@Override
public String getPathForRemoteArtifact(Artifact artifact, RemoteRepository repository, String context) {
return delegate.getPathForRemoteArtifact(artifact, repository, context);
}
@Override
public String getPathForRemoteMetadata(Metadata metadata, RemoteRepository repository, String context) {
return delegate.getPathForRemoteMetadata(metadata, repository, context);
}
@Override
public LocalRepository getRepository() {
return delegate.getRepository();
}
}