Skip to content

Commit 194d589

Browse files
committed
make 4 launchers NSIS-free, remains 7 NSIS
1 parent 6b3d412 commit 194d589

File tree

1 file changed

+198
-16
lines changed

1 file changed

+198
-16
lines changed

make.py

Lines changed: 198 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,87 @@ def build_nsis(srcname, dstname, data):
196196
print("Execution failed:", e, file=sys.stderr)
197197
os.remove(dstname)
198198

199+
def checkPath(path, mode):
200+
""" from https://gist.github.com/flyx/2965682 """
201+
import os, os.path
202+
if not os.path.exists(path) or not os.path.isfile(path):
203+
raise ValueError("{0} does not exist or isn't a file.".format(path))
204+
if not os.access(path, mode):
205+
raise ValueError("Insufficient permissions: {0}".format(path))
206+
207+
def updateExecutableIcon(executablePath, iconPath):
208+
""" from https://gist.github.com/flyx/2965682 """
209+
import win32api, win32con
210+
import struct
211+
import math
212+
"""
213+
Updates the icon of a Windows executable file.
214+
"""
215+
216+
checkPath(executablePath, os.W_OK)
217+
checkPath(iconPath, os.R_OK)
218+
219+
handle = win32api.BeginUpdateResource(executablePath, False)
220+
221+
icon = open(iconPath, "rb")
222+
223+
fileheader = icon.read(6)
224+
225+
# Read icon data
226+
image_type, image_count = struct.unpack("xxHH", fileheader)
227+
print ("Icon file has type {0} and contains {1} images.".format(image_type, image_count))
228+
229+
icon_group_desc = struct.pack("<HHH", 0, image_type, image_count)
230+
icon_sizes = []
231+
icon_offsets = []
232+
233+
# Read data of all included icons
234+
for i in range(1, image_count + 1):
235+
imageheader = icon.read(16)
236+
width, height, colors, panes, bits_per_pixel, image_size, offset =\
237+
struct.unpack("BBBxHHLL", imageheader)
238+
print ("Image is {0}x{1}, has {2} colors in the palette, {3} planes, {4} bits per pixel.".format(
239+
width, height, colors, panes, bits_per_pixel));
240+
print ("Image size is {0}, the image content has an offset of {1}".format(image_size, offset));
241+
242+
icon_group_desc = icon_group_desc + struct.pack("<BBBBHHIH",
243+
width, # Icon width
244+
height, # Icon height
245+
colors, # Colors (0 for 256 colors)
246+
0, # Reserved2 (must be 0)
247+
panes, # Color planes
248+
bits_per_pixel, # Bits per pixel
249+
image_size, # ImageSize
250+
i # Resource ID
251+
)
252+
icon_sizes.append(image_size)
253+
icon_offsets.append(offset)
254+
255+
# Read icon content and write it to executable file
256+
for i in range(1, image_count + 1):
257+
icon_content = icon.read(icon_sizes[i - 1])
258+
print ("Read {0} bytes for image #{1}".format(len(icon_content), i))
259+
win32api.UpdateResource(handle, win32con.RT_ICON, i, icon_content)
260+
261+
win32api.UpdateResource(handle, win32con.RT_GROUP_ICON, "MAINICON", icon_group_desc)
262+
263+
win32api.EndUpdateResource(handle, False)
264+
265+
266+
def build_shimmy_launcher(launcher_name, command, icon_path):
267+
"""Build shimmy script"""
268+
# access to mkshim.py
269+
# define where is mkshim
270+
mkshim_program = str(Path(__file__).resolve().parent / "mkshim.py")
271+
python_program = utils.get_python_executable()
272+
273+
# Create the executable using mkshim
274+
mkshim_command = f'{python_program} "{mkshim_program}" -f "{launcher_name}" -c "{command}"'
275+
print("zzzz Building shimmy:", mkshim_command)
276+
subprocess.run(mkshim_command, shell=True)
277+
278+
# Embed the icon pywin32
279+
updateExecutableIcon(launcher_name, icon_path)
199280

200281
def build_iss(srcname, dstname, data):
201282
"""Build Inno Setup Script"""
@@ -511,6 +592,48 @@ def create_batch_script(self, name, contents, do_changes=None):
511592
fd.write(contents_final)
512593
fd.close()
513594

