Last active
January 8, 2022 20:45
-
-
Save Leo40Git/21063d32474dbd5bc699cf873440abf8 to your computer and use it in GitHub Desktop.
Bad Theme Updater
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Uses CorellanStoma#1996's Canary update mappings | |
// https://docs.google.com/spreadsheets/d/1rLm7KJInDfLVbdnnjxfOaFjwdr51vr7hZdGc61-iyy0/edit (download as CSV) | |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.nio.charset.StandardCharsets; | |
import java.nio.file.Files; | |
import java.nio.file.LinkOption; | |
import java.nio.file.Path; | |
import java.nio.file.Paths; | |
import java.util.*; | |
import java.util.regex.Pattern; | |
public final class BadThemeUpdater { | |
public static final class ThemeFiles { | |
private final Map<Path, String> pathToContents; | |
private final Set<Path> dirtyPaths; | |
public ThemeFiles() { | |
pathToContents = new HashMap<>(); | |
dirtyPaths = new HashSet<>(); | |
} | |
public void collect(Path dir) throws IOException { | |
try (var ds = Files.newDirectoryStream(dir)) { | |
for (var child : ds) { | |
if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS)) { | |
collect(child); | |
} else { | |
String name = child.getFileName().toString(); | |
if (name.endsWith(".scss") || name.endsWith(".css")) { | |
pathToContents.put(child, String.join("\n", Files.readAllLines(child, StandardCharsets.UTF_8))); | |
} | |
} | |
} | |
} | |
} | |
private final class FileEntry implements Map.Entry<Path, String> { | |
private final Map.Entry<Path, String> delegate; | |
private FileEntry(Map.Entry<Path, String> delegate) { | |
this.delegate = delegate; | |
} | |
@Override | |
public Path getKey() { | |
return delegate.getKey(); | |
} | |
@Override | |
public String getValue() { | |
return delegate.getValue(); | |
} | |
@Override | |
public String setValue(String value) { | |
var old = delegate.setValue(value); | |
if (!value.equals(old)) { | |
dirtyPaths.add(delegate.getKey()); | |
} | |
return old; | |
} | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
FileEntry fileEntry = (FileEntry) o; | |
return delegate.equals(fileEntry.delegate); | |
} | |
@Override | |
public int hashCode() { | |
return Objects.hash(delegate); | |
} | |
} | |
public Iterable<Map.Entry<Path, String>> getFiles() { | |
return () -> new Iterator<>() { | |
private final Iterator<Map.Entry<Path, String>> delegate = pathToContents.entrySet().iterator(); | |
@Override | |
public boolean hasNext() { | |
return delegate.hasNext(); | |
} | |
@Override | |
public Map.Entry<Path, String> next() { | |
return new FileEntry(delegate.next()); | |
} | |
}; | |
} | |
public void flush() throws IOException { | |
for (var dirtyPath : dirtyPaths) { | |
var content = pathToContents.get(dirtyPath); | |
if (content == null) { | |
continue; | |
} | |
Files.writeString(dirtyPath, content, StandardCharsets.UTF_8); | |
} | |
dirtyPaths.clear(); | |
} | |
} | |
private static final int CLASSES_CSV_HEADER_LINES = 5; | |
private static Map<Pattern, String> parseClassesCSV(BufferedReader reader) throws IOException { | |
// skip header lines | |
for (int i = 0; i < CLASSES_CSV_HEADER_LINES; i++) { | |
if (reader.readLine() == null) { | |
throw new IOException("CSV file was too short!"); | |
} | |
} | |
var map = new HashMap<Pattern, String>(); | |
String line; | |
while ((line = reader.readLine()) != null) { | |
String[] parts = line.split(","); | |
if (parts.length < 3 || !parts[0].isEmpty() || parts[1].isEmpty() || parts[2].isEmpty()) { | |
continue; | |
} | |
parts[1] = addClassSpecifier(parts[1]); | |
parts[2] = addClassSpecifier(parts[2]); | |
map.put(Pattern.compile(parts[1], Pattern.LITERAL), parts[2]); | |
} | |
return map; | |
} | |
private static String addClassSpecifier(String str) { | |
if (!str.startsWith(".")) { | |
return "." + str; | |
} | |
return str; | |
} | |
private static void updateClassReferences(Map<Pattern, String> classMap, ThemeFiles files) { | |
for (var entry : files.getFiles()) { | |
var contents = entry.getValue(); | |
for (var classEntry : classMap.entrySet()) { | |
System.out.println(entry.getKey() + ": " + classEntry.getKey() + " -> " + classEntry.getValue()); | |
contents = classEntry.getKey().matcher(contents).replaceAll(classEntry.getValue()); | |
} | |
entry.setValue(contents); | |
} | |
} | |
public static void main(String[] args) { | |
if (args.length < 2) { | |
System.out.println("2 args expected: <classes csv> <theme directory>"); | |
return; | |
} | |
Path classesCSV = Paths.get(args[0]).toAbsolutePath(); | |
Path themeDir = Paths.get(args[1]).toAbsolutePath(); | |
Map<Pattern, String> classMap; | |
try (var reader = Files.newBufferedReader(classesCSV)) { | |
classMap = parseClassesCSV(reader); | |
} catch (IOException e) { | |
System.err.println("Failed to parse classes CSV from " + classesCSV); | |
e.printStackTrace(); | |
System.exit(1); | |
return; | |
} | |
ThemeFiles files = new ThemeFiles(); | |
try { | |
files.collect(themeDir); | |
} catch (IOException e) { | |
System.err.println("Failed to collect theme files from " + themeDir); | |
e.printStackTrace(); | |
System.exit(1); | |
return; | |
} | |
updateClassReferences(classMap, files); | |
try { | |
files.flush(); | |
} catch (IOException e) { | |
System.err.println("Failed to flush theme files"); | |
e.printStackTrace(); | |
System.exit(1); | |
return; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment