我们有一个内部工件存储库。目前所有快照都将部署在那里。我们还希望有一个具有 Web 界面的不同服务器,并希望将创建的工件复制到它。
对于我们的构建,我们使用 Hudson,但构建后操作“将工件部署到 Maven 存储库”与 scp 一起不起作用。所以有一个问题是用其他优雅的方式来做这件事。为什么 Maven 不能拥有多个分发存储库?有任何想法吗?
最好的事情是,如果 artifactory 在每次新部署后支持(自动!)增量导出到标准 maven 存储库。
我们有一个内部工件存储库。目前所有快照都将部署在那里。我们还希望有一个具有 Web 界面的不同服务器,并希望将创建的工件复制到它。
对于我们的构建,我们使用 Hudson,但构建后操作“将工件部署到 Maven 存储库”与 scp 一起不起作用。所以有一个问题是用其他优雅的方式来做这件事。为什么 Maven 不能拥有多个分发存储库?有任何想法吗?
最好的事情是,如果 artifactory 在每次新部署后支持(自动!)增量导出到标准 maven 存储库。
我不认为 maven 支持为单个配置文件部署到多个存储库,但也许配置文件可以更改存储库的 id 和 url。
<distributionManagement>
<repository>
<id>${repo-id}</id>
<name>${repo-name}</name>
<url>${repo-url}</url>
</repository>
</distributionManagement>
然后使用配置文件选择要部署到的存储库:
<profiles>
<profile>
<id>repo1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<repo-id>repo1</repo-id>
<repo-name>Repo1 Name </repo-name>
<repo-url>http://url.com/maven2</repo-url>
</properties>
</profile>
<profile>
<id>repo2</id>
<properties>
<repo-id>repo2</repo-id>
<repo-name>Repo2 Name </repo-name>
<repo-url>http://url2.com/maven2</repo-url>
</properties>
</profile>
</profiles>
如果您愿意使用自定义插件,您可以将 Maven 配置为与标准部署同时部署到“镜像”位置列表。我建议在配置文件中定义它,这样您就可以控制镜像哪些部署(在每个构建中都这样做可能不合适)。
要定义一个新插件,您需要创建一个新的 Maven 项目并指定 POM 具有包装maven-plugin:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>name.seller.rich</groupId>
<artifactId>maven-mirror-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
</project>
在 src/main/java 中定义一个 Mojo。下面的代码声明了一个“镜像”目标,它需要一个 mirrorRepository 项目列表(包含一个 repositoryId 和 url)来镜像工件部署。该插件使用与 maven-deploy-plugin 相同的部署方法,并采用大多数相同的参数。
请注意,您仍然需要在 settings.xml 中为每个具有适当权限的存储库定义一个服务器来进行部署,否则构建将失败!
package name.seller.rich;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.deployer.ArtifactDeployer;
import org.apache.maven.artifact.deployer.ArtifactDeploymentException;
import org.apache.maven.artifact.metadata.ArtifactMetadata;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.ProjectArtifactMetadata;
/**
* @goal mirror
* @phase deploy
*/
public class MirrorMojo extends AbstractMojo {
/**
* @parameter expression=
* "${component.org.apache.maven.artifact.deployer.ArtifactDeployer}"
* @required
* @readonly
*/
private ArtifactDeployer deployer;
/**
* Map that contains the layouts
*
* @component role=
* "org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout"
*/
private Map repositoryLayouts;
/**
* Component used to create a repository
*
* @component
*/
private ArtifactRepositoryFactory repositoryFactory;
/**
* The type of remote repository layout to deploy to. Try <i>legacy</i> for
* a Maven 1.x-style repository layout.
*
* @parameter expression="${repositoryLayout}" default-value="default"
* @required
*/
private String repositoryLayout;
/**
* Parameter used to update the metadata to make the artifact as release.
*
* @parameter expression="${updateReleaseInfo}" default-value="false"
*/
private boolean updateReleaseInfo;
/**
* Whether to deploy snapshots with a unique version or not.
*
* @parameter expression="${uniqueVersion}" default-value="true"
*/
private boolean uniqueVersion;
/**
* @parameter expression="${mirrorRepositories}"
* @required
*/
private MirrorRepository[] mirrorRepositories;
/**
* @parameter expression="${localRepository}"
* @required
* @readonly
*/
private ArtifactRepository localRepository;
/**
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
/**
* Deploy all artifacts for the project to each mirror repository.
*/
public void execute() throws MojoExecutionException, MojoFailureException {
ArtifactRepositoryLayout layout;
layout = (ArtifactRepositoryLayout) repositoryLayouts
.get(repositoryLayout);
for (int i = 0; i < mirrorRepositories.length; i++) {
MirrorRepository mirrorRepository = mirrorRepositories[i];
ArtifactRepository deploymentRepository = repositoryFactory
.createDeploymentArtifactRepository(mirrorRepository
.getRepositoryId(), mirrorRepository.getUrl(),
layout, uniqueVersion);
String protocol = deploymentRepository.getProtocol();
if ("".equals(protocol) || protocol == null) {
throw new MojoExecutionException("No transfer protocol found.");
}
deployToRepository(deploymentRepository);
}
}
/**
* Deploy all artifacts to the passed repository.
*/
private void deployToRepository(ArtifactRepository repo)
throws MojoExecutionException {
String protocol = repo.getProtocol();
if (protocol.equalsIgnoreCase("scp")) {
File sshFile = new File(System.getProperty("user.home"), ".ssh");
if (!sshFile.exists()) {
sshFile.mkdirs();
}
}
File pomFile = project.getFile();
Artifact artifact = project.getArtifact();
// Deploy the POM
boolean isPomArtifact = "pom".equals(project.getPackaging());
if (!isPomArtifact) {
ArtifactMetadata metadata = new ProjectArtifactMetadata(artifact,
pomFile);
artifact.addMetadata(metadata);
}
if (updateReleaseInfo) {
artifact.setRelease(true);
}
try {
List attachedArtifacts = project.getAttachedArtifacts();
if (isPomArtifact) {
deployer.deploy(pomFile, artifact, repo, localRepository);
} else {
File file = artifact.getFile();
if (file != null && !file.isDirectory()) {
deployer.deploy(file, artifact, repo, localRepository);
} else if (!attachedArtifacts.isEmpty()) {
getLog()
.info(
"No primary artifact to deploy, deploy attached artifacts instead.");
} else {
String message = "The packaging for this project did not assign a file to the build artifact";
throw new MojoExecutionException(message);
}
}
for (Iterator i = attachedArtifacts.iterator(); i.hasNext();) {
Artifact attached = (Artifact) i.next();
deployer.deploy(attached.getFile(), attached, repo,
localRepository);
}
} catch (ArtifactDeploymentException e) {
throw new MojoExecutionException(e.getMessage(), e);
}
}
}
mojo 引用了一个 MirrorRepository 类型来封装 repositoryId 和 url,它是一个简单的 bean:
package name.seller.rich;
public class MirrorRepository {
private String repositoryId;
private String url;
public String getRepositoryId() {
return repositoryId;
}
public void setRepositoryId(String repositoryId) {
this.repositoryId = repositoryId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
这是使用插件的示例配置。请注意,所有部署格式都受支持(http、scp、ftp):
<plugin>
<groupId>name.seller.rich</groupId>
<artifactId>maven-mirror-plugin</artifactId>
<executions>
<execution>
<id>mirror</id>
<phase>deploy</phase>
<goals>
<goal>mirror</goal>
</goals>
</execution>
</executions>
<configuration>
<mirrorRepositories>
<mirrorRepository>
<repositoryId>mirror</repositoryId>
<url>http://path/to/mirror</url>
</mirrorRepository>
</mirrorRepositories>
<!--any other deploy configuration needed-->
</configuration>
</plugin>
我认为在 Artifactory 中,默认情况下,它维护不同的逻辑存储库,用于上传快照和非快照。使用权限,您可以使快照存储库仅对某些人可见。
如果这还不够,另一个适用于 Artifactory 2.0 的解决方案是让 Artifactory 使用一个 MySQL 数据库,该数据库对另一个 MySQL 数据库进行异步复制,而另一个 MySQL 数据库又由 Artifactory 的单独安装读取。如果这太实时了,您可以简单地拥有两个不同的安装,根据业务规则进行更新。
Artifactory确实具有自动导出功能。从文档中:
您可以自动定期备份整个 Artifactory 系统。备份过程在目标备份目录中创建一个带时间戳的目录(或 zip 文件),基本上与使用元数据运行完整系统导出相同。[...] 每个备份都可以有自己的时间表并排除某些存储库 [...]
备份的内容(提取时)采用标准 Maven 格式,可以加载到任何外部 Maven 存储库 [...]
Artifactory 支持增量备份到目标备份目录中的同一目标目录(名为“当前”)。这种备份只是将增量写入输出目录,导致备份速度极快。
这不正是你需要的吗?要传输文件,您可以将共享目录挂载到远程服务器并在那里进行备份,或者在本地进行备份然后 rsync 它。