Commit d8a7d586 authored by Michael Hanus's avatar Michael Hanus
Browse files

CPM updated

parent daafe021
This directory contains some documention for the Curry Package Manager: This directory contains some documention for the Curry Package Manager:
pakcs_manual.tex: currysystem_manual.tex:
A short description to be included in the main manual of the Curry system. A short description to be included in the main manual of the Curry system.
manual.tex: manual.tex:
......
...@@ -604,13 +604,22 @@ caches. ...@@ -604,13 +604,22 @@ caches.
\section{Command Reference} \section{Command Reference}
\label{sec:cmd-reference} \label{sec:cmd-reference}
This section gives a short description of all available CPM commands. In This section gives a short description of all available CPM commands.
addition to the commands listed here, there is a global parameter In addition to the commands listed below, there are some global options
\code{--verbosity} which can be placed in front of the CPM command:
which defaults to \code{info} but can be increased to \code{debug} for \begin{description}
more output. \item[\code{-v$\,|\,$--verbosity [info|debug]}:]
Furthermore, there is a global parameter \code{--define} to override The default value is \code{info}.
the configuration options of CPM, see Section~\ref{sec:config}. The value \code{debug} provides more output messages in order to see
what CPM is doing.
\item[\code{-t$\,|\,$--time}:]
This option adds the elapsed time to every info or debug output line.
\item[\code{-d$\,|\,$--define $option$=$value$}:]
This option overrides the configuration options of CPM,
see Section~\ref{sec:config}.
\end{description}
%
The available commands of CPM are:
\begin{description} \begin{description}
\item[\fbox{\code{info}}] Gives information on the current package, e.g. the \item[\fbox{\code{info}}] Gives information on the current package, e.g. the
...@@ -859,8 +868,9 @@ text of the license. The suggested name for this file is \code{LICENSE}. ...@@ -859,8 +868,9 @@ text of the license. The suggested name for this file is \code{LICENSE}.
\item[\fbox{\code{homepage}}] The package's web site. This field should contain \item[\fbox{\code{homepage}}] The package's web site. This field should contain
a valid URL. a valid URL.
\item[\fbox{\code{bugReports}}] A place to report bugs found int he package. The \item[\fbox{\code{bugReports}}] A place to report bugs found in the package.
suggested formats are either a valid URL to a bug tracker or an email address. 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 \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 package's source code. Should be a valid URL to either a repository (e.g. a Git
...@@ -934,6 +944,9 @@ if this package contains also an executable application. ...@@ -934,6 +944,9 @@ if this package contains also an executable application.
The name of the executable must be defined (with key \code{name}) The name of the executable must be defined (with key \code{name})
whereas the name of the main module (key \code{main}) is optional. whereas the name of the main module (key \code{main}) is optional.
If the latter is missing, CPM assumes that the main module is \code{Main}. If the latter is missing, CPM assumes that the main module is \code{Main}.
Furthermore, the executable specification can also contain
options for various Curry compilers. The options must be a JSON object
consisting of compiler names as keys and an option string for the compiler.
For instance, a possible specification could be as follows: For instance, a possible specification could be as follows:
% %
\begin{lstlisting} \begin{lstlisting}
...@@ -941,8 +954,9 @@ For instance, a possible specification could be as follows: ...@@ -941,8 +954,9 @@ For instance, a possible specification could be as follows:
..., ...,
"executable": { "executable": {
"name": "cpm", "name": "cpm",
"main": "CPM.Main" "main": "CPM.Main",
} "options": { "kics2" : ":set rts -T" }
}
} }
\end{lstlisting} \end{lstlisting}
% %
...@@ -998,7 +1012,7 @@ directories \code{test} and \code{examples} could be as follows: ...@@ -998,7 +1012,7 @@ directories \code{test} and \code{examples} could be as follows:
"testsuite": [ "testsuite": [
{ "src-dir": "test", { "src-dir": "test",
"options": "-v", "options": "-v",
"script": [ "test.sh" ] "script": "test.sh"
}, },
{ "src-dir": "examples", { "src-dir": "examples",
"options": "-m80", "options": "-m80",
...@@ -1009,6 +1023,63 @@ directories \code{test} and \code{examples} could be as follows: ...@@ -1009,6 +1023,63 @@ directories \code{test} and \code{examples} could be as follows:
\end{lstlisting} \end{lstlisting}
\end{description} \end{description}
%
In order to provide a compact overview over all metadata fields,
we provide an example of a package specification where all fields
are used:
%
\begin{lstlisting}
{
"name": "PACKAGE_NAME",
"version": "0.0.1",
"author": "YOUR NAME <YOUR EMAIL ADDRESS>",
"maintainer": "ANOTHER NAME <ANOTHER EMAIL ADDRESS>",
"synopsis": "A ONE-LINE SUMMARY ABOUT THE PACKAGE",
"synopsis": "A MORE DEATILED SUMMARY ABOUT THE PACKAGE",
"category": [ "Category1", "Category2" ],
"license": "BSD-3-Clause",
"licenseFile": "LICENSE",
"copyright": "COPYRIGHT INFORMATION",
"homepage": "THE URL OF THE WEB SITE OF THE PACKAGE",
"bugReports": "EMAIL OR BUG TRACKER URL FOR REPORTING BUGS",
"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"
},
"compilerCompatibility": {
"pakcs": ">= 1.14.0, < 2.0.0",
"kics2": ">= 0.5.0, < 2.0.0"
},
"sourceDirs" : [ "src", "include" ],
"exportedModules": [ "Module1", "Module2" ],
"configModule": "ConfigPackage",
"executable": {
"name": "NAME_OF_BINARY",
"main": "Main",
"options": {
"kics2" : ":set rts -T",
"pakcs" : ":set printdepth 100"
}
},
"testsuite": [
{ "src-dir": "src",
"options": "-m80",
"modules": [ "Module1", "Module2" ]
},
{ "src-dir": "examples",
"options": "-v",
"script" : "test.sh"
}
],
"source": {
"git": "URL OF THE GIT REPOSITORY",
"tag": "$\$$version"
}
}
\end{lstlisting}
\section{Error Recovery} \section{Error Recovery}
\label{sec:recovery} \label{sec:recovery}
......
...@@ -9,6 +9,7 @@ module CPM.ErrorLogger ...@@ -9,6 +9,7 @@ module CPM.ErrorLogger
, logLevelOf , logLevelOf
, levelGte , levelGte
, getLogLevel, setLogLevel , getLogLevel, setLogLevel
, setWithShowTime
, (|>=) , (|>=)
, (|>) , (|>)
, (|->) , (|->)
...@@ -30,10 +31,6 @@ import System (exitWith, system) ...@@ -30,10 +31,6 @@ import System (exitWith, system)
infixl 0 |>= infixl 0 |>=
infixl 0 |> infixl 0 |>
-- Should the current time be shown with every log information?
withShowTime :: Bool
withShowTime = False
--- An error logger. --- An error logger.
type ErrorLogger a = ([LogEntry], Either LogEntry a) type ErrorLogger a = ([LogEntry], Either LogEntry a)
...@@ -62,6 +59,21 @@ getLogLevel = readGlobal logLevel ...@@ -62,6 +59,21 @@ getLogLevel = readGlobal logLevel
setLogLevel :: LogLevel -> IO () setLogLevel :: LogLevel -> IO ()
setLogLevel level = writeGlobal logLevel level setLogLevel level = writeGlobal logLevel level
-- Should the current time be shown with every log information?
withShowTime :: Global Bool
withShowTime = global False Temporary
--- Gets the "show time" information.
getWithShowTime :: IO Bool
getWithShowTime = readGlobal withShowTime
--- Sets the "show time" information. If true, then timing information
--- will be shown with every log information.
setWithShowTime :: Bool -> IO ()
setWithShowTime wst = writeGlobal withShowTime wst
---------------------------------------------------------------------------
--- Chains two actions passing the result from the first to the second. --- Chains two actions passing the result from the first to the second.
(|>=) :: IO (ErrorLogger a) -> (a -> IO (ErrorLogger b)) -> IO (ErrorLogger b) (|>=) :: IO (ErrorLogger a) -> (a -> IO (ErrorLogger b)) -> IO (ErrorLogger b)
a |>= f = do a |>= f = do
...@@ -170,11 +182,12 @@ failIO msg = return $ fail msg ...@@ -170,11 +182,12 @@ failIO msg = return $ fail msg
--- Create an IO action that logs a message. --- Create an IO action that logs a message.
log :: LogLevel -> String -> IO (ErrorLogger ()) log :: LogLevel -> String -> IO (ErrorLogger ())
log lvl msg = log lvl msg = do
if withShowTime wst <- getWithShowTime
if wst
then do then do
runtime <- getProcessInfos >>= return . maybe 0 id . lookup ElapsedTime runtime <- getProcessInfos >>= return . maybe 0 id . lookup ElapsedTime
return $ ([LogEntry lvl (showTime runtime ++ ' ':msg)], Right ()) return $ ([LogEntry lvl (showTime runtime ++ 's':' ':msg)], Right ())
else else
return $ ([LogEntry lvl msg], Right ()) return $ ([LogEntry lvl msg], Right ())
where where
......
...@@ -24,8 +24,7 @@ import CPM.ErrorLogger ...@@ -24,8 +24,7 @@ import CPM.ErrorLogger
import CPM.FileUtil ( fileInPath, joinSearchPath, safeReadFile, whenFileExists import CPM.FileUtil ( fileInPath, joinSearchPath, safeReadFile, whenFileExists
, ifFileExists, inDirectory, removeDirectoryComplete , ifFileExists, inDirectory, removeDirectoryComplete
, copyDirectory ) , copyDirectory )
import CPM.Config ( Config ( packageInstallDir, binInstallDir import CPM.Config ( Config (..)
, repositoryDir, appPackageDir, curryExec )
, readConfigurationWithDefault, showCompilerVersion ) , readConfigurationWithDefault, showCompilerVersion )
import CPM.PackageCache.Global ( GlobalCache, readInstalledPackagesFromDir import CPM.PackageCache.Global ( GlobalCache, readInstalledPackagesFromDir
, installFromZip, checkoutPackage , installFromZip, checkoutPackage
...@@ -46,7 +45,7 @@ cpmBanner :: String ...@@ -46,7 +45,7 @@ cpmBanner :: String
cpmBanner = unlines [bannerLine,bannerText,bannerLine] cpmBanner = unlines [bannerLine,bannerText,bannerLine]
where where
bannerText = bannerText =
"Curry Package Manager <curry-language.org/tools/cpm> (version of 19/05/2017)" "Curry Package Manager <curry-language.org/tools/cpm> (version of 24/05/2017)"
bannerLine = take (length bannerText) (repeat '-') bannerLine = take (length bannerText) (repeat '-')
main :: IO () main :: IO ()
...@@ -67,6 +66,7 @@ main = do ...@@ -67,6 +66,7 @@ main = do
runWithArgs :: Options -> IO () runWithArgs :: Options -> IO ()
runWithArgs opts = do runWithArgs opts = do
setWithShowTime (optWithTime opts)
missingExecutables <- checkExecutables missingExecutables <- checkExecutables
unless (null missingExecutables) $ do unless (null missingExecutables) $ do
putStrLn $ "The following programs could not be found on the PATH " ++ putStrLn $ "The following programs could not be found on the PATH " ++
...@@ -125,6 +125,7 @@ getGlobalCache config repo = do ...@@ -125,6 +125,7 @@ getGlobalCache config repo = do
data Options = Options data Options = Options
{ optLogLevel :: LogLevel { optLogLevel :: LogLevel
, optDefConfig :: [(String,String)] , optDefConfig :: [(String,String)]
, optWithTime :: Bool
, optCommand :: Command } , optCommand :: Command }
data Command data Command
...@@ -320,7 +321,7 @@ applyEither (f:fs) z = case f z of ...@@ -320,7 +321,7 @@ applyEither (f:fs) z = case f z of
applyParse :: [Options -> Either String Options] -> Either String Options applyParse :: [Options -> Either String Options] -> Either String Options
applyParse fs = applyEither fs defaultOpts applyParse fs = applyEither fs defaultOpts
where where
defaultOpts = Options Info [] NoCommand defaultOpts = Options Info [] False NoCommand
(>.>) :: Either String a -> (a -> b) -> Either String b (>.>) :: Either String a -> (a -> b) -> Either String b
a >.> f = case a of a >.> f = case a of
...@@ -340,6 +341,10 @@ optionParser = optParser ...@@ -340,6 +341,10 @@ optionParser = optParser
<> short "d" <> short "d"
<> metavar "DEFINITION" <> metavar "DEFINITION"
<> help "Overwrite definition of cpmrc file with 'option=value'." ) <> help "Overwrite definition of cpmrc file with 'option=value'." )
<.> flag (\a -> Right $ a { optWithTime = True })
( long "time"
<> short "t"
<> help "Show elapsed time with every log output" )
<.> commands (metavar "COMMAND") <.> commands (metavar "COMMAND")
( command "checkout" (help "Checkout a package.") Right ( command "checkout" (help "Checkout a package.") Right
(checkoutArgs Checkout) (checkoutArgs Checkout)
...@@ -747,13 +752,15 @@ installExecutable cfg repo pkg = ...@@ -747,13 +752,15 @@ installExecutable cfg repo pkg =
-- the installation of the package: -- the installation of the package:
getGlobalCache cfg repo >>= \gc -> getGlobalCache cfg repo >>= \gc ->
maybe (succeedIO ()) maybe (succeedIO ())
(\ (PackageExecutable name mainmod) -> (\ (PackageExecutable name mainmod eopts) ->
getLogLevel >>= \lvl -> getLogLevel >>= \lvl ->
getEnviron "PATH" >>= \path -> getEnviron "PATH" >>= \path ->
log Info ("Compiling main module: " ++ mainmod) |> log Info ("Compiling main module: " ++ mainmod) |>
let cmd = unwords $ let (cmpname,_,_) = compilerVersion cfg
[":set", if levelGte Debug lvl then "v1" else "v0", cmd = unwords $
":load", mainmod, ":save", ":quit"] [":set", if levelGte Debug lvl then "v1" else "v0"
, maybe "" id (lookup cmpname eopts)
, ":load", mainmod, ":save", ":quit"]
bindir = binInstallDir cfg bindir = binInstallDir cfg
binexec = bindir </> name binexec = bindir </> name
in compiler CompilerOptions { comCommand = cmd } in compiler CompilerOptions { comCommand = cmd }
...@@ -791,7 +798,7 @@ uninstall (UninstallOptions Nothing Nothing) cfg _ _ = ...@@ -791,7 +798,7 @@ uninstall (UninstallOptions Nothing Nothing) cfg _ _ =
tryFindLocalPackageSpec "." |>= \pkgdir -> tryFindLocalPackageSpec "." |>= \pkgdir ->
loadPackageSpec pkgdir |>= \pkg -> loadPackageSpec pkgdir |>= \pkg ->
maybe (succeedIO ()) maybe (succeedIO ())
(\ (PackageExecutable name _) -> (\ (PackageExecutable name _ _) ->
let binexec = binInstallDir cfg </> name let binexec = binInstallDir cfg </> name
in ifFileExists binexec in ifFileExists binexec
(removeFile binexec >> (removeFile binexec >>
...@@ -958,7 +965,7 @@ docCmd opts cfg getRepoGC = ...@@ -958,7 +965,7 @@ docCmd opts cfg getRepoGC =
let docdir = maybe "cdoc" id (docDir opts) let docdir = maybe "cdoc" id (docDir opts)
exports = exportedModules pkg exports = exportedModules pkg
mainmod = maybe Nothing mainmod = maybe Nothing
(\ (PackageExecutable _ emain) -> Just emain) (\ (PackageExecutable _ emain _) -> Just emain)
(executableSpec pkg) (executableSpec pkg)
(docmods,apidoc) <- (docmods,apidoc) <-
maybe (if null exports maybe (if null exports
......
...@@ -100,9 +100,11 @@ data CompilerCompatibility = CompilerCompatibility String Disjunction ...@@ -100,9 +100,11 @@ data CompilerCompatibility = CompilerCompatibility String Disjunction
data PackageId = PackageId String Version data PackageId = PackageId String Version
--- The specification to generate an executable from the package. --- The specification to generate an executable from the package.
--- It consists of the name of the executable and the name of the main --- It consists of the name of the executable, the name of the main
--- module (which must contain an operation `main`). --- module (which must contain an operation `main`), and list
data PackageExecutable = PackageExecutable String String --- of options for various compilers (i.e., pairs of compiler name and
--- options for this compiler).
data PackageExecutable = PackageExecutable String String [(String,String)]
deriving (Eq,Show) deriving (Eq,Show)
--- The specification of a single test suite for a package. --- The specification of a single test suite for a package.
...@@ -239,9 +241,15 @@ packageSpecToJSON pkg = JObject $ ...@@ -239,9 +241,15 @@ packageSpecToJSON pkg = JObject $
revToJSON VersionAsTag = [("tag", JString "$version")] revToJSON VersionAsTag = [("tag", JString "$version")]
maybeExecToJSON = maybeExecToJSON =
maybe [] (\ (PackageExecutable ename emain) -> maybe [] (\ (PackageExecutable ename emain eopts) ->
[("executable", JObject [ ("name", JString ename) [("executable", JObject $ [ ("name", JString ename)
, ("main", JString emain)])]) , ("main", JString emain)] ++
exOptsToJSON eopts)])
where
exOptsToJSON eopts =
if null eopts
then []
else [("options", JObject $ map (\ (c,o) -> (c, JString o)) eopts)]
maybeTestToJSON = maybe [] (\tests -> [("testsuite", testsToJSON tests)]) maybeTestToJSON = maybe [] (\tests -> [("testsuite", testsToJSON tests)])
where where
...@@ -705,7 +713,22 @@ execSpecFromJObject :: [(String, JValue)] -> Either String PackageExecutable ...@@ -705,7 +713,22 @@ execSpecFromJObject :: [(String, JValue)] -> Either String PackageExecutable
execSpecFromJObject kv = execSpecFromJObject kv =
mandatoryString "name" kv $ \name -> mandatoryString "name" kv $ \name ->
optionalString "main" kv $ \main -> optionalString "main" kv $ \main ->
Right $ PackageExecutable name (maybe "Main" id main) case lookup "options" kv of
Nothing -> Right $ PackageExecutable name (maybe "Main" id main) []
Just (JObject o) -> case optionsFromObject o of
Left e -> Left e
Right os -> Right $ PackageExecutable name (maybe "Main" id main) os
Just _ -> Left "Expected an object for 'executable>options'"
where
optionsFromObject o =
let os = map (extractString . snd) o
in if any isLeft os
then Left $ head (lefts os)
else Right (zip (map fst o) (map fromRight os))
extractString s = case s of
JString s' -> Right s'
_ -> Left $ "'executable>options': values must be strings"
--- Reads a test suite specification from the key-value-pairs of a JObject. --- Reads a test suite specification from the key-value-pairs of a JObject.
testSuiteFromJObject :: [(String, JValue)] -> Either String [PackageTest] testSuiteFromJObject :: [(String, JValue)] -> Either String [PackageTest]
......
...@@ -76,7 +76,8 @@ writePackageConfig :: Config -> String -> Package -> IO (ErrorLogger ()) ...@@ -76,7 +76,8 @@ writePackageConfig :: Config -> String -> Package -> IO (ErrorLogger ())
writePackageConfig cfg pkgdir pkg = writePackageConfig cfg pkgdir pkg =
maybe (succeedIO ()) maybe (succeedIO ())
(\ configmod -> (\ configmod ->
let binname = maybe "" (\ (PackageExecutable n _) -> n) let binname = maybe ""
(\ (PackageExecutable n _ _) -> n)
(executableSpec pkg) (executableSpec pkg)
in if null configmod in if null configmod
then succeedIO () then succeedIO ()
......
...@@ -244,10 +244,14 @@ renderPackageInfo allinfos plain gc pkg = pPrint doc ...@@ -244,10 +244,14 @@ renderPackageInfo allinfos plain gc pkg = pPrint doc
execspec = case executableSpec pkg of execspec = case executableSpec pkg of
Nothing -> empty Nothing -> empty
Just (PackageExecutable n m) -> Just (PackageExecutable n m eopts) ->
boldText "Executable" <$$> boldText "Executable" <$$>
indent 4 (boldText "Name " <+> text n) <$$> indent 4 (boldText "Name " <+> text n) <$$>
indent 4 (boldText "Main module " <+> text m) indent 4 (boldText "Main module " <+> text m) <$$>
if null eopts
then empty
else indent 4 (boldText "Options ") <+>
align (vsep (map (\ (c,o) -> text $ c ++ ": " ++ o) eopts))
testsuites = case testSuite pkg of testsuites = case testSuite pkg of
Nothing -> [] Nothing -> []
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment