diff --git a/Cabal/Cabal.cabal b/Cabal/Cabal.cabal index 3c03149b7fc42f3eed19f0e1ff949c428dfeace1..98523c353fdadee3b7098b7cbadcdf31e94669a9 100644 --- a/Cabal/Cabal.cabal +++ b/Cabal/Cabal.cabal @@ -25,7 +25,7 @@ build-type: Simple extra-source-files: README.md tests/README.md changelog - doc/developing-packages.markdown doc/index.markdown + doc/Cabal.css doc/developing-packages.markdown doc/index.markdown doc/installing-packages.markdown doc/misc.markdown @@ -296,6 +296,8 @@ library other-modules: Distribution.Compat.CopyFile + Distribution.Compat.GetShortPathName + Distribution.Compat.MonadFail Distribution.GetOpt Distribution.Lex Distribution.Simple.GHC.Internal @@ -310,9 +312,6 @@ library Distribution.Compat.Binary.Generic default-language: Haskell98 - -- starting with GHC 7.0, rely on {-# LANGUAGE CPP #-} instead - if !impl(ghc >= 7.0) - default-extensions: CPP -- Small, fast running tests. test-suite unit-tests @@ -367,7 +366,7 @@ test-suite package-tests regex-posix, old-time if !os(windows) - build-depends: unix + build-depends: unix, exceptions ghc-options: -Wall -rtsopts default-extensions: CPP default-language: Haskell98 diff --git a/Cabal/Distribution/Compat/GetShortPathName.hs b/Cabal/Distribution/Compat/GetShortPathName.hs new file mode 100644 index 0000000000000000000000000000000000000000..9a101dda7084fb5978385c307899f6a98651f8a7 --- /dev/null +++ b/Cabal/Distribution/Compat/GetShortPathName.hs @@ -0,0 +1,49 @@ +{-# LANGUAGE CPP, ForeignFunctionInterface #-} + +----------------------------------------------------------------------------- +-- | +-- Module : Distribution.Compat.GetShortPathName +-- +-- Maintainer : cabal-devel@haskell.org +-- Portability : Windows-only +-- +-- Win32 API 'GetShortPathName' function. + +module Distribution.Compat.GetShortPathName ( getShortPathName ) + where + +#ifdef mingw32_HOST_OS +import Control.Monad (void) + +import qualified System.Win32 as Win32 +import System.Win32 (LPCTSTR, LPTSTR, DWORD) +import Foreign.Marshal.Array (allocaArray) + +#ifdef x86_64_HOST_ARCH +#define WINAPI ccall +#else +#define WINAPI stdcall +#endif + +foreign import WINAPI unsafe "windows.h GetShortPathNameW" + c_GetShortPathName :: LPCTSTR -> LPTSTR -> DWORD -> IO DWORD + +-- | On Windows, retrieves the short path form of the specified path. On +-- non-Windows, does nothing. See https://github.com/haskell/cabal/issues/3185. +getShortPathName :: FilePath -> IO FilePath +getShortPathName path = + Win32.withTString path $ \c_path -> + allocaArray arr_len $ \c_out -> do + void $ Win32.failIfZero "GetShortPathName failed!" $ + c_GetShortPathName c_path c_out c_len + Win32.peekTString c_out + where + arr_len = length path + 1 + c_len = fromIntegral arr_len + +#else + +getShortPathName :: FilePath -> IO FilePath +getShortPathName path = return path + +#endif diff --git a/Cabal/Distribution/Simple.hs b/Cabal/Distribution/Simple.hs index 4571ef6d686634f9425a46c6cc47f4bbbabdf415..3861972975e255639a578fd3e72e6034b3402d25 100644 --- a/Cabal/Distribution/Simple.hs +++ b/Cabal/Distribution/Simple.hs @@ -87,12 +87,13 @@ import Distribution.License import Distribution.Text -- Base -import System.Environment(getArgs, getProgName) -import System.Directory(removeFile, doesFileExist, - doesDirectoryExist, removeDirectoryRecursive) -import System.Exit (exitWith,ExitCode(..)) -import System.FilePath(searchPathSeparator) -import Distribution.Compat.Environment (getEnvironment) +import System.Environment (getArgs, getProgName) +import System.Directory (removeFile, doesFileExist + ,doesDirectoryExist, removeDirectoryRecursive) +import System.Exit (exitWith,ExitCode(..)) +import System.FilePath (searchPathSeparator) +import Distribution.Compat.Environment (getEnvironment) +import Distribution.Compat.GetShortPathName (getShortPathName) import Control.Monad (when) import Data.Foldable (traverse_) @@ -612,6 +613,7 @@ runConfigureScript verbosity backwardsCompatHack flags lbi = do env <- getEnvironment let programConfig = withPrograms lbi (ccProg, ccFlags) <- configureCCompiler verbosity programConfig + ccProgShort <- getShortPathName ccProg -- The C compiler's compilation and linker flags (e.g. -- "C compiler flags" and "Gcc Linker flags" from GHC) have already -- been merged into ccFlags, so we set both CFLAGS and LDFLAGS @@ -623,7 +625,7 @@ runConfigureScript verbosity backwardsCompatHack flags lbi = do spSep = [searchPathSeparator] pathEnv = maybe (intercalate spSep extraPath) ((intercalate spSep extraPath ++ spSep)++) $ lookup "PATH" env overEnv = ("CFLAGS", Just cflagsEnv) : [("PATH", Just pathEnv) | not (null extraPath)] - args' = args ++ ["CC=" ++ ccProg] + args' = args ++ ["CC=" ++ ccProgShort] shProg = simpleProgram "sh" progDb = modifyProgramSearchPath (\p -> map ProgramSearchPathDir extraPath ++ p) emptyProgramDb shConfiguredProg <- lookupProgram shProg `fmap` configureProgram verbosity shProg progDb diff --git a/Cabal/tests/PackageTests/GhcPkgGuess/Symlink/ghc b/Cabal/tests/PackageTests/GhcPkgGuess/Symlink/ghc deleted file mode 120000 index 6533aff70cbf6d083f9800be50013bef88af8cab..0000000000000000000000000000000000000000 --- a/Cabal/tests/PackageTests/GhcPkgGuess/Symlink/ghc +++ /dev/null @@ -1 +0,0 @@ -bin/ghc \ No newline at end of file diff --git a/Cabal/tests/PackageTests/GhcPkgGuess/SymlinkGhcVersion/ghc b/Cabal/tests/PackageTests/GhcPkgGuess/SymlinkGhcVersion/ghc deleted file mode 120000 index c6c92d767566d1afb94bd076e3f85db3cb9d81a2..0000000000000000000000000000000000000000 --- a/Cabal/tests/PackageTests/GhcPkgGuess/SymlinkGhcVersion/ghc +++ /dev/null @@ -1 +0,0 @@ -bin/ghc-7.10 \ No newline at end of file diff --git a/Cabal/tests/PackageTests/GhcPkgGuess/SymlinkVersion/ghc b/Cabal/tests/PackageTests/GhcPkgGuess/SymlinkVersion/ghc deleted file mode 120000 index c6c92d767566d1afb94bd076e3f85db3cb9d81a2..0000000000000000000000000000000000000000 --- a/Cabal/tests/PackageTests/GhcPkgGuess/SymlinkVersion/ghc +++ /dev/null @@ -1 +0,0 @@ -bin/ghc-7.10 \ No newline at end of file diff --git a/Cabal/tests/PackageTests/PackageTester.hs b/Cabal/tests/PackageTests/PackageTester.hs index ae97edfd072092263f9cb5d693935d17ae2788eb..74c84b247f0d864df301e8bf66460020c838b5aa 100644 --- a/Cabal/tests/PackageTests/PackageTester.hs +++ b/Cabal/tests/PackageTests/PackageTester.hs @@ -48,6 +48,7 @@ module PackageTests.PackageTester , assertOutputDoesNotContain , assertFindInFile , concatOutput + , withSymlink -- * Test trees , TestTreeM @@ -111,6 +112,12 @@ import System.IO.Error (isDoesNotExistError) import System.Process (runProcess, waitForProcess, showCommandForUser) import Test.Tasty (TestTree, askOption, testGroup) +#ifndef mingw32_HOST_OS +import Control.Monad.Catch ( bracket_ ) +import System.Directory ( removeFile ) +import System.Posix.Files ( createSymbolicLink ) +#endif + -- | Our test monad maintains an environment recording the global test -- suite configuration 'SuiteConfig', and the local per-test -- configuration 'TestConfig'. @@ -624,6 +631,20 @@ assertFindInFile needle path = concatOutput :: String -> String concatOutput = unwords . lines . filter ((/=) '\r') +-- | Create a symlink for the duration of the provided action. If the symlink +-- already exists, it is deleted. Does not work on Windows. +withSymlink :: FilePath -> FilePath -> TestM a -> TestM a +#ifdef mingw32_HOST_OS +withSymlink _oldpath _newpath _act = + error "PackageTests.PackageTester.withSymlink: does not work on Windows!" +#else +withSymlink oldpath newpath act = do + symlinkExists <- liftIO $ doesFileExist newpath + when symlinkExists $ liftIO $ removeFile newpath + bracket_ (liftIO $ createSymbolicLink oldpath newpath) + (liftIO $ removeFile newpath) act +#endif + ------------------------------------------------------------------------ -- * Test trees diff --git a/Cabal/tests/PackageTests/Tests.hs b/Cabal/tests/PackageTests/Tests.hs index 91b71bdd0713bbd11cf367d1b45f01272c1e0a1c..106c8e2802b93094a9f9b8dcd12cd6d1e92a83ff 100644 --- a/Cabal/tests/PackageTests/Tests.hs +++ b/Cabal/tests/PackageTests/Tests.hs @@ -263,9 +263,21 @@ tests config = do tc "GhcPkgGuess/SameDirectoryGhcVersion" $ ghc_pkg_guess "ghc-7.10" unlessWindows $ do - tc "GhcPkgGuess/Symlink" $ ghc_pkg_guess "ghc" - tc "GhcPkgGuess/SymlinkVersion" $ ghc_pkg_guess "ghc" - tc "GhcPkgGuess/SymlinkGhcVersion" $ ghc_pkg_guess "ghc" + tc "GhcPkgGuess/Symlink" $ do + -- We don't want to distribute a tarball with symlinks. See #3190. + withSymlink "bin/ghc" + "tests/PackageTests/GhcPkgGuess/Symlink/ghc" $ + ghc_pkg_guess "ghc" + + tc "GhcPkgGuess/SymlinkVersion" $ do + withSymlink "bin/ghc-7.10" + "tests/PackageTests/GhcPkgGuess/SymlinkVersion/ghc" $ + ghc_pkg_guess "ghc" + + tc "GhcPkgGuess/SymlinkGhcVersion" $ do + withSymlink "bin/ghc-7.10" + "tests/PackageTests/GhcPkgGuess/SymlinkGhcVersion/ghc" $ + ghc_pkg_guess "ghc" where ghc_pkg_guess bin_name = do diff --git a/cabal-install/Distribution/Client/BuildTarget.hs b/cabal-install/Distribution/Client/BuildTarget.hs index 651790e9c80376d1d8cec5739c56f9977ca2612f..324288c2c5ed7c65f2a4c222258bbd86e46f6c1c 100644 --- a/cabal-install/Distribution/Client/BuildTarget.hs +++ b/cabal-install/Distribution/Client/BuildTarget.hs @@ -31,7 +31,6 @@ module Distribution.Client.BuildTarget ( -- * Resolving build targets resolveBuildTargets, - getUserTargetFileStatus, BuildTargetProblem(..), reportBuildTargetProblems, ) where @@ -214,6 +213,8 @@ data BuildTarget pkg = deriving (Eq, Ord, Functor, Show, Generic) +-- | Get the package that the 'BuildTarget' is referring to. +-- buildTargetPackage :: BuildTarget pkg -> pkg buildTargetPackage (BuildTargetPackage p) = p buildTargetPackage (BuildTargetComponent p _cn) = p @@ -221,6 +222,10 @@ buildTargetPackage (BuildTargetModule p _cn _mn) = p buildTargetPackage (BuildTargetFile p _cn _fn) = p +-- | Get the 'ComponentName' that the 'BuildTarget' is referring to, if any. +-- The 'BuildTargetPackage' target kind doesn't refer to any individual +-- component, while the component, module and file kinds do. +-- buildTargetComponentName :: BuildTarget pkg -> Maybe ComponentName buildTargetComponentName (BuildTargetPackage _p) = Nothing buildTargetComponentName (BuildTargetComponent _p cn) = Just cn @@ -232,6 +237,10 @@ buildTargetComponentName (BuildTargetFile _p cn _fn) = Just cn -- * Top level, do everything -- ------------------------------------------------------------ + +-- | Parse a bunch of command line args as user build targets, failing with an +-- error if any targets are unrecognised. +-- readUserBuildTargets :: [String] -> IO [UserBuildTarget] readUserBuildTargets targetStrs = do let (uproblems, utargets) = parseUserBuildTargets targetStrs @@ -239,6 +248,14 @@ readUserBuildTargets targetStrs = do return utargets +-- | A 'UserBuildTarget's is just a semi-structured string. We sill have quite +-- a bit of work to do to figure out which targets they refer to (ie packages, +-- components, file locations etc). +-- +-- The possible targets are based on the available packages (and their +-- locations). It fails with an error if any user string cannot be matched to +-- a valid target. +-- resolveUserBuildTargets :: [(PackageDescription, PackageLocation a)] -> [UserBuildTarget] -> IO [BuildTarget PackageName] resolveUserBuildTargets pkgs utargets = do @@ -319,12 +336,15 @@ forgetFileStatus t = case t of -- * Parsing user targets -- ------------------------------------------------------------ + +-- | Parse a bunch of 'UserBuildTarget's (purely without throwing exceptions). +-- parseUserBuildTargets :: [String] -> ([UserBuildTargetProblem] - ,[UserBuildTarget]) + ,[UserBuildTarget]) parseUserBuildTargets = partitionEithers . map parseUserBuildTarget parseUserBuildTarget :: String -> Either UserBuildTargetProblem - UserBuildTarget + UserBuildTarget parseUserBuildTarget targetstr = case readPToMaybe parseTargetApprox targetstr of Nothing -> Left (UserBuildTargetUnrecognised targetstr) @@ -363,10 +383,13 @@ parseUserBuildTarget targetstr = readPToMaybe p str = listToMaybe [ r | (r,s) <- Parse.readP_to_S p str , all isSpace s ] +-- | Syntax error when trying to parse a 'UserBuildTarget'. data UserBuildTargetProblem = UserBuildTargetUnrecognised String deriving Show +-- | Throw an exception with a formatted message if there are any problems. +-- reportUserBuildTargetProblems :: [UserBuildTargetProblem] -> IO () reportUserBuildTargetProblems problems = do case [ target | UserBuildTargetUnrecognised target <- problems ] of @@ -394,6 +417,10 @@ reportUserBuildTargetProblems problems = do ++ " - build tests:Data.Foo -- module qualified by component\n" ++ " - build lib:foo -- component qualified by kind" + +-- | Render a 'UserBuildTarget' back as the external syntax. This is mainly for +-- error messages. +-- showUserBuildTarget :: UserBuildTarget -> String showUserBuildTarget = intercalate ":" . components where @@ -465,6 +492,9 @@ resolveBuildTarget ppinfo opinfo userTarget = innerErr c m = (c,m) +-- | The various ways that trying to resolve a 'UserBuildTarget' to a +-- 'BuildTarget' can fail. +-- data BuildTargetProblem = BuildTargetExpected UserBuildTarget [String] String -- ^ [expected thing] (actually got) @@ -616,6 +646,8 @@ renderBuildTarget ql t = | PackageInfo { pinfoPackageFile = Just (fabs,frel) } <- [p] ] +-- | Throw an exception with a formatted message if there are any problems. +-- reportBuildTargetProblems :: [BuildTargetProblem] -> IO () reportBuildTargetProblems problems = do diff --git a/cabal-install/Main.hs b/cabal-install/Main.hs index 530698e24e609f4d83ffa918c3fd1fe810ea5bdd..6864adb9bab870518ebebc479b109fa3e91f1aa9 100644 --- a/cabal-install/Main.hs +++ b/cabal-install/Main.hs @@ -164,7 +164,7 @@ import Distribution.Version import qualified Paths_cabal_install (version) import System.Environment (getArgs, getProgName) -import System.Exit (exitFailure) +import System.Exit (exitFailure, exitSuccess) import System.FilePath ( dropExtension, splitExtension , takeExtension, (</>), (<.>)) import System.IO ( BufferMode(LineBuffering), hSetBuffering @@ -803,7 +803,7 @@ testAction (testFlags, buildFlags, buildExFlags) extraArgs globalFlags = do testFlags' = testFlags { testDistPref = toFlag distPref } -- The package was just configured, so the LBI must be available. - names <- componentNamesFromLBI distPref "test suites" + names <- componentNamesFromLBI verbosity distPref "test suites" (\c -> case c of { LBI.CTest{} -> True; _ -> False }) let extraArgs' | null extraArgs = case names of @@ -822,9 +822,10 @@ data ComponentNames = ComponentNamesUnknown | ComponentNames [LBI.ComponentName] -- | Return the names of all buildable components matching a given predicate. -componentNamesFromLBI :: FilePath -> String -> (LBI.Component -> Bool) +componentNamesFromLBI :: Verbosity -> FilePath -> String + -> (LBI.Component -> Bool) -> IO ComponentNames -componentNamesFromLBI distPref targetsDescr compPred = do +componentNamesFromLBI verbosity distPref targetsDescr compPred = do eLBI <- tryGetPersistBuildConfig distPref case eLBI of Left err -> case err of @@ -840,7 +841,10 @@ componentNamesFromLBI distPref targetsDescr compPred = do . filter compPred $ LBI.pkgComponents pkgDescr if null names - then die $ "Package has no buildable " ++ targetsDescr ++ "." + then do notice verbosity $ "Package has no buildable " + ++ targetsDescr ++ "." + exitSuccess -- See #3215. + else return $! (ComponentNames names) benchmarkAction :: (BenchmarkFlags, BuildFlags, BuildExFlags) @@ -869,7 +873,7 @@ benchmarkAction (benchmarkFlags, buildFlags, buildExFlags) benchmarkFlags'= benchmarkFlags { benchmarkDistPref = toFlag distPref } -- The package was just configured, so the LBI must be available. - names <- componentNamesFromLBI distPref "benchmarks" + names <- componentNamesFromLBI verbosity distPref "benchmarks" (\c -> case c of { LBI.CBench{} -> True; _ -> False; }) let extraArgs' | null extraArgs = case names of diff --git a/cabal-install/cabal-install.cabal b/cabal-install/cabal-install.cabal index 41b508d797dee7313043e823d6577f12d1fc8a81..b5f87e522e21f0f8982d47c6bb8429f4e38ad993 100644 --- a/cabal-install/cabal-install.cabal +++ b/cabal-install/cabal-install.cabal @@ -103,7 +103,7 @@ source-repository head subdir: cabal-install Flag old-bytestring - description: Use bytestring == 0.9.* and bytestring-builder + description: Use bytestring < 0.10.2 and bytestring-builder default: False Flag old-directory @@ -253,7 +253,7 @@ executable cabal hackage-security >= 0.5 && < 0.6 if flag(old-bytestring) - build-depends: bytestring < 0.10.2, bytestring-builder + build-depends: bytestring < 0.10.2, bytestring-builder >= 0.10 && < 1 else build-depends: bytestring >= 0.10.2 diff --git a/cabal-install/changelog b/cabal-install/changelog index 31b461806ab7cdf450d7bff5a65694856b2146af..f7ab189c3ab2ad8fb3ef390fd05f6f719718ff85 100644 --- a/cabal-install/changelog +++ b/cabal-install/changelog @@ -56,6 +56,8 @@ * Fixed space leaks in modular solver (#2916, #2914). * Added a new command: 'gen-bounds' (#3223). See http://softwaresimply.blogspot.se/2015/08/cabal-gen-bounds-easy-generation-of.html. + * Tech preview of new nix-style isolated project-based builds. + Currently provides the commands (new-)build/repl/configure. 1.22.0.0 Johan Tibell <johan.tibell@gmail.com> January 2015 * New command: user-config (#2159).