001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2015 ForgeRock AS.
015 */
016
017package org.forgerock.doc.maven.post;
018
019import org.apache.commons.io.FileUtils;
020import org.apache.commons.io.filefilter.FileFilterUtils;
021import org.apache.maven.plugin.MojoExecutionException;
022import org.forgerock.doc.maven.AbstractDocbkxMojo;
023
024import java.io.File;
025import java.io.IOException;
026
027/**
028 * Fix man page file locations.
029 */
030public class ManpagePost extends AbstractDocbkxMojo {
031
032    /**
033     * The Mojo that holds configuration and related methods.
034     */
035    private AbstractDocbkxMojo m;
036
037    /**
038     * Constructor setting the Mojo that holds the configuration.
039     *
040     * @param mojo The Mojo that holds the configuration.
041     */
042    public ManpagePost(final AbstractDocbkxMojo mojo) {
043        m = mojo;
044    }
045
046    /**
047     * Fix man page file locations.
048     * <br>
049     * Man page generation replaces spaces in path name with underscores.
050     * As a result, if man pages are built in a project directory like
051     * {@code /path/to/My Doc Project},
052     * then the generated man pages end up by default in
053     * {@code /path/to/My_Doc_Project/target/docbkx/manpages}.
054     * <br>
055     * This method copies the result to the expected location.
056     * <br>
057     * This method then attempts to remove the extra generated directory,
058     * though failure to remove the extra directory only logs an informational message
059     * and does no throw an exception.
060     *
061     * @throws MojoExecutionException   Failed to copy files.
062     */
063    public void execute() throws MojoExecutionException {
064        File manPageOutputDir = new File(m.getDocbkxOutputDirectory(), "manpages");
065        File generatedManPageDir = new File(manPageOutputDir.getAbsolutePath().replace(' ', '_'));
066        if (generatedManPageDir.equals(manPageOutputDir)) {
067            return; // Nothing to copy, and do not delete the man page directory.
068        }
069        if (!generatedManPageDir.exists() || !hasChildren(generatedManPageDir)) {
070            m.getLog().info("No man pages found in " + generatedManPageDir.getAbsolutePath());
071            return; // No man pages. Nothing to do.
072        }
073
074        // The generated man page dir is different from the expected man page output dir,
075        // so copy the content to the expected location and try to delete the generated dir.
076        try {
077            FileUtils.copyDirectory(generatedManPageDir, manPageOutputDir, FileFilterUtils.trueFileFilter());
078        } catch (IOException e) {
079            throw new MojoExecutionException(e.getMessage(), e);
080        }
081
082        File topGeneratedDirWithUnderscore = getTopAncestorWithUnderscore(generatedManPageDir);
083        try {
084            FileUtils.deleteDirectory(topGeneratedDirWithUnderscore);
085        } catch (IOException e) {
086            m.getLog().info("Failed to delete generated man page dir: " + generatedManPageDir + e.getMessage());
087        }
088    }
089
090    /**
091     * Returns true if the specified directory has children.
092     * @param directory The directory to check.
093     * @return True if the specified directory has children.
094     */
095    private boolean hasChildren(final File directory) {
096        String[] children = directory.list();
097        return children.length > 0;
098    }
099
100    /**
101     * Returns the top ancestor directory that contains an underscore in the path.
102     * @param directory Returns this directory or an ancestor.
103     * @return The top ancestor directory that contains an underscore in the path.
104     */
105    private File getTopAncestorWithUnderscore(final File directory) {
106        File topAncestorWithUnderscore = directory;
107        while (topAncestorWithUnderscore.getParent().contains("_")) {
108            topAncestorWithUnderscore = topAncestorWithUnderscore.getParentFile();
109        }
110        return topAncestorWithUnderscore;
111    }
112}