diff --git a/plugins/org.python.pydev.core/META-INF/MANIFEST.MF b/plugins/org.python.pydev.core/META-INF/MANIFEST.MF index 2f2baea0c7..6650905252 100644 --- a/plugins/org.python.pydev.core/META-INF/MANIFEST.MF +++ b/plugins/org.python.pydev.core/META-INF/MANIFEST.MF @@ -34,6 +34,7 @@ Export-Package: org.python.copiedfromeclipsesrc, org.python.pydev.core.log, org.python.pydev.core.logging, org.python.pydev.core.nature, + org.python.pydev.core.package_manager, org.python.pydev.core.parser, org.python.pydev.core.partition, org.python.pydev.core.performanceeval, diff --git a/plugins/org.python.pydev.core/pysrc/tests_python/my_django_proj_17/.pydevproject b/plugins/org.python.pydev.core/pysrc/tests_python/my_django_proj_17/.pydevproject index 6e842d0158..594f7b2b11 100644 --- a/plugins/org.python.pydev.core/pysrc/tests_python/my_django_proj_17/.pydevproject +++ b/plugins/org.python.pydev.core/pysrc/tests_python/my_django_proj_17/.pydevproject @@ -1,12 +1,22 @@ - -DJANGO_MANAGE_LOCATION -manage.py - - -/${PROJECT_DIR_NAME} - -python 2.7 -Default + + + + DJANGO_MANAGE_LOCATION + + manage.py + + + + + + /${PROJECT_DIR_NAME} + + + + python interpreter + + Default + diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/package_manager/BasePackageManager.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/package_manager/BasePackageManager.java new file mode 100644 index 0000000000..88d659db27 --- /dev/null +++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/package_manager/BasePackageManager.java @@ -0,0 +1,161 @@ +/** + * Base package manager + * + * Using either poetry or uv, manage the commands available to apply to a project. + * + * @author Martin Whitehouse + */ +package org.python.pydev.core.package_manager; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.runtime.Platform; +import org.python.pydev.core.log.Log; + +/** + * Using ProcessBuilder, runs the commands to achieve e.g. `poetry install + * package_name`. + */ +abstract public class BasePackageManager { + public enum Commands { + INSTALL("install"), ENV("env"), LOCK("lock"), SYNC("sync"), UPDATE("update"); + + private String command; + + private Commands(String command) { + this.command = command; + } + + public String command() { + return this.command; + } + } + + /** + * Argument to use for changing to the project directory. + */ + private String chDirArg; + + /** + * Name of the task + */ + protected String taskName; + + /** + * Path to the project directory + */ + private String projectRoot; + + /** + * Path to the binary + */ + private String binPath; + + /** + * Title to use when binary can't be found. + */ + private String errorTitle; + /** + * Message to display. + */ + private String errorMsg; + + public BasePackageManager(String projectRoot, String name, String prefsName, String chDirAarg) { + this.projectRoot = projectRoot; + this.chDirArg = chDirAarg; + binPath = Platform.getPreferencesService().getString("org.python.pydev", prefsName, null, null); + File f = null; + if (binPath != null) { + f = new File(binPath); + } + if (binPath == null | !(f != null && f.exists() && !f.isDirectory())) { + errorTitle = name + " not configured"; + errorMsg = "The path to " + name + "could not be found.\n"; + errorMsg += "Please configure the path to " + name; + } + } + + private Boolean checkError() { + if (errorMsg != null) { + Log.log(errorTitle + "\n" + errorMsg); + return false; + } + return true; + } + + protected ArrayList getCommandArgs(String args) { + return new ArrayList(Arrays.asList(args)); + } + + protected ArrayList getCommandArgs(String[] args) { + ArrayList parsedArgs = new ArrayList(); + for (String arg : args) { + parsedArgs.add(arg); + } + return parsedArgs; + } + + public String add(String appName) { + List args = getCommandArgs("add"); + String[] apps = appName.split(" "); + for (String app : apps) { + args.add(app); + } + return runCommand(args); + } + + public String lock() { + return runCommand(getCommandArgs("lock")); + } + + public String sync() { + return runCommand(getCommandArgs("sync")); + } + + public String remove(String appName) { + List args = getCommandArgs("remove"); + for (String app : appName.split(" ")) { + args.add(app); + } + return runCommand(args); + } + + /** + * Returns the output of running `poetry args...` + * + * @param args List of arguments to pass to binPath e.g. "[poetry] env info" + * @return The command output + */ + public String runCommand(List args) { + String output = null; + if (!checkError()) { + return output; + } + ArrayList commandArgs = new ArrayList(); + + commandArgs.add(binPath); + commandArgs.add(chDirArg); + commandArgs.add(projectRoot); + + for (String arg : args) { + commandArgs.add(arg); + } + + ProcessBuilder pb = new ProcessBuilder(commandArgs); + Process p; + + try { + p = pb.start(); + output = new String(p.getInputStream().readAllBytes()).strip(); + } catch (IOException e) { + Log.log(e); + } + + return output; + } + +} diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/package_manager/PoetryPackageManager.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/package_manager/PoetryPackageManager.java new file mode 100644 index 0000000000..934388f063 --- /dev/null +++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/package_manager/PoetryPackageManager.java @@ -0,0 +1,42 @@ +package org.python.pydev.core.package_manager; + +import java.util.ArrayList; + +public class PoetryPackageManager extends BasePackageManager { + final public static String PREFS_NAME = "POETRY_BIN"; + private String pythonPath; + + public PoetryPackageManager(String projectRoot) { + super(projectRoot, "poetry", PREFS_NAME, "-C"); + } + + public String install() { + return runCommand(getCommandArgs("install")); + } + + @Override + public String add(String appName) { + ArrayList args = getCommandArgs("add"); + String[] apps = appName.split(" "); + for (String app : apps) { + args.add(app); + } + return runCommand(args); + } + + public String update() { + return runCommand(getCommandArgs("update")); + } + + /** + * Returns the path to the python executable of a pyproject virtual environment. + * + * @return the path to python + */ + public String getPython() { + if (pythonPath == null) { + pythonPath = runCommand(getCommandArgs(new String[] { "env", "info", "-e" })); + } + return pythonPath; + } +} diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/package_manager/UVPackageManager.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/package_manager/UVPackageManager.java new file mode 100644 index 0000000000..bda4c5df99 --- /dev/null +++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/package_manager/UVPackageManager.java @@ -0,0 +1,22 @@ +package org.python.pydev.core.package_manager; + +public class UVPackageManager extends BasePackageManager { + final public static String PREFS_NAME = "UV_BIN"; + private String pythonPath; + + public UVPackageManager(String projectRoot) { + super(projectRoot, "uv", PREFS_NAME, "--directory"); + } + + /** + * Returns the path to the python executable of a pyproject virtual environment. + * + * @return the path to python + */ + public String getPython() { + if (pythonPath == null) { + pythonPath = runCommand(getCommandArgs(new String[] { "python", "find" })); + } + return pythonPath; + } +} diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/TestDependent.linux.properties b/plugins/org.python.pydev.core/tests/org/python/pydev/core/TestDependent.linux.properties index b71d632805..c2edc63c73 100644 --- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/TestDependent.linux.properties +++ b/plugins/org.python.pydev.core/tests/org/python/pydev/core/TestDependent.linux.properties @@ -41,4 +41,3 @@ JAVA_LOCATION=/usr/bin/java #/usr/bin/cygpath.exe #CYGWIN_UNIX_CYGPATH_LOCATION=null - diff --git a/plugins/org.python.pydev/icons/PythonPoetry.png b/plugins/org.python.pydev/icons/PythonPoetry.png new file mode 100644 index 0000000000..c22e6fbbc9 Binary files /dev/null and b/plugins/org.python.pydev/icons/PythonPoetry.png differ diff --git a/plugins/org.python.pydev/icons/PythonPoetry.svg b/plugins/org.python.pydev/icons/PythonPoetry.svg new file mode 100644 index 0000000000..2dfd64b6ea --- /dev/null +++ b/plugins/org.python.pydev/icons/PythonPoetry.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/org.python.pydev/icons/uv.svg b/plugins/org.python.pydev/icons/uv.svg new file mode 100644 index 0000000000..1701389d67 --- /dev/null +++ b/plugins/org.python.pydev/icons/uv.svg @@ -0,0 +1,4 @@ + + + + diff --git a/plugins/org.python.pydev/plugin.xml b/plugins/org.python.pydev/plugin.xml index a8542c58db..de4b8e2c3d 100644 --- a/plugins/org.python.pydev/plugin.xml +++ b/plugins/org.python.pydev/plugin.xml @@ -121,6 +121,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevPrefsInitializer.java b/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevPrefsInitializer.java index 6bace53f07..56f9d0d44f 100644 --- a/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevPrefsInitializer.java +++ b/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevPrefsInitializer.java @@ -37,7 +37,7 @@ public void initializeDefaultPreferences() { Preferences node = DefaultScope.INSTANCE.getNode(SharedCorePlugin.DEFAULT_PYDEV_PREFERENCES_SCOPE); node.putInt(IWizardNewProjectNameAndLocationPage.PYDEV_NEW_PROJECT_CREATE_PREFERENCES, - IWizardNewProjectNameAndLocationPage.PYDEV_NEW_PROJECT_CREATE_PROJECT_AS_SRC_FOLDER); + IWizardNewProjectNameAndLocationPage.PYDEV_NEW_PROJECT_CREATE_SRC_FOLDER); //comment blocks node.put(CommentBlocksPreferences.MULTI_BLOCK_COMMENT_CHAR, @@ -291,6 +291,8 @@ public void initializeDefaultPreferences() { //root node.putBoolean(PydevRootPrefs.CHECK_PREFERRED_PYDEV_SETTINGS, PydevRootPrefs.DEFAULT_CHECK_PREFERRED_PYDEV_SETTINGS); + node.put(PydevRootPrefs.POETRY_BIN, PydevRootPrefs.getDefaultPoetryBinPreference()); + node.put(PydevRootPrefs.UV_BIN, PydevRootPrefs.getDefaultUVBinPreference()); } diff --git a/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevRootPrefs.java b/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevRootPrefs.java index b8ace46ad6..39d0ddb28d 100644 --- a/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevRootPrefs.java +++ b/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevRootPrefs.java @@ -8,15 +8,19 @@ import org.eclipse.jface.preference.BooleanFieldEditor; import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.FileFieldEditor; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; +import org.python.pydev.core.package_manager.PoetryPackageManager; +import org.python.pydev.core.package_manager.UVPackageManager; import org.python.pydev.plugin.PydevPlugin; import org.python.pydev.plugin.preferences.CheckDefaultPreferencesDialog.CheckInfo; import org.python.pydev.shared_core.string.StringUtils; +import org.python.pydev.shared_core.utils.PlatformUtils; import org.python.pydev.shared_ui.dialogs.DialogHelpers; import org.python.pydev.shared_ui.field_editors.ButtonFieldEditor; @@ -24,6 +28,8 @@ public class PydevRootPrefs extends FieldEditorPreferencePage implements IWorkbe public static final String CHECK_PREFERRED_PYDEV_SETTINGS = "CHECK_PREFERRED_PYDEV_SETTINGS"; public static final boolean DEFAULT_CHECK_PREFERRED_PYDEV_SETTINGS = true; + public static final String POETRY_BIN = "POETRY_BIN"; + public static final String UV_BIN = "UV_BIN"; public PydevRootPrefs() { setDescription(StringUtils.format("PyDev version: %s", @@ -63,6 +69,8 @@ public void widgetSelected(SelectionEvent e) { public void widgetDefaultSelected(SelectionEvent e) { } })); + addField(new FileFieldEditor(PoetryPackageManager.PREFS_NAME, "Poetry path", p)); + addField(new FileFieldEditor(UVPackageManager.PREFS_NAME, "UV path", p)); } public static void setCheckPreferredPydevSettings(boolean b) { @@ -73,4 +81,36 @@ public static boolean getCheckPreferredPydevSettings() { return PydevPlugin.getDefault().getPreferenceStore().getBoolean(CHECK_PREFERRED_PYDEV_SETTINGS); } + /** + * Gets the default poetry install location. + * + * @return The path to the poetry bin + */ + public static String getDefaultPoetryBinPreference() { + String path; + if (PlatformUtils.isWindowsPlatform()) { + path = System.getenv("APPDATA") + "\\poetry"; + } else if (PlatformUtils.isMacOsPlatform()) { + path = System.getenv("HOME") + "/Library/Application Support/pypoetry"; + } else { + path = System.getenv("HOME") + "/.local/share/pypoetry/venv/bin/poetry"; + } + return path; + } + + /** + * Gets the default UV install location. + * + * @return The path to the uv bin + */ + public static String getDefaultUVBinPreference() { + String path; + if (PlatformUtils.isWindowsPlatform()) { + path = System.getenv("APPDATA") + "\\bin\\uv"; + } else { + path = System.getenv("HOME") + "/.local/bin/uv"; + } + return path; + } + } diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/container/PyPoetryAction.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/container/PyPoetryAction.java new file mode 100644 index 0000000000..22fd8168f2 --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/container/PyPoetryAction.java @@ -0,0 +1,62 @@ +package org.python.pydev.ui.actions.container; + +import java.util.Objects; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.python.pydev.core.log.Log; +import org.python.pydev.core.package_manager.PoetryPackageManager; + +public abstract class PyPoetryAction extends PyContainerAction { + protected PoetryPackageManager pm; + + @Override + protected boolean confirmRun() { + return true; + } + + @Override + protected void afterRun(int resourcesAffected) { + } + + @Override + protected boolean needsUIThread() { + return true; + } + + abstract protected String getTaskName(); + + @Override + protected int doActionOnContainer(IContainer container, IProgressMonitor monitor) { + if (monitor.isCanceled()) { + return 0; + } + monitor.beginTask(getTaskName(), 100); + monitor.worked(1); + IProject project = container.getProject(); + pm = new PoetryPackageManager(project.getLocation().toString()); + String result = runCommand(); + int affected = 1; + if (monitor.isCanceled()) { + return 0; + } + monitor.worked(50); + if (!Objects.equals(result, "")) { + try { + project.refreshLocal(IResource.DEPTH_INFINITE, monitor); + } catch (CoreException e) { + Log.log(e); + } + affected = 0; + } + monitor.worked(100); + monitor.done(); + return affected; + } + + abstract protected String runCommand(); + +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/container/PyUVAction.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/container/PyUVAction.java new file mode 100644 index 0000000000..056a586857 --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/container/PyUVAction.java @@ -0,0 +1,61 @@ +package org.python.pydev.ui.actions.container; + +import java.util.Objects; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.python.pydev.core.log.Log; +import org.python.pydev.core.package_manager.UVPackageManager; + +public abstract class PyUVAction extends PyContainerAction { + protected UVPackageManager pm; + + @Override + protected boolean confirmRun() { + return true; + } + + @Override + protected void afterRun(int resourcesAffected) { + } + + @Override + protected boolean needsUIThread() { + return true; + } + + abstract protected String getTaskName(); + + @Override + protected int doActionOnContainer(IContainer container, IProgressMonitor monitor) { + if (monitor.isCanceled()) { + return 0; + } + monitor.beginTask(getTaskName(), 100); + monitor.worked(1); + IProject project = container.getProject(); + pm = new UVPackageManager(project.getLocation().toString()); + String result = runCommand(); + int affected = 1; + if (monitor.isCanceled()) { + return 0; + } + monitor.worked(50); + if (!Objects.equals(result, "")) { + try { + project.refreshLocal(IResource.DEPTH_INFINITE, monitor); + } catch (CoreException e) { + Log.log(e); + } + affected = 0; + } + monitor.worked(100); + monitor.done(); + return affected; + } + + abstract protected String runCommand(); +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryAdd.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryAdd.java new file mode 100644 index 0000000000..f72860b3cd --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryAdd.java @@ -0,0 +1,33 @@ +/** + * + */ +package org.python.pydev.ui.actions.project; + +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.window.Window; +import org.python.pydev.shared_ui.EditorUtils; +import org.python.pydev.ui.actions.container.PyPoetryAction; + +/** + * + */ +public class PoetryAdd extends PyPoetryAction { + + @Override + protected String getTaskName() { + return "Installing python package..."; + } + + @Override + protected String runCommand() { + InputDialog dialog = new InputDialog(EditorUtils.getShell(), "App to install", + "Name of the python App to install", null, null); + int open = dialog.open(); + if (open != Window.OK) { + return ""; + } + String appName = dialog.getValue(); + return pm.add(appName); + } + +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryInstall.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryInstall.java new file mode 100644 index 0000000000..0eee709db2 --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryInstall.java @@ -0,0 +1,156 @@ +package org.python.pydev.ui.actions.project; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectNature; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.dialogs.MessageDialog; +import org.python.pydev.ast.interpreter_managers.InterpreterManagersAPI; +import org.python.pydev.core.IInterpreterInfo; +import org.python.pydev.core.IInterpreterManager; +import org.python.pydev.core.MisconfigurationException; +import org.python.pydev.core.PythonNatureWithoutProjectException; +import org.python.pydev.core.log.Log; +import org.python.pydev.core.package_manager.PoetryPackageManager; +import org.python.pydev.plugin.nature.PythonNature; +import org.python.pydev.shared_ui.EditorUtils; +import org.python.pydev.ui.actions.container.PyContainerAction; + +public class PoetryInstall extends PyContainerAction { + private IPath absPath; + private IProject project; + private String pythonBin; + + @Override + protected boolean confirmRun() { + // TODO Figure out why the monitor doesn't progress until a dialog is displayed then use the below. + // MessageDialog confirm = new MessageDialog(EditorUtils.getShell(), "Install using poetry", null, + // "This will install using...", MessageDialog.QUESTION_WITH_CANCEL, 0, new String[] { "OK", "Cancel" }); + // confirm.open(); + // if (confirm.getReturnCode() == 1) { + // return false; + // } + return true; + } + + @Override + protected void afterRun(int resourcesAffected) { + } + + @Override + protected boolean needsUIThread() { + return true; + } + + @Override + protected int doActionOnContainer(IContainer container, IProgressMonitor monitor) { + monitor.beginTask("Installing project with poetry...", 100); + MessageDialog confirm = new MessageDialog(EditorUtils.getShell(), "Install using poetry", null, + "This will install using...", MessageDialog.QUESTION_WITH_CANCEL, 0, new String[] { "OK", "Cancel" }); + confirm.open(); + if (confirm.getReturnCode() == 1) { + return 0; + } + project = container.getProject(); + absPath = project.getLocation(); + PoetryPackageManager pm = new PoetryPackageManager(absPath.toString()); + String result = pm.install(); + monitor.worked(50); + Log.logInfo("Result: " + result); + pythonBin = pm.getPython(); + Log.logInfo("Python found at: " + pythonBin); + PythonNature nature = getNature(); + if (nature == null) { + // This should never happen + } else { + setInterpreter(nature); + } + monitor.worked(75); + try { + project.refreshLocal(1, monitor); + } catch (CoreException e) { + Log.log(e); + } + monitor.worked(100); + monitor.done(); + return 0; + } + + private PythonNature getNature() { + IProjectNature nature; + try { + nature = project.getNature(PythonNature.PYTHON_NATURE_ID); + return (PythonNature) nature; + } catch (CoreException e) { + return null; + } + } + + private void setInterpreter(PythonNature nature) { + IInterpreterInfo interpreter; + try { + interpreter = nature.getProjectInterpreter(); + String name = interpreter.getName(); + Log.logInfo("Name: " + name); + } catch (MisconfigurationException e) { + String missingInterpeter = "Interpreter: " + project.getName() + " not found"; + if (Objects.equals("Python not configured.", e.getMessage())) { + Log.logInfo("Misconfiguration error, no interpreters configured."); + setDefaultInterpreter(nature); + } else if (Objects.equals(missingInterpeter, e.getMessage().toString())) { + Log.logInfo("Misconfiguration error, project interpreter not configured."); + updateInterpererInfo(nature); + } else { + Log.logInfo("Unknown error: Message: " + e.getMessage()); + Log.log(e); + } + } catch (PythonNatureWithoutProjectException e1) { + Log.logInfo("No project nature."); + Log.log(e1); + } + } + + private void setDefaultInterpreter(PythonNature nature) { + Log.logInfo("Setting default interpreter."); + IInterpreterManager pythonInterpreterManager = InterpreterManagersAPI.getPythonInterpreterManager(); + IInterpreterInfo projectInterpreter = pythonInterpreterManager.createInterpreterInfo(pythonBin, + new NullProgressMonitor(), false); + projectInterpreter.setName(project.getName()); + pythonInterpreterManager.setInfos(new IInterpreterInfo[] { projectInterpreter }, null, + new NullProgressMonitor()); + Log.logInfo("Configured!"); + try { + nature.setVersion(PythonNature.PYTHON_VERSION_INTERPRETER, project.getName()); + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private void updateInterpererInfo(PythonNature nature) { + IInterpreterManager pythonInterpreterManager = InterpreterManagersAPI.getPythonInterpreterManager(); + IInterpreterInfo[] infos = pythonInterpreterManager.getInterpreterInfos(); + IInterpreterInfo projectInterpreter = pythonInterpreterManager.createInterpreterInfo(pythonBin, + new NullProgressMonitor(), false); + projectInterpreter.setName(project.getName()); + Set existing = new HashSet(); + ArrayList newInfos = new ArrayList(); + for (IInterpreterInfo info : infos) { + existing.add(info.getName()); + newInfos.add(info); + } + newInfos.add(projectInterpreter); + pythonInterpreterManager.setInfos(newInfos.toArray(new IInterpreterInfo[newInfos.size()]), existing, + new NullProgressMonitor()); + + } + +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryLock.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryLock.java new file mode 100644 index 0000000000..1c9bd6ee82 --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryLock.java @@ -0,0 +1,17 @@ +package org.python.pydev.ui.actions.project; + +import org.python.pydev.ui.actions.container.PyPoetryAction; + +public class PoetryLock extends PyPoetryAction { + + @Override + protected String getTaskName() { + return "Locking project dependencies..."; + } + + @Override + protected String runCommand() { + return pm.lock(); + } + +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryRemove.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryRemove.java new file mode 100644 index 0000000000..bb476eef90 --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryRemove.java @@ -0,0 +1,32 @@ +/** + * + */ +package org.python.pydev.ui.actions.project; + +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.window.Window; +import org.python.pydev.shared_ui.EditorUtils; +import org.python.pydev.ui.actions.container.PyPoetryAction; + +/** + * + */ +public class PoetryRemove extends PyPoetryAction { + + @Override + protected String getTaskName() { + return "Removing python package..."; + } + + @Override + protected String runCommand() { + InputDialog dialog = new InputDialog(EditorUtils.getShell(), "App to remove", + "Name of the python App to remove", null, null); + int open = dialog.open(); + if (open != Window.OK) { + return ""; + } + String appName = dialog.getValue(); + return pm.remove(appName); + } +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetrySync.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetrySync.java new file mode 100644 index 0000000000..91a1cc9043 --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetrySync.java @@ -0,0 +1,17 @@ +package org.python.pydev.ui.actions.project; + +import org.python.pydev.ui.actions.container.PyPoetryAction; + +public class PoetrySync extends PyPoetryAction { + + @Override + protected String getTaskName() { + return "Syncronising project dependencies..."; + } + + @Override + protected String runCommand() { + return pm.sync(); + } + +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryUpdate.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryUpdate.java new file mode 100644 index 0000000000..fc85d63dac --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/PoetryUpdate.java @@ -0,0 +1,22 @@ +/** + * + */ +package org.python.pydev.ui.actions.project; + +import org.python.pydev.ui.actions.container.PyPoetryAction; + +/** + * + */ +public class PoetryUpdate extends PyPoetryAction { + + @Override + protected String getTaskName() { + return "Updating python packages..."; + } + + @Override + protected String runCommand() { + return pm.update(); + } +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVAdd.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVAdd.java new file mode 100644 index 0000000000..d6eeef29c1 --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVAdd.java @@ -0,0 +1,33 @@ +/** + * + */ +package org.python.pydev.ui.actions.project; + +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.window.Window; +import org.python.pydev.shared_ui.EditorUtils; +import org.python.pydev.ui.actions.container.PyUVAction; + +/** + * + */ +public class UVAdd extends PyUVAction { + + @Override + protected String getTaskName() { + return "Installing python package..."; + } + + @Override + protected String runCommand() { + InputDialog dialog = new InputDialog(EditorUtils.getShell(), "App to install", + "Name of the python App to install", null, null); + int open = dialog.open(); + if (open != Window.OK) { + return ""; + } + String appName = dialog.getValue(); + return pm.add(appName); + } + +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVLock.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVLock.java new file mode 100644 index 0000000000..902ca6ee8b --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVLock.java @@ -0,0 +1,17 @@ +package org.python.pydev.ui.actions.project; + +import org.python.pydev.ui.actions.container.PyUVAction; + +public class UVLock extends PyUVAction { + + @Override + protected String getTaskName() { + return "Locking project dependencies..."; + } + + @Override + protected String runCommand() { + return pm.lock(); + } + +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVRemove.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVRemove.java new file mode 100644 index 0000000000..ea4d184704 --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVRemove.java @@ -0,0 +1,33 @@ +/** + * + */ +package org.python.pydev.ui.actions.project; + +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.window.Window; +import org.python.pydev.shared_ui.EditorUtils; +import org.python.pydev.ui.actions.container.PyUVAction; + +/** + * + */ +public class UVRemove extends PyUVAction { + + @Override + protected String getTaskName() { + return "Installing python package..."; + } + + @Override + protected String runCommand() { + InputDialog dialog = new InputDialog(EditorUtils.getShell(), "App to remove", + "Name of the python App to remove", null, null); + int open = dialog.open(); + if (open != Window.OK) { + return ""; + } + String appName = dialog.getValue(); + return pm.remove(appName); + } + +} diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVSync.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVSync.java new file mode 100644 index 0000000000..4a8311d5ab --- /dev/null +++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/project/UVSync.java @@ -0,0 +1,17 @@ +package org.python.pydev.ui.actions.project; + +import org.python.pydev.ui.actions.container.PyUVAction; + +public class UVSync extends PyUVAction { + + @Override + protected String getTaskName() { + return "Syncronising project dependencies..."; + } + + @Override + protected String runCommand() { + return pm.sync(); + } + +}