Skip to content
Open
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 @@ -72,6 +72,7 @@
import org.openide.windows.OutputWriter;

import static org.netbeans.lib.terminalemulator.Term.ExternalCommandsConstants.*;
import org.netbeans.modules.nativeexecution.api.util.MacroMap;

/**
*
Expand Down Expand Up @@ -267,14 +268,14 @@ private void doWork() {
term.setEmulation("xterm"); // NOI18N

NativeProcessBuilder npb = NativeProcessBuilder.newProcessBuilder(env);
final MacroMap envVars = npb.getEnvironment();
// clear env modified by NB. Let it be initialized by started shell process
npb.getEnvironment().put("LD_LIBRARY_PATH", "");// NOI18N
npb.getEnvironment().put("DYLD_LIBRARY_PATH", "");// NOI18N

envVars.put("LD_LIBRARY_PATH", "");// NOI18N
envVars.put("DYLD_LIBRARY_PATH", "");// NOI18N
Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • it was always clear to me I need to set an environment variable to represent the value of --userdir
  • otherwise the CLIHandler won't be able to connect to the same NetBeans process
  • originally I thought I will have to make changes here, but ...

if (hostInfo.getOSFamily() == HostInfo.OSFamily.WINDOWS) {
// /etc/profile changes directory to ${HOME} if this
// variable is not set.
npb.getEnvironment().put("CHERE_INVOKING", "1");// NOI18N
envVars.put("CHERE_INVOKING", "1");// NOI18N
}

final TerminalPinSupport support = TerminalPinSupport.getDefault();
Expand Down Expand Up @@ -305,8 +306,8 @@ private void doWork() {
final String promptCommand = "printf \"\033]3;${PWD}\007\"; " // NOI18N
+ IDE_OPEN + "() { printf \"\033]10;" + COMMAND_PREFIX + IDE_OPEN + " $*;\007\"; printf \"Opening $# file(s) ...\n\";}"; // NOI18N
final String commandName = "PROMPT_COMMAND"; // NOI18N
String usrPrompt = npb.getEnvironment().get(commandName);
npb.getEnvironment().put(commandName,
String usrPrompt = envVars.get(commandName);
envVars.put(commandName,
(usrPrompt == null)
? promptCommand
: promptCommand + ';' + usrPrompt
Expand Down
21 changes: 19 additions & 2 deletions nb/ide.launcher/unix/netbeans
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,18 @@ cd "$progdir"/..
basedir=`pwd`
cd "$old"

case "`uname`" in
case "`uname -s -m`" in
Darwin*)
# set default userdir and cachedir on Mac OS X
DEFAULT_USERDIR_ROOT="${HOME}/Library/Application Support/NetBeans"
DEFAULT_CACHEDIR_ROOT=${HOME}/Library/Caches/NetBeans
;;
CYGWIN*_64)
exec "$progdir/netbeans64.exe" $*
;;
CYGWIN*)
exec "$progdir/netbeans.exe" $*
;;
*)
# set default userdir and cachedir on unix systems
DEFAULT_USERDIR_ROOT=${HOME}/.netbeans
Expand All @@ -65,8 +71,17 @@ fi

export DEFAULT_USERDIR_ROOT

if ! [ "$NETBEANS_USERDIR" = "IGNORE" ]; then
# make sure own launcher directory is on PATH as a fallback
PATH=$PATH:$progdir
fi

# #68373: look for userdir, but do not modify "$@"
userdir="${netbeans_default_userdir}"
if [ -z "$NETBEANS_USERDIR" ]; then
userdir="${netbeans_default_userdir}"
else
userdir="$NETBEANS_USERDIR"
fi
cachedir="${netbeans_default_cachedir}"

founduserdir=""
Expand Down Expand Up @@ -138,6 +153,8 @@ launchNbexec() {
then
sh=/bin/bash
fi
NETBEANS_USERDIR=${userdir}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • Store the value of --userdir to a system variable
  • so that child processes can pick it up

export NETBEANS_USERDIR
if [ "${founduserdir}" = "yes" ]; then
exec $sh "$nbexec" "$@"
else
Expand Down
34 changes: 30 additions & 4 deletions nb/ide.launcher/windows/nblauncher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
using namespace std;

const char *NbLauncher::NBEXEC_FILE_PATH = NBEXEC_DLL;
const char *ENV_NETBEANS_USERDIR="NETBEANS_USERDIR";
const char *NbLauncher::OPT_NB_DEFAULT_USER_DIR = "netbeans_default_userdir=";
const char *NbLauncher::OPT_NB_DEFAULT_CACHE_DIR = "netbeans_default_cachedir=";
const char *NbLauncher::OPT_NB_DEFAULT_OPTIONS = "netbeans_default_options=";
Expand Down Expand Up @@ -82,13 +83,26 @@ int NbLauncher::start(int argc, char *argv[]) {
return -1;
}

parseConfigFile((baseDir + "\\etc\\" + getAppName() + ".conf").c_str());
bool skipUserDir = false;
char *userDirViaEnv = getenv(ENV_NETBEANS_USERDIR);
if (userDirViaEnv != NULL) {
logMsg("NbLauncher::using NETBEANS_USERDIR env variable (%s)", userDirViaEnv);
string udve = userDirViaEnv;
if (udve == "IGNORE") {
skipUserDir = true;
userDirViaEnv = NULL;
} else {
userDir = userDirViaEnv;
}
}

parseConfigFile((baseDir + "\\etc\\" + getAppName() + ".conf").c_str(), userDirViaEnv == NULL);

if (!parseArgs(argc, argv)) {
return -1;
}
string oldUserDir = userDir;
parseConfigFile((userDir + "\\etc\\" + getAppName() + ".conf").c_str());
parseConfigFile((userDir + "\\etc\\" + getAppName() + ".conf").c_str(), userDirViaEnv == NULL);
userDir = oldUserDir;

addExtraClusters();
Expand All @@ -114,6 +128,18 @@ int NbLauncher::start(int argc, char *argv[]) {
if (!userDir.empty()) {
newArgs.add(ARG_NAME_USER_DIR);
newArgs.add(userDir.c_str());
if (!skipUserDir) {
string toSet = ENV_NETBEANS_USERDIR;
toSet = toSet + "=" + userDir;
putenv(toSet.c_str());

const char* path = getenv("PATH");
if (path != NULL) {
string setPath = "PATH=";
setPath = setPath + path + ";" + baseDir + "\\bin\\";
putenv(setPath.c_str());
Copy link
Contributor Author

@jtulach jtulach Sep 14, 2025

Choose a reason for hiding this comment

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

I tested these changes with following program:

package execenv;

public class ExecEnv {
    public static void main(String[] args) throws Exception {
        System.out.println("Env: " + System.getenv("PATH"));
        var p = new ProcessBuilder("netbeans", "S:\\readme.txt").start();
        var r = p.waitFor();
        System.out.println("Res: " + r);
    }
}

when executed on NetBeans 27 it fails with:

run:
Env: C:\Program Files\OpenSSH\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Git\cmd;C:\Users\jst\AppData\Local\nvm;C:\nvm4w\nodejs;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\;C:\Users\jst\.cargo\bin;C:\Users\jst\AppData\Local\Microsoft\WindowsApps;C:\Users\jst\AppData\Local\nvm;C:\nvm4w\nodejs;C:\Program Files\Git\bin;S:\windows\bin;S:\windows\bin\graalvm-community-openjdk-24.0.1+9.1\bin\;S:\windows\bin\sbt-1.7.2\bin\;
Exception in thread "main" java.io.IOException: Cannot run program "netbeans": CreateProcess error=2, The system cannot find the file specified
	at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1110)
	at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1044)
	at execenv.ExecEnv.main(ExecEnv.java:6)
Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specified
	at java.base/java.lang.ProcessImpl.create(Native Method)
	at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:485)
	at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:146)
	at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1076)
	... 2 more
C:\Users\jst\AppData\Local\NetBeans\Cache\27\executor-snippets\run.xml:111: The following error occurred while executing this line:
C:\Users\jst\AppData\Local\NetBeans\Cache\27\executor-snippets\run.xml:68: Java returned: 1
BUILD FAILED (total time: 1 second)

With changes in this PR it properly opens the file in the IDE executing the script. Setting NETBEANS_USERDIR=IGNORE opts-out and falls back to previous behavior.

}
}
}
if (!defUserDirRoot.empty()) {
newArgs.add(ARG_DEFAULT_USER_DIR_ROOT);
Expand Down Expand Up @@ -460,7 +486,7 @@ bool NbLauncher::getOption(char *&str, const char *opt) {
return false;
}

bool NbLauncher::parseConfigFile(const char* path) {
bool NbLauncher::parseConfigFile(const char* path, const bool searchUserDir) {
logMsg("parseConfigFile(%s)", path);
FILE *file = fopen(path, "r");
if (!file) {
Expand All @@ -474,7 +500,7 @@ bool NbLauncher::parseConfigFile(const char* path) {
if (*str == '#') {
continue;
}
if (getOption(str, getDefUserDirOptName())) {
if (searchUserDir && getOption(str, getDefUserDirOptName())) {
findUserDir(str);
logMsg("User dir: %s", userDir.c_str());
} else if (getOption(str, getDefCacheDirOptName())) {
Expand Down
2 changes: 1 addition & 1 deletion nb/ide.launcher/windows/nblauncher.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class NbLauncher {
NbLauncher(const NbLauncher& orig);
bool readClusterFile();
bool parseArgs(int argc, char *argv[]);
bool parseConfigFile(const char* path);
bool parseConfigFile(const char* path, const bool searchUserDir);
bool getOption(char *&str, const char *opt);
void addCluster(const char *cl);
void addExtraClusters();
Expand Down
2 changes: 1 addition & 1 deletion nb/ide.launcher/windows/netbeans.exe.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

-->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="101.3.0.0"
<assemblyIdentity version="101.4.0.0"
processorArchitecture="x86"
name="netbeans.exe"
type="win32"/>
Expand Down
2 changes: 1 addition & 1 deletion nb/ide.launcher/windows/netbeans64.exe.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<!-- Use processorArchitecture="x86", which is the value used by the 64-bit
javaw.exe on Java 10.0.2 and Java 11ea. -->
<assemblyIdentity version="101.3.0.0"
<assemblyIdentity version="101.4.0.0"
processorArchitecture="x86"
name="netbeans64.exe"
type="win32"/>
Expand Down
6 changes: 3 additions & 3 deletions nb/ide.launcher/windows/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

#define COMPANY ""
#define COMPONENT "Apache NetBeans IDE Launcher"
#define VER "101.3.0.0"
#define FVER 101,3,0,0
#define BUILD_ID "101300"
#define VER "101.4.0.0"
#define FVER 101,4,0,0
#define BUILD_ID "101400"
#define INTERNAL_NAME "netbeans"
#define COPYRIGHT "Based on Apache NetBeans from the Apache Software Foundation and is licensed under Apache License Version 2.0"
#define NAME "Apache NetBeans IDE Launcher"
Expand Down
37 changes: 37 additions & 0 deletions nb/o.n.upgrader/arch.xml
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,43 @@
clusters' fully qualified paths separated by path.separator (semicolon on Windows, colon on Unices)
</api></li>
</ul>
<p>
When the <code>netbeans</code> launcher starts, it also manipulates
(reads and writes) following properties:
</p>
<ul>
<li><api name="NETBEANS_USERDIR" category="devel" group="property" type="export">
<p>
If this <em>environment variable</em> is set to a valid value,
then its value is used as default user dir
instead of <code>netbeans_default_userdir</code> read from
the config file.
</p>
<p>
When the value of user dir is finally determined by the launcher
(by considering default values, value of this environment variable
and <code>--userdir</code> CLI switch, etc.) the launcher sets
<code>NETBEANS_USERDIR</code> environment variable for itself
and its subprocesses.
</p>
<p>
That way executing <code>netbeans</code> in the NetBeans internal
terminal will know what's the userdir of the surrouding NetBeans
and will open files in the same instance just as
<a href="https://github.com/apache/netbeans/pull/8756">#8756 illustrates</a>.
</p>
<p>
The launcher also modifies the <code>PATH</code> variable
by appending its own diretory - making sure typing <code>netbeans</code>
gets handled in the internal NetBeans terminal at all.
In the unusual and rare cases when <b>opt-out</b> of this
behavior maybe needed, just
set the environment variable to <code>IGNORE</code> to instruct
the launcher to avoid these environment variable modifications.
</p>
</api>
</li>
</ul>
</answer>


Expand Down
Loading