diff options
Diffstat (limited to 'gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java')
-rw-r--r-- | gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java | 306 |
1 files changed, 0 insertions, 306 deletions
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java deleted file mode 100644 index 4ad770189c..0000000000 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright (C) 2011 The Android Open Source Project -// -// 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 com.google.gerrit.pgm.rules; - -import com.google.gerrit.common.TimeUtil; -import com.google.gerrit.common.Version; -import com.google.gerrit.reviewdb.client.RefNames; -import com.google.gerrit.server.config.GerritServerConfig; -import com.google.gerrit.server.config.SitePaths; -import com.google.inject.Inject; -import com.google.inject.assistedinject.Assisted; -import com.googlecode.prolog_cafe.compiler.Compiler; -import com.googlecode.prolog_cafe.exceptions.CompileException; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.Callable; -import java.util.jar.Attributes; -import java.util.jar.JarEntry; -import java.util.jar.JarOutputStream; -import java.util.jar.Manifest; -import javax.tools.Diagnostic; -import javax.tools.DiagnosticCollector; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; -import org.eclipse.jgit.errors.MissingObjectException; -import org.eclipse.jgit.lib.Config; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.Repository; - -/** - * Helper class for Rulec: does the actual prolog -> java src -> class -> jar work Finds rules.pl in - * refs/meta/config branch Creates rules-(sha1 of rules.pl).jar in (site-path)/cache/rules - */ -public class PrologCompiler implements Callable<PrologCompiler.Status> { - public interface Factory { - PrologCompiler create(Repository git); - } - - public enum Status { - NO_RULES, - COMPILED - } - - private final Path ruleDir; - private final Repository git; - - @Inject - PrologCompiler( - @GerritServerConfig Config config, SitePaths site, @Assisted Repository gitRepository) { - Path cacheDir = site.resolve(config.getString("cache", null, "directory")); - ruleDir = cacheDir != null ? cacheDir.resolve("rules") : null; - git = gitRepository; - } - - @Override - public Status call() throws IOException, CompileException { - ObjectId metaConfig = git.resolve(RefNames.REFS_CONFIG); - if (metaConfig == null) { - return Status.NO_RULES; - } - - ObjectId rulesId = git.resolve(metaConfig.name() + ":rules.pl"); - if (rulesId == null) { - return Status.NO_RULES; - } - - if (ruleDir == null) { - throw new CompileException("Caching not enabled"); - } - Files.createDirectories(ruleDir); - - File tempDir = File.createTempFile("GerritCodeReview_", ".rulec"); - if (!tempDir.delete() || !tempDir.mkdir()) { - throw new IOException("Cannot create " + tempDir); - } - try { - // Try to make the directory accessible only by this process. - // This may help to prevent leaking rule data to outsiders. - tempDir.setReadable(true, true); - tempDir.setWritable(true, true); - tempDir.setExecutable(true, true); - - compileProlog(rulesId, tempDir); - compileJava(tempDir); - - Path jarPath = ruleDir.resolve("rules-" + rulesId.getName() + ".jar"); - List<String> classFiles = getRelativePaths(tempDir, ".class"); - createJar(jarPath, classFiles, tempDir, metaConfig, rulesId); - - return Status.COMPILED; - } finally { - deleteAllFiles(tempDir); - } - } - - /** Creates a copy of rules.pl and compiles it into Java sources. */ - private void compileProlog(ObjectId prolog, File tempDir) throws IOException, CompileException { - File tempRules = copyToTempFile(prolog, tempDir); - try { - Compiler comp = new Compiler(); - comp.prologToJavaSource(tempRules.getPath(), tempDir.getPath()); - } finally { - tempRules.delete(); - } - } - - private File copyToTempFile(ObjectId blobId, File tempDir) - throws IOException, FileNotFoundException, MissingObjectException { - // Any leak of tmp caused by this method failing will be cleaned - // up by our caller when tempDir is recursively deleted. - File tmp = File.createTempFile("rules", ".pl", tempDir); - try (OutputStream out = Files.newOutputStream(tmp.toPath())) { - git.open(blobId).copyTo(out); - } - return tmp; - } - - /** Compile java src into java .class files */ - private void compileJava(File tempDir) throws IOException, CompileException { - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - if (compiler == null) { - throw new CompileException("JDK required (running inside of JRE)"); - } - - DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); - try (StandardJavaFileManager fileManager = - compiler.getStandardFileManager(diagnostics, null, null)) { - Iterable<? extends JavaFileObject> compilationUnits = - fileManager.getJavaFileObjectsFromFiles(getAllFiles(tempDir, ".java")); - ArrayList<String> options = new ArrayList<>(); - String classpath = getMyClasspath(); - if (classpath != null) { - options.add("-classpath"); - options.add(classpath); - } - options.add("-d"); - options.add(tempDir.getPath()); - JavaCompiler.CompilationTask task = - compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits); - if (!task.call()) { - Locale myLocale = Locale.getDefault(); - StringBuilder msg = new StringBuilder(); - msg.append("Cannot compile to Java bytecode:"); - for (Diagnostic<? extends JavaFileObject> err : diagnostics.getDiagnostics()) { - msg.append('\n'); - msg.append(err.getKind()); - msg.append(": "); - if (err.getSource() != null) { - msg.append(err.getSource().getName()); - } - msg.append(':'); - msg.append(err.getLineNumber()); - msg.append(": "); - msg.append(err.getMessage(myLocale)); - } - throw new CompileException(msg.toString()); - } - } - } - - private String getMyClasspath() { - StringBuilder cp = new StringBuilder(); - appendClasspath(cp, getClass().getClassLoader()); - return 0 < cp.length() ? cp.toString() : null; - } - - private void appendClasspath(StringBuilder cp, ClassLoader classLoader) { - if (classLoader.getParent() != null) { - appendClasspath(cp, classLoader.getParent()); - } - if (classLoader instanceof URLClassLoader) { - for (URL url : ((URLClassLoader) classLoader).getURLs()) { - if ("file".equals(url.getProtocol())) { - if (0 < cp.length()) { - cp.append(File.pathSeparatorChar); - } - cp.append(url.getPath()); - } - } - } - } - - /** Takes compiled prolog .class files, puts them into the jar file. */ - private void createJar( - Path archiveFile, List<String> toBeJared, File tempDir, ObjectId metaConfig, ObjectId rulesId) - throws IOException { - long now = TimeUtil.nowMs(); - Manifest mf = new Manifest(); - mf.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); - mf.getMainAttributes().putValue("Built-by", "Gerrit Code Review " + Version.getVersion()); - if (git.getDirectory() != null) { - mf.getMainAttributes().putValue("Source-Repository", git.getDirectory().getPath()); - } - mf.getMainAttributes().putValue("Source-Commit", metaConfig.name()); - mf.getMainAttributes().putValue("Source-Blob", rulesId.name()); - - Path tmpjar = Files.createTempFile(archiveFile.getParent(), ".rulec_", ".jar"); - try (OutputStream stream = Files.newOutputStream(tmpjar); - JarOutputStream out = new JarOutputStream(stream, mf)) { - byte[] buffer = new byte[10240]; - // TODO: fixify this loop - for (String path : toBeJared) { - JarEntry jarAdd = new JarEntry(path); - File f = new File(tempDir, path); - jarAdd.setTime(now); - out.putNextEntry(jarAdd); - if (f.isFile()) { - try (InputStream in = Files.newInputStream(f.toPath())) { - while (true) { - int nRead = in.read(buffer, 0, buffer.length); - if (nRead <= 0) { - break; - } - out.write(buffer, 0, nRead); - } - } - } - out.closeEntry(); - } - } - - try { - Files.move(tmpjar, archiveFile); - } catch (IOException e) { - throw new IOException("Cannot replace " + archiveFile, e); - } - } - - private List<File> getAllFiles(File dir, String extension) throws IOException { - ArrayList<File> fileList = new ArrayList<>(); - getAllFiles(dir, extension, fileList); - return fileList; - } - - private void getAllFiles(File dir, String extension, List<File> fileList) throws IOException { - for (File f : listFiles(dir)) { - if (f.getName().endsWith(extension)) { - fileList.add(f); - } - if (f.isDirectory()) { - getAllFiles(f, extension, fileList); - } - } - } - - private List<String> getRelativePaths(File dir, String extension) throws IOException { - ArrayList<String> pathList = new ArrayList<>(); - getRelativePaths(dir, extension, "", pathList); - return pathList; - } - - private static void getRelativePaths( - File dir, String extension, String path, List<String> pathList) throws IOException { - for (File f : listFiles(dir)) { - if (f.getName().endsWith(extension)) { - pathList.add(path + f.getName()); - } - if (f.isDirectory()) { - getRelativePaths(f, extension, path + f.getName() + "/", pathList); - } - } - } - - private static void deleteAllFiles(File dir) throws IOException { - for (File f : listFiles(dir)) { - if (f.isDirectory()) { - deleteAllFiles(f); - } else { - f.delete(); - } - } - dir.delete(); - } - - private static File[] listFiles(File dir) throws IOException { - File[] files = dir.listFiles(); - if (files == null) { - throw new IOException("Failed to list directory: " + dir); - } - return files; - } -} |