public static FileEntriesLayer extraDirectoryLayerConfiguration(
      Path sourceDirectory,
      AbsoluteUnixPath targetDirectory,
      List<String> includes,
      List<String> excludes,
      Map<String, FilePermissions> extraDirectoryPermissions,
      ModificationTimeProvider modificationTimeProvider)
      throws IOException {
    FileEntriesLayer.Builder builder =
        FileEntriesLayer.builder().setName(LayerType.EXTRA_FILES.getName());
    Map<PathMatcher, FilePermissions> permissionsPathMatchers = new LinkedHashMap<>();
    for (Map.Entry<String, FilePermissions> entry : extraDirectoryPermissions.entrySet()) {
      permissionsPathMatchers.put(
          FileSystems.getDefault().getPathMatcher(GLOB_PREFIX + entry.getKey()), entry.getValue());
    }

    DirectoryWalker walker = new DirectoryWalker(sourceDirectory).filterRoot();
    // add exclusion filters
    excludes.stream()
        .map(pattern -> FileSystems.getDefault().getPathMatcher(GLOB_PREFIX + pattern))
        .forEach(
            pathMatcher ->
                walker.filter(path -> !pathMatcher.matches(sourceDirectory.relativize(path))));
    // add an inclusion filter
    includes.stream()
        .map(pattern -> FileSystems.getDefault().getPathMatcher(GLOB_PREFIX + pattern))
        .map(
            pathMatcher ->
                (Predicate<Path>) path -> pathMatcher.matches(sourceDirectory.relativize(path)))
        .reduce((matches1, matches2) -> matches1.or(matches2))
        .ifPresent(walker::filter);
    // walk the source tree and add layer entries
    walker.walk(
        localPath -> {
          AbsoluteUnixPath pathOnContainer =
              targetDirectory.resolve(sourceDirectory.relativize(localPath));
          Instant modificationTime = modificationTimeProvider.get(localPath, pathOnContainer);
          Optional<FilePermissions> permissions =
              determinePermissions(
                  pathOnContainer, extraDirectoryPermissions, permissionsPathMatchers);
          if (permissions.isPresent()) {
            builder.addEntry(localPath, pathOnContainer, permissions.get(), modificationTime);
          } else {
            builder.addEntry(localPath, pathOnContainer, modificationTime);
          }
        });
    return builder.build();
  }
@Test
  public void testExtraDirectoryLayerConfiguration_excludes()
      throws URISyntaxException, IOException {
    Path extraFilesDirectory = Paths.get(Resources.getResource("core/layer").toURI());
    FileEntriesLayer layerConfiguration =
        JavaContainerBuilderHelper.extraDirectoryLayerConfiguration(
            extraFilesDirectory,
            AbsoluteUnixPath.get("/"),
            Collections.emptyList(),
            Arrays.asList("**/bar", "**/*a*"),
            Collections.emptyMap(),
            (ignored1, ignored2) -> Instant.EPOCH);
    assertThat(layerConfiguration.getEntries())
        .comparingElementsUsing(SOURCE_FILE_OF)
        .containsExactly(
            extraFilesDirectory.resolve("a"),
            extraFilesDirectory.resolve("a/b"),
            extraFilesDirectory.resolve("c"),
            extraFilesDirectory.resolve("foo"));
  }