1 -----------------------------------------------------------------------------
2 -- $Id: Main.hs,v 1.5 2001/03/25 11:08:42 panne Exp $
4 -- Package management tool
5 -----------------------------------------------------------------------------
11 #ifdef __GLASGOW_HASKELL__
12 import qualified Exception
21 -- HACK: The confusing cpp tricks below introduce a leading space. Note that
22 -- cpp's stringify operator # doesn't work because of the -traditional flag.
23 -- TEXT SUBSTITUTION IS EVIL. TEXT SUBSTITUTION IS EVIL. TEXT SUBSTITUTION...
25 \ clibdir" ++ "/package.conf"
30 case getOpt Permute flags args of
31 (clis,[],[]) -> runit clis
32 (_,_,errors) -> die (concat errors ++
33 usageInfo usageHeader flags)
35 data Flag = Config String | List | Add | Remove String
36 isConfig (Config _) = True
39 usageHeader = "ghc-pkg [OPTION...]"
42 Option ['f'] ["config-file"] (ReqArg Config "FILE")
43 "Use the specified package config file",
44 Option ['l'] ["list-packages"] (NoArg List)
45 "List the currently installed packages",
46 Option ['a'] ["add-package"] (NoArg Add)
48 Option ['r'] ["remove-package"] (ReqArg Remove "NAME")
49 "Remove an installed package"
54 case [ f | Config f <- clis ] of
55 [] -> return (tail default_pkgconf) -- HACK: Remove leading space
57 _ -> die (usageInfo usageHeader flags)
59 s <- readFile conf_file
60 let details = read s :: [PackageConfig]
61 eval_catch details (\_ -> die "parse error in package config file")
63 case [ c | c <- clis, not (isConfig c) ] of
64 [ List ] -> listPackages details
65 [ Add ] -> addPackage details conf_file
66 [ Remove p ] -> removePackage details conf_file p
67 _ -> die (usageInfo usageHeader flags)
70 listPackages :: [PackageConfig] -> IO ()
71 listPackages details = do
72 hPutStr stdout (listPkgs details)
76 addPackage :: [PackageConfig] -> FilePath -> IO ()
77 addPackage details pkgconf = do
78 checkConfigAccess pkgconf
79 hPutStr stdout "Reading package info from stdin... "
81 let new_pkg = read s :: PackageConfig
82 eval_catch new_pkg (\_ -> die "parse error in package info")
83 hPutStrLn stdout "done."
84 if (name new_pkg `elem` map name details)
85 then die ("package `" ++ name new_pkg ++ "' already installed")
87 savePackageConfig pkgconf
88 maybeRestoreOldConfig pkgconf $ do
89 writeNewConfig pkgconf (details ++ [new_pkg])
92 removePackage :: [PackageConfig] -> FilePath -> String -> IO ()
93 removePackage details pkgconf pkg = do
94 checkConfigAccess pkgconf
95 if (pkg `notElem` map name details)
96 then die ("package `" ++ pkg ++ "' not installed")
98 savePackageConfig pkgconf
99 maybeRestoreOldConfig pkgconf $ do
100 writeNewConfig pkgconf (filter ((/= pkg) . name) details)
103 checkConfigAccess :: FilePath -> IO ()
104 checkConfigAccess pkgconf = do
105 access <- getPermissions pkgconf
106 when (not (writable access))
107 (die "you don't have permission to modify the package configuration file")
109 maybeRestoreOldConfig :: String -> IO () -> IO ()
110 maybeRestoreOldConfig conf_file io
111 = my_catch io (\e -> do
112 hPutStr stdout "\nWARNING: an error was encountered while the new \n\
113 \configuration was being written. Attempting to \n\
114 \restore the old configuration... "
115 renameFile (conf_file ++ ".old") conf_file
116 hPutStrLn stdout "done."
120 writeNewConfig :: String -> [PackageConfig] -> IO ()
121 writeNewConfig conf_file details = do
122 hPutStr stdout "Writing new package config file... "
123 h <- openFile conf_file WriteMode
124 hPutStr h (dumpPackages details )
126 hPutStrLn stdout "done."
128 savePackageConfig :: String -> IO ()
129 savePackageConfig conf_file = do
130 hPutStr stdout "Saving old package config file... "
131 -- mv rather than cp because we've already done an hGetContents
132 -- on this file so we won't be able to open it for writing
133 -- unless we move the old one out of the way...
134 renameFile conf_file (conf_file ++ ".old")
135 hPutStrLn stdout "done."
137 -----------------------------------------------------------------------------
139 die :: String -> IO a
140 die s = do { hPutStrLn stderr s; exitWith (ExitFailure 1) }
142 -----------------------------------------------------------------------------
145 #ifndef __GLASGOW_HASKELL__
147 eval_catch a h = a `seq` return ()
153 my_throw = Exception.throw
154 #if __GLASGOW_HASKELL__ > 408
155 eval_catch = Exception.catch . Exception.evaluate
156 my_catch = Exception.catch
158 eval_catch = Exception.catchAll
159 my_catch = Exception.catchAllIO