Commit 35704d59 authored by Michael Hanus's avatar Michael Hanus
Browse files

spicey and verification removed since it can be installed via CPM

parent e91c7ea9
......@@ -29,7 +29,7 @@ all: $(make_TOOLDIRS)
# Define dependencies between the different tools:
make_browser: | make_analysis make_CASS make_addtypes make_importcalls \
make_currydoc make_verification # avoid conflicts in analysis
make_currydoc # avoid conflicts in analysis
@$(MAKE) now_$@
make_analysis:
......@@ -39,13 +39,10 @@ make_CASS: | make_analysis
@$(MAKE) now_$@
make_currydoc: | make_analysis make_CASS \
make_currypp make_verification # avoid conflicts in analysis
make_currypp # avoid conflicts in analysis
@$(MAKE) now_$@
make_currypp: | make_analysis make_CASS make_currycheck make_verification
@$(MAKE) now_$@
make_verification: | make_analysis make_CASS make_currycheck
make_currypp: | make_analysis make_CASS make_currycheck
@$(MAKE) now_$@
make_%:
......@@ -85,7 +82,7 @@ $(uninstall_TOOLDIRS):
# Testing the tools
# Tools with test suites:
TESTTOOLS = optimize currypp runcurry currycheck spicey xmldata cpm
TESTTOOLS = optimize currypp runcurry currycheck xmldata cpm
# run the test suites to check the tools
.PHONY: runtest
......
This directory contains some documention for the tool:
manual.tex:
A short description to be included in the main manual of the Curry system.
\ No newline at end of file
\section{Spicey: An ER-based Web Framework}
\label{sec-spicey}
Spicey\index{Spicey} is a framework to support the implementation of
web-based systems in Curry. Spicey generates an initial implementation
from an entity-relationship (ER) description of the underlying
data. The generated implementation contains operations to create and
manipulate entities of the data model, supports authentication,
authorization, session handling, and the composition of individual
operations to user processes. Furthermore, the implementation ensures
the consistency of the database w.r.t. the data dependencies specified
in the ER model, i.e., updates initiated by the user cannot lead to an
inconsistent state of the database.
The idea of this tool, which is part of the distribution of \CYS,
is described in detail in \cite{HanusKoschnicke14TPLP}.
Thus, we describe only the basic steps to use this tool
in order to generate a web application.
First, one has to create a textual description of the
entity-relationship model
in a Curry program file as an (exported!) top-level operation type \code{ERD}
(w.r.t.\ the type definitions given in the system library
\code{Database.ERD})
and store it in some program file, e.g., \ccode{MyERD.curry}.
The directory \code{\cyshome/currytools/spicey/}
contains two examples for such ERD program files:
\begin{description}
\item[\code{BlogERD.curry}:]
This is a simple ER model for a blog with entries, comments,
and tags, as presented in the paper \cite{HanusKoschnicke14TPLP}.
\item[\code{UniERD.curry}:]
This is an ER model for university lectures as
presented in the paper \cite{BrasselHanusMueller08PADL}.
\end{description}
%
Then change to the directory in which you want to create
the project sources.
Execute the command\pindex{curry spiceup}\pindex{spiceup}
\begin{curry}
curry spiceup .../MyERD.curry
\end{curry}
with the path to the ERD term file as a parameter
You can also provide a path name, i.e., the name of a directory,
where the database files should be stored, e.g.,
\begin{curry}
curry spiceup --dbpath DBDIR .../MyERD.curry
\end{curry}
If the parameter \ccode{--dbpath DBDIR} is not provided,
then DBDIR is set to the current directory (\ccode{.}).
Since this specification will be used in the \emph{generated} web programs,
a relative database directory name will be relative to the place where
the web programs are stored.
In order to avoid such confusion, it might be better to specify
an absolute path name for the database directory.
After the generation of this project (see the generated file
\code{README.txt} for information about the generated project structure),
one can compile the generated programs by
\begin{curry}
make compile
\end{curry}
In order to generate the executable web application,
configure the generated \code{Makefile}
by adapting the variable \code{WEBSERVERDIR} to the location
where the compiled cgi programs should be stored, and run
\begin{curry}
make deploy
\end{curry}
After the successful compilation and deployment of all files,
the application is executable
in a web browser by selecting the URL \code{<URL of web dir>/spicey.cgi}.
import Database.ERD
blogERD :: ERD
blogERD =
ERD "Blog"
[Entity "Entry"
[Attribute "Title" (StringDom Nothing) Unique False,
Attribute "Text" (StringDom Nothing) NoKey False,
Attribute "Author" (StringDom Nothing) NoKey False,
Attribute "Date" (DateDom Nothing) NoKey False],
Entity "Comment"
[Attribute "Text" (StringDom Nothing) NoKey False,
Attribute "Author" (StringDom Nothing) NoKey False,
Attribute "Date" (DateDom Nothing) NoKey False],
Entity "Tag"
[Attribute "Name" (StringDom Nothing) Unique False]
]
[Relationship "Commenting"
[REnd "Entry" "commentsOn" (Exactly 1),
REnd "Comment" "isCommentedBy" (Between 0 Infinite)],
Relationship "Tagging"
[REnd "Entry" "tags" (Between 0 Infinite),
REnd "Tag" "tagged" (Between 0 Infinite)]
]
import Database.ERD
uniERD :: ERD
uniERD =
ERD "Uni"
[Entity "Student" [Attribute "MatNum" (IntDom Nothing) PKey False,
Attribute "Name" (StringDom Nothing) NoKey False,
Attribute "Firstname" (StringDom Nothing) NoKey False,
Attribute "Email" (StringDom Nothing) NoKey True],
Entity "Lecture" [Attribute "Id" (IntDom Nothing) PKey False,
Attribute "Title" (StringDom Nothing) Unique False,
Attribute "Hours" (IntDom (Just 4)) NoKey False],
Entity "Lecturer" [Attribute "Id" (IntDom Nothing) PKey False,
Attribute "Name" (StringDom Nothing) NoKey False,
Attribute "Firstname" (StringDom Nothing) NoKey False],
Entity "Group" [Attribute "Time" (StringDom Nothing) NoKey False]]
[Relationship "Teaching"
[REnd "Lecturer" "taught_by" (Exactly 1),
REnd "Lecture" "teaches" (Between 0 Infinite)],
Relationship "Participation"
[REnd "Student" "participated_by" (Between 0 Infinite),
REnd "Lecture" "participates" (Between 0 Infinite)],
Relationship "Membership"
[REnd "Student" "consists_of" (Exactly 3),
REnd "Group" "member_of" (Between 0 Infinite)]]
#!/bin/sh
# Shell script to test the current set of examples
CURRYBIN=`cd ../../../bin && pwd`
VERBOSE=no
if [ "$1" = "-v" ] ; then
VERBOSE=yes
fi
LOGFILE=`pwd`/xxx$$
/bin/rm -f $LOGFILE
PATH=$CURRYBIN:$PATH
export PATH
compile_spicey()
{
ERD=$1
/bin/rm -rf spicey_$ERD
mkdir spicey_$ERD
cd spicey_$ERD
$CURRYBIN/curry spiceup ../"$ERD"ERD.curry
echo "Compiling spicey_$ERD..."
make CURRYOPTIONS="$REPL_OPTS :set parser -Wnone" compile && cd ..
}
compile_spicey_and_check()
{
if [ $VERBOSE = yes ] ; then
compile_spicey $1
if [ $? -gt 0 ] ; then
exit 1
fi
else
compile_spicey $1 > $LOGFILE 2>&1
if [ $? -gt 0 ] ; then
echo "ERROR in Spicey generation:"
cat $LOGFILE
exit 1
fi
fi
}
compile_spicey_and_check Blog
# omitted due to bug in controller generation:
#compile_spicey_and_check Uni
################ end of tests ####################
# Clean:
/bin/rm -rf $LOGFILE spicey_Blog spicey_Uni
##############################################################################
# Makefile for Spicey Web Framework
##############################################################################
# binary
TOOL = $(BINDIR)/$(CURRYSYSTEM)-spiceup
# The directory containg the project generator
PROJECT_GEN_DIR=project_generator
# Some modules required by the Spicey implementation:
DEPS = $(PROJECT_GEN_DIR)/SpiceUp.curry scaffolding/*.curry \
$(LIBDIR)/AbstractCurry/*.curry $(LIBDIR)/Database/ERD*.curry
.PHONY: all compile install clean uninstall runtest
all: install
compile: spiceup
install: compile
rm -f $(TOOL) $(BINDIR)/spiceup
cd $(BINDIR) && ln -s ../currytools/spicey/spiceup $(notdir $(TOOL))
clean:
$(CLEANCURRY) -r
rm -f spiceup
uninstall: clean
rm -f $(TOOL)
# generate executable for Spicey generator:
spiceup: $(DEPS)
CURRYPATH=scaffolding && export CURRYPATH && \
cd $(PROJECT_GEN_DIR) && \
$(REPL) $(REPL_OPTS) :set path ../scaffolding :load SpiceUp :save :q
mv $(PROJECT_GEN_DIR)/SpiceUp $@
# run the test suite
runtest:
cd Examples && ./test.sh $(RUNTESTPARAMS)
Welcome to the Spicey web application framework!
To generate an application, follow the steps below.
1. Create a term file describing your entity-relationship model
(see the file "Blog.erdterm" as an example).
2. Change to the directory in which you want to create the project.
3. From there execute `curry spiceup` and supply the name of the term file,
e.g.,
curry spiceup .../Blog.erdterm
This generates the complete source code of the initial application
(see the generated file README.txt for some explanations).
You can also provide a path name, i.e., the name of a directory,
where the database files should be stored, e.g.,
curry spiceup --dbpath DBDIR .../Blog.erdterm
If the parameter "--dbpath DBDIR" is not provided, then DBDIR is the
current directory ("."). Since will be used in the _generated_ cgi
programs, a relative directory will be relative to the place where
the cgi programs are stored.
4. Compile the generated programs by `make compile`.
5. Configure the Makefile (variable WEBSERVERDIR) and execute
`make deploy` to deploy the web application.
6. After the successful compilation, the application is executable
in a web browser by loading `<URL of web dir>/spicey.cgi`.
#!/bin/bash
# Script to support the evolution of model-based software development
# with Spicey.
# One can use this script of the ER model is changed and one wants
# to generate a new Spicey system based on the new model and include
# all changes made to the old Spicey system.
# These changes are adapted to the new system via the revision control system
# git. Hence, conflicts might occur in the end that must be manually solved!
if [ $# -ne 4 ] ; then
echo "Illegal number of arguments, usage:"
echo "$0 ORGPATH MYORGPATH NEWPATH TARGETPATH"
echo "where"
echo "ORGPATH : path to original software (old ER-scheme)"
echo "MYORGPATH : path to original software (old ER-scheme) with user changes"
echo "NEWPATH : path to new software (new ER-scheme)"
echo "TARGETPATH: path to save new software with user changes"
exit 1
fi
ORGPATH=$1
MYORGPATH=$2
NEWPATH=$3
TARGETPATH=$4
GIT=`which git`
if [ -z "$GIT" ] ; then
echo "Revision control system 'git' not found!"
exit 1
fi
if [ -d "$ORGPATH" ] ; then
ORGPATH=`cd $ORGPATH && pwd`
else
echo "Path to original software '$ORGPATH' does not exist!"
exit 1
fi
if [ -d "$MYORGPATH" ] ; then
MYORGPATH=`cd $MYORGPATH && pwd`
else
echo "Original user-changed software path '$MYORGPATH' does not exist!"
exit 1
fi
if [ -d "$NEWPATH" ] ; then
NEWPATH=`cd $NEWPATH && pwd`
else
echo "Path to new software '$NEWPATH' does not exist!"
exit 1
fi
if [ ! -d "$TARGETPATH" ] ; then
echo "Target software path '$TARGETPATH' does not exist, trying to create it..."
mkdir $TARGETPATH
fi
cd $TARGETPATH
$GIT init
cp -r "$ORGPATH"/* .
$GIT add "*"
$GIT commit -m "start"
$GIT branch newscheme
cp -r "$MYORGPATH"/* .
$GIT add *
$GIT commit -m "update to myorg"
$GIT checkout newscheme
cp -r "$NEWPATH"/* .
$GIT add *
$GIT commit -m "update to new scheme"
$GIT checkout master
$GIT merge newscheme
echo "Status after merging:"
$GIT status
-- Main module to generate the initial Spicey application
import Database.ERDGoodies (storeERDFromProgram)
import Directory
import Distribution
import FilePath ((</>))
import List (isSuffixOf, last)
import System (system, getArgs, exitWith)
import SpiceyScaffolding
systemBanner :: String
systemBanner =
let bannerText = "Spicey Web Framework (Version of 12/01/17)"
bannerLine = take (length bannerText) (repeat '-')
in bannerLine ++ "\n" ++ bannerText ++ "\n" ++ bannerLine
data FileMode = Exec | NoExec
setFileMode :: FileMode -> String -> IO ()
setFileMode fmode filename =
if fmode==Exec then system ("chmod +x \"" ++ filename ++ "\"") >> done
else done
data DirTree =
Directory String [DirTree] -- a directory to be created
| ResourceFile FileMode String -- a file to be copied from resource directory
| ResourcePatchFile FileMode String (String->String) -- file to be copied from
-- resource directory where its contents is patched by the given function
| GeneratedFromERD (String -> String -> String -> String -> IO ())
-- takes an operation to generate code from ERD specification
spiceyStructure :: DirTree
spiceyStructure =
Directory "." [
ResourceFile NoExec "README.txt",
ResourcePatchFile NoExec "Makefile" replaceCurryDir,
ResourceFile NoExec "Main.curry",
Directory "system" [
ResourceFile NoExec "Spicey.curry",
ResourceFile NoExec "Routes.curry",
ResourceFile NoExec "Crypto.curry",
ResourceFile NoExec "Session.curry",
ResourceFile NoExec "SessionInfo.curry",
ResourceFile NoExec "Authorization.curry",
ResourceFile NoExec "Authentication.curry",
ResourceFile NoExec "Processes.curry" ],
Directory "views" [
ResourceFile NoExec "SpiceySystemView.curry",
GeneratedFromERD createViewsForTerm,
GeneratedFromERD createHtmlHelpersForTerm ],
Directory "controllers" [
ResourceFile NoExec "SpiceySystemController.curry",
GeneratedFromERD createControllersForTerm ],
Directory "models" [
GeneratedFromERD createModelsForTerm ],
Directory "config" [
ResourceFile NoExec "UserProcesses.curry",
GeneratedFromERD createRoutesForTerm ],
Directory "public" [
ResourceFile NoExec "index.html",
ResourceFile NoExec "favicon.ico",
Directory "css" [
ResourceFile NoExec "bootstrap.min.css",
ResourceFile NoExec "spicey.css"
],
Directory "js" [
ResourceFile NoExec "bootstrap.min.js",
ResourceFile NoExec "jquery.min.js"
],
Directory "fonts" [
ResourceFile NoExec "glyphicons-halflings-regular.eot",
ResourceFile NoExec "glyphicons-halflings-regular.svg",
ResourceFile NoExec "glyphicons-halflings-regular.ttf",
ResourceFile NoExec "glyphicons-halflings-regular.woff",
ResourceFile NoExec "glyphicons-halflings-regular.woff2"
],
Directory "images" [
ResourceFile NoExec "spicey-logo.png",
ResourceFile NoExec "text.png",
ResourceFile NoExec "time.png",
ResourceFile NoExec "number.png",
ResourceFile NoExec "foreign.png"
]
]
]
resourceDirectoryLocal :: String
resourceDirectoryLocal = "resource_files" -- script directory gets prepended
-- Replace every occurrence of "XXXCURRYBINXXX" by installDir++"/bin"
replaceCurryDir :: String -> String
replaceCurryDir [] = []
replaceCurryDir (c:cs)
| c=='X' && take 13 cs == "XXCURRYBINXXX"
= installDir ++ "/bin" ++ replaceCurryDir (drop 13 cs)
| otherwise = c : replaceCurryDir cs
prependPath :: String -> String -> String
prependPath path name | last path == '/' = path ++ name
| otherwise = path ++ "/" ++ name
copyFileLocal :: FileMode -> String -> String -> String -> IO ()
copyFileLocal fmode path generator_path filename = do
let infile = prependPath (prependPath generator_path resourceDirectoryLocal)
filename
let outfile = prependPath path filename
system $ "cp \"" ++ infile ++ "\" \"" ++ outfile ++ "\""
setFileMode fmode outfile
-- checks if given path exists (file or directory) and executes
-- given action if not
ifNotExistsDo :: String -> IO () -> IO ()
ifNotExistsDo path cmd = do
fileExists <- doesFileExist path
dirExists <- doesDirectoryExist path
if fileExists || dirExists
then putStrLn ("Skipping " ++ path ++ " ...")
else cmd
createStructure :: String -> String -> String -> String -> DirTree -> IO ()
createStructure target_path generator_path _ _ (ResourceFile fmode filename) =
let full_path = prependPath target_path filename
in ifNotExistsDo full_path
(putStrLn ("Creating file " ++ full_path ++ " ...") >>
copyFileLocal fmode target_path generator_path filename)
createStructure target_path generator_path _ _
(ResourcePatchFile fmode filename f) =
let full_path = prependPath target_path filename
in ifNotExistsDo full_path $ do
putStrLn ("Creating file " ++ full_path ++ " ...")
cnt <- readFile (prependPath (prependPath generator_path
resourceDirectoryLocal)
filename)
let outfile = prependPath target_path filename
writeFile outfile (f cnt)
setFileMode fmode outfile
createStructure target_path generator_path term_path db_path
(Directory dirname subtree) = do
let full_path = prependPath target_path dirname
ifNotExistsDo full_path (putStrLn ("Creating directory "++full_path++" ...")
>> createDirectory full_path)
foldl (\a b -> a >> createStructure full_path generator_path term_path db_path b)
done subtree
createStructure target_path generator_path term_path db_path
(GeneratedFromERD generatorFunction) = do
putStrLn $ "Generating from term file " ++ term_path ++ " ..."
generatorFunction generator_path term_path target_path db_path
--- The main operation to start the scaffolding.
main :: IO ()
main = do
putStrLn systemBanner
args <- getArgs
case args of
["-h"] -> putStrLn helpText >> exitWith 0
["--help"] -> putStrLn helpText >> exitWith 0
["-?"] -> putStrLn helpText >> exitWith 0
["--dbpath",dbpath,orgfile] -> createStructureWith orgfile dbpath
[orgfile] -> createStructureWith orgfile "."
_ -> putStrLn ("Wrong arguments!\n" ++ helpText) >> exitWith 1
putStrLn $ take 70 (repeat '-')
putStrLn "Source files for the application generated.\n"
putStrLn "IMPORTANT NOTE: Before you deploy your web application (by 'make deploy'),"
putStrLn "you should define the variable WEBSERVERDIR in the Makefile!"
where
createStructureWith orgfile dbpath = do
-- The directory containing the project generator:
let generatordir = installDir </> "currytools"
</> "spicey" </> "project_generator"
exfile <- doesFileExist orgfile
unless exfile $ error ("File `" ++ orgfile ++ "' does not exist!")
termfile <- if ".curry" `isSuffixOf` orgfile ||
".lcurry" `isSuffixOf` orgfile
then storeERDFromProgram orgfile
else return orgfile
curdir <- getCurrentDirectory
createStructure curdir generatordir termfile dbpath spiceyStructure
-- delete generated ERD term file:
when (orgfile /= termfile) $ removeFile termfile
helpText :: String
helpText = unlines $
[ "Usage:"
, ""
, " curry spiceup [--dbpath <dirpath>] <ERD program file>"
, ""
, "Parameters:"
, "--dbpath <dir> : name of the directory where DB files are stored"
, "<ERD program file>: name of Curry program file containing ERD definition"
]
\ No newline at end of file
----------------------------------------------------------------------------
--- This library contains operations to support the management of
--- user authentication. It provides operations for password
--- generation, password hashing (based on hashing algorithms from Unix),
--- and storing logins in sessions.
---
--- @author Michael Hanus
----------------------------------------------------------------------------
module Authentication (
getUserHash, randomPassword,
getSessionLogin, loginToSession, logoutFromSession
) where
import SessionInfo
import Crypto
--------------------------------------------------------------------------
-- Operations for hashing.
--- Gets a hash string for a user name and password. The generated
--- hash string should be stored for the user instead of the password.
getUserHash :: String -> String -> IO String
getUserHash username userpassword = do
let systemkey = "3spicey5" -- change this key for every spicey instance
getHash (username++userpassword++systemkey)
--- Returns a random password (a hexadecimal string) of a particular length.
--- @param length - length of the desired password
--- @return the random password
randomPassword :: Int -> IO String
randomPassword = randomString
--------------------------------------------------------------------------
-- Operations for storing logins in the current session.
--- Gets the login name of the current session
--- (or the Nothing if there is no login).
getSessionLogin :: IO (Maybe String)
getSessionLogin = getUserSessionInfo >>= return . userLoginOfSession
--- Stores a login name in the current session.
--- The authentication has to be done before!
loginToSession :: String -> IO ()
loginToSession loginname =
updateUserSessionInfo (setUserLoginOfSession (Just loginname))
--- removes the login name from the current session.
logoutFromSession :: IO ()
logoutFromSession = updateUserSessionInfo (setUserLoginOfSession Nothing)
--------------------------------------------------------------------------
--- This module specifies the access authorization to web pages.
module Authorization(AccessType(..), AccessResult(..),
checkAuthorization) where
import Spicey(Controller,displayError)
import HTML
import SessionInfo
--- The various kinds of operations applied to an entity.
data AccessType a = NewEntity | ShowEntity a | UpdateEntity a | DeleteEntity a
| ListEntities
--- The result of checking an authorization. The access is either granted
--- or denied with a string explaining the reason.
data AccessResult = AccessGranted | AccessDenied String
--- Checks the results of an authoriation access.
--- If the access is granted, we proceed with the given controller