Hello, 2 patches to contribute to cabal. The first is a simple oversite I noticed while implementing the second. Essentially, the call out to an external command by system has every supplied string wrapped in ', but doesn't escape this character. This is fixed in the first patch.
Thu Aug 4 20:06:11 EDT 2011 m...@mattcox.ca * Protect internal ' in quoted system commands The previous implementation did not escape ' in the input which causes them to break the quotation. The second is support that I require for a project which needs to use hooks to invoke cmake and make to build a legacy C component. I followed the existing code conventions which make a few questionable choices. For one, the progInvokeEnv field is [(String, String)] rather than Maybe [(String, String)] like is used by e.g., runInteractiveProcess. The interpretation in the existing code is that this is a supplemental list of environment variables rather than a complete environment. There is no way to remove existing variable with this representation other than assigning them empty values. This is a different interpretation to that used by rawSystemExitWithEnv, which uses it as the entire environment. I had the runInvokation functions merge the supplied environment on top of the system environment rather than modify the behaviour of the rawSystemExitWithEnv function. The rawSystemExit functions were given variants accepting working directories rather than adding a Maybe FilePath argument and changing the type signature. I hope that this can go in for 1.12. In particular, I'd like to suggest a bump to 1.11.3 so that I can depend on the version to ensure the behaviour introduced in this patch is available. Fri Aug 5 12:19:48 EDT 2011 m...@mattcox.ca * Finish implementing Distribution.Simple.Program.Run The environment and working directory settings in the ProgramInvocation record were not totally handled by the run invocation functions in the module. The selection of a working directory was implemented for all functions, and input set in the invocation is handled by getProgramInvocation output. The environment in the record is taken to be a list of supplemental environment settings to add or override the system environment variables, rather than as a complete environment. This is the behaviour implemented by the functions in Distribution.Simple.Program.Script. New functions taking an environment and working directory were added to the Distribution.Simple.Utils module.
New patches: [Protect internal ' in quoted system commands m...@mattcox.ca**20110805000611 Ignore-this: 393b6661e5fc222bcdcbdfb290760430 The previous implementation did not escape ' in the input which causes them to break the quotation. ] hunk ./cabal/Distribution/Simple/Utils.hs 475 hPutStr inHandle inputStr hClose inHandle - let quote name = "'" ++ name ++ "'" + let quote name = "'" ++ concatMap quote_c name ++ "'" + -- Quote protect a single character + quote_c '\'' = "\\'" + quote_c c = [c] cmd = unwords (map quote (path:args)) ++ " <" ++ quote inName ++ " >" ++ quote outName [Finish implementing Distribution.Simple.Program.Run m...@mattcox.ca**20110805161948 Ignore-this: e91fdea2fdd145d222082b6e93fe6d6e The environment and working directory settings in the ProgramInvocation record were not totally handled by the run invocation functions in the module. The selection of a working directory was implemented for all functions, and input set in the invocation is handled by getProgramInvocation output. The environment in the record is taken to be a list of supplemental environment settings to add or override the system environment variables, rather than as a complete environment. This is the behaviour implemented by the functions in Distribution.Simple.Program.Script. New functions taking an environment and working directory were added to the Distribution.Simple.Utils module. ] { hunk ./cabal/Distribution/Simple/Program/Run.hs 28 import Distribution.Simple.Program.Types ( ConfiguredProgram(..), programPath ) import Distribution.Simple.Utils - ( die, rawSystemExit, rawSystemStdInOut - , toUTF8, fromUTF8, normaliseLineEndings ) + ( die + , toUTF8, fromUTF8, normaliseLineEndings + , rawSystemExitWithEnv + , rawSystemExitWithCwdAndEnv + , rawSystemStdInOutWithCwdAndEnv + ) import Distribution.Verbosity ( Verbosity ) hunk ./cabal/Distribution/Simple/Program/Run.hs 39 import Data.List ( foldl', unfoldr ) +import qualified Data.Map as M + ( fromList, toList, insert) import Control.Monad ( when ) import System.Exit hunk ./cabal/Distribution/Simple/Program/Run.hs 46 ( ExitCode(..) ) +import System.Environment + ( getEnvironment ) + -- | Represents a specific invocation of a specific program. -- -- This is used as an intermediate type between deciding how to call a program hunk ./cabal/Distribution/Simple/Program/Run.hs 59 data ProgramInvocation = ProgramInvocation { progInvokePath :: FilePath, progInvokeArgs :: [String], - progInvokeEnv :: [(String, String)], + progInvokeEnv :: [(String, String)], -- ^ Supplemental environment progInvokeCwd :: Maybe FilePath, progInvokeInput :: Maybe String, progInvokeInputEncoding :: IOEncoding, hunk ./cabal/Distribution/Simple/Program/Run.hs 97 ++ programOverrideArgs prog } +mergeEnvironment :: [(String,String)] -> IO [(String,String)] +mergeEnvironment new = do + env <- getEnvironment + let sysvars = M.fromList env + merged = foldr (uncurry M.insert) sysvars new + return (M.toList merged) runProgramInvocation :: Verbosity -> ProgramInvocation -> IO () runProgramInvocation verbosity hunk ./cabal/Distribution/Simple/Program/Run.hs 109 ProgramInvocation { progInvokePath = path, progInvokeArgs = args, - progInvokeEnv = [], - progInvokeCwd = Nothing, + progInvokeEnv = env, + progInvokeCwd = mcwd, progInvokeInput = Nothing hunk ./cabal/Distribution/Simple/Program/Run.hs 112 - } = - rawSystemExit verbosity path args + } = mergeEnvironment env >>= \renv -> case mcwd of + Nothing -> rawSystemExitWithEnv verbosity path args renv + Just dir -> rawSystemExitWithCwdAndEnv verbosity path args dir renv runProgramInvocation verbosity ProgramInvocation { hunk ./cabal/Distribution/Simple/Program/Run.hs 120 progInvokePath = path, progInvokeArgs = args, - progInvokeEnv = [], - progInvokeCwd = Nothing, + progInvokeEnv = env, + progInvokeCwd = mcwd, progInvokeInput = Just inputStr, progInvokeInputEncoding = encoding } = do hunk ./cabal/Distribution/Simple/Program/Run.hs 125 - (_, errors, exitCode) <- rawSystemStdInOut verbosity - path args - (Just input) False + renv <- mergeEnvironment env + (_, errors, exitCode) <- rawSystemStdInOutWithCwdAndEnv verbosity path args + mcwd (Just renv) (Just input) False when (exitCode /= ExitSuccess) $ die errors where hunk ./cabal/Distribution/Simple/Program/Run.hs 135 IOEncodingText -> (inputStr, False) IOEncodingUTF8 -> (toUTF8 inputStr, True) -- use binary mode for utf8 -runProgramInvocation _ _ = - die "runProgramInvocation: not yet implemented for this form of invocation" - getProgramInvocationOutput :: Verbosity -> ProgramInvocation -> IO String getProgramInvocationOutput verbosity hunk ./cabal/Distribution/Simple/Program/Run.hs 141 ProgramInvocation { progInvokePath = path, progInvokeArgs = args, - progInvokeEnv = [], - progInvokeCwd = Nothing, - progInvokeInput = Nothing, + progInvokeEnv = env, + progInvokeCwd = mcwd, + progInvokeInput = minput, progInvokeOutputEncoding = encoding } = do let utf8 = case encoding of IOEncodingUTF8 -> True; _ -> False hunk ./cabal/Distribution/Simple/Program/Run.hs 149 decode | utf8 = fromUTF8 . normaliseLineEndings | otherwise = id - (output, errors, exitCode) <- rawSystemStdInOut verbosity - path args - Nothing utf8 + renv <- mergeEnvironment env + (output, errors, exitCode) <- rawSystemStdInOutWithCwdAndEnv verbosity path + args mcwd (Just renv) + (fmap (\x -> (x, False)) minput) utf8 when (exitCode /= ExitSuccess) $ die errors return (decode output) hunk ./cabal/Distribution/Simple/Program/Run.hs 158 -getProgramInvocationOutput _ _ = - die "getProgramInvocationOutput: not yet implemented for this form of invocation" - - -- | Like the unix xargs program. Useful for when we've got very long command -- lines that might overflow an OS limit on command line length and so you -- need to invoke a command multiple times to get all the args in. hunk ./cabal/Distribution/Simple/Utils.hs 61 -- * running programs rawSystemExit, + rawSystemExitWithCwd, rawSystemExitWithEnv, hunk ./cabal/Distribution/Simple/Utils.hs 63 + rawSystemExitWithCwdAndEnv, rawSystemStdout, hunk ./cabal/Distribution/Simple/Utils.hs 65 + rawSystemStdoutWithCwdAndEnv, rawSystemStdInOut, hunk ./cabal/Distribution/Simple/Utils.hs 67 + rawSystemStdInOutWithCwdAndEnv, maybeExit, xargs, findProgramLocation, hunk ./cabal/Distribution/Simple/Utils.hs 159 , findExecutable ) import System.Environment ( getProgName ) -import System.Cmd - ( rawSystem ) import System.Exit ( exitWith, ExitCode(..) ) import System.FilePath hunk ./cabal/Distribution/Simple/Utils.hs 352 res <- cmd unless (res == ExitSuccess) $ exitWith res -printRawCommandAndArgs :: Verbosity -> FilePath -> [String] -> IO () -printRawCommandAndArgs verbosity path args - | verbosity >= deafening = print (path, args) - | verbosity >= verbose = putStrLn $ unwords (path : args) - | otherwise = return () - -printRawCommandAndArgsAndEnv :: Verbosity - -> FilePath - -> [String] - -> [(String, String)] - -> IO () -printRawCommandAndArgsAndEnv verbosity path args env - | verbosity >= deafening = do putStrLn ("Environment: " ++ show env) +-- | Print status to indicate that a raw command is being run. +printRawCommandAndArgs :: Verbosity + -> FilePath -- ^ The command being run. + -> [String] -- ^ Any arguments + -> Maybe FilePath -- ^ The working directory + -> Maybe [(String,String)] -- ^ The environment + -> IO () +printRawCommandAndArgs verbosity path args cwd env + | verbosity >= deafening = do case env of + Just e -> putStrLn ("Environment: " ++ show e) + Nothing -> return () + case cwd of + Just dir -> putStrLn ("Cwd: " ++ dir) + Nothing -> return () print (path, args) | verbosity >= verbose = putStrLn $ unwords (path : args) | otherwise = return () hunk ./cabal/Distribution/Simple/Utils.hs 370 --- Exit with the same exitcode if the subcommand fails +-- | Exit with the same exitcode if the subcommand fails rawSystemExit :: Verbosity -> FilePath -> [String] -> IO () hunk ./cabal/Distribution/Simple/Utils.hs 372 -rawSystemExit verbosity path args = do - printRawCommandAndArgs verbosity path args - hFlush stdout - exitcode <- rawSystem path args - unless (exitcode == ExitSuccess) $ do - debug verbosity $ path ++ " returned " ++ show exitcode - exitWith exitcode +rawSystemExit verbosity path args = + doRawSystemExitWithCwdAndEnv verbosity path args Nothing Nothing + +-- | Exit with the same exitcode if the subcommand fails +rawSystemExitWithCwd :: Verbosity -> FilePath -> [String] + -> FilePath -- ^ Directory to run command in + -> IO () +rawSystemExitWithCwd verbosity path args cwd = + doRawSystemExitWithCwdAndEnv verbosity path args (Just cwd) Nothing hunk ./cabal/Distribution/Simple/Utils.hs 382 +-- | Exit with the same exitcode if the subcommand fails rawSystemExitWithEnv :: Verbosity -> FilePath -> [String] hunk ./cabal/Distribution/Simple/Utils.hs 386 - -> [(String, String)] + -> [(String, String)] -- ^ Replace system environment -> IO () hunk ./cabal/Distribution/Simple/Utils.hs 388 -rawSystemExitWithEnv verbosity path args env = do - printRawCommandAndArgsAndEnv verbosity path args env +rawSystemExitWithEnv verbosity path args env = + doRawSystemExitWithCwdAndEnv verbosity path args Nothing (Just env) + +-- | Exit with the same exitcode if the subcommand fails +rawSystemExitWithCwdAndEnv :: Verbosity + -> FilePath + -> [String] + -> FilePath -- ^ Directory to run in + -> [(String, String)] -- ^ Replace system evironment + -> IO () +rawSystemExitWithCwdAndEnv verbosity path args cwd env = + doRawSystemExitWithCwdAndEnv verbosity path args (Just cwd) (Just env) + +doRawSystemExitWithCwdAndEnv :: Verbosity + -> FilePath + -> [String] + -> Maybe FilePath + -> Maybe [(String, String)] + -> IO () +doRawSystemExitWithCwdAndEnv verbosity path args cwd env = do + printRawCommandAndArgs verbosity path args cwd env hFlush stdout hunk ./cabal/Distribution/Simple/Utils.hs 410 - ph <- runProcess path args Nothing (Just env) Nothing Nothing Nothing + ph <- runProcess path args cwd env Nothing Nothing Nothing exitcode <- waitForProcess ph unless (exitcode == ExitSuccess) $ do debug verbosity $ path ++ " returned " ++ show exitcode hunk ./cabal/Distribution/Simple/Utils.hs 421 -- The output is assumed to be text in the locale encoding. -- rawSystemStdout :: Verbosity -> FilePath -> [String] -> IO String -rawSystemStdout verbosity path args = do - (output, errors, exitCode) <- rawSystemStdInOut verbosity path args - Nothing False +rawSystemStdout verbosity path args = + rawSystemStdoutWithCwdAndEnv verbosity path args Nothing Nothing + +-- | Run a command in a specified directory and return its output. +-- +-- The output is assumed to be text in the locale encoding. +-- +rawSystemStdoutWithCwdAndEnv :: Verbosity + -> FilePath -- ^ The command + -> [String] -- ^ The arguments + -> Maybe FilePath -- ^ The working directory + -> Maybe [(String, String)] + -- ^ Replace the system environment + -> IO String +rawSystemStdoutWithCwdAndEnv verbosity path args cwd env = do + (output, errors, exitCode) <- rawSystemStdInOutWithCwdAndEnv verbosity path + args cwd env Nothing False when (exitCode /= ExitSuccess) $ die errors return output hunk ./cabal/Distribution/Simple/Utils.hs 451 -> Maybe (String, Bool) -- ^ input text and binary mode -> Bool -- ^ output in binary mode -> IO (String, String, ExitCode) -- ^ output, errors, exit -rawSystemStdInOut verbosity path args input outputBinary = do - printRawCommandAndArgs verbosity path args +rawSystemStdInOut verbosity path args input outputBinary = + rawSystemStdInOutWithCwdAndEnv verbosity path args Nothing Nothing + input outputBinary + +rawSystemStdInOutWithCwdAndEnv + :: Verbosity + -> FilePath -> [String] + -> Maybe FilePath -- ^ The working directory + -> Maybe [(String, String)] -- ^ Replace the system environment + -> Maybe (String, Bool) -- ^ input text and binary mode + -> Bool -- ^ output in binary mode + -> IO (String, String, ExitCode) -- ^ output, errors, exit +rawSystemStdInOutWithCwdAndEnv verbosity path args cwd env input outputBinary = do + printRawCommandAndArgs verbosity path args cwd env #ifdef __GLASGOW_HASKELL__ Exception.bracket hunk ./cabal/Distribution/Simple/Utils.hs 468 - (runInteractiveProcess path args Nothing Nothing) + (runInteractiveProcess path args cwd env) (\(inh,outh,errh,_) -> hClose inh >> hClose outh >> hClose errh) $ \(inh,outh,errh,pid) -> do hunk ./cabal/Distribution/Simple/Utils.hs 526 hPutStr inHandle inputStr hClose inHandle + unless (env == Nothing && cwd == Nothing) $ + die "raw system execution with cwd or env is only implemented for ghc" + let quote name = "'" ++ concatMap quote_c name ++ "'" -- Quote protect a single character quote_c '\'' = "\\'" } Context: [Simplify some code in Program.Hpc slightly Duncan Coutts <dun...@community.haskell.org>**20110726001531 Ignore-this: d7ea77d1f072f7071fc709e0c9a38ded ] [Added Distribution.Simple.Program.Hpc. Thomas Tuegel <ttue...@gmail.com>**20110719004251 Ignore-this: a988f4262e4f52c8ae0a3ca5715a636e ] [Restore graceful failure upon invoking "cabal test" before "cabal build". Thomas Tuegel <ttue...@gmail.com>**20110719002218 Ignore-this: 2096a4cfad17eb67ef26bb15a8b3a066 ] [Fix executable test suite unit test for improved HPC interface. Thomas Tuegel <ttue...@gmail.com>**20110718033150 Ignore-this: b543b01721940b23aac7bd46282425b1 ] [Generate aggregate coverage statistics from all test suites in package. Thomas Tuegel <ttue...@gmail.com>**20110718050448 Ignore-this: bff5f3167ab61da015b8fcb7c4f77cdc ] [Invoke HPC using D.S.Program utilities. Thomas Tuegel <ttue...@gmail.com>**20110718045949 Ignore-this: 37e1f01f594dd522c5328b397ac0e94d This patch also reorganizes the HPC output directories for consistency. All files related to HPC are now located in the "dist/hpc" directory. ] [Fix cabal haddock for packages with internal dependencies Duncan Coutts <dun...@community.haskell.org>**20110718235728 Ignore-this: 86cdab6325a86875e9ae592881b4f54f ] [Update cabal sdist to follow the changes in the Cabal lib Duncan Coutts <dun...@community.haskell.org>**20110717223648 Ignore-this: 1136aa98cb024a10250ea75ec8633a2c ] [Added unit test for test options. Thomas Tuegel <ttue...@gmail.com>**20110521164529 Ignore-this: 3dc94c06cdfacf20cf000682370fbf3 ] [Fixed crash on Windows due to file handle leak. Thomas Tuegel <ttue...@gmail.com>**20110518030422 Ignore-this: c94eb903aef9ffcf52394a821d245dda Ticket #843. Cabal test crashed when trying to delete a temporary log file because 'readFile' reads unnecessarily lazily and was keeping a file handle open during attempted deletion. This patch forces the entire file to be read so the handle will be closed. ] [Stop cabal-install from duplicating test options. Thomas Tuegel <ttue...@gmail.com>**20110521232047 Ignore-this: 55b98ab47306178e355cacedc7a5a6d2 ] [Fix use of multiple test options. Thomas Tuegel <ttue...@gmail.com>**20110521223029 Ignore-this: c694ad21faab23abb7157ccec700ccf2 ] [Don't prefix test output with ">>>". Thomas Tuegel <ttue...@gmail.com>**20110708035007 Ignore-this: a9d417eb836c641339a0203d1c36e82e Ticket #848. Removing the prefix brings "cabal test" in line with other cabal commands, which do not prefix their output, either. Prior to this patch, the summary notices which appear before and after each test suite were written to the temporary log file along with the stdio from the test executable; this would lead to duplicate notices when the contents of the temporary log file are read onto the console. After this patch, the summary notices are never written to the temporary log file, only to the console and the final log file (which is never read by Cabal), removing the confusing duplicate notices. ] [Fail gracefully when running "setup test" before "setup build". Thomas Tuegel <ttue...@gmail.com>**20110303164611 Ignore-this: a4d818cd7702ddbbbbffc8679abeb85d ] [Bump cabal-install version Duncan Coutts <dun...@community.haskell.org>**20110708013248 Ignore-this: 16626faad564787fc5ae3808d1e6ccc9 ] [Bump Cabal lib version Duncan Coutts <dun...@community.haskell.org>**20110708013245 Ignore-this: e01c7efbb68856167c227ba118ddce33 ] [Couple of trivial code changes Duncan Coutts <dun...@community.haskell.org>**20110708013012 Ignore-this: b98aaac9e33f8c684cefedcd05d37ee2 ] [Fix withComponentsLBI and move Components to LocalBuildInfo module Duncan Coutts <dun...@community.haskell.org>**20110708012122 Ignore-this: 57217119f7825c9bcd3824a34ecd0c8f An annoyance of the current Simple build system is that each phase (build, install, etc) can be passed additional HookedBuildInfo which gets merged into the PackageDescription. This means that we cannot process the PackageDescription up front at configure time and just store and reuse it later, we have to work from it each time afresh. The recent addition of Components (libs, exes, test suites) and a topoligical sort of the components in the LocalBuildInfo fell foul of this annoyance. The LocalBuildInfo stored the entire component which meant they were not updated with the HookedBuildInfo. This broke packages with custom Setup.hs scripts that took advantage of the HookedBuildInfo feature, including those with configure scripts. The solution is to store not the list of whole components but the list of component names. Then withComponentsLBI retrieves the actual components from the PackageDescription which thus includes the HookedBuildInfo. Also moved the Components into an internal module because (for the moment at least) it is part of the Simple build system, not part of the package description. ] [Relax some dependencies Ian Lynagh <ig...@earth.li>**20110706192619 Ignore-this: 6353c1d64a2fff3cef3ca0d8a9f2e95e ] [Add files needed by the GHC build system Ian Lynagh <ig...@earth.li>**20110624003654 Ignore-this: a40dd98104e994d1a1648c3ce2676a45 ] [Add a dash separator for pid in createTempDirectory and openBinaryTempFile too Jens Petersen <j...@community.haskell.org>**20110519021658 Ignore-this: ee0c842388212326579309ac6f93408f ] [Update changelog for 1.10.2.0 Duncan Coutts <dun...@community.haskell.org>**20110618190748 Ignore-this: 64129f45dd16d2d93c82097530dc15d1 ] [TAG cabal-install merged Duncan Coutts <dun...@community.haskell.org>**20110619135228 Ignore-this: 58d670de46a24046d0b869dc2b88e13a We now have both the Cabal library and the cabal-install tool together in the same repo, each in a subdir. The idea is that this will make splitting packages and moving code between package rather easier in future. ] Patch bundle hash: 0d9e4009e9161b3e2f5668e58b27163d7c180f5f
_______________________________________________ cabal-devel mailing list cabal-devel@haskell.org http://www.haskell.org/mailman/listinfo/cabal-devel