/* * 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. * * Contributions from 2013-2017 where performed either by US government * employees, or under US Veterans Health Administration contracts. * * US Veterans Health Administration contributions by government employees * are work of the U.S. Government and are not subject to copyright * protection in the United States. Portions contributed by government * employees are USGovWork (17USC ยง105). Not subject to copyright. * * Contribution by contractors to the US Veterans Health Administration * during this period are contractually contributed under the * Apache License, Version 2.0. * * See: https://www.usa.gov/government-works * * Contributions prior to 2013: * * Copyright (C) International Health Terminology Standards Development Organisation. * Licensed under the Apache License, Version 2.0. * */ package sh.isaac.pombuilder.upload; //~--- JDK imports ------------------------------------------------------------ import java.io.File; import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; //~--- non-JDK imports -------------------------------------------------------- import javafx.beans.value.ChangeListener; import javafx.concurrent.Task; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import sh.isaac.api.util.MavenPublish; import sh.isaac.api.util.WorkExecutors; import sh.isaac.api.util.Zip; import sh.isaac.pombuilder.FileUtil; import sh.isaac.pombuilder.GitPublish; import sh.isaac.pombuilder.converter.SupportedConverterTypes; //~--- classes ---------------------------------------------------------------- /** * {@link SrcUploadCreator} * Create a new maven pom project which when executed, will upload a set of SDO input files. * * @author <a href="mailto:daniel.armbrust.list@gmail.com">Dan Armbrust</a> */ public class SrcUploadCreator { /** The Constant LOG. */ private static final Logger LOG = LogManager.getLogger(); //~--- methods ------------------------------------------------------------- /** * Creates the src upload configuration. * * @param uploadType - What type of content is being uploaded. * @param version - What version number does the passed in content represent * @param extensionName - optional - If the upload type is a type such as {@link SupportedConverterTypes#SCT_EXTENSION} which contains a * wildcard '*' in its {@link SupportedConverterTypes#getArtifactId()} value, this parameter must be provided, and is the string to use to * replace the wildcard. This would typically be a value such as "en" or "fr", when used for snomed extension content. * @param filesToUpload the files to upload * @param gitRepositoryURL - The URL to publish this built project to * @param gitUsername - The username to utilize to publish this project * @param gitPassword the git password * @param artifactRepositoryURL - The artifact server path where the created artifact should be transferred. This path should go all the way down to * a specific repository, such as http://artifactory.isaac.sh/artifactory/libs-release-local or http://artifactory.isaac.sh/artifactory/termdata-release-local * This should not point to a URL that represents a 'group' repository view. * @param repositoryUsername - The username to utilize to upload the artifact to the artifact server * @param repositoryPassword - The passwordto utilize to upload the artifact to the artifact server * @return the tag created in the repository that carries the created project * - the task handle - which will return the tag that was created in the git repository upon completion. Note that the task is NOT yet started, when * it is returned. * @throws Throwable the throwable */ public static Task<String> createSrcUploadConfiguration(SupportedConverterTypes uploadType, String version, String extensionName, List<File> filesToUpload, String gitRepositoryURL, String gitUsername, char[] gitPassword, String artifactRepositoryURL, String repositoryUsername, String repositoryPassword) throws Throwable { LOG.info( "Building the task to create a source upload configuration for {}, version: {}, extensionName: {}, to git: {} and artifact server: {}", uploadType, version, extensionName, gitRepositoryURL, artifactRepositoryURL); if (LOG.isDebugEnabled() && (filesToUpload != null)) { LOG.debug("Provided files []", Arrays.toString(filesToUpload.toArray(new File[filesToUpload.size()]))); } if ((filesToUpload == null) || (filesToUpload.size() == 0)) { LOG.info("Throwing an exception because No content was found to upload"); throw new Exception("No content was found to upload!"); } final Task<String> uploader = new Task<String>() { @Override protected String call() throws Exception { updateMessage("Preparing"); File baseFolder = null; try { baseFolder = Files.createTempDirectory("src-upload") .toFile(); // Otherwise, move forward. Create our native-source folder, and move everything into it. final File nativeSource = new File(baseFolder, "native-source"); if (nativeSource.exists()) { LOG.info("Task failing due to unexpected file in upload content '{}'", nativeSource); throw new RuntimeException("Unexpected file found in upload content!"); } nativeSource.mkdir(); for (final File f: filesToUpload) { // validate it is a file, move it into native-source if (f.isFile()) { Files.move(f.toPath(), nativeSource.toPath() .resolve(f.toPath() .getFileName())); } else { LOG.info("Task failing due to unexpected directory in upload content: '{}'", f.getAbsolutePath()); throw new Exception("Unexpected directory found in upload content! " + f.getAbsolutePath()); } } final StringBuffer noticeAppend = new StringBuffer(); final HashMap<String, String> pomSwaps = new HashMap<>(); pomSwaps.put("#VERSION#", version); pomSwaps.put("#SCM_URL#", GitPublish.constructChangesetRepositoryURL(gitRepositoryURL)); if (uploadType.getArtifactId().contains("*") && StringUtils.isBlank(extensionName)) { throw new Exception("ExtensionName is required when the upload type artifact id contains a wildcard"); } pomSwaps.put("#GROUPID#", uploadType.getSourceUploadGroupId()); String temp = uploadType.getArtifactId(); if (temp.contains("*")) { temp = temp.replace("*", extensionName); } pomSwaps.put("#ARTIFACTID#", temp); pomSwaps.put("#NAME#", uploadType.getNiceName() + " Source Upload"); pomSwaps.put("#LICENSE#", uploadType.getLicenseInformation()[0]); // we only use the first license for source upload noticeAppend.append(uploadType.getNoticeInformation()[0]); // only use the first notice info final String tagWithoutRevNumber = pomSwaps.get("#GROUPID#") + "/" + pomSwaps.get("#ARTIFACTID#") + "/" + pomSwaps.get("#VERSION#"); LOG.debug("Desired tag (withoutRevNumber): {}", tagWithoutRevNumber); final ArrayList<String> existingTags = GitPublish.readTags(gitRepositoryURL, gitUsername, gitPassword); if (LOG.isDebugEnabled()) { LOG.debug("Currently Existing tags in '{}': {} ", gitRepositoryURL, Arrays.toString(existingTags.toArray(new String[existingTags.size()]))); } final int highestBuildRevision = GitPublish.readHighestRevisionNumber(existingTags, tagWithoutRevNumber); String tag; // Fix version number if (highestBuildRevision == -1) { // No tag at all - create without rev number, don't need to change our pomSwaps tag = tagWithoutRevNumber; } else { // If we are a SNAPSHOT, don't embed a build number, because nexus won't allow the upload, otherwise, embed a rev number if (!pomSwaps.get("#VERSION#") .endsWith("SNAPSHOT")) { pomSwaps.put("#VERSION#", pomSwaps.get("#VERSION#") + "-" + (highestBuildRevision + 1)); } tag = tagWithoutRevNumber + "-" + (highestBuildRevision + 1); } LOG.info("Final calculated tag: '{}'", tag); pomSwaps.put("#SCM_TAG#", tag); FileUtil.writeFile("shared", "LICENSE.txt", baseFolder); FileUtil.writeFile("shared", "NOTICE.txt", baseFolder, null, noticeAppend.toString()); FileUtil.writeFile("srcUploadProjectTemplate", "native-source/DOTgitignore", baseFolder); FileUtil.writeFile("srcUploadProjectTemplate", "assembly.xml", baseFolder); FileUtil.writeFile("srcUploadProjectTemplate", "pom.xml", baseFolder, pomSwaps, ""); updateTitle("Publishing configuration to Git"); GitPublish.publish(baseFolder, gitRepositoryURL, gitUsername, gitPassword, tag); updateTitle("Zipping content"); LOG.debug("Zipping content"); final Zip z = new Zip(pomSwaps.get("#ARTIFACTID#"), pomSwaps.get("#VERSION#"), null, null, new File(baseFolder, "target"), nativeSource, false); final ArrayList<File> toZip = new ArrayList<>(); for (final File f: nativeSource.listFiles()) { if (f.getName() .equals(".gitignore")) { // noop } else { toZip.add(f); } } z.getStatus() .addListener((ChangeListener<String>) (observable, oldValue, newValue) -> updateMessage(newValue)); z.getTotalWork() .add(z.getWorkComplete()) .addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> updateProgress(z.getWorkComplete() .get(), z.getTotalWork() .get())); // This blocks till complete final File zipFile = z.addFiles(toZip); LOG.info("Zip complete, publishing to artifact repo {}", artifactRepositoryURL); updateTitle("Publishing files to the Artifact Repository"); final MavenPublish pm = new MavenPublish(pomSwaps.get("#GROUPID#"), pomSwaps.get("#ARTIFACTID#"), pomSwaps.get("#VERSION#"), new File(baseFolder, "pom.xml"), new File[] { zipFile }, artifactRepositoryURL, repositoryUsername, repositoryPassword); pm.progressProperty() .addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> updateProgress(pm.getWorkDone(), pm.getTotalWork())); pm.messageProperty() .addListener((ChangeListener<String>) (observable, oldValue, newValue) -> updateMessage(newValue)); WorkExecutors.get() .getExecutor() .execute(pm); // block till upload complete pm.get(); updateTitle("Cleaning Up"); try { FileUtil.recursiveDelete(baseFolder); } catch (final Exception e) { LOG.error("Problem cleaning up temp folder " + baseFolder, e); } updateTitle("Complete"); return tag; } catch (final Throwable e) { LOG.error("Unexpected error", e); throw new RuntimeException(e); } finally { try { FileUtil.recursiveDelete(baseFolder); } catch (final Exception e) { LOG.error("Problem cleaning up temp folder " + baseFolder, e); } } } }; return uploader; } }