|
1 | 1 | /* |
2 | | - * Copyright 2016 DiffPlug |
| 2 | + * Copyright 2016-2020 DiffPlug |
3 | 3 | * |
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | 5 | * you may not use this file except in compliance with the License. |
@@ -72,7 +72,70 @@ public final class GitAttributesLineEndings { |
72 | 72 | // prevent direct instantiation |
73 | 73 | private GitAttributesLineEndings() {} |
74 | 74 |
|
75 | | - public static Policy create(File projectDir, Supplier<Iterable<File>> toFormat) { |
| 75 | + /** |
| 76 | + * Creates a line-endings policy whose serialized state is relativized against projectDir, |
| 77 | + * at the cost of eagerly evaluating the line-ending state of every target file. |
| 78 | + */ |
| 79 | + public static LineEnding.Policy createRelocatable(File projectDir, Supplier<Iterable<File>> toFormat) { |
| 80 | + return new RelocatablePolicy(projectDir, toFormat); |
| 81 | + } |
| 82 | + |
| 83 | + static class RelocatablePolicy extends LazyForwardingEquality<CachedEndings> implements LineEnding.Policy { |
| 84 | + private static final long serialVersionUID = 5868522122123693015L; |
| 85 | + |
| 86 | + final transient File projectDir; |
| 87 | + final transient Supplier<Iterable<File>> toFormat; |
| 88 | + |
| 89 | + RelocatablePolicy(File projectDir, Supplier<Iterable<File>> toFormat) { |
| 90 | + this.projectDir = Objects.requireNonNull(projectDir, "projectDir"); |
| 91 | + this.toFormat = Objects.requireNonNull(toFormat, "toFormat"); |
| 92 | + } |
| 93 | + |
| 94 | + @Override |
| 95 | + protected CachedEndings calculateState() throws Exception { |
| 96 | + Runtime runtime = new FileState(projectDir, toFormat.get()).atRuntime(); |
| 97 | + return new CachedEndings(projectDir, runtime, toFormat.get()); |
| 98 | + } |
| 99 | + |
| 100 | + @Override |
| 101 | + public String getEndingFor(File file) { |
| 102 | + return state().endingFor(file); |
| 103 | + } |
| 104 | + } |
| 105 | + |
| 106 | + static class CachedEndings implements Serializable { |
| 107 | + private static final long serialVersionUID = -2534772773057900619L; |
| 108 | + |
| 109 | + /** this is transient, to simulate PathSensitive.RELATIVE */ |
| 110 | + transient final String rootDir; |
| 111 | + /** the line ending used for most files */ |
| 112 | + final String defaultEnding; |
| 113 | + /** any exceptions to that default, in terms of relative path from rootDir */ |
| 114 | + final ConcurrentRadixTree<String> hasNonDefaultEnding = new ConcurrentRadixTree<>(new DefaultCharSequenceNodeFactory()); |
| 115 | + |
| 116 | + CachedEndings(File projectDir, Runtime runtime, Iterable<File> toFormat) { |
| 117 | + rootDir = FileSignature.pathNativeToUnix(projectDir.getAbsolutePath()) + "/"; |
| 118 | + defaultEnding = runtime.defaultEnding; |
| 119 | + for (File file : toFormat) { |
| 120 | + String ending = runtime.getEndingFor(file); |
| 121 | + if (!ending.equals(defaultEnding)) { |
| 122 | + String path = FileSignature.pathNativeToUnix(file.getAbsolutePath()); |
| 123 | + hasNonDefaultEnding.put(path, ending); |
| 124 | + } |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + /** Returns the line ending appropriate for the given file. */ |
| 129 | + public String endingFor(File file) { |
| 130 | + String path = FileSignature.pathNativeToUnix(file.getAbsolutePath()); |
| 131 | + String subpath = FileSignature.subpath(rootDir, path); |
| 132 | + String ending = hasNonDefaultEnding.getValueForExactKey(subpath); |
| 133 | + return ending == null ? defaultEnding : ending; |
| 134 | + } |
| 135 | + } |
| 136 | + |
| 137 | + /** Creates a line-endings policy whose serialized state includes absolute paths to this machine. */ |
| 138 | + public static LineEnding.Policy create(File projectDir, Supplier<Iterable<File>> toFormat) { |
76 | 139 | return new Policy(projectDir, toFormat); |
77 | 140 | } |
78 | 141 |
|
|
0 commit comments