From e38fb56c57772cb2586dcc0648989c208bd72cb8 Mon Sep 17 00:00:00 2001 From: randen Date: Tue, 13 Mar 2018 23:35:30 -0700 Subject: [PATCH 1/7] Fix issue #289: Add command line switches to hptool for Windows Fixes haskell-platform issue #289 by removing all positional parameters from the command line for the hptool, replacing them with all with explicit switches, and adding new command line parameters via new switches in order to specify additional inputs needed for the Windows version of hptool. Fixing #289 should make it a little easier to get the Windows HP builds to include the correct documentation and other ancillary files. Unit testing is introduced to the hptool package with this commit, which is immediately useful to the new command line functionality, but should be useful for future work as well. * hptool/hptool.cabal * To accomodate unit tests, break hptool up into a library that both the executable and the unit tests can reference. Also, add the new files introduced, and handle building the unit tests. * hptool/os-extras/win/templates/Nsisfile.nsi.mu * Update the doc short cuts which are created during installation, to track how GHC docs are currently structured. * hptool/os-extras/win/templates/index.html.mu * New. The template to use for the overall index.html file for the installed GHC docs. * hptool/src/CLArgs.hs * New. Handles the new command line argument processing. * hptool/src/Config.hs * Add to the Oracle, the new parameters that come from the command line, keeping them in a UserConfig. * hptool/src/Internal/CLArgs.hs * New. A separation of CLArgs functionality which allows the unit tests to access non-exported functions. * hptool/src/Main.hs * Replace the command line processing using the new CLArgs module, while updating the usage message, and connecting the args with the oracle. * hptool/src/OS/Win/WinNsis.hs * Rather than use a index.html file that has to be updated by hand for each release, use a template to generate one. * hptool/src/OS/Win/WinPaths.hs * Add paths for the index.html and its template. Remove the winExternalDocs path, since it is now unused. * hptool/src/OS/Win/WinRules.hs * Rather than copy a hand-crafted directory into the release, grab the appropriate pieces as specified by the user from the command line args (and pushed into the oracle), and untar those into the release instaed. * hptool/src/Package.hs * Compiler warning. * hptool/src/Types.hs * Add two types, BuildFlavor and UserConfig, for storing the user command line args. * hptool/tests/UnitTests.hs * New. The main unit tests file, which will invoke the sub-tests (so far only one: CLArgs) * hptool/tests/UnitTests/CLArgs.hs * New. Tests the new command line parsing/handling. * windows-platform.sh * Some updated paths; update the messages to match the new params; update the sanity checks; add a time stamp to start and end. --- hptool/hptool.cabal | 80 ++++++++- .../os-extras/win/templates/Nsisfile.nsi.mu | 4 +- hptool/os-extras/win/templates/index.html.mu | 56 ++++++ hptool/src/CLArgs.hs | 137 +++++++++++++++ hptool/src/Config.hs | 62 ++++++- hptool/src/Internal/CLArgs.hs | 75 ++++++++ hptool/src/Main.hs | 72 ++++---- hptool/src/OS/Win/WinNsis.hs | 8 +- hptool/src/OS/Win/WinPaths.hs | 17 +- hptool/src/OS/Win/WinRules.hs | 26 ++- hptool/src/Package.hs | 2 +- hptool/src/Types.hs | 26 ++- hptool/tests/UnitTests.hs | 16 ++ hptool/tests/UnitTests/CLArgs.hs | 160 ++++++++++++++++++ windows-platform.sh | 35 ++-- 15 files changed, 704 insertions(+), 72 deletions(-) create mode 100644 hptool/os-extras/win/templates/index.html.mu create mode 100644 hptool/src/CLArgs.hs create mode 100644 hptool/src/Internal/CLArgs.hs create mode 100644 hptool/tests/UnitTests.hs create mode 100644 hptool/tests/UnitTests/CLArgs.hs diff --git a/hptool/hptool.cabal b/hptool/hptool.cabal index fe35f76..05dfc10 100644 --- a/hptool/hptool.cabal +++ b/hptool/hptool.cabal @@ -1,4 +1,4 @@ -Name: hptool +Name: HPTool Version: 0.1 Author: Mark Lentczner Maintainer: gershomb@gmail.com @@ -10,9 +10,63 @@ 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, + base, + bytestring, + containers, + directory, + hastache >=0.6.0, + shake >= 0.14 && < 0.16, + split, + text, + transformers, + unix-compat, + filepath + hs-source-dirs: src + Executable hptool Main-is: Main.hs + hs-source-dirs: src Other-Modules: + CLArgs, + Internal.CLArgs, Config, Dirs GhcDist, @@ -45,9 +99,6 @@ Executable hptool Types, Utils, Website - - hs-source-dirs: src - Build-depends: Cabal, base, @@ -55,11 +106,30 @@ Executable hptool containers, directory, hastache >=0.6.0, + HPTool, shake >= 0.14 && < 0.16, split, text, transformers, unix-compat, filepath - ghc-options: -Wall -fwarn-tabs + + +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 diff --git a/hptool/os-extras/win/templates/Nsisfile.nsi.mu b/hptool/os-extras/win/templates/Nsisfile.nsi.mu index 82b1bd7..e789d2e 100644 --- a/hptool/os-extras/win/templates/Nsisfile.nsi.mu +++ b/hptool/os-extras/win/templates/Nsisfile.nsi.mu @@ -439,10 +439,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" \ 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..765864c 100644 --- a/hptool/src/Config.hs +++ b/hptool/src/Config.hs @@ -8,6 +8,10 @@ module Config , addConfigOracle , askCabalExe , askStackExe + , askGhcUgPDF + , askGhcUgHtml + , askGhcLibs + , askHaddockHTML ) where @@ -16,7 +20,6 @@ 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) @@ -89,8 +92,44 @@ 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) + +askGhcUgPDF :: Action FilePath +askGhcUgPDF = do + fname <- askOracle $ GhcUsersGuidePDFFileQ () + need [fname] + return fname + +newtype GhcUsersGuideHTMLTarFileQ = GhcUsersGuideHTMLTarFileQ () + deriving (Show,Typeable,Eq,Hashable,Binary,NFData) + +askGhcUgHtml :: Action FilePath +askGhcUgHtml = do + fname <- askOracle $ GhcUsersGuideHTMLTarFileQ () + need [fname] + return fname + +newtype GhcLibsHTMLTarFileQ = GhcLibsHTMLTarFileQ () + deriving (Show,Typeable,Eq,Hashable,Binary,NFData) + +askGhcLibs :: Action FilePath +askGhcLibs = do + fname <- askOracle $ GhcLibsHTMLTarFileQ () + need [fname] + return fname + +newtype HaddockHTMLTarFileQ = HaddockHTMLTarFileQ () + deriving (Show,Typeable,Eq,Hashable,Binary,NFData) + +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 _ <- addOracle $ @@ -99,10 +138,27 @@ addConfigOracle hpRel tarFile (cabalexe,stackexe) prefix includeExtra = do \(CabalExeQ _) -> return cabalexe _ <- addOracle $ \(StackExeQ _) -> return stackexe + _ <- addOracle $ + \(GhcUsersGuidePDFFileQ _) -> return ghcUgPdf + _ <- addOracle $ + \(GhcUsersGuideHTMLTarFileQ _) -> return ghcUgHtml + _ <- addOracle $ + \(GhcLibsHTMLTarFileQ _) -> return ghcLibsHtml + _ <- addOracle $ + \(HaddockHTMLTarFileQ _) -> return haddockHtml _ <- addOracle $ \(BuildConfigQ _) -> either fail (return . show) 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/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/WinNsis.hs b/hptool/src/OS/Win/WinNsis.hs index c5fcaef..96024b9 100644 --- a/hptool/src/OS/Win/WinNsis.hs +++ b/hptool/src/OS/Win/WinNsis.hs @@ -18,7 +18,7 @@ import Config import OS.Win.WinPaths import OS.Win.WinUtils import Paths ( phonyTargetDir ) -import Templates +import Templates ( copyExpandedFile, ctxAppend, platformContext ) import Types import Utils @@ -50,6 +50,12 @@ genNsisFiles = do ghcNsisFile %> expandAndCopy ghcNsiTemplate ghcProductFile msysNsisFile %> expandAndCopy msysNsiTemplate msysProductFile extralibsNsisFile %> expandAndCopy extralibsNsiTemplate extralibsProductFile + + -- Create the main doc/index.html from the template + docIndexFile %> \_ -> do + pCtx <- platformContext + copyExpandedFile pCtx docIndexTmpl docIndexFile + where makeInstDat instFilter targDir dFile = do need [phonyTargetDir] diff --git a/hptool/src/OS/Win/WinPaths.hs b/hptool/src/OS/Win/WinPaths.hs index b71442f..43bbbdb 100644 --- a/hptool/src/OS/Win/WinPaths.hs +++ b/hptool/src/OS/Win/WinPaths.hs @@ -121,6 +121,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 +146,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" @@ -241,7 +245,8 @@ winGhcTargetPackageDbDir = winTargetDir winGhcPackageDbDir winNeeds :: [FilePath] winNeeds = [ nsisFile, msysNsisFile, msysNsisInstDat, msysNsisUninstDat, - ghcNsisFile, ghcNsisInstDat, ghcNsisUninstDat + ghcNsisFile, ghcNsisInstDat, ghcNsisUninstDat, + docIndexFile ] ++ winInstExtras diff --git a/hptool/src/OS/Win/WinRules.hs b/hptool/src/OS/Win/WinRules.hs index ac1f5ce..7786726 100644 --- a/hptool/src/OS/Win/WinRules.hs +++ b/hptool/src/OS/Win/WinRules.hs @@ -65,7 +65,31 @@ copyWinTargetExtras bc = do copyFilesAction mkIconsDir winExtrasSrc winTargetDir winIconsFiles -- copy user's guide docs: ps, pdf, html, etc.... - copyDirAction winExternalDocs winDocTargetDir + 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 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/Types.hs b/hptool/src/Types.hs index d94b20c..868812a 100644 --- a/hptool/src/Types.hs +++ b/hptool/src/Types.hs @@ -12,10 +12,11 @@ module Types , BuildConfig(..) , GhcInstallAction , GhcInstall(..) + , BuildFlavor(..) + , UserConfig(..) ) where -import Control.Applicative import Data.Char (isDigit) import Data.List (intercalate) import Data.Version (Version, showVersion, parseVersion) @@ -128,3 +129,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/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..514639a 100644 --- a/windows-platform.sh +++ b/windows-platform.sh @@ -1,17 +1,16 @@ #!/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) # 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" +MSYS_BIN="/usr/bin" +HASK_BIN="/f/Program Files/Haskell/bin:/f/Program Files/Haskell Platform/8.2.2/lib/extralibs/bin" +NSIS_BIN="/f/Program Files (x86)/NSIS" GHC_BINDIST=build/ghc-bindist/local HPTOOL=hptool/dist/build/hptool/hptool.exe @@ -49,6 +48,8 @@ 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 @@ -86,10 +87,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 \ @@ -119,26 +116,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 '***' From 99b113c2b7e44c2e5b344bbd717d3ba91f18c586 Mon Sep 17 00:00:00 2001 From: randen Date: Sun, 3 Jun 2018 23:11:21 -0700 Subject: [PATCH 2/7] Fix issue #279: add MSys to user's cabal.config Resolve Windows installer should add MSYS to extra-prog-path/extra-lib-dirs/... (#279). When the installer runs, Windows elevates the process, when possible, to the role of admin. If the installer writes the cabal.config under these privileges, the cabal.config file will have the wrong permissions for the end user. So, we must separate the privilege escalation, and perform the cabal.config change as the end user. A new sub-installer (not visible to the end-user) is introduced which performs this task, and also launches the full installer, which will get (when possible) raised privileges. As before, the full installer then launches the sub-installers. Add command line switches to hptool for additional archives needed for Windows (#289) The GHC sub-installer has grown over the NSI 2GB uncompressed raw payload limit, so another split was done, breaking the GHC docs out into a separate sub-installer. As before, the sub-installers are not end-user visible (unless they looked really hard). * hptool/hptool.cabal * Add constraint to Cabal package for vers 2.2, as the cabal files generated during the build (by invocations of cabal.exe) have some changes which are not parsable with earlier versions of Cabal. * hptool/os-extras/win/templates/Bootstrapper.nsi.mu * New. 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. * hptool/os-extras/win/templates/CommonHP.nsh.mu * New. A few macros common to our (sub-)installer(s). * hptool/os-extras/win/templates/Extralibs.nsi.mu * hptool/os-extras/win/templates/GHC.nsi.mu * hptool/os-extras/win/templates/MSys.nsi.mu * Deleted. Replaced by using a common SubInstall.nsi.mu to generate the .nsi files for the sub-installers. * hptool/os-extras/win/templates/Nsisfile.nsi.mu * This is the "main" installer, which runs as an admin if possible. However, it is launched by the "Bootstrapper" installer (which continues to run as an unprivileged user). We want this main install to have its windows be on top of other windows. This installer handles all the user interaction, so if the user chooses not to have the cabal.config file updated, this installer needs to communicate back to the Bootstrapper that. So, when this main installer is successful (not cancelled by user or an error) *and* the user has chosen to update the cabal.config file, it returns to the shell a magic value 3 (rather than 0 or 1 for failure/success, respectively). * Moved some macros to CommonHP.nsh * Add some macros to do the sub-installer steps, and remove/edit the repeated steps which now use the macros * Add some "BringToFront" commands to try to make sure the installer window ends up on top of the windows stack. * Use nsExec::Exec rather than ExecWait, to get rid of the DOS window that shows up when we are running the ghc-pkg recache. * During the install, use the TEMP dir to hold the uncompressed installer payload (we already were doing this for the uninstaller). * hptool/os-extras/win/templates/SubInstall.nsi.mu * New. Templatized version of the sub-installer .nsi files (Extralibs.nsi.mu, GHC.nsi.mu, and MSys.nsi.mu, which are deleted), used to generate the .nsi for the Extralibs, GHC, Msys, and the new GHCDoc sub-installers. * hptool/src/GhcDist.hs * Pass in a param to allow the multiple untarrings of GHC to be named independently (which allows parallel untarring). * hptool/src/OS/Win.hs * Move most of the steps from osRules into genNsisFiles time, so that parallel building can be done shake. * hptool/src/OS/Win/WinNsis.hs * Use the SubInstall.nsi.mu to generate the sub-installer nsi files, rather than using separate files for each. * In adding the sub-installer, we added a couple more template variables which need expanding, and this requires a bit more info to be threaded through. * Add a new sub-installer, GHCDoc, needed since the main GHC sub-installer has again went over the NSI limit of 2GB (uncompressed, raw payload). * Re-order some steps, taking some from the function osRules in Win.hs, to reflect better dependencies and thus allow more parallelism in the shake build. * The function copyWinTargetExtras is moved from WinRules to this module. * hptool/src/OS/Win/WinPaths.hs * Filename re-working due to the new sub-installer template, CommonHP.nsh, plus adding the new GHCDoc sub-installer and the "Bootstrapper.nsi". * hptool/src/OS/Win/WinRules.hs * Add the FilePath for the top-level output (the "main" installer) to the winRules, so this can be passed to genNsisFiles. * Change the command which takes the untarred ghc directory and allows it to moved to a specified location, which is part of the change to allow the installer build to do the two ghc untars in parallel. * Move copyWinTargetExtras from here to WinNsis.hs * copyFileAction, copyFilesAction, copyDirAction moved to WinUtils in order to to move the body of copyWinTargetExtras into WinNsis. Note that WinRules imports WinNsis, so these common functions needed to be in a module separate from either. * HPTOOL/src/OS/Win/WinUtils.hs * copyFileAction, copyFilesAction, copyDirAction moved here from WinRules, which imports/exports fixed up accordingly. * hptool/src/Paths.hs * Add an extra parameter for ghcBinDistDir in order to name the ghc bin dist directory differently for the two times we have to untar the ghc tar file, which allows those two un-tars to be done potentially in parallel. * hptool/src/Target.hs * Separated two targets, "ghcVirtualTarget" and "haddockDocDir" so they won't be done in parallel (we really need to go through the dependencies of this entire project, as there have been a few occasional things, e.g., sometimes timing-dependent behavior of dependencies not being available when needed, etc.) * Added missing newline at end-of-file. * hptool/src/Utils.hs * Added a log message during makeDirectory. * windows-platform.sh --- hptool/hptool.cabal | 7 +- .../win/templates/Bootstrapper.nsi.mu | 192 +++++++++++++++ .../os-extras/win/templates/CommonHP.nsh.mu | 122 ++++++++++ .../os-extras/win/templates/Extralibs.nsi.mu | 192 --------------- hptool/os-extras/win/templates/MSys.nsi.mu | 192 --------------- .../os-extras/win/templates/Nsisfile.nsi.mu | 225 ++++++++---------- .../{GHC.nsi.mu => SubInstall.nsi.mu} | 72 +----- hptool/src/GhcDist.hs | 10 +- hptool/src/OS/Win.hs | 32 +-- hptool/src/OS/Win/WinNsis.hs | 204 +++++++++++++--- hptool/src/OS/Win/WinPaths.hs | 88 +++++-- hptool/src/OS/Win/WinRules.hs | 82 +------ hptool/src/OS/Win/WinUtils.hs | 28 ++- hptool/src/Paths.hs | 9 +- hptool/src/Target.hs | 6 +- hptool/src/Utils.hs | 4 +- windows-platform.sh | 26 +- 17 files changed, 722 insertions(+), 769 deletions(-) create mode 100644 hptool/os-extras/win/templates/Bootstrapper.nsi.mu create mode 100644 hptool/os-extras/win/templates/CommonHP.nsh.mu delete mode 100644 hptool/os-extras/win/templates/Extralibs.nsi.mu delete mode 100644 hptool/os-extras/win/templates/MSys.nsi.mu rename hptool/os-extras/win/templates/{GHC.nsi.mu => SubInstall.nsi.mu} (51%) diff --git a/hptool/hptool.cabal b/hptool/hptool.cabal index 05dfc10..1d326a3 100644 --- a/hptool/hptool.cabal +++ b/hptool/hptool.cabal @@ -1,10 +1,10 @@ +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: @@ -47,7 +47,7 @@ Library Utils, Website Build-depends: - Cabal, + Cabal >=2.2.0, base, bytestring, containers, @@ -60,6 +60,7 @@ Library unix-compat, filepath hs-source-dirs: src + Default-Language: Haskell2010 Executable hptool Main-is: Main.hs @@ -114,6 +115,7 @@ Executable hptool unix-compat, filepath ghc-options: -Wall -fwarn-tabs + Default-Language: Haskell2010 test-suite unit-tests @@ -133,3 +135,4 @@ test-suite unit-tests 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..f461bf5 --- /dev/null +++ b/hptool/os-extras/win/templates/Bootstrapper.nsi.mu @@ -0,0 +1,192 @@ +;; 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: do not use $INSTDIR here, as it will not be correct if the user +; selects a non-default install directory in the launched sub-installer. + + +;-------------------------------- +;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 ACTUAL_INSTDIR ; only valid after the enclosed installed has finished + Var tempDir + +;-------------------------------- +;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 + ${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' "" 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 e789d2e..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 @@ -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/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/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 96024b9..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,47 +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 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] @@ -66,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 @@ -86,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 = @@ -122,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 "" @@ -166,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 43bbbdb..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" @@ -243,15 +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, - docIndexFile +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 7786726..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,51 +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.... - 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 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 @@ -132,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/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..b325e32 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 @@ -181,4 +181,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/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/windows-platform.sh b/windows-platform.sh index 514639a..11ee3ea 100644 --- a/windows-platform.sh +++ b/windows-platform.sh @@ -6,10 +6,17 @@ 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="/usr/bin" -HASK_BIN="/f/Program Files/Haskell/bin:/f/Program Files/Haskell Platform/8.2.2/lib/extralibs/bin" +# 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.2/i386/cabal-install-2.2.0.0-i386-unknown-mingw32" +# 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 @@ -42,7 +49,9 @@ 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 +echo "> echo \$PATH" +echo $PATH which cabal || { echo "Could not find cabal.exe on PATH!"; echo "PATH=$PATH"; exit 1; } @@ -53,10 +62,11 @@ which tar || 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 # Make sure makensisw.exe is compiled with support for large strings # makensisw="/c/Program\ Files\ \(x86\)/NSIS/Orig/makensis //HDRINFO" From 3294fbb3ea0c8ad127578dcb3cb0108585d07b1d Mon Sep 17 00:00:00 2001 From: randen Date: Fri, 15 Jun 2018 10:41:40 -0700 Subject: [PATCH 3/7] Windows script need to find hscolour Shuffling the path components left hscolour out, which is needed for building the source documentation. (Remember, the specific paths here would needed to be changed for who ever is running them.) --- windows-platform.sh | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/windows-platform.sh b/windows-platform.sh index 11ee3ea..3844768 100644 --- a/windows-platform.sh +++ b/windows-platform.sh @@ -12,9 +12,12 @@ echo '***' # 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" +# 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.2/i386/cabal-install-2.2.0.0-i386-unknown-mingw32" +# 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" @@ -22,20 +25,20 @@ 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 @@ -43,13 +46,13 @@ 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:$CABAL_BIN +export PATH=$CWD/$GHC_BINDIST/bin:$CWD/$MINGW/bin:$MSYS_BIN:$NSIS_BIN:$CABAL_BIN:$HSCOLOUR_BIN echo "> echo \$PATH" echo $PATH @@ -68,6 +71,11 @@ cabal --version # 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" nsis_max_strlen=`makensis //HDRINFO | grep 'NSIS_MAX_STRLEN' | awk '{ match($0, /NSIS_MAX_STRLEN=([0-9]+)/, x); if(x[1] != "") print x[1] }'` @@ -108,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' From 285aa01bce5f5273daa2608c920d4eb44cba9bd7 Mon Sep 17 00:00:00 2001 From: randen Date: Sun, 24 Jun 2018 11:19:51 -0700 Subject: [PATCH 4/7] Fix issue #311: Install directory option ignored on Windows The changes for #279 (Windows installer should add MSYS to extra-prog-path/extra-lib-dirs/...) broke silent installs. * hptool/os-extras/win/templates/Bootstrapper.nsi.mu * Force /D= to the launched sub-installer to fix #311 * Add many comments about the weirdness of handling $INSTDIR --- .../win/templates/Bootstrapper.nsi.mu | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/hptool/os-extras/win/templates/Bootstrapper.nsi.mu b/hptool/os-extras/win/templates/Bootstrapper.nsi.mu index f461bf5..c26110b 100644 --- a/hptool/os-extras/win/templates/Bootstrapper.nsi.mu +++ b/hptool/os-extras/win/templates/Bootstrapper.nsi.mu @@ -14,8 +14,34 @@ ; 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: do not use $INSTDIR here, as it will not be correct if the user -; selects a non-default install directory in the launched sub-installer. +;;;;;;;;; +; 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. ;-------------------------------- @@ -49,9 +75,12 @@ Var PROGRAM_FILES Var INSTALLER_PARAMS - Var ACTUAL_INSTDIR ; only valid after the enclosed installed has finished Var tempDir + ; ACTUAL_INSTDIR: set from registry, and only valid after the enclosed + ; installed has finished + Var ACTUAL_INSTDIR + ;-------------------------------- ;General settings @@ -94,6 +123,9 @@ 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, @@ -162,7 +194,7 @@ Section "Base components" SecMain ; Can bring down the banner now Banner::destroy BringToFront - !insertmacro ShellExecWait "" '"$tempDir\{{osProductFileName}}"' '$INSTALLER_PARAMS' "" SW_SHOWNORMAL $0 + !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 From e47c87d24b2fe4d81fbd1d88adeed6ffb1c58f17 Mon Sep 17 00:00:00 2001 From: randen Date: Fri, 6 Jul 2018 15:27:18 -0700 Subject: [PATCH 5/7] Fix issue #288: Upgrade hptool for shake version 0.16 Most of the changes were to derive some instances that allows us to place nicely with shake. The 0.16-required changes were to define some type instances in our "oracle". * hptool/hptool.cabal * need shake >=0.16 now * hptool/src/Config.hs * Previously, all of the oracle data types were smashed into strings (if they were not already), but shake allows them to be any type, so by deriving some instances in Types.hs for the non-string data items which are in the oracle, we can simplify some of this module. * For each type of item stored, we did need to add a type instance of RuleResult (part of the changes needed for shake 0.16). * Provide an Eq instance for the Release structure, to account for the lists it contains. * Some lines were shuffled to restore the grouping of newtype's with the function that uses each. * hptool/src/Types.hs * Derive instances of Eq, Generic, Hashable, Binary, NFData for the data structures (and any nested structures) which we store in the oracle mechanism. --- hptool/hptool.cabal | 4 ++-- hptool/src/Config.hs | 49 ++++++++++++++++++++++---------------------- hptool/src/Types.hs | 22 +++++++++++++++----- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/hptool/hptool.cabal b/hptool/hptool.cabal index 1d326a3..ed8fe33 100644 --- a/hptool/hptool.cabal +++ b/hptool/hptool.cabal @@ -53,7 +53,7 @@ Library containers, directory, hastache >=0.6.0, - shake >= 0.14 && < 0.16, + shake >= 0.16, split, text, transformers, @@ -108,7 +108,7 @@ Executable hptool directory, hastache >=0.6.0, HPTool, - shake >= 0.14 && < 0.16, + shake >= 0.16, split, text, transformers, diff --git a/hptool/src/Config.hs b/hptool/src/Config.hs index 765864c..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 @@ -22,35 +22,22 @@ import Development.Shake.Classes import Development.Shake.FilePath 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. @@ -63,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 @@ -84,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 @@ -94,6 +85,7 @@ askCabalExe = do newtype GhcUsersGuidePDFFileQ = GhcUsersGuidePDFFileQ () deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult GhcUsersGuidePDFFileQ = FilePath askGhcUgPDF :: Action FilePath askGhcUgPDF = do @@ -101,8 +93,10 @@ askGhcUgPDF = do need [fname] return fname + newtype GhcUsersGuideHTMLTarFileQ = GhcUsersGuideHTMLTarFileQ () deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult GhcUsersGuideHTMLTarFileQ = FilePath askGhcUgHtml :: Action FilePath askGhcUgHtml = do @@ -110,8 +104,10 @@ askGhcUgHtml = do need [fname] return fname + newtype GhcLibsHTMLTarFileQ = GhcLibsHTMLTarFileQ () deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult GhcLibsHTMLTarFileQ = FilePath askGhcLibs :: Action FilePath askGhcLibs = do @@ -119,8 +115,10 @@ askGhcLibs = do need [fname] return fname + newtype HaddockHTMLTarFileQ = HaddockHTMLTarFileQ () deriving (Show,Typeable,Eq,Hashable,Binary,NFData) +type instance RuleResult HaddockHTMLTarFileQ = FilePath askHaddockHTML :: Action FilePath askHaddockHTML = do @@ -128,10 +126,11 @@ askHaddockHTML = do 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 $ @@ -147,7 +146,7 @@ addConfigOracle hpRel userConfig = do _ <- addOracle $ \(HaddockHTMLTarFileQ _) -> return haddockHtml _ <- addOracle $ - \(BuildConfigQ _) -> either fail (return . show) buildConfig + \(BuildConfigQ _) -> either fail return buildConfig either fail return buildConfig where tarFile = ucGHCBinDist userConfig diff --git a/hptool/src/Types.hs b/hptool/src/Types.hs index 868812a..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 @@ -18,9 +18,11 @@ module Types where 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) @@ -33,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 @@ -59,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 @@ -73,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 @@ -81,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 @@ -95,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 @@ -112,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 From a110d30e0b1a7fae1d16541e9af252d699330f79 Mon Sep 17 00:00:00 2001 From: randen Date: Fri, 6 Jul 2018 15:58:36 -0700 Subject: [PATCH 6/7] Fix issue #312: 8.4.3 full addLibrarySearchPath error on Windows 10 When cabal is invoked during an HP build, we will set and use a default cabal config file. * hptool/src/Target.hs * Entries from the build-machine-user's cabal config file are copied into the .conf files. We need to insulate against this inadvertent pollution of the built packages. So, with each cabal invocation, specify a path to a cabal config file to use. The first time cabal runs, it will create this file with all defaults, and that file will be used for all the other uses of cabal during the HP build. --- hptool/src/Target.hs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hptool/src/Target.hs b/hptool/src/Target.hs index b325e32..943cfec 100644 --- a/hptool/src/Target.hs +++ b/hptool/src/Target.hs @@ -85,8 +85,15 @@ 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 + 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) $ cabal "clean" [] -- This is a hack to handle when packages, other -- than alex or happy themselves, have outdated From 1b929167a6073acc790baf55b8c7d524fb470551 Mon Sep 17 00:00:00 2001 From: randen Date: Fri, 6 Jul 2018 16:43:06 -0700 Subject: [PATCH 7/7] Workaround cabal #5362: "cabal clean" behavior 2.2 vs 2.0 Using cabal-install 2.0, if a "cabal clean" is done on a non-existent directory, it will successfully complete. In cabal-install 2.2, "cabal clean" on a non-existent directory will fail (on Windows, at least) with "dist\build: getDirectoryContents:findFirstFile: does not exist (The system cannot find the path specified.)" So, we will temporarily work around this by creating the directory if it doesn't already exist, before we invoke "cabal clean". * hptool/src/Target.hs * use createDirectoryIfMissing (via Util.makeDirectory) to create the directory about to be "cleaned" if not already there, to work-around the cabal issue. --- hptool/src/Target.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hptool/src/Target.hs b/hptool/src/Target.hs index 943cfec..bf3d0b7 100644 --- a/hptool/src/Target.hs +++ b/hptool/src/Target.hs @@ -94,7 +94,9 @@ buildAction buildDir hpRel bc = do cabalGlobalOpts = [ "--config-file=" ++ (buildRoot "cabal.conf") `relativeToDir` buildDir ] - when (not isAlexOrHappy) $ + 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.