All Downloads are FREE. Search and download functionalities are using the official Maven repository.

au.net.causal.maven.plugins.boxdb.ScriptRunner Maven / Gradle / Ivy

package au.net.causal.maven.plugins.boxdb;

import au.net.causal.maven.plugins.boxdb.db.BoxConfiguration;
import au.net.causal.maven.plugins.boxdb.db.BoxContext;
import au.net.causal.maven.plugins.boxdb.db.BoxDatabase;
import au.net.causal.maven.plugins.boxdb.db.BoxDatabaseException;
import au.net.causal.maven.plugins.boxdb.db.DatabaseStage;
import au.net.causal.maven.plugins.boxdb.db.DatabaseTarget;
import au.net.causal.maven.plugins.boxdb.db.ProjectConfiguration;
import au.net.causal.maven.plugins.boxdb.db.ScriptExecution;
import au.net.causal.maven.plugins.boxdb.db.ScriptSelection;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.shared.filtering.MavenFilteringException;
import org.apache.maven.shared.filtering.MavenResourcesExecution;
import org.apache.maven.shared.filtering.MavenResourcesFiltering;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * Run SQL scripts.
 */
public class ScriptRunner
{
    private final BoxConfiguration boxConfiguration;
    private final BoxDatabase boxDatabase;
    private final ProjectConfiguration projectConfiguration;
    private final BoxContext context;
    private final MavenResourcesFiltering resourcesFiltering;

    private final List tempFilesCreated = new ArrayList<>();

    public ScriptRunner(BoxDatabase boxDatabase, BoxConfiguration boxConfiguration,
                        ProjectConfiguration projectConfiguration, BoxContext context,
                        MavenResourcesFiltering resourcesFiltering)
    {
        this.boxDatabase = boxDatabase;
        this.boxConfiguration = boxConfiguration;
        this.projectConfiguration = projectConfiguration;
        this.context = context;
        this.resourcesFiltering = resourcesFiltering;
    }

    public void execute(ScriptExecution execution, Duration timeout)
    throws IOException, SQLException, BoxDatabaseException, MojoExecutionException
    {
        Objects.requireNonNull(execution, "execution == null");

        DatabaseTarget target;
        if (execution.getStage() == DatabaseStage.CREATE)
            target = DatabaseTarget.ADMIN;
        else
            target = DatabaseTarget.USER;

        List scripts = prepareScriptsForExecution(execution);
        for (Path scriptFile : scripts)
        {
            context.getLog().info("Executing script " + scriptFile);

            switch (execution.getMode())
            {
                case JDBC:
                    try (BufferedReader reader = Files.newBufferedReader(scriptFile, StandardCharsets.UTF_8))
                    {
                        boxDatabase.executeJdbcScript(reader, target);
                    }
                    break;
                case NATIVE:
                    boxDatabase.executeScript(scriptFile.toUri().toURL(), target, timeout);
                    break;
                default:
                    throw new Error("Unsupported execution mode: " + execution.getMode());
            }
        }
    }

    private List prepareScriptsForExecution(ScriptExecution scriptExecution)
    throws MojoExecutionException
    {
        //Expand list out into files - need to expand variables such as box.type, etc.
        List scriptNames = scriptExecution.getScripts();
        processScriptNamesSubstitutions(scriptNames);

        //Now fully expanded, turn into list of paths
        List scriptPaths = scriptNames.stream()
                .map(scriptName -> makePath(scriptExecution.getDirectory() == null ? null : scriptExecution.getDirectory().toPath(), scriptName))
                .collect(Collectors.toList());

        //Filter out non-existing script paths
        List scriptPathsThatDoNotExist = new ArrayList<>();
        for (Iterator i = scriptPaths.iterator(); i.hasNext();)
        {
            Path scriptPath = i.next();
            if (Files.notExists(scriptPath))
            {
                context.getLog().info("Script " + scriptPath + " does not exist");
                scriptPathsThatDoNotExist.add(scriptPath);
                i.remove();
            }
        }

        if (!scriptExecution.isIgnoreMissing() && scriptExecution.getSelection() != ScriptSelection.FIRST &&
                !scriptPathsThatDoNotExist.isEmpty())
        {
            throw new MojoExecutionException("Script files " + scriptPathsThatDoNotExist + " do not exist.");
        }
        else if (!scriptExecution.isIgnoreMissing() && scriptExecution.getSelection() == ScriptSelection.FIRST &&
                scriptPaths.isEmpty())
        {
            throw new MojoExecutionException("No script files specified by " + scriptNames + " exist.");
        }

        //If there are no scripts left then abort now
        if (scriptPaths.isEmpty())
            return Collections.emptyList();

        if (scriptExecution.getSelection() == ScriptSelection.FIRST && scriptPaths.size() > 1)
            scriptPaths = Collections.singletonList(scriptPaths.get(0));

        //We now have a list of script files we want to execute
        if (scriptExecution.isFiltering())
            scriptPaths = filterScripts(scriptPaths);

        return scriptPaths;
    }

    private List filterScripts(List scriptFiles)
            throws MojoExecutionException
    {
        context.getLog().debug("Filtering " + scriptFiles);

        List resources = new ArrayList<>();

        for (Path scriptFile : scriptFiles)
        {
            Resource r = new Resource();
            r.setFiltering(true);
            r.setDirectory(scriptFile.getParent().toString());
            r.setIncludes(Collections.singletonList(scriptFile.getFileName().toString()));
            resources.add(r);
        }

        Properties boxProperties = new Properties();
        boxConfiguration.toProperties(boxProperties);

        try
        {
            Path workDirectory = context.getTempDirectory();
            Files.createDirectories(workDirectory);
            File outDirectory = Files.createTempDirectory(workDirectory, "sql").toFile();
            tempFilesCreated.add(outDirectory.toPath());
            MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution(resources, outDirectory,
                    projectConfiguration.getProject(), StandardCharsets.UTF_8.name(),
                    Collections.emptyList(), Collections.emptyList(),
                    context.getSession());
            mavenResourcesExecution.setAdditionalProperties(boxProperties);
            resourcesFiltering.filterResources(mavenResourcesExecution);

            //Find the matching file names in the output directory
            List outputFiles = new ArrayList<>(scriptFiles.size());
            Path outPath = outDirectory.toPath();
            for (Path inFile : scriptFiles)
            {
                Path outFile = outPath.resolve(inFile.getFileName());
                tempFilesCreated.add(outFile);
                outputFiles.add(outFile);
            }

            return outputFiles;
        }
        catch (MavenFilteringException e)
        {
            throw new MojoExecutionException("Error filtering files: " + e, e);
        }
        catch (IOException e)
        {
            throw new MojoExecutionException("Error creating output directory: " + e, e);
        }
    }

    private Path makePath(Path baseDirectory, String name)
    {
        //TODO do we need separator substitution here?
        if (baseDirectory == null)
            return Paths.get(name);
        else
            return baseDirectory.resolve(name);
    }

    private void processScriptNamesSubstitutions(List names)
    {
        for (ListIterator i = names.listIterator(); i.hasNext();)
        {
            String name = i.next();
            name = processScriptNameSubstitution(name);
            i.set(name);
        }
    }

    private String processScriptNameSubstitution(String name)
    {
        //TODO replace ${box.name}, etc. with actual value using better mechanism
        name = name.replace("${box.databaseType}", boxConfiguration.getDatabaseType());
        name = name.replace("${box.databaseName}", boxConfiguration.getDatabaseName());
        if (boxConfiguration.getDatabaseVersion() != null)
        {
            name = name.replace("${box.databaseVersion}", boxConfiguration.getDatabaseVersion());
            name = name.replace("${box.databaseVersion.major}", Versions.majorVersion(boxConfiguration.getDatabaseVersion()));
        }
        return name;
    }

    public List getTempFilesCreated()
    {
        return Collections.unmodifiableList(tempFilesCreated);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy