module Swish ( SwishStatus(..)
, SwishAction
, runSwish
, runSwishActions
, displaySwishHelp
, splitArguments
, validateCommands
) where
import Swish.Commands
( swishFormat
, swishBase
, swishInput
, swishOutput
, swishMerge
, swishCompare
, swishGraphDiff
, swishScript
)
import Swish.Monad (SwishStateIO, SwishState(..), SwishStatus(..)
, SwishFormat(..)
, emptyState)
import Swish.QName (qnameFromURI)
import Control.Monad.State (execStateT)
import Control.Monad (liftM)
import Network.URI (parseURI)
import Data.Char (isSpace)
import Data.Either (partitionEithers)
import System.Exit (ExitCode(ExitSuccess, ExitFailure))
usageText :: [String]
usageText :: [String]
usageText =
[ "Swish: Read, merge, write, compare and process RDF graphs."
, ""
, "Usage: swish option option ..."
, ""
, "where the options are processed from left to right, and may be"
, "any of the following:"
, "-h display this message."
, "-? display this message."
, "-v display Swish version and quit."
, "-q do not display Swish version on start up."
, "-nt use Ntriples format for subsequent input and output."
, "-ttl use Turtle format for subsequent input and output."
, "-n3 use Notation3 format for subsequent input and output (default)"
, "-i[=file] read file in selected format into the graph workspace,"
, " replacing any existing graph."
, "-m[=file] merge file in selected format with the graph workspace."
, "-c[=file] compare file in selected format with the graph workspace."
, "-d[=file] show graph differences between the file in selected"
, " format and the graph workspace. Differences are displayed"
, " to the standard output stream."
, "-o[=file] write the graph workspace to a file in the selected format."
, "-s[=file] read and execute Swish script commands from the named file."
, "-b[=base] set or clear the base URI. The semantics of this are not"
, " fully defined yet."
, ""
, " If an optional filename value is omitted, the standard input"
, " or output stream is used, as appropriate."
, ""
, "Exit status codes:"
, "Success - operation completed successfully/graphs compare equal"
, "1 - graphs compare different"
, "2 - input data format error"
, "3 - file access problem"
, "4 - command line error"
, "5 - script file execution error"
, ""
, "Examples:"
, ""
, "swish -i=file"
, " read file as Notation3, and report any syntax errors."
, "swish -i=file1 -o=file2"
, " read file1 as Notation3, report any syntax errors, and output the"
, " resulting graph as reformatted Notation3 (the output format"
, " is not perfect but may be improved)."
, "swish -nt -i=file -n3 -o"
, " read file as NTriples and output as Notation3 to the screen."
, "swich -i=file1 -c=file2"
, " read file1 and file2 as notation3, report any syntax errors, and"
, " if both are OK, compare the resulting graphs to indicate whether"
, " or not they are equivalent."
]
displaySwishHelp :: IO ()
displaySwishHelp :: IO ()
displaySwishHelp = (String -> IO ()) -> [String] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ String -> IO ()
putStrLn [String]
usageText
splitArguments :: [String] -> ([String], [String])
splitArguments :: [String] -> ([String], [String])
splitArguments = [Either String String] -> ([String], [String])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either String String] -> ([String], [String]))
-> ([String] -> [Either String String])
-> [String]
-> ([String], [String])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Either String String)
-> [String] -> [Either String String]
forall a b. (a -> b) -> [a] -> [b]
map String -> Either String String
splitArgument
splitArgument :: String -> Either String String
splitArgument :: String -> Either String String
splitArgument "-?" = String -> Either String String
forall a b. a -> Either a b
Left "-h"
splitArgument "-h" = String -> Either String String
forall a b. a -> Either a b
Left "-h"
splitArgument "-v" = String -> Either String String
forall a b. a -> Either a b
Left "-v"
splitArgument "-q" = String -> Either String String
forall a b. a -> Either a b
Left "-q"
splitArgument x :: String
x = String -> Either String String
forall a b. b -> Either a b
Right String
x
newtype SwishAction = SA (String, SwishStateIO ())
instance Show SwishAction where
show :: SwishAction -> String
show (SA (lbl :: String
lbl,_)) = "SwishAction: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
lbl
validateCommands :: [String] -> Either (String, SwishStatus) [SwishAction]
validateCommands :: [String] -> Either (String, SwishStatus) [SwishAction]
validateCommands args :: [String]
args =
let (ls :: [(String, SwishStatus)]
ls, rs :: [SwishAction]
rs) = [Either (String, SwishStatus) SwishAction]
-> ([(String, SwishStatus)], [SwishAction])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ((String -> Either (String, SwishStatus) SwishAction)
-> [String] -> [Either (String, SwishStatus) SwishAction]
forall a b. (a -> b) -> [a] -> [b]
map String -> Either (String, SwishStatus) SwishAction
validateCommand [String]
args)
in case [(String, SwishStatus)]
ls of
(e :: (String, SwishStatus)
e:_) -> (String, SwishStatus) -> Either (String, SwishStatus) [SwishAction]
forall a b. a -> Either a b
Left (String, SwishStatus)
e
[] -> [SwishAction] -> Either (String, SwishStatus) [SwishAction]
forall a b. b -> Either a b
Right [SwishAction]
rs
validateCommand :: String -> Either (String, SwishStatus) SwishAction
validateCommand :: String -> Either (String, SwishStatus) SwishAction
validateCommand cmd :: String
cmd =
let (nam :: String
nam,more :: String
more) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
=='=') String
cmd
arg :: String
arg = Int -> ShowS
forall a. Int -> [a] -> [a]
drop 1 String
more
marg :: Maybe String
marg = if String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
arg then Maybe String
forall a. Maybe a
Nothing else String -> Maybe String
forall a. a -> Maybe a
Just String
arg
wrap :: (Maybe String -> SwishStateIO ()) -> Either a SwishAction
wrap f :: Maybe String -> SwishStateIO ()
f = SwishAction -> Either a SwishAction
forall a b. b -> Either a b
Right (SwishAction -> Either a SwishAction)
-> SwishAction -> Either a SwishAction
forall a b. (a -> b) -> a -> b
$ (String, SwishStateIO ()) -> SwishAction
SA (String
cmd, Maybe String -> SwishStateIO ()
f Maybe String
marg)
wrap1 :: SwishStateIO () -> Either a SwishAction
wrap1 f :: SwishStateIO ()
f = SwishAction -> Either a SwishAction
forall a b. b -> Either a b
Right (SwishAction -> Either a SwishAction)
-> SwishAction -> Either a SwishAction
forall a b. (a -> b) -> a -> b
$ (String, SwishStateIO ()) -> SwishAction
SA (String
cmd, SwishStateIO ()
f)
in case String
nam of
"-ttl" -> SwishStateIO () -> Either (String, SwishStatus) SwishAction
forall a. SwishStateIO () -> Either a SwishAction
wrap1 (SwishStateIO () -> Either (String, SwishStatus) SwishAction)
-> SwishStateIO () -> Either (String, SwishStatus) SwishAction
forall a b. (a -> b) -> a -> b
$ SwishFormat -> SwishStateIO ()
swishFormat SwishFormat
Turtle
"-nt" -> SwishStateIO () -> Either (String, SwishStatus) SwishAction
forall a. SwishStateIO () -> Either a SwishAction
wrap1 (SwishStateIO () -> Either (String, SwishStatus) SwishAction)
-> SwishStateIO () -> Either (String, SwishStatus) SwishAction
forall a b. (a -> b) -> a -> b
$ SwishFormat -> SwishStateIO ()
swishFormat SwishFormat
NT
"-n3" -> SwishStateIO () -> Either (String, SwishStatus) SwishAction
forall a. SwishStateIO () -> Either a SwishAction
wrap1 (SwishStateIO () -> Either (String, SwishStatus) SwishAction)
-> SwishStateIO () -> Either (String, SwishStatus) SwishAction
forall a b. (a -> b) -> a -> b
$ SwishFormat -> SwishStateIO ()
swishFormat SwishFormat
N3
"-i" -> (Maybe String -> SwishStateIO ())
-> Either (String, SwishStatus) SwishAction
forall a. (Maybe String -> SwishStateIO ()) -> Either a SwishAction
wrap Maybe String -> SwishStateIO ()
swishInput
"-m" -> (Maybe String -> SwishStateIO ())
-> Either (String, SwishStatus) SwishAction
forall a. (Maybe String -> SwishStateIO ()) -> Either a SwishAction
wrap Maybe String -> SwishStateIO ()
swishMerge
"-c" -> (Maybe String -> SwishStateIO ())
-> Either (String, SwishStatus) SwishAction
forall a. (Maybe String -> SwishStateIO ()) -> Either a SwishAction
wrap Maybe String -> SwishStateIO ()
swishCompare
"-d" -> (Maybe String -> SwishStateIO ())
-> Either (String, SwishStatus) SwishAction
forall a. (Maybe String -> SwishStateIO ()) -> Either a SwishAction
wrap Maybe String -> SwishStateIO ()
swishGraphDiff
"-o" -> (Maybe String -> SwishStateIO ())
-> Either (String, SwishStatus) SwishAction
forall a. (Maybe String -> SwishStateIO ()) -> Either a SwishAction
wrap Maybe String -> SwishStateIO ()
swishOutput
"-b" -> String -> Maybe String -> Either (String, SwishStatus) SwishAction
validateBase String
cmd Maybe String
marg
"-s" -> (Maybe String -> SwishStateIO ())
-> Either (String, SwishStatus) SwishAction
forall a. (Maybe String -> SwishStateIO ()) -> Either a SwishAction
wrap Maybe String -> SwishStateIO ()
swishScript
_ -> (String, SwishStatus) -> Either (String, SwishStatus) SwishAction
forall a b. a -> Either a b
Left ("Invalid command line argument: "String -> ShowS
forall a. [a] -> [a] -> [a]
++String
cmd, SwishStatus
SwishArgumentError)
swishCommands :: [SwishAction] -> SwishStateIO ()
swishCommands :: [SwishAction] -> SwishStateIO ()
swishCommands = (SwishAction -> SwishStateIO ())
-> [SwishAction] -> SwishStateIO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ SwishAction -> SwishStateIO ()
swishCommand
swishCommand :: SwishAction -> SwishStateIO ()
swishCommand :: SwishAction -> SwishStateIO ()
swishCommand (SA (_,act :: SwishStateIO ()
act)) = SwishStateIO ()
act
validateBase :: String -> Maybe String -> Either (String, SwishStatus) SwishAction
validateBase :: String -> Maybe String -> Either (String, SwishStatus) SwishAction
validateBase arg :: String
arg Nothing = SwishAction -> Either (String, SwishStatus) SwishAction
forall a b. b -> Either a b
Right (SwishAction -> Either (String, SwishStatus) SwishAction)
-> SwishAction -> Either (String, SwishStatus) SwishAction
forall a b. (a -> b) -> a -> b
$ (String, SwishStateIO ()) -> SwishAction
SA (String
arg, Maybe QName -> SwishStateIO ()
swishBase Maybe QName
forall a. Maybe a
Nothing)
validateBase arg :: String
arg (Just b :: String
b) =
case String -> Maybe URI
parseURI String
b Maybe URI -> (URI -> Maybe QName) -> Maybe QName
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= URI -> Maybe QName
qnameFromURI of
j :: Maybe QName
j@(Just _) -> SwishAction -> Either (String, SwishStatus) SwishAction
forall a b. b -> Either a b
Right (SwishAction -> Either (String, SwishStatus) SwishAction)
-> SwishAction -> Either (String, SwishStatus) SwishAction
forall a b. (a -> b) -> a -> b
$ (String, SwishStateIO ()) -> SwishAction
SA (String
arg, Maybe QName -> SwishStateIO ()
swishBase Maybe QName
j)
_ -> (String, SwishStatus) -> Either (String, SwishStatus) SwishAction
forall a b. a -> Either a b
Left ("Invalid base URI <" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
b String -> ShowS
forall a. [a] -> [a] -> [a]
++ ">", SwishStatus
SwishArgumentError)
runSwish :: String -> IO ExitCode
runSwish :: String -> IO ExitCode
runSwish cmdline :: String
cmdline = do
let args :: [String]
args = (Char -> Bool) -> String -> [String]
forall a. (a -> Bool) -> [a] -> [[a]]
breakAll Char -> Bool
isSpace String
cmdline
(_, cmds :: [String]
cmds) = [String] -> ([String], [String])
splitArguments [String]
args
case [String] -> Either (String, SwishStatus) [SwishAction]
validateCommands [String]
cmds of
Left (emsg :: String
emsg, ecode :: SwishStatus
ecode) -> do
String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ "Swish exit: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
emsg
ExitCode -> IO ExitCode
forall (m :: * -> *) a. Monad m => a -> m a
return (ExitCode -> IO ExitCode) -> ExitCode -> IO ExitCode
forall a b. (a -> b) -> a -> b
$ Int -> ExitCode
ExitFailure (Int -> ExitCode) -> Int -> ExitCode
forall a b. (a -> b) -> a -> b
$ SwishStatus -> Int
forall a. Enum a => a -> Int
fromEnum SwishStatus
ecode
Right acts :: [SwishAction]
acts -> do
SwishStatus
ec <- [SwishAction] -> IO SwishStatus
runSwishActions [SwishAction]
acts
case SwishStatus
ec of
SwishSuccess -> ExitCode -> IO ExitCode
forall (m :: * -> *) a. Monad m => a -> m a
return ExitCode
ExitSuccess
_ -> do
String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ "Swish exit: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ SwishStatus -> String
forall a. Show a => a -> String
show SwishStatus
ec
ExitCode -> IO ExitCode
forall (m :: * -> *) a. Monad m => a -> m a
return (ExitCode -> IO ExitCode) -> ExitCode -> IO ExitCode
forall a b. (a -> b) -> a -> b
$ Int -> ExitCode
ExitFailure (Int -> ExitCode) -> Int -> ExitCode
forall a b. (a -> b) -> a -> b
$ SwishStatus -> Int
forall a. Enum a => a -> Int
fromEnum SwishStatus
ec
breakAll :: (a -> Bool) -> [a] -> [[a]]
breakAll :: (a -> Bool) -> [a] -> [[a]]
breakAll _ [] = []
breakAll p :: a -> Bool
p s :: [a]
s = let (h :: [a]
h,s' :: [a]
s') = (a -> Bool) -> [a] -> ([a], [a])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break a -> Bool
p [a]
s
in [a]
h [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: (a -> Bool) -> [a] -> [[a]]
forall a. (a -> Bool) -> [a] -> [[a]]
breakAll a -> Bool
p (Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop 1 [a]
s')
runSwishActions :: [SwishAction] -> IO SwishStatus
runSwishActions :: [SwishAction] -> IO SwishStatus
runSwishActions acts :: [SwishAction]
acts = SwishState -> SwishStatus
exitcode (SwishState -> SwishStatus) -> IO SwishState -> IO SwishStatus
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
`liftM` SwishStateIO () -> SwishState -> IO SwishState
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m s
execStateT ([SwishAction] -> SwishStateIO ()
swishCommands [SwishAction]
acts) SwishState
emptyState