LCOV - code coverage report
Current view: top level - pgm - JythonShell.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 0 89 0.0 %
Date: 2022-11-19 15:00:39 Functions: 0 17 0.0 %

          Line data    Source code
       1             : // Copyright (C) 2013 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.pgm;
      16             : 
      17             : import com.google.common.flogger.FluentLogger;
      18             : import com.google.gerrit.launcher.GerritLauncher;
      19             : import java.io.File;
      20             : import java.io.IOException;
      21             : import java.io.InputStream;
      22             : import java.lang.reflect.InvocationTargetException;
      23             : import java.lang.reflect.Method;
      24             : import java.net.URL;
      25             : import java.net.URLClassLoader;
      26             : import java.util.ArrayList;
      27             : import java.util.Properties;
      28             : 
      29             : public class JythonShell {
      30           0 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      31             : 
      32             :   private static final String STARTUP_RESOURCE = "com/google/gerrit/pgm/Startup.py";
      33             :   private static final String STARTUP_FILE = "Startup.py";
      34             : 
      35             :   private Class<?> console;
      36             :   private Class<?> pyObject;
      37             :   private Class<?> pySystemState;
      38             :   private Object shell;
      39             :   private ArrayList<String> injectedVariables;
      40             : 
      41           0 :   public JythonShell() {
      42           0 :     Properties env = new Properties();
      43             :     // Let us inspect private class members
      44           0 :     env.setProperty("python.security.respectJavaAccessibility", "false");
      45             : 
      46           0 :     File home = GerritLauncher.getHomeDirectory();
      47           0 :     if (home != null) {
      48           0 :       env.setProperty("python.cachedir", new File(home, "jythoncache").getPath());
      49             :     }
      50             : 
      51             :     // For package introspection and "import com.google" to work,
      52             :     // Jython needs to inspect actual .jar files (not just classloader)
      53           0 :     StringBuilder classPath = new StringBuilder();
      54           0 :     final ClassLoader cl = getClass().getClassLoader();
      55           0 :     if (cl instanceof java.net.URLClassLoader) {
      56             :       @SuppressWarnings("resource")
      57           0 :       URLClassLoader ucl = (URLClassLoader) cl;
      58           0 :       for (URL u : ucl.getURLs()) {
      59           0 :         if ("file".equals(u.getProtocol())) {
      60           0 :           if (classPath.length() > 0) {
      61           0 :             classPath.append(java.io.File.pathSeparatorChar);
      62             :           }
      63           0 :           classPath.append(u.getFile());
      64             :         }
      65             :       }
      66             :     }
      67           0 :     env.setProperty("java.class.path", classPath.toString());
      68             : 
      69           0 :     console = findClass("org.python.util.InteractiveConsole");
      70           0 :     pyObject = findClass("org.python.core.PyObject");
      71           0 :     pySystemState = findClass("org.python.core.PySystemState");
      72             : 
      73           0 :     runMethod(
      74             :         pySystemState,
      75             :         pySystemState,
      76             :         "initialize",
      77             :         new Class<?>[] {Properties.class, Properties.class},
      78             :         new Object[] {null, env});
      79             : 
      80             :     try {
      81           0 :       shell = console.getConstructor(new Class<?>[] {}).newInstance();
      82           0 :       logger.atInfo().log("Jython shell instance created.");
      83           0 :     } catch (InstantiationException
      84             :         | IllegalAccessException
      85             :         | IllegalArgumentException
      86             :         | InvocationTargetException
      87             :         | NoSuchMethodException
      88             :         | SecurityException e) {
      89           0 :       throw noInterpreter(e);
      90           0 :     }
      91           0 :     injectedVariables = new ArrayList<>();
      92           0 :     set("Shell", this);
      93           0 :   }
      94             : 
      95             :   protected Object runMethod0(
      96             :       Class<?> klazz, Object instance, String name, Class<?>[] sig, Object[] args)
      97             :       throws InvocationTargetException {
      98             :     try {
      99             :       Method m;
     100           0 :       m = klazz.getMethod(name, sig);
     101           0 :       return m.invoke(instance, args);
     102           0 :     } catch (NoSuchMethodException
     103             :         | IllegalAccessException
     104             :         | IllegalArgumentException
     105             :         | SecurityException e) {
     106           0 :       throw cannotStart(e);
     107             :     }
     108             :   }
     109             : 
     110             :   protected Object runMethod(
     111             :       Class<?> klazz, Object instance, String name, Class<?>[] sig, Object[] args) {
     112             :     try {
     113           0 :       return runMethod0(klazz, instance, name, sig, args);
     114           0 :     } catch (InvocationTargetException e) {
     115           0 :       throw cannotStart(e);
     116             :     }
     117             :   }
     118             : 
     119             :   protected Object runInterpreter(String name, Class<?>[] sig, Object[] args) {
     120           0 :     return runMethod(console, shell, name, sig, args);
     121             :   }
     122             : 
     123             :   protected String getDefaultBanner() {
     124           0 :     return (String) runInterpreter("getDefaultBanner", new Class<?>[] {}, new Object[] {});
     125             :   }
     126             : 
     127             :   protected void printInjectedVariable(String id) {
     128           0 :     runInterpreter(
     129             :         "exec",
     130             :         new Class<?>[] {String.class},
     131             :         new Object[] {"print '\"%s\" is \"%s\"' % (\"" + id + "\", " + id + ")"});
     132           0 :   }
     133             : 
     134             :   public void run() {
     135           0 :     for (String key : injectedVariables) {
     136           0 :       printInjectedVariable(key);
     137           0 :     }
     138           0 :     reload();
     139           0 :     runInterpreter(
     140             :         "interact",
     141             :         new Class<?>[] {String.class, pyObject},
     142             :         new Object[] {
     143           0 :           getDefaultBanner()
     144             :               + " running for Gerrit "
     145           0 :               + com.google.gerrit.common.Version.getVersion(),
     146             :           null,
     147             :         });
     148           0 :   }
     149             : 
     150             :   public void set(String key, Object content) {
     151           0 :     runInterpreter("set", new Class<?>[] {String.class, Object.class}, new Object[] {key, content});
     152           0 :     injectedVariables.add(key);
     153           0 :   }
     154             : 
     155             :   private static Class<?> findClass(String klazzname) {
     156             :     try {
     157           0 :       return Class.forName(klazzname);
     158           0 :     } catch (ClassNotFoundException e) {
     159           0 :       throw noShell("Class " + klazzname + " not found", e);
     160             :     }
     161             :   }
     162             : 
     163             :   public void reload() {
     164           0 :     execResource(STARTUP_RESOURCE);
     165           0 :     execFile(GerritLauncher.getHomeDirectory(), STARTUP_FILE);
     166           0 :   }
     167             : 
     168             :   protected void execResource(String p) {
     169           0 :     try (InputStream in = JythonShell.class.getClassLoader().getResourceAsStream(p)) {
     170           0 :       if (in != null) {
     171           0 :         execStream(in, "resource " + p);
     172             :       } else {
     173           0 :         logger.atSevere().log("Cannot load resource %s", p);
     174             :       }
     175           0 :     } catch (IOException e) {
     176           0 :       logger.atSevere().withCause(e).log("%s", e.getMessage());
     177           0 :     }
     178           0 :   }
     179             : 
     180             :   protected void execFile(File parent, String p) {
     181             :     try {
     182           0 :       File script = new File(parent, p);
     183           0 :       if (script.canExecute()) {
     184           0 :         runMethod0(
     185             :             console,
     186             :             shell,
     187             :             "execfile",
     188             :             new Class<?>[] {String.class},
     189           0 :             new Object[] {script.getAbsolutePath()});
     190             :       } else {
     191           0 :         logger.atInfo().log(
     192           0 :             "User initialization file %s is not found or not executable", script.getAbsolutePath());
     193             :       }
     194           0 :     } catch (InvocationTargetException e) {
     195           0 :       logger.atSevere().withCause(e).log("Exception occurred while loading file %s", p);
     196           0 :     } catch (SecurityException e) {
     197           0 :       logger.atSevere().withCause(e).log("SecurityException occurred while loading file %s", p);
     198           0 :     }
     199           0 :   }
     200             : 
     201             :   protected void execStream(InputStream in, String p) {
     202             :     try {
     203           0 :       runMethod0(
     204             :           console,
     205             :           shell,
     206             :           "execfile",
     207             :           new Class<?>[] {InputStream.class, String.class},
     208             :           new Object[] {in, p});
     209           0 :     } catch (InvocationTargetException e) {
     210           0 :       logger.atSevere().withCause(e).log("Exception occurred while loading %s", p);
     211           0 :     }
     212           0 :   }
     213             : 
     214             :   private static UnsupportedOperationException noShell(String m, Throwable why) {
     215           0 :     final String prefix = "Cannot create Jython shell: ";
     216           0 :     final String postfix = "\n     (You might need to install jython.jar in the lib directory)";
     217           0 :     return new UnsupportedOperationException(prefix + m + postfix, why);
     218             :   }
     219             : 
     220             :   private static UnsupportedOperationException noInterpreter(Throwable why) {
     221           0 :     final String msg = "Cannot create Python interpreter";
     222           0 :     return noShell(msg, why);
     223             :   }
     224             : 
     225             :   private static UnsupportedOperationException cannotStart(Throwable why) {
     226           0 :     final String msg = "Cannot start Jython shell";
     227           0 :     return new UnsupportedOperationException(msg, why);
     228             :   }
     229             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750