feat(cli): add option to disable plugins (#2277)

This commit is contained in:
Skylot
2024-11-01 20:13:34 +00:00
parent 313c4a121a
commit 57238de6ff
9 changed files with 94 additions and 18 deletions
@@ -264,6 +264,9 @@ public class JadxCLIArgs {
@Parameter(names = { "-q", "--quiet" }, description = "turn off output (set --log-level to QUIET)")
protected boolean quiet = false;
@Parameter(names = { "--disable-plugins" }, description = "comma separated list of plugin ids to disable")
protected String disablePlugins = "";
@Parameter(names = { "--version" }, description = "print jadx version")
protected boolean printVersion = false;
@@ -370,6 +373,7 @@ public class JadxCLIArgs {
args.setIntegerFormat(integerFormat);
args.setUseDxInput(useDx);
args.setPluginOptions(pluginOptions);
args.setDisabledPlugins(Arrays.stream(disablePlugins.split(",")).map(String::trim).collect(Collectors.toSet()));
return args;
}
@@ -580,6 +584,10 @@ public class JadxCLIArgs {
return pluginOptions;
}
public String getDisablePlugins() {
return disablePlugins;
}
static class RenameConverter implements IStringConverter<Set<RenameEnum>> {
private final String paramName;
@@ -1,7 +1,7 @@
package jadx.cli;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import com.beust.jcommander.JCommander;
@@ -10,7 +10,7 @@ import jadx.cli.commands.ICommand;
import jadx.core.utils.exceptions.JadxArgsValidateException;
public class JadxCLICommands {
private static final Map<String, ICommand> COMMANDS_MAP = new TreeMap<>();
private static final Map<String, ICommand> COMMANDS_MAP = new LinkedHashMap<>();
static {
JadxCLICommands.register(new CommandPlugins());
@@ -1,12 +1,17 @@
package jadx.cli.commands;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import jadx.api.plugins.JadxPluginInfo;
import jadx.cli.JCommanderWrapper;
import jadx.cli.LogHelper;
import jadx.plugins.tools.JadxPluginsList;
import jadx.plugins.tools.JadxPluginsTools;
import jadx.plugins.tools.data.JadxPluginMetadata;
@@ -24,6 +29,9 @@ public class CommandPlugins implements ICommand {
@Parameter(names = { "-l", "--list" }, description = "list installed plugins")
protected boolean list;
@Parameter(names = { "--list-all" }, description = "list all plugins including bundled and dropins")
protected boolean listAll;
@Parameter(names = { "-a", "--available" }, description = "list available plugins")
protected boolean available;
@@ -53,8 +61,12 @@ public class CommandPlugins implements ICommand {
jcw.printUsage(subCommander);
return;
}
if (!subCommander.getUnknownOptions().isEmpty()) {
System.out.println("Error: found unknown options: " + subCommander.getUnknownOptions());
Set<String> unknownOptions = new HashSet<>(subCommander.getUnknownOptions());
boolean verbose = unknownOptions.remove("-v") || unknownOptions.remove("--verbose");
LogHelper.setLogLevel(verbose ? LogHelper.LogLevelEnum.DEBUG : LogHelper.LogLevelEnum.INFO);
if (!unknownOptions.isEmpty()) {
System.out.println("Error: found unknown options: " + unknownOptions);
}
if (install != null) {
@@ -79,7 +91,10 @@ public class CommandPlugins implements ICommand {
}
}
if (list) {
printInstalledPlugins();
printPlugins(JadxPluginsTools.getInstance().getInstalled());
}
if (listAll) {
printAllPlugins();
}
if (available) {
@@ -107,13 +122,11 @@ public class CommandPlugins implements ICommand {
}
}
private static void printInstalledPlugins() {
List<JadxPluginMetadata> installed = JadxPluginsTools.getInstance().getInstalled();
private static void printPlugins(List<JadxPluginMetadata> installed) {
System.out.println("Installed plugins: " + installed.size());
for (JadxPluginMetadata plugin : installed) {
StringBuilder sb = new StringBuilder();
sb.append(" - ");
sb.append(plugin.getPluginId());
sb.append(" - ").append(plugin.getPluginId());
String version = plugin.getVersion();
if (version != null) {
sb.append(" (").append(version).append(')');
@@ -121,14 +134,28 @@ public class CommandPlugins implements ICommand {
if (plugin.isDisabled()) {
sb.append(" (disabled)");
}
sb.append(" - ");
sb.append(plugin.getName());
sb.append(": ");
sb.append(plugin.getDescription());
sb.append(" - ").append(plugin.getName());
sb.append(": ").append(plugin.getDescription());
System.out.println(sb);
}
}
private static void printAllPlugins() {
List<JadxPluginMetadata> installed = JadxPluginsTools.getInstance().getInstalled();
printPlugins(installed);
Set<String> installedSet = installed.stream().map(JadxPluginMetadata::getPluginId).collect(Collectors.toSet());
List<JadxPluginInfo> plugins = JadxPluginsTools.getInstance().getAllPluginsInfo();
System.out.println("Other plugins: " + plugins.size());
for (JadxPluginInfo plugin : plugins) {
if (!installedSet.contains(plugin.getPluginId())) {
System.out.println(" - " + plugin.getPluginId()
+ " - " + plugin.getName()
+ ": " + plugin.getDescription());
}
}
}
private void installPlugin(String locationId) {
JadxPluginMetadata plugin = JadxPluginsTools.getInstance().install(locationId);
System.out.println("Plugin installed: " + plugin.getPluginId() + ":" + plugin.getVersion());
@@ -7,6 +7,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -194,6 +195,8 @@ public class JadxArgs implements Closeable {
private Map<String, String> pluginOptions = new HashMap<>();
private Set<String> disabledPlugins = new HashSet<>();
private JadxPluginLoader pluginLoader = new JadxBasePluginLoader();
private boolean loadJadxClsSetFile = true;
@@ -766,6 +769,14 @@ public class JadxArgs implements Closeable {
this.pluginOptions = pluginOptions;
}
public Set<String> getDisabledPlugins() {
return disabledPlugins;
}
public void setDisabledPlugins(Set<String> disabledPlugins) {
this.disabledPlugins = disabledPlugins;
}
public JadxPluginLoader getPluginLoader() {
return pluginLoader;
}
@@ -85,7 +85,7 @@ public final class JadxDecompiler implements Closeable {
private static final Logger LOG = LoggerFactory.getLogger(JadxDecompiler.class);
private final JadxArgs args;
private final JadxPluginManager pluginManager = new JadxPluginManager(this);
private final JadxPluginManager pluginManager;
private final List<ICodeLoader> loadedInputs = new ArrayList<>();
private RootNode root;
@@ -93,7 +93,7 @@ public final class JadxDecompiler implements Closeable {
private List<ResourceFile> resources;
private final IDecompileScheduler decompileScheduler = new DecompilerScheduler();
private final ResourcesLoader resourcesLoader = new ResourcesLoader(this);
private final ResourcesLoader resourcesLoader;
private final List<ICodeLoader> customCodeLoaders = new ArrayList<>();
private final List<CustomResourcesLoader> customResourcesLoaders = new ArrayList<>();
@@ -106,7 +106,9 @@ public final class JadxDecompiler implements Closeable {
}
public JadxDecompiler(JadxArgs args) {
this.args = args;
this.args = Objects.requireNonNull(args);
this.pluginManager = new JadxPluginManager(this);
this.resourcesLoader = new ResourcesLoader(this);
}
public void load() {
@@ -4,12 +4,14 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -26,6 +28,7 @@ public class JadxPluginManager {
private final JadxDecompiler decompiler;
private final JadxPluginsData pluginsData;
private final Set<String> disabledPlugins;
private final SortedSet<PluginContext> allPlugins = new TreeSet<>();
private final SortedSet<PluginContext> resolvedPlugins = new TreeSet<>();
private final Map<String, String> provideSuggestions = new TreeMap<>();
@@ -35,6 +38,7 @@ public class JadxPluginManager {
public JadxPluginManager(JadxDecompiler decompiler) {
this.decompiler = decompiler;
this.pluginsData = new JadxPluginsData(decompiler, this);
this.disabledPlugins = decompiler.getArgs().getDisabledPlugins();
}
/**
@@ -55,12 +59,19 @@ public class JadxPluginManager {
public void register(JadxPlugin plugin) {
Objects.requireNonNull(plugin);
PluginContext addedPlugin = addPlugin(plugin);
if (addedPlugin == null) {
LOG.debug("Can't register plugin, it was disabled: {}", plugin.getPluginInfo().getPluginId());
return;
}
LOG.debug("Register plugin: {}", addedPlugin.getPluginId());
resolve();
}
private PluginContext addPlugin(JadxPlugin plugin) {
private @Nullable PluginContext addPlugin(JadxPlugin plugin) {
PluginContext pluginContext = new PluginContext(decompiler, pluginsData, plugin);
if (disabledPlugins.contains(pluginContext.getPluginId())) {
return null;
}
LOG.debug("Loading plugin: {}", pluginContext);
if (!allPlugins.add(pluginContext)) {
throw new IllegalArgumentException("Duplicate plugin id: " + pluginContext + ", class " + plugin.getClass());
@@ -61,6 +61,7 @@ public class JadxSettings extends JadxCLIArgs {
static final Set<String> SKIP_FIELDS = new HashSet<>(Arrays.asList(
"files", "input", "outDir", "outDirSrc", "outDirRes", "outputFormat",
"deobfuscationMapFile",
"disablePlugins",
"verbose", "quiet", "logLevel",
"printVersion", "printHelp"));
@@ -33,7 +33,8 @@ public class CollectPlugins {
.ifPresent(decompiler -> allPlugins.addAll(decompiler.getPluginManager().getResolvedPluginContexts()));
// collect and init not loaded plugins in new temp context
try (JadxDecompiler decompiler = new JadxDecompiler(new JadxArgs())) {
JadxArgs jadxArgs = mainWindow.getSettings().toJadxArgs();
try (JadxDecompiler decompiler = new JadxDecompiler(jadxArgs)) {
JadxPluginManager pluginManager = decompiler.getPluginManager();
pluginManager.registerAddPluginListener(pluginContext -> {
AppContext appContext = new AppContext();
@@ -12,6 +12,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
@@ -115,6 +116,20 @@ public class JadxPluginsTools {
return loadPluginsJson().getInstalled();
}
/**
* Return all loadable plugins info (including installed, bundled and dropins).
* <br>
* For only installed plugins prefer {@link jadx.plugins.tools.JadxPluginsTools#getInstalled}
* method.
*/
public List<JadxPluginInfo> getAllPluginsInfo() {
try (JadxExternalPluginsLoader pluginsLoader = new JadxExternalPluginsLoader()) {
return pluginsLoader.load().stream()
.map(JadxPlugin::getPluginInfo)
.collect(Collectors.toList());
}
}
public List<Path> getAllPluginJars() {
List<Path> list = new ArrayList<>();
for (JadxPluginMetadata pluginMetadata : loadPluginsJson().getInstalled()) {