Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the TypeScript target work on Windows #850

Merged
merged 11 commits into from
Jan 18, 2022
9 changes: 2 additions & 7 deletions .github/workflows/ts-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
run:
strategy:
matrix:
platform: [ubuntu-latest, macos-latest]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
- name: Setup Java JDK
Expand All @@ -23,13 +23,8 @@ jobs:
java-version: 11
- name: Setup Node.js environment
uses: actions/setup-node@v2.1.2
- name: Cache .pnpm-store
uses: actions/cache@v1
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-node${{ matrix.node-version }}-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Install pnpm
run: sudo npm i -g pnpm
run: npm i -g pnpm
- name: Install Dependencies Ubuntu
run: sudo apt-get install libprotobuf-dev protobuf-compiler
if: ${{ runner.os == 'Linux' }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.lflang.tests.runtime;

import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import org.lflang.Target;
import org.lflang.tests.AbstractTest;
Expand Down Expand Up @@ -46,6 +47,7 @@ public void runMultiportTests() {
@Test
@Override
public void runSerializationTests() {
Assumptions.assumeFalse(isWindows(), Message.NO_WINDOWS_SUPPORT);
super.runSerializationTests();
}

Expand Down
3 changes: 2 additions & 1 deletion org.lflang/src/lib/ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@
"@babel/preset-typescript": "^7.8.3",
"@types/google-protobuf": "^3.7.4",
"@types/node": "^13.9.2",
"rimraf": "^3.0.2",
"typescript": "^3.8.3",
"ts-protoc-gen": "^0.12.0"
},
"scripts": {
"check-types": "tsc",
"build": "rm -rf dist && babel src --out-dir dist --extensions '.ts,.js'"
"build": "rimraf dist && babel src --out-dir dist --extensions .ts,.js"
}
}
61 changes: 47 additions & 14 deletions org.lflang/src/org/lflang/util/LFCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
import java.io.PrintStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.eclipse.xtext.util.CancelIndicator;

Expand Down Expand Up @@ -174,13 +177,8 @@ public int run(CancelIndicator cancelIndicator) {
System.out.println("--- Current working directory: " + processBuilder.directory().toString());
System.out.println("--- Executing command: " + String.join(" ", processBuilder.command()));

final Process process;
try {
process = processBuilder.start();
} catch (IOException e) {
e.printStackTrace();
return -1;
}
final Process process = startProcess();
if (process == null) return -1;

ScheduledExecutorService poller = Executors.newSingleThreadScheduledExecutor();
poller.scheduleAtFixedRate(
Expand Down Expand Up @@ -303,7 +301,7 @@ public static LFCommand get(final String cmd, final List<String> args, Path dir)
final File cmdFile = dir.resolve(cmd).toFile();
if (cmdFile.exists() && cmdFile.canExecute()) {
builder = new ProcessBuilder(cmdList);
} else if (checkIfCommandIsOnPath(cmd, dir)) {
} else if (findCommand(cmd) != null) {
builder = new ProcessBuilder(cmdList);
} else if (checkIfCommandIsExecutableWithBash(cmd, dir)) {
builder = new ProcessBuilder("bash", "--login", "-c", String.join(" ", cmdList));
Expand All @@ -318,23 +316,58 @@ public static LFCommand get(final String cmd, final List<String> args, Path dir)
}


private static boolean checkIfCommandIsOnPath(final String command, final Path dir) {
/**
* Search for matches to the given command by following the PATH environment variable.
* @param command A command for which to search.
* @return The file locations of matches to the given command.
*/
private static List<File> findCommand(final String command) {
final String whichCmd = System.getProperty("os.name").startsWith("Windows") ? "where" : "which";
final ProcessBuilder whichBuilder = new ProcessBuilder(List.of(whichCmd, command));
whichBuilder.directory(dir.toFile());
try {
int whichReturn = whichBuilder.start().waitFor();
return whichReturn == 0;
Process p = whichBuilder.start();
if (p.waitFor() != 0) return null;
return Arrays.stream(new String(p.getInputStream().readAllBytes()).split("\n"))
.map(String::strip).map(File::new).filter(File::canExecute).collect(Collectors.toList());
} catch (InterruptedException | IOException e) {
e.printStackTrace();
return false;
return null;
}
}

/**
* Attempt to start the execution of this command.
petervdonovan marked this conversation as resolved.
Show resolved Hide resolved
*
* First collect a list of paths where the executable might be found,
* then select an executable that successfully executes from the
* list of paths. Return the {@code Process} instance that is the
* result of a successful execution, or {@code null} if no successful
* execution happened.
* @return The {@code Process} that is started by this command, or {@code null} in case of failure.
*/
private Process startProcess() {
ArrayDeque<String> commands = new ArrayDeque<>();
List<File> matchesOnPath = findCommand(processBuilder.command().get(0));
if (matchesOnPath != null) {
matchesOnPath.stream().map(File::toString).forEach(commands::addLast);
}
while (true) {
try {
return processBuilder.start();
} catch (IOException e) {
if (commands.isEmpty()) {
e.printStackTrace();
return null;
}
}
processBuilder.command().set(0, commands.removeFirst());
}
}


private static boolean checkIfCommandIsExecutableWithBash(final String command, final Path dir) {
// check first if bash is installed
if (!checkIfCommandIsOnPath("bash", dir)) {
if (findCommand("bash") == null) {
return false;
}

Expand Down