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

Set cwd before executing a project #12618

Open
wants to merge 20 commits into
base: develop
Choose a base branch
from

Conversation

Akirathan
Copy link
Member

@Akirathan Akirathan commented Mar 24, 2025

Fixes #12301

Pull Request Description

Set working directory to the parent of PROJECT_ROOT before executing project. This ensures that all the relative paths are resolved as expected.

Important Notes

Implemented via TruffleLanguage.Env.setWorkingDirectory in https://github.com/enso-org/enso/pull/12618/files#diff-00348de86920168e139b84ff0d5c712b1e58065389cc7a0cbd90421a31a2954dR177. At the end, it seems that we won't need to use syscalls as proposed in #12301.

Reverted relevant parts of #10660 and #10928 - see #12618 (comment)

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • The documentation has been updated, if necessary.
  • Screenshots/screencasts have been attached, if there are any visual changes. For interactive or animated visual changes, a screencast is preferred.
  • All code follows the
    Scala,
    Java,
    TypeScript,
    and
    Rust
    style guides. In case you are using a language not listed above, follow the Rust style guide.
  • Unit tests have been written where possible.
  • If meaningful changes were made to logic or tests affecting Enso Cloud integration in the libraries,
    or the Snowflake database integration, a run of the Extra Tests has been scheduled.
    • If applicable, it is suggested to paste a link to a successful run of the Extra Tests.

@Akirathan Akirathan added the CI: No changelog needed Do not require a changelog entry for this PR. label Mar 24, 2025
@Akirathan Akirathan self-assigned this Mar 24, 2025
@Akirathan
Copy link
Member Author

Setting current working directory via System.setProperty("user.dir", path) does not work. Let's try to set the current directory via polyglot context builder - 020c735.

…ests.

Runner_Spec was failing on NI anyway. There is no way of getting path to the currently running binary.
@Akirathan
Copy link
Member Author

Relevant parts from #10660 reverted in:

#10928 reverted in c0df438

@Akirathan
Copy link
Member Author

Tested:

  • runEngineDistribution --run /home/pavel/tmp/Proj/src/Main.enso
  • runEngineDistribution --run test/Base_Tests/src/Data/Vector_Spec.enso

Both works well without any warnings.

Copy link
Member

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • trying to avoid usage of JNI and System Java?
  • I am skeptical we can get this done without it
  • Please expand the test cases to use java.io.File via host interop

