Skip to content

Commit

Permalink
Merge branch 'dev4' of https://github.com/Col-E/Recaf into pr/722
Browse files Browse the repository at this point in the history
  • Loading branch information
Col-E committed Oct 21, 2023
2 parents b8c5f22 + 1260283 commit b9dc5cc
Show file tree
Hide file tree
Showing 30 changed files with 370 additions and 97 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
**/hs_err_pid*
# Build the distribution jar and upload it, without bundling JavaFX in the jar
- name: Create distribution jar
run: ./gradlew build -x test -Dskip.jfx.bundle=true
run: ./gradlew assemble -x compileTestJava -Dskip.jfx.bundle=true
- name: Upload distribution jar
if: always()
uses: actions/upload-artifact@v3
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,19 @@ An easy to use modern Java bytecode editor that abstracts away the complexities

## Download

- [Managed launcher](https://github.com/Col-E/Recaf-Launcher) _(Pending)_
- [Independent releases](https://github.com/Col-E/Recaf/releases)
- [Managed launcher](https://github.com/Col-E/Recaf-Launcher)
- Use the following launcher commands, one after another, to keep Recaf up-to-date and run it:
- `update-ci -b dev4`
- `update-jfx`
- `compatibility`
- `run`
- Or run the launcher with the following argument to do that all for you in one go:
- `auto`
- To update Recaf use `update-ci -b dev4`. The `-b <VALUE>` can be used to specify other 4X based branches.
- To run Recaf use the `run` command.
- To use the `run` command you must use the `update-jfx` command at least once.
- To validate your local environment can run Recaf the `compatibility` command tells you what conflicts exist, if any.
- [Independent releases](https://github.com/Col-E/Recaf/releases) _(None for 4X currently)_

## Features

Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
plugins {
id "com.github.ben-manes.versions" version "0.42.0" apply false
id 'com.github.ben-manes.versions' version '0.42.0' apply false
id 'gov.tak.gradle.plugins.coverage-report-aggregator' version '1.3.0'
id 'gov.tak.gradle.plugins.checker-processor' version "1.2.7"
id 'gov.tak.gradle.plugins.checker-processor' version '2.0.0' apply false
}

allprojects {
Expand Down
18 changes: 9 additions & 9 deletions dependencies.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
def asmVersion = '9.5'
def asmVersion = '9.6'
def cafeDudeVersion = '1.10.2'
def junitVersion = '5.10.0'
def jasmVersion = '2.0.1'
def junitVersion = '5.9.2'

project.ext {
asm = "org.ow2.asm:asm:$asmVersion"
Expand All @@ -13,21 +13,21 @@ project.ext {
// Use our fork of Android's release with fixes and less transitive dependencies
binary_resources = 'com.github.Col-E:binary-resources:31.3.0-alpha01.8'

atlantafx = 'io.github.mkpaz:atlantafx-base:2.0.0'
atlantafx = 'io.github.mkpaz:atlantafx-base:2.0.1'

cafedude = "com.github.Col-E:CAFED00D:$cafeDudeVersion"

cfr = 'org.benf:cfr:0.152'

cdi_api = 'jakarta.enterprise:jakarta.enterprise.cdi-api:4.0.1'
cdi_impl = 'org.jboss.weld.se:weld-se-core:5.1.0.Final'
cdi_impl = 'org.jboss.weld.se:weld-se-core:5.1.2.Final'

dex_translator = 'software.coley:dex-translator:1.1.1'

directories = 'dev.dirs:directories:26'
docking = 'com.github.Col-E:tiwulfx-dock:1.2.3'

downgrader = 'com.github.RaphiMC.JavaDowngrader:core:13e29798a8'
downgrader = 'com.github.RaphiMC.JavaDowngrader:core:1.1.1'

extra_collections = 'software.coley:extra-collections:1.2.3'
extra_observables = 'software.coley:extra-observables:1.3.0'
Expand All @@ -54,15 +54,15 @@ project.ext {

llzip = 'software.coley:lljzip:2.3.0'

logging_impl = 'ch.qos.logback:logback-classic:1.2.10' // newer releases break in jar releases
logging_impl = 'ch.qos.logback:logback-classic:1.4.11' // newer releases break in jar releases

mockito = 'org.mockito:mockito-core:4.9.0'
mockito = 'org.mockito:mockito-core:5.6.0'

openrewrite = 'org.openrewrite:rewrite-java-17:8.1.3'
openrewrite = 'org.openrewrite:rewrite-java-17:8.7.4'

procyon = "org.bitbucket.mstrobel:procyon-compilertools:0.6.0"

picocli = 'info.picocli:picocli:4.7.1'
picocli = 'info.picocli:picocli:4.7.5'

regex = 'com.github.tommyettinger:regexodus:0.1.15'

Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.gradle.caching=true
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ public Object intercept(InvocationContext context) throws Exception {
if (isApplicationScoped) {
// Application scoped beans may want to listen to workspaces opening and closing
// for, well, the duration of the application.
if (value instanceof WorkspaceOpenListener)
workspaceManager.addWorkspaceOpenListener((WorkspaceOpenListener) value);
if (value instanceof WorkspaceCloseListener)
workspaceManager.addWorkspaceCloseListener((WorkspaceCloseListener) value);
if (value instanceof WorkspaceOpenListener openListener)
workspaceManager.addWorkspaceOpenListener(openListener);
if (value instanceof WorkspaceCloseListener closeListener)
workspaceManager.addWorkspaceCloseListener(closeListener);
} else {
// The bean is likely dependent scoped, or linked to the lifespan of the current workspace.
// This it only really makes sense to have the close listener be supported.
Expand All @@ -75,16 +75,15 @@ public Object intercept(InvocationContext context) throws Exception {
if (value instanceof WorkspaceOpenListener)
logger.warn("The class '{}' implements '{}' but is not @ApplicationScoped",
valueType.getName(), WorkspaceOpenListener.class.getSimpleName());
if (value instanceof WorkspaceCloseListener)
workspaceManager.addWorkspaceCloseListener(
new AutoUnregisteringCloseListener((WorkspaceCloseListener) value));
if (value instanceof WorkspaceCloseListener closeListener)
workspaceManager.addWorkspaceCloseListener(new AutoUnregisteringCloseListener(closeListener));
}

// If a current workspace exists (at the time of creation of the instance), add the modification listener too.
// We don't need to worry about clearing these because workspaces remove their own listeners on closing.
Workspace current = workspaceManager.getCurrent();
if (current != null && value instanceof WorkspaceModificationListener)
current.addWorkspaceModificationListener((WorkspaceModificationListener) value);
if (current != null && value instanceof WorkspaceModificationListener modificationListener)
current.addWorkspaceModificationListener(modificationListener);

return context.proceed();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,32 @@ public JvmClassInfoBuilder(@Nonnull byte[] bytecode) {

/**
* Copies over values by reading the contents of the class file in the reader.
* Calls {@link #adaptFrom(ClassReader, int)} with {@code flags=0}.
*
* @param reader
* ASM class reader to pull data from.
*
* @return Builder.
*/
@Nonnull
@SuppressWarnings("deprecation")
public JvmClassInfoBuilder adaptFrom(@Nonnull ClassReader reader) {
reader.accept(new ClassBuilderAppender(), 0);
return adaptFrom(reader, 0);
}

/**
* Copies over values by reading the contents of the class file in the reader.
*
* @param reader
* ASM class reader to pull data from.
* @param flags
* Reader flags to use when populating information.
*
* @return Builder.
*/
@Nonnull
@SuppressWarnings(value = "deprecation")
public JvmClassInfoBuilder adaptFrom(@Nonnull ClassReader reader, int flags) {
reader.accept(new ClassBuilderAppender(), flags);
return withBytecode(reader.b);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,14 @@ public boolean hasEqualOrChildValue(@Nonnull PathNode<?> other) {
if (other instanceof DirectoryPathNode otherDirectory) {
String dir = getValue();
String maybeParentDir = otherDirectory.getValue();
return dir.startsWith(maybeParentDir);

// We cannot do just a basic 'startsWith' check on the path values since they do not
// end with a trailing slash. This could lead to cases where:
// 'co' is a parent value of 'com/foo'
//
// By doing an equals check, we allow for 'co' vs 'com' to fail but 'co' vs 'co' to pass,
// and the following startsWith check with a slash allows us to not fall to the suffix issue described above.
return dir.equals(maybeParentDir) || dir.startsWith(maybeParentDir + "/");
}

return super.hasEqualOrChildValue(other);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ public DelegatingJavaParser(@Nonnull JavaParser delegate) {
this.delegate = delegate;
}

@Nonnull
@Override
public SourceFile requirePrintEqualsInput(@Nonnull SourceFile sourceFile, @Nonnull Input input, @Nullable Path relativeTo, @Nonnull ExecutionContext ctx) {
// Do not do any idempotent source file checks
return sourceFile;
}

@Nonnull
@Override
public Stream<SourceFile> parseInputs(@Nonnull Iterable<Input> sources,
Expand All @@ -41,6 +48,10 @@ public Stream<SourceFile> parseInputs(@Nonnull Iterable<Input> sources,
// The default source-set type generation logic is not well optimized.
// We also do not gain significant benefits from it, so we can skip it entirely.
ctx.putMessage(SKIP_SOURCE_SET_TYPE_GENERATION, true);

// Do not do any idempotent source file checks
ctx.putMessage(ExecutionContext.REQUIRE_PRINT_EQUALS_INPUT, false);

return delegate.parseInputs(sources, relativeTo, ctx);
} catch (Throwable t) {
logger.error("Error while parsing source into AST", t);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ public JvmClassInfo get(@Nonnull Object name) {
cache.put(key, STUB);
return null;
}
JvmClassInfo info = new JvmClassInfoBuilder(new ClassReader(value)).build();
JvmClassInfo info = new JvmClassInfoBuilder()
.adaptFrom(new ClassReader(value), ClassReader.SKIP_CODE)
.build();
cache.put(key, info);
return info;
}
Expand Down
24 changes: 16 additions & 8 deletions recaf-ui/build.gradle
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.13'
id 'com.github.johnrengelman.shadow' version '7.1.2'
id 'org.openjfx.javafxplugin' version '0.1.0'
id 'com.github.johnrengelman.shadow' version '8.1.1'
}

def javaFxVersion = '19'
def javaFxVersion = '21'
def javaFxIncludeInDist = System.getProperty('skip.jfx.bundle') == null

application {
mainClass = 'software.coley.recaf.Main'
}

javafx {
version = javaFxVersion
modules = ['javafx.controls', 'javafx.media']
configuration = javaFxIncludeInDist ? 'implementation' : 'compileOnly'
configurations = javaFxIncludeInDist ? [ 'implementation' ] : [ 'compileOnly', 'testImplementation' ]
}

dependencies {
Expand All @@ -27,4 +23,16 @@ dependencies {
implementation ikonli_pack
implementation richtextfx
implementation treemapfx
}

application {
mainClass = 'software.coley.recaf.Main'
}

shadowJar {
exclude "META-INF/maven/**"
exclude "META-INF/rewrite/**"
exclude "META-INF/proguard/*"
exclude "META-INF/native-image/*"
exclude "META-INF/*.properties"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import jakarta.annotation.Nonnull;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Scene;
Expand Down Expand Up @@ -38,6 +37,8 @@
public class RecafApplication extends Application implements WorkspaceOpenListener, WorkspaceCloseListener {
private final Recaf recaf = Bootstrap.get();
private final BorderPane root = new BorderPane();
private WorkspaceRootPane workspaceRootPane;
private WelcomePane welcomePane;

@Override
public void start(Stage stage) {
Expand All @@ -48,6 +49,8 @@ public void start(Stage stage) {
MainMenu menu = recaf.get(MainMenu.class);
WelcomePane pane = recaf.get(WelcomePane.class);
Node logging = createLoggingWrapper();
workspaceRootPane = recaf.get(WorkspaceRootPane.class);
welcomePane = recaf.get(WelcomePane.class);

// Layout
SplitPane splitPane = new SplitPane(root, logging);
Expand Down Expand Up @@ -93,17 +96,11 @@ private Node createLoggingWrapper() {

@Override
public void onWorkspaceClosed(@Nonnull Workspace workspace) {
FxThreadUtil.run(() -> {
WelcomePane pane = recaf.get(WelcomePane.class);
root.setCenter(pane);
});
FxThreadUtil.run(() -> root.setCenter(welcomePane));
}

@Override
public void onWorkspaceOpened(@Nonnull Workspace workspace) {
FxThreadUtil.run(() -> {
WorkspaceRootPane pane = recaf.get(WorkspaceRootPane.class);
root.setCenter(pane);
});
FxThreadUtil.run(() -> root.setCenter(workspaceRootPane));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ public void configure(@Nonnull Cell<?> cell, @Nonnull PathNode<?> item, @Nonnull
openPath(item);
else if (treeItem.isExpanded()) // Looks odd, but results in less rapid re-closures
TreeItems.recurseOpen(treeItem);
else
TreeItems.recurseClose(treeCell.getTreeView(), treeItem);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Node;
import javafx.scene.control.Tab;
import org.slf4j.Logger;
import software.coley.recaf.analytics.logging.Logging;
import software.coley.recaf.cdi.EagerInitialization;
Expand All @@ -21,6 +22,7 @@
import software.coley.recaf.services.mapping.MappingResults;
import software.coley.recaf.ui.docking.DockingManager;
import software.coley.recaf.ui.docking.DockingTab;
import software.coley.recaf.util.FxThreadUtil;
import software.coley.recaf.workspace.WorkspaceManager;
import software.coley.recaf.workspace.WorkspaceModificationListener;
import software.coley.recaf.workspace.model.Workspace;
Expand Down Expand Up @@ -77,7 +79,8 @@ public NavigationManager(@Nonnull NavigationManagerConfig config,
spy.changed(contentProperty, null, contentProperty.getValue());
});
dockingManager.addTabClosureListener(((parent, tab) -> {
NavigableSpy spy = tabToSpy.get(tab);
// The tab is closed, remove its spy lookup.
NavigableSpy spy = tabToSpy.remove(tab);
if (spy == null) {
logger.warn("Tab {} was closed, but had no associated content spy instance", tab.getText());
return;
Expand All @@ -98,6 +101,20 @@ public NavigationManager(@Nonnull NavigationManagerConfig config,
if (dockingTab != null)
dockingTab.close();
}

// Validate all child references have been removed.
if (!children.isEmpty()) {
logger.warn("Navigation manager children list was not empty after workspace closure");
children.clear();
}
if (!childrenToTab.isEmpty()) {
logger.warn("Navigation manager children-to-tab map was not empty after workspace closure");
childrenToTab.clear();
}

// Remove the path reference to the old workspace.
forwarding.workspacePath = null;
path = null;
});

// Track current workspace so that we are navigable ourselves.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*
* @author Matt Coley
*/
@SuppressWarnings("unchecked")
public class ItemListSelectionPopup<T> extends SelectionPopup<T> {
private final ListView<T> list = new ListView<>();

Expand Down Expand Up @@ -84,7 +85,6 @@ protected ObservableValue<Boolean> isNullSelection() {

@Nonnull
@Override
@SuppressWarnings("unchecked")
public ItemListSelectionPopup<T> withMultipleSelection() {
list.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
return this;
Expand Down
Loading

0 comments on commit b9dc5cc

Please sign in to comment.