-#ifdef mingw32_TARGET_OS
-subst a b ls = map (\ x -> if x == a then b else x) ls
-
-unDosifyPath xs = subst '\\' '/' xs
-#endif
-
-runit clis = do
- conf_file <-
- case [ f | Config f <- clis ] of
- fs@(_:_) -> return (last fs)
-#ifndef mingw32_TARGET_OS
- [] -> die "missing -f option, location of package.conf unknown"
-#else
- [] -> do h <- getModuleHandle Nothing
- n <- getModuleFileName h
- return (reverse (drop (length "/bin/ghc-pkg.exe") (reverse (unDosifyPath n))) ++ "/package.conf")
-#endif
-
- let toField "import_dirs" = return import_dirs
- toField "source_dirs" = return source_dirs
- toField "library_dirs" = return library_dirs
- toField "hs_libraries" = return hs_libraries
- toField "extra_libraries" = return extra_libraries
- toField "include_dirs" = return include_dirs
- toField "c_includes" = return c_includes
- toField "package_deps" = return package_deps
- toField "extra_ghc_opts" = return extra_ghc_opts
- toField "extra_cc_opts" = return extra_cc_opts
- toField "extra_ld_opts" = return extra_ld_opts
- toField s = die ("unknown field: `" ++ s ++ "'")
-
- fields <- mapM toField [ f | Field f <- clis ]
-
- s <- readFile conf_file
- let packages = read s :: [PackageConfig]
- eval_catch packages (\_ -> die "parse error in package config file")
-
- let auto_ghci_libs = any isAuto clis
- where isAuto AutoGHCiLibs = True; isAuto _ = False
- input_file = head ([ f | (Input f) <- clis] ++ ["-"])
+ourCopyright :: String
+ourCopyright = "GHC package manager version " ++ version ++ "\n"
+
+usageHeader :: String -> String
+usageHeader prog = substProg prog $
+ "Usage:\n" ++
+ " $p register {filename | -}\n" ++
+ " Register the package using the specified installed package\n" ++
+ " description. The syntax for the latter is given in the $p\n" ++
+ " documentation.\n" ++
+ "\n" ++
+ " $p update {filename | -}\n" ++
+ " Register the package, overwriting any other package with the\n" ++
+ " same name.\n" ++
+ "\n" ++
+ " $p unregister {pkg-id}\n" ++
+ " Unregister the specified package.\n" ++
+ "\n" ++
+ " $p expose {pkg-id}\n" ++
+ " Expose the specified package.\n" ++
+ "\n" ++
+ " $p hide {pkg-id}\n" ++
+ " Hide the specified package.\n" ++
+ "\n" ++
+ " $p list\n" ++
+ " List registered packages in the global database, and also the" ++
+ " user database if --user is given.\n" ++
+ "\n" ++
+ " $p describe {pkg-id}\n" ++
+ " Give the registered description for the specified package. The\n" ++
+ " description is returned in precisely the syntax required by $p\n" ++
+ " register.\n" ++
+ "\n" ++
+ " $p field {pkg-id} {field}\n" ++
+ " Extract the specified field of the package description for the\n" ++
+ " specified package.\n" ++
+ "\n" ++
+ " The following optional flags are also accepted:\n"
+
+substProg :: String -> String -> String
+substProg _ [] = []
+substProg prog ('$':'p':xs) = prog ++ substProg prog xs
+substProg prog (c:xs) = c : substProg prog xs
+
+-- -----------------------------------------------------------------------------
+-- Do the business
+
+runit :: [Flag] -> [String] -> IO ()
+runit cli nonopts = do
+ prog <- getProgramName
+ let
+ force = FlagForce `elem` cli
+ auto_ghci_libs = FlagAutoGHCiLibs `elem` cli
+ --
+ -- first, parse the command
+ case nonopts of
+ ["register", filename] ->
+ registerPackage filename [] cli auto_ghci_libs False force
+ ["update", filename] ->
+ registerPackage filename [] cli auto_ghci_libs True force
+ ["unregister", pkgid_str] -> do
+ pkgid <- readGlobPkgId pkgid_str
+ unregisterPackage pkgid cli
+ ["expose", pkgid_str] -> do
+ pkgid <- readGlobPkgId pkgid_str
+ exposePackage pkgid cli
+ ["hide", pkgid_str] -> do
+ pkgid <- readGlobPkgId pkgid_str
+ hidePackage pkgid cli
+ ["list"] -> do
+ listPackages cli
+ ["describe", pkgid_str] -> do
+ pkgid <- readGlobPkgId pkgid_str
+ describePackage cli pkgid
+ ["field", pkgid_str, field] -> do
+ pkgid <- readGlobPkgId pkgid_str
+ describeField cli pkgid field
+ [] -> do
+ die ("missing command\n" ++
+ usageInfo (usageHeader prog) flags)
+ (_cmd:_) -> do
+ die ("command-line syntax error\n" ++
+ usageInfo (usageHeader prog) flags)
+
+parseCheck :: ReadP a a -> String -> String -> IO a
+parseCheck parser str what =
+ case [ x | (x,ys) <- readP_to_S parser str, all isSpace ys ] of
+ [x] -> return x
+ _ -> die ("cannot parse \'" ++ str ++ "\' as a " ++ what)
+
+readPkgId :: String -> IO PackageIdentifier
+readPkgId str = parseCheck parsePackageId str "package identifier"
+
+readGlobPkgId :: String -> IO PackageIdentifier
+readGlobPkgId str = parseCheck parseGlobPackageId str "package identifier"
+
+parseGlobPackageId :: ReadP r PackageIdentifier
+parseGlobPackageId =
+ parsePackageId
+ +++
+ (do n <- parsePackageName; string "-*"
+ return (PackageIdentifier{ pkgName = n, pkgVersion = globVersion }))
+
+-- globVersion means "all versions"
+globVersion :: Version
+globVersion = Version{ versionBranch=[], versionTags=["*"] }
+
+-- -----------------------------------------------------------------------------
+-- Package databases
+
+-- Some commands operate on a single database:
+-- register, unregister, expose, hide
+-- however these commands also check the union of the available databases
+-- in order to check consistency. For example, register will check that
+-- dependencies exist before registering a package.
+--
+-- Some commands operate on multiple databases, with overlapping semantics:
+-- list, describe, field
+
+type PackageDBName = FilePath
+type PackageDB = [InstalledPackageInfo]
+
+type PackageDBStack = [(PackageDBName,PackageDB)]
+ -- A stack of package databases. Convention: head is the topmost
+ -- in the stack. Earlier entries override later one.
+
+getPkgDatabases :: Bool -> [Flag] -> IO PackageDBStack
+getPkgDatabases modify flags = do
+ -- first we determine the location of the global package config. On Windows,
+ -- this is found relative to the ghc-pkg.exe binary, whereas on Unix the
+ -- location is passed to the binary using the --global-config flag by the
+ -- wrapper script.
+ let err_msg = "missing --global-conf option, location of global package.conf unknown\n"
+ global_conf <-
+ case [ f | FlagGlobalConfig f <- flags ] of
+ [] -> do mb_dir <- getExecDir "/bin/ghc-pkg.exe"
+ case mb_dir of
+ Nothing -> die err_msg
+ Just dir -> return (dir `joinFileName` "package.conf")
+ fs -> return (last fs)
+
+ -- get the location of the user package database, and create it if necessary
+ appdir <- getAppUserDataDirectory "ghc"
+
+ let
+ subdir = targetARCH ++ '-':targetOS ++ '-':version
+ archdir = appdir `joinFileName` subdir
+ user_conf = archdir `joinFileName` "package.conf"
+ b <- doesFileExist user_conf
+ when (not b) $ do
+ putStrLn ("Creating user package database in " ++ user_conf)
+ createDirectoryIfMissing True archdir
+ writeFile user_conf emptyPackageConfig
+
+ let
+ -- The semantics here are slightly strange. If we are
+ -- *modifying* the database, then the default is to modify
+ -- the global database by default, unless you say --user.
+ -- If we are not modifying (eg. list, describe etc.) then
+ -- the user database is included by default.
+ databases
+ | modify = foldl addDB [global_conf] flags
+ | otherwise = foldl addDB [user_conf,global_conf] flags
+
+ -- implement the following rules:
+ -- --user means overlap with the user database
+ -- --global means reset to just the global database
+ -- -f <file> means overlap with <file>
+ addDB dbs FlagUser = if user_conf `elem` dbs
+ then dbs
+ else user_conf : dbs
+ addDB dbs FlagGlobal = [global_conf]
+ addDB dbs (FlagConfig f) = f : dbs
+ addDB dbs _ = dbs
+
+ db_stack <- mapM readParseDatabase databases
+ return db_stack
+
+readParseDatabase :: PackageDBName -> IO (PackageDBName,PackageDB)
+readParseDatabase filename = do
+ str <- readFile filename
+ let packages = read str
+ Exception.evaluate packages
+ `Exception.catch` \_ ->
+ die (filename ++ ": parse error in package config file")
+ return (filename,packages)
+
+emptyPackageConfig :: String
+emptyPackageConfig = "[]"
+
+-- -----------------------------------------------------------------------------
+-- Registering
+
+registerPackage :: FilePath
+ -> [(String,String)] -- defines, ToDo: maybe remove?
+ -> [Flag]
+ -> Bool -- auto_ghci_libs
+ -> Bool -- update
+ -> Bool -- force
+ -> IO ()
+registerPackage input defines flags auto_ghci_libs update force = do
+ db_stack <- getPkgDatabases True flags
+ let
+ db_to_operate_on = my_head "db" db_stack
+ db_filename = fst db_to_operate_on
+ --
+ checkConfigAccess db_filename