var parentDirAbs = parentDir.toAbsolutePath().toString();
if (!System.getProperty("user.dir").equals(parentDirAbs)) {
var truffleFile = env.getPublicTruffleFile(parentDirAbs);
env.setCurrentWorkingDirectory(truffleFile);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The javadoc says:

The current working directory is used to resolve non absolute paths in TruffleFile methods.

Is this enough? How does:

polyglot java import java.io.File
main =
            file = File.new "MY_FILE.txt"
            file.absolute.path

behave?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately you are right. The test with java.io.File, added in b6ae534, fails:

[error] Test org.enso.interpreter.test.ContextInitTest.shouldChangeWorkingDir_BeforeExecutingProject_JavaFile failed: java.lang.AssertionError: 
[error] Expected: is "/tmp/junit14724631386455624624/MY_FILE.txt"
[error]      but: was "/home/pavel/dev/enso/engine/runtime-integration-tests/MY_FILE.txt", took 4.496 sec
[error]     at org.enso.interpreter.test.ContextInitTest.lambda$shouldChangeWorkingDir_BeforeExecutingProject_JavaFile$1(ContextInitTest.java:64)
[error]     at org.enso.test.utils.ProjectUtils.testProjectRun(ProjectUtils.java:108)
[error]     at org.enso.interpreter.test.ContextInitTest.shouldChangeWorkingDir_BeforeExecutingProject_JavaFile(ContextInitTest.java:59)
[error]     at jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
[error]     at java.lang.reflect.Method.invoke(Method.java:580)
[error]     ...
[info] Test run org.enso.interpreter.test.ContextInitTest finished: 1 failed, 0 ignored, 2 total, 6.832s
[error] Failed: Total 2, Failed 1, Errors 0, Passed 1
[error] Failed tests:
[error] 	org.enso.interpreter.test.ContextInitTest
[error] (Test / testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 113 s (01:53), completed Mar 27, 2025, 6:22:45 PM

I will need to implement this via JNI and System Java after all ...

var ctxBuilder = ContextUtils.defaultContextBuilder().out(out).err(out);
var expectedWorkingDir = projDir.getParent();
var expectedPath = expectedWorkingDir.resolve("MY_FILE.txt").toAbsolutePath().toString();
ProjectUtils.testProjectRun(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to turn this (also) into integration test that launches enso with and without --jvm flag. Such tests are traditionally placed into Example_Tests - like

res = Process.run enso_bin.path [ "--run", prj.path ]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted in the commit message of ae2b06c, I have already tried to test it that way, but the test was failing in NI, as enso_bin could not be found. If you could think about a way how to launch something like enso --new New_Project from within enso running in NI, I will reintroduce that test once again.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no way of getting path to the currently running binary

There is a way. I was working with @sdedic to get such functionality into NI few years ago...

how to launch something like enso --new New_Project from within enso running in NI

..one can getClass().getProtectioDomain().getCodeSource().getLocation() to get "some URL" - probably the URL should point to the location of enso executable. Invoking that from a .enso test may need further changes:

  • either some builtin
  • or reflective config

private Platform() {}

private static Platform detectOperatingSystem() {
public static Platform detectOperatingSystem() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want to make this a compilation constant during NI build time, so I suggest:

Suggested change
public static Platform detectOperatingSystem() {
private static Platform detectOperatingSystem() {

and rather make OPERATING_SYSTEM publicly visible. Possibly rename the field. Maybe CURRENT?


/** Provides information about user directories. */
public sealed interface Directories permits LinuxDirectories, MacOsDirectories, WindowsDirectories {
static Directories getForCurrentPlatform() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we may also benefit from CURRENT being a compilation constant during NI build time. Make it a field:

Suggested change
static Directories getForCurrentPlatform() {
public static final Directories CURRENT = switch (...) {}


private LinuxDirectories() {}

static LinuxDirectories getInstance() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lazy initialization makes no sense. Either:

private static final LinuxDirectories INSTANCE = new LinuxDirectories()

or just new LinuxDirectories() in the CURRENT = switch.

private static final String XDG_DATA_HOME = "XDG_DATA_HOME";
private static final String PATH_TRASH = "Trash";
private static final String PATH_FILES = "files";
private static final String PATH_INFO = "info";

private final LinuxDirectories directories = new LinuxDirectories();
public static LinuxTrashBin getInstance() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least encapsulate:

Suggested change
public static LinuxTrashBin getInstance() {
static LinuxTrashBin getInstance() {

but probably do way more. I really don't think this lazy initialization pattern is good for anything!

@@ -4,6 +4,16 @@
import java.nio.file.Path;

final class MacOsDirectories implements Directories {
private static MacOsDirectories instance;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


/** Operations with system trash */
public sealed interface TrashBin permits LinuxTrashBin, WindowsTrashBin, MacTrashBin {
static TrashBin getForCurrentPlatform() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make public static final field.

@Akirathan
Copy link
Member Author

Akirathan commented Mar 31, 2025

I attempted to implement and test working directory changing in repo https://github.com/Akirathan/chdir-native. Linux part is OK, but Windows tests on GH hosted runners were still failing. Last fail is in https://github.com/Akirathan/chdir-native/actions/runs/14173427574/job/39702423890#step:6:1876. Failing in linker. I think this is an issue with how I set up the Windows environment in those jobs. I will continue the work here.

GitHub
Does java.io in NI respect cwd? Contribute to Akirathan/chdir-native development by creating an account on GitHub.
GitHub
Does java.io in NI respect cwd? Contribute to Akirathan/chdir-native development by creating an account on GitHub.

@Akirathan
Copy link
Member Author

On fe862e1, we can run sbt:change-directory/test which builds NativeImage and runs TestRunner in native image. The native image is lightweight, the build on my machine takes just 18 seconds. If we want to have some unit test for this feature, this is the easiest and proper way to do that - refactor it into a separate project, and build test NativeImage.

The test passes for Linux at the moment, I will add more platforms.

In the future, we can implement our own junit-platform-native inspired by graalvm/native-build-tools/junit-platform-native.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: No changelog needed Do not require a changelog entry for this PR.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fix CWD before executing libraries code
3 participants