Commit 5a668b2e authored by Michael Hanus 's avatar Michael Hanus
Browse files

CPM updated

parent d7c05784
......@@ -52,19 +52,40 @@
\maketitle
\begin{abstract}
\tableofcontents
\clearpage
\section{Introduction}
This document describes the Curry package manager (CPM), a tool to
distribute and install Curry libraries and manage version dependencies
between these libraries.
\end{abstract}
A distinguishing feature of CPM is its ability to perform
\emph{semantic versioning checking}, i.e., CPM provides a command
to check the semantics of a new package version against an
older version of the same package.
\bigskip\bigskip
\section{Installing the Curry Package Manager}
To install and use CPM, a working installation of either the
CPM is part of recent distributions of the Curry systems
PAKCS\footnote{\url{https://www.informatik.uni-kiel.de/~pakcs/}}
compiler in version 1.14.1 or greater, or the
(since version 1.15.0)
and
KiCS2\footnote{\url{https://www-ps.informatik.uni-kiel.de/kics2/}}
compiler in version 0.5.1 or greater is required. Additionally, CPM requires
(since version 0.6.0).
If you use an older release of PAKCS or KiCS2 or you want to
install the most recent CPM version from the source repository,
this section contains some hints about the installation of CPM.
To install and use CPM, a working installation of either
PAKCS in version 1.14.1 or greater, or
KiCS2 in version 0.5.1 or greater is required. Additionally, CPM requires
\emph{Git}\footnote{\url{http://www.git-scm.com}},
\emph{curl}\footnote{\url{https://curl.haxx.se}}
and \emph{unzip} to be available on the \code{PATH} during installation and
......@@ -82,8 +103,46 @@ Then type \code{make} to compile CPM which generates
a binary called \code{cpm} in the \code{bin} subdirectory. Put
this binary somewhere on your path.
Afterwards, run \code{cpm update} to pull down a copy of the central package
index to your system.
\clearpage
\section{Starting the Curry Package Manager}
If the binary \code{cpm} is on your path, execute the command
%
\begin{lstlisting}
> cpm update
\end{lstlisting}
%
to pull down a copy of the central package index to your system.
You can use the same command to update later
your copy of the central package index to the newest version.
Afterwards, you can show a short list of all packages in this index by
%
\begin{lstlisting}
> cpm list
\end{lstlisting}
%
The command
%
\begin{lstlisting}
> cpm info PACKAGE
\end{lstlisting}
%
can be used to show more information about a package.
There is also a command
%
\begin{lstlisting}
> cpm search QUERY
\end{lstlisting}
%
to search inside the central package index.
Section~\ref{sec:cmd-reference} contains a complete list of all
available CPM commands.
\clearpage
\section{Package Basics}
\label{sec:package-basics}
......@@ -139,6 +198,8 @@ $\geq 2.0.0, < 3.0.0 || \geq 4.0.0$ would match any version within major version
$2$ and from major version $4$ onwards, but no version within major version $3$.
\clearpage
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Using Packages}
......@@ -187,14 +248,6 @@ installed on previous runs of \code{cpm install}, you can use the
compatible versions, or \code{cpm upgrade <package>} to update a specific
package and all its transitive dependencies to the newest compatible version.
Note that there is also a \code{cpm update} command, which will update
your copy of the central package index to the newest version. You can
list all packages of the central package index via the
\code{cpm list} command, or you can
search the central package index via the \code{cpm search}
command. See Section~\ref{sec:cmd-reference} for a reference of all
commands.
If the package also contains an implementation of a complete executable,
e.g., some useful tool,
which can be specifed in the \code{package.json} file
......@@ -268,18 +321,18 @@ if \code{\$HOME/.cpm/bin} is in your path
of this default path).
\subsection{Executing the Curry Compiler}
\subsection{Executing the Curry System in a Package}
To use the dependencies of a package, the Curry compiler needs to be
started via CPM so that the compiler will know where to search for the
To use the dependencies of a package, the Curry system needs to be
started via CPM so that it will know where to search for the
modules provided. You can use the command \ccode{cpm curry} to start the
Curry compiler (which is either the compiler used to install CPM
Curry system (which is either the compiler used to install CPM
or specified with the configuration option \code{CURRY_BIN},
see Section~\ref{sec:config}).
Any parameters given to \ccode{cpm curry} will be passed along verbatim to
the Curry compiler.
For example, the following will start the Curry
compiler, print the result of evaluating the expression \code{39+3}
the Curry system.
For example, the following will start the Curry system,
print the result of evaluating the expression \code{39+3}
and then quit.
\begin{lstlisting}
......@@ -293,6 +346,31 @@ This command will set the \code{CURRYPATH} environment variable
and then execute the command given after \ccode{exec}.
\subsection{Using Packages Without a 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{cpm add --dependency} (short: \code{cpm add -d})
to install the package specification file.
For instance, to use the libraries of the JSON package
in your application, one can use the following commands:
%
\begin{lstlisting}
> cpm add -d json # generate package specification with 'json' dependency
> cpm install # download and install all dependencies
> cpm curry # start Curry system with JSON libraries in load path
...
Prelude> :load JSON.Data
JSON.Data>
\end{lstlisting}
%
\subsection{Replacing Dependencies with Local Versions}
\label{sec:cpm-link}
......@@ -320,6 +398,9 @@ arguments, which will clear the local package cache. See
Section~\ref{sec:internals} for more information on the global and local package
caches.
\clearpage
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Authoring Packages}
If you want to create packages for other people to use, you should consider
......@@ -446,7 +527,7 @@ when searching for packages. For this purpose, you can use the
\ccode{cpm add} command:
%
\begin{lstlisting}
> cpm add mypackage
> cpm add --package mypackage
\end{lstlisting}
%
In this case, \code{mypackage} is the name of the directory containing
......@@ -522,6 +603,8 @@ specification file to \url{packages@curry-language.org} in order to
publish it.
\clearpage
\section{Configuration}
\label{sec:config}
......@@ -568,6 +651,8 @@ one can execute the command
\end{lstlisting}
\clearpage
\section{Some CPM Internals}
\label{sec:internals}
......@@ -601,6 +686,9 @@ local package cache to the \emph{run-time cache}, which is stored in
copies in the run-time cache, and never those from the local or global package
caches.
\clearpage
\section{Command Reference}
\label{sec:cmd-reference}
......@@ -695,7 +783,7 @@ or by the CPM option \code{--define}, see Section~\ref{sec:config}).
\code{--$pre$} enables the installation of pre-release versions.
\item[\fbox{\code{install $package$ $version$}}]
Install the application provided by a specific version of a package.
Installs the application provided by a specific version of a package.
The binary of the application is installed into the directory
\code{\$HOME/.cpm/bin}
(this location can be changed via the \code{\$HOME/.cpmrc} configuration file
......@@ -836,16 +924,25 @@ Any arguments are passed verbatim to the compiler.
\item[\fbox{\code{link $source$}}] Can be used to replace a dependency of the
current package using a local copy, see Section~\ref{sec:cpm-link} for details.
\item[\fbox{\code{add $source$ [--force]}}]
Copies the package contained in $source$ into the local copy
\item[\fbox{\code{add --package $dir$ [--force]}}]
Copies the package contained in directory $dir$ into the local copy
of the central package index so that it can be used by other packages
in the local environment
(see Section~\ref{sec:adding-a-package} for details).
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.
The option \ccode{--force} allows to overwrite existing dependencies
in the package description file.
\item[\fbox{\code{clean}}] Cleans the current package from the
generated auxiliariy files, e.g., intermediate Curry files,
generated auxiliary files, e.g., intermediate Curry files,
installed dependent packages, etc.
Note that a binary installed in the CPM \code{bin} directory
(by the \code{install} command) will not be removed.
......@@ -857,6 +954,8 @@ Creates a new project package with the given name and some template files.
\end{description}
\clearpage
\section{Package Specification Reference}
\label{sec:reference}
......@@ -872,8 +971,11 @@ for semantic versioning version numbers.
\item[\fbox{\code{author*}}] The package's author. This is a free-form field,
the suggested format is either a name or a name followed by an email address in
angle brackets, e.g., \code{John Doe <john@doe.com>}. Multiple authors should
be separated by commas.
angle brackets, e.g.,
\begin{lstlisting}
John Doe <john@doe.com>
\end{lstlisting}
Multiple authors should be separated by commas.
\item[\fbox{\code{maintainer}}] The current maintainers of the package, if
different from the original authors. This field allows the current maintainers
......@@ -881,7 +983,10 @@ to indicate the best person or persons to contact about the package while
attributing the original authors.
The suggested format is a name followed by an email address in
angle brackets, e.g., \code{John Doe <john@doe.com>}.
angle brackets, e.g.,
\begin{lstlisting}
John Doe <john@doe.com>
\end{lstlisting}
Multiple maintainers should be separated by commas.
\item[\fbox{\code{synopsis*}}] A short form summary of the package's purpose.
......@@ -1171,6 +1276,8 @@ are used:
\end{lstlisting}
\clearpage
\section{Error Recovery}
\label{sec:recovery}
......@@ -1203,3 +1310,5 @@ by the command \code{cpm update}.
\end{document}
% LocalWords: CPM versioning
......@@ -10,9 +10,7 @@ module CPM.ErrorLogger
, levelGte
, getLogLevel, setLogLevel
, setWithShowTime
, (|>=)
, (|>)
, (|->)
, (|>=), (|>), (|->), (|>>)
, mapEL
, foldEL
, succeedIO
......@@ -28,8 +26,7 @@ import Pretty
import Profile -- for show run-time
import System (exitWith, system)
infixl 0 |>=
infixl 0 |>
infixl 0 |>=, |>, |>>, |->
--- An error logger.
type ErrorLogger a = ([LogEntry], Either LogEntry a)
......@@ -106,6 +103,11 @@ a |-> b = do
return $ (msgs', err)
Left m -> return $ ([], Left m)
--- Chains a standard IO action (where the result is ignored)
--- with an error logger action.
(|>>) :: IO a -> IO (ErrorLogger b) -> IO (ErrorLogger b)
a |>> b = (a >> succeedIO ()) |> b
--- Maps an action over a list of values. Fails if one of the actions fails.
mapEL :: (a -> IO (ErrorLogger b)) -> [a] -> IO (ErrorLogger [b])
mapEL _ [] = succeedIO []
......
......@@ -47,7 +47,7 @@ cpmBanner :: String
cpmBanner = unlines [bannerLine,bannerText,bannerLine]
where
bannerText =
"Curry Package Manager <curry-language.org/tools/cpm> (version of 17/07/2017)"
"Curry Package Manager <curry-language.org/tools/cpm> (version of 19/09/2017)"
bannerLine = take (length bannerText) (repeat '-')
main :: IO ()
......@@ -194,8 +194,10 @@ data LinkOptions = LinkOptions
{ lnkSource :: String }
data AddOptions = AddOptions
{ addSource :: String
, forceAdd :: Bool
{ addPackage :: Bool
, addDependency :: Bool
, addSource :: String
, forceAdd :: Bool
}
data NewOptions = NewOptions
......@@ -269,7 +271,7 @@ linkOpts s = case optCommand s of
addOpts :: Options -> AddOptions
addOpts s = case optCommand s of
Add opts -> opts
_ -> AddOptions "" False
_ -> AddOptions False False "" False
newOpts :: Options -> NewOptions
newOpts s = case optCommand s of
......@@ -403,7 +405,7 @@ optionParser = optParser
upgradeArgs
<|> command "link" (help "Link a package to the local cache") Right
linkArgs
<|> command "add" (help "Add a package to the local repository") Right
<|> command "add" (help "Add a package (as dependency or to the local repository)") Right
addArgs ) )
where
checkoutArgs cmd =
......@@ -622,14 +624,24 @@ optionParser = optParser
addArgs =
flag (\a -> Right $ a { optCommand =
Add (addOpts a) { addPackage = True } })
( short "p"
<> long "package"
<> help "Add a local package to the local repository" )
<.> flag (\a -> Right $ a { optCommand =
Add (addOpts a) { addDependency = True } })
( short "d"
<> long "dependency"
<> help "Add a dependency to the current package" )
<.> flag (\a -> Right $ a { optCommand =
Add (addOpts a) { forceAdd = True } })
( short "f"
<> long "force"
<> help "Force, i.e., overwrite existing package" )
<.> arg (\s a -> Right $ a { optCommand =
Add (addOpts a) { addSource = s } })
( metavar "SOURCE"
<> help "The directory to add to the local repository" )
( metavar "PACKAGE"
<> help "The package directory or name to be added" )
-- Check if operating system executables we depend on are present on the
-- current system.
......@@ -649,14 +661,14 @@ checkExecutables = do
deps :: Config -> Repository -> GlobalCache -> IO (ErrorLogger ())
deps cfg repo gc =
tryFindLocalPackageSpec "." |>= \specDir ->
getLocalPackageSpec "." |>= \specDir ->
resolveDependencies cfg repo gc specDir |>= \result ->
putStrLn (showResult result) >> succeedIO ()
infoCmd :: InfoOptions -> Config -> Repository -> GlobalCache
-> IO (ErrorLogger ())
-> IO (ErrorLogger ())
infoCmd (InfoOptions Nothing Nothing allinfos plain) _ _ gc =
tryFindLocalPackageSpec "." |>= \specDir ->
getLocalPackageSpec "." |>= \specDir ->
loadPackageSpec specDir |>= printInfo allinfos plain gc
infoCmd (InfoOptions (Just pkg) Nothing allinfos plain) cfg repo gc =
case findLatestVersion cfg repo pkg False of
......@@ -680,7 +692,7 @@ printInfo allinfos plain gc pkg =
compiler :: CompilerOptions -> Config -> IO (Repository,GlobalCache)
-> IO (ErrorLogger ())
compiler o cfg getRepoGC =
tryFindLocalPackageSpec "." |>= \pkgdir ->
getLocalPackageSpec "." |>= \pkgdir ->
loadPackageSpec pkgdir |>= \pkg ->
checkCompiler cfg pkg >>
loadCurryPathFromCache pkgdir |>=
......@@ -722,14 +734,14 @@ checkout (CheckoutOptions pkg (Just ver) _) cfg repo gc =
install :: InstallOptions -> Config -> Repository -> GlobalCache
-> IO (ErrorLogger ())
install (InstallOptions Nothing Nothing _ instexec False) cfg repo gc =
tryFindLocalPackageSpec "." |>= \pkgdir ->
getLocalPackageSpec "." |>= \pkgdir ->
cleanCurryPathCache pkgdir |>
installLocalDependencies cfg repo gc pkgdir |>= \ (pkg,_) ->
writePackageConfig cfg pkgdir pkg |>
if instexec then installExecutable cfg repo pkg else succeedIO ()
-- Install executable only:
install (InstallOptions Nothing Nothing _ _ True) cfg repo _ =
tryFindLocalPackageSpec "." |>= \pkgdir ->
getLocalPackageSpec "." |>= \pkgdir ->
loadPackageSpec pkgdir |>= \pkg ->
installExecutable cfg repo pkg
install (InstallOptions (Just pkg) vers pre _ _) cfg repo gc = do
......@@ -836,7 +848,7 @@ uninstall (UninstallOptions (Just pkgname) Nothing) cfg _ = do
uninstall (UninstallOptions Nothing (Just _)) _ _ =
log Error "Please provide a package and version number!"
uninstall (UninstallOptions Nothing Nothing) cfg _ =
tryFindLocalPackageSpec "." |>= \pkgdir ->
getLocalPackageSpec "." |>= \pkgdir ->
loadPackageSpec pkgdir |>= uninstallPackageExecutable cfg
uninstallPackageExecutable :: Config -> Package -> IO (ErrorLogger ())
......@@ -949,12 +961,12 @@ searchCmd (SearchOptions q smod sexec) cfg repo =
upgrade :: UpgradeOptions -> Config -> Repository -> GlobalCache
-> IO (ErrorLogger ())
upgrade (UpgradeOptions Nothing) cfg repo gc =
tryFindLocalPackageSpec "." |>= \specDir ->
getLocalPackageSpec "." |>= \specDir ->
cleanCurryPathCache specDir |>
log Info "Upgrading all packages" |>
upgradeAllPackages cfg repo gc specDir
upgrade (UpgradeOptions (Just pkg)) cfg repo gc =
tryFindLocalPackageSpec "." |>= \specDir ->
getLocalPackageSpec "." |>= \specDir ->
log Info ("Upgrade " ++ pkg) |>
upgradeSinglePackage cfg repo gc specDir pkg
......@@ -962,7 +974,7 @@ upgrade (UpgradeOptions (Just pkg)) cfg repo gc =
--- `link` command.
linkCmd :: LinkOptions -> Config -> IO (ErrorLogger ())
linkCmd (LinkOptions src) _ =
tryFindLocalPackageSpec "." |>= \specDir ->
getLocalPackageSpec "." |>= \specDir ->
cleanCurryPathCache specDir |>
log Info ("Linking '" ++ src ++ "' into local package cache...") |>
linkToLocalCache src specDir
......@@ -971,7 +983,16 @@ linkCmd (LinkOptions src) _ =
--- and package installation directory so that it is available as
--- any other package.
addCmd :: AddOptions -> Config -> IO (ErrorLogger ())
addCmd (AddOptions pkgdir force) config = do
addCmd (AddOptions addpkg adddep pkg force) config
| addpkg = addPackageCmd pkg force config
| adddep = addDependencyCmd pkg force config
| otherwise = log Critical "Option --package or --dependency missing!"
--- `add --package` command: copy the given package to the repository index
--- and package installation directory so that it is available as
--- any other package.
addPackageCmd :: String -> Bool -> Config -> IO (ErrorLogger ())
addPackageCmd pkgdir force config = do
dirExists <- doesDirectoryExist pkgdir
if dirExists
then loadPackageSpec pkgdir |>= \pkgSpec ->
......@@ -1002,7 +1023,49 @@ addCmd (AddOptions pkgdir force) config = do
copyDirectory pkgdir pkgInstallDir
updateRepositoryCache config
useForce = "Use option '-f' or '--force' to overwrite it."
useForce :: String
useForce = "Use option '-f' or '--force' to overwrite it."
--- `add --dependency` command: add the given package as a new
--- dependency to the current package.
addDependencyCmd :: String -> Bool -> Config -> IO (ErrorLogger ())
addDependencyCmd pkgname force config =
readRepository config >>= \repo ->
case findLatestVersion config repo pkgname False of
Nothing -> failIO $
"Package '" ++ pkgname ++ "' not found in package repository."
Just p -> searchLocalPackageSpec "." |>=
maybe (genNewLocalPackage (version p))
(addDepToLocalPackage (version p))
where
addDepToLocalPackage vers pkgdir =
loadPackageSpec pkgdir |>= \pkgSpec ->
let depexists = pkgname `elem` dependencyNames pkgSpec
newdeps = addDep [[VGte vers]] (dependencies pkgSpec)
newpkg = pkgSpec { dependencies = newdeps }
in if force || not depexists
then writePackageSpec newpkg (pkgdir </> "package.json") |>>
log Info ("Dependency '" ++ pkgname ++ " >= " ++
showVersion vers ++
"' added to current package specification")
else log Critical ("Dependency '" ++ pkgname ++
"' already exists!\n" ++ useForce)
genNewLocalPackage vers =
let newpkg = emptyPackage { name = "PSEUDO_PACKAGE"
, version = initialVersion
, author = "NN"
, synopsis = "UNKNOWN"
, dependencies = addDep [[VGte vers]] []
}
in writePackageSpec newpkg "package.json" |>>
log Info ("New package specification 'package.json' with dependency '" ++
pkgname ++ " >= " ++ showVersion vers ++ "' generated")
addDep vcs [] = [Dependency pkgname vcs]
addDep vcs (Dependency pn pvcs : deps) =
if pn == pkgname then Dependency pn vcs : deps
else Dependency pn pvcs : addDep vcs deps
------------------------------------------------------------------------------
--- `doc` command: run `curry doc` on the modules provided as an argument
......@@ -1012,20 +1075,20 @@ addCmd (AddOptions pkgdir force) config = do
docCmd :: DocOptions -> Config -> IO (Repository,GlobalCache)
-> IO (ErrorLogger ())
docCmd opts cfg getRepoGC =
tryFindLocalPackageSpec "." |>= \specDir ->
getLocalPackageSpec "." |>= \specDir ->
loadPackageSpec specDir |>= \pkg -> do
let docdir = maybe "cdoc" id (docDir opts)
absdocdir <- getAbsolutePath docdir
createDirectoryIfMissing True absdocdir
(if docManual opts then genPackageManual opts cfg getRepoGC pkg absdocdir
(if docManual opts then genPackageManual opts cfg pkg absdocdir
else succeedIO ()) |>
(if docPrograms opts then genDocForPrograms opts cfg getRepoGC specDir pkg
else succeedIO ())
--- Generate manual according to documentation specification of package.
genPackageManual :: DocOptions -> Config -> IO (Repository,GlobalCache)
-> Package -> String -> IO (ErrorLogger ())
genPackageManual _ _ _ pkg outputdir = case documentation pkg of
genPackageManual :: DocOptions -> Config -> Package -> String
-> IO (ErrorLogger ())
genPackageManual _ _ pkg outputdir = case documentation pkg of
Nothing -> succeedIO ()
Just (PackageDocumentation docdir docmain doccmd) -> do
let formatcmd = replaceSubString "OUTDIR" outputdir $
......@@ -1118,7 +1181,7 @@ genDocForPrograms opts cfg getRepoGC specDir pkg = do
testCmd :: TestOptions -> Config -> IO (Repository,GlobalCache)
-> IO (ErrorLogger ())
testCmd opts cfg getRepoGC =
tryFindLocalPackageSpec "." |>= \specDir ->
getLocalPackageSpec "." |>= \specDir ->
loadPackageSpec specDir |>= \pkg -> do
checkCompiler cfg pkg
aspecDir <- getAbsolutePath specDir
......@@ -1180,7 +1243,7 @@ curryModulesInDir dir = getModules "" dir
diff :: DiffOptions -> Config -> Repository -> GlobalCache
-> IO (ErrorLogger ())
diff opts cfg repo gc =
tryFindLocalPackageSpec "." |>= \specDir ->
getLocalPackageSpec "." |>= \specDir ->
loadPackageSpec specDir |>= \localSpec ->
let localname = name localSpec
localv = version localSpec
......@@ -1226,7 +1289,7 @@ diff opts cfg repo gc =
exec :: ExecOptions -> Config -> IO (Repository,GlobalCache)
-> IO (ErrorLogger ())
exec o cfg getRepoGC =
tryFindLocalPackageSpec "." |>= execWithPkgDir o cfg getRepoGC
getLocalPackageSpec "." |>= execWithPkgDir o cfg getRepoGC
execWithPkgDir :: ExecOptions -> Config -> IO (Repository,GlobalCache)
-> String -> IO (ErrorLogger ())
......@@ -1254,7 +1317,7 @@ execWithPkgDir o cfg getRepoGC specDir =
-- Clean auxiliary files in the current package
cleanPackage :: LogLevel -> IO (ErrorLogger ())
cleanPackage ll =
tryFindLocalPackageSpec "." |>= \specDir ->
getLocalPackageSpec "." |>= \specDir ->
loadPackageSpec specDir |>= \pkg ->
let dotcpm = specDir </> ".cpm"
srcdirs = map (specDir </>) (sourceDirsOf pkg)
......@@ -1266,7 +1329,8 @@ cleanPackage ll =
in log ll ("Removing directories: " ++ unwords rmdirs) |>
(showExecCmd (unwords $ ["rm", "-rf"] ++ rmdirs) >> succeedIO ())
--- Creates a new package by asking some questions.
--- Creates a new package.
newPackage :: NewOptions -> IO (ErrorLogger ())
newPackage (NewOptions pname) = do
exists <- doesDirectoryExist pname
......
......@@ -38,7 +38,6 @@ module CPM.Package
, writePackageSpec
, Conjunction
, Disjunction
, showDisjunction
, packageSpecToJSON
) where
......@@ -433,10 +432,8 @@ showCompilerDependency (CompilerCompatibility cc vcs) =
--- Renders a list of version constraints in disjunctive normal form.
showVersionConstraints :: [[VersionConstraint]] -> String
showVersionConstraints vcs = intercalate " || " $ map (\c -> intercalate ", " $ map showVersionConstraint c) vcs
showDisjunction :: Disjunction -> String
showDisjunction = intercalate " || " . map (intercalate ", " . map showVersionConstraint)
showVersionConstraints =
intercalate " || " . map (intercalate ", " . map showVersionConstraint)
--- Renders a single version constraint as a string.
showVersionConstraint :: VersionConstraint -> String
......
......@@ -9,7 +9,7 @@ module CPM.PackageCopy
, resolveDependencies
, upgradeAllPackages
, upgradeSinglePackage
, tryFindLocalPackageSpec
, getLocalPackageSpec, searchLocalPackageSpec
, linkToLocalCache
, acquireAndInstallPackageWithDependencies
, installLocalDependencies
......@@ -161,17 +161,24 @@ linkToLocalCache src pkgDir = do
--- Tries to find a package specification in the current directory or one of its
--- ancestors.
tryFindLocalPackageSpec :: String -> IO (ErrorLogger String)
tryFindLocalPackageSpec dir = do
getLocalPackageSpec :: String -> IO (ErrorLogger String)
getLocalPackageSpec dir =
searchLocalPackageSpec dir |>=
maybe (failIO "No package.json found") succeedIO
--- 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 dir
then succeedIO (Just dir)
else log Debug ("No package.json in " ++ show dir ++ ", trying " ++
show (dir </> "..")) |> do
parentExists <- doesDirectoryExist $ dir </> ".."