public class TempDir implements Directory {

    final File f;

    public TempDir(final TemporaryFolder tempFolder) throws IOException {
        f = tempFolder.newFolder();
    }

    @Override
    public File asFile() {
        return f;
    }

    @Override
    public boolean isGenerated() {
        return true;
    }
} @Value.Immutable
public interface DistributionPackage {
	
	@Parameter
	ArchiveType archiveType();
	
	@Parameter
	FileSet fileSet();
	
	@Parameter
	String archivePath();
	
	static DistributionPackage of(ArchiveType archiveType, FileSet fileSet, String path) {
		return ImmutableDistributionPackage.of(archiveType, fileSet, path);
	}
	
	static ImmutableDistributionPackage.Builder builder() {
		return ImmutableDistributionPackage.builder();
	}
} @Value.Immutable
public interface DownloadConfig {
	
	DistributionDownloadPath getDownloadPath();
	
	ProgressListener getProgressListener();

	Directory getArtifactStorePath();
	
	TempNaming getFileNaming();

	String getDownloadPrefix();

	String getUserAgent();

	Optional<String> getAuthorization();

	PackageResolver getPackageResolver();

	@Default
	default TimeoutConfig getTimeoutConfig() {
		return TimeoutConfig.defaults();
	}
	
	Optional<ProxyFactory> proxyFactory();

	public static ImmutableDownloadConfig.Builder builder() {
		return ImmutableDownloadConfig.builder();
	}
} @Value.Immutable
public interface FileSet {

	List<Entry> entries();
	
	@Check
	default void shouldContainOneMoreExecutable() {
		boolean oneOrMoreExecutableFound = entries().stream().anyMatch(e -> e.type()==FileType.Executable);
		if (!oneOrMoreExecutableFound) {
			throw new IllegalArgumentException("there is no executable in this file set");
		}
	}
	
	@Value.Immutable
    abstract class Entry {
		@Parameter
		public abstract FileType type();

		@Parameter
		public abstract String destination();

		@Parameter
		protected abstract UncompiledPattern uncompiledMatchingPattern();
		
		@Auxiliary
		public Pattern matchingPattern() {
			return uncompiledMatchingPattern().compile();
		}

		static Entry of(FileType type, String filename, Pattern pattern) {
			return ImmutableEntry.of(type,filename, UncompiledPattern.of(pattern));
		}
	}
	
	class Builder extends ImmutableFileSet.Builder {
		
		public Builder addEntry(FileType type, String filename) {
			return addEntry(type,filename,".*"+filename);
		}

		public Builder addEntry(FileType type, String filename, String pattern) {
			return addEntry(type,filename,Pattern.compile(pattern,Pattern.CASE_INSENSITIVE));
		}

		public Builder addEntry(FileType type, String filename, Pattern pattern) {
			return addEntries(Entry.of(type,filename, pattern));
		}

	}
	
	static Builder builder() {
		return new Builder();
	}
} public enum FileType {
	Executable,
	Library
} public interface PackageResolver {
	DistributionPackage packageFor(Distribution distribution);
} public enum ArchiveType {
	TGZ(new TgzExtractor()),
	TBZ2(new Tbz2Extractor()),
	ZIP(new ZipExtractor()),
	EXE(new ArchiveIsFileExtractor()),
	TXZ(new TxzExtractor());

	private final Extractor extractor;

	ArchiveType(Extractor extractor) {
		this.extractor = extractor;
	}

	public Extractor getExtractor() {
		return extractor;
	}
} @Value.Immutable
public abstract class Distribution {

	@Parameter
	public abstract Version version();

	@Parameter
	public abstract Platform platform();

	@Override
	public String toString() {
		return "" + version() + ":" + platform();
	}

	public static Distribution detectFor(Version version) {
		return of(version, Platform.detect());
	}

	public static Distribution of(Version version, Platform platform) {
		return ImmutableDistribution.of(version, platform);
	}
} @FunctionalInterface
public interface Version {

	String asInDownloadPath();
	
	@Value.Immutable
	interface GenericVersion extends Version {
		
		@Override
		@Parameter
		String asInDownloadPath();
	}
	
	static GenericVersion of(String asInDownloadPath) {
		return ImmutableGenericVersion.of(asInDownloadPath);
	}
} public class UUIDTempNaming implements TempNaming {

	@Override
	public String nameFor(String prefix, String postfix) {
		return prefix + "-" + UUID.randomUUID().toString() + postfix;
	}

} public interface Directory {

	File asFile();

	boolean isGenerated();
} public class StandardConsoleProgressListener implements ProgressListener {

	private String lastLabel = null;
	private int lastPercent = -1;

	@Override
	public void progress(String label, int percent) {
		if (!label.equals(lastLabel)) {
			System.out.print(label);
			System.out.print(" ");
		}
		if (percent != lastPercent) {
			System.out.print(percent);
			System.out.print("% ");
		}
		lastLabel = label;
		lastPercent = percent;
	}

	@Override
	public void done(String label) {
		System.out.println(label + " DONE");
	}

	@Override
	public void start(String label) {
		System.out.println(label + " START");
	}

	@Override
	public void info(String label, String message) {
		System.out.println(label + " " + message);
	}
}
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import de.flapdoodle.embed.process.TempDir;
import de.flapdoodle.embed.process.config.store.DistributionPackage;
import de.flapdoodle.embed.process.config.store.DownloadConfig;
import de.flapdoodle.embed.process.config.store.FileSet;
import de.flapdoodle.embed.process.config.store.FileType;
import de.flapdoodle.embed.process.config.store.PackageResolver;
import de.flapdoodle.embed.process.distribution.ArchiveType;
import de.flapdoodle.embed.process.distribution.Distribution;
import de.flapdoodle.embed.process.distribution.Version;
import de.flapdoodle.embed.process.extract.UUIDTempNaming;
import de.flapdoodle.embed.process.io.directories.Directory;
import de.flapdoodle.embed.process.io.progress.StandardConsoleProgressListener;
/**
 * Copyright (C) 2011
 *   Michael Mosmann <michael@mosmann.de>
 *   Martin Jöhren <m.joehren@googlemail.com>
 *
 * with contributions from
 * 	konstantin-ba@github,
	Archimedes Trajano (trajano@github),
	Kevin D. Keck (kdkeck@github),
	Ben McCann (benmccann@github)
 *
 * 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.
 */
package de.flapdoodle.embed.process.store;





public class LocalArtifactStoreTest {

  @Rule
  public TemporaryFolder tempFolder = new TemporaryFolder();

  @Test
  public void storingArtifactShouldNotFailWhenAlreadyExists() throws IOException {
    Distribution distribution = Distribution.detectFor(Version.of("1.0.37"));