diff --git a/make.py b/make.py index ed896854..773660d8 100644 --- a/make.py +++ b/make.py @@ -102,9 +102,6 @@ def _get_python_zip_file(self) -> Path: @property def package_index_markdown(self) -> str: """Generates a Markdown formatted package index page.""" - installed_tools_markdown = self._get_installed_tools_markdown() - installed_packages_markdown = self._get_installed_packages_markdown() - return f"""## WinPython {self.winpyver2 + self.flavor} The following packages are included in WinPython-{self.architecture_bits}bit v{self.winpyver2 + self.flavor} {self.release_level}. @@ -115,49 +112,17 @@ def package_index_markdown(self) -> str: Name | Version | Description -----|---------|------------ -{installed_tools_markdown} +{utils.get_installed_tools_markdown(utils.get_python_executable(self.python_executable_directory))} ### Python packages Name | Version | Description -----|---------|------------ -[Python](http://www.python.org/) | {self.python_full_version} | Python programming language with standard library -{installed_packages_markdown} +{self.distribution.get_installed_packages_markdown()} """ - def _get_installed_tools_markdown(self) -> str: - """Generates Markdown for installed tools section in package index.""" - tool_lines = [] - - if (nodejs_path := self.winpython_directory / NODEJS_RELATIVE_PATH).exists(): - version = utils.exec_shell_cmd("node -v", nodejs_path).splitlines()[0] - tool_lines.append(f"[Nodejs](https://nodejs.org) | {version} | xa JavaScript runtime built on Chrome's V8 JavaScript engine") - version = utils.exec_shell_cmd("npm -v", nodejs_path).splitlines()[0] - tool_lines.append(f"[npmjs](https://www.npmjs.com) | {version} | a package manager for JavaScript") - - if (pandoc_exe := self.winpython_directory / "t" / "pandoc.exe").exists(): - version = utils.exec_shell_cmd("pandoc -v", pandoc_exe.parent).splitlines()[0].split(" ")[-1] - tool_lines.append(f"[Pandoc](https://pandoc.org) | {version} | an universal document converter") - - if vscode_exe := (self.winpython_directory / "t" / "VSCode" / "Code.exe").exists(): - version = utils.getFileProperties(str(vscode_exe))["FileVersion"] - tool_lines.append(f"[VSCode](https://code.visualstudio.com) | {version} | a source-code editor developed by Microsoft") - - return "\n".join(tool_lines) - - def _get_installed_packages_markdown(self) -> str: - """Generates Markdown for installed packages section in package index.""" - if not self.distribution: - return "" # Distribution not initialized yet. - self.installed_packages = self.distribution.get_installed_packages(update=True) - package_lines = [ - f"[{pkg.name}]({pkg.url}) | {pkg.version} | {pkg.description}" - for pkg in sorted(self.installed_packages, key=lambda p: p.name.lower()) - ] - return "\n".join(package_lines) - @property def winpython_version_name(self) -> str: """Returns the full WinPython version string.""" diff --git a/portable/build_my_launchers.bat b/portable/build_my_launchers.bat index 04c4671e..35fa6e65 100644 --- a/portable/build_my_launchers.bat +++ b/portable/build_my_launchers.bat @@ -7,12 +7,17 @@ set VCVARS_PATH="C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\ rem pick the right ones and rename them in launchers_final set do_launcher=%~dp0launchers_src\build_one_launcher.bat +set do_launcher_original=%~dp0launchers_src_original\build_one_launcher.bat ::WINDOWS launchers -call %do_launcher% "powershell.ico" "cmd_ps.bat" "WinPython Powershell Prompt" WINDOWS +call %do_launcher% "python.ico" "winidle.bat" "IDLE (Python GUI)" WINDOWS +echo displace this pause if you want to re-build more pause -call %do_launcher% "python.ico" "winidle.bat" "IDLE (Python GUI)" WINDOWS +exit + + +call %do_launcher% "powershell.ico" "cmd_ps.bat" "WinPython Powershell Prompt" WINDOWS call %do_launcher% "spyder.ico" "winspyder.bat" "Spyder" WINDOWS call %do_launcher% "spyder_reset.ico" "spyder_reset.bat" "Spyder reset" WINDOWS call %do_launcher% "code.ico" "winvscode.bat" "VS Code" WINDOWS diff --git a/portable/launchers_final_original/IDLE (Python GUI).exe b/portable/launchers_final_original/IDLE (Python GUI).exe new file mode 100644 index 00000000..c1e0c9dc Binary files /dev/null and b/portable/launchers_final_original/IDLE (Python GUI).exe differ diff --git a/portable/launchers_final_original/Jupyter Lab.exe b/portable/launchers_final_original/Jupyter Lab.exe new file mode 100644 index 00000000..98bb8bde Binary files /dev/null and b/portable/launchers_final_original/Jupyter Lab.exe differ diff --git a/portable/launchers_final_original/Jupyter Notebook.exe b/portable/launchers_final_original/Jupyter Notebook.exe new file mode 100644 index 00000000..5d59af59 Binary files /dev/null and b/portable/launchers_final_original/Jupyter Notebook.exe differ diff --git a/portable/launchers_final_original/Spyder reset.exe b/portable/launchers_final_original/Spyder reset.exe new file mode 100644 index 00000000..21250f98 Binary files /dev/null and b/portable/launchers_final_original/Spyder reset.exe differ diff --git a/portable/launchers_final_original/Spyder.exe b/portable/launchers_final_original/Spyder.exe new file mode 100644 index 00000000..43874aa7 Binary files /dev/null and b/portable/launchers_final_original/Spyder.exe differ diff --git a/portable/launchers_final_original/VS Code.exe b/portable/launchers_final_original/VS Code.exe new file mode 100644 index 00000000..225decb4 Binary files /dev/null and b/portable/launchers_final_original/VS Code.exe differ diff --git a/portable/launchers_final_original/WinPython Command Prompt.exe b/portable/launchers_final_original/WinPython Command Prompt.exe new file mode 100644 index 00000000..e4e824c5 Binary files /dev/null and b/portable/launchers_final_original/WinPython Command Prompt.exe differ diff --git a/portable/launchers_final_original/WinPython Control Panel.exe b/portable/launchers_final_original/WinPython Control Panel.exe new file mode 100644 index 00000000..5795bf9c Binary files /dev/null and b/portable/launchers_final_original/WinPython Control Panel.exe differ diff --git a/portable/launchers_final_original/WinPython Interpreter.exe b/portable/launchers_final_original/WinPython Interpreter.exe new file mode 100644 index 00000000..dfa43135 Binary files /dev/null and b/portable/launchers_final_original/WinPython Interpreter.exe differ diff --git a/portable/launchers_final_original/WinPython Powershell Prompt.exe b/portable/launchers_final_original/WinPython Powershell Prompt.exe new file mode 100644 index 00000000..d4512f32 Binary files /dev/null and b/portable/launchers_final_original/WinPython Powershell Prompt.exe differ diff --git a/portable/launchers_src_original/LICENSE b/portable/launchers_src_original/LICENSE new file mode 100644 index 00000000..b3fb976c --- /dev/null +++ b/portable/launchers_src_original/LICENSE @@ -0,0 +1,63 @@ +DataLab-WinPython license terms +=============================== + +DataLab-WinPython is a Python distribution for Windows: +- Based on WinPython, a portable distribution of Python for Windows (see section I. below). +- Including DataLab, an open-source platform for signal and image processing (see section II. below). + +I. - WinPython License Agreement (MIT License) +---------------------------------------------- + +Copyright (c) 2012 Pierre Raybaut, 2016+ WinPython team + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +II. - DataLab License Agreement (BSD 3-Clause License) +------------------------------------------------------ + +Copyright (c) 2023, DataLab Platform Developers. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/portable/launchers_src_original/build_one_launcher.bat b/portable/launchers_src_original/build_one_launcher.bat new file mode 100644 index 00000000..233f68de --- /dev/null +++ b/portable/launchers_src_original/build_one_launcher.bat @@ -0,0 +1,107 @@ +@echo on +set icon_name=%1 +set LAUNCH_TARGET=%2 +set launcher_name=%3 +set subsystem=%4 + +set icon_name=%icon_name:"=% +set LAUNCH_TARGET=%LAUNCH_TARGET:"=% +set launcher_name=%launcher_name:"=% +set subsystem=%subsystem:"=% + +set ROOT_PATH=%~dp0..\ +set SCRIPT_PATH=%~dp0 +set TEMPO_PATH=%ROOT_PATH%launchers_temp +set OUTPUT_DIR=%ROOT_PATH%launchers_final + +set "ICON_FILE=%ROOT_PATH%icons\%icon_name%" +set LAUNCHER_EXE=%OUTPUT_DIR%\%launcher_name%.exe + + +:: Paths to template WINDOWS or CONSOLE +set SOURCE_FILE=%SCRIPT_PATH%launcher_template_%subsystem%.cpp +echo SOURCE_FILE=%SOURCE_FILE% + +set "RESOURCE_FILE=%TEMPO_PATH%\%icon_name%.rc" +set "RESOURCE_OBJ=%TEMPO_PATH%\%icon_name%.res" + + +:: create pDirectory if needed +if not exist "%OUTPUT_DIR%" mkdir "%OUTPUT_DIR%" +if not exist "%TEMPO_PATH%" mkdir "%TEMPO_PATH%" + +cd/d %TEMPO_PATH% + +:: Check if MSVC environment is already initialized +if not defined VSINSTALLDIR ( + echo Initializing MSVC environment... + call %VCVARS_PATH% + if errorlevel 1 ( + echo [ERROR] Failed to initialize MSVC environment. + exit /b 1 + ) +) + +@echo on + +:: Walk through .bat files in the current directory + echo Processing %icon_name%.. + :: Stonebig: Remove previous .exe file + echo launcher_exe_action del /q "%LAUNCHER_EXE%" + if exist "%LAUNCHER_EXE%" ( + move "%LAUNCHER_EXE%" "%LAUNCHER_EXE%.old.exe" + del /q "%LAUNCHER_EXE%.old.exe" + ) + :: Stonebig: Remove intermediate .res and.rc file + if exist "%RESOURCE_OBJ%" ( + move "%RESOURCE_OBJ%" "%RESOURCE_OBJ%.old.exe" + del /q "%RESOURCE_OBJ%.old.exe" + ) + if exist "%RESOURCE_FILE%" ( + move "%RESOURCE_FILE%" "%RESOURCE_FILE%.old.exe" + del /q "%RESOURCE_FILE%.old.exe" + ) + :: Remove intermediate .obj file + del /q "launcher_template_%subsystem%.obj" + + :: Check if the icon exists + if exist "%ICON_FILE%" ( + echo Icon found: "%ICON_FILE%" + ) else ( + echo No icon found for "%ICON_FILE%" stoping + pause + exit + ) + + + :: Create resource file + echo Creating resource file... + > "%RESOURCE_FILE%" echo IDI_ICON1 ICON "%ICON_FILE%" + :: Compile resource + echo Compiling resource... + rc /fo "%RESOURCE_OBJ%" "%RESOURCE_FILE%" + + :: Compile the launcher executable + echo Compiling launcher executable... + cl /EHsc /O2 /DUNICODE /W4 "%SOURCE_FILE%" "%RESOURCE_OBJ%" ^ + /Fe"%LAUNCHER_EXE%%" ^ + /DLAUNCH_TARGET=\"%LAUNCH_TARGET%\" ^ + User32.lib ^ + /link /SUBSYSTEM:%subsystem% + + + if errorlevel 1 ( + echo [ERROR] Failed to build launcher for %LAUNCH_TARGET% + exit /b 1 + ) + + if exist "%LAUNCHER_EXE%" ( + echo [SUCCESS] Launcher created: "%LAUNCHER_EXE%"" + ) else ( + echo [ERROR] Failed to build launcher "%LAUNCHER_EXE%" from "%icon_name%" to call "%LAUNCH_TARGET%" + exit /b 1 + ) + +echo All launchers processed. +rem exit /b 0 + diff --git a/portable/launchers_src_original/launcher_template_CONSOLE.cpp b/portable/launchers_src_original/launcher_template_CONSOLE.cpp new file mode 100644 index 00000000..93614b9e --- /dev/null +++ b/portable/launchers_src_original/launcher_template_CONSOLE.cpp @@ -0,0 +1,75 @@ +/* +DataLab-WinPython launcher script +--------------------------------- + +Licensed under the terms of the BSD 3-Clause +(see ./LICENSE for details) + +*/ + +#include +#include + +int main() { + // Get the path to the current executable + wchar_t exePath[MAX_PATH]; + GetModuleFileNameW(NULL, exePath, MAX_PATH); + + // Determine the directory of the executable + std::wstring exeDir = exePath; + exeDir = exeDir.substr(0, exeDir.find_last_of(L"\\/")); + + // Define the path to the "scripts" directory + std::wstring scriptsDir = exeDir + L"\\scripts"; + + // Check if the "scripts" directory exists + DWORD attributes = GetFileAttributesW(scriptsDir.c_str()); + if (attributes == INVALID_FILE_ATTRIBUTES || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) { + MessageBoxW(NULL, L"The 'scripts' directory does not exist. Please ensure it is in the same folder as the launcher.", + L"Launcher Error", MB_ICONERROR); + return 1; + } + + // Set the working directory to the "scripts" folder + if (!SetCurrentDirectoryW(scriptsDir.c_str())) { + MessageBoxW(NULL, L"Failed to set the working directory to 'scripts'.", + L"Launcher Error", MB_ICONERROR); + return 1; + } + + // Define the command to run + std::wstring target = L"cmd.exe /c \"" LAUNCH_TARGET L"\""; + + // Configure the process startup info + STARTUPINFO si = { sizeof(si) }; + si.dwFlags = STARTF_USESHOWWINDOW; // Prevent the window from appearing + si.wShowWindow = SW_HIDE; // Hide the command window + + PROCESS_INFORMATION pi = {}; + + // Start the process without CREATE_NO_WINDOW flag to show the command window + if (!CreateProcessW( + NULL, // Application name (NULL because we pass the command in the command line) + &target[0], // Command line + NULL, // Process security attributes + NULL, // Thread security attributes + FALSE, // Inherit handles + 0, // No special flags + NULL, // Environment block (NULL to inherit parent) + NULL, // Current directory (NULL to use the parent process's current directory) + &si, // Startup info + &pi // Process information + )) { + MessageBoxW(NULL, L"Failed to launch the script.", L"Launcher Error", MB_ICONERROR); + return 1; + } + + // Wait for the script to finish + WaitForSingleObject(pi.hProcess, INFINITE); + + // Cleanup + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + return 0; +} diff --git a/portable/launchers_src_original/launcher_template_WINDOWS.cpp b/portable/launchers_src_original/launcher_template_WINDOWS.cpp new file mode 100644 index 00000000..9c878be6 --- /dev/null +++ b/portable/launchers_src_original/launcher_template_WINDOWS.cpp @@ -0,0 +1,75 @@ +/* +DataLab-WinPython launcher script +--------------------------------- + +Licensed under the terms of the BSD 3-Clause +(see ./LICENSE for details) + +*/ + +#include +#include + +int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/) { + // Get the path to the current executable + wchar_t exePath[MAX_PATH]; + GetModuleFileNameW(NULL, exePath, MAX_PATH); + + // Determine the directory of the executable + std::wstring exeDir = exePath; + exeDir = exeDir.substr(0, exeDir.find_last_of(L"\\/")); + + // Define the path to the "scripts" directory + std::wstring scriptsDir = exeDir + L"\\scripts"; + + // Check if the "scripts" directory exists + DWORD attributes = GetFileAttributesW(scriptsDir.c_str()); + if (attributes == INVALID_FILE_ATTRIBUTES || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) { + MessageBoxW(NULL, L"The 'scripts' directory does not exist. Please ensure it is in the same folder as the launcher.", + L"Launcher Error", MB_ICONERROR); + return 1; + } + + // Set the working directory to the "scripts" folder + if (!SetCurrentDirectoryW(scriptsDir.c_str())) { + MessageBoxW(NULL, L"Failed to set the working directory to 'scripts'.", + L"Launcher Error", MB_ICONERROR); + return 1; + } + + // Define the command to run + std::wstring target = L"cmd.exe /c \"" LAUNCH_TARGET L"\""; + + // Configure the process startup info + STARTUPINFO si = { sizeof(si) }; + si.dwFlags = STARTF_USESHOWWINDOW; // Prevent the window from appearing + si.wShowWindow = SW_HIDE; // Hide the command window + + PROCESS_INFORMATION pi = {}; + + // Start the process with CREATE_NO_WINDOW flag + if (!CreateProcessW( + NULL, // Application name (NULL because we pass the command in the command line) + &target[0], // Command line + NULL, // Process security attributes + NULL, // Thread security attributes + FALSE, // Inherit handles + CREATE_NO_WINDOW, // Flags to prevent creating a window + NULL, // Environment block (NULL to inherit parent) + NULL, // Current directory (NULL to use the parent process's current directory) + &si, // Startup info + &pi // Process information + )) { + MessageBoxW(NULL, L"Failed to launch the script.", L"Launcher Error", MB_ICONERROR); + return 1; + } + + // Wait for the script to finish + WaitForSingleObject(pi.hProcess, INFINITE); + + // Cleanup + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + return 0; +} diff --git a/winpython/__init__.py b/winpython/__init__.py index 32bccb82..b865bf4c 100644 --- a/winpython/__init__.py +++ b/winpython/__init__.py @@ -28,6 +28,6 @@ OTHER DEALINGS IN THE SOFTWARE. """ -__version__ = '15.3.20250425' +__version__ = '15.4.20250507' __license__ = __doc__ __project_url__ = 'http://winpython.github.io/' diff --git a/winpython/utils.py b/winpython/utils.py index 98a2b1f0..40961ec1 100644 --- a/winpython/utils.py +++ b/winpython/utils.py @@ -43,6 +43,26 @@ def get_site_packages_path(path=None): pypy_site_packages = base_dir / 'site-packages' # For PyPy return str(pypy_site_packages if pypy_site_packages.is_dir() else site_packages) +def get_installed_tools_markdown(path=None)-> str: + """Generates Markdown for installed tools section in package index.""" + tool_lines = [] + python_exe = Path(get_python_executable(path)) + version = exec_shell_cmd(f'powershell (Get-Item {python_exe}).VersionInfo.FileVersion', python_exe.parent).splitlines()[0] + tool_lines.append(f"[Python](http://www.python.org/) | {version} | Python programming language with standard library") + if (node_exe := python_exe.parent.parent / "n" / "node.exe").exists(): + version = exec_shell_cmd(f'powershell (Get-Item {node_exe}).VersionInfo.FileVersion', node_exe.parent).splitlines()[0] + tool_lines.append(f"[Nodejs](https://nodejs.org) | {version} | a JavaScript runtime built on Chrome's V8 JavaScript engine") + + if (pandoc_exe := python_exe.parent.parent / "t" / "pandoc.exe").exists(): + version = exec_shell_cmd("pandoc -v", pandoc_exe.parent).splitlines()[0].split(" ")[-1] + tool_lines.append(f"[Pandoc](https://pandoc.org) | {version} | an universal document converter") + + if (vscode_exe := python_exe.parent.parent / "t" / "VSCode" / "Code.exe").exists(): + version = exec_shell_cmd(f'powershell (Get-Item {vscode_exe}).VersionInfo.FileVersion', vscode_exe.parent).splitlines()[0] + tool_lines.append(f"[VSCode](https://code.visualstudio.com) | {version} | a source-code editor developed by Microsoft") + return "\n".join(tool_lines) + + def onerror(function, path, excinfo): """Error handler for `shutil.rmtree`.""" if not os.access(path, os.W_OK): diff --git a/winpython/wppm.py b/winpython/wppm.py index 34e3c9da..e24ca6c2 100644 --- a/winpython/wppm.py +++ b/winpython/wppm.py @@ -74,17 +74,21 @@ def create_file(self, package, name, dstdir, contents): def get_installed_packages(self, update: bool = False) -> list[Package]: """Return installed packages.""" - - # Include package installed via pip (not via WPPM) if str(Path(sys.executable).parent) == self.target: self.pip = piptree.PipData() else: self.pip = piptree.PipData(utils.get_python_executable(self.target)) pip_list = self.pip.pip_list(full=True) - - # return a list of package objects return [Package(f"{i[0].replace('-', '_').lower()}-{i[1]}-py3-none-any.whl", suggested_summary=i[2]) for i in pip_list] + def get_installed_packages_markdown(self) -> str: + """Generates Markdown for installed packages section in package index.""" + package_lines = [ + f"[{pkg.name}]({pkg.url}) | {pkg.version} | {pkg.description}" + for pkg in sorted(self.get_installed_packages(), key=lambda p: p.name.lower()) + ] + return "\n".join(package_lines) + def find_package(self, name: str) -> Package | None: """Find installed package by name.""" for pack in self.get_installed_packages():