From 7b8d87c7a47d2625cf1e22404a188bf2cc1889b8 Mon Sep 17 00:00:00 2001 From: albilu <35330562+albilu@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:16:13 +0200 Subject: [PATCH 1/8] Fix Release 23 --- .github/workflows/maven.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 856d968..fece2b5 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -233,6 +233,7 @@ jobs: MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} MAVEN_GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} + GITHUB_TOKEN: ${{ github.token }} - name: Attach RELEASE210 NBM uses: actions/upload-release-asset@v1 @@ -252,6 +253,7 @@ jobs: MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} MAVEN_GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} + GITHUB_TOKEN: ${{ github.token }} - name: Attach RELEASE220 NBM uses: actions/upload-release-asset@v1 @@ -271,6 +273,7 @@ jobs: MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} MAVEN_GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} + GITHUB_TOKEN: ${{ github.token }} - name: Attach RELEASE230 NBM uses: actions/upload-release-asset@v1 From 32c13920951571fd6abe50d405d319644122bceb Mon Sep 17 00:00:00 2001 From: albilu <35330562+albilu@users.noreply.github.com> Date: Mon, 30 Sep 2024 15:40:26 +0200 Subject: [PATCH 2/8] Fix invalid path call in getVersion Fix python-lsp-isort state display in LSP server conf --- .../modules/python/PythonUtility.java | 1171 +++++++++-------- .../options/PythonLspServerConfigsPanel.java | 2 +- 2 files changed, 589 insertions(+), 584 deletions(-) diff --git a/src/main/java/org/netbeans/modules/python/PythonUtility.java b/src/main/java/org/netbeans/modules/python/PythonUtility.java index 08edf93..4f602b1 100644 --- a/src/main/java/org/netbeans/modules/python/PythonUtility.java +++ b/src/main/java/org/netbeans/modules/python/PythonUtility.java @@ -1,583 +1,588 @@ -package org.netbeans.modules.python; - -import com.electronwill.nightconfig.core.file.FileConfig; -import com.google.common.collect.Maps; -import java.awt.event.ActionEvent; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.prefs.Preferences; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.swing.ImageIcon; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.ArrayUtils; -import org.json.JSONObject; -import org.netbeans.api.annotations.common.NonNull; -import org.netbeans.api.extexecution.ExecutionDescriptor; -import org.netbeans.api.extexecution.ExecutionService; -import org.netbeans.api.extexecution.print.LineConvertor; -import org.netbeans.api.extexecution.print.LineConvertors; -import org.netbeans.api.project.FileOwnerQuery; -import org.netbeans.api.project.Project; -import org.netbeans.api.project.ui.OpenProjects; -import org.netbeans.modules.python.options.PythonPlatformManager; -import static org.netbeans.modules.python.options.PythonPlatformManager.getPathFile; -import org.netbeans.modules.python.project.PythonProject; -import org.openide.awt.NotificationDisplayer; -import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileUtil; -import org.openide.util.Exceptions; -import org.openide.util.ImageUtilities; -import org.openide.util.NbBundle; -import org.openide.util.NbPreferences; -import org.openide.util.Pair; -import org.openide.util.RequestProcessor; -import org.openide.util.Utilities; - -/** - * - * @author albilu - */ -public class PythonUtility { - - public static final Logger LOG = Logger.getLogger(PythonUtility.class.getName()); - - public static final RequestProcessor RP = new RequestProcessor("Retry RP", 2); - public static final String PYTHON_MIME_TYPE = "text/x-python"; - public static final File PYLSP_VENV_DIR = Paths.get(System.getProperty("netbeans.user")).resolve(".pythonlsp").toFile(); - - public static final Pattern HOME_PAGE = Pattern.compile(".*Home-page:\\s+(.*)"); - public static final Pattern PAC_VERSIONS = Pattern.compile(".*Available versions:\\s+(.*)"); - public static final Pattern NO_MODULE_PATTERN = Pattern.compile("(.*):\\s+No module named\\s([a-z-]+)"); - public static final Pattern POETRY_PYTHON_PATH = Pattern.compile("(.*)\\s+\\(Activated\\)"); - static final Pattern PYTHON_STACKTRACE_PATTERN = Pattern.compile("^ File \"(.+\\.py)\", line (\\d+).*"); - - public static final LineConvertor HTTP_CONVERTOR = LineConvertors.httpUrl(); - - public static LineConvertors.FileLocator FILE_LOCATOR = (String filename) -> { - FileObject toFileObject = FileUtil.toFileObject(new File(filename.replaceAll("\"", "") - .strip())); - return toFileObject != null ? toFileObject : null; - }; - - public static LineConvertor FILE_CONVERTOR = LineConvertors.filePattern(FILE_LOCATOR, - PYTHON_STACKTRACE_PATTERN, - null, 1, 2); - - public static final String[] IMPORTANT_FILES = { - "Dockerfile", - "Jenkinsfile", - "LICENSE", - "md", - "setup.py", - "pyproject.toml" - }; - - public static String[] EXCLUDED_DIRS = new String[]{ - ".venv", - "venv", - "build", - "dist", - "nbproject", - "py_tests", - "pynguin-report", - "pycache", - ".ropeproject", - "__pycache__", - "poetry.lock", - ".coverage.json" - }; - - public static String[] VENV_DEPS = new String[]{ - "pytest", - "pynguin", - "build" - }; - - public static String[] LSP_DEPS = new String[]{ - "python-lsp-server[all]", - "python-lsp-isort", - "pylsp-mypy", - "pylsp-rope", - "black", - "python-lsp-black", - "isort", - "pyls-memestra", - "ptpython", - "ipython", - "pytest", - //"pynguin", - "build", - "pdoc", - "poetry" - }; - - public static final File SETTINGS = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("settings.json").toFile(); - public static final File SETTINGS_SCHEMA = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("schema.json").toFile(); - public static final File REPOS = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("repos.json").toFile(); - public static final File PLATFORMS = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("platforms.json").toFile(); - public static final File ENVS = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("envs.json").toFile(); - public static final File TEST_RUNNER = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("nb_test_runner.py").toFile(); - public static final File TOML_HANDLER = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("toml_handler.py").toFile(); - - public static Preferences TERMINAL_PREFS = NbPreferences.root() - .node("org/netbeans/modules/terminal/nb"); - - public static int getTermFontSize() { - return TERMINAL_PREFS.getInt("term.fontSize", 18); - } - - public static int geTermFontSt() { - return TERMINAL_PREFS.getInt("term.fontStyle", 0); - } - - public static String getTermFontFam() { - return TERMINAL_PREFS.get("term.fontFamily", "DejaVu Sans Mono"); - } - - public static String getServerVersion() throws IOException { - String commandOutput = getCommandOutput(new String[]{getLspPythonExe(), "-m", "pylsp", "--version"}, null); - if (!commandOutput.startsWith("__main__.py")) { - LOG.log(Level.SEVERE, commandOutput); - return "UNKNOW"; - } - return commandOutput; - - } - - public static String getCommandOutput(String[] cmd, FileObject projectDir) throws IOException { - ProcessBuilder p = new ProcessBuilder(cmd); - if (projectDir != null) { - p.directory(FileUtil.toFile(projectDir)); - } - return IOUtils.toString(p.redirectErrorStream(true).start().getInputStream(), - StandardCharsets.UTF_8).strip(); - } - - public static String getPythonStdLibPath(String path) throws IOException { - return getCommandOutput(new String[]{path, "-c", - "import sysconfig; print(sysconfig.get_paths()['stdlib'])"}, null); - - } - - public static String getLspPythonExe() { - return normalizeVenvPath(PYLSP_VENV_DIR.toPath()); - } - - public static String getProjectPythonExe(FileObject fileObject) - throws IOException { - if (fileObject != null) { - Project owner = FileOwnerQuery.getOwner(fileObject); - if (owner != null) { - FileObject fileObject1 = owner.getProjectDirectory() - .getFileObject("nbproject/project.properties"); - if (fileObject1 != null) { - File toFile = FileUtil.toFile(fileObject1); - Properties appProps = new Properties(); - if (toFile != null) { - appProps.load(new FileInputStream(toFile)); - String property = appProps.getProperty("nbproject.python_path"); - return (property == null || property.isBlank()) - ? (PythonUtility.isPoetry((PythonProject) owner) - /**/ ? PythonUtility.getPoetryPythonPath(PythonUtility.getLspPythonExe(), - owner.getProjectDirectory()) : getPlatformPythonExe()) - : /*appProps.getProperty("nbproject.python_path")*/ property; - } - } - } - } - return getPlatformPythonExe(); - } - - public static List> getPythonExes() throws IOException { - List> versions = new ArrayList<>(); - for (String python : new String[]{"python", "python3", "py"}) { - getCommandOutput(new String[]{Utilities.isWindows() - ? "where" : "which", python}, null).lines().forEach(exe -> { - try { - String striped = exe.strip(); - if (isValidFilePath(striped)) { - String vers = getVersion(striped); - if (!vers.isEmpty()) { - versions.add(Pair.of(vers, striped)); - } - } - } catch (Exception ex) { - Exceptions.printStackTrace(ex); - } - }); - - } - - return versions; - } - - private static boolean isValidFilePath(String filePath) { - try { - // Attempt to create a Path object from the provided string - Path path = Paths.get(filePath); - - // Check if the path is absolute and exists - return path.isAbsolute() && path.toFile().exists() && Files.isExecutable(path); - } catch (Exception e) { - // An exception was thrown when parsing the path - return false; - } - } - - public static String[] getOsShell() { - if (Utilities.isWindows()) { - return new String[]{"cmd.exe", "/c"}; - } else if (Utilities.isMac() || Utilities.isUnix()) { - return new String[]{getEnvs().getOrDefault("SHELL", "/bin/bash"), "-c"}; - } - return null; - } - - public static Map getEnvs() { - Map envs = Maps.newHashMap(System.getenv()); - return envs; - } - - public static String getPlatformPythonExe() throws IOException { - return PythonPlatformManager.getDefault(); - } - - public static ImageIcon getPythonIcon() { - return ImageUtilities.loadImageIcon("org/netbeans/modules/python/python-2.png", false); - - } - - public static ImageIcon getClassIcon() { - return ImageUtilities.loadImageIcon("org/netbeans/modules/python/Classes.png", false); - - } - - public static ImageIcon getMethodIcon() { - return ImageUtilities.loadImageIcon("org/netbeans/modules/python/methodPublic.png", false); - - } - - public static ImageIcon getPytestIcon() { - return ImageUtilities.loadImageIcon("org/netbeans/modules/python/pytest.png", false); - - } - - public static ImageIcon getPackageIcon() { - return ImageUtilities.loadImageIcon("org/netbeans/modules/python/package16.png", false); - - } - - public static ImageIcon getPynguinIcon() { - return ImageUtilities.loadImageIcon("org/netbeans/modules/python/pynguin.png", false); - - } - - public static Properties getProperties(@NonNull Project project, boolean isCreating) throws IOException { - - Properties prop = new Properties(); - if (OpenProjects.getDefault().isProjectOpen(project) || isCreating) { - File file = createProperties(project); - prop.load(new FileInputStream(file)); - } - return prop; - - } - - public static String getVersion(String projectPythonExe) throws IOException { - String commandOutput = getCommandOutput(new String[]{projectPythonExe, "--version"}, null); - if (!commandOutput.startsWith("Py")) { - LOG.log(Level.SEVERE, commandOutput); - return ""; - } - return commandOutput; - } - - public static ImageIcon getErrorIcon() { - return ImageUtilities.loadImageIcon("org/netbeans/modules/python/error-badge.png", false); - - } - - public static ImageIcon getPythonPackageIcon() { - return ImageUtilities.loadImageIcon("org/netbeans/modules/python/libraries.png", false); - - } - - public static int venvPackageInstaller(FileObject projectDirectory) { - String[] cmd = { - normalizeVenvPath(FileUtil.toFile(projectDirectory).toPath()), - "-m", - "pip", - "install" - }; - return processExecutor(ArrayUtils.addAll(cmd, VENV_DEPS), "Installing packages"); - } - - public static String normalizeVenvPath(Path base) { - return Utilities.isWindows() ? base.resolve(".venv\\Scripts\\python.exe").toString() - : base.resolve(".venv/bin/python").toString(); - - } - - @NbBundle.Messages("CTL_Install=Installing packages") - public static void packageInstaller(String errorLline) { - Matcher matcher = NO_MODULE_PATTERN.matcher(errorLline); - while (matcher.find()) { - String[] cmd = { - matcher.group(1), - "-m", - "pip", - "install", - matcher.group(2) - }; - - processExecutor(cmd, Bundle.CTL_Install()); - } - } - - public static int processExecutor(String[] cmd, String message) { - try { - ProcessBuilder pb = new ProcessBuilder(); - pb.command(cmd); - LOG.info(() -> Arrays.toString(cmd)); - - ExecutionDescriptor execDescriptor = new ExecutionDescriptor() - .frontWindowOnError(true) - .showProgress(true) - .outConvertorFactory(new PythonOutputLine()) - .errConvertorFactory(new PythonOutputLine()); - - ExecutionService service = ExecutionService - .newService(() -> pb.start(), execDescriptor, message); - - int waitFor = service.run().get(); - - return waitFor; - } catch (InterruptedException | ExecutionException ex) { - Exceptions.printStackTrace(ex); - } - return 1; - } - - @NbBundle.Messages({ - "CTL_CreatePylsp=Creating pylsp environment", - "CTL_PylspInstallIssue=Issue when creating Pylsp environment.", - "CTL_PylspRetry=Retry" - }) - public static int installLsp(ClassLoader cl) { - try { - if (!PythonUtility.PYLSP_VENV_DIR.exists()) { - PythonUtility.PYLSP_VENV_DIR.mkdir(); - Files.writeString(SETTINGS.toPath(), - IOUtils.resourceToString("org/netbeans/modules/python/settings.json", - StandardCharsets.UTF_8, cl) - ); - Files.writeString(SETTINGS_SCHEMA.toPath(), - IOUtils.resourceToString("org/netbeans/modules/python/schema.json", - StandardCharsets.UTF_8, cl) - ); - Files.writeString(REPOS.toPath(), - IOUtils.resourceToString("org/netbeans/modules/python/repos.json", - StandardCharsets.UTF_8, cl) - ); - Files.writeString(PLATFORMS.toPath(), - IOUtils.resourceToString("org/netbeans/modules/python/platforms.json", - StandardCharsets.UTF_8, cl) - ); - Files.writeString(ENVS.toPath(), - IOUtils.resourceToString("org/netbeans/modules/python/envs.json", - StandardCharsets.UTF_8, cl) - ); - Files.writeString(TEST_RUNNER.toPath(), - IOUtils.resourceToString("org/netbeans/modules/python/nb_test_runner.py", - StandardCharsets.UTF_8, cl) - ); - Files.writeString(TOML_HANDLER.toPath(), - IOUtils.resourceToString("org/netbeans/modules/python/toml_handler.py", - StandardCharsets.UTF_8, cl) - ); - } - String[] cmd = { - PythonUtility.getPlatformPythonExe(), - "-m", - "venv", - PythonUtility.PYLSP_VENV_DIR.toPath().resolve(".venv").toString() - }; - - int processExecutor = PythonUtility.processExecutor(cmd, Bundle.CTL_CreatePylsp()); - if (processExecutor != 0) { - - NotificationDisplayer.getDefault().notify(Bundle.CTL_PylspInstallIssue(), - PythonUtility.getErrorIcon(), - Bundle.CTL_PylspRetry(), - (ActionEvent e) -> { - RP.post(() -> { - PythonUtility.processExecutor(cmd, Bundle.CTL_CreatePylsp()); - finish(); - }); - }, - NotificationDisplayer.Priority.HIGH, - NotificationDisplayer.Category.ERROR); - } - - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - - return finish(); - } - - public static String getPipList(String exe) throws IOException { - return getCommandOutput(new String[]{exe, "-m", "pip", "list"}, null); - } - - @NbBundle.Messages({ - "CTL_InstallDeps=Installing pylsp dependencies", - "CTL_MissingDeps=Missing dependency:" - }) - public static int finish() { - String[] cmd = {PythonUtility.getLspPythonExe(), "-m", "pip", "install", "--upgrade"}; - return processExecutor(ArrayUtils.addAll(cmd, LSP_DEPS), Bundle.CTL_InstallDeps()); - } - - public static void noModuleInstalledHandler(String line) { - Matcher matcher = PythonUtility.NO_MODULE_PATTERN.matcher(line); - if (matcher.find()) { - String pyPackage = matcher.group(2); - NotificationDisplayer.getDefault().notify(String.format("%s %s", Bundle.CTL_MissingDeps(), pyPackage), - PythonUtility.getPythonPackageIcon(), - String.format("Install %s", pyPackage), - (ActionEvent e) -> { - RP.post(() -> { - PythonUtility.packageInstaller(line); - }); - }, - NotificationDisplayer.Priority.NORMAL, - NotificationDisplayer.Category.WARNING); - } - } - - public static Map getUserEnvs() throws IOException { - File envsFile = PythonPlatformManager.getPathFile(); - JSONObject jsonObject = new JSONObject(Files.readString(envsFile.toPath())); - return jsonObject.toMap(); - } - - public static void insertUserEnvs(String toString) { - try { - Files.writeString(getPathFile().toPath(), toString); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - } - - public static ExecutionDescriptor getExecutorDescriptor(ExecutionDescriptor.LineConvertorFactory convertorFactory, - Runnable preExeRunnable, Runnable postRunnable, boolean controllable, boolean select) { - ExecutionDescriptor execDescriptor = new ExecutionDescriptor() - .frontWindow(select) - .frontWindowOnError(select) - .controllable(controllable) - .showProgress(true) - .inputVisible(true) - .outConvertorFactory(convertorFactory) - .errConvertorFactory(convertorFactory) - .preExecution(preExeRunnable) - .postExecution(postRunnable); - - return execDescriptor; - } - - public static boolean isRunWithSysEnvs() { - return NbPreferences.root().getBoolean("sysEnv", true); - } - - public static void manageRunEnvs(ProcessBuilder pb) { - try { - Map environment = pb.environment(); - if (!PythonUtility.isRunWithSysEnvs()) { - environment.clear(); - } - Map userEnvs = getUserEnvs(); - environment.putAll(userEnvs); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - - } - - public static String getVenv(PythonProject get) { - try { - return getProperties(get, false).getProperty("nbproject.virtualmanager", "venv"); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - return "venv"; - } - - public static String getProjectType(File toFile) { - try (FileConfig conf = FileConfig.of(toFile)) { - conf.load(); - Object get = conf.get("tool.poetry"); - return get == null ? PythonProject.PYTHON : PythonProject.POETRY; - } - } - - public static boolean isPoetry(PythonProject project) { - FileObject fileObject = project.getProjectDirectory().getFileObject("pyproject.toml"); - - return (fileObject != null && PythonUtility.getProjectType(FileUtil.toFile(fileObject)) - .equals(PythonProject.POETRY)) || project.getProjectDirectory().getFileObject("poetry.lock") != null; - - } - - public static String getPoetryPythonPath(String defaultPython, FileObject projectDir) { - try { - String[] cmd = {defaultPython, "-m", "poetry", "env", "list", "--full-path"}; - - Matcher matcher = PythonUtility.POETRY_PYTHON_PATH.matcher(PythonUtility.getCommandOutput(cmd, projectDir)); - if (matcher.find()) { - String endPath; - if (Utilities.isWindows()) { - endPath = "\\Scripts\\python.exe"; - } else { - endPath = "/bin/python"; - } - return String.format("%s%s", matcher.group(1), endPath); - } - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - return defaultPython; - } - - public static File createProperties(Project project) { - File toFile = Paths.get(project.getProjectDirectory().getPath()) - .resolve("nbproject").resolve("project.properties").toFile(); - if (!toFile.exists()) { - try { - FileUtils.createParentDirectories(toFile); - toFile.createNewFile(); - return toFile; - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - - } - return toFile; - } - -} +package org.netbeans.modules.python; + +import com.electronwill.nightconfig.core.file.FileConfig; +import com.google.common.collect.Maps; +import java.awt.event.ActionEvent; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.prefs.Preferences; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.swing.ImageIcon; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.json.JSONObject; +import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.extexecution.ExecutionDescriptor; +import org.netbeans.api.extexecution.ExecutionService; +import org.netbeans.api.extexecution.print.LineConvertor; +import org.netbeans.api.extexecution.print.LineConvertors; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ui.OpenProjects; +import org.netbeans.modules.python.options.PythonPlatformManager; +import static org.netbeans.modules.python.options.PythonPlatformManager.getPathFile; +import org.netbeans.modules.python.project.PythonProject; +import org.openide.awt.NotificationDisplayer; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.Exceptions; +import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle; +import org.openide.util.NbPreferences; +import org.openide.util.Pair; +import org.openide.util.RequestProcessor; +import org.openide.util.Utilities; + +/** + * + * @author albilu + */ +public class PythonUtility { + + public static final Logger LOG = Logger.getLogger(PythonUtility.class.getName()); + + public static final RequestProcessor RP = new RequestProcessor("Retry RP", 2); + public static final String PYTHON_MIME_TYPE = "text/x-python"; + public static final File PYLSP_VENV_DIR = Paths.get(System.getProperty("netbeans.user")).resolve(".pythonlsp").toFile(); + + public static final Pattern HOME_PAGE = Pattern.compile(".*Home-page:\\s+(.*)"); + public static final Pattern PAC_VERSIONS = Pattern.compile(".*Available versions:\\s+(.*)"); + public static final Pattern NO_MODULE_PATTERN = Pattern.compile("(.*):\\s+No module named\\s([a-z-]+)"); + public static final Pattern POETRY_PYTHON_PATH = Pattern.compile("(.*)\\s+\\(Activated\\)"); + static final Pattern PYTHON_STACKTRACE_PATTERN = Pattern.compile("^ File \"(.+\\.py)\", line (\\d+).*"); + + public static final LineConvertor HTTP_CONVERTOR = LineConvertors.httpUrl(); + + public static LineConvertors.FileLocator FILE_LOCATOR = (String filename) -> { + FileObject toFileObject = FileUtil.toFileObject(new File(filename.replaceAll("\"", "") + .strip())); + return toFileObject != null ? toFileObject : null; + }; + + public static LineConvertor FILE_CONVERTOR = LineConvertors.filePattern(FILE_LOCATOR, + PYTHON_STACKTRACE_PATTERN, + null, 1, 2); + + public static final String[] IMPORTANT_FILES = { + "Dockerfile", + "Jenkinsfile", + "LICENSE", + "md", + "setup.py", + "pyproject.toml" + }; + + public static String[] EXCLUDED_DIRS = new String[]{ + ".venv", + "venv", + "build", + "dist", + "nbproject", + "py_tests", + "pynguin-report", + "pycache", + ".ropeproject", + "__pycache__", + "poetry.lock", + ".coverage.json" + }; + + public static String[] VENV_DEPS = new String[]{ + "pytest", + "pynguin", + "build" + }; + + public static String[] LSP_DEPS = new String[]{ + "python-lsp-server[all]", + "python-lsp-isort", + "pylsp-mypy", + "pylsp-rope", + "black", + "python-lsp-black", + "isort", + "pyls-memestra", + "ptpython", + "ipython", + "pytest", + //"pynguin", + "build", + "pdoc", + "poetry" + }; + + public static final File SETTINGS = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("settings.json").toFile(); + public static final File SETTINGS_SCHEMA = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("schema.json").toFile(); + public static final File REPOS = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("repos.json").toFile(); + public static final File PLATFORMS = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("platforms.json").toFile(); + public static final File ENVS = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("envs.json").toFile(); + public static final File TEST_RUNNER = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("nb_test_runner.py").toFile(); + public static final File TOML_HANDLER = PythonUtility.PYLSP_VENV_DIR.toPath().resolve("toml_handler.py").toFile(); + + public static Preferences TERMINAL_PREFS = NbPreferences.root() + .node("org/netbeans/modules/terminal/nb"); + + public static int getTermFontSize() { + return TERMINAL_PREFS.getInt("term.fontSize", 18); + } + + public static int geTermFontSt() { + return TERMINAL_PREFS.getInt("term.fontStyle", 0); + } + + public static String getTermFontFam() { + return TERMINAL_PREFS.get("term.fontFamily", "DejaVu Sans Mono"); + } + + public static String getServerVersion() throws IOException { + String commandOutput = getCommandOutput(new String[]{getLspPythonExe(), "-m", "pylsp", "--version"}, null); + if (!commandOutput.startsWith("__main__.py")) { + LOG.log(Level.SEVERE, commandOutput); + return "UNKNOW"; + } + return commandOutput; + + } + + public static String getCommandOutput(String[] cmd, FileObject projectDir) throws IOException { + ProcessBuilder p = new ProcessBuilder(cmd); + if (projectDir != null) { + p.directory(FileUtil.toFile(projectDir)); + } + return IOUtils.toString(p.redirectErrorStream(true).start().getInputStream(), + StandardCharsets.UTF_8).strip(); + } + + public static String getPythonStdLibPath(String path) throws IOException { + return getCommandOutput(new String[]{path, "-c", + "import sysconfig; print(sysconfig.get_paths()['stdlib'])"}, null); + + } + + public static String getLspPythonExe() { + return normalizeVenvPath(PYLSP_VENV_DIR.toPath()); + } + + public static String getProjectPythonExe(FileObject fileObject) + throws IOException { + if (fileObject != null) { + Project owner = FileOwnerQuery.getOwner(fileObject); + if (owner != null) { + FileObject fileObject1 = owner.getProjectDirectory() + .getFileObject("nbproject/project.properties"); + if (fileObject1 != null) { + File toFile = FileUtil.toFile(fileObject1); + Properties appProps = new Properties(); + if (toFile != null) { + appProps.load(new FileInputStream(toFile)); + String property = appProps.getProperty("nbproject.python_path"); + return (property == null || property.isBlank()) + ? (PythonUtility.isPoetry((PythonProject) owner) + /**/ ? PythonUtility.getPoetryPythonPath(PythonUtility.getLspPythonExe(), + owner.getProjectDirectory()) : getPlatformPythonExe()) + : /*appProps.getProperty("nbproject.python_path")*/ property; + } + } + } + } + return getPlatformPythonExe(); + } + + public static List> getPythonExes() throws IOException { + List> versions = new ArrayList<>(); + for (String python : new String[]{"python", "python3", "py"}) { + getCommandOutput(new String[]{Utilities.isWindows() + ? "where" : "which", python}, null).lines().forEach(exe -> { + try { + String striped = exe.strip(); + if (isValidFilePath(striped)) { + String vers = getVersion(striped); + if (!vers.isEmpty()) { + versions.add(Pair.of(vers, striped)); + } + } + } catch (Exception ex) { + Exceptions.printStackTrace(ex); + } + }); + + } + + return versions; + } + + private static boolean isValidFilePath(String filePath) { + try { + // Attempt to create a Path object from the provided string + Path path = Paths.get(filePath); + + // Check if the path is absolute and exists + return path.isAbsolute() && path.toFile().exists() && Files.isExecutable(path); + } catch (Exception e) { + // An exception was thrown when parsing the path + return false; + } + } + + public static String[] getOsShell() { + if (Utilities.isWindows()) { + return new String[]{"cmd.exe", "/c"}; + } else if (Utilities.isMac() || Utilities.isUnix()) { + return new String[]{getEnvs().getOrDefault("SHELL", "/bin/bash"), "-c"}; + } + return null; + } + + public static Map getEnvs() { + Map envs = Maps.newHashMap(System.getenv()); + return envs; + } + + public static String getPlatformPythonExe() throws IOException { + return PythonPlatformManager.getDefault(); + } + + public static ImageIcon getPythonIcon() { + return ImageUtilities.loadImageIcon("org/netbeans/modules/python/python-2.png", false); + + } + + public static ImageIcon getClassIcon() { + return ImageUtilities.loadImageIcon("org/netbeans/modules/python/Classes.png", false); + + } + + public static ImageIcon getMethodIcon() { + return ImageUtilities.loadImageIcon("org/netbeans/modules/python/methodPublic.png", false); + + } + + public static ImageIcon getPytestIcon() { + return ImageUtilities.loadImageIcon("org/netbeans/modules/python/pytest.png", false); + + } + + public static ImageIcon getPackageIcon() { + return ImageUtilities.loadImageIcon("org/netbeans/modules/python/package16.png", false); + + } + + public static ImageIcon getPynguinIcon() { + return ImageUtilities.loadImageIcon("org/netbeans/modules/python/pynguin.png", false); + + } + + public static Properties getProperties(@NonNull Project project, boolean isCreating) throws IOException { + + Properties prop = new Properties(); + if (OpenProjects.getDefault().isProjectOpen(project) || isCreating) { + File file = createProperties(project); + prop.load(new FileInputStream(file)); + } + return prop; + + } + + public static String getVersion(String projectPythonExe) throws IOException { + String stripedPath = projectPythonExe.strip(); + if (!isValidFilePath(stripedPath)) { + LOG.log(Level.SEVERE, stripedPath); + return ""; + } + String commandOutput = getCommandOutput(new String[]{stripedPath, "--version"}, null); + if (!commandOutput.startsWith("Py")) { + LOG.log(Level.SEVERE, commandOutput); + return ""; + } + return commandOutput; + } + + public static ImageIcon getErrorIcon() { + return ImageUtilities.loadImageIcon("org/netbeans/modules/python/error-badge.png", false); + + } + + public static ImageIcon getPythonPackageIcon() { + return ImageUtilities.loadImageIcon("org/netbeans/modules/python/libraries.png", false); + + } + + public static int venvPackageInstaller(FileObject projectDirectory) { + String[] cmd = { + normalizeVenvPath(FileUtil.toFile(projectDirectory).toPath()), + "-m", + "pip", + "install" + }; + return processExecutor(ArrayUtils.addAll(cmd, VENV_DEPS), "Installing packages"); + } + + public static String normalizeVenvPath(Path base) { + return Utilities.isWindows() ? base.resolve(".venv\\Scripts\\python.exe").toString() + : base.resolve(".venv/bin/python").toString(); + + } + + @NbBundle.Messages("CTL_Install=Installing packages") + public static void packageInstaller(String errorLline) { + Matcher matcher = NO_MODULE_PATTERN.matcher(errorLline); + while (matcher.find()) { + String[] cmd = { + matcher.group(1), + "-m", + "pip", + "install", + matcher.group(2) + }; + + processExecutor(cmd, Bundle.CTL_Install()); + } + } + + public static int processExecutor(String[] cmd, String message) { + try { + ProcessBuilder pb = new ProcessBuilder(); + pb.command(cmd); + LOG.info(() -> Arrays.toString(cmd)); + + ExecutionDescriptor execDescriptor = new ExecutionDescriptor() + .frontWindowOnError(true) + .showProgress(true) + .outConvertorFactory(new PythonOutputLine()) + .errConvertorFactory(new PythonOutputLine()); + + ExecutionService service = ExecutionService + .newService(() -> pb.start(), execDescriptor, message); + + int waitFor = service.run().get(); + + return waitFor; + } catch (InterruptedException | ExecutionException ex) { + Exceptions.printStackTrace(ex); + } + return 1; + } + + @NbBundle.Messages({ + "CTL_CreatePylsp=Creating pylsp environment", + "CTL_PylspInstallIssue=Issue when creating Pylsp environment.", + "CTL_PylspRetry=Retry" + }) + public static int installLsp(ClassLoader cl) { + try { + if (!PythonUtility.PYLSP_VENV_DIR.exists()) { + PythonUtility.PYLSP_VENV_DIR.mkdir(); + Files.writeString(SETTINGS.toPath(), + IOUtils.resourceToString("org/netbeans/modules/python/settings.json", + StandardCharsets.UTF_8, cl) + ); + Files.writeString(SETTINGS_SCHEMA.toPath(), + IOUtils.resourceToString("org/netbeans/modules/python/schema.json", + StandardCharsets.UTF_8, cl) + ); + Files.writeString(REPOS.toPath(), + IOUtils.resourceToString("org/netbeans/modules/python/repos.json", + StandardCharsets.UTF_8, cl) + ); + Files.writeString(PLATFORMS.toPath(), + IOUtils.resourceToString("org/netbeans/modules/python/platforms.json", + StandardCharsets.UTF_8, cl) + ); + Files.writeString(ENVS.toPath(), + IOUtils.resourceToString("org/netbeans/modules/python/envs.json", + StandardCharsets.UTF_8, cl) + ); + Files.writeString(TEST_RUNNER.toPath(), + IOUtils.resourceToString("org/netbeans/modules/python/nb_test_runner.py", + StandardCharsets.UTF_8, cl) + ); + Files.writeString(TOML_HANDLER.toPath(), + IOUtils.resourceToString("org/netbeans/modules/python/toml_handler.py", + StandardCharsets.UTF_8, cl) + ); + } + String[] cmd = { + PythonUtility.getPlatformPythonExe(), + "-m", + "venv", + PythonUtility.PYLSP_VENV_DIR.toPath().resolve(".venv").toString() + }; + + int processExecutor = PythonUtility.processExecutor(cmd, Bundle.CTL_CreatePylsp()); + if (processExecutor != 0) { + + NotificationDisplayer.getDefault().notify(Bundle.CTL_PylspInstallIssue(), + PythonUtility.getErrorIcon(), + Bundle.CTL_PylspRetry(), + (ActionEvent e) -> { + RP.post(() -> { + PythonUtility.processExecutor(cmd, Bundle.CTL_CreatePylsp()); + finish(); + }); + }, + NotificationDisplayer.Priority.HIGH, + NotificationDisplayer.Category.ERROR); + } + + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + + return finish(); + } + + public static String getPipList(String exe) throws IOException { + return getCommandOutput(new String[]{exe, "-m", "pip", "list"}, null); + } + + @NbBundle.Messages({ + "CTL_InstallDeps=Installing pylsp dependencies", + "CTL_MissingDeps=Missing dependency:" + }) + public static int finish() { + String[] cmd = {PythonUtility.getLspPythonExe(), "-m", "pip", "install", "--upgrade"}; + return processExecutor(ArrayUtils.addAll(cmd, LSP_DEPS), Bundle.CTL_InstallDeps()); + } + + public static void noModuleInstalledHandler(String line) { + Matcher matcher = PythonUtility.NO_MODULE_PATTERN.matcher(line); + if (matcher.find()) { + String pyPackage = matcher.group(2); + NotificationDisplayer.getDefault().notify(String.format("%s %s", Bundle.CTL_MissingDeps(), pyPackage), + PythonUtility.getPythonPackageIcon(), + String.format("Install %s", pyPackage), + (ActionEvent e) -> { + RP.post(() -> { + PythonUtility.packageInstaller(line); + }); + }, + NotificationDisplayer.Priority.NORMAL, + NotificationDisplayer.Category.WARNING); + } + } + + public static Map getUserEnvs() throws IOException { + File envsFile = PythonPlatformManager.getPathFile(); + JSONObject jsonObject = new JSONObject(Files.readString(envsFile.toPath())); + return jsonObject.toMap(); + } + + public static void insertUserEnvs(String toString) { + try { + Files.writeString(getPathFile().toPath(), toString); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + + public static ExecutionDescriptor getExecutorDescriptor(ExecutionDescriptor.LineConvertorFactory convertorFactory, + Runnable preExeRunnable, Runnable postRunnable, boolean controllable, boolean select) { + ExecutionDescriptor execDescriptor = new ExecutionDescriptor() + .frontWindow(select) + .frontWindowOnError(select) + .controllable(controllable) + .showProgress(true) + .inputVisible(true) + .outConvertorFactory(convertorFactory) + .errConvertorFactory(convertorFactory) + .preExecution(preExeRunnable) + .postExecution(postRunnable); + + return execDescriptor; + } + + public static boolean isRunWithSysEnvs() { + return NbPreferences.root().getBoolean("sysEnv", true); + } + + public static void manageRunEnvs(ProcessBuilder pb) { + try { + Map environment = pb.environment(); + if (!PythonUtility.isRunWithSysEnvs()) { + environment.clear(); + } + Map userEnvs = getUserEnvs(); + environment.putAll(userEnvs); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + + } + + public static String getVenv(PythonProject get) { + try { + return getProperties(get, false).getProperty("nbproject.virtualmanager", "venv"); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + return "venv"; + } + + public static String getProjectType(File toFile) { + try (FileConfig conf = FileConfig.of(toFile)) { + conf.load(); + Object get = conf.get("tool.poetry"); + return get == null ? PythonProject.PYTHON : PythonProject.POETRY; + } + } + + public static boolean isPoetry(PythonProject project) { + FileObject fileObject = project.getProjectDirectory().getFileObject("pyproject.toml"); + + return (fileObject != null && PythonUtility.getProjectType(FileUtil.toFile(fileObject)) + .equals(PythonProject.POETRY)) || project.getProjectDirectory().getFileObject("poetry.lock") != null; + + } + + public static String getPoetryPythonPath(String defaultPython, FileObject projectDir) { + try { + String[] cmd = {defaultPython, "-m", "poetry", "env", "list", "--full-path"}; + + Matcher matcher = PythonUtility.POETRY_PYTHON_PATH.matcher(PythonUtility.getCommandOutput(cmd, projectDir)); + if (matcher.find()) { + String endPath; + if (Utilities.isWindows()) { + endPath = "\\Scripts\\python.exe"; + } else { + endPath = "/bin/python"; + } + return String.format("%s%s", matcher.group(1), endPath); + } + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + return defaultPython; + } + + public static File createProperties(Project project) { + File toFile = Paths.get(project.getProjectDirectory().getPath()) + .resolve("nbproject").resolve("project.properties").toFile(); + if (!toFile.exists()) { + try { + FileUtils.createParentDirectories(toFile); + toFile.createNewFile(); + return toFile; + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + + } + return toFile; + } + +} diff --git a/src/main/java/org/netbeans/modules/python/options/PythonLspServerConfigsPanel.java b/src/main/java/org/netbeans/modules/python/options/PythonLspServerConfigsPanel.java index 9a77cf9..f13b74e 100644 --- a/src/main/java/org/netbeans/modules/python/options/PythonLspServerConfigsPanel.java +++ b/src/main/java/org/netbeans/modules/python/options/PythonLspServerConfigsPanel.java @@ -42,7 +42,7 @@ final class PythonLspServerConfigsPanel extends javax.swing.JPanel { public static String[] PACKAGES = { "pylsp", - "python-lsp-isort", + "pyls-isort", "pylsp-mypy", "pylsp-rope", "black", From 627f6742474e821d9001390c5bcc8413f202bd6b Mon Sep 17 00:00:00 2001 From: albilu <35330562+albilu@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:08:33 +0200 Subject: [PATCH 3/8] Remove pynguin also from project venv dependencies --- src/main/java/org/netbeans/modules/python/PythonUtility.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/netbeans/modules/python/PythonUtility.java b/src/main/java/org/netbeans/modules/python/PythonUtility.java index 4f602b1..f144b01 100644 --- a/src/main/java/org/netbeans/modules/python/PythonUtility.java +++ b/src/main/java/org/netbeans/modules/python/PythonUtility.java @@ -104,7 +104,7 @@ public class PythonUtility { public static String[] VENV_DEPS = new String[]{ "pytest", - "pynguin", + //"pynguin", "build" }; From 3d36f5fdcf9ae7b3d45f4327d302e232359ee604 Mon Sep 17 00:00:00 2001 From: albilu <35330562+albilu@users.noreply.github.com> Date: Mon, 30 Sep 2024 21:06:28 +0200 Subject: [PATCH 4/8] Remove Pytest Test results windows draft Package installer improvment Fix incorrec venv console mode --- .../actions/PythonVEnvConsoleAction.java | 8 +++++++ .../options/PythonLspServerConfigsPanel.java | 2 +- .../PythonPackageManagerTopComponent.java | 18 ++++++++++++--- .../PythonTestResultsTopComponent.java | 23 ++++++++----------- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/netbeans/modules/python/actions/PythonVEnvConsoleAction.java b/src/main/java/org/netbeans/modules/python/actions/PythonVEnvConsoleAction.java index 26015dc..d43d076 100644 --- a/src/main/java/org/netbeans/modules/python/actions/PythonVEnvConsoleAction.java +++ b/src/main/java/org/netbeans/modules/python/actions/PythonVEnvConsoleAction.java @@ -19,6 +19,8 @@ import org.openide.util.LookupListener; import org.openide.util.NbBundle; import org.openide.util.Utilities; +import org.openide.windows.Mode; +import org.openide.windows.WindowManager; /** * @@ -92,6 +94,12 @@ public void actionPerformed(ActionEvent ev) { PythonProject get = lkpInfo.allInstances().stream().findFirst().get(); PythonVEnvConsoleActionTopComponent pythonVEnvConsoleActionTopComponent = new PythonVEnvConsoleActionTopComponent(get, "venv"); + for (Mode mode : WindowManager.getDefault().getModes()) { + if (mode.getName().equals("output") && mode.canDock(pythonVEnvConsoleActionTopComponent)) { + mode.dockInto(pythonVEnvConsoleActionTopComponent); + break; + } + } pythonVEnvConsoleActionTopComponent.open(); pythonVEnvConsoleActionTopComponent.requestActive(); } diff --git a/src/main/java/org/netbeans/modules/python/options/PythonLspServerConfigsPanel.java b/src/main/java/org/netbeans/modules/python/options/PythonLspServerConfigsPanel.java index f13b74e..9a77cf9 100644 --- a/src/main/java/org/netbeans/modules/python/options/PythonLspServerConfigsPanel.java +++ b/src/main/java/org/netbeans/modules/python/options/PythonLspServerConfigsPanel.java @@ -42,7 +42,7 @@ final class PythonLspServerConfigsPanel extends javax.swing.JPanel { public static String[] PACKAGES = { "pylsp", - "pyls-isort", + "python-lsp-isort", "pylsp-mypy", "pylsp-rope", "black", diff --git a/src/main/java/org/netbeans/modules/python/packagemanager/PythonPackageManagerTopComponent.java b/src/main/java/org/netbeans/modules/python/packagemanager/PythonPackageManagerTopComponent.java index 541a082..f1af6fc 100644 --- a/src/main/java/org/netbeans/modules/python/packagemanager/PythonPackageManagerTopComponent.java +++ b/src/main/java/org/netbeans/modules/python/packagemanager/PythonPackageManagerTopComponent.java @@ -243,9 +243,21 @@ private void installButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN switch (text) { case "Install": RP.post(() -> { - PythonUtility.processExecutor(new String[]{pyPath, "-m", "pip", - "install", name + "==" + versionsComboBox.getSelectedItem() - .toString()}, "Installing Package " + name); + PythonUtility.processExecutor( + new String[]{ + pyPath, + "-m", + "pip", + "install", + String.format( + "%s%s", + name, + versionsComboBox.getSelectedItem() != null + ? "==" + versionsComboBox.getSelectedItem().toString() + : "") + }, + "Installing Package " + name + ); PythonPackagesModel.loadInstalled(pyPath); }); break; diff --git a/src/main/java/org/netbeans/modules/python/testrunner/PythonTestResultsTopComponent.java b/src/main/java/org/netbeans/modules/python/testrunner/PythonTestResultsTopComponent.java index 2d6d618..a316dcf 100644 --- a/src/main/java/org/netbeans/modules/python/testrunner/PythonTestResultsTopComponent.java +++ b/src/main/java/org/netbeans/modules/python/testrunner/PythonTestResultsTopComponent.java @@ -17,10 +17,7 @@ import org.netbeans.api.editor.EditorRegistry; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; -import org.netbeans.api.settings.ConvertAsProperties; import org.netbeans.modules.editor.NbEditorUtilities; -import org.openide.awt.ActionID; -import org.openide.awt.ActionReference; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; @@ -31,16 +28,16 @@ /** * Top component which displays something. */ -@ConvertAsProperties(dtd = "-//org.netbeans.modules.python.testrunner//PythonTestResults//EN", autostore = false) -@TopComponent.Description(preferredID = "PythonTestResultsTopComponent", iconBase = "org/netbeans/modules/python/pytest.png", persistenceType = TopComponent.PERSISTENCE_ALWAYS) -@TopComponent.Registration(mode = "output", openAtStartup = false) -@ActionID(category = "Window", id = "org.netbeans.modules.python.testrunner.PythonTestResultsTopComponent") -@ActionReference(path = "Menu/Window/Tools", position = 255) -@TopComponent.OpenActionRegistration(displayName = "#CTL_PythonTestResultsAction", preferredID = "PythonTestResultsTopComponent") +//@ConvertAsProperties(dtd = "-//org.netbeans.modules.python.testrunner//PythonTestResults//EN", autostore = false) +//@TopComponent.Description(preferredID = "PythonTestResultsTopComponent", iconBase = "org/netbeans/modules/python/pytest.png", persistenceType = TopComponent.PERSISTENCE_ALWAYS) +//@TopComponent.Registration(mode = "output", openAtStartup = false) +//@ActionID(category = "Window", id = "org.netbeans.modules.python.testrunner.PythonTestResultsTopComponent") +//@ActionReference(path = "Menu/Window/Tools", position = 255) +//@TopComponent.OpenActionRegistration(displayName = "#CTL_PythonTestResultsAction", preferredID = "PythonTestResultsTopComponent") @Messages({ - "CTL_PythonTestResultsAction=PyTest Results", - "CTL_PythonTestResultsTopComponent=PyTest Results Window", - "HINT_PythonTestResultsTopComponent=This is a PyTest Results window" + "CTL_PythonTestResultsAction=PyTest Results", + "CTL_PythonTestResultsTopComponent=PyTest Results Window", + "HINT_PythonTestResultsTopComponent=This is a PyTest Results window" }) public final class PythonTestResultsTopComponent extends TopComponent { @@ -91,7 +88,7 @@ public void componentOpened() { .getProjectDirectory()).toPath()) .map(Path::toFile) .filter(file -> file.getName() - .equals("report.html")) + .equals("report.html")) .collect(Collectors.toList()); collect.sort(LastModifiedFileComparator.LASTMODIFIED_REVERSE); if (!collect.isEmpty()) { From 5aa8f1fc6f90e853f9a1e97557e403c0d19da204 Mon Sep 17 00:00:00 2001 From: albilu <35330562+albilu@users.noreply.github.com> Date: Mon, 30 Sep 2024 21:47:26 +0200 Subject: [PATCH 5/8] Upgrade pty4j --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 746e5b8..50815a1 100644 --- a/pom.xml +++ b/pom.xml @@ -434,7 +434,7 @@ org.jetbrains.pty4j pty4j - 0.12.10 + 0.12.35 jar From ce4077a195820a65c1116f667657b987b28cb91c Mon Sep 17 00:00:00 2001 From: Piotr Hoppe Date: Wed, 16 Oct 2024 15:03:17 +0200 Subject: [PATCH 6/8] Replace a split method by a StringTokenizer clas to parse run param. In current implementation for split "Run Paramteres" of project is used split method that split a String by space. I that not handle qouted parameters with spaces and split it by space that not allow to pass the text as parameter with spaces. To handle this situation the split method are replaced by use the StringTokenizer class, that support single (`) and duble (") quote that arrond the tekst as a params. Task: #123 --- .../java/org/netbeans/modules/python/actions/PythonRun.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/netbeans/modules/python/actions/PythonRun.java b/src/main/java/org/netbeans/modules/python/actions/PythonRun.java index 10d6c94..f7ca882 100644 --- a/src/main/java/org/netbeans/modules/python/actions/PythonRun.java +++ b/src/main/java/org/netbeans/modules/python/actions/PythonRun.java @@ -7,6 +7,8 @@ import java.util.List; import java.util.Properties; import java.util.logging.Logger; +import org.apache.commons.text.StringTokenizer; +import org.apache.commons.text.matcher.StringMatcherFactory; import org.netbeans.api.extexecution.ExecutionService; import org.netbeans.api.project.Project; import org.netbeans.modules.python.PythonOutputLine; @@ -57,8 +59,7 @@ public static List getRunArgs(Project owner, DataObject context, boolean if (owner != null) { Properties prop = PythonUtility.getProperties(owner, false); if (!prop.getProperty("nbproject.run.params", "").isEmpty()) { - params = prop.getProperty("nbproject.run.params", "") - .split(" "); + params = new StringTokenizer(prop.getProperty("nbproject.run.params", ""), StringMatcherFactory.INSTANCE.spaceMatcher(), StringMatcherFactory.INSTANCE.quoteMatcher()).getTokenArray(); } } if (owner != null && PythonUtility.isPoetry((PythonProject) owner) && !isDebug) { From 3991900dfc956fc62b5463fc3d17407fc63df005 Mon Sep 17 00:00:00 2001 From: albilu <35330562+albilu@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:00:20 +0200 Subject: [PATCH 7/8] Apply StringTokenizer to build/test/pdoc parameters --- .../org/netbeans/modules/python/PythonUtility.java | 13 +++++++++++++ .../modules/python/actions/PythonBuild.java | 5 +++-- .../modules/python/actions/PythonDocGenerator.java | 5 +++-- .../netbeans/modules/python/actions/PythonRun.java | 5 ++--- .../python/testrunner/PythonTestManager.java | 3 ++- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/netbeans/modules/python/PythonUtility.java b/src/main/java/org/netbeans/modules/python/PythonUtility.java index f144b01..be60f27 100644 --- a/src/main/java/org/netbeans/modules/python/PythonUtility.java +++ b/src/main/java/org/netbeans/modules/python/PythonUtility.java @@ -25,6 +25,8 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.text.StringTokenizer; +import org.apache.commons.text.matcher.StringMatcherFactory; import org.json.JSONObject; import org.netbeans.api.annotations.common.NonNull; import org.netbeans.api.extexecution.ExecutionDescriptor; @@ -56,6 +58,13 @@ public class PythonUtility { public static final Logger LOG = Logger.getLogger(PythonUtility.class.getName()); + public static final StringTokenizer STRING_TOKENIZER = new StringTokenizer(); + + static { + STRING_TOKENIZER.setDelimiterMatcher(StringMatcherFactory.INSTANCE.spaceMatcher()); + STRING_TOKENIZER.setQuoteMatcher(StringMatcherFactory.INSTANCE.quoteMatcher()); + } + public static final RequestProcessor RP = new RequestProcessor("Retry RP", 2); public static final String PYTHON_MIME_TYPE = "text/x-python"; public static final File PYLSP_VENV_DIR = Paths.get(System.getProperty("netbeans.user")).resolve(".pythonlsp").toFile(); @@ -74,6 +83,10 @@ public class PythonUtility { return toFileObject != null ? toFileObject : null; }; + public static StringTokenizer getParamsTokenizer() { + return STRING_TOKENIZER; + } + public static LineConvertor FILE_CONVERTOR = LineConvertors.filePattern(FILE_LOCATOR, PYTHON_STACKTRACE_PATTERN, null, 1, 2); diff --git a/src/main/java/org/netbeans/modules/python/actions/PythonBuild.java b/src/main/java/org/netbeans/modules/python/actions/PythonBuild.java index 9cda480..84ebbbd 100644 --- a/src/main/java/org/netbeans/modules/python/actions/PythonBuild.java +++ b/src/main/java/org/netbeans/modules/python/actions/PythonBuild.java @@ -45,8 +45,9 @@ public static void runAction(Project owner, FileObject context) { if (owner != null) { Properties prop = PythonUtility.getProperties(owner, false); if (!prop.getProperty("nbproject.build.params", "").isEmpty()) { - params = prop.getProperty("nbproject.build.params", "") - .split(" "); + params = PythonUtility.getParamsTokenizer().reset( + prop.getProperty("nbproject.build.params", "") + ).getTokenArray(); } } List asList1 = null; diff --git a/src/main/java/org/netbeans/modules/python/actions/PythonDocGenerator.java b/src/main/java/org/netbeans/modules/python/actions/PythonDocGenerator.java index 7a6437e..f054ea9 100644 --- a/src/main/java/org/netbeans/modules/python/actions/PythonDocGenerator.java +++ b/src/main/java/org/netbeans/modules/python/actions/PythonDocGenerator.java @@ -52,8 +52,9 @@ public void actionPerformed(ActionEvent ev) { String[] params = {}; List argList = new ArrayList<>(); Properties prop = PythonUtility.getProperties(context, false); - params = prop.getProperty("nbproject.pdoc.params", "-o docs") - .split(" "); + params = PythonUtility.getParamsTokenizer().reset( + prop.getProperty("nbproject.pdoc.params", "-o docs") + ).getTokenArray(); List asList1 = null; asList1 = Arrays.asList(/*osShell[1],*/PythonUtility.getLspPythonExe(), diff --git a/src/main/java/org/netbeans/modules/python/actions/PythonRun.java b/src/main/java/org/netbeans/modules/python/actions/PythonRun.java index f7ca882..5422059 100644 --- a/src/main/java/org/netbeans/modules/python/actions/PythonRun.java +++ b/src/main/java/org/netbeans/modules/python/actions/PythonRun.java @@ -7,8 +7,6 @@ import java.util.List; import java.util.Properties; import java.util.logging.Logger; -import org.apache.commons.text.StringTokenizer; -import org.apache.commons.text.matcher.StringMatcherFactory; import org.netbeans.api.extexecution.ExecutionService; import org.netbeans.api.project.Project; import org.netbeans.modules.python.PythonOutputLine; @@ -59,7 +57,8 @@ public static List getRunArgs(Project owner, DataObject context, boolean if (owner != null) { Properties prop = PythonUtility.getProperties(owner, false); if (!prop.getProperty("nbproject.run.params", "").isEmpty()) { - params = new StringTokenizer(prop.getProperty("nbproject.run.params", ""), StringMatcherFactory.INSTANCE.spaceMatcher(), StringMatcherFactory.INSTANCE.quoteMatcher()).getTokenArray(); + params = PythonUtility.getParamsTokenizer() + .reset(prop.getProperty("nbproject.run.params", "")).getTokenArray(); } } if (owner != null && PythonUtility.isPoetry((PythonProject) owner) && !isDebug) { diff --git a/src/main/java/org/netbeans/modules/python/testrunner/PythonTestManager.java b/src/main/java/org/netbeans/modules/python/testrunner/PythonTestManager.java index 5ef0e20..d1a8408 100644 --- a/src/main/java/org/netbeans/modules/python/testrunner/PythonTestManager.java +++ b/src/main/java/org/netbeans/modules/python/testrunner/PythonTestManager.java @@ -31,7 +31,8 @@ public static Object[] getTestRunParams(PythonProject project) { try { Properties prop = PythonUtility.getProperties(project, false); return new Object[]{prop.getProperty("nbproject.test.runner", "unittest"), - prop.getProperty("nbproject.test.params", "*Test.py").split(" ")}; + PythonUtility.getParamsTokenizer().reset( + prop.getProperty("nbproject.test.params", "*Test.py")).getTokenArray()}; } catch (IOException ex) { Exceptions.printStackTrace(ex); } From cb46675e544951e0602607b9684410936f6e102d Mon Sep 17 00:00:00 2001 From: albilu <35330562+albilu@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:45:49 +0200 Subject: [PATCH 8/8] 1.9.3 Release --- pom.xml | 2 +- ppuc/21/updates.xml | 6 +++--- ppuc/22/updates.xml | 6 +++--- ppuc/23/updates.xml | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 50815a1..0d6f1ee 100644 --- a/pom.xml +++ b/pom.xml @@ -802,7 +802,7 @@ target/keystore RELEASE230 - 1.9.2 + 1.9.3 https://github.com/albilu/netbeansPython https://github.com/albilu/netbeansPython.git UTF-8 diff --git a/ppuc/21/updates.xml b/ppuc/21/updates.xml index 9ac07b5..642fa6a 100644 --- a/ppuc/21/updates.xml +++ b/ppuc/21/updates.xml @@ -1,6 +1,6 @@ - - - + + + \ No newline at end of file diff --git a/ppuc/22/updates.xml b/ppuc/22/updates.xml index b33b5fa..e10a3eb 100644 --- a/ppuc/22/updates.xml +++ b/ppuc/22/updates.xml @@ -1,6 +1,6 @@ - - - + + + \ No newline at end of file diff --git a/ppuc/23/updates.xml b/ppuc/23/updates.xml index f3f574c..8e30469 100644 --- a/ppuc/23/updates.xml +++ b/ppuc/23/updates.xml @@ -1,6 +1,6 @@ - - - + + + \ No newline at end of file