[java-identity-provider] 04/11: IDP-1499 New V4 Installer: Copy Distribution

Rod Widdowson rdw at steadingsoftware.com
Fri Oct 11 11:08:27 EDT 2019


This is an automated email from the git hooks/post-receive script.

rdw pushed a commit to branch master
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=48188349acffdf1561aff36a5b6de9c8a1c997ae

commit 48188349acffdf1561aff36a5b6de9c8a1c997ae
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Mon Oct 7 13:50:34 2019 +0100

    IDP-1499 New V4 Installer: Copy Distribution
    
    https://issues.shibboleth.net/jira/browse/IDP-1499
---
 .../idp/installer/impl/CopyDistributions.java      | 173 +++++++++++++++++++++
 .../idp/installer/impl/InstallerSupport.java       |  80 +++++++++-
 idp-installer/src/main/resources/logback.xml       |  17 ++
 3 files changed, 267 insertions(+), 3 deletions(-)

diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/CopyDistributions.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/CopyDistributions.java
new file mode 100644
index 0000000..43079f5
--- /dev/null
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/CopyDistributions.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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.
+ */
+
+package net.shibboleth.idp.installer.impl;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Instant;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Copy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** 
+ * Copy the distribution to its final location.
+ */
+public final class CopyDistributions {
+
+    /** Log. */
+    public static final Logger LOG = LoggerFactory.getLogger(CopyDistributions.class);
+
+    /** Private Constructor. */
+    private CopyDistributions() { }
+
+    /** Copy the distribution from the dstribution to its new location.
+     * @param ip what drives the install.
+     * @throws BuildException if badness occurs
+     */
+    public static void copyDistribution(final InstallerProperties ip) throws BuildException {
+        backupOld(ip);
+        deleteOld(ip);
+        copyDist(ip);
+        copyBinDocSystem(ip);
+        createUserFolders(ip);
+    }
+
+    /** Helper for the {@link #backupOld(InstallerProperties)} method.
+     * @param from where from
+     * @param to where to.
+     * @throws BuildException if badness occurs
+     */
+    private static void backup(final Path from, final Path to) throws BuildException {
+        LOG.debug("Backing up From {} to {}", from, to);
+        final Copy copy = InstallerSupport.getCopyTask(from, to);
+        copy.setFailOnError(false);
+        copy.execute();
+    }
+
+    /** Copy bin, edit-webapp, dist and doc to old-date-time. 
+     * @param ip The configuration for this install
+     * @throws BuildException if badness occurs
+     */
+    protected static void backupOld(final InstallerProperties ip) throws BuildException {
+        final Path backup = ip.getTargetDir().resolve("Old-" + Instant.now().toString());
+        InstallerSupport.createDirectory(backup);
+        backup(ip.getTargetDir().resolve("edit-webapp"), backup.resolve("edit-webapp"));
+        backup(ip.getTargetDir().resolve("doc"), backup.resolve("doc"));
+        backup(ip.getTargetDir().resolve("system"), backup.resolve("system"));
+    }
+
+    /** Helper for the delete {@link #deleteOld(InstallerProperties)} method.
+     * @param what what to delete
+     */
+    private static void delete(final Path what) {
+        if (!Files.exists(what)) {
+            LOG.debug("{} doesn't exist, ignoring", what);
+        } else if (Files.isDirectory(what)) {
+            throw new BuildException("Corrupt install " + what + " is not a directory");
+        } else {
+            LOG.debug("Deleteing {} ", what);
+            try {
+                DeletingVisitor.deleteTree(what);
+            } catch (final IOException e) {
+                LOG.warn("Deleting {} failed", what, e);
+            }
+        }
+    }
+        
+    /** Delete old copies of bin/lib (leaving bin for scripts), disty, doc and system.
+     * system has to be unprotected first which also means we need to create it too.
+     * @param ip The configuration for this install
+     * @throws BuildException if badness occurs
+     */
+    protected static void deleteOld(final InstallerProperties ip) {
+        delete(ip.getTargetDir().resolve("bin").resolve("lib"));
+        delete(ip.getTargetDir().resolve("dist"));
+        delete(ip.getTargetDir().resolve("doc"));
+        final Path system = ip.getTargetDir().resolve("system");
+        if (Files.exists(system)) {
+            LOG.debug("Clearing  {} readonly (id Windows)", system);
+            InstallerSupport.setReadOnly(system, false);
+        }
+        delete(system);
+    }
+    
+
+    /** Helper for the delete {@link #copyDist(InstallerProperties)} and
+     *  {@link #copyBinDocSystem(InstallerProperties)} methods.
+     * @param srcDist the source distribution.
+     * @param dist the dist directory
+     * @param to the subfolder name
+     * @throws BuildException if badness occurs
+     */
+    private static void distCopy(final Path srcDist, final Path dist, final String to) throws BuildException {
+        final Path toPath =  dist.resolve(to);
+        final Path fromPath = srcDist.resolve(to);
+        LOG.debug("Copying distribution from {} to {}", fromPath, toPath);
+        final Copy copy = InstallerSupport.getCopyTask(fromPath, toPath);
+        copy.execute();
+    }
+
+    /** Populate the dist folder.
+     * @param ip The configuration for this install
+     * @throws BuildException if badness occurs
+     */
+    protected static void copyDist(final InstallerProperties ip) {
+        final Path dist = ip.getTargetDir().resolve("dist");
+        InstallerSupport.createDirectory(dist);
+        final Path src = ip.getSourceDir().resolve("dist");
+        if (!Files.exists(src)) {
+            LOG.error("Source distribution {} not found", src);
+            throw new BuildException("Source distribution not found");
+        }
+        distCopy(src, dist, "conf");
+        distCopy(src, dist, "flows");
+        distCopy(src, dist, "messages");
+        distCopy(src, dist, "views");
+        distCopy(src, dist, "webapp");
+    }
+
+    /** Populate the per distribution (but non dist) folders.
+     * @param ip The configuration for this install
+     * @throws BuildException if badness occurs
+     */
+    protected static void copyBinDocSystem(final InstallerProperties ip) {
+        distCopy(ip.getSourceDir(), ip.getTargetDir(), "bin");
+        distCopy(ip.getSourceDir(), ip.getTargetDir(), "doc");
+        distCopy(ip.getSourceDir(), ip.getTargetDir(), "system");
+    }
+    
+    /** Create (if they do not exist) the user editable folders, suitable for
+     * later population during update or install.
+     * @param ip The configuration for this install
+     * @throws BuildException if badness occurs
+     */
+    protected static void createUserFolders(final InstallerProperties ip) {
+        final Path target = ip.getTargetDir();
+        InstallerSupport.createDirectory(target.resolve("conf"));
+        InstallerSupport.createDirectory(target.resolve("credentials"));
+        InstallerSupport.createDirectory(target.resolve("flows"));
+        InstallerSupport.createDirectory(target.resolve("logs"));
+        InstallerSupport.createDirectory(target.resolve("messages"));
+        InstallerSupport.createDirectory(target.resolve("metadata"));
+        InstallerSupport.createDirectory(target.resolve("views"));
+        InstallerSupport.createDirectory(target.resolve("war"));
+    }
+}
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/InstallerSupport.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/InstallerSupport.java
index 6edfd8e..e8bb479 100644
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/InstallerSupport.java
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/InstallerSupport.java
@@ -17,31 +17,57 @@
 
 package net.shibboleth.idp.installer.impl;
 
