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

de.flapdoodle.embed.process.store.PostgresFilesToExtract Maven / Gradle / Ivy

The newest version!
package de.flapdoodle.embed.process.store;

import de.flapdoodle.embed.process.config.store.FileSet;
import de.flapdoodle.embed.process.config.store.FileType;
import de.flapdoodle.embed.process.distribution.Distribution;
import de.flapdoodle.embed.process.extract.*;
import de.flapdoodle.embed.process.io.directories.IDirectory;
import de.flapdoodle.embed.process.io.file.Files;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.nio.file.Paths;


/**
 * @author Ilya Sadykov
 *         Hacky strategy of extraction. Allows to extract the full postgres binaries.
 */
public class PostgresFilesToExtract extends FilesToExtract {
    private static final Logger LOGGER = LoggerFactory.getLogger(PostgresFilesToExtract.class);

    private static final String SKIP_PATTERN = "pgsql/(doc|include|symbols|pgAdmin[^/]*)/.+";
    private static final String EXECUTABLE_PATTERN = "pgsql/bin/.+";

    private final FileSet    fileSet;
    private final String       extractBasePath;

    public PostgresFilesToExtract(IDirectory dirFactory, ITempNaming executableNaming, FileSet fileSet, Distribution distribution) {
        super(dirFactory, executableNaming, fileSet);
        this.fileSet = fileSet;

        if (dirFactory.asFile() != null) {
            final File file = new File(dirFactory.asFile(), "pgsql-" + distribution.getVersion().asInDownloadPath());
            if (!file.exists()) {
                //noinspection ResultOfMethodCallIgnored
                file.mkdir();
            }
            this.extractBasePath = file.getPath();
        } else {
            this.extractBasePath = null;
        }
    }

    /**
     * This is actually the very dirty hack method to adopt the Flapdoodle's API to the compatible way to extract and run
     * TODO: hacky method. Should be considered for complete rewriting //NOSONAR
     */
    @Override
    public IExtractionMatch find(final IArchiveEntry entry) {//NOSONAR
        if (this.extractBasePath == null) {
            return null;
        }
        if (entry.getName().matches(SKIP_PATTERN)) {
            return null;
        }

        final Path path = Paths.get(this.extractBasePath, entry.getName());
        return new IExtractionMatch() { //NOSONAR
            @Override
            public File write(InputStream source, long size) throws IOException { //NOSONAR
                boolean isSymLink = false;
                String linkName = "";
                if (entry instanceof CommonsArchiveEntryAdapter) {
                    try {
                        // hack to allow symlinks extraction (ONLY tar archives are supported!)
                        Field archiveEntryField = CommonsArchiveEntryAdapter.class.getDeclaredField("_entry");
                        archiveEntryField.setAccessible(true);
                        ArchiveEntry archiveEntry = (ArchiveEntry) archiveEntryField.get(entry);
                        if (archiveEntry instanceof TarArchiveEntry
                                && (isSymLink = ((TarArchiveEntry) archiveEntry).isSymbolicLink())) { //NOSONAR
                            linkName = ((TarArchiveEntry) archiveEntry).getLinkName();
                        }
                        archiveEntry.getSize();
                    } catch (NoSuchFieldException | IllegalAccessException e) {
                        throw new RuntimeException("Check the version of de.flapdoodle.embed.process API. " + //NOSONAR
                                "Has it changed?", e);
                    }
                }
                // I got some problems with concurrency. Not sure this is required.
                synchronized (PostgresFilesToExtract.class) {
                    final File outputFile = path.toFile();
                    if (entry.isDirectory()) {
                        if (!outputFile.exists()) {
                            Files.createDir(outputFile);
                        }
                    } else {
                        if (!outputFile.exists()) { // prevent double extraction (for other binaries)
                            if (isSymLink) {
                                try { // NOSONAR
                                    final Path target = path.getParent().resolve(Paths.get(linkName));
                                    java.nio.file.Files.createSymbolicLink(outputFile.toPath(), target);
                                } catch (Exception e) {
                                    LOGGER.trace("Failed to extract symlink", e);
                                }
                            } else {
                                Files.write(source, outputFile);
                            }
                        }
                        // hack to mark binaries as executable
                        if (entry.getName().matches(EXECUTABLE_PATTERN)) {
                            outputFile.setExecutable(true);
                        }
                    }
                    return outputFile;
                }
            }

            @Override
            public FileType type() {
                // does this archive entry match to any of the provided fileset entries?
                for (FileSet.Entry matchingEntry : fileSet.entries()) {
                    if (matchingEntry.matchingPattern().matcher(path.toString()).matches()) {
                        return matchingEntry.type();
                    }
                }
                // Otherwise - it's just an library file
                return FileType.Library;
            }
        };
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy