cabal-macosx 0.1.2.2 → 0.2.4.2
raw patch · 11 files changed
Files
- Distribution/MacOSX.hs +143/−102
- Distribution/MacOSX/AppBuildInfo.hs +35/−0
- Distribution/MacOSX/Common.hs +1/−0
- Distribution/MacOSX/DG.hs +0/−0
- Distribution/MacOSX/Dependencies.hs +25/−5
- Distribution/MacOSX/Internal.hs +74/−0
- Distribution/MacOSX/Templates.hs +46/−0
- cabal-macosx.cabal +53/−17
- macosx-app.hs +3/−3
- tests/Distribution/MacOSX/Internal/Tests.hs +88/−0
- tests/Main.hs +9/−0
Distribution/MacOSX.hs view
@@ -1,21 +1,25 @@-{- | Cabal support for creating Mac OSX application bundles.+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+ {- | Cabal support for creating Mac OSX application bundles. -GUI applications on Mac OSX should be run as application /bundles/;-these wrap an executable in a particular directory structure which can-also carry resources such as icons, program metadata, images, other-binaries, and copies of shared libraries.+ GUI applications on Mac OSX should be run as application /bundles/;+ these wrap an executable in a particular directory structure which can+ also carry resources such as icons, program metadata, images, other+ binaries, and copies of shared libraries. -This module provides a Cabal post-build hook for creating such-application bundles, and controlling their contents.+ This module provides a Cabal post-build hook for creating such+ application bundles, and controlling their contents. -For more information about OSX application bundles, look for the-/Bundle Programming Guide/ on the /Apple Developer Connection/-website, <http://developer.apple.com/>.+ For more information about OSX application bundles, look for the+ /Bundle Programming Guide/ on the /Apple Developer Connection/+ website, <http://developer.apple.com/>. --}+ -} module Distribution.MacOSX (- appBundleBuildHook, appBundleInstallHook,+ appBundleBuildHook,+ appBundleInstallHook,+ appBundleCopyHook, makeAppBundle, MacApp(..), ChaseDeps(..),@@ -23,27 +27,34 @@ defaultExclusions ) where +import Control.Exception+import Prelude hiding ( catch ) import Control.Monad (forM_, when)-import Data.String.Utils (replace)-import Distribution.PackageDescription (PackageDescription(..),- Executable(..))+import Data.List ( isPrefixOf )+import System.Cmd (system)+import System.FilePath+import System.Directory (copyFile, createDirectoryIfMissing, getHomeDirectory)+import qualified Data.Text as T+import qualified Data.Text.IO as T++import Distribution.PackageDescription (PackageDescription(..)) import Distribution.Simple import Distribution.Simple.InstallDirs (bindir, prefix, CopyDest(NoCopyDest)) import Distribution.Simple.LocalBuildInfo (absoluteInstallDirs, LocalBuildInfo(..))-import Distribution.Simple.Setup (BuildFlags, InstallFlags,- fromFlagOrDefault, installVerbosity- )+import Distribution.Simple.Setup (BuildFlags, InstallFlags, CopyFlags, fromFlagOrDefault, installVerbosity, copyVerbosity) import Distribution.Simple.Utils (installDirectoryContents, installExecutableFile)-import Distribution.Verbosity (normal)-import System.Cmd (system)-import System.FilePath+#if MIN_VERSION_Cabal(1,18,0)+import Distribution.System (Platform (..), OS (OSX))+#else import System.Info (os)-import System.Directory (copyFile, createDirectoryIfMissing)-import System.Exit+#endif+import Distribution.Verbosity (normal, Verbosity) +import Distribution.MacOSX.Internal import Distribution.MacOSX.AppBuildInfo import Distribution.MacOSX.Common import Distribution.MacOSX.Dependencies+import Distribution.MacOSX.Templates -- | Post-build hook for OS X application bundles. Does nothing if -- called on another O/S.@@ -55,13 +66,15 @@ -- 'Distribution.Simple.postBuild'. -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO () appBundleBuildHook apps _ _ pkg localb =+#if MIN_VERSION_Cabal(1,18,0)+ if isMacOS localb+#else if isMacOS- then forM_ apps' $ makeAppBundle . toAppBuildInfo localb+#endif+ then do let buildDirLbi = buildDir localb+ let macApps = getMacAppsForBuildableExecutors apps (executables pkg)+ forM_ macApps (makeAppBundle . createAppBuildInfo buildDirLbi) else putStrLn "Not OS X, so not building an application bundle."- where apps' = case apps of- [] -> map mkDefault $ executables pkg- xs -> xs- mkDefault x = MacApp (exeName x) Nothing Nothing [] [] DoNotChase -- | Post-install hook for OS X application bundles. Copies the -- application bundle (assuming you are also using the appBundleBuildHook)@@ -74,42 +87,129 @@ -> Args -- ^ All other parameters as per -- 'Distribution.Simple.postInstall'. -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO ()-appBundleInstallHook apps _ iflags pkg localb = when isMacOS $ do- let verbosity = fromFlagOrDefault normal (installVerbosity iflags)+appBundleInstallHook apps _ iflags =+ appBundleInstallOrCopyHook apps+ (fromFlagOrDefault normal (installVerbosity iflags))+{-# DEPRECATED appBundleInstallHook "Use appBundleCopyHook instead" #-}++-- | Post-copy hook for OS X application bundles. Copies the+-- application bundle (assuming you are also using the appBundleBuildHook)+-- to @$prefix/Applications@+-- Does nothing if called on another O/S.+-- Use this instead of appBundleInstallHook (do not hook+-- both postInst and postCopy).+appBundleCopyHook ::+ [MacApp] -- ^ List of applications to build; if empty, an+ -- application is built for each executable in the package,+ -- with no icon or plist, and no dependency-chasing.+ -> Args -- ^ All other parameters as per+ -- 'Distribution.Simple.postCopy'.+ -> CopyFlags -> PackageDescription -> LocalBuildInfo -> IO ()+appBundleCopyHook apps _ cflags =+ appBundleInstallOrCopyHook apps+ (fromFlagOrDefault normal (copyVerbosity cflags))++appBundleInstallOrCopyHook ::+ [MacApp] -- ^ List of applications to build; if empty, an+ -- application is built for each executable in the package,+ -- with no icon or plist, and no dependency-chasing.+ -> Verbosity+ -> PackageDescription -> LocalBuildInfo -> IO ()+#if MIN_VERSION_Cabal(1,18,0)+appBundleInstallOrCopyHook apps verbosity pkg localb = when (isMacOS localb) $ do+#else+appBundleInstallOrCopyHook apps verbosity pkg localb = when isMacOS $ do+#endif+ libraryHaskell <- flip fmap getHomeDirectory $ (</> "Library/Haskell")+ let standardPrefix = (libraryHaskell ++ "/") `isPrefixOf` prefix installDir+ let applicationsDir = if standardPrefix+ then libraryHaskell </> "Applications"+ else prefix installDir </> "Applications" createDirectoryIfMissing False applicationsDir forM_ apps $ \app -> do let appInfo = toAppBuildInfo localb app- appPathSrc = appPath appInfo+ appPathSrc = abAppPath appInfo appPathTgt = applicationsDir </> takeFileName appPathSrc exe ap = ap </> pathInApp app (appName app) installDirectoryContents verbosity appPathSrc appPathTgt installExecutableFile verbosity (exe appPathSrc) (exe appPathTgt) -- generate a tiny shell script for users who expect to run their -- applications from the command line with flags and all- let script = "`dirname $0`" </> "../Applications"- </> takeFileName appPathSrc- </> "Contents/MacOS" </> appName app- ++ " \"$@\""+ let script = if standardPrefix+ then bundleScriptLibraryHaskell localb app+ else bundleScriptElsewhere localb app scriptFileSrc = buildDir localb </> "_" ++ appName app <.> "sh" scriptFileTgt = bindir installDir </> appName app writeFile scriptFileSrc script installExecutableFile verbosity scriptFileSrc scriptFileTgt where installDir = absoluteInstallDirs pkg localb NoCopyDest- applicationsDir = prefix installDir </> "Applications" +bundleScriptLibraryHaskell :: LocalBuildInfo -> MacApp -> String+bundleScriptLibraryHaskell localb app = unlines+ [ "#!/bin/bash"+ , "$HOME/Library/Haskell/Applications"+ </> takeFileName appPathSrc+ </> "Contents/MacOS" </> appName app ++ " \"$@\""+ ]+ where+ appInfo = toAppBuildInfo localb app+ appPathSrc = abAppPath appInfo+ +bundleScriptElsewhere :: LocalBuildInfo -> MacApp -> String+bundleScriptElsewhere localb app = unlines+ [ "#!/bin/bash"+ , "MAX_DEPTH=256"+ , "COUNTER=0"+ , "ZERO=$0"+ , "STATUS=0"+ , ""+ , "# The counter is just a safeguard in case I'd done something silly"+ , "while [ $STATUS -eq 0 -a $COUNTER -lt $MAX_DEPTH ]; do"+ , " COUNTER=$(($COUNTER+1))"+ , " NZERO=`readlink $ZERO`; STATUS=$?"+ , " if [ $STATUS -eq 0 ]; then"+ , " # go to my parent dir"+ , " pushd $(dirname $ZERO) > /dev/null"+ , " # now follow the symlink if at all"+ , " pushd $(dirname $NZERO) > /dev/null"+ , " ZERO=$PWD/$(basename $NZERO)"+ , " popd > /dev/null"+ , " popd > /dev/null"+ , " fi"+ , "done"+ , "if [ $COUNTER -ge $MAX_DEPTH ]; then"+ , " echo >&2 Urk! exceeded symlink depth of $MAX_DEPTH trying to dereference $0"+ , " exit 1"+ , "fi"+ , "`dirname $ZERO`" </> "../Applications"+ </> takeFileName appPathSrc+ </> "Contents/MacOS" </> appName app ++ " \"$@\""+ ]+ where+ appInfo = toAppBuildInfo localb app+ appPathSrc = abAppPath appInfo++#if MIN_VERSION_Cabal(1,18,0)+isMacOS :: LocalBuildInfo -> Bool+isMacOS localb = case hostPlatform localb of+ Platform _ OSX -> True+ _ -> False+#else isMacOS :: Bool isMacOS = os == "darwin"+#endif + -- | Given a 'MacApp' in context, make an application bundle in the -- build area. (for internal use only) makeAppBundle :: AppBuildInfo -> IO () makeAppBundle appInfo@(AppBuildInfo appPath _ app) =- do createAppDir appInfo+ do _ <- createAppDir appInfo maybeCopyPlist appPath app maybeCopyIcon appPath app- `catch` \err -> putStrLn ("Warning: could not set up icon for " ++- appName app ++ ": " ++ show err)+ `catch` \(SomeException err) ->+ putStrLn $ "Warning: could not set up icon for " ++ appName app ++ ": " ++ show err includeResources appPath app includeDependencies appPath app osxIncantations appPath app@@ -123,7 +223,7 @@ createDirectoryIfMissing False appPath createDirectoryIfMissing True $ takeDirectory exeDest createDirectoryIfMissing True $ appPath </> "Contents/Resources"- putStrLn $ "Copying executable " ++ appName app ++ " into place"+ putStrLn $ "Copying executable " ++ appName app ++ " into place from " ++ exeSrc ++ " to " ++ exeDest copyFile exeSrc exeDest return appPath where exeDest = appPath </> pathInApp app (appName app)@@ -155,9 +255,9 @@ Nothing -> case appIcon app of Just icPath -> do -- Need a plist to support icon; use default.- let pl = replace "$program" (appName app) plistTemplate- pl' = replace "$iconPath" (takeFileName icPath) pl- writeFile plDest pl'+ let pl = T.replace "$program" (T.pack (appName app)) plistTemplate+ pl' = T.replace "$iconPath" (T.pack (takeFileName icPath)) pl+ T.writeFile plDest pl' return () Nothing -> return () -- No icon, no plist, nothing to do. where plDest = appPath </> "Contents/Info.plist"@@ -173,62 +273,3 @@ copyFile icPath $ appPath </> "Contents/Resources" </> takeFileName icPath Nothing -> return ()---- | Perform various magical OS X incantations for turning the app--- directory into a bundle proper.-osxIncantations ::- FilePath -- ^ Path to application bundle root.- -> MacApp -> IO ()-osxIncantations appPath app =- do putStrLn "Running Rez, etc."- ExitSuccess <- system $ rez ++ " Carbon.r -o " ++- appPath </> pathInApp app (appName app)- writeFile (appPath </> "PkgInfo") "APPL????"- -- Tell Finder about the icon.- ExitSuccess <- system $ setFile ++ " -a C " ++ appPath </> "Contents"- return ()---- | Path to @Rez@ tool.-rez :: FilePath-rez = "/Developer/Tools/Rez"---- | Path to @SetFile@ tool.-setFile :: FilePath-setFile = "/Developer/Tools/SetFile"---- | Default plist template, based on that in macosx-app from wx (but--- with version stuff removed).-plistTemplate :: String-plistTemplate = "\- \<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\- \<!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">\n\- \<plist version=\"0.9\">\n\- \<dict>\n\- \<key>CFBundleInfoDictionaryVersion</key>\n\- \<string>6.0</string>\n\- \<key>CFBundleIdentifier</key>\n\- \<string>org.haskell.$program</string>\n\- \<key>CFBundleDevelopmentRegion</key>\n\- \<string>English</string>\n\- \<key>CFBundleExecutable</key>\n\- \<string>$program</string>\n\- \<key>CFBundleIconFile</key>\n\- \<string>$iconPath</string>\n\- \<key>CFBundleName</key>\n\- \<string>$program</string>\n\- \<key>CFBundlePackageType</key>\n\- \<string>APPL</string>\n\- \<key>CFBundleSignature</key>\n\- \<string>????</string>\n\- \<key>CFBundleVersion</key>\n\- \<string>1.0</string>\n\- \<key>CFBundleShortVersionString</key>\n\- \<string>1.0</string>\n\- \<key>CFBundleGetInfoString</key>\n\- \<string>$program, bundled by cabal-macosx</string>\n\- \<key>LSRequiresCarbon</key>\n\- \<true/>\n\- \<key>CSResourcesFileMapped</key>\n\- \<true/>\n\- \</dict>\n\- \</plist>"
+ Distribution/MacOSX/AppBuildInfo.hs view
@@ -0,0 +1,35 @@+-- | Information used to help create an application bundle+module Distribution.MacOSX.AppBuildInfo where++import Distribution.Simple.LocalBuildInfo (LocalBuildInfo(..))+import System.FilePath++import Distribution.MacOSX.Common++-- | Information needed to build a bundle+--+-- This exists to make it possible to have a standalone+-- macosx-app executable without it necessarily having to+-- know a lot of Cabal internals+data AppBuildInfo = AppBuildInfo+ { -- | Location of the application bundle being built+ abAppPath :: FilePath+ -- | Location of the original executable that was built+ , abAppOrigExe :: FilePath+ -- |+ , abApp :: MacApp+ }++-- | @toAppBuildInfo l m@ returns information for an application bundle+-- within the @l@ build directory+toAppBuildInfo :: LocalBuildInfo -> MacApp -> AppBuildInfo+toAppBuildInfo localb app = createAppBuildInfo (buildDir localb) app++-- | @createAppBuildInfo d m@ returns information for an application bundle+-- within the @d@ build directory from LocalBuildInfo+createAppBuildInfo :: FilePath -> MacApp -> AppBuildInfo+createAppBuildInfo buildDirLocalBuildInfo app = AppBuildInfo+ { abAppPath = buildDirLocalBuildInfo </> appName app <.> "app"+ , abAppOrigExe = buildDirLocalBuildInfo </> appName app </> appName app+ , abApp = app+ }
Distribution/MacOSX/Common.hs view
@@ -1,3 +1,4 @@+-- | Utility functions module Distribution.MacOSX.Common where import Data.List
Distribution/MacOSX/DG.hs view
Distribution/MacOSX/Dependencies.hs view
@@ -142,7 +142,9 @@ -> Exclusions -- ^ List of exclusions for dependency chasing. -> IO FDeps getFDeps appPath app path exclusions =- do contents <- readProcess oTool ["-L", absPath] ""+ do putStrLn $ "path: " ++ path+ contents <- readProcess oTool ["-L", absPath] ""+ putStrLn $ "contents: " ++ contents case parse parseFileDeps "" contents of Left err -> error $ show err Right fDeps -> return $ exclude exclusions fDeps@@ -152,6 +154,7 @@ parseFileDeps :: Parser FDeps parseFileDeps = do f <- manyTill (noneOf ":") (char ':') _ <- char '\n'+ deps <- parseDepOrName `sepEndBy` char '\n' eof return $ FDeps f $ filter (f /=) $ catMaybes deps@@ -159,12 +162,22 @@ parseDepOrName = do c <- oneOf "\t/" case c of '\t' -> -- A dependency.- do dep <- parseDep- return $ Just dep+ do dep <- parseDepOrIgnoreAt+ return $ dep '/' -> -- Same filename, alternative arch do _ <- manyTill (noneOf ":") (char ':') return Nothing _ -> error "Can't happen"+ parseDepOrIgnoreAt :: Parser (Maybe FilePath)+ parseDepOrIgnoreAt = do c <- lookAhead (oneOf "/@")+ case c of+ '/' -> -- A dependency.+ do dep <- parseDep+ return $ Just $ dep+ '@' -> -- ignore entries that start with @+ do _ <- manyTill (noneOf ")") (char ')')+ return Nothing+ _ -> error "Can't happen" parseDep :: Parser FilePath parseDep = do dep <- manyTill (noneOf " ") (char ' ') _ <- char '('@@ -213,10 +226,17 @@ updateDependency appPath app src tgt = do putStrLn $ "Updating " ++ newLib ++ "'s dependency on " ++ tgt ++ " to " ++ tgt'+ -- Ensure we have write permissions while editing the library. Notably,+ -- Homebrew removes write permissions from installed files.+ perm <- getPermissions newLib+ setPermissions newLib perm { writable = True } let cmd = iTool ++ " -change " ++ show tgt ++ " " ++ show tgt' ++ " " ++ show newLib- --putStrLn cmd- ExitSuccess <- system cmd+ exitCode <- system cmd+ setPermissions newLib perm+ when (exitCode /= ExitSuccess) $+ error $ "Failed to update library dependencies on " ++ show newLib +++ " with command: " ++ cmd return () where tgt' = "@executable_path/../Frameworks/" </> makeRelative "/" tgt newLib = appPath </> pathInApp app src
+ Distribution/MacOSX/Internal.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{- | Cabal support for creating Mac OSX application bundles.++GUI applications on Mac OSX should be run as application /bundles/;+these wrap an executable in a particular directory structure which can+also carry resources such as icons, program metadata, images, other+binaries, and copies of shared libraries.++This module provides internals to a Cabal post-build hook for creating such+application bundles, and controlling their contents.++For more information about OSX application bundles, look for the+/Bundle Programming Guide/ on the /Apple Developer Connection/+website, <http://developer.apple.com/>.++-}++module Distribution.MacOSX.Internal (+ getMacAppsForBuildableExecutors,+ osxIncantations+) where++#if MIN_VERSION_Cabal(2,0,0)+import Data.String (fromString)+import Distribution.Text (display)+import Distribution.Types.UnqualComponentName (unUnqualComponentName)+#endif+import Prelude hiding ( catch )+import System.Cmd ( system )+import System.Exit+import System.FilePath+import Control.Monad (filterM)+import System.Directory (doesDirectoryExist)++import Distribution.PackageDescription (BuildInfo(..), Executable(..))+import Distribution.MacOSX.Common++-- | Filter or create new 'MacApp's that are associated by name to buildable 'Executable's.+getMacAppsForBuildableExecutors ::+ [MacApp] -- ^ List of 'MacApp's to filter if any.+ -> [Executable] -- ^ List of 'Executable's from .cabal.+ -> [MacApp] -- ^ Returned list of 'MacApp's that are associated by name to buildable 'Executable's.+getMacAppsForBuildableExecutors macApps executables =+ case macApps of+ [] -> map mkDefault buildables+ xs -> filter buildableApp xs+ where -- Make a default MacApp in absence of explicit from Setup.hs+#if MIN_VERSION_Cabal(2,0,0)+ mkDefault x = MacApp (unUnqualComponentName $ exeName x) Nothing Nothing [] [] DoNotChase+#else+ mkDefault x = MacApp (exeName x) Nothing Nothing [] [] DoNotChase+#endif++ -- Check if a MacApp is in that list of buildable executables.+ buildableApp :: MacApp -> Bool+#if MIN_VERSION_Cabal(2,0,0)+ buildableApp app = any (\e -> exeName e == fromString (appName app)) buildables+#else+ buildableApp app = any (\e -> exeName e == appName app) buildables+#endif++ -- List of buildable executables from .cabal file.+ buildables :: [Executable]+ buildables = filter (buildable . buildInfo) executables++-- | Perform various magical OS X incantations for turning the app+-- directory into a bundle proper.+osxIncantations ::+ FilePath -- ^ Path to application bundle root.+ -> MacApp -> IO ()+osxIncantations appPath app =+ do writeFile (appPath </> "PkgInfo") "APPL????"+ return ()
+ Distribution/MacOSX/Templates.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Templates for the bundle.++module Distribution.MacOSX.Templates (+ plistTemplate+) where++import Data.Text ( Text )++-- | Default plist template, based on that in macosx-app from wx (but+-- with version stuff removed).+plistTemplate :: Text+plistTemplate = "\+ \<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\+ \<!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">\n\+ \<plist version=\"0.9\">\n\+ \<dict>\n\+ \<key>CFBundleInfoDictionaryVersion</key>\n\+ \<string>6.0</string>\n\+ \<key>CFBundleIdentifier</key>\n\+ \<string>org.haskell.$program</string>\n\+ \<key>CFBundleDevelopmentRegion</key>\n\+ \<string>English</string>\n\+ \<key>CFBundleExecutable</key>\n\+ \<string>$program</string>\n\+ \<key>CFBundleIconFile</key>\n\+ \<string>$iconPath</string>\n\+ \<key>CFBundleName</key>\n\+ \<string>$program</string>\n\+ \<key>CFBundlePackageType</key>\n\+ \<string>APPL</string>\n\+ \<key>CFBundleSignature</key>\n\+ \<string>????</string>\n\+ \<key>CFBundleVersion</key>\n\+ \<string>1.0</string>\n\+ \<key>CFBundleShortVersionString</key>\n\+ \<string>1.0</string>\n\+ \<key>CFBundleGetInfoString</key>\n\+ \<string>$program, bundled by cabal-macosx</string>\n\+ \<key>LSRequiresCarbon</key>\n\+ \<true/>\n\+ \<key>CSResourcesFileMapped</key>\n\+ \<true/>\n\+ \</dict>\n\+ \</plist>"
cabal-macosx.cabal view
@@ -1,5 +1,5 @@ Name: cabal-macosx-Version: 0.1.2.2+Version: 0.2.4.2 Stability: Alpha Synopsis: Cabal support for creating Mac OSX application bundles. Description:@@ -21,27 +21,63 @@ License-file: LICENSE Copyright: Eric Kow & Andy Gimblett Author: Eric Kow <eric.kow@gmail.com> & Andy Gimblett <haskell@gimbo.org.uk>-Maintainer: Andy Gimblett <haskell@gimbo.org.uk>-Homepage: http://github.com/gimbo/cabal-macosx+Maintainer: Daniele Francesconi <dfrancesconi12@gmail.com>+Homepage: http://github.com/danfran/cabal-macosx Build-Type: Simple-Cabal-Version: >=1.6+Cabal-Version: >=1.8+Tested-With: GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.1, GHC == 7.10.2, GHC == 7.10.3, GHC == 8.0.1, GHC == 8.0.2 Source-Repository head Type: git- Location: http://github.com/gimbo/cabal-macosx+ Location: http://github.com/danfran/cabal-macosx Library- Build-Depends: base >= 4 && < 5, Cabal >= 1.6, directory- , fgl >= 5.4.2.2 && < 5.5- , filepath, MissingH, parsec, process- Exposed-modules: Distribution.MacOSX- Other-modules: Distribution.MacOSX.Common,- Distribution.MacOSX.Dependencies,- Distribution.MacOSX.DG- ghc-options: -fwarn-tabs -Wall+ Build-Depends: base == 4.*+ , Cabal >= 1.6, directory+ , hscolour+ , fgl+ , filepath+ , parsec+ , process+ , text+ , containers+ Exposed-modules: Distribution.MacOSX+ Other-modules: Distribution.MacOSX.Internal,+ Distribution.MacOSX.Common,+ Distribution.MacOSX.AppBuildInfo,+ Distribution.MacOSX.Dependencies,+ Distribution.MacOSX.DG,+ Distribution.MacOSX.Templates+ ghc-options: -fwarn-tabs -Wall Executable macosx-app- Main-is: macosx-app.hs- Build-Depends: base >= 4 && < 5, Cabal >= 1.6, directory- , fgl >= 5.4.2.2 && < 5.5- , filepath, MissingH, parsec, process+ Main-is: macosx-app.hs+ Build-Depends: base == 4.*+ , Cabal >= 1.6+ , directory+ , fgl+ , filepath+ , parsec+ , process+ , text+ , containers++test-suite tests+ ghc-options: -Wall+ hs-source-dirs: .,tests+ Main-is: Main.hs+ Type: exitcode-stdio-1.0+ Other-modules: Distribution.MacOSX.Internal.Tests,+ Distribution.MacOSX.Common,+ Distribution.MacOSX.Internal+ Build-depends: base == 4.*+ , HUnit+ , test-framework+ , test-framework-hunit+ , temporary+ , Cabal >= 1.6+ , filepath+ , process+ , text+ , containers+ , directory
macosx-app.hs view
@@ -20,9 +20,9 @@ , otherBins = [] , appDeps = DoNotChase } - appInfo = AppBuildInfo { app = macapp- , appPath = appName macapp <.> "app"- , appOrigExe = exe+ appInfo = AppBuildInfo { abApp = macapp+ , abAppPath = appName macapp <.> "app"+ , abAppOrigExe = exe } if exeExists then makeAppBundle appInfo
+ tests/Distribution/MacOSX/Internal/Tests.hs view
@@ -0,0 +1,88 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+module Distribution.MacOSX.Internal.Tests where++import Prelude hiding (catch)+import Test.HUnit (Assertion, assertEqual)+import Test.Framework (Test, mutuallyExclusive, testGroup)+import Test.Framework.Providers.HUnit (testCase)++#if MIN_VERSION_Cabal(2,0,0)+import Distribution.Types.ExecutableScope+#endif+import Distribution.PackageDescription (BuildInfo(..), Executable(..), emptyBuildInfo, emptyExecutable)++import Distribution.MacOSX.Internal (getMacAppsForBuildableExecutors)+import Distribution.MacOSX.Common++#if MIN_VERSION_Cabal(2,0,0)+getExecutableScopeUnknown :: ExecutableScope+getExecutableScopeUnknown = exeScope $ emptyExecutable+#endif++macosxInternalTests :: Test+macosxInternalTests = testGroup "Distribution.MacOSX.Internal"+ [ mutuallyExclusive $ testGroup "MacOSX Internal"+ [ -- I should consider to use QuickCheck maybe... :)+ testCase "given nothing then should not try to build any mac-app" testBuildMacApp_noInput,+ testCase "given no executables then should not try to build any mac-app" testBuildMacApp_noExecutables,+ testCase "given only two executables then should try to build two mac-apps" testBuildMacApp_twoBuildableExecutables,+ testCase "given only two executables and one not executable then should try to build one mac-app" testBuildMacApp_twoExcetuablesOneBuildableAndOneNot,+ testCase "given two executables and one not executable and two apps then should try to build one mac-app" testBuildMacApp_twoAppsAndTwoExecutablesOneBuildableOneNot+ ]+ ]++testBuildMacApp_noInput :: Assertion+testBuildMacApp_noInput = do+ let actual = getMacAppsForBuildableExecutors [] []+ let expected = []+ assertEqual "nothing should be built" expected actual++testBuildMacApp_noExecutables :: Assertion+testBuildMacApp_noExecutables = do+ let apps = [MacApp "Dummy App" Nothing Nothing [] [] DoNotChase]+ let actual = getMacAppsForBuildableExecutors apps []+ let expected = []+ assertEqual "nothing should be built" expected actual++testBuildMacApp_twoBuildableExecutables :: Assertion+testBuildMacApp_twoBuildableExecutables = do+#if MIN_VERSION_Cabal(2,0,0)+ let execs = [ Executable "Dummy One" "/tmp" getExecutableScopeUnknown emptyBuildInfo+ , Executable "Dummy Two" "/tmp" getExecutableScopeUnknown emptyBuildInfo ]+#else+ let execs = [ Executable "Dummy One" "/tmp" emptyBuildInfo+ , Executable "Dummy Two" "/tmp" emptyBuildInfo ]+#endif+ let actual = getMacAppsForBuildableExecutors [] execs+ let expected = [ MacApp "Dummy One" Nothing Nothing [] [] DoNotChase+ , MacApp "Dummy Two" Nothing Nothing [] [] DoNotChase ]+ assertEqual "two mac-apps should be built" expected actual++testBuildMacApp_twoExcetuablesOneBuildableAndOneNot :: Assertion+testBuildMacApp_twoExcetuablesOneBuildableAndOneNot = do+#if MIN_VERSION_Cabal(2,0,0)+ let execs = [ Executable "Dummy One" "/tmp" getExecutableScopeUnknown (emptyBuildInfo { buildable = False })+ , Executable "Dummy Two" "/tmp" getExecutableScopeUnknown emptyBuildInfo ]+#else+ let execs = [ Executable "Dummy One" "/tmp" (emptyBuildInfo { buildable = False })+ , Executable "Dummy Two" "/tmp" emptyBuildInfo ]+#endif+ let actual = getMacAppsForBuildableExecutors [] execs+ let expected = [ MacApp "Dummy Two" Nothing Nothing [] [] DoNotChase ]+ assertEqual "two mac-apps should be built" expected actual++testBuildMacApp_twoAppsAndTwoExecutablesOneBuildableOneNot :: Assertion+testBuildMacApp_twoAppsAndTwoExecutablesOneBuildableOneNot = do+#if MIN_VERSION_Cabal(2,0,0)+ let execs = [ Executable "Dummy One" "/tmp" getExecutableScopeUnknown (emptyBuildInfo { buildable = False })+ , Executable "Dummy Two" "/tmp" getExecutableScopeUnknown emptyBuildInfo ]+#else+ let execs = [ Executable "Dummy One" "/tmp" (emptyBuildInfo { buildable = False })+ , Executable "Dummy Two" "/tmp" emptyBuildInfo ]+#endif+ let apps = [ MacApp "Dummy One" Nothing Nothing [] [] DoNotChase+ , MacApp "Dummy Two" Nothing Nothing [] [] DoNotChase ]+ let actual = getMacAppsForBuildableExecutors apps execs+ let expected = [ MacApp "Dummy Two" Nothing Nothing [] [] DoNotChase ]+ assertEqual "one mac-app should be built" expected actual
+ tests/Main.hs view
@@ -0,0 +1,9 @@+module Main (main) where++import Test.Framework (defaultMain)+import Distribution.MacOSX.Internal.Tests (macosxInternalTests)++main :: IO ()+main = defaultMain+ [ macosxInternalTests+ ]