final @NotNull <T extends GeneralCommandLine> T doPatchCommandLine(@NotNull T commandLine,
                                                                     @Nullable Project project,
                                                                     @NotNull WSLCommandLineOptions options) throws ExecutionException {
    logCommandLineBefore(commandLine, options);
    Path executable = getExecutablePath();
    boolean launchWithWslExe = options.isLaunchWithWslExe() || executable == null;
    Path wslExe = launchWithWslExe ? findWslExe() : null;
    if (wslExe == null && executable == null) {
      throw new ExecutionException(IdeBundle.message("wsl.not.installed.dialog.message"));
    }
    boolean executeCommandInShell = wslExe == null || options.isExecuteCommandInShell();
    List<String> linuxCommand = buildLinuxCommand(commandLine, executeCommandInShell);

    final boolean isElevated = options.isSudo();
    // use old approach in case of wsl.exe is not available
    if (isElevated && wslExe == null) { // fixme shouldn't we sudo for every chunk? also, preserve-env, login?
      prependCommand(linuxCommand, "sudo", "-S", "-p", "''");
      //TODO[traff]: ask password only if it is needed. When user is logged as root, password isn't asked.

      SUDO_LISTENER_KEY.set(commandLine, new ProcessAdapter() {
        @Override
        public void startNotified(@NotNull ProcessEvent event) {
          OutputStream input = event.getProcessHandler().getProcessInput();
          if (input == null) {
            return;
          }
          String password = CredentialPromptDialog.askPassword(
            project,
            IdeBundle.message("wsl.enter.root.password.dialog.title"),
            IdeBundle.message("wsl.sudo.password.for.root.label", getPresentableName()),
            new CredentialAttributes("WSL", "root"),
            true
          );
          if (password != null) {
            try (PrintWriter pw = new PrintWriter(input, false, commandLine.getCharset())) {
              pw.println(password);
            }
          }
          else {
            // fixme notify user?
          }
          super.startNotified(event);
        }
      });
    }

    if (executeCommandInShell && StringUtil.isNotEmpty(options.getRemoteWorkingDirectory())) {
      prependCommand(linuxCommand, "cd", CommandLineUtil.posixQuote(options.getRemoteWorkingDirectory()), "&&");
    }
    if (executeCommandInShell && !options.isPassEnvVarsUsingInterop()) {
      Comparator<Map.Entry<String, String>> comparator = Map.Entry.<String, String>comparingByKey().reversed();
      commandLine.getEnvironment().entrySet().stream().sorted(comparator).forEach((entry) -> {
        String key = entry.getKey();
        String val = entry.getValue();
        if (ENV_VARIABLE_NAME_PATTERN.matcher(key).matches()) {
          prependCommand(linuxCommand, "export", key + "=" + CommandLineUtil.posixQuote(val), "&&");
        }
        else {
          LOG.debug("Can not pass environment variable (bad name): '", key, "'");
        }
      });
      commandLine.getEnvironment().clear();
    }
    else {
      passEnvironmentUsingInterop(commandLine);
    }
    if (executeCommandInShell) {
      for (String command : options.getInitShellCommands()) {
        prependCommand(linuxCommand, command, "&&");
      }
    }

    commandLine.getParametersList().clearAll();
    String linuxCommandStr = StringUtil.join(linuxCommand, " ");
    if (wslExe != null) {
      commandLine.setExePath(wslExe.toString());
      commandLine.addParameters(DISTRIBUTION_PARAMETER, getMsId());
      if (isElevated) {
        commandLine.addParameters("-u", "root");
      }
      if (options.isExecuteCommandInShell()) {
        // workaround WSL1 problem: https://github.com/microsoft/WSL/issues/4082
        if (options.getSleepTimeoutSec() > 0 && getVersion() == 1) {
          linuxCommandStr += EXIT_CODE_PARAMETER + "; sleep " + options.getSleepTimeoutSec() + "; (exit $exitcode)";
        }

        if (options.isExecuteCommandInDefaultShell()) {
          fixTTYSize(commandLine);
          commandLine.addParameters(SHELL_PARAMETER, "-c", linuxCommandStr);
        }
        else {
          commandLine.addParameter(EXEC_PARAMETER);
          fixTTYSize(commandLine);
          commandLine.addParameter(getShellPath());
          if (options.isExecuteCommandInInteractiveShell()) {
            commandLine.addParameters("-i");
          }
          if (options.isExecuteCommandInLoginShell()) {
            commandLine.addParameters("-l");
          }
          commandLine.addParameters("-c", linuxCommandStr);
        }
      }
      else {
        commandLine.addParameter(EXEC_PARAMETER);
        commandLine.addParameters(linuxCommand);
      }
    }
    else {
      commandLine.setExePath(executable.toString());
      commandLine.addParameter(getRunCommandLineParameter());
      commandLine.addParameter(linuxCommandStr);
    }

    if (Registry.is("wsl.use.utf8.encoding", true)) {
      // Unlike the default system encoding on Windows (e.g. cp-1251),
      // UTF-8 is the default for most Linux distributions
      commandLine.setCharset(StandardCharsets.UTF_8);
    }

    logCommandLineAfter(commandLine);
    return commandLine;
  }
final @NotNull <T extends GeneralCommandLine> T doPatchCommandLine(@NotNull T commandLine,
                                                                     @Nullable Project project,
                                                                     @NotNull WSLCommandLineOptions options)