+import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 
+import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Project;
 import org.apache.tools.ant.taskdefs.Copy;
+import org.apache.tools.ant.taskdefs.optional.windows.Attrib;
 import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.selectors.PresentSelector;
+import org.apache.tools.ant.types.selectors.PresentSelector.FilePresence;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /** General common names and helper functions for the installer. */
 public final class InstallerSupport {
 
+    /** Log. */
+    public static final Logger LOG = LoggerFactory.getLogger(InstallerSupport.class);
+
     /** The name of the file and the property with the current V4 installation value.*/
     public static final String VERSION_NAME = "idp.installed.version";
-    
+
     /** A psuedo ant-project as parent. */
     public static final Project ANT_PROJECT = new Project();
 
     /** Private Constructor. */
     private InstallerSupport() {}
-    
+
+    /** Method to create a directory and log same.
+     * @param dir what to create
+     * @throws BuildException if bad ness occurs
+     */
+    protected static void createDirectory(final Path dir) throws BuildException{
+        if (!Files.exists(dir)) {
+            try {
+                Files.createDirectory(dir);
+                LOG.debug("Created directory {}", dir);
+            } catch (final IOException e) {
+                LOG.error("Could no create {}", dir, e);
+               throw new BuildException(e);
+            }
+        }
+    }
+
     /** Copy files.  We use ant rather than {@link Files#copy(Path, Path, java.nio.file.CopyOption...)}
      * because the latter has issues with the Windows ReadOnly Attribute, and the former is tried
      * and tested technology.
      * @param from where to copy from
      * @param to where to copy to
-     * @return a partially populated {@link Copy} task 
+     * @return a partially populated {@link Copy} task
      */
     protected static Copy getCopyTask(final Path from, final Path to) {
         final Copy result = new Copy();
@@ -53,4 +79,52 @@ public final class InstallerSupport {
         return result;
     }
 
+    /** Populate a with all the missing files.
+     * @param from where to go from
+     * @param to where to go to
+     * @throws BuildException
+     * Based on (for instance the following ant<code>
+        <!-- flows: copy from dist if not already present -->
+        <mkdir dir="${idp.target.dir}/flows" />
+        <copy todir="${idp.target.dir}/flows">
+            <fileset dir="${idp.target.dir}/dist/flows" includes="**\/*">
+                <present present="srconly" targetdir="${idp.target.dir}/flows" />
+            </fileset >
+        </copy>
+        </code>
+     *
+     */
+    protected static void copyDirIfNotPresent(final Path from, final Path to) throws BuildException {
+        createDirectory(to);
+        final Copy copy = new Copy();
+        copy.setTodir(to.toFile());
+        final FileSet fromSet = new FileSet();
+        fromSet.setDir(from.toFile());
+        fromSet.setIncludes("**/**");
+        final PresentSelector present = new PresentSelector();
+        present.setPresent((FilePresence) FilePresence.getInstance(FilePresence.class, "srconly"));
+        present.setTargetdir(from.toFile());
+        fromSet.addPresent(present);
+        copy.addFileset(fromSet);
+        copy.setProject(ANT_PROJECT);
+        copy.execute();
+        LOG.debug("Copied not-previously existing files from {} to {}", from, to);
+
+    }
+
+    /** On Windows sets the readOnly attribute recursively.
+     * @param directory where
+     * @param readOnly what to set it as
+     */
+    protected static void setReadOnly(final Path directory, final boolean readOnly) {
+        final Attrib attrib = new Attrib();
+        attrib.setReadonly(readOnly);
+        final FileSet where = new FileSet();
+        where.setDir(directory.toFile());
+        where.setIncludes("**/**");
+        attrib.addFileset(where);
+        attrib.setProject(ANT_PROJECT);
+        attrib.execute();
+    }
+
 }
diff --git a/idp-installer/src/main/resources/logback.xml b/idp-installer/src/main/resources/logback.xml
new file mode 100644
index 0000000..f52d4cc
--- /dev/null
+++ b/idp-installer/src/main/resources/logback.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Logging for the installer.  Pin to Debug for now -->
+<configuration>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%level [%logger:%line] - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <root>
+        <level value="DEBUG" />
+        <appender-ref ref="STDOUT" />
+    </root>
+    
+</configuration>

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list