595+
def create_launcher_shimmy(
596+
self,
597+
name,
598+
icon,
599+
command=None,
600+
args=None,
601+
workdir=r"$EXEDIR\scripts",
602+
launcher="launcher_basic.nsi",
603+
):
604+
"""Create exe launcher with NSIS"""
605+
assert name.endswith(".exe")
606+
portable_dir = str(Path(__file__).resolve().parent / "portable")
607+
icon_fname = str(Path(portable_dir) / "icons" / icon)
608+
assert Path(icon_fname).is_file()
609+
610+
# Customizing NSIS script
611+
if command is None:
612+
if args is not None and ".pyw" in args:
613+
command = "${WINPYDIR}\pythonw.exe"
614+
else:
615+
command = "${WINPYDIR}\python.exe"
616+
if args is None:
617+
args = ""
618+
if workdir is None:
619+
workdir = ""
620+
fname = str(Path(self.winpydir) / (Path(name).stem + ".nsi"))
621+
622+
data = [
623+
("WINPYDIR", f"$EXEDIR\{self.python_name}"),
624+
("WINPYVER", self.winpyver),
625+
("COMMAND", command),
626+
("PARAMETERS", args),
627+
("WORKDIR", workdir),
628+
("Icon", icon_fname),
629+
("OutFile", name),
630+
]
631+
iconlauncherfullname= str(Path(self.winpydir) / name)
632+
633+
print("yyyy Buildin shimmy:", iconlauncherfullname, command , icon_fname)
634+
true_command = command.replace(r"$SYSDIR\cmd.exe","cmd.exe")+ " " + args
635+
build_shimmy_launcher(iconlauncherfullname, true_command, icon_fname)
636+
514637
def create_launcher(
515638
self,
516639
name,
@@ -718,31 +841,55 @@ def _create_launchers(self):
718841
"""Create launchers"""
719842

720843
self._print("Creating launchers")
721-
self.create_launcher(
844+
845+
self.create_launcher_shimmy(
722846
"WinPython Command Prompt.exe",
723847
"cmd.ico",
724-
command="$SYSDIR\cmd.exe",
725-
args=r"/k cmd.bat",
848+
#command="$SYSDIR\cmd.exe",
849+
#args=r"/k cmd.bat",
850+
command="scripts\\cmd.bat",
851+
args=r"",
726852
)
853+
727854
self.create_launcher(
728855
"WinPython Powershell Prompt.exe",
729856
"powershell.ico",
730857
command="$SYSDIR\cmd.exe",
731858
args=r"/k cmd_ps.bat",
732859
)
733860

861+
#not yet: workdirectory = icon directory
862+
# self.create_launcher_shimmy(
863+
# "WinPython Powershell PromptShimmy.exe",
864+
# "powershell.ico",
865+
# #command="$SYSDIR\cmd.exe",
866+
# #args=r"/k scripts\\cmd_ps.bat",
867+
# command="scripts\\cmd_ps.bat",
868+
# args=r"",
869+
#)
870+
734871
self.create_launcher(
735872
"WinPython Terminal.exe",
736873
"terminal.ico",
737874
command="wscript.exe",
738875
args=r"Noshell.vbs WinPython_Terminal.bat",
739876
)
740877

741-
self.create_launcher(
878+
#not yet: workdirectory = icon directory
879+
#self.create_launcher_shimmy(
880+
# "WinPython TerminalShimmy.exe",
881+
# "terminal.ico",
882+
# command="wscript.exe",
883+
# args=r"scripts\\Noshell.vbs scripts\\WinPython_Terminal.bat",
884+
#)
885+
886+
self.create_launcher_shimmy(
742887
"WinPython Interpreter.exe",
743888
"python.ico",
744-
command="$SYSDIR\cmd.exe",
745-
args=r"/k winpython.bat",
889+
#command="$SYSDIR\cmd.exe",
890+
#args=r"/k scripts\\winpython.bat",
891+
command="scripts\\winpython.bat",
892+
args=r"",
746893
)
747894

748895
self.create_launcher(
@@ -752,32 +899,60 @@ def _create_launchers(self):
752899
args=r"Noshell.vbs winidle.bat",
753900
)
754901

902+
#not yet: dos window behind
903+
#self.create_launcher_shimmy(
904+
# "IDLE (Python GUI)Shimmy.exe",
905+
# "python.ico",
906+
# command="wscript.exe",
907+
# args=r"scripts\\Noshell.vbs scripts\\winidle.bat",
908+
#command="scripts\\Noshell.vbs scripts\\winidle.bat",
909+
#args=r"",
910+
#)
911+
755912
self.create_launcher(
756913
"Spyder.exe",
757914
"spyder.ico",
758915
command="wscript.exe",
759916
args=r"Noshell.vbs winspyder.bat",
760917
)
761918

919+
#not yet
920+
#self.create_launcher_shimmy(
921+
# "SpyderShimmy.exe",
922+
# "spyder.ico",
923+
# command="wscript.exe",
924+
# args=r"scripts\\Noshell.vbs scripts\\winspyder.bat",
925+
#)
926+
762927
self.create_launcher(
763928
"Spyder reset.exe",
764929
"spyder_reset.ico",
765930
command="wscript.exe",
766-
args=r"Noshell.vbs spyder_reset.bat",
931+
args=r"scripts\\Noshell.vbs scripts\\spyder_reset.bat",
767932
)
768933

769-
self.create_launcher(
934+
#not yet
935+
#self.create_launcher_shimmy(
936+
# "Spyder reset.exe",
937+
# "spyder_reset.ico",
938+
# command="wscript.exe",
939+
# args=r"scripts\\Noshell.vbs scripts\\spyder_reset.bat",
940+
#)
941+
942+
943+
self.create_launcher_shimmy(
770944
"WinPython Control Panel.exe",
771945
"winpython.ico",
772946
# command="wscript.exe",
773947
# args=r"Noshell.vbs wpcp.bat",
774-
command="$SYSDIR\cmd.exe",
775-
args=r"/k wpcp.bat",
948+
#command="$SYSDIR\cmd.exe",
949+
#args=r"/k scripts\\wpcp.bat",
950+
command="scripts\\wpcp.bat",
951+
args=r"",
776952
)
777953

778954
# Jupyter launchers
779955

780-
# removing another Qt string
781956
# self.create_launcher(
782957
# "IPython Qt Console.exe",
783958
# "ipython.ico",
@@ -802,11 +977,11 @@ def _create_launchers(self):
802977
)
803978

804979
# VSCode launcher
805-
self.create_launcher(
806-
"VS Code.exe",
980+
self.create_launcher_shimmy(
981+
"VS CodeShimmy.exe",
807982
"code.ico",
808983
command="wscript.exe",
809-
args=r"Noshell.vbs winvscode.bat",
984+
args=r"scripts\\Noshell.vbs scripts\\winvscode.bat",
810985
)
811986

812987
self._print_done()
@@ -1203,8 +1378,8 @@ def _create_batch_scripts_initial(self):
12031378
)
12041379
)
12051380
) else (
1206-
rem if it is launched from another directory , we keep it that one echo %__CD__%
1207-
if not "%__CD__%"=="%~dp0" set WINPYWORKDIR1="%__CD__%"
1381+
rem if it is launched from another directory than icon origin , we keep it that one echo %__CD__%
1382+
if not "%__CD__%"=="%~dp0" if not "%__CD__%scripts\"=="%~dp0" set WINPYWORKDIR1="%__CD__%"
12081383
)
12091384
rem remove potential doublequote
12101385
set WINPYWORKDIR1=%WINPYWORKDIR1:"=%
@@ -1214,6 +1389,13 @@ def _create_batch_scripts_initial(self):
12141389
FOR /F "delims=" %%i IN ('cscript /nologo "%~dp0WinpythonIni.vbs"') DO set winpythontoexec=%%i
12151390
%winpythontoexec%set winpythontoexec=
12161391
1392+
rem 2024-08-18: we go initial directory WINPYWORKDIR if no direction and we are on icon directory
1393+
rem old NSIS launcher is by default at icon\scripts level
1394+
if "%__CD__%scripts\"=="%~dp0" if "%WINPYWORKDIR1%"=="%WINPYDIRBASE%\Notebooks" cd/D %WINPYWORKDIR1%
1395+
rem new shimmy launcher is by default at icon level
1396+
if "%__CD__%"=="%~dp0" if "%WINPYWORKDIR1%"=="%WINPYDIRBASE%\Notebooks" cd/D %WINPYWORKDIR1%
1397+
1398+
12171399
rem ******************
12181400
rem missing student directory part
12191401
rem ******************

0 commit comments

Comments
 (0)