{-# LANGUAGE OverloadedStrings #-}---------------------------------------------------------------------------------- See end of this file for licence information.---------------------------------------------------------------------------------- |-- Module : SwishCommands-- Copyright : (c) 2003, Graham Klyne, 2009 Vasili I Galchin, 2011 Douglas Burke-- License : GPL V2---- Maintainer : Douglas Burke-- Stability : experimental-- Portability : OverloadedStrings---- SwishCommands: functions to deal with indivudual Swish command options.----------------------------------------------------------------------------------moduleSwish.RDF.SwishCommands(swishFormat,swishBase-- , swishVerbose,swishInput,swishOutput,swishMerge,swishCompare,swishGraphDiff,swishScript)whereimportSwish.RDF.SwishMonad(SwishStateIO,SwishState(..),SwishStatus(..),setFormat,setBase,setGraph,resetInfo,resetError,setStatus-- , setVerbose,SwishFormat(..),swishError,reportLine)importSwish.RDF.SwishScript(parseScriptFromText)importSwish.RDF.GraphPartition(GraphPartition(..),partitionGraph,comparePartitions,partitionShowP)importSwish.RDF.RDFGraph(RDFGraph,merge)importqualifiedSwish.RDF.TurtleFormatterasTTLFimportqualifiedSwish.RDF.N3FormatterasN3FimportqualifiedSwish.RDF.NTFormatterasNTFimportSwish.RDF.TurtleParser(parseTurtle)importSwish.RDF.N3Parser(parseN3)importSwish.RDF.NTParser(parseNT)importSwish.RDF.RDFParser(appendURIs)importSwish.RDF.GraphClass(LDGraph(..),Label(..))importSwish.Utils.QName(QName,qnameFromURI,qnameFromFilePath,getQNameURI)importSystem.IO(Handle,openFile,IOMode(..),hPutStr,hPutStrLn,hClose,hIsReadable,hIsWritable,stdin,stdout)importNetwork.URI(parseURIReference)importControl.Monad.Trans(MonadTrans(..))importControl.Monad.State(modify,gets)importControl.Monad(liftM,when)importqualifiedData.Text.LazyasTimportqualifiedData.Text.Lazy.IOasIOimportSystem.IO.ErrorimportData.Maybe(isJust,fromMaybe)-------------------------------------------------------------- Set file format to supplied value-------------------------------------------------------------- the second argument allows for options to be passed along-- with the format (a la cwm) but this is not supported yet--swishFormat::SwishFormat->MaybeString->SwishStateIO()swishFormatfmt_=modify(setFormatfmt)-------------------------------------------------------------- Set base URI to supplied value-------------------------------------------------------------- the Maybe String argument is ignored (a result of a lack of-- design with the command-line processing)--swishBase::MaybeQName->MaybeString->SwishStateIO()swishBasemb_=modify(setBasemb)-------------------------------------------------------------- Read graph from named file------------------------------------------------------------swishInput::MaybeString->SwishStateIO()swishInputfnam=swishReadGraphfnam>>=maybe(return())(modify.setGraph)-------------------------------------------------------------- Merge graph from named file------------------------------------------------------------swishMerge::MaybeString->SwishStateIO()swishMergefnam=swishReadGraphfnam>>=maybe(return())(modify.mergeGraph)mergeGraph::RDFGraph->SwishState->SwishStatemergeGraphgrstate=state{graph=newgr}wherenewgr=mergegr(graphstate)-------------------------------------------------------------- Compare graph from named file------------------------------------------------------------swishCompare::MaybeString->SwishStateIO()swishComparefnam=swishReadGraphfnam>>=maybe(return())compareGraphcompareGraph::RDFGraph->SwishStateIO()compareGraphgr=dooldGr<-getsgraphletexitCode=ifgr==oldGrthenSwishSuccesselseSwishGraphCompareErrormodify$setStatusexitCode-------------------------------------------------------------- Display graph differences from named file------------------------------------------------------------swishGraphDiff::MaybeString->SwishStateIO()swishGraphDifffnam=swishReadGraphfnam>>=maybe(return())diffGraphdiffGraph::RDFGraph->SwishStateIO()diffGraphgr=dooldGr<-getsgraphletp1=partitionGraph(getArcsoldGr)p2=partitionGraph(getArcsgr)diffs=comparePartitionsp1p2swishWriteFile(swishOutputDiffsdiffs)NothingswishOutputDiffs::(Labellb)=>[(Maybe(GraphPartitionlb),Maybe(GraphPartitionlb))]->MaybeString->Handle->SwishStateIO()swishOutputDiffsdiffsfnamhnd=dolift$hPutStrLnhnd("Graph differences: "++show(lengthdiffs))mapM_(swishOutputDifffnamhnd)(zip[1..]diffs)swishOutputDiff::(Labellb)=>MaybeString->Handle->(Int,(Maybe(GraphPartitionlb),Maybe(GraphPartitionlb)))->SwishStateIO()swishOutputDifffnamhnd(diffnum,(part1,part2))=dolift$hPutStrLnhnd("---- Difference "++showdiffnum++" ----")lift$hPutStrhnd"Graph 1:"swishOutputPartfnamhndpart1lift$hPutStrhnd"Graph 2:"swishOutputPartfnamhndpart2swishOutputPart::(Labellb)=>MaybeString->Handle->Maybe(GraphPartitionlb)->SwishStateIO()swishOutputPart_hndpart=letout=maybe"\n(No arcs)"(partitionShowP"\n")partinlift$hPutStrLnhndout-------------------------------------------------------------- Execute script from named file------------------------------------------------------------swishScript::MaybeString->SwishStateIO()swishScriptfnam=swishReadScriptfnam>>=mapM_swishCheckResultswishReadScript::MaybeString->SwishStateIO[SwishStateIO()]swishReadScript=swishReadFileswishParseScript[]{-|
Calculate the base URI to use; it combines the file name
with any user-supplied base.
If both the file name and user-supplied base are Nothing
then the value
http://id.ninebynine.org/2003/Swish/is used.
Needs some work.
-}defURI::QNamedefURI="http://id.ninebynine.org/2003/Swish/"calculateBaseURI::MaybeFilePath-- ^ file name->SwishStateIOQName-- ^ base URIcalculateBaseURINothing=fromMaybedefURI`liftM`getsbasecalculateBaseURI(Justfnam)=caseparseURIReferencefnamofJustfuri->dombase<-getsbasecasembaseofJustburi->caseappendURIs(getQNameURIburi)furiofLeftemsg->failemsg-- TODO: think about this ...Rightres->return$qnameFromURIresNothing->lift$qnameFromFilePathfnamNothing->fail$"Unable to convert to URI: filepath="++fnamswishParseScript::MaybeString-- file name (or "stdin" if Nothing)->T.Text-- script contents->SwishStateIO[SwishStateIO()]swishParseScriptmfpathinp=doburi<-calculateBaseURImfpathcaseparseScriptFromText(Justburi)inpofLefterr->doletinName=maybe"standard input"("file "++)mfpathswishError("Script syntax error in "++inName++": "++err)SwishDataInputErrorreturn[]Rightscs->returnscsswishCheckResult::SwishStateIO()->SwishStateIO()swishCheckResultswishcommand=doswishcommander<-getserrormsgcaseerofJustx->swishErrorxSwishExecutionError>>modifyresetError_->return()ms<-getsinfomsgcasemsofJustx->reportLinex>>modifyresetInfo_->return()-------------------------------------------------------------- Output graph to named file------------------------------------------------------------swishOutput::MaybeString->SwishStateIO()swishOutput=swishWriteFileswishOutputGraphswishOutputGraph::MaybeString->Handle->SwishStateIO()swishOutputGraph_hnd=dofmt<-getsformatletwriteOutformatter=doout<-gets$formatter.graphlift$IO.hPutStrLnhndoutcasefmtofN3->writeOutN3F.formatGraphAsLazyTextNT->writeOutNTF.formatGraphAsLazyTextTurtle->writeOutTTLF.formatGraphAsLazyText-- _ -> swishError ("Unsupported file format: "++show fmt) SwishArgumentError-------------------------------------------------------------- Common input functions---------------------------------------------------------------- Keep the logic separate for reading file data and-- parsing it to an RDF graph value.swishReadGraph::MaybeString->SwishStateIO(MaybeRDFGraph)swishReadGraph=swishReadFileswishParseNothing-- | Open a file (or stdin), read its contents, and process them.--swishReadFile::(MaybeString->T.Text->SwishStateIOa)-- ^ Convert filename and contents into desired value->a-- ^ the value to use if the file can not be read in->MaybeString-- ^ the file name or @stdin@ if @Nothing@->SwishStateIOaswishReadFileconverrValfnam=letreader(h,f,i)=dores<-convfnamiwhenf$lift$hCloseh-- given that we use IO.hGetContents not sure the close is neededreturnresinswishOpenFilefnam>>=maybe(returnerrVal)reader-- | Open and read file, returning its handle and content, or Nothing-- WARNING: the handle must not be closed until input is fully evaluated--swishOpenFile::MaybeString->SwishStateIO(Maybe(Handle,Bool,T.Text))swishOpenFileNothing=readFromHandlestdinNothingswishOpenFile(Justfnam)=doo<-lift$try$openFilefnamReadModecaseoofLeft_->doswishError("Cannot open file: "++fnam)SwishDataAccessErrorreturnNothingRighthnd->readFromHandlehnd$Just("file: "++fnam)readFromHandle::Handle->MaybeString->SwishStateIO(Maybe(Handle,Bool,T.Text))readFromHandlehdlmlbl=dohrd<-lift$hIsReadablehdlifhrdthendofc<-lift$IO.hGetContentshdlreturn$Just(hdl,isJustmlbl,fc)elsedolbl<-casemlblofJustl->lift(hClosehdl)>>returnlNothing->return"standard input"swishError("Cannot read from "++lbl)SwishDataAccessErrorreturnNothingswishParse::MaybeString-- ^ filename (if not stdin)->T.Text-- ^ contents of file->SwishStateIO(MaybeRDFGraph)swishParsemfpathinp=dofmt<-getsformatburi<-calculateBaseURImfpathlettoErroreMsg=swishError(showfmt++" syntax error in "++inName++": "++eMsg)SwishDataInputError>>returnNothinginName=maybe"standard input"("file "++)mfpathreadInreader=casereaderinpofLefteMsg->toErroreMsgRightres->return$JustrescasefmtofTurtle->readIn(`parseTurtle`Just(getQNameURIburi))N3->readIn(`parseN3`Justburi)NT->readInparseNT{-
_ -> swishError ("Unsupported file format: "++show fmt) SwishArgumentError >>
return Nothing
-}swishWriteFile::(MaybeString->Handle->SwishStateIO())-- ^ given a file name and a handle, write to it->MaybeString->SwishStateIO()swishWriteFileconvfnam=lethdlr(h,c)=convfnamh>>whenc(lift$hCloseh)inswishCreateWriteableFilefnam>>=maybe(return())hdlr-- | Open file for writing, returning its handle, or Nothing-- Also returned is a flag indicating whether or not the-- handled should be closed when writing is done (if writing-- to standard output, the handle should not be closed as the-- run-time system should deal with that).swishCreateWriteableFile::MaybeString->SwishStateIO(Maybe(Handle,Bool))swishCreateWriteableFileNothing=dohwt<-lift$hIsWritablestdoutifhwtthenreturn$Just(stdout,False)elsedoswishError"Cannot write to standard output"SwishDataAccessErrorreturnNothingswishCreateWriteableFile(Justfnam)=doo<-lift$try$openFilefnamWriteModecaseoofLeft_->doswishError("Cannot open file for writing: "++fnam)SwishDataAccessErrorreturnNothingRighthnd->dohwt<-lift$hIsWritablehndifhwtthenreturn$Just(hnd,True)elsedolift$hClosehndswishError("Cannot write to file: "++fnam)SwishDataAccessErrorreturnNothing------------------------------------------------------------------------------------ Copyright (c) 2003, Graham Klyne, 2009 Vasili I Galchin, 2011 Douglas Burke -- All rights reserved.---- This file is part of Swish.---- Swish is free software; you can redistribute it and/or modify-- it under the terms of the GNU General Public License as published by-- the Free Software Foundation; either version 2 of the License, or-- (at your option) any later version.---- Swish is distributed in the hope that it will be useful,-- but WITHOUT ANY WARRANTY; without even the implied warranty of-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-- GNU General Public License for more details.---- You should have received a copy of the GNU General Public License-- along with Swish; if not, write to:-- The Free Software Foundation, Inc.,-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA----------------------------------------------------------------------------------