diff --git a/hptool/hptool.cabal b/hptool/hptool.cabal index fe35f76..ed8fe33 100644 --- a/hptool/hptool.cabal +++ b/hptool/hptool.cabal @@ -1,18 +1,73 @@ -Name: hptool +Cabal-version: 2.2 +Name: HPTool Version: 0.1 Author: Mark Lentczner Maintainer: gershomb@gmail.com Category: Utility Build-type: Simple -Cabal-version: >=1.8 Synopsis: Haskell Platform Utility Data-files: templates/*.cabal.mu +Library + Exposed-Modules: + CLArgs, + Internal.CLArgs, + Config, + Dirs + GhcDist, + HaddockMaster, + LocalCommand, + OS, + OS.Internal, + OS.Mac, + OS.Posix, + OS.Win + OS.Win.WinNsis, + OS.Win.WinPaths, + OS.Win.WinRules, + OS.Win.WinUtils, + Package, + Paths, + PlatformDB, + ReleaseFiles, + Releases, + Releases2012, + Releases2013, + Releases2014, + Releases2015, + Releases2016, + Releases2017, + Releases2018, + SourceTarball, + Target, + Templates, + Types, + Utils, + Website + Build-depends: + Cabal >=2.2.0, + base, + bytestring, + containers, + directory, + hastache >=0.6.0, + shake >= 0.16, + split, + text, + transformers, + unix-compat, + filepath + hs-source-dirs: src + Default-Language: Haskell2010 + Executable hptool Main-is: Main.hs + hs-source-dirs: src Other-Modules: + CLArgs, + Internal.CLArgs, Config, Dirs GhcDist, @@ -45,9 +100,6 @@ Executable hptool Types, Utils, Website - - hs-source-dirs: src - Build-depends: Cabal, base, @@ -55,11 +107,32 @@ Executable hptool containers, directory, hastache >=0.6.0, - shake >= 0.14 && < 0.16, + HPTool, + shake >= 0.16, split, text, transformers, unix-compat, filepath - ghc-options: -Wall -fwarn-tabs + Default-Language: Haskell2010 + + +test-suite unit-tests + type: exitcode-stdio-1.0 + hs-source-dirs: tests + other-modules: + UnitTests.CLArgs + main-is: UnitTests.hs + build-depends: + base, + directory, + HPTool, + HUnit, + QuickCheck, + tasty, + tasty-hunit, + tasty-hspec, + transformers + ghc-options: -Wall + Default-Language: Haskell2010 diff --git a/hptool/os-extras/win/templates/Bootstrapper.nsi.mu b/hptool/os-extras/win/templates/Bootstrapper.nsi.mu new file mode 100644 index 0000000..c26110b --- /dev/null +++ b/hptool/os-extras/win/templates/Bootstrapper.nsi.mu @@ -0,0 +1,224 @@ +;; WARNING: Bootstrapper.nsi is automatically generated from +;; Bootstrapper.nsi.mu by the hptool. +;; Make sure you are editing Bootstrapper.nsi.mu, not Bootstrapper.nsi. + +; Haskell Platform Bootstrapper-Installer +; +; The purpose of the "bootstrapper" is to be able to launch processes +; as either elevated or not (once elevated, it requires non-trivial code +; for that process to launch an un-elevated process). So, this installer +; is the wrapper of the entire HP installer. This bootstrapper must specify +; "RequestExecutionLevel user". Installers launched from here can specify +; "RequestExecutionLevel highest" or as needed. +; +; This bootstrapper exists for one feature (currently) which must be done as +; the user, which is to write update/create the user's cabal config file. +; +;;;;;;;;; +; NOTE, special handling for $INSTDIR: +; +; $INSTDIR is a variable set initially by the NSIS framework before calling any +; functions in the client's NSI file. It can be set by the user with the +; command line parameter "D=", or to some default by NSIS. +; +; Using $INSTDIR in this particular installer is only correct when the user has +; launched this installer with the /S and /D options; otherwise, installing +; anything to $INSTDIR from this installer may not have the correct value since +; the user can subsequently change the install directory in the following +; sub-installer's dialog. This installer handles post-install tasks, so it +; gets the actual installed directory from the registry for those purposes. +; +; We only support two cases: 1) both /S and /D= or 2) neither /S nor /D= +; +; This installer does modify $INSTDIR for a non-silent install, according to +; the defaults for 32-bit vs 64-bit (using the macro "do64Stuff"), which means +; if the user specifies "/D=" without "/S" (for silent), the user's "/D=" will +; not be used (we cannot readily detect if the user specified "/D=" or not, +; since the NSIS framework strips it out of $CMDLINE; however if /S is present, +; then we do not modify $INSTDIR, so any user-specified /D= will be retained). +; +; To the sub-installer which is launched from here, this installer provides a +; forced "/D=" command line switch, which accounts for whether the user set it +; (but also must have /S), or it was set by the "do64Stuff" logic. In either +; case, unless /S, the launched sub-installer will ask the user and ignore the +; /D= parameter. + + +;-------------------------------- +;Includes + + !Include "WinMessages.nsh" + !Include "FileFunc.nsh" + !Include "StrFunc.nsh" + !Include "LogicLib.nsh" + !Include "MUI2.nsh" + !Include "WordFunc.nsh" + !Include "x64.nsh" + !insertmacro GetParameters + !insertmacro GetOptions + !Include "CommonHP.nsh" + +;-------------------------------- +;Defines + + !Define GHC_VERSION "{{ghcVersion}}" + !Define PLATFORM_VERSION "{{hpVersion}}" + !Define PRODUCT_DIR_REG_KEY "Software\Haskell\Haskell Platform\${PLATFORM_VERSION}" + !Define CABAL_CONFIG_MSYS_ADDITIONS \ + '--augment="extra-prog-path: $ACTUAL_INSTDIR\msys\usr\bin" \ + --augment="extra-prog-path: $APPDATA\cabal\bin" \ + --augment="extra-lib-dirs: $ACTUAL_INSTDIR\mingw\lib" \ + --augment="extra-include-dirs: $ACTUAL_INSTDIR\mingw\include"' + +;-------------------------------- +;Variables + + Var PROGRAM_FILES + Var INSTALLER_PARAMS + Var tempDir + + ; ACTUAL_INSTDIR: set from registry, and only valid after the enclosed + ; installed has finished + Var ACTUAL_INSTDIR + +;-------------------------------- +;General settings + + ;Name and file + Name "Haskell Platform ${PLATFORM_VERSION} {{is32or64}}-bit" + OutFile "{{productFile}}" + + ;Default install dir + ; Set as appropriate for 32-bit or 64-bit OS +{{#build64bit}} + InstallDir "$PROGRAMFILES64\Haskell Platform\${PLATFORM_VERSION}" +{{/build64bit}} + +{{^build64bit}} + InstallDir "$PROGRAMFILES\Haskell Platform\${PLATFORM_VERSION}" +{{/build64bit}} + + ;Icon + !Define MUI_ICON "icons/installer.ico" + !Define MUI_UNICON "icons/installer.ico" + + ; do this as the user, not as Administrator! + RequestExecutionLevel user + + ;Best available compression + SetCompressor lzma + + ;Install types + InstType "Standard" + InstType "Portable (just unpack the files)" + + ;Used on the UI Pages + BrandingText "Haskell.org" + +;-------------------------------- +;Macros + +;-------------------------------- +;Callbacks + +Function .onInit + ; Store and pass on all the params given to this bootstrapper + ; NOTE: GetParameters uses $CMDLINE which has already stripped out any /D= + ; "If /D= is specified on the command line (to override the install + ; directory) it won't show up in $CMDLINE." (nor GetParameters) + ${GetParameters} $INSTALLER_PARAMS + + ; If the /S (for silent install) switch has been supplied by the user, + ; then make this truely silent and not show the banner + ; Without some kind of window to show, this installer gets shoved out of + ; the foreground, and then the main installer comes up behind windows. + ClearErrors + ${GetOptions} "$INSTALLER_PARAMS" "/S" $0 + ; error flag is set if the flag we looked for was not there + ${If} ${ERRORS} + Banner::show "Extracting Haskell Platform installer..." + BringToFront + ${EndIf} + + !insertmacro do64Stuff 1 + + ; Keep this as the current user, so that $APPDATA is expanded for this user! + SetShellVarContext current +FunctionEnd + +Function .onInstSuccess +FunctionEnd + +;-------------------------------- +Function CreateGUID + System::Call 'ole32::CoCreateGuid(g .s)' +FunctionEnd + +;-------------------------------- +;Interface Settings + + !define MUI_ABORTWARNING + +; Make this installer completely silent +SilentInstall silent + +;-------------------------------- +;Pages + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Installer Sections + +Section "Base components" SecMain + + ; Make this section mandatory + SectionIn RO + + ;Meta-installer should not try to re-compress the payloads! + SetCompress off + + ; Create a unique name for a folder in $TEMP + Call CreateGUID + pop $0 + StrCpy $tempDir "$TEMP\temp_$0" + + ; 1. HP elevated-privileges wrapper + SetOutPath "$tempDir" + ; Yes, we extract the core installer and rename it as the "main" installer. + ; This way, the user sees the same name as the file that was launched. + File "/oname={{osProductFileName}}" "..\product\HP-setup.exe" + ; Can bring down the banner now + Banner::destroy + BringToFront + !insertmacro ShellExecWait "" '"$tempDir\{{osProductFileName}}"' '$INSTALLER_PARAMS /D=$INSTDIR' "" SW_SHOWNORMAL $0 + ; return value from the ShellExecWait is now in $0 + Delete "$tempDir\{{osProductFileName}}" + SetOutPath "$TEMP" ; RMDIR on a dir will not work if it is the CWD + RMDir "$tempDir" + + ; 2. Cabal config update + ; Should only do this config update if + ; a) user has requested + ; b) the main installation above completed successfully + ${If} $0 == 3 ; magic value means successful install, and user wants update + ClearErrors + ReadRegStr $ACTUAL_INSTDIR HKLM "${PRODUCT_DIR_REG_KEY}" "InstallDir" + IfErrors +2 + nsExec::Exec '"$ACTUAL_INSTDIR\lib\extralibs\bin\cabal" user-config update ${CABAL_CONFIG_MSYS_ADDITIONS}' + ${EndIf} + + ; Turn compression back on + SetCompress auto + +SectionEnd + +;-------------------------------- +; "the last SetCompress command in the file also determines whether or not the +; install info section and uninstall data of the installer is compressed." +; Yes, we want this meta-info to be compressed + +SetCompress auto diff --git a/hptool/os-extras/win/templates/CommonHP.nsh.mu b/hptool/os-extras/win/templates/CommonHP.nsh.mu new file mode 100644 index 0000000..6890c26 --- /dev/null +++ b/hptool/os-extras/win/templates/CommonHP.nsh.mu @@ -0,0 +1,122 @@ +;; WARNING: CommonHP.nsh is automatically generated from CommonHP.nsh.mu by +;; the hptool. Make sure you are editing the template not the generated file. + +; --------------------- +; CommonHP.nsh +; --------------------- +; +; A few macros common to our (sub-)installer(s). +; $PROGRAM_FILES and $INSTDIR will be modified by the do64Stuff macro! +; be sure to put the following in any file !Include-ing this file: +; +; Var PROGRAM_FILES +; + +!ifndef ___COMMONHP__NSH__ +!define ___COMMONHP__NSH___ + +;-------------------------------- +;Includes + + !Include "StrFunc.nsh" + !Include "LogicLib.nsh" + !Include "x64.nsh" + + +;-------------------------------- +;Macros + +!macro CheckAdmin thing + UserInfo::GetAccountType + pop $0 + ${If} $0 != "admin" ;Require admin rights on NT4+ + MessageBox MB_YESNO "It is recommended to run this ${thing} as administrator. Do you want to quit and restart the ${thing} manually with elevated privileges?" IDNO CheckAdminDone + SetErrorLevel 740 ;ERROR_ELEVATION_REQUIRED + Quit + ${EndIf} + CheckAdminDone: +!macroend + + ;-------------------------------- + ;Win 64-bit support + +!macro do64Stuff isInstall + ; The NSIS installer is a 32-bit executable, but it can do a 64-bit install. + ; Default to 32-bit, change if installing 64-bit on 64-bit. + ; + ; The 'isInstall' argument is 1 for the install part of the script (from + ; .onInit function) and 0 if for the uninstall part (via un.onInit). The + ; $INSTDIR must be changed for the installation step to account for the case + ; of installing the 32-bit installer onto 64-bit Windows; and it must + ; happen before the user gets to the dialog to change installation location. + ; On the other hand, $INSTDIR must *not* be changed for the uninstall step + ; because doing so over-rides what the user did during the install step. + ; + ; Also, do not force $INSTDIR to change if this is a silent install. + SetRegView 32 + StrCpy $PROGRAM_FILES "$PROGRAMFILES" + ${IfNot} ${Silent} + ${If} ${isInstall} = 1 + StrCpy $INSTDIR "$PROGRAM_FILES\Haskell Platform\${PLATFORM_VERSION}" + ${EndIf} + ${EndIf} + {{#build64bit}} + ${If} ${RunningX64} + ; If this is installing the 64-bit HP on 64-bit Windows, enable FSRedirection. + ${EnableX64FSRedirection} + ; enable access to 64-bit portion of registry + SetRegView 64 + StrCpy $PROGRAM_FILES "$PROGRAMFILES64" + ${IfNot} ${Silent} + ${If} ${isInstall} = 1 + StrCpy $INSTDIR "$PROGRAM_FILES\Haskell Platform\${PLATFORM_VERSION}" + ${EndIf} + ${EndIf} + ${Else} + ; pop up an error message: Cannot install 64-bit HP on 32-bit Windows + MessageBox MB_OK "You are trying to install the 64-bit version of the Haskell Platform onto a 32-bit version of Windows. Please use the 32-bit version of the Haskell Platform." + SetErrorLevel 0x800401FAL ; CO_E_WRONGOSFORAPP + Quit + ${EndIf} + {{/build64bit}} +!macroend + + +;-------------------------------- +; http://nsis.sourceforge.net/ShellExecWait +;-------------------------------- + +;-------------------------------- +;Includes + +!include LogicLib.nsh +!include WinMessages.nsh + +; ShellExecWait +; +!macro ShellExecWait verb app param workdir show exitoutvar ;only app and show must be != "", every thing else is optional +#define SEE_MASK_NOCLOSEPROCESS 0x40 +System::Store S +System::Call '*(&i60)i.r0' +System::Call '*$0(i 60,i 0x40,i $hwndparent,t "${verb}",t $\'${app}$\',t $\'${param}$\',t "${workdir}",i ${show})i.r0' +BringToFront +System::Call 'shell32::ShellExecuteEx(ir0)i.r1 ?e' +${If} $1 <> 0 + System::Call '*$0(is,i,i,i,i,i,i,i,i,i,i,i,i,i,i.r1)' ;stack value not really used, just a fancy pop ;) + System::Call 'kernel32::WaitForSingleObject(ir1,i-1)' + System::Call 'kernel32::GetExitCodeProcess(ir1,*i.s)' + System::Call 'kernel32::CloseHandle(ir1)' +${EndIf} +System::Free $0 +!if "${exitoutvar}" == "" + pop $0 +!endif +System::Store L +!if "${exitoutvar}" != "" + pop ${exitoutvar} +!endif +!macroend + + + +!endif # !___COMMONHP__NSH___ diff --git a/hptool/os-extras/win/templates/Extralibs.nsi.mu b/hptool/os-extras/win/templates/Extralibs.nsi.mu deleted file mode 100644 index b1b80c5..0000000 --- a/hptool/os-extras/win/templates/Extralibs.nsi.mu +++ /dev/null @@ -1,192 +0,0 @@ -;; WARNING: Extralibs.nsi is automatically generated from Extralibs.nsi.mu by -;; the hptool. Make sure you are editing the template not the generated file. - - -; Extralibs Installer - -;-------------------------------- -;Includes - - !Include "FileFunc.nsh" - !Include "StrFunc.nsh" - !Include "LogicLib.nsh" - !Include "MUI2.nsh" - !Include "WordFunc.nsh" - !Include "x64.nsh" - -;-------------------------------- -;Defines - - !Define GHC_VERSION "{{ghcVersion}}" - !Define PLATFORM_VERSION "{{hpVersion}}" - !Define PRODUCT_DIR_REG_KEY "Software\Haskell\Haskell Platform\${PLATFORM_VERSION}" - !Define HACKAGE_SHORTCUT_TEXT "HackageDB - Haskell Software Repository" - !Define FILES_SOURCE_PATH "{{targetFiles}}" - !Define INST_DAT "Extralibs_inst.dat" - !Define UNINST_DAT "Extralibs_uninst.dat" - -;-------------------------------- -;Variables - - Var PROGRAM_FILES - -;-------------------------------- -;General settings - - ;Name and file - Name "Haskell Platform ${PLATFORM_VERSION} {{is32or64}}-bit" - OutFile "{{productFile}}" - - ;Default install dir - InstallDir "$PROGRAMFILES\Haskell Platform\${PLATFORM_VERSION}" - InstallDirRegKey HKLM "${PRODUCT_DIR_REG_KEY}" "" - - ;Icon - !Define MUI_ICON "icons/installer.ico" - !Define MUI_UNICON "icons/installer.ico" - - ;Request application privileges for Windows Vista - RequestExecutionLevel highest - - ;Best available compression - SetCompressor /SOLID lzma - - ;Install types - InstType "Standard" - InstType "Portable (just unpack the files)" - -;-------------------------------- -;Macros - -!macro CheckAdmin thing -UserInfo::GetAccountType -pop $0 -${If} $0 != "admin" ;Require admin rights on NT4+ - MessageBox MB_YESNO "It is recommended to run this ${thing} as administrator. Do you want to quit and restart the ${thing} manually with elevated privileges?" IDNO CheckAdminDone - SetErrorLevel 740 ;ERROR_ELEVATION_REQUIRED - Quit -${EndIf} -CheckAdminDone: -!macroend - - ;-------------------------------- - ;Win 64-bit support - -!macro do64Stuff isInstall - ; The NSIS installer is a 32-bit executable, but it can do a 64-bit install. - ; Default to 32-bit, change if installing 64-bit on 64-bit. - ; - ; The 'isInstall' argument is 1 for the install part of the script (from - ; .onInit function) and 0 if for the uninstall part (via un.onInit). The - ; $INSTDIR must be changed for the installation step to account for the case - ; of installing the 32-bit installer onto 64-bit Windows; and and it must - ; happen before the user gets to the dialog to change installation location. - ; On the other hand, $INSTDIR must *not* be changed for the uninstall step - ; because doing so over-rides what the user did during the install step. - ; - ; Also, do not force $INSTDIR to change if this is a silent install. -SetRegView 32 -StrCpy $PROGRAM_FILES "$PROGRAMFILES" -${IfNot} ${Silent} - ${If} ${isInstall} = 1 - StrCpy $INSTDIR "$PROGRAM_FILES\Haskell Platform\${PLATFORM_VERSION}" - ${EndIf} -${EndIf} -{{#build64bit}} -${If} ${RunningX64} - ; If this is installing the 64-bit HP on 64-bit Windows, enable FSRedirection. - ${EnableX64FSRedirection} - ; enable access to 64-bit portion of registry - SetRegView 64 - StrCpy $PROGRAM_FILES "$PROGRAMFILES64" - ${IfNot} ${Silent} - ${If} ${isInstall} = 1 - StrCpy $INSTDIR "$PROGRAM_FILES\Haskell Platform\${PLATFORM_VERSION}" - ${EndIf} - ${EndIf} -${Else} -; pop up an error message: Cannot install 64-bit HP on 32-bit Windows - MessageBox MB_OK "You are trying to install the 64-bit version of the Haskell Platform onto a 32-bit version of Windows. Please use the 32-bit version of the Haskell Platform." - SetErrorLevel 0x800401FAL ; CO_E_WRONGOSFORAPP - Quit -${EndIf} -{{/build64bit}} -!macroend - -;-------------------------------- -;Callbacks - -Function .onInit - !insertmacro do64Stuff 1 - !insertmacro CheckAdmin "installer" - SetShellVarContext all -FunctionEnd - -Function un.onInit - !insertmacro do64Stuff 0 - !insertmacro CheckAdmin "uninstaller" - SetShellVarContext all -FunctionEnd - -;-------------------------------- -;Interface Settings - - !define MUI_ABORTWARNING - -;-------------------------------- -;Pages - - !Define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp" - !insertmacro MUI_PAGE_WELCOME - !insertmacro MUI_PAGE_LICENSE "LICENSE" - !insertmacro MUI_PAGE_DIRECTORY - - !Define MUI_COMPONENTSPAGE_NODESC - !insertmacro MUI_PAGE_COMPONENTS - - !insertmacro MUI_PAGE_INSTFILES - !insertmacro MUI_PAGE_FINISH - - !insertmacro MUI_UNPAGE_WELCOME - !insertmacro MUI_UNPAGE_CONFIRM - !insertmacro MUI_UNPAGE_INSTFILES - !insertmacro MUI_UNPAGE_FINISH - -;-------------------------------- -;Languages - - !insertmacro MUI_LANGUAGE "English" - -;-------------------------------- -;Installer Sections - -Section "Base components" SecMain - - SectionIn 1 2 - ; Make this section mandatory - SectionIn RO - - !Include ${INST_DAT} - -SectionEnd - -Section "Create uninstaller" SecAddRem - - SectionIn 1 - SectionIn RO - - ;Create uninstaller - WriteUninstaller "$INSTDIR\Extralibs_Uninstall.exe" - -SectionEnd - -;-------------------------------- -;Uninstaller Section - -Section "Uninstall" - - !Include ${UNINST_DAT} - - Delete "$INSTDIR\Extralibs_Uninstall.exe" - -SectionEnd diff --git a/hptool/os-extras/win/templates/MSys.nsi.mu b/hptool/os-extras/win/templates/MSys.nsi.mu deleted file mode 100644 index 91a05b3..0000000 --- a/hptool/os-extras/win/templates/MSys.nsi.mu +++ /dev/null @@ -1,192 +0,0 @@ -;; WARNING: MSys.nsi is automatically generated from MSys.nsi.mu by -;; the hptool. Make sure you are editing the template not the generated file. - - -; MSys Installer - -;-------------------------------- -;Includes - - !Include "FileFunc.nsh" - !Include "StrFunc.nsh" - !Include "LogicLib.nsh" - !Include "MUI2.nsh" - !Include "WordFunc.nsh" - !Include "x64.nsh" - -;-------------------------------- -;Defines - - !Define GHC_VERSION "{{ghcVersion}}" - !Define PLATFORM_VERSION "{{hpVersion}}" - !Define PRODUCT_DIR_REG_KEY "Software\Haskell\Haskell Platform\${PLATFORM_VERSION}" - !Define HACKAGE_SHORTCUT_TEXT "HackageDB - Haskell Software Repository" - !Define FILES_SOURCE_PATH "{{targetFiles}}" - !Define INST_DAT "MSys_inst.dat" - !Define UNINST_DAT "MSys_uninst.dat" - -;-------------------------------- -;Variables - - Var PROGRAM_FILES - -;-------------------------------- -;General settings - - ;Name and file - Name "Haskell Platform ${PLATFORM_VERSION} {{is32or64}}-bit" - OutFile "{{productFile}}" - - ;Default install dir - InstallDir "$PROGRAMFILES\Haskell Platform\${PLATFORM_VERSION}" - InstallDirRegKey HKLM "${PRODUCT_DIR_REG_KEY}" "" - - ;Icon - !Define MUI_ICON "icons/installer.ico" - !Define MUI_UNICON "icons/installer.ico" - - ;Request application privileges for Windows Vista - RequestExecutionLevel highest - - ;Best available compression - SetCompressor /SOLID lzma - - ;Install types - InstType "Standard" - InstType "Portable (just unpack the files)" - -;-------------------------------- -;Macros - -!macro CheckAdmin thing -UserInfo::GetAccountType -pop $0 -${If} $0 != "admin" ;Require admin rights on NT4+ - MessageBox MB_YESNO "It is recommended to run this ${thing} as administrator. Do you want to quit and restart the ${thing} manually with elevated privileges?" IDNO CheckAdminDone - SetErrorLevel 740 ;ERROR_ELEVATION_REQUIRED - Quit -${EndIf} -CheckAdminDone: -!macroend - - ;-------------------------------- - ;Win 64-bit support - -!macro do64Stuff isInstall - ; The NSIS installer is a 32-bit executable, but it can do a 64-bit install. - ; Default to 32-bit, change if installing 64-bit on 64-bit. - ; - ; The 'isInstall' argument is 1 for the install part of the script (from - ; .onInit function) and 0 if for the uninstall part (via un.onInit). The - ; $INSTDIR must be changed for the installation step to account for the case - ; of installing the 32-bit installer onto 64-bit Windows; and and it must - ; happen before the user gets to the dialog to change installation location. - ; On the other hand, $INSTDIR must *not* be changed for the uninstall step - ; because doing so over-rides what the user did during the install step. - ; - ; Also, do not force $INSTDIR to change if this is a silent install. -SetRegView 32 -StrCpy $PROGRAM_FILES "$PROGRAMFILES" -${IfNot} ${Silent} - ${If} ${isInstall} = 1 - StrCpy $INSTDIR "$PROGRAM_FILES\Haskell Platform\${PLATFORM_VERSION}" - ${EndIf} -${EndIf} -{{#build64bit}} -${If} ${RunningX64} - ; If this is installing the 64-bit HP on 64-bit Windows, enable FSRedirection. - ${EnableX64FSRedirection} - ; enable access to 64-bit portion of registry - SetRegView 64 - StrCpy $PROGRAM_FILES "$PROGRAMFILES64" - ${IfNot} ${Silent} - ${If} ${isInstall} = 1 - StrCpy $INSTDIR "$PROGRAM_FILES\Haskell Platform\${PLATFORM_VERSION}" - ${EndIf} - ${EndIf} -${Else} -; pop up an error message: Cannot install 64-bit HP on 32-bit Windows - MessageBox MB_OK "You are trying to install the 64-bit version of the Haskell Platform onto a 32-bit version of Windows. Please use the 32-bit version of the Haskell Platform." - SetErrorLevel 0x800401FAL ; CO_E_WRONGOSFORAPP - Quit -${EndIf} -{{/build64bit}} -!macroend - -;-------------------------------- -;Callbacks - -Function .onInit - !insertmacro do64Stuff 1 - !insertmacro CheckAdmin "installer" - SetShellVarContext all -FunctionEnd - -Function un.onInit - !insertmacro do64Stuff 0 - !insertmacro CheckAdmin "uninstaller" - SetShellVarContext all -FunctionEnd - -;-------------------------------- -;Interface Settings - - !define MUI_ABORTWARNING - -;-------------------------------- -;Pages - - !Define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp" - !insertmacro MUI_PAGE_WELCOME - !insertmacro MUI_PAGE_LICENSE "LICENSE" - !insertmacro MUI_PAGE_DIRECTORY - - !Define MUI_COMPONENTSPAGE_NODESC - !insertmacro MUI_PAGE_COMPONENTS - - !insertmacro MUI_PAGE_INSTFILES - !insertmacro MUI_PAGE_FINISH - - !insertmacro MUI_UNPAGE_WELCOME - !insertmacro MUI_UNPAGE_CONFIRM - !insertmacro MUI_UNPAGE_INSTFILES - !insertmacro MUI_UNPAGE_FINISH - -;-------------------------------- -;Languages - - !insertmacro MUI_LANGUAGE "English" - -;-------------------------------- -;Installer Sections - -Section "Base components" SecMain - - SectionIn 1 2 - ; Make this section mandatory - SectionIn RO - - !Include ${INST_DAT} - -SectionEnd - -Section "Create uninstaller" SecAddRem - - SectionIn 1 - SectionIn RO - - ;Create uninstaller - WriteUninstaller "$INSTDIR\MSys_Uninstall.exe" - -SectionEnd - -;-------------------------------- -;Uninstaller Section - -Section "Uninstall" - - !Include ${UNINST_DAT} - - Delete "$INSTDIR\MSys_Uninstall.exe" - -SectionEnd diff --git a/hptool/os-extras/win/templates/Nsisfile.nsi.mu b/hptool/os-extras/win/templates/Nsisfile.nsi.mu index 82b1bd7..c0b4f2b 100644 --- a/hptool/os-extras/win/templates/Nsisfile.nsi.mu +++ b/hptool/os-extras/win/templates/Nsisfile.nsi.mu @@ -17,6 +17,7 @@ !Include "x64.nsh" !insertmacro GetParameters !insertmacro GetOptions + !Include "CommonHP.nsh" ;-------------------------------- ;Defines @@ -33,6 +34,7 @@ Var START_MENU_FOLDER Var PROGRAM_FILES Var STACK_INSTALL_DIR + Var tempDir ;-------------------------------- ;General settings @@ -73,51 +75,6 @@ ;-------------------------------- ;Macros -!macro CheckAdmin thing -UserInfo::GetAccountType -pop $0 -${If} $0 != "admin" ;Require admin rights on NT4+ - MessageBox MB_YESNO "It is recommended to run this ${thing} as administrator. Do you want to quit and restart the ${thing} manually with elevated privileges?" IDNO CheckAdminDone - SetErrorLevel 740 ;ERROR_ELEVATION_REQUIRED - Quit -${EndIf} -CheckAdminDone: -!macroend - - ;-------------------------------- - ;Win 64-bit support - -!macro do64Stuff isInstall - ; The NSIS installer is a 32-bit executable, but it can do a 64-bit install. - ; Default to 32-bit, change if installing 64-bit on 64-bit. - ; - ; The 'isInstall' argument is 1 for the install part of the script (from - ; .onInit function) and 0 if for the uninstall part (via un.onInit). The - ; $INSTDIR must be changed for the installation step to account for the case - ; of installing the 32-bit installer onto 64-bit Windows; and it must - ; happen before the user gets to the dialog to change installation location. - ; On the other hand, $INSTDIR must *not* be changed for the uninstall step - ; because doing so over-rides what the user did during the install step. - ; - ; Also, do not force $INSTDIR to change if this is a silent install. -SetRegView 32 -StrCpy $PROGRAM_FILES "$PROGRAMFILES" -{{#build64bit}} -${If} ${RunningX64} - ; If this is installing the 64-bit HP on 64-bit Windows, enable FSRedirection. - ${EnableX64FSRedirection} - ; enable access to 64-bit portion of registry - SetRegView 64 - StrCpy $PROGRAM_FILES "$PROGRAMFILES64" -${Else} -; pop up an error message: Cannot install 64-bit HP on 32-bit Windows - MessageBox MB_OK "You are trying to install the 64-bit version of the Haskell Platform onto a 32-bit version of Windows. Please use the 32-bit version of the Haskell Platform." - SetErrorLevel 0x800401FAL ; CO_E_WRONGOSFORAPP - Quit -${EndIf} -{{/build64bit}} - -!macroend ;-------------------------------- ;Warn about other HP installs @@ -130,6 +87,8 @@ loop${loopN}: ${StrStr} $2 $1 "HaskellPlatform-" IntOp $0 $0 + 1 StrCmp $2 "" loop${loopN} + ShowWindow $HWNDPARENT ${SW_SHOW} + BringToFront MessageBox MB_YESNO|MB_ICONEXCLAMATION "You have other/older versions of the Haskell Platform installed.$\n\ $\n\ Due to how the PATH environment variable is used (by cabal, etc.) to find the needed GHC toolset, currently only one Haskell Platform can be used at a time. While it is possible to manually modify the PATH variable to work-around this, it is not recommended.$\n\ @@ -147,30 +106,69 @@ done${loopN}: !macroend - !macro CheckOtherInstalls - {{#build64bit}} -SetRegView 64 -!insertmacro CheckForOthers 1 -SetRegView 32 + SetRegView 64 + !insertmacro CheckForOthers 1 + SetRegView 32 {{/build64bit}} !insertmacro CheckForOthers 2 CheckOtherInstallsDone: - {{#build64bit}} -SetRegView 64 + SetRegView 64 {{/build64bit}} +!macroend + + +!macro SubInstallEn thing thingFileName + DetailPrint "extracting ${thing}" + SetOutPath "$tempDir" + File "..\product\${thingFileName}" + DetailPrint "installing ${thing}" + SetDetailsPrint listonly +!macroend + +!macro SubInstallEx thing thingFileName + SetDetailsPrint lastused + DetailPrint "finished ${thing}" + Delete "$tempDir\${thingFileName}" + SetOutPath "$INSTDIR" ; RMDIR on a dir will not work if it is the CWD + RMDir "$tempDir" +!macroend +!macro SubInstall thing thingFileName + !insertmacro SubInstallEn "${thing}" "${thingFileName}" + ExecWait '"$tempDir\${thingFileName}" /S /D=$INSTDIR' + !insertmacro SubInstallEx "${thing}" "${thingFileName}" +!macroend + + +!macro SubUninstall thing thingFileName + Call un.CreateGUID + pop $0 + StrCpy $tempname "$TEMP\uninstHP_$0.exe" + ; copy the uninstaller so it can delete itself + CopyFiles /SILENT /FILESONLY "$INSTDIR\${thingFileName}" "$tempname" + DetailPrint "uninstalling ${thing}" + SetDetailsPrint listonly + ExecWait '"$tempname" /S _?=$INSTDIR' + Delete "$tempname" + SetDetailsPrint lastused !macroend ;-------------------------------- ;Callbacks +Function my.onGUIInit + ShowWindow $HWNDPARENT ${SW_SHOW} + BringToFront +FunctionEnd + Function .onInit + BringToFront !insertmacro do64Stuff 1 !insertmacro CheckAdmin "installer" !insertmacro CheckOtherInstalls @@ -192,7 +190,7 @@ FunctionEnd Function .onInstSuccess SetOutPath "$INSTDIR\bin" - ExecWait '"$INSTDIR\bin\ghc-pkg" recache' + nsExec::Exec '"$INSTDIR\bin\ghc-pkg" recache' ; IfFileExists $SYSDIR\glut32.dll Done ; MessageBox MB_YESNO "It looks like the GLUT library is not installed on your computer. Do you want to install GLUT?" IDNO Done @@ -201,6 +199,11 @@ Function .onInstSuccess ; Done: FunctionEnd +;-------------------------------- +Function CreateGUID + System::Call 'ole32::CoCreateGuid(g .s)' +FunctionEnd + ;-------------------------------- Function un.CreateGUID System::Call 'ole32::CoCreateGuid(g .s)' @@ -216,6 +219,8 @@ FunctionEnd ;-------------------------------- ;Pages + !Define MUI_CUSTOMFUNCTION_GUIINIT my.onGUIInit + !Define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp" !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "LICENSE" @@ -240,7 +245,7 @@ FunctionEnd ; No amount of shenanigans could get the default string to be referenced ; properly, just to add a bit more, so we just need to hardcode it here :( !define MUI_FINISHPAGE_TEXT \ - "$(^NameDA) has been installed on your computer.$\r$\n$\r$\nClick Finish to close this wizard.$\r$\n$\r$\n(You may notice a window briefly appear while GHC package.cache is refreshed.)" + "$(^NameDA) has been installed on your computer.$\r$\n$\r$\nClick Finish to close this wizard." !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_WELCOME @@ -266,64 +271,34 @@ Section "Base components" SecMain ;Meta-installer should not try to re-compress the payloads! SetCompress off + ; Create a unique name for a folder in $TEMP + Call CreateGUID + pop $0 + StrCpy $tempDir "$TEMP\temp_$0" + ; Put the install of stack here so it is first, since it requires additional ; user interaction, and putting it near the end makes the user have to wait. ${If} ${SectionIsSelected} 1 ; ${SecStack} but the symbol is not defined yet - DetailPrint "extracting Stack" - SetOutPath "$INSTDIR\temp" - File "{{stackInstallerPath}}" - DetailPrint "installing Stack" - SetDetailsPrint listonly + !insertmacro SubInstallEn "Stack" "{{stackInstallerPath}}" ${If} ${Silent} - ExecWait '"$INSTDIR\temp\{{stackInstallerFileName}}" /S $STACK_INSTALL_DIR' + ExecWait '"$tempDir\{{stackInstallerFileName}}" /S $STACK_INSTALL_DIR' ${Else} - ExecWait '"$INSTDIR\temp\{{stackInstallerFileName}}" $STACK_INSTALL_DIR' + ExecWait '"$tempDir\{{stackInstallerFileName}}" $STACK_INSTALL_DIR' ${EndIf} - SetDetailsPrint lastused - DetailPrint "finished Stack" - Delete "$INSTDIR\temp\{{stackInstallerFileName}}" - SetOutPath "$INSTDIR" ; RMDIR on a dir will not work if it is the CWD - RMDir "$INSTDIR\temp" + !insertmacro SubInstallEx "Stack" "{{stackInstallerFileName}}" ${EndIf} ; 1. MSys - DetailPrint "extracting MSys" - SetOutPath "$INSTDIR\temp" - File "..\product\MSys-setup.exe" - DetailPrint "installing MSys" - SetDetailsPrint listonly - ExecWait '"$INSTDIR\temp\MSys-setup.exe" /S /D=$INSTDIR' - SetDetailsPrint lastused - DetailPrint "finished MSys" - Delete "$INSTDIR\temp\MSys-setup.exe" - SetOutPath "$INSTDIR" ; RMDIR on a dir will not work if it is the CWD - RMDir "$INSTDIR\temp" + !insertmacro SubInstall "MSys" "MSys-setup.exe" ; 2. HP-provided packages - DetailPrint "extracting Extralibs" - SetOutPath "$INSTDIR\temp" - File "..\product\Extralibs-setup.exe" - DetailPrint "installing Extralibs" - SetDetailsPrint listonly - ExecWait '"$INSTDIR\temp\Extralibs-setup.exe" /S /D=$INSTDIR' - SetDetailsPrint lastused - DetailPrint "finished Extralibs" - Delete "$INSTDIR\temp\Extralibs-setup.exe" - SetOutPath "$INSTDIR" ; RMDIR on a dir will not work if it is the CWD - RMDir "$INSTDIR\temp" + !insertmacro SubInstall "Extralibs" "Extralibs-setup.exe" - ; 3. GHC (and anything else not already covered) - DetailPrint "extracting GHC" - SetOutPath "$INSTDIR\temp" - File "..\product\GHC-setup.exe" - DetailPrint "installing GHC" - SetDetailsPrint listonly - ExecWait '"$INSTDIR\temp\GHC-setup.exe" /S /D=$INSTDIR' - SetDetailsPrint lastused - DetailPrint "finished GHC" - Delete "$INSTDIR\temp\GHC-setup.exe" - SetOutPath "$INSTDIR" ; RMDIR on a dir will not work if it is the CWD - RMDir "$INSTDIR\temp" + ; 3. GHC doc + !insertmacro SubInstall "GHC doc" "GHCDoc-setup.exe" + + ; 4. GHC (and anything else not already covered) + !insertmacro SubInstall "GHC" "GHC-setup.exe" ; Turn compression back on SetCompress auto @@ -395,6 +370,15 @@ Section "Store GHC's location in registry" SecGHCLoc SectionEnd + +Section "Update user's global cabal configuration file" SecUpdCabal + SectionIn 1 + + DetailPrint "updating user's global cabal configuration file" + SetErrorLevel 3 ; magic value meaning for the meta-installer to update +SectionEnd + + Section "Create uninstaller" SecAddRem SectionIn 1 @@ -439,10 +423,10 @@ Section "-StartMenu" StartMenu "$INSTDIR\doc\html\index.html" CreateShortCut \ "$SMPROGRAMS\$START_MENU_FOLDER\GHC Flag Reference.lnk" \ - "$INSTDIR\doc\html\users_guide\flag-reference.html" + "$INSTDIR\doc\html\users_guide\flags.html" CreateShortCut \ "$SMPROGRAMS\$START_MENU_FOLDER\Library Documentation.lnk" \ - "$INSTDIR\lib\extralibs\doc\frames.html" + "$INSTDIR\lib\extralibs\doc\index.html" CreateShortCut "$SMPROGRAMS\$START_MENU_FOLDER\GHCi.lnk" \ "$INSTDIR\bin\ghci.exe" CreateShortCut "$SMPROGRAMS\$START_MENU_FOLDER\WinGHCi.lnk" \ @@ -456,7 +440,7 @@ SectionEnd ;Uninstaller Section ; Section /o "un.Stack" UnSecStack - ; Actually, we do not want ot let user uninstall Stack this way; the user + ; Actually, we do not want to let user uninstall Stack this way; the user ; should remove Stack using the the normal Add/Remove Programs functionality ; in Windows. If we allow this here, the user might have already removed ; Stack using Add/Remove Programs but we would have to go through more @@ -469,44 +453,21 @@ Section "Uninstall" !define MSYS_UNINST "MSys_Uninstall.exe" !define EXTRA_UNINST "Extralibs_Uninstall.exe" !define GHC_UNINST "GHC_Uninstall.exe" + !define GHCDOC_UNINST "GHCDoc_Uninstall.exe" Var /GLOBAL tempname ; uninstall the sub-components ; 1. MSys - Call un.CreateGUID - pop $0 - StrCpy $tempname "$TEMP\uninstHP_$0.exe" - ; copy the uninstaller so it can delete itself - CopyFiles /SILENT /FILESONLY "$INSTDIR\${MSYS_UNINST}" "$tempname" - DetailPrint "uninstalling MSys" - SetDetailsPrint listonly - ExecWait '"$tempname" /S _?=$INSTDIR' - Delete "$tempname" - SetDetailsPrint lastused + !insertmacro SubUninstall "MSys" "${MSYS_UNINST}" ; 2. HP-provided packages - Call un.CreateGUID - pop $0 - StrCpy $tempname "$TEMP\uninstHP_$0.exe" - ; copy the uninstaller so it can delete itself - CopyFiles /SILENT /FILESONLY "$INSTDIR\${EXTRA_UNINST}" "$tempname" - DetailPrint "uninstalling Extralibs" - SetDetailsPrint listonly - ExecWait '"$tempname" /S _?=$INSTDIR' - Delete "$tempname" - SetDetailsPrint lastused + !insertmacro SubUninstall "Extralibs" "${EXTRA_UNINST}" - ; 3. GHC (and anything else not already covered) - Call un.CreateGUID - pop $0 - StrCpy $tempname "$TEMP\uninstHP_$0.exe" - ; copy the uninstaller so it can delete itself - CopyFiles /SILENT /FILESONLY "$INSTDIR\${GHC_UNINST}" "$tempname" - DetailPrint "uninstalling GHC" - SetDetailsPrint listonly - ExecWait '"$tempname" /S _?=$INSTDIR' - Delete "$tempname" - SetDetailsPrint lastused + ; 3. GHC doc + !insertmacro SubUninstall "GHC doc" "${GHCDOC_UNINST}" + + ; 4. GHC (and anything else not already covered) + !insertmacro SubUninstall "GHC" "${GHC_UNINST}" Delete "$INSTDIR\Uninstall.exe" RMDir $INSTDIR diff --git a/hptool/os-extras/win/templates/GHC.nsi.mu b/hptool/os-extras/win/templates/SubInstall.nsi.mu similarity index 51% rename from hptool/os-extras/win/templates/GHC.nsi.mu rename to hptool/os-extras/win/templates/SubInstall.nsi.mu index fd838d0..8854bf7 100644 --- a/hptool/os-extras/win/templates/GHC.nsi.mu +++ b/hptool/os-extras/win/templates/SubInstall.nsi.mu @@ -1,8 +1,8 @@ -;; WARNING: GHC.nsi is automatically generated from GHC.nsi.mu by +;; WARNING: {{productName}}.nsi is automatically generated from {{productName}}.nsi.mu by ;; the hptool. Make sure you are editing the template not the generated file. -; GHC Installer +; {{productName}} Installer ;-------------------------------- ;Includes @@ -12,7 +12,7 @@ !Include "LogicLib.nsh" !Include "MUI2.nsh" !Include "WordFunc.nsh" - !Include "x64.nsh" + !Include "CommonHP.nsh" ;-------------------------------- ;Defines @@ -22,8 +22,9 @@ !Define PRODUCT_DIR_REG_KEY "Software\Haskell\Haskell Platform\${PLATFORM_VERSION}" !Define HACKAGE_SHORTCUT_TEXT "HackageDB - Haskell Software Repository" !Define FILES_SOURCE_PATH "{{targetFiles}}" - !Define INST_DAT "GHC_inst.dat" - !Define UNINST_DAT "GHC_uninst.dat" + !Define INST_DAT "{{productName}}_inst.dat" + !Define UNINST_DAT "{{productName}}_uninst.dat" + !Define PKG_NAME "{{productName}}" ;-------------------------------- ;Variables @@ -34,7 +35,7 @@ ;General settings ;Name and file - Name "Haskell Platform ${PLATFORM_VERSION} {{is32or64}}-bit" + Name "Haskell Platform ${PLATFORM_VERSION} {{is32or64}}-bit ${PKG_NAME}" OutFile "{{productFile}}" ;Default install dir @@ -58,61 +59,6 @@ ;-------------------------------- ;Macros -!macro CheckAdmin thing -UserInfo::GetAccountType -pop $0 -${If} $0 != "admin" ;Require admin rights on NT4+ - MessageBox MB_YESNO "It is recommended to run this ${thing} as administrator. Do you want to quit and restart the ${thing} manually with elevated privileges?" IDNO CheckAdminDone - SetErrorLevel 740 ;ERROR_ELEVATION_REQUIRED - Quit -${EndIf} -CheckAdminDone: -!macroend - - ;-------------------------------- - ;Win 64-bit support - -!macro do64Stuff isInstall - ; The NSIS installer is a 32-bit executable, but it can do a 64-bit install. - ; Default to 32-bit, change if installing 64-bit on 64-bit. - ; - ; The 'isInstall' argument is 1 for the install part of the script (from - ; .onInit function) and 0 if for the uninstall part (via un.onInit). The - ; $INSTDIR must be changed for the installation step to account for the case - ; of installing the 32-bit installer onto 64-bit Windows; and and it must - ; happen before the user gets to the dialog to change installation location. - ; On the other hand, $INSTDIR must *not* be changed for the uninstall step - ; because doing so over-rides what the user did during the install step. - ; - ; Also, do not force $INSTDIR to change if this is a silent install. -SetRegView 32 -StrCpy $PROGRAM_FILES "$PROGRAMFILES" -${IfNot} ${Silent} - ${If} ${isInstall} = 1 - StrCpy $INSTDIR "$PROGRAM_FILES\Haskell Platform\${PLATFORM_VERSION}" - ${EndIf} -${EndIf} -{{#build64bit}} -${If} ${RunningX64} - ; If this is installing the 64-bit HP on 64-bit Windows, enable FSRedirection. - ${EnableX64FSRedirection} - ; enable access to 64-bit portion of registry - SetRegView 64 - StrCpy $PROGRAM_FILES "$PROGRAMFILES64" - ${IfNot} ${Silent} - ${If} ${isInstall} = 1 - StrCpy $INSTDIR "$PROGRAM_FILES\Haskell Platform\${PLATFORM_VERSION}" - ${EndIf} - ${EndIf} -${Else} -; pop up an error message: Cannot install 64-bit HP on 32-bit Windows - MessageBox MB_OK "You are trying to install the 64-bit version of the Haskell Platform onto a 32-bit version of Windows. Please use the 32-bit version of the Haskell Platform." - SetErrorLevel 0x800401FAL ; CO_E_WRONGOSFORAPP - Quit -${EndIf} -{{/build64bit}} -!macroend - ;-------------------------------- ;Callbacks @@ -176,7 +122,7 @@ Section "Create uninstaller" SecAddRem SectionIn RO ;Create uninstaller - WriteUninstaller "$INSTDIR\GHC_Uninstall.exe" + WriteUninstaller "$INSTDIR\{{productName}}_Uninstall.exe" SectionEnd @@ -187,6 +133,6 @@ Section "Uninstall" !Include ${UNINST_DAT} - Delete "$INSTDIR\GHC_Uninstall.exe" + Delete "$INSTDIR\{{productName}}_Uninstall.exe" SectionEnd diff --git a/hptool/os-extras/win/templates/index.html.mu b/hptool/os-extras/win/templates/index.html.mu new file mode 100644 index 0000000..39090f1 --- /dev/null +++ b/hptool/os-extras/win/templates/index.html.mu @@ -0,0 +1,56 @@ + + + + GHC Documentation + + + + +

GHC Documentation

+ +

+ Welcome to GHC! +

+ +

+ This is the top of the GHC documentation tree, where you will find + links to all the supplied documentation about GHC and its libraries. +

+ + + +

For more information, see the following:

+ + diff --git a/hptool/src/CLArgs.hs b/hptool/src/CLArgs.hs new file mode 100644 index 0000000..6668b87 --- /dev/null +++ b/hptool/src/CLArgs.hs @@ -0,0 +1,137 @@ +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE LambdaCase #-} + +-- | Command Line Args handling. + +module CLArgs + ( checkAndValidateArgs + , flags + , Flags(..) + , ValidationErrs + ) + where + +import Control.Monad.Trans.Writer.Strict ( execWriterT ) +import System.Console.GetOpt + +import Types + +import Internal.CLArgs + + +-- | Long Options, provided at top-level so they can be used in the +-- specific error messages (the OptDescr is not very ammenable to mapping +-- from a value in Flags to the option). Note no short options are used +-- since otherwise they likely would conflict with the Shake command-line +-- options, so we use a long option, with an "X" before our "short" option. +-- --Xb: cabal executable file +-- --Xc: core build only +-- --Xf: full build +-- --Xg: ghc-bindist (tar file) +-- --Xh: haddock docs in HTML (tar file) +-- --Xi: print info +-- --Xl: ghc libraries docs in HTML (tar file) +-- --Xp: ghc user's guide PDF (file) +-- --Xs: stack installer or executable file +-- --Xu: ghc user's guide in HTML (tar file) +-- --Xx: set installation prefix (for Posix builds) +optCabalExe, optCore, optFull, optGHCBinDist, optHaddockDocs, optInfo, + optGHCLibsHTML, optGHCUsersPDF, optStackExe, optGHCUsersHTML, optPrefix, + optUsage :: [Char] +optCabalExe = "Xb" +optCore = "Xc" +optFull = "Xf" +optGHCBinDist = "Xg" +optHaddockDocs = "Xh" +optInfo = "Xi" +optGHCLibsHTML = "Xl" +optGHCUsersPDF = "Xp" +optStackExe = "Xs" +optGHCUsersHTML = "Xu" +optPrefix = "Xx" +optUsage = "X?" + +-- If we use the long option of "help", shake intercepts that from us. +flags :: [OptDescr (Either a Flags)] +flags = [ Option "" [optUsage] (NoArg $ Right Usage) + "Show command line flags and options." + , Option "" [optCabalExe] (ReqArg (Right . CabalExe) "PATH") + "Path to the cabal executable to use during build." + , Option "" [optCore] (NoArg (Right $ FlavorFlag BuildFlavorCore)) + "Perform a core-only HP build." + , Option "" [optFull] (NoArg $ Right $ FlavorFlag BuildFlavorFull) + "Perform a full HP build." + , Option "" [optGHCBinDist] (ReqArg (Right . GHCBinDist) "TAR") + "Path to the GHC distribution tarfile." + , Option "" [optHaddockDocs] (ReqArg (Right . HaddockHTML) "TAR") + "WINDOWS: Path to Haddock documentation tarfile." + , Option "" [optInfo] (NoArg $ Right Info) + "Show details on packages are in this HP release." + , Option "" [optGHCLibsHTML] (ReqArg (Right . GHCLibsHTML) "TAR") + "WINDOWS: Path to GHC library docs tarfile." + , Option "" [optGHCUsersPDF] (ReqArg (Right . GHCUsersPDF) "PDF") + "WINDOWS: Path to the GHC User's Guide (PDF file)." + , Option "" [optStackExe] (ReqArg (Right . StackExe) "PATH") + "Path to the stack installer or executable." + , Option "" [optGHCUsersHTML] (ReqArg (Right . GHCUsersHTML) "TAR") + "WINDOWS: Path to GHC User's Guide (HTML) tarfile." + , Option "" [optPrefix] (ReqArg (Right . Prefix) "DIR") + "Set a custom install prefix (only Posix builds)." + ] + +flagsToConfig :: UserConfig -> Flags -> UserConfig +flagsToConfig uc Info = uc +flagsToConfig uc@UserConfig{..} (Prefix a) = uc{ ucPrefix = Just a } +flagsToConfig uc@UserConfig{..} (FlavorFlag a) = uc{ ucBuildFlavor = a } +flagsToConfig uc@UserConfig{..} (CabalExe a) = uc{ ucCabalExe = a } +flagsToConfig uc@UserConfig{..} (GHCBinDist a) = uc{ ucGHCBinDist = a } +flagsToConfig uc@UserConfig{..} (StackExe a) = uc{ ucStackExe = a } +flagsToConfig uc@UserConfig{..} (GHCUsersPDF a) = uc{ ucGHCUsersPDF = a } +flagsToConfig uc@UserConfig{..} (GHCUsersHTML a) = uc{ ucGHCUsersHTML = a } +flagsToConfig uc@UserConfig{..} (GHCLibsHTML a) = uc{ ucGHCLibsHTML = a } +flagsToConfig uc@UserConfig{..} (HaddockHTML a) = uc{ ucHaddockHTML = a } +flagsToConfig uc Usage = uc + +defUserConfig :: UserConfig +defUserConfig = UserConfig Nothing BuildFlavorCore "" "" "" "" "" "" "" + +checkAndValidateArgs :: (Monad m) => Bool -> (FilePath -> m Bool) -> [Flags] + -> m (UserConfig, ValidationErrs) +checkAndValidateArgs buildWin doesFileExist flgVals = do + let checkRequiredAndExists' = checkRequiredAndExists doesFileExist flgVals + uc = defUserConfig + -- Some flags are required only for Windows, and are misleading if + -- otherwise provided. + validator = + if buildWin then checkRequiredAndExists' else checkExcess flgVals + validationErrors <- execWriterT $ do + checkCoreOrFull flgVals + checkRequiredAndExists' + (\case (CabalExe s) -> Just s + _ -> Nothing ) + "cabal executable" optCabalExe + checkRequiredAndExists' + (\case (GHCBinDist s) -> Just s + _ -> Nothing ) + "GHC distro tarfile" optGHCBinDist + checkRequiredAndExists' + (\case (StackExe s) -> Just s + _ -> Nothing ) + "Stack installer/executable" optStackExe + validator (\case (GHCUsersPDF s) -> Just s + _ -> Nothing ) + "GHC User's Guide (PDF file)" optGHCUsersPDF + validator (\case (GHCUsersHTML s) -> Just s + _ -> Nothing ) + "GHC User's Guide (HTML tarfile)" optGHCUsersHTML + validator (\case (GHCLibsHTML s) -> Just s + _ -> Nothing ) + "Required: path to Libraries Doc HTML tarfile" optGHCLibsHTML + validator (\case (HaddockHTML s) -> Just s + _ -> Nothing ) + "Required: path to Haddock HTML tarfile" optHaddockDocs + let userConfigValidated = + if (not $ null validationErrors ) + then uc + else foldl flagsToConfig uc flgVals + return ( userConfigValidated, validationErrors ) diff --git a/hptool/src/Config.hs b/hptool/src/Config.hs index 235a378..677dcef 100644 --- a/hptool/src/Config.hs +++ b/hptool/src/Config.hs @@ -1,5 +1,5 @@ {-# LANGUAGE ConstraintKinds, DeriveDataTypeable, GeneralizedNewtypeDeriving, - RecordWildCards #-} + RecordWildCards, TypeFamilies #-} module Config ( askHpRelease @@ -8,6 +8,10 @@ module Config , addConfigOracle , askCabalExe , askStackExe + , askGhcUgPDF + , askGhcUgHtml + , askGhcLibs + , askHaddockHTML ) where @@ -16,38 +20,24 @@ import Data.List.Split (splitOn) import Development.Shake import Development.Shake.Classes import Development.Shake.FilePath -import Development.Shake.Rule import Types -import Utils (readMaybe, version) +import Utils (version) -readOracle :: (ShakeValue q, Read a) => String -> q -> Action a -readOracle name q = do - s <- askOracle q - maybe (error $ msg s) return $ readMaybe reads s - where - msg s = "readOracle failed to parse " ++ name ++ " from " ++ show s - -{- -Release and BuildConfig are not used directly in the oracles because writing all -the required instances is possible but lengthly, and Version is missing -instances for both Hashable and Binary. It is easier to just rely on the -generated instances of Show and Read for these, and use String in the oracle. --} - newtype HpReleaseQ = HpReleaseQ () deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult HpReleaseQ = Release -- | Provide the Platform release information -- The release information will be tracked as a dependency - askHpRelease :: Action Release -askHpRelease = readOracle "HpRelease" (HpReleaseQ ()) +askHpRelease = askOracle $ HpReleaseQ () newtype GhcBinDistTarFileQ = GhcBinDistTarFileQ () deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult GhcBinDistTarFileQ = FilePath -- | Provide the bindist tar file. -- The filepath will be tracked as a dependency. @@ -60,18 +50,17 @@ askGhcBinDistTarFile = do newtype BuildConfigQ = BuildConfigQ () deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult BuildConfigQ = BuildConfig -- | Provide the Platform release information -- The release information will be tracked as a dependency - askBuildConfig :: Action BuildConfig -askBuildConfig = readOracle "BuildConfig" (BuildConfigQ ()) +askBuildConfig = askOracle $ BuildConfigQ () -newtype StackExeQ = StackExeQ () - deriving (Show,Typeable,Eq,Hashable,Binary,NFData) -newtype CabalExeQ = CabalExeQ () +newtype StackExeQ = StackExeQ () deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult StackExeQ = FilePath -- | Provide the stack executable -- The filepath will be tracked as a dependency @@ -81,6 +70,11 @@ askStackExe = do need [stackexe] return stackexe + +newtype CabalExeQ = CabalExeQ () + deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult CabalExeQ = FilePath + -- | Provide the stack executable -- The filepath will be tracked as a dependency askCabalExe :: Action FilePath @@ -89,10 +83,54 @@ askCabalExe = do need [cabalexe] return cabalexe -addConfigOracle :: Release -> FilePath -> (FilePath,FilePath) -> Maybe FilePath -> Bool -> Rules BuildConfig -addConfigOracle hpRel tarFile (cabalexe,stackexe) prefix includeExtra = do +newtype GhcUsersGuidePDFFileQ = GhcUsersGuidePDFFileQ () + deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult GhcUsersGuidePDFFileQ = FilePath + +askGhcUgPDF :: Action FilePath +askGhcUgPDF = do + fname <- askOracle $ GhcUsersGuidePDFFileQ () + need [fname] + return fname + + +newtype GhcUsersGuideHTMLTarFileQ = GhcUsersGuideHTMLTarFileQ () + deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult GhcUsersGuideHTMLTarFileQ = FilePath + +askGhcUgHtml :: Action FilePath +askGhcUgHtml = do + fname <- askOracle $ GhcUsersGuideHTMLTarFileQ () + need [fname] + return fname + + +newtype GhcLibsHTMLTarFileQ = GhcLibsHTMLTarFileQ () + deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult GhcLibsHTMLTarFileQ = FilePath + +askGhcLibs :: Action FilePath +askGhcLibs = do + fname <- askOracle $ GhcLibsHTMLTarFileQ () + need [fname] + return fname + + +newtype HaddockHTMLTarFileQ = HaddockHTMLTarFileQ () + deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult HaddockHTMLTarFileQ = FilePath + +askHaddockHTML :: Action FilePath +askHaddockHTML = do + fname <- askOracle $ HaddockHTMLTarFileQ () + need [fname] + return fname + + +addConfigOracle :: Release -> UserConfig -> Rules BuildConfig +addConfigOracle hpRel userConfig = do _ <- addOracle $ - \(HpReleaseQ _) -> return $ show hpRel + \(HpReleaseQ _) -> return hpRel _ <- addOracle $ \(GhcBinDistTarFileQ _) -> return tarFile _ <- addOracle $ @@ -100,9 +138,26 @@ addConfigOracle hpRel tarFile (cabalexe,stackexe) prefix includeExtra = do _ <- addOracle $ \(StackExeQ _) -> return stackexe _ <- addOracle $ - \(BuildConfigQ _) -> either fail (return . show) buildConfig + \(GhcUsersGuidePDFFileQ _) -> return ghcUgPdf + _ <- addOracle $ + \(GhcUsersGuideHTMLTarFileQ _) -> return ghcUgHtml + _ <- addOracle $ + \(GhcLibsHTMLTarFileQ _) -> return ghcLibsHtml + _ <- addOracle $ + \(HaddockHTMLTarFileQ _) -> return haddockHtml + _ <- addOracle $ + \(BuildConfigQ _) -> either fail return buildConfig either fail return buildConfig where + tarFile = ucGHCBinDist userConfig + cabalexe = ucCabalExe userConfig + stackexe = ucStackExe userConfig + prefix = ucPrefix userConfig + ghcUgPdf = ucGHCUsersPDF userConfig + ghcUgHtml = ucGHCUsersHTML userConfig + ghcLibsHtml = ucGHCLibsHTML userConfig + haddockHtml = ucHaddockHTML userConfig + includeExtra = ucBuildFlavor userConfig == BuildFlavorFull buildConfig = extractBuildConfig hpRel tarFile prefix includeExtra diff --git a/hptool/src/GhcDist.hs b/hptool/src/GhcDist.hs index 62596e7..fee4444 100644 --- a/hptool/src/GhcDist.hs +++ b/hptool/src/GhcDist.hs @@ -38,12 +38,12 @@ cppCommandFlags cpp = case cpp of CPP_cpphs -> "--cpp -traditional" -ghcInstall :: GhcInstall -> +ghcInstall :: GhcInstall -> String -> FilePath -> Maybe (BuildConfig -> FilePath) -> Action (Maybe FilePath) -ghcInstall postUntarAction base mfPrefix = do +ghcInstall postUntarAction suffix base mfPrefix = do tarFile <- askGhcBinDistTarFile conf <- askBuildConfig - let distDir = ghcBinDistDir $ bcGhcVersion conf + let distDir = ghcBinDistDir suffix (bcGhcVersion conf) untarDir = takeDirectory distDir makeDirectory untarDir @@ -110,10 +110,10 @@ ghcDistRules :: Rules () ghcDistRules = do ghcLocalDir %/> \_ -> do postUntar <- osGhcLocalInstall . osFromConfig <$> askBuildConfig - ghcInstall postUntar ghcLocalDir Nothing >> return () + ghcInstall postUntar "" ghcLocalDir Nothing >> return () ghcVirtualTarget ~/> do postUntar <- osGhcTargetInstall . osFromConfig <$> askBuildConfig - ghcInstall postUntar targetDir (Just targetPrefix) + ghcInstall postUntar "-tmp" targetDir (Just targetPrefix) where targetPrefix = osGhcPrefix . osFromConfig diff --git a/hptool/src/Internal/CLArgs.hs b/hptool/src/Internal/CLArgs.hs new file mode 100644 index 0000000..f744a36 --- /dev/null +++ b/hptool/src/Internal/CLArgs.hs @@ -0,0 +1,75 @@ +{-# LANGUAGE RecordWildCards #-} + +-- | An internal module used by the Command Line Args handling, split out +-- to facilitate the unit tests. + +module Internal.CLArgs + ( checkCoreOrFull + , checkRequiredAndExists + , checkExcess + , Flags(..) + , ValidationErrs + ) + where + +import Control.Monad ( unless, when ) +import Control.Monad.Trans.Writer.Strict ( tell, WriterT ) +import Control.Monad.Trans.Class ( lift ) +import Data.List ( find ) +import Data.Maybe ( fromJust, isJust ) + +import Types + + +data Flags = Info | Usage + | Prefix String + | FlavorFlag BuildFlavor + | CabalExe String | GHCBinDist String | StackExe String + | GHCUsersPDF String | GHCUsersHTML String | GHCLibsHTML String + | HaddockHTML String + deriving (Eq) + +type ValidationErrs = [String] + +unlessM :: (Monad m) => m Bool -> m () -> m () +unlessM mp m = mp >>= \p -> unless p m + +checkRequiredAndExists :: (Monad m, Foldable t) => + (FilePath -> m Bool) -> t a -> (a -> Maybe FilePath) + -> String -> [Char] + -> WriterT ValidationErrs m () +checkRequiredAndExists doesFileExist flgVals maybeIsFlag flagDesc longOpt = do + case (find (isJust . maybeIsFlag) flgVals) of + Just a -> do + let fname = fromJust $ maybeIsFlag a + unlessM (lift $ doesFileExist fname) $ + fileDoesNotExistError flagDesc fname + Nothing -> missingArgError flagDesc longOpt + +fileDoesNotExistError :: (Monad m) => String -> FilePath + -> WriterT ValidationErrs m () +fileDoesNotExistError flagDesc fn = + tell [ flagDesc ++ ": File does not exist: \"" ++ fn ++ "\"." ] + +missingArgError :: (Monad m) => String -> String -> WriterT ValidationErrs m () +missingArgError flagDesc longOpt = + tell [ "Required: path to " ++ flagDesc ++ ". Use --" ++ longOpt ++ "." ] + +checkCoreOrFull :: (Monad m) => [Flags] -> WriterT ValidationErrs m () +checkCoreOrFull flgVals = do + let isFull = isJust $ find ((==) (FlavorFlag BuildFlavorFull)) flgVals + isCore = isJust $ find ((==) (FlavorFlag BuildFlavorCore)) flgVals + when (isFull == isCore) $ tell [ "Must specify exactly one of --Xf or --Xc." ] + +excessArgError :: (Monad m) => String -> [Char] -> WriterT ValidationErrs m () +excessArgError flagDesc longOpt = + tell [ "Unused flag: " ++ flagDesc ++ ". This platform does not use -" + ++ longOpt ++ "."] + +checkExcess :: (Monad m, Foldable t) => + t a -> (a -> Maybe FilePath) -> String -> [Char] + -> WriterT ValidationErrs m () +checkExcess flgVals maybeIsFlag flagDesc longOpt = do + case (find (isJust . maybeIsFlag) flgVals) of + Just _ -> excessArgError flagDesc longOpt + _ -> return () diff --git a/hptool/src/Main.hs b/hptool/src/Main.hs index 4243a70..c274afa 100644 --- a/hptool/src/Main.hs +++ b/hptool/src/Main.hs @@ -2,14 +2,16 @@ module Main where -import Control.Monad (forM_) -import Data.Monoid (mconcat) +import Control.Monad ( forM_ ) +import Data.List ( intercalate ) import Development.Shake import Development.Shake.FilePath -import System.Console.GetOpt +import System.Console.GetOpt ( usageInfo ) +import System.Directory as SD ( doesFileExist ) import qualified System.Info (os, arch) import System.IO +import CLArgs import Config import Dirs import GhcDist @@ -24,29 +26,26 @@ import Types import Target import Website -data Flags = Info | Prefix String | Full - deriving Eq - -flags :: [OptDescr (Either a Flags)] -flags = [ Option ['i'] ["info"] (NoArg $ Right Info) - "Show info on what gets included in this HP release" - , Option [] ["prefix"] (ReqArg (Right . Prefix) "DIR") - "Set installation prefix (only for Posix builds)" - , Option ['f'] ["full"] (NoArg $ Right Full) - "Do a full (rather than core) build of the platform." - ] main :: IO () main = hSetEncoding stdout utf8 >> shakeArgsWith opts flags main' where - main' flgs args = - if Info `elem` flgs - then info - else case args of - (tarfile:cabalexe:stackexe:buildType) -> return $ Just $ do - allRules tarfile (cabalexe,stackexe) flgs - want $ if null buildType then ["build-all"] else buildType - _ -> usage + main' flgVals nonFlagArgs = + if Info `elem` flgVals then info + else + if Usage `elem` flgVals then usage + else do + -- if we were to do cross-building, using System.Info.os is incorrect + let buildWin = System.Info.os == "mingw32" + (uc, v) <- checkAndValidateArgs buildWin SD.doesFileExist flgVals + if (not $ null v ) + then do + putStrLn "ERRORS:" + putStrLn $ intercalate "\n" v + usage + else return $ Just $ do + allRules uc + want $ if null nonFlagArgs then ["build-all"] else nonFlagArgs info = do putStrLn $ "This hptool is built to construct " ++ hpFullName ++ "\n\ @@ -57,8 +56,10 @@ main = hSetEncoding stdout utf8 >> shakeArgsWith opts flags main' return Nothing usage = do - putStrLn "usage: hptool --info\n\ - \ hptool [opts] [target...]\n\ + putStr $ usageInfo + "usage: hptool --info\n\ + \ hptool --help\n\ + \ hptool [args] [target...]\n\ \ where target is one of:\n\ \ build-all -- build everything (default)\n\ \ build-source -- build the source tar ball\n\ @@ -67,12 +68,22 @@ main = hSetEncoding stdout utf8 >> shakeArgsWith opts flags main' \ build-package- -- build the package (name or name-ver)\n\ \ build-local -- build the local GHC environment\n\ \ build-website -- build the website\n\ - \ and opts may be 'f' for a full rather than core build, 'i' for info\n\ - \ or 'prefix=...' to set a custom install location prefix for linux" + \ and args may be:" flags + putStrLn "NOTE:\n\ + \ The GHC binary distro, the cabal executable, and the \n\ + \ stack installer/executable are *required*.\n\ + \ Further, for the Windows platform, four additional\n\ + \ arguments are also required:\n\ + \ * the GHC Library documentation (tarfile)\n\ + \ * the GHC User's Guide (HTML format, tarfile)\n\ + \ * the GHC User's Guide (single PDF file)\n\ + \ * the Haddock documentation (HTML format, tarfile)" + return Nothing - allRules tarfile stackcabalexe flgs = do - buildConfig <- addConfigOracle hpRelease tarfile stackcabalexe (prefixSetting flgs) (Full `elem` flgs) + allRules :: UserConfig -> Rules () + allRules userConfig = do + buildConfig <- addConfigOracle hpRelease userConfig ghcDistRules packageRules targetRules buildConfig @@ -81,11 +92,6 @@ main = hSetEncoding stdout utf8 >> shakeArgsWith opts flags main' buildRules hpRelease srcTarFile buildConfig websiteRules "website" - prefixSetting = mconcat . reverse . map ps - where - ps (Prefix p) = Just p - ps _ = Nothing - opts = shakeOptions hpRelease = hp_8_4_3 diff --git a/hptool/src/OS/Win.hs b/hptool/src/OS/Win.hs index 0c15764..d063f05 100644 --- a/hptool/src/OS/Win.hs +++ b/hptool/src/OS/Win.hs @@ -19,8 +19,6 @@ import qualified Distribution.Package as C import qualified Distribution.Text as C ( display ) #endif -import Dirs -import LocalCommand import OS.Internal import OS.Win.WinPaths import OS.Win.WinRules @@ -136,35 +134,7 @@ winOsFromConfig BuildConfig{..} = os osProduct = winProductFile bcIncludeExtra hpVersion bcArch - osRules _rel bc = do - winRules - - osProduct %> \_ -> do - need $ [dir ghcLocalDir, phonyTargetDir, vdir ghcVirtualTarget] - - copyWinTargetExtras bc - - -- Now, targetDir is actually ready to snapshot (we skipped doing - -- this in osGhcTargetInstall). - void $ getDirectoryFiles "" [targetDir ++ "//*"] - - need winNeeds - need winExtraNeeds - - -- Now, it is time to make sure there are no problems with the - -- conf files copied to - localCommand' [] "ghc-pkg" - [ "recache" - , "--package-db=" ++ winGhcTargetPackageDbDir ] - localCommand' [] "ghc-pkg" - [ "check" - , "--package-db=" ++ winGhcTargetPackageDbDir ] - - -- Build installer now; makensis must be run in installerPartsDir - command_ [Cwd installerPartsDir] "makensis" [extralibsNsisFileName] - command_ [Cwd installerPartsDir] "makensis" [msysNsisFileName] - command_ [Cwd installerPartsDir] "makensis" [ghcNsisFileName] - command_ [Cwd installerPartsDir] "makensis" [nsisFileName] + osRules _rel _bc = winRules osProduct osPackageConfigureExtraArgs _ = [ "--prefix=" ++ toCabalPrefix osHpPrefix diff --git a/hptool/src/OS/Win/WinNsis.hs b/hptool/src/OS/Win/WinNsis.hs index c5fcaef..cc57646 100644 --- a/hptool/src/OS/Win/WinNsis.hs +++ b/hptool/src/OS/Win/WinNsis.hs @@ -2,12 +2,12 @@ module OS.Win.WinNsis ( genNsisFiles ) where -import Control.Monad ( join ) +import Control.Monad ( join, void ) import Data.List ( sortBy ) import Data.Ord ( comparing ) -import Data.Version ( Version ) import Development.Shake -import Development.Shake.FilePath ( toNative, takeDirectory, takeFileName ) +import Development.Shake.FilePath ( (), toNative, takeDirectory + , takeFileName ) import System.FilePath ( equalFilePath, splitDirectories ) import System.Posix.Types ( FileOffset ) import System.PosixCompat.Files ( fileSize, getFileStatus ) @@ -15,41 +15,123 @@ import Text.Hastache ( MuType(..), MuContext ) import Text.Hastache.Context (mkStrContext) import Config +import Dirs ( (%/>), dir, vdir ) +import LocalCommand (localCommand' ) import OS.Win.WinPaths import OS.Win.WinUtils -import Paths ( phonyTargetDir ) -import Templates +import Paths ( ghcLocalDir, ghcVirtualTarget, installerPartsDir, phonyTargetDir + , targetDir ) +import Templates ( copyExpandedFile, ctxAppend, platformContext ) import Types import Utils data InfoForTemplate = InfoForTemplate - { iftGetProdName :: (Bool -> Version -> String -> FilePath) - , iftNSISFile :: FilePath - , iftStackFile :: FilePath - , iftStackInstalledSize :: FileOffset - , iftMainInstalledSize :: FileOffset + { iftProdName :: String -- Name for (sub-)installer (e.g., "Foo") + , iftProdFile :: FilePath -- (Sub-)installer filename (e.g., "foo.exe") + , iftNSISFile :: FilePath -- (Sub-)installer.nsi path (rooted at buildRoot) + , iftStackFile :: FilePath -- path to the stack installer + , iftStackInstalledSize :: FileOffset -- size in bytes of stack (installed) + , iftMainInstalledSize :: FileOffset -- size in bytes of 'target' dir } -- | Using a template, generate the NSIS files. Note that this file will -- contain definitions of variables which are used by the inst.dat and -- uninst.dat files (which get included into the NSIS file during the build -- of the installer). That is, there is a coupling between these files. -genNsisFiles :: Rules () -genNsisFiles = do +genNsisFiles :: FilePath -> Rules () +genNsisFiles osProduct = do ghcNsisInstDat %> makeInstDat ghcInstFilter winTargetDir ghcNsisUninstDat %> makeUninstDat ghcUninstFilter winTargetDir - msysNsisInstDat %> makeInstDat filterEmptyDirs winMSysTargetDir - msysNsisUninstDat %> makeUninstDat sortByDirRev winMSysTargetDir + ghcDocNsisInstDat %> makeInstDat filterEmptyDirs winDocTargetDir + ghcDocNsisUninstDat %> makeUninstDat sortByDirRev winDocTargetDir + + -- copy msys(msys2) pieces + winMSysTargetDir %/> \_ -> do + bc <- askBuildConfig + copyDirAction (winExternalMSysDir bc) winMSysTargetDir + + msysNsisInstDat %> \fn -> do + need [ dir winMSysTargetDir ] + makeInstDat filterEmptyDirs winMSysTargetDir fn + msysNsisUninstDat %> \fn -> do + need [ dir winMSysTargetDir ] + makeUninstDat sortByDirRev winMSysTargetDir fn extralibsNsisInstDat %> makeInstDat filterEmptyDirs winHpTargetDir extralibsNsisUninstDat %> makeUninstDat sortByDirRev winHpTargetDir - nsisFile %> expandAndCopy nsiTemplate winProductFile - ghcNsisFile %> expandAndCopy ghcNsiTemplate ghcProductFile - msysNsisFile %> expandAndCopy msysNsiTemplate msysProductFile - extralibsNsisFile %> expandAndCopy extralibsNsiTemplate extralibsProductFile + commonNshFile %> \fn -> do + need [ commonNshTemplate ] + expandAndCopy "CommonNsh" commonNshTemplate commonNshFile fn + nsisFile %> \fn -> do + need [ nsiTemplate, commonNshFile ] + expandAndCopy "Haskell Platform" nsiTemplate nsisFileProductFile fn + ghcNsisFile %> \fn -> do + need [ subInstNsiTemplate, commonNshFile ] + expandAndCopy "GHC" subInstNsiTemplate ghcProductFile fn + ghcDocNsisFile %> \fn -> do + need [ subInstNsiTemplate, commonNshFile ] + expandAndCopy "GHCDoc" subInstNsiTemplate ghcDocProductFile fn + msysNsisFile %> \fn -> do + need [ subInstNsiTemplate, commonNshFile ] + expandAndCopy "MSys" subInstNsiTemplate msysProductFile fn + extralibsNsisFile %> \fn -> do + need [ subInstNsiTemplate, commonNshFile ] + expandAndCopy "Extralibs" subInstNsiTemplate extralibsProductFile fn + bootstrapNsisFile %> \fn -> do + need [ bootstrapNsiTemplate, commonNshFile ] + expandAndCopy "Bootstrap" bootstrapNsiTemplate osProduct fn + + -- Create the main doc/index.html from the template + docIndexFile %> \_ -> do + pCtx <- platformContext + copyExpandedFile pCtx docIndexTmpl docIndexFile + + -- Build installer rules; makensis must be run in installerPartsDir + ghcProductFile %> \_ -> do + need [ ghcNsisFile, ghcNsisInstDat, ghcNsisUninstDat ] + command_ [Cwd installerPartsDir] "makensis" [ghcNsisFileName] + ghcDocProductFile %> \_ -> do + need [ ghcDocNsisFile, ghcDocNsisInstDat, ghcDocNsisUninstDat ] + command_ [Cwd installerPartsDir] "makensis" [ghcDocNsisFileName] + msysProductFile %> \_ -> do + need [ msysNsisFile, msysNsisInstDat, msysNsisUninstDat ] + command_ [Cwd installerPartsDir] "makensis" [msysNsisFileName] + extralibsProductFile %> \_ -> do + need [ extralibsNsisFile, extralibsNsisInstDat, extralibsNsisUninstDat ] + command_ [Cwd installerPartsDir] "makensis" [extralibsNsisFileName] + nsisFileProductFile %> \_ -> do + need $ [dir ghcLocalDir, phonyTargetDir, vdir ghcVirtualTarget] + + copyWinTargetExtras + + -- Now, targetDir is actually ready to snapshot (we skipped doing + -- this in osGhcTargetInstall). + void $ getDirectoryFiles "" [targetDir ++ "//*"] + + need winNeeds + + -- Now, it is time to make sure there are no problems with the + -- conf files copied to + localCommand' [] "ghc-pkg" + [ "recache" + , "--package-db=" ++ winGhcTargetPackageDbDir ] + localCommand' [] "ghc-pkg" + [ "check" + , "--package-db=" ++ winGhcTargetPackageDbDir ] + + -- in parallel, build the sub-installers + need winSubProductFiles + command_ [Cwd installerPartsDir] "makensis" [nsisFileName] + + osProduct %> \_ -> do + need [ nsisFileProductFile ] + need [ bootstrapNsisFile ] + -- Build main installer; makensis must be run in installerPartsDir + command_ [Cwd installerPartsDir] "makensis" [bootstrapNsisFileName] + where makeInstDat instFilter targDir dFile = do need [phonyTargetDir] @@ -60,16 +142,18 @@ genNsisFiles = do dirs <- getDirsFiles uninstFilter targDir genData nsisUninstDatTmpl uFile dirs - -- ghc bucket covers all directories and files not in msys or extralibs - -- since targetDir contains the msys sub-dir as well as lib/extralibs, + -- ghc bucket covers all directories and files not in msys, extralibs, + -- or ghc's doc directory. + -- + -- Since targetDir contains all the files in the entire release, -- we need to filter those paths out as they are covered by the - -- msys and extralibs .dat lists. N.b.: Filtering by names could be + -- msys, extralibs, ghcdoc .dat lists. N.b.: Filtering by names could be -- fragile in light of any directory, package, structuring changes. -- Also note that even in for the "core" HP build, there are still -- a few things in extralibs (specifically alex and happy, as well as - -- the cabal executable.) - ghcInstFilter = filterEmptyDirs . skipExtralibs . skipMSys - ghcUninstFilter = sortByDirRev . skipExtralibs . skipMSys + -- the cabal executable). + ghcInstFilter = filterEmptyDirs . skipGHCDoc . skipExtralibs . skipMSys + ghcUninstFilter = sortByDirRev . skipGHCDoc . skipExtralibs . skipMSys -- For install, sort doesn't matter when parent vs child dir is created; -- For uninstall, deeper directories must be removed before their parent @@ -80,16 +164,22 @@ genNsisFiles = do -- install but leave them for uninstall. filterEmptyDirs = filter (\(_,fs) -> not $ null fs) + -- Note there filters any file with "doc" in the directory path, not just + -- GHC doc, so this is nasty. In this case, there is a "doc" within + -- "extralibs" as well, but it is ok since we want no "extralibs" anyway. + skipGHCDoc = filter (\(d, _) -> + not $ any (equalFilePath "doc") (splitDirectories d)) + skipExtralibs = filter (\(d, _) -> not $ any (equalFilePath "extralibs") (splitDirectories d)) skipMSys = filter (\(d, _) -> not $ any (equalFilePath "msys") (splitDirectories d)) - getDirsFiles f dir = liftIO $ + getDirsFiles f dr = liftIO $ makeNativeRelPaths <$> f <$> - getDirContentsR dir + getDirContentsR dr where makeNativeRelPath = toNative . (`relativeToDir` winTargetDir) makeNativeRelPaths = @@ -116,33 +206,44 @@ genNsisFiles = do getFileSize :: FilePath -> IO FileOffset getFileSize f = fileSize <$> getFileStatus f - getDirContentSize f dir = liftIO $ + getDirContentSize f d = liftIO $ (sum <$>) $ join $ (mapM (\(_,fs) -> sum <$> mapM getFileSize fs)) <$> f <$> - getDirContentsR dir + getDirContentsR d - expandAndCopy templ pFile nFile = do + expandAndCopy nm templ pFile nFile = do stackFile <- askStackExe bc <- askBuildConfig - rls <- askHpRelease pCtx <- platformContext mainSize <- getDirContentSize filterEmptyDirs winTargetDir - let nsisCtx = expandNsisInfo rls bc ift + let nsisCtx = expandNsisInfo bc ift ctx = nsisCtx `ctxAppend` pCtx stackSize = 48 * 1024 * 1024 -- not sure how to automatically determine - ift = InfoForTemplate pFile nFile stackFile stackSize mainSize + ift = InfoForTemplate nm pFile nFile stackFile stackSize mainSize copyExpandedFile ctx templ nFile -expandNsisInfo :: (Monad m) => Release -> BuildConfig -> InfoForTemplate -> +-- | Expand the template, replacing following "keys" with values: +-- * key value +-- * osProductFileName The final installer executable's filename +-- * productFile The path (rooted at build) for this (sub-)installer +-- * productName The string to use in UI for this (sub-)installer +-- * build64bit Boolean: true if installer exe is 64-bit native +-- * is32or64 String: for UI to show "32" or "64" +-- * etc. +expandNsisInfo :: (Monad m) => BuildConfig -> InfoForTemplate -> MuContext m -expandNsisInfo rls BuildConfig{..} InfoForTemplate{..} = mkStrContext ex +expandNsisInfo BuildConfig{..} InfoForTemplate{..} = mkStrContext ex where - productFile = iftGetProdName bcIncludeExtra hpver bcArch + productFile = iftProdFile `relativeToDir` takeDirectory iftNSISFile -- NSIS tool needs to run from the installerPartsDir + HpVersion{..} = bcHpVersion + osProductFileName = winProductFileName bcIncludeExtra hpVersion bcArch + ex "osProductFileName" = MuVariable osProductFileName ex "productFile" = MuVariable . toNative $ productFile + ex "productName" = MuVariable iftProdName ex "build64bit" = MuBool is64 ex "is32or64" = MuVariable $ if is64 then "64" else "32" ex "programFiles64" = MuVariable $ if is64 then "64" else "" @@ -160,7 +261,46 @@ expandNsisInfo rls BuildConfig{..} InfoForTemplate{..} = mkStrContext ex ex _ = MuNothing is64 = bcArch == "x86_64" - hpver = hpVersion . relVersion $ rls -- NSIS wants this in "kilobytes" inKB :: FileOffset -> Int inKB b = truncate $ (fromIntegral b) / (1024::Double) + +copyWinTargetExtras :: Action () +copyWinTargetExtras = do + -- copy icons + let mkIconsDir = makeDirectory $ winTargetDir "icons" + copyFilesAction mkIconsDir winExtrasSrc winTargetDir winIconsFiles + + -- copy user's guide docs: ps, pdf, html, etc.... + makeDirectory winDocTargetDir + + ghcUgHtml <- askGhcUgHtml + need [ghcUgHtml] + command_ [Cwd winDocTargetDir] + "tar" ["xf", ghcUgHtml `relativeToDir` winDocTargetDir] + + ghcLibsHtml <- askGhcLibs + need [ghcLibsHtml] + command_ [Cwd winDocTargetDir] + "tar" ["xf", ghcLibsHtml `relativeToDir` winDocTargetDir] + + haddockHtml <- askHaddockHTML + need [haddockHtml] + command_ [Cwd winDocTargetDir] + "tar" ["xf", haddockHtml `relativeToDir` winDocTargetDir] + + -- needContents winDocTargetDir -- needed here? is done by our caller, actually + + -- copy the PDF version of the GHC User's Guide + -- (copyFilesAction does the 'need' on the PDF file) + ghcUgPdf <- askGhcUgPDF + need [ghcUgPdf] + copyFileAction (return ()) (takeDirectory ghcUgPdf) winDocTargetDir + (takeFileName ghcUgPdf) + + -- copy winghci pieces + copyDirAction winExternalWinGhciDir winWinGhciTargetDir + + -- copy cabal executable + cabalFile <- askCabalExe + copyFileAction (return ()) (takeDirectory cabalFile) (winHpTargetDir "bin") (takeFileName cabalFile) diff --git a/hptool/src/OS/Win/WinPaths.hs b/hptool/src/OS/Win/WinPaths.hs index b71442f..4d59ce1 100644 --- a/hptool/src/OS/Win/WinPaths.hs +++ b/hptool/src/OS/Win/WinPaths.hs @@ -20,7 +20,7 @@ winTemplates = winExtrasSrc "templates" -- | File name of the data file used by NSIS to create the installer exe --- (this is everything (including GHC) that is not MSys or extralibs) +-- (this is everything (including GHC) that is not MSys, extralibs, or ghc doc) nsisFileName :: FilePath nsisFileName = "Nsisfile.nsi" @@ -28,6 +28,20 @@ nsisFileName = "Nsisfile.nsi" nsisFile :: FilePath nsisFile = installerPartsDir nsisFileName +-- | The full sub-installer file name; it is internal only; +-- launched by bootstrapper. +nsisFileProductFileName :: FilePath +nsisFileProductFileName = "HP-setup" <.> "exe" + +-- | Directory where the MSys sub-installer file is built. +nsisFileProductFile :: FilePath +nsisFileProductFile = productDir nsisFileProductFileName + +commonNshFileName :: FilePath +commonNshFileName = "CommonHP.nsh" + +commonNshFile :: FilePath +commonNshFile = installerPartsDir commonNshFileName -- | MSys installation data files msysNsisFileName :: FilePath @@ -47,8 +61,8 @@ msysProductFileName :: FilePath msysProductFileName = "MSys-setup" <.> "exe" -- | Directory where the MSys sub-installer file is built. -msysProductFile :: Bool -> Version -> String -> FilePath -msysProductFile _isFull _hpv _arch = productDir msysProductFileName +msysProductFile :: FilePath +msysProductFile = productDir msysProductFileName -- | Extralibs installation data files @@ -69,8 +83,8 @@ extralibsProductFileName :: FilePath extralibsProductFileName = "Extralibs-setup" <.> "exe" -- | Directory where the extralibs sub-installer file is built. -extralibsProductFile :: Bool -> Version -> String -> FilePath -extralibsProductFile _ _ _ = productDir extralibsProductFileName +extralibsProductFile :: FilePath +extralibsProductFile = productDir extralibsProductFileName -- | GHC installation data files @@ -91,8 +105,41 @@ ghcProductFileName :: FilePath ghcProductFileName = "GHC-setup" <.> "exe" -- | Directory where the GHC sub-installer file is built. -ghcProductFile :: Bool -> Version -> String -> FilePath -ghcProductFile _ _ _ = productDir ghcProductFileName +ghcProductFile :: FilePath +ghcProductFile = productDir ghcProductFileName + + +-- | GHC doc installation data files +ghcDocNsisFileName :: FilePath +ghcDocNsisFileName = "GHCDoc.nsi" + +ghcDocNsisFile :: FilePath +ghcDocNsisFile = installerPartsDir ghcDocNsisFileName + +ghcDocNsisInstDat :: FilePath +ghcDocNsisInstDat = installerPartsDir "GHCDoc_inst.dat" + +ghcDocNsisUninstDat :: FilePath +ghcDocNsisUninstDat = installerPartsDir "GHCDoc_uninst.dat" + +-- | The GHC Doc sub-installer file name; it is internal only +ghcDocProductFileName :: FilePath +ghcDocProductFileName = "GHCDoc-setup" <.> "exe" + +-- | Directory where the GHC doc sub-installer file is built. +ghcDocProductFile :: FilePath +ghcDocProductFile = productDir ghcDocProductFileName + + +-- | A tiny installer just to launch the full installer and also to +-- modify/install the user's cabal config, which is kept separate +-- so that it does not elevate to admin and updates the config as the user. +-- Since this is the overall wrapper, it gets the "main" file name. +bootstrapNsisFileName :: FilePath +bootstrapNsisFileName = "Bootstrapper.nsi" + +bootstrapNsisFile :: FilePath +bootstrapNsisFile = installerPartsDir bootstrapNsisFileName -- | Pre-built or unchanging files that need to be included in the installer @@ -104,15 +151,14 @@ winInstExtras = map (installerPartsDir ) winInstExtrasFiles nsiTemplate :: FilePath nsiTemplate = winTemplates "Nsisfile.nsi.mu" -msysNsiTemplate :: FilePath -msysNsiTemplate = winTemplates "MSys.nsi.mu" - -extralibsNsiTemplate :: FilePath -extralibsNsiTemplate = winTemplates "Extralibs.nsi.mu" +subInstNsiTemplate :: FilePath +subInstNsiTemplate = winTemplates "SubInstall.nsi.mu" -ghcNsiTemplate :: FilePath -ghcNsiTemplate = winTemplates "GHC.nsi.mu" +commonNshTemplate :: FilePath +commonNshTemplate = winTemplates "CommonHP.nsh.mu" +bootstrapNsiTemplate :: FilePath +bootstrapNsiTemplate = winTemplates "Bootstrapper.nsi.mu" nsisInstDatTmpl :: FilePath nsisInstDatTmpl = winTemplates "inst.dat.mu" @@ -121,6 +167,14 @@ nsisUninstDatTmpl :: FilePath nsisUninstDatTmpl = winTemplates "uninst.dat.mu" +-- | Template file and end-result file for the overall index.html +docIndexFile :: FilePath +docIndexFile = winDocTargetDir "index.html" + +docIndexTmpl :: FilePath +docIndexTmpl = winTemplates "index.html.mu" + + -- | Some scripts and unchanging data files needed for the installer winInstExtrasFiles :: [FilePath] winInstExtrasFiles = [ "EnvVarUpdate.nsh" @@ -138,15 +192,11 @@ winIconsFiles = [ "icons/installer.ico" , "icons/hackage.ico" ] --- | This is the place for pre-built files (e.g., docs from GHC), which +-- | This is the place for pre-built files (e.g., Glut libraries), which -- will be installed, but are not part of the build or of hptool. winExternalSrc :: FilePath winExternalSrc = "winExternalSrc" --- | These will be copied to the top-level doc directory -winExternalDocs :: FilePath -winExternalDocs = winExternalSrc "doc" - -- | Source info (paths & names) for GLUT pieces, which will be simply copied winExternalGlut :: FilePath winExternalGlut = winExternalSrc "glut" @@ -239,14 +289,11 @@ winGhcTargetPackageDbDir = winTargetDir winGhcPackageDbDir -- | Additional build targets needed for the Windows version of HP winNeeds :: [FilePath] -winNeeds = [ nsisFile, - msysNsisFile, msysNsisInstDat, msysNsisUninstDat, - ghcNsisFile, ghcNsisInstDat, ghcNsisUninstDat +winNeeds = [ nsisFile + , docIndexFile ] ++ winInstExtras --- | Additional build targets needed for the Windows version of full HP --- (note however, that alex and happy live here, so we always need these) -winExtraNeeds :: [FilePath] -winExtraNeeds = [ - extralibsNsisFile, extralibsNsisInstDat, extralibsNsisUninstDat ] +winSubProductFiles :: [FilePath] +winSubProductFiles = [ + ghcDocProductFile, ghcProductFile, extralibsProductFile, msysProductFile ] diff --git a/hptool/src/OS/Win/WinRules.hs b/hptool/src/OS/Win/WinRules.hs index ac1f5ce..b39360d 100644 --- a/hptool/src/OS/Win/WinRules.hs +++ b/hptool/src/OS/Win/WinRules.hs @@ -1,8 +1,7 @@ {-# LANGUAGE RecordWildCards, OverloadedStrings #-} module OS.Win.WinRules - ( copyWinTargetExtras - , pkgrootConfFixup + ( pkgrootConfFixup , winGhcInstall , winRules ) @@ -12,9 +11,8 @@ import qualified Data.ByteString as B import qualified Data.Text as T import qualified Data.Text.Encoding as E import Development.Shake -import Development.Shake.FilePath ( (), takeDirectory, takeFileName ) +import Development.Shake.FilePath ( () ) -import Config import Dirs import OS.Internal import OS.Win.WinNsis @@ -25,17 +23,15 @@ import Types import Utils -winRules :: Rules () -winRules = do - genNsisFiles +winRules :: FilePath -> Rules () +winRules osProduct = do + genNsisFiles osProduct copyInstExtras winGhcInstall :: FilePath -> GhcInstallAction winGhcInstall destDir bc distDir = do - let untarDir = takeDirectory distDir - -- (will this cause some race conditions, removing vs populating?) - command_ [] "mv" [untarDir show (bcGhcVersion bc), destDir ] + command_ [] "mv" [distDir, destDir ] -- Install the GLUT components into destDir: -- lib, dll, ... @@ -57,27 +53,6 @@ winGhcInstall destDir bc distDir = do return . Just $ destDir - -copyWinTargetExtras :: BuildConfig -> Action () -copyWinTargetExtras bc = do - -- copy icons - let mkIconsDir = makeDirectory $ winTargetDir "icons" - copyFilesAction mkIconsDir winExtrasSrc winTargetDir winIconsFiles - - -- copy user's guide docs: ps, pdf, html, etc.... - copyDirAction winExternalDocs winDocTargetDir - - -- copy winghci pieces - copyDirAction winExternalWinGhciDir winWinGhciTargetDir - - -- copy msys(msys2) pieces - copyDirAction (winExternalMSysDir bc) winMSysTargetDir - - -- copy cabal executable - cabalFile <- askCabalExe - copyFileAction (return ()) (takeDirectory cabalFile) (winHpTargetDir "bin") (takeFileName cabalFile) - - -- | These files are needed when building the installer copyInstExtras :: Rules () copyInstExtras = do @@ -108,24 +83,3 @@ pkgrootConfFixup os confFile = do copyFilesRules :: Action () -> FilePath -> FilePath -> [FilePath] -> Rules () copyFilesRules setup srcDir dstDir = mapM_ (\f -> dstDir f %> \_ -> copyFileAction setup srcDir dstDir f) - -copyFileAction :: Action () -> FilePath -> FilePath -> FilePath -> Action () -copyFileAction setup srcDir dstDir file = do - need [srcDir file] - setup - command_ [] "cp" ["-p", srcDir file, dstDir file] - -copyFilesAction :: Action () -> FilePath -> FilePath -> [FilePath] -> Action () -copyFilesAction setup srcDir dstDir files = do - setup - mapM_ (copyFileAction (return ()) srcDir dstDir) files - -copyDirAction :: FilePath -> FilePath -> Action () -copyDirAction srcDir dstDir = do - needContents srcDir - makeDirectory dstDir - -- Two problems: seems that () strips the "." out, so use (++); - -- second problem is that using an "*" in the path results in an error, - -- so "/." works better. - command_ [] "cp" ["-pR", srcDir ++ "/.", dstDir] - needContents dstDir diff --git a/hptool/src/OS/Win/WinUtils.hs b/hptool/src/OS/Win/WinUtils.hs index ccab1cb..ae4097e 100644 --- a/hptool/src/OS/Win/WinUtils.hs +++ b/hptool/src/OS/Win/WinUtils.hs @@ -1,5 +1,8 @@ module OS.Win.WinUtils ( DirContents + , copyDirAction + , copyFileAction + , copyFilesAction , getDirContents , getDirContentsR , parseConfFile @@ -10,11 +13,13 @@ module OS.Win.WinUtils import Control.Applicative ( (<$>), liftA ) import Control.Monad ( forM, unless ) import Data.Either ( partitionEithers ) -import Development.Shake ( Action, putNormal ) +import Development.Shake ( Action, need, putNormal, command_ ) import Development.Shake.FilePath ( toNative, () ) import qualified Distribution.InstalledPackageInfo as C import qualified System.Directory ( doesDirectoryExist, getDirectoryContents ) +import Dirs ( needContents ) +import Utils ( makeDirectory ) type DirContents = [(FilePath, [FilePath])] @@ -54,3 +59,24 @@ parseConfFile confFile conf = -- Cabal on Windows requires an absolute, native-format prefix. toCabalPrefix :: FilePath -> FilePath toCabalPrefix = toNative . ("C:/" ++) + +copyFileAction :: Action () -> FilePath -> FilePath -> FilePath -> Action () +copyFileAction setup srcDir dstDir file = do + need [srcDir file] + setup + command_ [] "cp" ["-p", srcDir file, dstDir file] + +copyFilesAction :: Action () -> FilePath -> FilePath -> [FilePath] -> Action () +copyFilesAction setup srcDir dstDir files = do + setup + mapM_ (copyFileAction (return ()) srcDir dstDir) files + +copyDirAction :: FilePath -> FilePath -> Action () +copyDirAction srcDir dstDir = do + needContents srcDir + makeDirectory dstDir + -- Two problems: seems that () strips the "." out, so use (++); + -- second problem is that using an "*" in the path results in an error, + -- so "/." works better. + command_ [] "cp" ["-pR", srcDir ++ "/.", dstDir] + needContents dstDir -- is this 'need' here correct? we do this in Win.hs diff --git a/hptool/src/Package.hs b/hptool/src/Package.hs index 587dced..7c5209c 100644 --- a/hptool/src/Package.hs +++ b/hptool/src/Package.hs @@ -7,7 +7,7 @@ module Package import Control.Applicative ((<$>)) import Data.Graph (flattenSCCs, stronglyConnComp) -import Data.List (isPrefixOf, isInfixOf) +import Data.List ( isInfixOf) #if MIN_VERSION_base(4,6,0) import Data.Ord (Down(..)) #endif diff --git a/hptool/src/Paths.hs b/hptool/src/Paths.hs index 7753b58..ce605be 100644 --- a/hptool/src/Paths.hs +++ b/hptool/src/Paths.hs @@ -74,8 +74,10 @@ packageTargetConf = packageBase "target.conf" -- reg. for target inst. extractPackage :: FilePath -> Package extractPackage = read . takeFileName . takeDirectory -ghcBinDistDir :: GhcVersion -> FilePath -ghcBinDistDir ghcVer = buildRoot "ghc-bindist" show ghcVer +-- There are two times where the ghc dist is untarred, so allow a unique path +-- for each instance. +ghcBinDistDir :: String -> GhcVersion -> FilePath +ghcBinDistDir s ghcVer = buildRoot ("ghc-bindist" ++ s) show ghcVer ghcLocalDir :: FilePath ghcLocalDir = buildRoot "ghc-bindist" "local" @@ -148,6 +150,3 @@ sourceForPackageDir p = sourceRoot show p markerRoot :: FilePath markerRoot = buildRoot ".markers" - - - diff --git a/hptool/src/Target.hs b/hptool/src/Target.hs index d06655c..bf3d0b7 100644 --- a/hptool/src/Target.hs +++ b/hptool/src/Target.hs @@ -34,8 +34,8 @@ targetRules bc = do let OS{..} = osFromConfig bc' let packages = platformPackages (bcIncludeExtra bc') hpRel - need $ vdir ghcVirtualTarget - : dir (haddockDocDir bc') + need [ vdir ghcVirtualTarget ] + need $ dir (haddockDocDir bc') : map (dir . (targetDir ) . osPackageTargetDir) packages osTargetAction @@ -85,9 +85,18 @@ buildAction buildDir hpRel bc = do ] cabalVerbosity <- show . fromEnum <$> shakeToCabalVerbosity + -- This variable, cabal, has the command, plus any global options. + -- The global options must appear before the command (in arg named 'c') let cabal c as = localCommand' [Cwd buildDir] "cabal" $ - c : ("--verbose=" ++ cabalVerbosity) : as - when (not isAlexOrHappy) $ + cabalGlobalOpts ++ + (c : ("--verbose=" ++ cabalVerbosity) : as) + -- To make the HP build cleaner, use a default cabal config file + cabalGlobalOpts = + [ "--config-file=" ++ + (buildRoot "cabal.conf") `relativeToDir` buildDir ] + when (not isAlexOrHappy) $ do + -- work-around cabal 2.2 bug with clean + makeDirectory (buildDir "dist/build") cabal "clean" [] -- This is a hack to handle when packages, other -- than alex or happy themselves, have outdated -- bootstrap files in their sdist tarballs. @@ -181,4 +190,4 @@ stripAbiDepends f = do ls <- lines <$> readFile f _ <- evaluate $ length ls let (l1,l2) = break ("abi-depends:" `isPrefixOf`) ls - writeFile f $ unlines $ l1 ++ (dropWhile (all isSeparator . take 1) (drop 1 l2)) \ No newline at end of file + writeFile f $ unlines $ l1 ++ (dropWhile (all isSeparator . take 1) (drop 1 l2)) diff --git a/hptool/src/Types.hs b/hptool/src/Types.hs index d94b20c..6e78f56 100644 --- a/hptool/src/Types.hs +++ b/hptool/src/Types.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE CPP, RecordWildCards #-} +{-# LANGUAGE CPP, RecordWildCards, DeriveAnyClass, DeriveGeneric #-} module Types ( PackageName @@ -12,14 +12,17 @@ module Types , BuildConfig(..) , GhcInstallAction , GhcInstall(..) + , BuildFlavor(..) + , UserConfig(..) ) where -import Control.Applicative import Data.Char (isDigit) -import Data.List (intercalate) +import Data.List (intercalate, sort) import Data.Version (Version, showVersion, parseVersion) import Development.Shake (Action) +import Development.Shake.Classes (Binary, Hashable, NFData) +import GHC.Generics import Text.ParserCombinators.ReadP (ReadP, char, endBy1, munch, readP_to_S, satisfy, skipSpaces) @@ -32,6 +35,7 @@ type PackageName = String -- a hyphen between the two parts. i.e.: "acme-inator-0.1.0.0". Note that no -- component of a package name can start with a digit. data Package = Package { pkgName :: PackageName, pkgVersion :: Version } + deriving (Eq, Ord, Generic, Hashable, Binary, NFData) readPackageP :: ReadP Package readPackageP = do @@ -58,7 +62,7 @@ instance Show Package where data IncludeType = IncGHC | IncGHCLib | IncGHCTool | IncLib | IncTool | IncIfWindows IncludeType | IncIfNotWindows IncludeType - deriving (Eq, Read, Show) + deriving (Eq, Read, Show, Ord, Generic, Hashable, Binary, NFData) readFixedPacakgeP :: (Version -> a) -> String -> ReadP a @@ -72,6 +76,7 @@ readFixedPacakgeP f fixedName = do -- | Version of the platform itself. -- 'Read'/'Show' format is "haskell-platform-" newtype HpVersion = HpVersion { hpVersion :: Version } + deriving (Eq, Generic, Hashable, Binary, NFData) instance Read HpVersion where readsPrec _ = readP_to_S $ readFixedPacakgeP HpVersion "haskell-platform" instance Show HpVersion where @@ -80,6 +85,7 @@ instance Show HpVersion where -- | Version of the GHC. -- 'Read'/'Show' format is "ghc-" newtype GhcVersion = GhcVersion { ghcVersion :: Version } + deriving (Eq, Generic, Hashable, Binary, NFData) instance Read GhcVersion where readsPrec _ = readP_to_S $ readFixedPacakgeP GhcVersion "ghc" instance Show GhcVersion where @@ -94,7 +100,14 @@ data Release = Release , relMinimalIncludes :: [Include] , relIncludes :: [Include] } - deriving (Read, Show) + deriving (Read, Show, Generic, Hashable, Binary, NFData) +-- The order of entries in the relMinimalIncludes and relIncludes does not +-- matter for equality (and these lists will have 20-40 entries max with no +-- duplicates), so this Eq instance addresses that. +instance Eq Release where + (Release v1 m1 i1) == (Release v2 m2 i2) = + (v1 == v2) && (sortedEq m1 m2) && (sortedEq i1 i2) + where sortedEq as bs = (sort as) == (sort bs) -- | The configuration of a build. These are the parameters of the build that -- specify what type of system this build of Haskell Platform is for. It @@ -111,7 +124,7 @@ data BuildConfig = BuildConfig , bcPrefix :: Maybe FilePath -- ex.: "/usr/local/haskell" , bcIncludeExtra :: Bool } - deriving (Read, Show) + deriving (Read, Show, Eq, Generic, Hashable, Binary, NFData) -- | A function that is used for the actions after untar-ing GHC. -- The build configuration and file path of the untar-ed directory is @@ -128,3 +141,26 @@ data GhcInstall = -- the haddock-html field; the second is the haddock-interfaces field. data HaddockPkgLoc = HaddockPkgLoc { pkgLocHtml, pkgLocIntf :: String } deriving (Show) + +-- | The HP can be built in two flavors: full or core, where "full" is +-- "all the batteries included" (the full, agreed upon set of packages felt to +-- be most useful to many GHC users); and "core" is just GHC, the packages +-- included with its release (and minimally needed to successfully compile and +-- link). +data BuildFlavor = BuildFlavorCore | BuildFlavorFull + deriving (Eq, Show) + +-- | The digested user-provided flags and arguments for the build. +-- Used for setting the user requests into the "oracle". +data UserConfig = UserConfig + { ucPrefix :: Maybe FilePath + , ucBuildFlavor :: BuildFlavor + , ucCabalExe :: FilePath + , ucGHCBinDist :: FilePath + , ucStackExe :: FilePath + , ucGHCUsersPDF :: FilePath + , ucGHCUsersHTML :: FilePath + , ucGHCLibsHTML :: FilePath + , ucHaddockHTML :: FilePath + } + deriving (Show) diff --git a/hptool/src/Utils.hs b/hptool/src/Utils.hs index f6b2f63..823eeaf 100644 --- a/hptool/src/Utils.hs +++ b/hptool/src/Utils.hs @@ -80,7 +80,9 @@ removeDirectoryRecursive fp = do command_ [] "rm" [ "-Rf", "--", fp] makeDirectory :: FilePath -> Action () -makeDirectory fp = liftIO $ createDirectoryIfMissing True fp +makeDirectory fp = do + putNormal $ "createDirectoryIfMissing \""++fp++"\"" + liftIO $ createDirectoryIfMissing True fp writeFileLinesChanged :: FilePath -> [String] -> Action () writeFileLinesChanged fp = writeFileChanged fp . unlines diff --git a/hptool/tests/UnitTests.hs b/hptool/tests/UnitTests.hs new file mode 100644 index 0000000..64ffb42 --- /dev/null +++ b/hptool/tests/UnitTests.hs @@ -0,0 +1,16 @@ +module Main + ( main + ) where + +import Test.Tasty + +import qualified UnitTests.CLArgs + + +tests :: IO TestTree +tests = do + clArgs <- UnitTests.CLArgs.tests + return $ testGroup "Unit Tests" [ clArgs ] + +main :: IO () +main = tests >>= defaultMain diff --git a/hptool/tests/UnitTests/CLArgs.hs b/hptool/tests/UnitTests/CLArgs.hs new file mode 100644 index 0000000..0508fa1 --- /dev/null +++ b/hptool/tests/UnitTests/CLArgs.hs @@ -0,0 +1,160 @@ +{-# LANGUAGE LambdaCase #-} + +module UnitTests.CLArgs + ( tests + ) + where + +import Control.Monad.Trans.Writer.Strict ( execWriterT ) +import Data.List ( delete ) +import Test.Tasty +import Test.Tasty.Hspec + +import CLArgs +import Internal.CLArgs +import Types + + +doesFileExistMock :: (Monad m) => FilePath -> m Bool +doesFileExistMock "./exists" = return True +doesFileExistMock _ = return False + +checkRequiredAndExistsTestSimple :: [Flags] -> IO ValidationErrs +checkRequiredAndExistsTestSimple flgVals = + execWriterT $ do + checkRequiredAndExists doesFileExistMock flgVals + (\case (GHCBinDist s) -> Just s + _ -> Nothing ) + "GHC distro tarfile" ['x'] + +checkRequiredAndExistsTestArgExists :: IO ValidationErrs +checkRequiredAndExistsTestArgExists = checkRequiredAndExistsTestSimple flgVals + where flgVals = [ GHCBinDist "./exists" ] + +checkRequiredAndExistsTestNoArg :: IO ValidationErrs +checkRequiredAndExistsTestNoArg = checkRequiredAndExistsTestSimple flgVals + where flgVals = [] + +additionalRequiredForWin :: [Flags] +additionalRequiredForWin = [ GHCUsersHTML "./exists" + , GHCLibsHTML "./exists" + , HaddockHTML "./exists" + , GHCUsersPDF "./exists" + ] + +allRequiredFlagsCommon :: [Flags] +allRequiredFlagsCommon = [ CabalExe "./exists" + , GHCBinDist "./exists" + , StackExe "./exists" + , FlavorFlag BuildFlavorFull + ] + +allRequiredFlagsWin :: [Flags] +allRequiredFlagsWin = allRequiredFlagsCommon ++ additionalRequiredForWin + +checkAndValidateArgsTestSimple' :: Bool -> [Flags] -> IO ValidationErrs +checkAndValidateArgsTestSimple' buildWin flgVals = do + (_, v) <- checkAndValidateArgs buildWin doesFileExistMock flgVals + return v + +checkAndValidateArgsTestSimple :: [Flags] -> IO ValidationErrs +checkAndValidateArgsTestSimple = checkAndValidateArgsTestSimple' True + +checkAndValidateArgsTestAllExistsWin :: IO ValidationErrs +checkAndValidateArgsTestAllExistsWin = + checkAndValidateArgsTestSimple allRequiredFlagsWin + +checkAndValidateArgsTestAllExistsNonWin :: IO ValidationErrs +checkAndValidateArgsTestAllExistsNonWin = + checkAndValidateArgsTestSimple' False allRequiredFlagsCommon + +checkAndValidateArgsTestOneMissingFlag :: IO ValidationErrs +checkAndValidateArgsTestOneMissingFlag = checkAndValidateArgsTestSimple flgVals + where flgVals = delete (GHCBinDist "./exists") allRequiredFlagsWin + +checkAndValidateArgsTestOneMissingFile :: IO ValidationErrs +checkAndValidateArgsTestOneMissingFile = checkAndValidateArgsTestSimple flgVals + where flgVals = (GHCBinDist "") : + delete (GHCBinDist "./exists") allRequiredFlagsWin + +checkAndValidateArgsTestBothFC :: IO ValidationErrs +checkAndValidateArgsTestBothFC = checkAndValidateArgsTestSimple flgVals + where flgVals = (FlavorFlag BuildFlavorCore) : allRequiredFlagsWin + +checkAndValidateArgsTestNeitherFC :: IO ValidationErrs +checkAndValidateArgsTestNeitherFC = checkAndValidateArgsTestSimple flgVals + where flgVals = delete (FlavorFlag BuildFlavorFull) allRequiredFlagsWin + +checkAndValidateArgsTestExcess :: IO ValidationErrs +checkAndValidateArgsTestExcess = checkAndValidateArgsTestSimple' False flgVals + where flgVals = allRequiredFlagsWin + +checkAndValidateArgsTestAllMissingWin :: IO ValidationErrs +checkAndValidateArgsTestAllMissingWin = checkAndValidateArgsTestSimple [] + +checkAndValidateArgsTestAdditionalMissingWin :: IO ValidationErrs +checkAndValidateArgsTestAdditionalMissingWin = + checkAndValidateArgsTestSimple allRequiredFlagsCommon + +checkAndValidateArgsTestAllMissingNonWin :: IO ValidationErrs +checkAndValidateArgsTestAllMissingNonWin = + checkAndValidateArgsTestSimple' False [] + +checkCoreOrFullTest :: [Flags] -> IO ValidationErrs +checkCoreOrFullTest = execWriterT . checkCoreOrFull + +tests :: IO TestTree +tests = do + hs <- hspecTests + return $ testGroup "CLArgs unit tests" [hs] + +hspecTests :: IO TestTree +hspecTests = do + testSpec "CLArgs HSpec tests" $ do + describe "checkAndValidateArgs" $ do + it "succeeds given a Flag and the file exists" $ + checkRequiredAndExistsTestArgExists >>= (`shouldSatisfy` null) + it "fails given a missing Flag" $ + checkRequiredAndExistsTestNoArg >>= (`shouldSatisfy` (not . null)) + describe "checkAndValidateArgs" $ do + it "succeeds given a list of all required Flags (Windows)" $ + checkAndValidateArgsTestAllExistsWin >>= (`shouldSatisfy` null) + it "succeeds given a list of all required Flags (non-Windows)" $ + checkAndValidateArgsTestAllExistsNonWin >>= (`shouldSatisfy` null) + it "fails given a full list, less one missing Flag" $ + checkAndValidateArgsTestOneMissingFlag >>= + (`shouldSatisfy` (not . null)) + it "fails given a full list, but one file doesn't exist" $ + checkAndValidateArgsTestOneMissingFile >>= + (`shouldSatisfy` (not . null)) + it "fails if given both -f and -c" $ + checkAndValidateArgsTestBothFC >>= (`shouldSatisfy` (not . null)) + it "fails if given neither -f nor -c" $ + checkAndValidateArgsTestNeitherFC >>= (`shouldSatisfy` (not . null)) + it "fails given an arg only for Windows on non-Windows build" $ + checkAndValidateArgsTestExcess >>= (`shouldSatisfy` (not . null)) + it ("fails with " ++ (show . length $ allRequiredFlagsWin) + ++ " errors when given no args, on Windows") $ + checkAndValidateArgsTestAllMissingWin >>= + (\x -> (length allRequiredFlagsWin) `shouldBe` (length x)) + it ("fails with " ++ (show . length $ additionalRequiredForWin) + ++ " errors if missing additionals for Windows") $ + checkAndValidateArgsTestAdditionalMissingWin >>= + (\x -> (length additionalRequiredForWin) `shouldBe` (length x)) + it ("fails with " ++ (show . length $ allRequiredFlagsCommon) + ++ " errors when given no args, on non-Windows") $ + checkAndValidateArgsTestAllMissingNonWin >>= + (\x -> (length allRequiredFlagsCommon) `shouldBe` (length x)) + describe "checkCoreOrFull" $ do + it "fails given both -f and -c" $ + checkCoreOrFullTest + [FlavorFlag BuildFlavorFull, FlavorFlag BuildFlavorCore] + >>= (`shouldSatisfy` (not . null)) + it "fails given neither -f nor -c" $ + checkCoreOrFullTest [] >>= (`shouldSatisfy` (not . null)) + it "succeeds given only -f" $ + checkCoreOrFullTest [FlavorFlag BuildFlavorFull] + >>= (`shouldSatisfy` null) + it "succeeds given only -c" $ + checkCoreOrFullTest [FlavorFlag BuildFlavorCore] + >>= (`shouldSatisfy` null) diff --git a/windows-platform.sh b/windows-platform.sh index ae60280..3844768 100644 --- a/windows-platform.sh +++ b/windows-platform.sh @@ -1,35 +1,44 @@ #!/bin/sh -TAR_FILE=$1 -tar_name=${TAR_FILE##*/} -tar_vers=${tar_name#*-} -GHC_VERS=${tar_vers%%-*} +echo '***' +echo '*** ' $(date) "HP installer tool started" +echo '***' # These may need to be edited to suit your specific environment # MSYS_BIN is needed on path for configure scripts; -# HASK_BIN is needed on path for shake.exe, HsColour.exe (maybe cabal.exe) +## HASK_BIN is needed on path for haddock.exe, HsColour.exe (maybe cabal.exe) +# CABAL_BIN for cabal.exe # NSIS_BIN is needed on path for makensisw.exe -MSYS_BIN="/c/Program Files (x86)/MinGW/msys/1.0/bin" -HASK_BIN="/c/Program Files/Haskell/bin:/c/Program Files/Haskell Platform/2014.2.0.0/lib/extralibs/bin" -NSIS_BIN="/c/Program Files (x86)/NSIS" +# MSYSTEM_PREFIX: set by the msys2 shell; either "/mingw64" or "/mingw32" + +MSYS_BIN="$MSYSTEM_PREFIX/bin:/usr/bin" +# CABAL_BIN="/f/Program Files/Haskell Platform/8.4.2/lib/extralibs/bin" +# or something like this to use the cabal which is part of build +# CABAL_BIN="/d/haskell/ghc-8.4.3/x86_64/cabal-install-2.2.0.0-x86_64-unknown-mingw32" +# CABAL_BIN="/d/haskell/ghc-8.4.3/i386/cabal-install-2.2.0.0-i386-unknown-mingw32" +CABAL_BIN="/d/haskell/ghc-8.2.2/x86_64/cabal-install-2.0.0.1-x86_64-unknown-mingw32" +HSCOLOUR_BIN="/f/Program Files/Haskell Platform/8.2.2/lib/extralibs/bin" +# HASK_BIN="/d/haskell/ghc-8.4.2/i386/cabal-install-2.2.0.0-i386-unknown-mingw32" + +NSIS_BIN="/f/Program Files (x86)/NSIS" GHC_BINDIST=build/ghc-bindist/local HPTOOL=hptool/dist/build/hptool/hptool.exe -if ( cabal sandbox --help >/dev/null 2>&1 ) ; then +if ( $CABAL_BIN/cabal sandbox --help >/dev/null 2>&1 ) ; then if [ \! -d hptool/.cabal-sandbox ] then echo '***' echo '*** Setting up sandbox for hptool' echo '***' - cabal update - (cd hptool; cabal sandbox init; cabal install --only-dependencies) + $CABAL_BIN/cabal update + (cd hptool; $CABAL_BIN/cabal sandbox init; $CABAL_BIN/cabal install --only-dependencies) fi else - if ( cabal install --dry-run --only-dependencies | grep -q 'would be installed' ) ; then + if ( $CABAL_BIN/cabal install --dry-run --only-dependencies | grep -q 'would be installed' ) ; then echo '=== pre-requisite packages for hptool are not installed' echo ' run the following:' - echo ' cd hptool ; cabal install --only-dependencies' + echo ' cd hptool ; $CABAL_BIN/cabal install --only-dependencies' exit 1 fi fi @@ -37,25 +46,35 @@ fi echo '***' echo '*** Building hptool' echo '***' -(cd hptool; cabal build) +(cd hptool; $CABAL_BIN/cabal build) CWD=`pwd` MINGW=$GHC_BINDIST/mingw # A clean, well-lighted, cruft-free PATH -export PATH=$CWD/$GHC_BINDIST/bin:$CWD/$MINGW/bin:$MSYS_BIN:$NSIS_BIN:$HASK_BIN +export PATH=$CWD/$GHC_BINDIST/bin:$CWD/$MINGW/bin:$MSYS_BIN:$NSIS_BIN:$CABAL_BIN:$HSCOLOUR_BIN +echo "> echo \$PATH" +echo $PATH which cabal || { echo "Could not find cabal.exe on PATH!"; echo "PATH=$PATH"; exit 1; } which makensisw || { echo "Could not find makensisw.exe on PATH!"; echo "PATH=$PATH"; exit 1; } +which tar || + { echo "Could not find tar.exe on PATH!"; echo "PATH=$PATH"; exit 1; } echo "> cabal --version" cabal --version -echo "> which haddock" -which haddock -echo "> haddock --version" -haddock --version +# haddock should come from the ghc release itself, so this is obsolete +# echo "> which haddock" +# which haddock +# echo "> haddock --version" +# haddock --version + +echo "> which hscolour" +which hscolour +echo "> hscolour --version" +hscolour --version # Make sure makensisw.exe is compiled with support for large strings # makensisw="/c/Program\ Files\ \(x86\)/NSIS/Orig/makensis //HDRINFO" @@ -86,10 +105,6 @@ if [ \! \( -d winExternalSrc \ -a -d winExternalSrc/glut/lib/x86_64 \ -a -e winExternalSrc/glut/lib/x86_64/libglut32.a \ -a -e winExternalSrc/glut/lib/x86_64/glut32.dll \ - -a -d winExternalSrc/doc \ - -a -e winExternalSrc/doc/users_guide.ps \ - -a -e winExternalSrc/doc/users_guide.pdf \ - -a -d winExternalSrc/doc/html \ -a -d winExternalSrc/winghci \ -a -e winExternalSrc/winghci/winghci.exe \ -a -d winExternalSrc/msys/i386/usr \ @@ -101,7 +116,6 @@ then echo 'to be provided:' echo ' * winghci (can copy from a previous HP release)' echo ' * GLUT library & DLL (e.g,. from freeglut-MinGW-2.8.1-1.mp.zip)' - echo " * GHC user's guide (matching the GHC in this HP)" echo " * MSys2 'usr' directory, as seen in git-for-windows(tm)" echo '' echo 'Please create a subdirectory in this directory (where this script' @@ -119,26 +133,26 @@ then x86_64/ libglut32.a glut32.dll - doc/ - users_guide.ps - users_guide.pdf - html/ - winghci/ winghci.exe msys/ i386/ - usr/{bin,lib,libexec,share,ssl} + x86_64/ - usr/{bin,lib,libexec,share,ssl} + EOF exit 1 fi echo '***' -echo "*** Running hptool for $GHC_VERS" +echo "*** Running hptool" echo '***' # For Windows platforms, do not build the source tarball +echo $HPTOOL "$@" build-local build-product $HPTOOL "$@" build-local build-product + +echo '***' +echo '*** ' $(date) "HP installer tool finished" +echo '***'