-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtemplate.nsi
1344 lines (1182 loc) · 43.9 KB
/
template.nsi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Installer template file for creating a Windows installer using NSIS.
# Dependencies:
# NSIS >=3.08 conda install "nsis>=3.08" (includes extra unicode plugins)
Unicode "true"
#if enable_debugging is True
# Special logging build needed for ENABLE_LOGGING
# See https://nsis.sourceforge.io/Special_Builds
!define ENABLE_LOGGING
#endif
# Comes from https://nsis.sourceforge.io/Logging:Enable_Logs_Quickly
!define LogSet "!insertmacro LogSetMacro"
!macro LogSetMacro SETTING
!ifdef ENABLE_LOGGING
LogSet ${SETTING}
!endif
!macroend
!define LogText "!insertmacro LogTextMacro"
!macro LogTextMacro INPUT_TEXT
!ifdef ENABLE_LOGGING
LogText ${INPUT_TEXT}
!endif
!macroend
!include "WinMessages.nsh"
!include "WordFunc.nsh"
!include "LogicLib.nsh"
!include "WinVer.nsh"
!include "MUI2.nsh"
!include "x64.nsh"
!include "FileFunc.nsh"
!insertmacro GetParameters
!insertmacro GetOptions
!include "UAC.nsh"
!include "nsDialogs.nsh"
!include "Utils.nsh"
!define NAME __NAME__
!define VERSION __VERSION__
!define COMPANY __COMPANY__
!define ARCH __ARCH__
!define PLATFORM __PLATFORM__
!define CONSTRUCTOR_VERSION __CONSTRUCTOR_VERSION__
!define PY_VER __PY_VER__
!define PYVERSION_JUSTDIGITS __PYVERSION_JUSTDIGITS__
!define PYVERSION __PYVERSION__
!define PYVERSION_MAJOR __PYVERSION_MAJOR__
!define DEFAULT_PREFIX __DEFAULT_PREFIX__
!define DEFAULT_PREFIX_DOMAIN_USER __DEFAULT_PREFIX_DOMAIN_USER__
!define DEFAULT_PREFIX_ALL_USERS __DEFAULT_PREFIX_ALL_USERS__
!define PRE_INSTALL_DESC __PRE_INSTALL_DESC__
!define POST_INSTALL_DESC __POST_INSTALL_DESC__
!define MENU_PKGS "@MENU_PKGS@"
!define SHOW_REGISTER_PYTHON __SHOW_REGISTER_PYTHON__
!define SHOW_ADD_TO_PATH __SHOW_ADD_TO_PATH__
!define PRODUCT_NAME "${NAME} ${VERSION} (${ARCH})"
!define UNINSTALL_NAME "@UNINSTALL_NAME@"
!define UNINSTREG "SOFTWARE\Microsoft\Windows\CurrentVersion\
\Uninstall\${UNINSTALL_NAME}"
var /global INSTDIR_JUSTME
var /global INSTALLER_VERSION
var /global INSTALLER_NAME_FULL
# UAC shield overlay
!ifndef BCM_SETSHIELD
!define BCM_SETSHIELD 0x0000160C
!endif
var /global ARGV
var /global ARGV_Help
var /global ARGV_InstallationType
var /global ARGV_AddToPath
var /global ARGV_KeepPkgCache
var /global ARGV_RegisterPython
var /global ARGV_NoRegistry
var /global ARGV_NoScripts
var /global ARGV_NoShortcuts
var /global ARGV_CheckPathLength
var /global IsDomainUser
var /global CheckPathLength
var /global LongPathsEnabled
var /global InstDirLen
var /global InstModePage_RadioButton_JustMe
var /global InstModePage_RadioButton_AllUsers
var /global InstMode # 0 = Just Me, 1 = All Users.
!define JUST_ME 0
!define ALL_USERS 1
# Include this one after our defines
!include "OptionsDialog.nsh"
CRCCheck On
# Basic options
Name "${PRODUCT_NAME}"
OutFile __OUTFILE__
ShowInstDetails "hide"
ShowUninstDetails "hide"
# This installer contains tar.bz2 files, which are already compressed
SetCompress "off"
# Start off with the lowest permissions and work our way up.
RequestExecutionLevel user
# Version information & branding text
VIAddVersionKey "ProductName" "${PRODUCT_NAME}"
VIAddVersionKey "FileVersion" "${VERSION}"
VIAddVersionKey "ProductVersion" "${VERSION}"
VIAddVersionKey "CompanyName" "${COMPANY}"
VIAddVersionKey "LegalCopyright" "(c) ${COMPANY}"
VIAddVersionKey "FileDescription" "${NAME} Installer"
VIAddVersionKey "Comments" "Created by constructor ${CONSTRUCTOR_VERSION}"
VIProductVersion __VIPV__
BrandingText /TRIMLEFT "${COMPANY}"
# Interface configuration
!define MUI_ICON __ICONFILE__
!define MUI_UNICON __ICONFILE__
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP __HEADERIMAGE__
!define MUI_HEADERIMAGE_UNBITMAP __HEADERIMAGE__
!define MUI_ABORTWARNING
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
!define MUI_WELCOMEFINISHPAGE_BITMAP __WELCOMEIMAGE__
!define MUI_UNWELCOMEFINISHPAGE_BITMAP __WELCOMEIMAGE__
#!define MUI_CUSTOMFUNCTION_GUIINIT GuiInit
# Pages
#!define MUI_PAGE_CUSTOMFUNCTION_SHOW OnStartup
#if custom_welcome
# Custom welcome file(s)
@CUSTOM_WELCOME_FILE@
#else
!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipPageIfUACInnerInstance
!insertmacro MUI_PAGE_WELCOME
#endif
!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipPageIfUACInnerInstance
!insertmacro MUI_PAGE_LICENSE __LICENSEFILE__
Page Custom InstModePage_Create InstModePage_Leave
!define MUI_PAGE_CUSTOMFUNCTION_PRE DisableBackButtonIfUACInnerInstance
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE OnDirectoryLeave
!insertmacro MUI_PAGE_DIRECTORY
# Custom options now differ depending on installation mode.
Page Custom mui_AnaCustomOptions_Show
!insertmacro MUI_PAGE_INSTFILES
#if with_conclusion_text is True
!define MUI_FINISHPAGE_TITLE __CONCLUSION_TITLE__
!define MUI_FINISHPAGE_TITLE_3LINES
!define MUI_FINISHPAGE_TEXT __CONCLUSION_TEXT__
#endif
#if custom_conclusion
# Custom conclusion file(s)
@CUSTOM_CONCLUSION_FILE@
#else
!insertmacro MUI_PAGE_FINISH
#endif
!insertmacro MUI_UNPAGE_WELCOME
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE un.OnDirectoryLeave
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
# Language
!insertmacro MUI_LANGUAGE "English"
Function SkipPageIfUACInnerInstance
${LogSet} on
${If} ${UAC_IsInnerInstance}
Abort
${EndIf}
FunctionEnd
!macro DoElevation
GetDlgItem $1 $HWNDParent 1
System::Call user32::GetFocus()i.s
# Disable 'Next' button.
EnableWindow $1 0
!insertmacro UAC_PageElevation_RunElevated
EnableWindow $1 1
System::call user32::SetFocus(is)
${If} $2 = 0x666
MessageBox MB_ICONEXCLAMATION \
"You need to log in with an administrative account \
in order to perform an 'All Users' installation."
Abort
${ElseIf} $0 = 1223
# UAC canceled by user.
Abort
${Else}
${If} $0 <> 0
${If} $0 = 1062
MessageBox MB_ICONSTOP \
"Elevation failed; Secondary Logon service is \
not running."
${Else}
MessageBox MB_ICONSTOP \
"Elevation failed; error code: $0."
${EndIf}
Abort
${EndIf}
${EndIf}
# UAC worked, we're the outer installer, so we can quit.
Quit
!macroend
!macro ParseCommandLineArgs
ClearErrors
${GetParameters} $ARGV
${GetOptions} $ARGV "/?" $ARGV_Help
${IfNot} ${Errors}
MessageBox MB_OK|MB_ICONEXCLAMATION \
"Usage: $EXEFILE [options]$\n\
Options:$\n$\n\
/InstallationType=AllUsers [default: JustMe]$\n$\n\
/AddToPath=[0|1] [default: 0]$\n$\n\
#if keep_pkgs is True
/KeepPkgCache=[0|1] [default: 1]$\n$\n\
#endif
#if keep_pkgs is False
/KeepPkgCache=[0|1] [default: 0]$\n$\n\
#endif
/RegisterPython=[0|1] [default: AllUsers: 1, JustMe: 0]$\n$\n\
/NoRegistry=[0|1] [default: AllUsers: 0, JustMe: 0]$\n$\n\
/NoScripts=[0|1] [default: 0]$\n$\n\
/NoShortcuts=[0|1] [default: 0]$\n$\n\
/CheckPathLength=[0|1] [default: 1]$\n$\n\
Examples:$\n\
Install for all users, but don't add to PATH env var:$\n\
$EXEFILE /InstallationType=AllUsers$\n$\n\
Install for just me, add to PATH and register as system Python:$\n\
$EXEFILE /RegisterPython=1 /AddToPath=1$\n$\n\
Install for just me, with no registry modification (for CI):$\n\
$EXEFILE /NoRegistry=1$\n$\n\
NOTE: If you install for AllUsers, then the option to AddToPath$\n\
is disabled (i.e. if ./InstallationType=AllUsers, then$\n\
/AddToPath=1 will be ignored).$\n" \
/SD IDOK
Abort
${EndIf}
ClearErrors
${GetOptions} $ARGV "/InstallationType=" $ARGV_InstallationType
${IfNot} ${Errors}
${If} $ARGV_InstallationType == "AllUsers"
StrCpy $InstMode ${ALL_USERS}
${Else}
StrCpy $InstMode ${JUST_ME}
${EndIf}
${EndIf}
ClearErrors
${GetOptions} $ARGV "/RegisterPython=" $ARGV_RegisterPython
${IfNot} ${Errors}
${If} $ARGV_RegisterPython = "1"
StrCpy $Ana_RegisterSystemPython_State ${BST_CHECKED}
${ElseIf} $ARGV_RegisterPython = "0"
StrCpy $Ana_RegisterSystemPython_State ${BST_UNCHECKED}
${EndIf}
${EndIf}
ClearErrors
${GetOptions} $ARGV "/KeepPkgCache=" $ARGV_KeepPkgCache
${If} ${Errors}
StrCpy $ARGV_KeepPkgCache "@KEEP_PKGS@"
${EndIf}
ClearErrors
${GetOptions} $ARGV "/NoRegistry=" $ARGV_NoRegistry
${If} ${Errors}
StrCpy $ARGV_NoRegistry "0"
${EndIf}
ClearErrors
${GetOptions} $ARGV "/NoScripts=" $ARGV_NoScripts
${IfNot} ${Errors}
${If} $ARGV_NoScripts = "1"
StrCpy $Ana_PostInstall_State ${BST_UNCHECKED}
${ElseIf} $ARGV_NoScripts = "0"
StrCpy $Ana_PostInstall_State ${BST_CHECKED}
${EndIf}
${EndIf}
ClearErrors
${GetOptions} $ARGV "/NoShortcuts=" $ARGV_NoShortcuts
${IfNot} ${Errors}
${If} $ARGV_NoShortcuts = "1"
StrCpy $Ana_CreateShortcuts_State ${BST_UNCHECKED}
${ElseIf} $ARGV_NoShortcuts = "0"
StrCpy $Ana_CreateShortcuts_State ${BST_CHECKED}
${EndIf}
${EndIf}
ClearErrors
${GetOptions} $ARGV "/CheckPathLength=" $ARGV_CheckPathLength
${IfNot} ${Errors}
${If} $ARGV_CheckPathLength = "0"
StrCpy $CheckPathLength "0"
${ElseIf} $ARGV_CheckPathLength = "1"
StrCpy $CheckPathLength "1"
${EndIf}
${EndIf}
!macroend
Function OnInit_Release
${LogSet} on
!insertmacro ParseCommandLineArgs
# Parsing the AddToPath option here (and not in ParseCommandLineArgs) to prevent the MessageBox from showing twice.
# For more context, see https://github.com/conda/constructor/pull/584#issuecomment-1347688020
ClearErrors
${GetOptions} $ARGV "/AddToPath=" $ARGV_AddToPath
${IfNot} ${Errors}
${If} $ARGV_AddToPath = "1"
${If} $InstMode == ${ALL_USERS}
# To address CVE-2022-26526.
# In AllUsers install mode, do not allow AddToPath as an option.
MessageBox MB_OK|MB_ICONEXCLAMATION "/AddToPath=1 is disabled and ignored in 'All Users' installations" /SD IDOK
StrCpy $Ana_AddToPath_State ${BST_UNCHECKED}
${Else}
StrCpy $Ana_AddToPath_State ${BST_CHECKED}
${EndIf}
${ElseIf} $ARGV_AddToPath = "0"
StrCpy $Ana_AddToPath_State ${BST_UNCHECKED}
${EndIf}
${EndIf}
FunctionEnd
Function InstModePage_RadioButton_OnClick
${LogSet} on
Exch $0
Push $1
Push $2
nsDialogs::GetUserData $0
Pop $1
GetDlgItem $2 $HWNDParent 1
SendMessage $2 ${BCM_SETSHIELD} 0 $1
Pop $2
Pop $1
Exch $0
FunctionEnd
Function InstModePage_Create
${LogSet} on
Push $0
Push $1
Push $2
Push $3
${If} ${UAC_IsInnerInstance}
Abort
${EndIf}
!insertmacro MUI_HEADER_TEXT_PAGE \
"Select Installation Type" \
"Please select the type of installation you would like to perform \
for ${PRODUCT_NAME}."
GetFunctionAddress $0 InstModePage_RadioButton_OnClick
nsDialogs::Create /NOUNLOAD 1018
Pop $1
${NSD_OnBack} RemoveNextBtnShield
${NSD_CreateLabel} 0 20u 75% 20u "Install for:"
${NSD_CreateRadioButton} 0 40u 75% 15u "Just Me (recommended)"
Pop $2
#MessageBox MB_OK "OnClick 2! 0: $0, 1: $1, 2: $2"
StrCpy $InstModePage_RadioButton_JustMe $2
nsDialogs::OnClick $2 $0
nsDialogs::SetUserData $2 0
SendMessage $2 ${BM_CLICK} 0 0
${NSD_CreateRadioButton} 0 60u 75% 15u \
"All Users (requires admin privileges)"
#MessageBox MB_OK "OnClick 3! 0: $0, 1: $1, 2: $2, 3: $3"
Pop $3
StrCpy $InstModePage_RadioButton_AllUsers $3
nsDialogs::OnClick $3 $0
nsDialogs::SetUserData $3 1
${IfThen} $InstMode <> ${JUST_ME} ${|} SendMessage $3 ${BM_CLICK} 0 0 ${|}
Push $3
nsDialogs::Show
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
Function DisableBackButtonIfUACInnerInstance
${LogSet} on
Push $0
${If} ${UAC_IsInnerInstance}
GetDlgItem $0 $HWNDParent 3
EnableWindow $0 0
${EndIf}
Pop $0
FunctionEnd
Function RemoveNextBtnShield
${LogSet} on
Push $0
GetDlgItem $0 $HWNDParent 1
SendMessage $0 ${BCM_SETSHIELD} 0 0
Pop $0
FunctionEnd
Function InstModeChanged
${LogSet} on
# When using the installer with /S (silent mode), the /D option sets $INSTDIR,
# and it is therefore important not to overwrite $INSTDIR here, but it is also
# important that we do call SetShellVarContext with the appropriate value.
Push $0
${If} $InstMode = ${JUST_ME}
SetShellVarContext Current
# If we're on Vista+, the installation directory will
# have a nice, no-space name like:
# C:\Users\Trent\AppData\Local\Continuum\Anaconda.
# On 2003/XP, it will be in C:\Documents and Settings,
# with a space. We're allowing spaces now.
${IfNot} ${Silent}
StrCpy $INSTDIR $INSTDIR_JUSTME
${EndIf}
${Else}
SetShellVarContext All
${IfNot} ${Silent}
ExpandEnvStrings $0 ${DEFAULT_PREFIX_ALL_USERS}
StrCpy $INSTDIR $0
${Endif}
${EndIf}
Pop $0
FunctionEnd
!macro SetInstMode mode
StrCpy $InstMode ${mode}
Call InstModeChanged
!macroend
Function InstModePage_Leave
${LogSet} on
Push $0
Push $1
Push $2
${NSD_GetState} $InstModePage_RadioButton_AllUsers $0
${If} $0 = 0
!insertmacro SetInstMode ${JUST_ME}
${Else}
!insertmacro SetInstMode ${ALL_USERS}
${IfNot} ${UAC_IsAdmin}
!insertmacro DoElevation
${EndIf}
${EndIf}
Pop $2
Pop $1
Pop $0
FunctionEnd
Function .onInit
${LogSet} on
Push $0
Push $1
Push $2
Push $R1
Push $R2
InitPluginsDir
@TEMP_EXTRA_FILES@
!insertmacro ParseCommandLineArgs
# Select the correct registry to look at, depending
# on whether it's a 32-bit or 64-bit installer
SetRegView @BITS@
#if win64
# If we're a 64-bit installer, make sure it's 64-bit Windows
${IfNot} ${RunningX64}
MessageBox MB_OK|MB_ICONEXCLAMATION \
"This installer is for a 64-bit version for ${NAME}$\n\
but your system is 32-bit. Please use the 32-bit Windows$\n\
${NAME} installer." \
/SD IDOK
Abort
${EndIf}
#endif
!insertmacro UAC_PageElevation_OnInit
${If} ${UAC_IsInnerInstance}
${AndIfNot} ${UAC_IsAdmin}
SetErrorLevel 0x666
Quit
${EndIf}
# Look for a number of signs that indicate the user is a domain user and
# alter the default installation directory for 'Just Me' accordingly. We
# want to ensure that if we're a user domain account, we always install to
# %LOCALAPPDATA% (i.e. C:\Users\Trent\AppData\Local\Continuum\Anaconda),
# as this is the only place guaranteed to not be backed by a network share
# or included in a user's roaming profile. However, if we're a normal user
# account, then C:\Users\Trent\Anaconda is fine.
ReadEnvStr $0 USERDNSDOMAIN
${If} $0 != ""
# If not null, USERDNSDOMAIN is an unambiguous indication that we're
# logged into a domain account.
StrCpy $IsDomainUser 1
${Else}
# If it's not set, apply some simple heuristics to discern whether or
# not we're logged in as a domain user.
ReadEnvStr $0 LOGONSERVER
${If} $0 == ""
# This should never be unset; but if it is, we're definitely not
# a domain user.
StrCpy $IsDomainUser 0
${Else}
StrCpy $1 $0 "" 2 # lop-off the leading \\.
${StrFilter} $1 "+" "" "" $2 # convert to uppercase, store in $2
${If} $2 == "MICROSOFTACCOUNT"
# The new Windows 8.x live accounts have \\MicrosoftAccount
# set as LOGONSERVER; interpret this as being a non-domain
# user.
StrCpy $IsDomainUser 0
${Else}
ReadEnvStr $R1 COMPUTERNAME
${If} $R1 == ""
# This should never be unset either; if it is, assume
# we're not a domain user.
StrCpy $IsDomainUser 0
${Else}
# We've got a value for both LOGONSERVER and COMPUTERNAME
# environment variables (which should always be the case).
# Proceed to compare LOGONSERVER[-2:] to COMPUTERNAME; if
# they match, assume we're not a domain user account.
${StrFilter} $R1 "+" "" "" $R2 # convert to uppercase
${If} $2 != $R2
# COMPUTERNAME doesn't match LOGONSERVER; assume we're
# logged in via a domain account.
StrCpy $IsDomainUser 1
${Else}
# COMPUTERNAME matches LOGONSERVER; safe to assume
# we're logged in as a user account. (I guess there's
# the remote possibility a domain user has logged onto
# a server that has the same NetBIOS name as the Active
# Directory name... if that's the case, potentially
# installing Anaconda into an area that gets picked up
# by a roaming profile is the very least of your
# problems.)
StrCpy $IsDomainUser 0
${EndIf} # LOGONSERVER[-2:] != COMPUTERNAME
${EndIf} # COMPUTERNAME != ""
${EndIf} # LOGONSERVER != "\\MicrosoftAccount"
${EndIf} # LOGONSERVER != ""
${EndIf} # USERDNSDOMAIN != ""
${If} $IsDomainUser = 0
ExpandEnvStrings $0 ${DEFAULT_PREFIX}
StrCpy $INSTDIR_JUSTME $0
${ElseIf} $IsDomainUser = 1
ExpandEnvStrings $0 ${DEFAULT_PREFIX_DOMAIN_USER}
StrCpy $INSTDIR_JUSTME $0
${Else}
# Should never happen; indicates a logic error above.
MessageBox MB_OK "Internal error: IsUserDomain not set properly!" \
/SD IDOK
Abort
${EndIf}
${If} $InstMode == ""
StrCpy $InstMode ${JUST_ME}
${IfThen} ${UAC_IsAdmin} ${|} StrCpy $InstMode ${ALL_USERS} ${|}
# If running as 'SYSTEM' then JustMe is not appropriate; note that
# we should advise against this. SCCM has an option to run as user
System::Call "advapi32::GetUserName(t .r0, *i ${NSIS_MAX_STRLEN} r1) i.r2"
${IfThen} $0 == "SYSTEM" ${|} StrCpy $InstMode ${ALL_USERS} ${|}
${EndIf}
call InstModeChanged
${If} ${Silent}
${If} $InstMode == ${ALL_USERS}
${IfNot} ${UAC_IsAdmin}
MessageBox MB_ICONSTOP "Installation for all users requires an elevated prompt."
Abort
${EndIF}
${EndIF}
${EndIF}
; /D was not used, add default based on install type
${If} $InstDir == ""
${If} $InstMode == ${ALL_USERS}
ExpandEnvStrings $0 ${DEFAULT_PREFIX_ALL_USERS}
StrCpy $INSTDIR $0
${Else}
strcpy $INSTDIR $INSTDIR_JUSTME
${EndIf}
${EndIf}
; Set default value
${If} $CheckPathLength == ""
StrCpy $CheckPathLength "1"
${EndIf}
# Initialize the default settings for the anaconda custom options
Call mui_AnaCustomOptions_InitDefaults
# Override custom options with explicitly given values from contruct.yaml.
# If initialize_by_default (register_python_default) is None, do nothing.
#if initialize_conda is True and initialize_by_default is True
${If} $InstMode == ${JUST_ME}
StrCpy $Ana_AddToPath_State ${BST_CHECKED}
${EndIF}
#endif
#if initialize_conda is True and initialize_by_default is False
StrCpy $Ana_AddToPath_State ${BST_UNCHECKED}
#endif
#if register_python is True and register_python_default is True
StrCpy $Ana_RegisterSystemPython_State ${BST_CHECKED}
#endif
#if register_python is True and register_python_default is False
StrCpy $Ana_RegisterSystemPython_State ${BST_UNCHECKED}
#endif
#if check_path_length is True
StrCpy $CheckPathLength "1"
#endif
#if check_path_length is False
StrCpy $CheckPathLength "0"
#endif
#if keep_pkgs is True
StrCpy $Ana_ClearPkgCache_State ${BST_UNCHECKED}
#endif
#if keep_pkgs is False
StrCpy $Ana_ClearPkgCache_State ${BST_CHECKED}
#endif
#if pre_install_exists is True
StrCpy $Ana_PreInstall_State ${BST_CHECKED}
#endif
#if pre_install_exists is False
StrCpy $Ana_PreInstall_State ${BST_UNCHECKED}
#endif
#if post_install_exists is True
StrCpy $Ana_PostInstall_State ${BST_CHECKED}
#endif
#if post_install_exists is False
StrCpy $Ana_PostInstall_State ${BST_UNCHECKED}
#endif
Call OnInit_Release
Pop $R2
Pop $R1
Pop $2
Pop $1
Pop $0
FunctionEnd
Function un.onInit
Push $0
Push $1
Push $2
Push $3
# Resolve INSTDIR
GetFullPathName $0 $INSTDIR
# If the directory does not exist or cannot be resolved, $0 will be empty
StrCmp $0 "" invalid_dir
StrCpy $INSTDIR $0
# Never run the uninstaller when $INSTDIR points at system-critical directories
StrLen $InstDirLen $INSTDIR
# INSTDIR is a full path and has no trailing backslash,
# so if its length is 2, it is pointed at a system root
StrCmp $InstdirLen 2 invalid_dir
# Never delete anything inside Windows
StrCpy $0 $INSTDIR 7 3
StrCmp $0 "Windows" invalid_dir
StrCpy $0 "ALLUSERSPROFILE APPDATA LOCALAPPDATA PROGRAMDATA PROGRAMFILES PROGRAMFILES(x86) PUBLIC SYSTEMDRIVE SYSTEMROOT USERPROFILE"
StrCpy $1 1
loop_critical:
${WordFind} $0 " " "E+$1" $2
IfErrors endloop_critical
ReadEnvStr $3 $2
StrCmp $3 $INSTDIR invalid_dir
IntOp $1 $1 + 1
goto loop_critical
endloop_critical:
# Primitive check to see that $INSTDIR points to a conda directory
StrCpy $0 "_conda.exe conda-meta\history"
StrCpy $1 1
loop_conda:
${WordFind} $0 " " "E+$1" $2
IfErrors endloop_conda
IfFileExists $INSTDIR\$2 0 invalid_dir
IntOp $1 $1 + 1
goto loop_conda
endloop_conda:
# All checks have passed
goto valid_dir
invalid_dir:
MessageBox MB_OK|MB_ICONSTOP \
"Error: $INSTDIR is not a valid conda directory. Please run the uninstaller from a conda directory." \
/SD IDABORT
abort
valid_dir:
# Select the correct registry to look at, depending
# on whether it's a 32-bit or 64-bit installer
SetRegView @BITS@
# Since the switch to a dual-mode installer (All Users/Just Me), the
# uninstaller will inherit the requested execution level of the main
# installer -- which we now have to set to 'user'. Thus, Windows will
# not automatically elevate the uninstaller for us -- we need to do it
# ourselves if we're not a 'Just Me' installation.
!insertmacro UAC_PageElevation_OnInit
${IfNot} ${FileExists} "$INSTDIR\.nonadmin"
${AndIfNot} ${UAC_IsAdmin}
!insertmacro DoElevation
${EndIf}
${If} ${FileExists} "$INSTDIR\.nonadmin"
SetShellVarContext Current
${Else}
SetShellVarContext All
${EndIf}
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
# http://nsis.sourceforge.net/Check_for_spaces_in_a_directory_path
Function CheckForSpaces
${LogSet} on
Exch $R0
Push $R1
Push $R2
Push $R3
StrCpy $R1 -1
StrCpy $R3 $R0
StrCpy $R0 0
loop:
StrCpy $R2 $R3 1 $R1
IntOp $R1 $R1 - 1
StrCmp $R2 "" done
StrCmp $R2 " " 0 loop
IntOp $R0 $R0 + 1
Goto loop
done:
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
# http://nsis.sourceforge.net/StrCSpn,_StrCSpnReverse:_Scan_strings_for_characters
Function StrCSpn
${LogSet} on
Exch $R0 ; string to check
Exch
Exch $R1 ; string of chars
Push $R2 ; current char
Push $R3 ; current char
Push $R4 ; char loop
Push $R5 ; char loop
StrCpy $R4 -1
NextChar:
StrCpy $R2 $R1 1 $R4
IntOp $R4 $R4 - 1
StrCmp $R2 "" StrOK
StrCpy $R5 -1
NextCharCheck:
StrCpy $R3 $R0 1 $R5
IntOp $R5 $R5 - 1
StrCmp $R3 "" NextChar
StrCmp $R3 $R2 0 NextCharCheck
StrCpy $R0 $R2
Goto Done
StrOK:
StrCpy $R0 ""
Done:
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
# http://stackoverflow.com/a/29569614/1170370
!macro _IsNonEmptyDirectory _a _b _t _f
!insertmacro _LOGICLIB_TEMP
!insertmacro _IncreaseCounter
Push $0
FindFirst $0 $_LOGICLIB_TEMP "${_b}\*"
_IsNonEmptyDirectory_loop${LOGICLIB_COUNTER}:
StrCmp "" $_LOGICLIB_TEMP _IsNonEmptyDirectory_done${LOGICLIB_COUNTER}
StrCmp "." $_LOGICLIB_TEMP +2
StrCmp ".." $_LOGICLIB_TEMP 0 _IsNonEmptyDirectory_done${LOGICLIB_COUNTER}
FindNext $0 $_LOGICLIB_TEMP
Goto _IsNonEmptyDirectory_loop${LOGICLIB_COUNTER}
_IsNonEmptyDirectory_done${LOGICLIB_COUNTER}:
FindClose $0
Pop $0
!insertmacro _!= "" $_LOGICLIB_TEMP `${_t}` `${_f}`
!macroend
!define IsNonEmptyDirectory `"" IsNonEmptyDirectory`
Function OnDirectoryLeave
${LogSet} on
${If} ${IsNonEmptyDirectory} "$InstDir"
DetailPrint "::error:: Directory '$INSTDIR' is not empty, please choose a different location."
MessageBox MB_OK|MB_ICONEXCLAMATION \
"Directory '$INSTDIR' is not empty,$\n\
please choose a different location." \
/SD IDOK
Abort
${EndIf}
ReadRegStr $LongPathsEnabled HKLM "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled"
StrLen $InstDirLen "$InstDir"
${If} $CheckPathLength == "1"
${AndIf} $LongPathsEnabled == "0"
${AndIf} $InstDirLen > 46
; With windows 10, we can enable support for long path, for earlier
; version, suggest user to use shorter installation path
${If} ${AtLeastWin10}
${AndIfNot} $ARGV_NoRegistry = "1"
; If we have admin right, we enable long path on windows
${If} ${UAC_IsAdmin}
WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled" 1
; If we don't have admin right, we suggest a shorter path or suggest to run with admin right
${Else}
DetailPrint "::error:: The installation path should be shorter than 46 characters or \
the installation requires administrator rights to enable long \
path on Windows."
MessageBox MB_OK|MB_ICONSTOP "The installation path should be shorter than 46 characters or \
the installation requires administrator rights to enable long \
path on Windows." \
/SD IDOK
Abort
${EndIf}
; If we don't have admin right, we suggest a shorter path or suggest to run with admin right
${Else}
DetailPrint "::error:: The installation path should be shorter than 46 characters. \
Please choose another location."
MessageBox MB_OK|MB_ICONSTOP "The installation path should be shorter than 46 characters. \
Please choose another location." \
/SD IDOK
Abort
${EndIf}
${EndIf}
# Call the CheckForSpaces function.
Push $INSTDIR # Input string (install path).
Call CheckForSpaces
Pop $R0 # The function returns the number of spaces found in the input string.
Push $R7
Push $R8
Push $R9
# Check if any spaces exist in $INSTDIR.
StrCmp $R0 0 NoSpaces
# Plural if more than 1 space in $INSTDIR.
StrCmp $R0 1 0 +3
StrCpy $R1 ""
Goto +2
StrCpy $R1 "s"
${If} ${Silent}
StrCpy $R7 " "
${Else}
StrCpy $R7 "$\n"
${EndIf}
StrCpy $R8 "'Destination Folder' contains $R0 space$R1.$R7This can cause problems with several conda packages.$R7"
#if check_path_spaces is True
StrCpy $R8 "$R8Please remove the space$R1 from the destination folder."
StrCpy $R9 "Error"
#else
StrCpy $R8 "$R8Please consider removing the space$R1."
StrCpy $R9 "Warning"
#endif
# Show message box then take the user back to the Directory page.
${If} ${Silent}
DetailPrint "::$R9:: $R8"
${Else}
MessageBox MB_OK|MB_ICONINFORMATION "$R9: $R8" /SD IDOK
${EndIf}
#if check_path_spaces is True
abort
#endif
NoSpaces:
Pop $R7
Pop $R8
Pop $R9
# List of characters not allowed anywhere in $INSTDIR
Push "^%!=,()"
Push $INSTDIR
Call StrCSpn
Pop $R0
StrCmp $R0 "" NoInvalidCharaceters
DetailPrint "::error:: 'Destination Folder' contains the following invalid character: $R0"
MessageBox MB_OK|MB_ICONEXCLAMATION \
"Error: 'Destination Folder' contains the following invalid character: $R0" \
/SD IDOK
abort
NoInvalidCharaceters:
UnicodePathTest::SpecialCharPathTest $INSTDIR
Pop $R1
StrCmp $R1 "nothingspecial" nothing_special_path
DetailPrint "::error:: 'Destination Folder' contains the following invalid character$R1"
MessageBox MB_OK|MB_ICONEXCLAMATION \
"Error: 'Destination Folder' contains the following invalid character$R1" \
/SD IDOK
abort
nothing_special_path:
; test if path contains unicode characters
UnicodePathTest::UnicodePathTest $INSTDIR
Pop $R1
# Python 3 can be installed in a CP_ACP path until MKL is Unicode capable.
# (mkl_rt.dll calls LoadLibraryA() to load mkl_intel_thread.dll)
# Python 2 can only be installed to an ASCII path.
StrCmp $R1 "ascii" valid_path
StrCmp ${PY_VER} "2.7" not_cp_acp_capable
StrCmp $R1 "ascii_cp_acp" valid_path
not_cp_acp_capable:
DetailPrint "::error:: Due to incompatibility with several \
Python libraries, 'Destination Folder' cannot contain non-ascii characters \
(special characters or diacritics). Please choose another location."
MessageBox MB_OK|MB_ICONEXCLAMATION "Error: Due to incompatibility with several \
Python libraries, 'Destination Folder' cannot contain non-ascii characters \
(special characters or diacritics). Please choose another location." \
/SD IDOK
abort
valid_path:
Push $R1
${IsWritable} $INSTDIR $R1
IntCmp $R1 0 pathgood
Pop $R1
DetailPrint "::error: Path $INSTDIR is not writable. Please check permissions or \
try respawning the installer with elevated privileges."
MessageBox MB_OK|MB_ICONEXCLAMATION \
"Error: Path $INSTDIR is not writable. Please check permissions or \
try respawning the installer with elevated privileges." \
/SD IDOK
Abort
pathgood:
Pop $R1
FunctionEnd
Function .onVerifyInstDir
${LogSet} on
StrLen $0 $Desktop
StrCpy $0 $INSTDIR $0