Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ public class ProjectConfigBuilder {
public static MapRequest.CompilationResult apply(WurstProjectConfigData projectConfig, File targetMap,
File mapScript, File buildDir,
RunArgs runArgs, W3InstallationData w3data) throws IOException {
return apply(projectConfig, targetMap, mapScript, buildDir, runArgs, w3data, MapRequest.BUILD_CONFIGURED_SCRIPT_NAME);
}

public static MapRequest.CompilationResult apply(WurstProjectConfigData projectConfig, File targetMap,
File mapScript, File buildDir,
RunArgs runArgs, W3InstallationData w3data,
String outputScriptName) throws IOException {
if (projectConfig.getProjectName().isEmpty()) {
throw new RequestFailedException(MessageType.Error, "wurst.build is missing projectName.");
}
Expand Down Expand Up @@ -72,7 +79,7 @@ public static MapRequest.CompilationResult apply(WurstProjectConfigData projectC
// Only apply buildMapData if config changed or name is present
if (configNeedsApplying && StringUtils.isNotBlank(buildMapData.getName())) {
WLogger.info("Applying buildMapData config");
applyBuildMapData(projectConfig, mapScript, buildDir, w3data, w3I, result, configHash);
applyBuildMapData(projectConfig, mapScript, buildDir, w3data, w3I, result, configHash, outputScriptName);
} else if (!configNeedsApplying) {
WLogger.info("Using cached w3i configuration");
// Still need to set the result.script correctly
Expand Down Expand Up @@ -170,10 +177,10 @@ private static String calculateProjectConfigHash(WurstProjectConfigData projectC

private static void applyBuildMapData(WurstProjectConfigData projectConfig, File mapScript, File buildDir,
W3InstallationData w3data, W3I w3I, MapRequest.CompilationResult result,
String configHash) throws IOException {
String configHash, String outputScriptName) throws IOException {
// Apply w3i config values
prepareW3I(projectConfig, w3I);
result.script = new File(buildDir, "war3mapj_with_config.j.txt");
result.script = new File(buildDir, outputScriptName);

try (FileInputStream inputStream = new FileInputStream(mapScript)) {
StringWriter sw = new StringWriter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ public abstract class MapRequest extends UserRequest<Object> {
private static Long lastMapModified = 0L;
private static String lastMapPath = "";

public static final String BUILD_CONFIGURED_SCRIPT_NAME = "01_war3mapj_with_config.j.txt";
public static final String BUILD_COMPILED_JASS_NAME = "02_compiled.j.txt";
public static final String BUILD_COMPILED_LUA_NAME = "02_compiled.lua";
public static final String BUILD_JHCR_SCRIPT_NAME = "03_jhcr_war3map.j";

/**
* makes the compilation slower, but more safe by discarding results from the editor and working on a copy of the model
*/
Expand Down Expand Up @@ -160,7 +165,7 @@ protected File compileMap(File projectFolder, WurstGui gui, Optional<File> mapCo

String compiledMapScript = sb.toString();
File buildDir = getBuildDir();
File outFile = new File(buildDir, "compiled.lua");
File outFile = new File(buildDir, BUILD_COMPILED_LUA_NAME);
Files.write(compiledMapScript.getBytes(Charsets.UTF_8), outFile);
return outFile;

Expand All @@ -178,7 +183,7 @@ protected File compileMap(File projectFolder, WurstGui gui, Optional<File> mapCo
JassPrinter printer = new JassPrinter(!runArgs.isOptimize(), jassProg.get());
String compiledMapScript = printer.printProg();
File buildDir = getBuildDir();
File outFile = new File(buildDir, "compiled.j.txt");
File outFile = new File(buildDir, BUILD_COMPILED_JASS_NAME);
Files.write(compiledMapScript.getBytes(Charsets.UTF_8), outFile);

if (!runArgs.isDisablePjass()) {
Expand Down Expand Up @@ -208,7 +213,7 @@ protected File compileMap(File projectFolder, WurstGui gui, Optional<File> mapCo
}
}

private File runJassHotCodeReload(File mapScript) throws IOException, InterruptedException {
protected File runJassHotCodeReload(File mapScript) throws IOException, InterruptedException {
File buildDir = getBuildDir();
File commonJ = new File(buildDir, "common.j");
File blizzardJ = new File(buildDir, "blizzard.j");
Expand All @@ -224,7 +229,7 @@ private File runJassHotCodeReload(File mapScript) throws IOException, Interrupte
ProcessBuilder pb = new ProcessBuilder(langServer.getConfigProvider().getJhcrExe(), "init", commonJ.getName(), blizzardJ.getName(), mapScript.getName());
pb.directory(buildDir);
Utils.exec(pb, Duration.ofSeconds(30), System.err::println);
return new File(buildDir, "jhcr_war3map.j");
return renameJhcrOutput(buildDir);
}

/**
Expand Down Expand Up @@ -410,7 +415,7 @@ protected CompilationResult compileScript(ModelManager modelManager, WurstGui gu

if (runArgs.isHotReload()) {
result = new CompilationResult();
result.script = new File(buildDir, "war3mapj_with_config.j.txt");
result.script = new File(buildDir, BUILD_CONFIGURED_SCRIPT_NAME);
if (!result.script.exists()) {
result.script = new File(new File(workspaceRoot.getFile(), "wurst"), "war3map.j");
}
Expand All @@ -419,9 +424,9 @@ protected CompilationResult compileScript(ModelManager modelManager, WurstGui gu
}
} else {
timeTaker.beginPhase("load map script");
File scriptFile = loadMapScript(testMap, modelManager, gui);
File scriptFile = loadMapScript(getMapForScriptExtraction(testMap), modelManager, gui);
timeTaker.endPhase();
result = applyProjectConfig(gui, testMap, buildDir, projectConfigData, scriptFile);
result = applyProjectConfig(gui, testMap, buildDir, projectConfigData, scriptFile, BUILD_CONFIGURED_SCRIPT_NAME);
}

// Compile the script
Expand Down Expand Up @@ -526,7 +531,7 @@ private static boolean startsWith(byte[] data, byte[] prefix) {
return true;
}

private File loadMapScript(Optional<File> mapCopy, ModelManager modelManager, WurstGui gui) throws Exception {
protected File loadMapScript(Optional<File> mapCopy, ModelManager modelManager, WurstGui gui) throws Exception {
File scriptFile = new File(new File(workspaceRoot.getFile(), "wurst"), "war3map.j");
// If runargs are no extract, either use existing or throw error
// Otherwise try loading from map, if map was saved with wurst, try existing script, otherwise error
Expand All @@ -548,12 +553,7 @@ private File loadMapScript(Optional<File> mapCopy, ModelManager modelManager, Wu
lastMapModified = MapRequest.mapLastModified;
lastMapPath = MapRequest.mapPath;
System.out.println("Map not cached yet, extracting script");
byte[] extractedScript = null;
try (@Nullable MpqEditor mpqEditor = MpqEditorFactory.getEditor(mapCopy, true)) {
if (mpqEditor.hasFile("war3map.j")) {
extractedScript = mpqEditor.extractFile("war3map.j");
}
}
byte[] extractedScript = extractMapScript(mapCopy);
if (extractedScript == null) {
if (scriptFile.exists()) {
String msg = "No war3map.j in map file, using old extracted file";
Expand Down Expand Up @@ -589,19 +589,49 @@ private File loadMapScript(Optional<File> mapCopy, ModelManager modelManager, Wu
return scriptFile;
}

private CompilationResult applyProjectConfig(WurstGui gui, Optional<File> testMap, File buildDir, WurstProjectConfigData projectConfig, File scriptFile) {
protected CompilationResult applyProjectConfig(WurstGui gui, Optional<File> testMap, File buildDir, WurstProjectConfigData projectConfig, File scriptFile,
String outputScriptName) {
AtomicReference<CompilationResult> result = new AtomicReference<>();
gui.sendProgress("Applying Map Config...");
timeTaker.measure("Applying Map Config", () -> {
try {
result.set(ProjectConfigBuilder.apply(projectConfig, testMap.get(), scriptFile, buildDir, runArgs, w3data));
result.set(ProjectConfigBuilder.apply(projectConfig, testMap.get(), scriptFile, buildDir, runArgs, w3data, outputScriptName));
} catch (IOException e) {
throw new RuntimeException(e);
}
});
return result.get();
}

protected Optional<File> getMapForScriptExtraction(Optional<File> mapCopy) {
if (map.isPresent()) {
return map;
}
return mapCopy;
}

protected byte[] extractMapScript(Optional<File> mapCopy) throws Exception {
if (!mapCopy.isPresent()) {
return null;
}
try (@Nullable MpqEditor mpqEditor = MpqEditorFactory.getEditor(mapCopy, true)) {
if (mpqEditor.hasFile("war3map.j")) {
return mpqEditor.extractFile("war3map.j");
}
}
return null;
}

protected File renameJhcrOutput(File buildDir) throws IOException {
File rawJhcrScript = new File(buildDir, "jhcr_war3map.j");
if (!rawJhcrScript.exists()) {
throw new IOException("Could not find file " + rawJhcrScript.getAbsolutePath());
}
File renamedJhcrScript = new File(buildDir, BUILD_JHCR_SCRIPT_NAME);
java.nio.file.Files.move(rawJhcrScript.toPath(), renamedJhcrScript.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
return renamedJhcrScript;
}

private W3InstallationData getBestW3InstallationData() throws RequestFailedException {
if (Orient.isLinuxSystem()) {
// no Warcraft installation supported on Linux
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package tests.wurstscript.tests;

import de.peeeq.wurstio.languageserver.BufferManager;
import de.peeeq.wurstio.languageserver.ModelManagerImpl;
import de.peeeq.wurstio.languageserver.WFile;
import de.peeeq.wurstio.languageserver.WurstLanguageServer;
import de.peeeq.wurstio.languageserver.requests.MapRequest;
import de.peeeq.wurstio.utils.FileUtils;
import de.peeeq.wurstscript.gui.WurstGui;
import de.peeeq.wurstscript.gui.WurstGuiLogger;
import org.testng.annotations.Test;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;

public class HotReloadPipelineTests {

@Test
public void hotReloadExtractionUsesSourceMap() throws Exception {
File projectFolder = new File("./temp/testProject_hotrun_extract/");
File wurstFolder = new File(projectFolder, "wurst");
newCleanFolder(wurstFolder);

File sourceMap = new File(projectFolder, "source_map.w3x");
File cachedMap = new File(projectFolder, "cached_map.w3x");
Files.write(sourceMap.toPath(), new byte[] {0x01});
Files.write(cachedMap.toPath(), new byte[] {0x02});

WurstLanguageServer langServer = new WurstLanguageServer();
TestMapRequest request = new TestMapRequest(
langServer,
Optional.of(sourceMap),
List.of(),
WFile.create(projectFolder),
Map.of(
sourceMap, "source script".getBytes(StandardCharsets.UTF_8),
cachedMap, "cached script".getBytes(StandardCharsets.UTF_8)
)
);

MapRequest.mapLastModified = System.currentTimeMillis();
MapRequest.mapPath = sourceMap.getAbsolutePath();

Optional<File> extractionMap = request.getMapForScriptExtractionForTest(Optional.of(cachedMap));
File scriptFile = request.loadMapScriptForTest(extractionMap, new ModelManagerImpl(projectFolder, new BufferManager()), new WurstGuiLogger());

assertEquals(extractionMap.orElse(null), sourceMap);
assertEquals(request.getLastExtractedMap(), sourceMap);
assertEquals(Files.readString(scriptFile.toPath()), "source script");
}

@Test
public void jhcrPipelineRenamesOutputScript() throws Exception {
File projectFolder = new File("./temp/testProject_jhcr_output/");
File wurstFolder = new File(projectFolder, "wurst");
File buildDir = new File(projectFolder, "_build");
newCleanFolder(wurstFolder);
buildDir.mkdirs();

File sourceMap = new File(projectFolder, "source_map.w3x");
WurstLanguageServer langServer = new WurstLanguageServer();
TestMapRequest request = new TestMapRequest(
langServer,
Optional.of(sourceMap),
List.of("-hotstart"),
WFile.create(projectFolder),
new HashMap<>()
);

File rawJhcrScript = new File(buildDir, "jhcr_war3map.j");
Files.writeString(rawJhcrScript.toPath(), "jhcr output");

File renamed = request.renameJhcrOutputForTest(buildDir);

assertEquals(request.isHotStartmapForTest(), true);
assertNotNull(renamed);
assertEquals(renamed.getName(), MapRequest.BUILD_JHCR_SCRIPT_NAME);
}

private void newCleanFolder(File f) throws Exception {
FileUtils.deleteRecursively(f);
Files.createDirectories(f.toPath());
}

private static final class TestMapRequest extends MapRequest {
private final Map<File, byte[]> scriptByMap;
private File lastExtractedMap;

private TestMapRequest(WurstLanguageServer langServer, Optional<File> map, List<String> compileArgs, WFile workspaceRoot,
Map<File, byte[]> scriptByMap) {
super(langServer, map, compileArgs, workspaceRoot, Optional.empty(), Optional.empty());
this.scriptByMap = scriptByMap;
}

@Override
public Object execute(de.peeeq.wurstio.languageserver.ModelManager modelManager) {
return null;
}

@Override
protected byte[] extractMapScript(Optional<File> mapCopy) {
if (mapCopy.isEmpty()) {
return null;
}
lastExtractedMap = mapCopy.get();
return scriptByMap.get(mapCopy.get());
}

private File getLastExtractedMap() {
return lastExtractedMap;
}

private boolean isHotStartmapForTest() {
return runArgs.isHotStartmap();
}

private Optional<File> getMapForScriptExtractionForTest(Optional<File> mapCopy) {
return getMapForScriptExtraction(mapCopy);
}

private File loadMapScriptForTest(Optional<File> mapCopy, ModelManagerImpl modelManager, WurstGui gui) throws Exception {
return loadMapScript(mapCopy, modelManager, gui);
}

private File renameJhcrOutputForTest(File buildDir) throws Exception {
return renameJhcrOutput(buildDir);
}
}
}
Loading