Commit 05d3f0d0 authored by Michael Hanus's avatar Michael Hanus
Browse files

CPM update

parent afa166f5
......@@ -95,6 +95,13 @@ using UTF-8 encoding by default. Haskell uses the system locale charmap for its
default encoding. You can check the current value using
\code{System.IO.localeEncoding} inside a \code{ghci} session.
It is also recommended that
SQLite\footnote{\url{https://www.sqlite.org}} is installed
so that the executable \code{sqlite3} is in your path.
In this case, CPM uses a SQLite database for caching
the central package index (see Section~\ref{sec:internals}).
This yields faster response times of various CPM commands.
To install CPM from the sources, enter the
root directory of the CPM source distribution.
The main executable \code{curry} of your Curry system must be in your
......@@ -220,7 +227,7 @@ creates a new project directory with a
\code{package.json} file for you.\footnote{The \code{new} command
also creates some other useful template files. Look into the
output of this command.}
Declare a dependency inside the new \code{package.json} file, e.g.:
Then declare the dependencies inside the new \code{package.json} file, e.g.:
\begin{lstlisting}
{
......@@ -347,23 +354,34 @@ This command will set the \code{CURRYPATH} environment variable
and then execute the command given after \ccode{exec}.
\subsection{Using Packages Without a Package}
\subsection{Using Packages Outside a Package}
\label{sec:meta-package}
In principle, packages can be used only inside another package
by declaring dependencies.
Thus, if you develop a Curry application which is not a package
but you want to use some package, you have to put
a package specification file into the source directory of
your application where you define the required packages.
As a shortcut for this, you can use the CPM command
\code{cypm add --dependency} (short: \code{cypm add -d})
to install the package specification file.
by declaring dependencies in the package specification file
\code{package.json}.
If you invoke \code{cypm} in a directory which contains
no package specification file, CPM searches for such a file
from the current directory to the parent directories (up to the
root of the file system).
Thus, if you are outside a package, such a file is not available.
In order to support the use other packages outside package,
CPM provides a meta-package which is usually stored in your home directory
at \code{\char126/.cpm/$Curry system$-homepackage}.\footnote{%
Use \code{cypm config} and look at \code{HOME_PACKAGE_PATH}
to see the current location of this meta-package.}
This meta-package is used when your are not inside another package.
Hence, if you write some Curry program which is not a package
but you want to use some package \code{P}, you have to add a dependency
to \code{P} to this meta-package.
CPM does this automatically for you with the CPM command
\code{cypm add --dependency} (short: \code{cypm add -d}).
For instance, to use the libraries of the JSON package
in your application, one can use the following commands:
%
\begin{lstlisting}
> cypm add -d json # generate package specification with 'json' dependency
> cypm add -d json # add 'json' dependency to meta-package
> cypm install # download and install all dependencies
> cypm curry # start Curry system with JSON libraries in load path
...
......@@ -634,11 +652,34 @@ The path to the package cache where packages are checked out if only
their binaries are installed (see Section~\ref{sec:installapp}).
Default value: \code{\$HOME/.cpm/app_packages}.
\item[\fbox{\code{HOME_PACKAGE_PATH}}]
The path to the meta-package which is used if you are outside another
package (see Section~\ref{sec:meta-package}).
Default value: \code{\$HOME/.cpm/$Curry system$-homepackage}.
\item[\fbox{\code{CURRY_BIN}}]
The name of the executable of the Curry system used
to compile and test packages.
The default value is the binary of the Curry system which has been used
to compile CPM.
\item[\fbox{\code{BASE_VERSION}}]
The version of the base libraries which is used for package installations.
In the default case, the base version is the version of the system libraries
used by the Curry compiler. These system libraries are also available
as package \ccode{base} so that they can listed as a dependency
in the package specification.
If the base version of the package is identical to the base version
of the Curry compiler used by CPM, the installed copy
of the base libraries is ignored.\footnote{Since the system libraries
of a Curry compiler are usually pre-compiled, the usage of the
system libraries instead of the \code{base} package might result
in faster compilation times.}
If one uses a different base version, e.g., enforced by a package
dependency or by setting this configuration variable,
then this version of the base package is used.
Thus, one can use a package even if the current compiler
has a different version of the base libraries.
\end{description}
%
Note that one write the option names also in lowercase or omit
......@@ -947,11 +988,11 @@ The option \ccode{--force} allows to overwrite existing copies
in the central package index.
\item[\fbox{\code{add --dependency $package$ [--force]}}]
Adds the package $package$ as a new dependency of the current package.
This command either modifies the package description file (\code{package.json})
of the current package and adds a dependency to the given package
in this file or, if there is no package description file,
generates a new one with this dependency.
Adds the package $package$ as a new dependency.
This command adds a dependency to the given package
either in the package description file (\code{package.json})
of the current package or in the meta-package
(see Section~\ref{sec:meta-package}).
The option \ccode{--force} allows to overwrite existing dependencies
in the package description file.
......
......@@ -12,17 +12,17 @@ module CPM.AbstractCurry
, applyModuleRenames
) where
import Distribution (FrontendTarget (..), FrontendParams (..), defaultParams
import Distribution ( FrontendTarget (..), FrontendParams (..), defaultParams
, callFrontendWithParams, setQuiet, setFullPath
, sysLibPath, inCurrySubdir, modNameToPath
, inCurrySubdirModule, lookupModuleSource)
import List (intercalate, nub)
import FilePath ((</>), (<.>), takeFileName, replaceExtension)
import AbstractCurry.Files (readAbstractCurryFile, writeAbstractCurryFile)
import AbstractCurry.Pretty (showCProg)
import AbstractCurry.Select (imports)
, inCurrySubdirModule, lookupModuleSource )
import List ( intercalate, nub )
import FilePath ( (</>), (<.>), takeFileName, replaceExtension )
import AbstractCurry.Files ( readAbstractCurryFile, writeAbstractCurryFile )
import AbstractCurry.Pretty ( showCProg )
import AbstractCurry.Select ( imports )
import AbstractCurry.Transform
import AbstractCurry.Types (CurryProg)
import AbstractCurry.Types
import System
import CPM.ErrorLogger
......@@ -62,7 +62,7 @@ readAbstractCurryFromPackagePath :: Package -> String -> [Package] -> String
readAbstractCurryFromPackagePath pkg pkgDir deps modname = do
let loadPath = fullLoadPathForPackage pkg pkgDir deps
params <- return $ setQuiet True (setFullPath loadPath defaultParams)
callFrontendWithParams ACY params modname
callFrontendWithParams ACY params modname
src <- lookupModuleSource loadPath modname
acyName <- return $ case src of
Nothing -> error $ "Module not found: " ++ modname
......@@ -77,14 +77,7 @@ readAbstractCurryFromPackagePath pkg pkgDir deps modname = do
readAbstractCurryFromDeps :: String -> [Package] -> String -> IO CurryProg
readAbstractCurryFromDeps pkgDir deps modname = do
pkg <- fromErrorLogger (loadPackageSpec pkgDir)
let loadPath = fullLoadPathForPackage pkg pkgDir deps
params <- return $ setQuiet True (setFullPath loadPath defaultParams)
src <- lookupModuleSource loadPath modname
sourceFile <- return $ case src of
Nothing -> error $ "Module not found: " ++ modname
Just (_, file) -> replaceExtension (inCurrySubdirModule modname file) ".acy"
callFrontendWithParams ACY params modname
readAbstractCurryFile sourceFile
readAbstractCurryFromPackagePath pkg pkgDir deps modname
--- Applies a transformation function to a module from a package or one of its
--- dependencies and writes the modified module to a file in Curry form.
......@@ -94,18 +87,10 @@ readAbstractCurryFromDeps pkgDir deps modname = do
--- @param f - the transformation function
--- @param mod - the module to transform
--- @param dest - the destination file for the transformed module
transformAbstractCurryInDeps :: String -> [Package] -> (CurryProg -> CurryProg)
transformAbstractCurryInDeps :: String -> [Package] -> (CurryProg -> CurryProg)
-> String -> String -> IO ()
transformAbstractCurryInDeps pkgDir deps transform modname destFile = do
pkg <- fromErrorLogger (loadPackageSpec pkgDir)
let loadPath = fullLoadPathForPackage pkg pkgDir deps
params <- return $ setQuiet True (setFullPath loadPath defaultParams)
src <- lookupModuleSource loadPath modname
sourceFile <- return $ case src of
Nothing -> error $ "Module not found: " ++ modname
Just (_, file) -> replaceExtension (inCurrySubdirModule modname file) ".acy"
callFrontendWithParams ACY params modname
acy <- readAbstractCurryFile sourceFile
acy <- readAbstractCurryFromDeps pkgDir deps modname
writeFile destFile $ showCProg (transform acy)
--- Renames all references to some modules in a Curry program.
......
......@@ -6,15 +6,15 @@
module CPM.Config
( Config ( Config, packageInstallDir, binInstallDir, repositoryDir
, appPackageDir, packageIndexRepository, curryExec
, compilerVersion )
, appPackageDir, packageIndexRepository, homePackageDir, curryExec
, compilerVersion, compilerBaseVersion, baseVersion )
, readConfigurationWith, defaultConfig
, showConfiguration, showCompilerVersion ) where
import Char ( toUpper )
import Directory ( getHomeDirectory, createDirectoryIfMissing )
import Distribution ( installDir, curryCompiler, curryCompilerMinorVersion
, curryCompilerMajorVersion )
import Directory ( doesDirectoryExist, createDirectoryIfMissing
, getHomeDirectory )
import qualified Distribution as Dist
import FilePath ( (</>), isAbsolute )
import Function ( (***) )
import IOExts ( evalCmd )
......@@ -46,12 +46,23 @@ data Config = Config {
, appPackageDir :: String
--- URL to the package index repository
, packageIndexRepository :: String
--- The directory where the default home package is stored
, homePackageDir :: String
--- The executable of the Curry system used to compile and check packages
, curryExec :: String
--- The compiler version (name,major,minor) used to compile packages
, compilerVersion :: (String,Int,Int)
--- The version of the base libraries used by the compiler
, compilerBaseVersion :: String
--- The version of the base libraries to be used for package installations
, baseVersion :: String
}
--- Workaround since Distribution.baseVersion is not defined in Curry
--- without typeclasses.
distBaseVersion :: String
distBaseVersion = "0.0.0"
--- CPM's default configuration values. These are used if no .cpmrc file is found
--- or a new value for the option is not specified in the .cpmrc file.
defaultConfig :: Config
......@@ -61,21 +72,27 @@ defaultConfig = Config
, repositoryDir = "$HOME/.cpm/index"
, appPackageDir = "$HOME/.cpm/app_packages"
, packageIndexRepository = packageIndexURI
, curryExec = installDir </> "bin" </> curryCompiler
, compilerVersion = (curryCompiler, curryCompilerMajorVersion,
curryCompilerMinorVersion)
, homePackageDir = ""
, curryExec = Dist.installDir </> "bin" </> Dist.curryCompiler
, compilerVersion = ( Dist.curryCompiler
, Dist.curryCompilerMajorVersion
, Dist.curryCompilerMinorVersion )
, compilerBaseVersion = distBaseVersion
, baseVersion = ""
}
--- Shows the configuration.
showConfiguration :: Config -> String
showConfiguration cfg = unlines
[ "Current configuration:"
, "Compiler version : " ++ showCompilerVersion cfg
, "CURRYBIN : " ++ curryExec cfg
, "REPOSITORYPATH : " ++ repositoryDir cfg
, "PACKAGEINSTALLPATH: " ++ packageInstallDir cfg
, "BININSTALLPATH : " ++ binInstallDir cfg
, "APPPACKAGEPATH : " ++ appPackageDir cfg
[ "Compiler version : " ++ showCompilerVersion cfg
, "Compiler base version : " ++ compilerBaseVersion cfg
, "BASE_VERSION : " ++ baseVersion cfg
, "CURRY_BIN : " ++ curryExec cfg
, "REPOSITORY_PATH : " ++ repositoryDir cfg
, "PACKAGE_INSTALL_PATH : " ++ packageInstallDir cfg
, "BIN_INSTALL_PATH : " ++ binInstallDir cfg
, "APP_PACKAGE_PATH : " ++ appPackageDir cfg
, "HOME_PACKAGE_PATH : " ++ homePackageDir cfg
]
--- Shows the compiler version in the configuration.
......@@ -100,25 +117,64 @@ setCompilerExecutable cfg = do
maybe (error $ "Executable '" ++ exec ++ "' not found in path!")
(\absexec -> return cfg { curryExec = absexec })
--- Sets the `homePackageDir` depending on the compiler version.
setHomePackageDir :: Config -> IO Config
setHomePackageDir cfg
| null (homePackageDir cfg)
= do homedir <- getHomeDirectory
let cpmdir = homedir </> ".cpm"
excpmdir <- doesDirectoryExist cpmdir
if excpmdir
then let (cname,cmaj,cmin) = compilerVersion cfg
cvname = cname ++ "-" ++ show cmaj ++ "." ++ show cmin
homepkgdir = cpmdir </> cvname ++ "-homepackage"
in return cfg { homePackageDir = homepkgdir }
else return cfg
| otherwise = return cfg
--- Sets the correct compiler version in the configuration.
setCompilerVersion :: Config -> IO Config
setCompilerVersion cfg0 = do
cfg <- setCompilerExecutable cfg0
if curryExec cfg == installDir </> "bin" </> curryCompiler
then return cfg { compilerVersion = currVersion }
else do (c1,sname,e1) <- evalCmd (curryExec cfg) ["--compiler-name"] ""
(c2,svers,e2) <- evalCmd (curryExec cfg) ["--numeric-version"] ""
when (c1 > 0 || c2 > 0) $
error $ "Cannot determine compiler version:\n" ++
unlines (filter (not . null) [e1,e2])
let initbase = baseVersion cfg
if curryExec cfg == Dist.installDir </> "bin" </> Dist.curryCompiler
then return cfg { compilerVersion = currVersion
, compilerBaseVersion = distBaseVersion
, baseVersion = if null initbase
then distBaseVersion
else initbase }
else do (sname,svers,sbver) <- getCompilerVersion (curryExec cfg)
let cname = strip sname
cvers = strip svers
bvers = strip sbver
(majs:mins:_) = split (=='.') cvers
debugMessage $ "Compiler version: " ++ cname ++ " " ++ cvers
return cfg { compilerVersion = (cname, readInt majs, readInt mins) }
debugMessage $ "Base lib version: " ++ bvers
return cfg { compilerVersion = (cname, readInt majs, readInt mins)
, compilerBaseVersion = bvers
, baseVersion = if null initbase
then bvers
else initbase }
where
currVersion = (curryCompiler, curryCompilerMajorVersion,
curryCompilerMinorVersion)
getCompilerVersion currybin = do
debugMessage $ "Getting version information from " ++ currybin
(r,s,e) <- evalCmd currybin
["--compiler-name","--numeric-version","--base-version"] ""
if r>0
then error $ "Cannot determine compiler version:\n" ++ e
else case lines s of
[sname,svers,sbver] -> return (sname,svers,sbver)
_ -> do debugMessage $ "Query version information again..."
(c1,sname,e1) <- evalCmd currybin ["--compiler-name"] ""
(c2,svers,e2) <- evalCmd currybin ["--numeric-version"] ""
(c3,sbver,e3) <- evalCmd currybin ["--base-version"] ""
when (c1 > 0 || c2 > 0 || c3 > 0) $
error $ "Cannot determine compiler version:\n" ++
unlines (filter (not . null) [e1,e2,e3])
return (sname,svers,sbver)
currVersion = (Dist.curryCompiler, Dist.curryCompilerMajorVersion,
Dist.curryCompilerMinorVersion)
--- Reads the .cpmrc file from the user's home directory (if present) and
--- merges its contents and some given default settings (first argument)
......@@ -140,7 +196,8 @@ readConfigurationWith defsettings = do
Right s0 -> do s1 <- replaceHome s0
createDirectories s1
s2 <- setCompilerVersion s1
return $ Right s2
s3 <- setHomePackageDir s2
return $ Right s3
replaceHome :: Config -> IO Config
replaceHome cfg = do
......@@ -191,7 +248,9 @@ keySetters =
, ("PACKAGEINSTALLPATH" , \v c -> c { packageInstallDir = v })
, ("BININSTALLPATH" , \v c -> c { binInstallDir = v })
, ("APPPACKAGEPATH" , \v c -> c { appPackageDir = v })
, ("HOMEPACKAGEPATH" , \v c -> c { homePackageDir = v })
, ("CURRYBIN" , \v c -> c { curryExec = v })
, ("BASEVERSION" , \v c -> c { baseVersion = v })
]
--- Sequentially applies a list of functions that transform a value to a value
......
......@@ -17,14 +17,15 @@ module CPM.ErrorLogger
, failIO
, log
, showLogEntry
, infoMessage, debugMessage, fromErrorLogger
, infoMessage, debugMessage, errorMessage, fromErrorLogger
, showExecCmd, execQuietCmd
) where
import Global
import IO ( hPutStrLn, stderr )
import Pretty
import Profile -- for show run-time
import System (exitWith, system)
import System ( exitWith, system )
infixl 0 |>=, |>, |>>, |->
......@@ -133,12 +134,13 @@ foldEL f z (x:xs) = do
Right v -> foldEL f v xs
Left m -> return $ ([], Left m)
--- Renders a log entry.
--- Renders a log entry to stderr.
showLogEntry :: LogEntry -> IO ()
showLogEntry (LogEntry lvl msg) = do
minLevel <- getLogLevel
if levelGte lvl minLevel
then putStrLn $ pPrint $ lvlText <+> (text msg)
then mapIO_ (\l -> hPutStrLn stderr $ pPrint $ lvlText <+> text l)
(lines msg)
else return ()
where
lvlText = case lvl of
......@@ -213,6 +215,10 @@ infoMessage msg = (log Info msg |> succeedIO ()) >> done
debugMessage :: String -> IO ()
debugMessage msg = (log Debug msg |> succeedIO ()) >> done
--- Prints an error message in the standard IO monad.
errorMessage :: String -> IO ()
errorMessage msg = (log Error msg |> succeedIO ()) >> done
--- Transforms an error logger actions into a standard IO action.
--- It shows all messages and, if the result is not available,
--- exits with a non-zero code.
......
......@@ -18,7 +18,7 @@ module CPM.FileUtil
, inDirectory
, recreateDirectory
, removeDirectoryComplete
, safeReadFile, checkAndGetDirectoryContents
, safeReadFile, checkAndGetVisibleDirectoryContents
, whenFileExists, ifFileExists
) where
......@@ -29,7 +29,7 @@ import Directory ( doesFileExist, doesDirectoryExist, getCurrentDirectory
import System ( system, getEnviron, exitWith )
import IOExts ( evalCmd, readCompleteFile )
import FilePath ( FilePath, replaceFileName, (</>), searchPathSeparator )
import List ( intercalate, splitOn )
import List ( intercalate, isPrefixOf, splitOn )
--- Joins a list of directories into a search path.
joinSearchPath :: [FilePath] -> String
......@@ -158,6 +158,13 @@ checkAndGetDirectoryContents dir = do
else do putStrLn $ "ERROR: Directory '" ++ dir ++ "' does not exist!"
exitWith 1
--- Returns the list of all visible entries in a directory (i.e., not starting
--- with '.') and terminates with an error message if the directory
--- does not exist.
checkAndGetVisibleDirectoryContents :: FilePath -> IO [FilePath]
checkAndGetVisibleDirectoryContents dir =
checkAndGetDirectoryContents dir >>= return . filter (not . isPrefixOf ".")
--- Performs an action when a file exists.
whenFileExists :: FilePath -> IO () -> IO ()
whenFileExists fname act = do
......
This diff is collapsed.
......@@ -6,7 +6,6 @@
module CPM.Package
( Version, initialVersion
, Dependency
, VersionConstraint (..)
, CompilerCompatibility (..)
, Package (..), emptyPackage
......@@ -439,12 +438,12 @@ showVersionConstraints =
--- Renders a single version constraint as a string.
showVersionConstraint :: VersionConstraint -> String
showVersionConstraint (VLt v) = " < " ++ (showVersion v)
showVersionConstraint (VLte v) = " <= " ++ (showVersion v)
showVersionConstraint (VGt v) = " > " ++ (showVersion v)
showVersionConstraint (VGte v) = " >= " ++ (showVersion v)
showVersionConstraint (VExact v) = " = " ++ (showVersion v)
showVersionConstraint (VCompatible v) = " ~> " ++ (showVersion v)
showVersionConstraint (VLt v) = " < " ++ showVersion v
showVersionConstraint (VLte v) = " <= " ++ showVersion v
showVersionConstraint (VGt v) = " > " ++ showVersion v
showVersionConstraint (VGte v) = " >= " ++ showVersion v
showVersionConstraint (VExact v) = " = " ++ showVersion v
showVersionConstraint (VCompatible v) = " ~> " ++ showVersion v
--- Renders the id of a package as a string. Package name and version separated
--- by a dash.
......
......@@ -8,7 +8,7 @@ module CPM.Package.Helpers
( installPackageSourceTo
, renderPackageInfo
, cleanPackage
, getLocalPackageSpec, searchLocalPackageSpec
, getLocalPackageSpec
) where
import Directory
......@@ -17,6 +17,7 @@ import FilePath
import List ( splitOn, nub )
import Pretty hiding ((</>))
import CPM.Config ( Config, homePackageDir )
import CPM.ErrorLogger
import CPM.FileUtil ( inDirectory, inTempDir, quote
, removeDirectoryComplete, tempDir, whenFileExists )
......@@ -112,10 +113,10 @@ checkoutGitRef dir ref = do
------------------------------------------------------------------------------
--- Cleans auxiliary files in the local package, i.e., the package
--- containing the current working directory.
cleanPackage :: LogLevel -> IO (ErrorLogger ())
cleanPackage ll =
getLocalPackageSpec "." |>= \specDir ->
loadPackageSpec specDir |>= \pkg ->
cleanPackage :: Config -> LogLevel -> IO (ErrorLogger ())
cleanPackage cfg ll =
getLocalPackageSpec cfg "." |>= \specDir ->
loadPackageSpec specDir |>= \pkg ->
let dotcpm = specDir </> ".cpm"
srcdirs = map (specDir </>) (sourceDirsOf pkg)
testdirs = map (specDir </>)
......@@ -128,13 +129,13 @@ cleanPackage ll =
------------------------------------------------------------------------------
--- Renders information about a package.
renderPackageInfo :: Bool -> Bool -> Maybe Bool -> Package -> String
renderPackageInfo allinfos plain mbinstalled pkg = pPrint doc
renderPackageInfo :: Bool -> Bool -> Bool -> Package -> String
renderPackageInfo allinfos plain installed pkg = pPrint doc
where
boldText s = (if plain then id else bold) $ text s
maxLen = 12
doc = vcat $ [ heading, rule
, maybe empty instTxt mbinstalled
, if allinfos then instTxt installed else empty
, ver, auth, maintnr, synop
, cats, deps, compilers, descr, execspec ] ++
if allinfos
......@@ -255,25 +256,47 @@ renderPackageInfo allinfos plain mbinstalled pkg = pPrint doc
indent 4 (fillSep (map text (words s)))
------------------------------------------------------------------------------
--- Tries to find a package specification in the current directory or one of its
--- ancestors.
getLocalPackageSpec :: String -> IO (ErrorLogger String)
getLocalPackageSpec dir =
searchLocalPackageSpec dir |>=
maybe (failIO "No package.json found") succeedIO
--- Tries to find a package specification in the given directory or one of its
--- ancestors. If there is no package specifiction in these directories,
--- the home package specification (i.e., `~/.cpm/home-package/package.json`
--- is returned (and created if it does not exist).
--- In order to avoid infinite loops due to cyclic file structures,
--- the search is limited to the number of directories occurring in the
--- current absolute path.
getLocalPackageSpec :: Config -> String -> IO (ErrorLogger String)
getLocalPackageSpec cfg dir = do
adir <- getAbsolutePath dir
searchLocalSpec (length (splitPath adir)) dir
>>= maybe returnHomePackage succeedIO
where
returnHomePackage = do
let homepkgdir = homePackageDir cfg
homepkgspec = homepkgdir </> "package.json"
specexists <- doesFileExist homepkgspec
unless (specexists || null homepkgdir) $ do
createDirectoryIfMissing True homepkgdir
let newpkg = emptyPackage
{ name = snd (splitFileName homepkgdir)
, version = initialVersion
, author = "CPM"
, synopsis = "Default home package"
, dependencies = []
}
writePackageSpec newpkg homepkgspec
infoMessage $ "New empty package specification '" ++ homepkgspec ++
"' generated"
succeedIO homepkgdir
--- Tries to find a package specification in the current directory or one of its
--- ancestors. Returns `Nothing` if there is not package specifiction.
searchLocalPackageSpec :: String -> IO (ErrorLogger (Maybe String))
searchLocalPackageSpec dir = do
existsLocal <- doesFileExist $ dir </> "package.json"
if existsLocal
then succeedIO (Just dir)
else log Debug ("No package.json in " ++ show dir ++ ", trying " ++
show (dir </> "..")) |> do
parentExists <- doesDirectoryExist $ dir </> ".."
if parentExists
then searchLocalPackageSpec $ dir </> ".."
else succeedIO Nothing
searchLocalSpec m sdir = do
existsLocal <- doesFileExist $ sdir </> "package.json"
if existsLocal
then return (Just sdir)
else do
debugMessage ("No package.json in " ++ show sdir ++ ", trying " ++
show (sdir </> ".."))
parentExists <- doesDirectoryExist $ sdir </> ".."
if m>0 && parentExists
then searchLocalSpec (m-1) $ sdir </> ".."
else return Nothing
------------------------------------------------------------------------------
......@@ -8,9 +8,9 @@ module CPM.PackageCache.Global
, findAllVersions
, findNewestVersion
, findVersion
, isPackageInstalled
, packageInstalled
, installedPackageDir
, readInstalledPackagesFromDir
, readGlobalCache, readInstalledPackagesFromDir
, allPackages
, copyPackage
, installMissingDependencies
......@@ -34,7 +34,7 @@ import CPM.Config ( Config, packageInstallDir )
import CPM.ErrorLogger
import CPM.FileUtil ( copyDirectory, inTempDir, recreateDirectory, inDirectory
, removeDirectoryComplete, tempDir, whenFileExists
, checkAndGetDirectoryContents, quote )
, checkAndGetVisibleDirectoryContents, quote )
import CPM.Package
import CPM.Package.Helpers ( installPackageSourceTo )
import CPM.Repository
......@@ -92,10 +92,12 @@ isPackageInstalled db p = isJust $ findVersion db (name p) (version p)
--- The directory of a package in the global package cache. Does not check
--- whether the package is actually installed!
installedPackageDir :: Config -> Package -> String
installedPackageDir cfg pkg =
base </> (name pkg ++ "-" ++ (showVersion $ version pkg))
where
base = packageInstallDir cfg
installedPackageDir cfg pkg = packageInstallDir cfg </> packageId pkg
--- Checks whether a package is installed in the global cache.
packageInstalled :: Config -> Package -> IO Bool
packageInstalled cfg pkg =
doesDirectoryExist (installedPackageDir cfg pkg)
--- Copy a package version to a directory.
copyPackage :: Config -> Package -> String -> IO (ErrorLogger ())
......@@ -110,7 +112,8 @@ copyPackage cfg pkg dir = do
--- Acquires a package from the source specified in its specification and
--- installs it to the global package cache.
acquireAndInstallPackage :: Config -> Package -> IO (ErrorLogger ())
acquireAndInstallPackage cfg pkg =
acquireAndInstallPackage cfg reppkg =
readPackageFromRepository cfg reppkg |>= \pkg ->
case source pkg of
Nothing -> failIO $ "No source specified for " ++ packageId pkg
Just s -> log Info ("Installing package '" ++ packageId pkg ++ "'...") |>
......@@ -163,9 +166,9 @@ missingPackages :: GlobalCache -> [Package] -> [Package]
missingPackages gc = filter (not . isPackageInstalled gc)
--- Checkout a package from the global package cache.
checkoutPackage :: Config -> Repository -> GlobalCache -> Package
checkoutPackage :: Config -> Package
-> IO (ErrorLogger ())
checkoutPackage cfg _ _ pkg = do
checkoutPackage cfg pkg = do
sexists <- doesDirectoryExist pkgDir
texists <- doesDirectoryExist codir
if texists
......@@ -175,22 +178,21 @@ checkoutPackage cfg _ _ pkg = do
else log Error $ "Package '" ++ pkgId ++ "' is not installed."
where
pkgId = packageId pkg
pkgDir = packageInstallDir cfg </> pkgId