Commit 03e888a8 authored by Michael Hanus 's avatar Michael Hanus
Browse files

CPM updated with faster "update" and support for caret and tilde comparison...

CPM updated with faster "update" and support for caret and tilde comparison operators in dependency descriptions
parent e7dd2a10
Hints about CPM's Implementation
================================
Some details about CPM's Implementation
========================================
Information about CPM's local storage structure can be found in the manual.
Information about CPM's local storage structure (i.e., on the client side)
can be found in the manual.
Here is some information about CPM's global storage structure.
......@@ -51,7 +52,7 @@ CPM uses a global store containing a gzipped tar file for each package.
The default URL is defined in `CPM.Config.packageTarFilesDefaultURL`,
currently as
https://www.informatik.uni-kiel.de/~curry/cpm/PACKAGES/
https://www-ps.informatik.uni-kiel.de/~cpm/PACKAGES/
This configuration can be changed by the `.cpmrc` value
......@@ -64,7 +65,7 @@ In order to download the package `pkg` in version `vers`,
CPM extends this URL by the string `pkg-vers.tar.gz`.
For instance, CPM downloads version 2.1.0 of the package `cpm` from
https://www.informatik.uni-kiel.de/~curry/cpm/PACKAGES/cpm-2.1.0.tar.gz
https://www-ps.informatik.uni-kiel.de/~cpm/PACKAGES/cpm-2.1.0.tar.gz
If CPM cannot download anything from this location,
it tries to download the package from the `source` field
......@@ -77,7 +78,7 @@ Global package index cache
In order to accelerate the creation of the sqlite3 database
during the `update` command, CPM tries to download the file
https://www.informatik.uni-kiel.de/~curry/cpm/PACKAGES/REPOSITORY_CACHE.csv
https://www-ps.informatik.uni-kiel.de/~cpm/PACKAGES/REPOSITORY_CACHE.csv
which contains the database information in CSV format.
If CPM cannot download this file, it creates the database
......@@ -105,5 +106,4 @@ source repository. This command tests the package and, in case
of a successful test, uploads the package to the global package
index and store via the web script at URL
https://www-ps.informatik.uni-kiel.de/~mh/cpm-upload.cgi
https://www-ps.informatik.uni-kiel.de/~cpm/cpm-upload.cgi
Copyright (c) 2017, Michael Hanus
Copyright (c) 2020, Michael Hanus
All rights reserved.
Redistribution and use in source and binary forms, with or without
......
......@@ -73,35 +73,43 @@ older version of the same package.
\section{Installing the Curry Package Manager}
\subsection{Requirements}
CPM requires
\emph{Git}\footnote{\url{http://www.git-scm.com}},
\emph{curl}\footnote{\url{https://curl.haxx.se}},
\emph{tar},
and \emph{unzip} to be available on the \code{PATH} during installation and
operation.
It is strongly 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.
CPM is part of recent distributions of the Curry systems
PAKCS\footnote{\url{https://www.informatik.uni-kiel.de/~pakcs/}}
(since version 1.15.0)
and
KiCS2\footnote{\url{https://www-ps.informatik.uni-kiel.de/kics2/}}
(since version 0.6.0).
(since version 0.6.0) so that it can directly be used with
these Curry systems.
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.
install some CPM version from the source repository,
the following section contains some hints about the installation of CPM.
\subsection{Source Code Installation}
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}},
\emph{tar},
and \emph{unzip} to be available on the \code{PATH} during installation and
operation. You also need to ensure that your Haskell installations reads files
KiCS2 in version 0.5.1 or greater is required.
You need to ensure that your Haskell installation reads files
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
......@@ -187,24 +195,48 @@ Dependencies are specified as a nested JSON object with package names as keys
and dependency constraints as values. A dependency constraint restricts the
range of versions of the dependency that a package is compatible to. Constraints
consist of elementary comparisons that can be combined into conjunctions, which
can then be combined into one large disjunction -- essentially a disjunctive
normal form. The supported comparison operators are $<, \leq, >, \geq, =$ and
$\sim>$. The first four are interpreted according to the rules for comparing
version numbers laid out in the semantic versioning standard. $\sim>$ is called
the \emph{semantic versioning arrow}. It requires that the package version be
at least as large as its argument, but still within the same minor version, i.e.
$\sim> 1.2.3$ would match $1.2.3$, $1.2.9$ and $1.2.55$, but not $1.2.2$ or
$1.3.0$.
can then be combined into one large disjunction---essentially a disjunctive
normal form.
The supported comparison operators are
\code{<}, \code{<=}, \code{>}, \code{>=}, \code{=}, \code{\char126},
and \code{\char94}.
The first five are interpreted according to the rules for comparing
version numbers laid out in the semantic versioning standard.
\code{\char126} requires\footnote{%
In previous versions of CPM this was denoted
as \code{{\char126}>} and called \emph{semantic versioning arrow}.}
that the package version be
at least as large as its argument but still within the same minor version,
i.e.,
\code{{\char126}1.2.3} would match
\code{1.2.3}, \code{1.2.9}, and \code{1.2.55}
but not \code{1.2.2}, \code{1.3.0}, or \code{2.1.0}.
Analogously, \code{\char94} requires that the package version be
at least as large as its argument but still within the same major version,
i.e.,
\code{{\char94}1.2.3} would match
\code{1.2.3} and \code{1.4.3}
but not \code{2.1.0}.
To combine multiple comparisons into a conjunction, separate them by commas,
e.g. $\geq 2.0.0, < 3.0.0$ would match all versions with major version $2$.
Note that it would not match \textit{2.1.3-beta5} for example, since pre-release
e.g.,
\begin{lstlisting}
>= 2.0.0, < 3.0.0
\end{lstlisting}
would match all versions
with major version \code{2}.
Note that it would not match \code{2.1.3-beta5} for example, since pre-release
versions are only matched if the comparison is explicitly made to a pre-release
version, e.g. $= \text{2.1.3-beta5}$ or $\geq \text{2.1.3-beta2}$.
version, e.g., \code{= 2.1.3-beta5} or \code{> 2.1.3-beta2}.
Conjunctions can be combined into a disjunction via the $||$ characters, e.g.
$\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$.
Conjunctions can be combined into a disjunction via the
\code{||} characters, e.g.,
\begin{lstlisting}
>= 2.0.0, < 3.0.0 || >= 4.0.0
\end{lstlisting}
would match any version within major version
\code{2} and from major version \code{4} onwards,
but no version within major version \code{3}.
\clearpage
......@@ -234,8 +266,9 @@ Then declare the dependencies inside the new \code{package.json} file, e.g.:
{
...,
"dependencies": {
"base": ">= 1.0.0, < 2.0.0",
"json": "~> 1.1.0"
"base": "^1.0.0",
"html": ">= 2.0.0, < 2.2.0"
"json": "~1.1.0"
}
}
\end{lstlisting}
......@@ -676,11 +709,6 @@ CPM can be configured via the \code{\$HOME/.cpmrc} configuration file. The
following list shows all configuration options and their default values.
\begin{description}
\item[\fbox{\code{PACKAGE_INDEX_URL}}]
The URL of the central package index
which is used by the \code{update} command to download the
index of all repositories.
\item[\fbox{\code{REPOSITORY_PATH}}] The path to the index of all packages.
Default value: \code{\$HOME/.cpm/index}.
......@@ -728,10 +756,42 @@ 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.
\item[\fbox{\code{PACKAGE_INDEX_URL}}]
The URL of the central package index
which is used by the \code{update} command to download the
index of all repositories.
Default value:
\begin{lstlisting}
https://git.ps.informatik.uni-kiel.de/curry-packages/cpm-index.git
\end{lstlisting}
\item[\fbox{\code{PACKAGE_TARFILES_URL}}]
The URL prefix to the directory containing the ``tar'' files of all packages.
If a package $p$ with version $v$ is downloaded
(via the \code{install} or \code{checkout} command),
the source of the package is downloaded from this location
as file \code{$p$-$v$.tar.gz}.
Default value:
\begin{lstlisting}
https://www-ps.informatik.uni-kiel.de/~cpm/PACKAGES/
\end{lstlisting}
For instance, the package \code{cpm} with version \code{2.2.0}
is downloaded from
\begin{lstlisting}
https://www-ps.informatik.uni-kiel.de/~cpm/PACKAGES/cpm-2.2.0.tar.gz
\end{lstlisting}
\end{description}
%
The CPM command
\begin{lstlisting}
> cypm config
\end{lstlisting}
show the current values of the configuration options.
Note that one write the option names also in lowercase or omit
the underscores. For instance, one can also write \code{currybin}
the underscores. For instance, one can write \code{currybin}
instead of \code{CURRY_BIN}.
Moreover, one can override the values of these configuration options
by the CPM options \code{-d} or \code{--define}.
......@@ -748,12 +808,16 @@ one can execute the command
\section{Some CPM Internals}
\label{sec:internals}
CPM's central package index is contains all package specification files.
CPM's central package index contains all package specification files.
It is stored at a central server where the actual location is defined
by CPM's configuration variable \code{PACKAGE_INDEX_URL},
see Section~\ref{sec:config}.
A copy of this index is stored on your
local system in the \code{\$HOME/.cpm/index} directory, unless you
When the command
\begin{lstlisting}
> cypm update
\end{lstlisting}
is executed, a copy of this index is downloaded and stored on your
local system in the directory \code{\$HOME/.cpm/index}, unless you
changed the location using the \code{REPOSITORY_PATH} setting. CPM
uses the package index when searching for and installing packages and
during dependency resolution.
......@@ -1179,13 +1243,15 @@ a valid URL.
The suggested formats are either a valid URL to a bug tracker
or an email address.
\item[\fbox{\code{repository}}] The location of a SCM repository containing the
package's source code. Should be a valid URL to either a repository (e.g. a Git
URL), or a website representing the repository.
\item[\fbox{\code{repository}}]
The location of a SCM repository containing the package's source
code. Should be a valid URL to either a repository (e.g. a Git URL),
or a website representing the repository.
\item[\fbox{\code{dependencies*}}] The package's dependencies. This must be JSON
\item[\fbox{\code{dependencies*}}]
The package's dependencies. This must be JSON
object where the keys are package names and the values are version
constraints. See Section~\ref{sec:package-basics}.
constraints. See Section~\ref{sec:package-basics} for more details.
\item[\fbox{\code{compilerCompatibility}}] The package's compatibility to
different Curry compilers. Expects a JSON object where the keys are compiler
......@@ -1395,8 +1461,9 @@ are used:
"repository": "THE (GIT) URL OF THE WEB SITE REPOSITORY",
"dependencies": {
"PACKAGE1" : ">= 0.0.1, < 1.5.0",
"PACKAGE2" : "~> 1.2.3",
"PACKAGE3" : ">= 2.1.4, < 3.0.0 || >= 4.0.0"
"PACKAGE2" : "~1.2.3",
"PACKAGE3" : ">= 2.1.4, < 3.0.0 || >= 4.0.0",
"PACKAGE2" : "^2.1.3",
},
"compilerCompatibility": {
"pakcs": ">= 1.14.0, < 2.0.0",
......
......@@ -6,7 +6,7 @@
module CPM.Config
( Config ( Config, packageInstallDir, binInstallDir, repositoryDir
, appPackageDir, packageIndexURL, packageTarFilesURL
, appPackageDir, packageIndexURLs, packageTarFilesURL
, homePackageDir, curryExec
, compilerVersion, compilerBaseVersion, baseVersion )
, readConfigurationWith, defaultConfig
......@@ -19,7 +19,7 @@ import qualified Distribution as Dist
import FilePath ( (</>), isAbsolute )
import Function ( (***) )
import IOExts ( evalCmd )
import List ( split, splitOn, intersperse )
import List ( intercalate, intersperse, split, splitOn )
import Maybe ( mapMaybe )
import Read ( readInt )
......@@ -30,17 +30,18 @@ import CPM.ErrorLogger
import CPM.FileUtil ( ifFileExists )
import CPM.Helpers ( strip )
--- The default location of the central package index.
packageIndexDefaultURL :: String
packageIndexDefaultURL =
"https://git.ps.informatik.uni-kiel.de/curry-packages/cpm-index.git"
-- If you have an ssh access to git.ps.informatik.uni-kiel.de:
-- "ssh://git@git.ps.informatik.uni-kiel.de:55055/curry-packages/cpm-index.git"
--- The default URL prefix to the directory containing tar files of all packages
packageTarFilesDefaultURL :: String
packageTarFilesDefaultURL =
"https://www.informatik.uni-kiel.de/~curry/cpm/PACKAGES/"
"https://www-ps.informatik.uni-kiel.de/~cpm/PACKAGES/"
--- The default location of the central package index.
packageIndexDefaultURLs :: [String]
packageIndexDefaultURLs =
[packageTarFilesDefaultURL ++ "INDEX.tar.gz",
"https://git.ps.informatik.uni-kiel.de/curry-packages/cpm-index.git"]
-- If you have an ssh access to git.ps.informatik.uni-kiel.de:
--["ssh://git@git.ps.informatik.uni-kiel.de:55055/curry-packages/cpm-index.git"]
--- Data type containing the main configuration of CPM.
data Config = Config {
......@@ -52,8 +53,8 @@ data Config = Config {
, repositoryDir :: String
--- Directory where the application packages are stored (cmd 'install')
, appPackageDir :: String
--- URL to the package index repository
, packageIndexURL :: String
--- URLs tried for downloading the package index
, packageIndexURLs :: [String]
--- URL prefix to the directory containing tar files of all packages
, packageTarFilesURL :: String
--- The directory where the default home package is stored
......@@ -76,7 +77,7 @@ defaultConfig = Config
, binInstallDir = "$HOME/.cpm/bin"
, repositoryDir = "$HOME/.cpm/index"
, appPackageDir = ""
, packageIndexURL = packageIndexDefaultURL
, packageIndexURLs = packageIndexDefaultURLs
, packageTarFilesURL = packageTarFilesDefaultURL
, homePackageDir = ""
, curryExec = Dist.installDir </> "bin" </> Dist.curryCompiler
......@@ -100,7 +101,7 @@ showConfiguration cfg = unlines
, "BIN_INSTALL_PATH : " ++ binInstallDir cfg
, "APP_PACKAGE_PATH : " ++ appPackageDir cfg
, "HOME_PACKAGE_PATH : " ++ homePackageDir cfg
, "PACKAGE_INDEX_URL : " ++ packageIndexURL cfg
, "PACKAGE_INDEX_URL : " ++ intercalate "|" (packageIndexURLs cfg)
, "PACKAGE_TARFILES_URL : " ++ packageTarFilesURL cfg
]
......@@ -274,7 +275,7 @@ keySetters =
, ("BININSTALLPATH" , \v c -> c { binInstallDir = v })
, ("CURRYBIN" , \v c -> c { curryExec = v })
, ("HOMEPACKAGEPATH" , \v c -> c { homePackageDir = v })
, ("PACKAGEINDEXURL" , \v c -> c { packageIndexURL = v })
, ("PACKAGEINDEXURL" , \v c -> c { packageIndexURLs = [v] })
, ("PACKAGETARFILESURL" , \v c -> c { packageTarFilesURL = v })
, ("PACKAGEINSTALLPATH" , \v c -> c { packageInstallDir = v })
, ("REPOSITORYPATH" , \v c -> c { repositoryDir = v })
......
......@@ -101,8 +101,8 @@ compareModulesInDirs :: Config -> Repository -> GC.GlobalCache -> String
compareModulesInDirs cfg repo gc dirA dirB onlyMods =
loadPackageSpec dirA |>= \pkgA ->
loadPackageSpec dirB |>= \pkgB ->
resolveAndCopyDependencies cfg repo gc dirA |>= \depsA ->
resolveAndCopyDependencies cfg repo gc dirB |>= \depsB ->
fromELM (resolveAndCopyDependencies cfg repo gc dirA) |>= \depsA ->
fromELM (resolveAndCopyDependencies cfg repo gc dirB) |>= \depsB ->
let cmpmods = nub (exportedModules pkgA ++ exportedModules pkgB) in
if null cmpmods
then log Info "No exported modules to compare" |> succeedIO []
......
......@@ -659,8 +659,8 @@ findTypeInModules cfg repo gc info acy (mod,n) =
Nothing ->
(case findModule mod acy of
Just p -> succeedIO $ p
Nothing -> resolveAndCopyDependencies cfg repo gc
(infSourceDirA info) |>= \deps ->
Nothing -> fromELM (resolveAndCopyDependencies cfg repo gc
(infSourceDirA info)) |>= \deps ->
readAbstractCurryFromDeps (infSourceDirA info) deps mod >>=
succeedIO) |>= \prog ->
case filter ((== n) . snd . typeName) (types prog) of
......@@ -834,7 +834,7 @@ findFunctionsToCompare :: Config
findFunctionsToCompare cfg repo gc dirA dirB useanalysis onlymods =
loadPackageSpec dirA |>= \pkgA ->
loadPackageSpec dirB |>= \pkgB ->
resolveAndCopyDependencies cfg repo gc dirA |>= \depsA ->
fromELM (resolveAndCopyDependencies cfg repo gc dirA) |>= \depsA ->
succeedIO (let cmods = intersect (exportedModules pkgA) (exportedModules pkgB)
in maybe cmods (intersect cmods) onlymods) |>= \mods ->
if null mods
......
......@@ -39,7 +39,7 @@ import CPM.Repository (Repository)
prefixPackageAndDeps :: Config -> Repository -> GC.GlobalCache -> String
-> String -> String -> IO (ErrorLogger [(String, String)])
prefixPackageAndDeps cfg repo gc dir prefix destDir =
resolveAndCopyDependencies cfg repo gc dir |>=
fromELM (resolveAndCopyDependencies cfg repo gc dir) |>=
\deps -> (mapIO (findAllModulesInPackage . RuntimeCache.cacheDirectory dir) deps >>= succeedIO) |>=
\depMods -> (findAllModulesInPackage dir >>= succeedIO) |>=
\ownMods -> succeedIO (ownMods ++ concat depMods) |>=
......
......@@ -10,12 +10,13 @@ module CPM.ErrorLogger
, levelGte
, getLogLevel, setLogLevel
, setWithShowTime
, (|>=), (|>), (|->), (|>>)
, ErrorLoggerIO, fromELM, toELM, execIO, putStrELM, putStrLnELM, runELM
, (|>=), (|>)
, mapEL
, foldEL
, succeedIO
, failIO
, log
, failIO, failELM
, log, logMsg
, showLogEntry
, infoMessage, debugMessage, errorMessage, fromErrorLogger
, showExecCmd, execQuietCmd
......@@ -28,7 +29,7 @@ import System ( exitWith, system )
import Debug.Profile -- for show run-time
import Text.Pretty
infixl 0 |>=, |>, |>>, |->
infixl 0 |>=, |>
--- An error logger.
type ErrorLogger a = ([LogEntry], Either LogEntry a)
......@@ -73,44 +74,63 @@ setWithShowTime :: Bool -> IO ()
setWithShowTime wst = writeGlobal withShowTime wst
---------------------------------------------------------------------------
--- Chains two actions passing the result from the first to the second.
--- Datatype to define the `ErrorLoggerIO` monad.
data ErrorLoggerIO a = ErrorLoggerIO (IO (ErrorLogger a))
--- Transforms an `ErrorLoggerIO` monad action into an IO action.
fromELM :: ErrorLoggerIO a -> IO (ErrorLogger a)
fromELM (ErrorLoggerIO errio) = errio
--- Transforms an IO action into an `ErrorLoggerIO` monad action.
toELM :: IO (ErrorLogger a) -> ErrorLoggerIO a
toELM act = ErrorLoggerIO act
--- Definition of the `ErrorLoggerIO` monad.
instance Monad ErrorLoggerIO where
return = toELM . succeedIO
a >>= f = toELM (fromELM a |>= \x -> fromELM (f x))
--- Executes an IO action in the `ErrorLoggerIO` monad.
execIO :: IO a -> ErrorLoggerIO a
execIO act = toELM (act >>= succeedIO)
--- Prints a string in the `ErrorLoggerIO` monad.
putStrELM :: String -> ErrorLoggerIO ()
putStrELM = execIO . putStr
--- Prints a line in the `ErrorLoggerIO` monad.
putStrLnELM :: String -> ErrorLoggerIO ()
putStrLnELM = execIO . putStrLn
--- Runs an `ErrorLoggerIO` monad action as an IO action.
--- Shows all messages and exit with status 1 if an error occurred.
runELM :: ErrorLoggerIO a -> IO a
runELM elmact = do
(msgs, result) <- fromELM elmact
mapM showLogEntry msgs
let allOk = all (levelGte Info) (map logLevelOf msgs) &&
either (\le -> levelGte Info (logLevelOf le))
(const True)
result
unless allOk $ exitWith 1
case result of Left m -> showLogEntry m >> exitWith 1
Right v -> return v
----------------------------------------------------------------------------
-- Chains two actions passing the result from the first to the second.
(|>=) :: IO (ErrorLogger a) -> (a -> IO (ErrorLogger b)) -> IO (ErrorLogger b)
a |>= f = do
(msgs, err) <- a
mapIO showLogEntry msgs
case err of
Right v -> do
(msgs', err') <- f v
return $ (msgs', err')
Left m -> return $ ([], Left m)
Right v -> do (msgs', err') <- f v
return (msgs', err')
Left m -> return ([], Left m)
--- Chains two actions ignoring the result of the first.
(|>) :: IO (ErrorLogger a) -> IO (ErrorLogger b) -> IO (ErrorLogger b)
a |> f = do
(msgs, err) <- a
mapIO showLogEntry msgs
case err of
Right _ -> do
(msgs', err') <- f
return $ (msgs', err')
Left m -> return $ ([], Left m)
--- Chains two actions ignoring the result of the second.
(|->) :: IO (ErrorLogger a) -> IO (ErrorLogger b) -> IO (ErrorLogger a)
a |-> b = do
(msgs, err) <- a
mapIO showLogEntry msgs
case err of
Right _ -> do
(msgs', _) <- b
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
a1 |> a2 = a1 |>= \_ -> a2
--- Maps an action over a list of values. Fails if one of the actions fails.
mapEL :: (a -> IO (ErrorLogger b)) -> [a] -> IO (ErrorLogger [b])
......@@ -190,13 +210,22 @@ succeedIO v = return $ succeed v
--- Create an action that always fails.
fail :: String -> ErrorLogger a
fail msg = ([logMsg], Left logMsg) where logMsg = LogEntry Critical msg
fail msg = ([logmsg], Left logmsg)
where logmsg = LogEntry Critical msg
--- Create an IO action that always fails.
failIO :: String -> IO (ErrorLogger a)
failIO msg = return $ fail msg
--- Create an IO action that logs a message.
--- Create an `ErrorLoggerIO` action that always fails with a message.
failELM :: String -> ErrorLoggerIO a
failELM msg = toELM (failIO msg)
--- Creates an IO action that logs a message.
logMsg :: LogLevel -> String -> ErrorLoggerIO ()
logMsg lvl msg = toELM $ log lvl msg
--- Creates an IO action that logs a message.
log :: LogLevel -> String -> IO (ErrorLogger ())
log lvl msg = do
wst <- getWithShowTime
......@@ -221,7 +250,7 @@ debugMessage msg = (log Debug msg |> succeedIO ()) >> done
errorMessage :: String -> IO ()
errorMessage msg = (log Error msg |> succeedIO ()) >> done
--- Transforms an error logger actions into a standard IO action.
--- Transforms an error logger action into a standard IO action.
--- It shows all messages and, if the result is not available,
--- exits with a non-zero code.
fromErrorLogger :: IO (ErrorLogger a) -> IO a
......@@ -229,8 +258,8 @@ fromErrorLogger a = do
(msgs, err) <- a
mapIO showLogEntry msgs
case err of
Right v -> return v
Left m -> showLogEntry m >> exitWith 1
Right v -> return v
--- Executes a system command and show the command as debug message.
showExecCmd :: String -> IO Int
......
This diff is collapsed.
......@@ -33,7 +33,8 @@ module CPM.Package
, PackageExecutable (..), PackageTest (..), PackageDocumentation (..)
, showDependency
, showCompilerDependency
, loadPackageSpec
, showVersionConstraints
, loadPackageSpec, loadPackageSpecELM
, writePackageSpec
, Conjunction
, Disjunction
......@@ -89,14 +90,17 @@ data Dependency = Dependency String Disjunction
--- @cons VLt - version must be strictly smaller than specified version
--- @cons VGte - version must be larger or equal to specified version
--- @cons VLte - version must be smaller or equal to specified version
--- @cons VCompatible - semver arrow, version must be larger or equal and
--- within same minor version
data VersionConstraint = VExact Version
| VGt Version
| VLt Version
| VGte Version
| VLte Version
| VCompatible Version
--- @cons VMinCompatible - version must be larger or equal and
--- within same minor version
--- @cons VMajCompatible - version must be larger or equal and
--- within same minor version
data VersionConstraint = VExact Version
| VGt Version
| VLt Version
| VGte Version
| VLte Version
| VMinCompatible Version
| VMajCompatible Version
deriving (Eq,Show)
--- Compiler compatibility constraint, takes the name of the compiler (kics2 or
......@@ -324,6 +328,12 @@ writePackageSpec :: Package -> String -> IO ()
writePackageSpec pkg file = writeFile file $ ppJSON $ packageSpecToJSON pkg
--- Loads a package specification from a package directory.
---
--- @param the directory containing the package.json file
loadPackageSpecELM :: String -> ErrorLoggerIO Package
loadPackageSpecELM = toELM . loadPackageSpec
--- Loads a package specification from a package directory.
---
--- @param the directory containing the package.json file
......@@ -466,12 +476,13 @@ 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 (VMinCompatible v) = " ~" ++ showVersion v
showVersionConstraint (VMajCompatible v) = " ^" ++ showVersion v
--- Renders the id of a package as a string. Package name and version separated
--- by a dash.
......@@ -913,16 +924,24 @@ test_readVersionConstraint_greaterThan :: Prop
test_readVersionConstraint_greaterThan = readVersionConstraint "> 1.2.3" -=- (Just $ VGt (1, 2, 3, Nothing))