packages feed

moss (empty) → 0.1.0.0

raw patch · 6 files changed

+299/−0 lines, 6 filesdep +basedep +bytestringdep +conduit-extrasetup-changed

Dependencies added: base, bytestring, conduit-extra, mtl, network, network-simple, unix-compat

Files

+ ChangeLog.md view
@@ -0,0 +1,3 @@+# Changelog for moss++## Unreleased changes
+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2018 Michael B. Gale++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,28 @@+# moss++Haskell client library for [Moss](https://theory.stanford.edu/~aiken/moss/).++## Example++In order to use Moss, you need to register on the Moss website. Once you have your access token, using the library is fairly easy:++```haskell+import Stanford.Moss++cfg :: MossCfg+cfg = defaultMossCfg {+    mossLanguage = Haskell,+    mossUser = "[YOUR ACCESS TOKEN HERE]"+}++main :: IO ()+main = do+    url <- withMoss cfg $ do+        addBaseFile "Skeleton" "Skeleton.hs"+        addFile "StudentA" "StudentA.hs"+        addFile "StudentB" "StudentB.hs"+        query "Test"+    print url+```++This example establishes a connection with Moss using Haskell as the selected programming language. We assume that some skeleton code (`Skeleton.hs`) has been made available to students and relevant parts from that file should be ignored for plagiarism checking. The example then uploads two students' submissions (`StudentA.hs` and `StudentB.hs`) before telling Moss to run the plagiarism check with `query` which eventually returns a URL to the results.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ moss.cabal view
@@ -0,0 +1,46 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 242278afc3ff26ab06aac60f132d9b70b071d6757c7763d6bf804c6cf8260412++name:           moss+version:        0.1.0.0+synopsis:       Haskell client for Moss+description:    Please see the README on Github at <https://github.com/mbg/moss#readme>+category:       Web+homepage:       https://github.com/mbg/moss#readme+bug-reports:    https://github.com/mbg/moss/issues+author:         Michael B. Gale+maintainer:     m.gale@warwick.ac.uk+copyright:      Copyright (c) 2018 Michael B. Gale+license:        MIT+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    ChangeLog.md++source-repository head+  type: git+  location: https://github.com/mbg/moss++library+  hs-source-dirs:+      src+  default-extensions: RecordWildCards OverloadedStrings+  build-depends:+      base >=4.7 && <5+    , bytestring+    , conduit-extra+    , mtl+    , network+    , network-simple+    , unix-compat+  exposed-modules:+      Stanford.Moss+  other-modules:+      Paths_moss+  default-language: Haskell2010
+ src/Stanford/Moss.hs view
@@ -0,0 +1,199 @@+--------------------------------------------------------------------------------+-- Haskell client for Moss                                                    --+-- Copyright (c) 2018 Michael B. Gale (m.gale@warwick.ac.uk)                  --+--------------------------------------------------------------------------------++module Stanford.Moss (+    MossCfg(..),+    defaultMossCfg,++    Language(..),+    Moss,+    liftIO,++    withMoss,+    addBaseFile,+    addFile,+    addFilesForStudent,+    query+) where++--------------------------------------------------------------------------------++import Control.Exception+import Control.Monad.State++import Data.Monoid++import Network.Simple.TCP++import System.IO+import System.PosixCompat++import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as C++--------------------------------------------------------------------------------++-- | Represents the configuration for a Moss connection.+data MossCfg = MossCfg {+    mossServer     :: HostName,+    mossPort       :: ServiceName,+    mossUser       :: BS.ByteString,+    mossDir        :: Maybe FilePath,+    mossX          :: Bool,+    mossMaxMatches :: Int,+    mossShow       :: Bool,+    mossLanguage   :: Language+}++-- | 'defaultMossCfg' is the default configuration for a Moss connection.+defaultMossCfg :: MossCfg+defaultMossCfg = MossCfg {+    mossServer     = "moss.stanford.edu",+    mossPort       = "7690",+    mossUser       = "",+    mossDir        = Nothing,+    mossX          = False,+    mossMaxMatches = 250,+    mossShow       = True,+    mossLanguage   = Haskell+}++--------------------------------------------------------------------------------++-- | Enumerates programming languages supported by Moss.+data Language+    = C+    | CPP+    | Java+    | CSharp+    | Python+    | VisualBasic+    | Javascript+    | FORTRAN+    | ML+    | Haskell+    | Lisp+    | Scheme+    | Pascal+    | Modula2+    | Ada+    | Perl+    | TCL+    | Matlab+    | VHDL+    | Verilog+    | Spice+    | MIPS+    | A8086+    | HCL2+    deriving (Enum)++instance Show Language where+    show C       = "c"+    show CPP     = "cc"+    show Java    = "java"+    show ML      = "ml"+    show Pascal  = "pascal"+    show Ada     = "ada"+    show Lisp    = "lisp"+    show Scheme  = "scheme"+    show Haskell = "haskell"+    show FORTRAN = "fortran"++--------------------------------------------------------------------------------++-- | Represents the state of a Moss connection.+data MossSt = MossSt {+    mossSocket  :: Socket,+    mossCounter :: Int,+    mossCfg     :: MossCfg+}++type Moss = StateT MossSt IO++-- | 'sendCmd' @socket bytestring@ sends @bytestring@ as a command over the+-- connection represented by @socket@.+sendCmd :: Socket -> BS.ByteString -> IO ()+sendCmd s xs = do+    putStr "Send: "+    putStrLn (show xs)+    send s (xs <> "\n")++-- | 'withMoss' @cfg m@ runs a computation @m@ using a Moss connection whose+-- configuration is reprsented by @cfg@.+withMoss :: MossCfg -> Moss a -> IO a+withMoss (cfg@MossCfg {..}) m =+    connect mossServer mossPort $ \(s, addr) -> do+        sendCmd s ("moss " <> mossUser)+        sendCmd s ("X " <> C.pack (show (fromEnum mossX)))+        sendCmd s ("maxmatches " <> C.pack (show mossMaxMatches))+        sendCmd s ("language " <> C.pack (show mossLanguage))++        ls <- recv s 1024++        case ls of+            Nothing -> error "No data received."+            Just "no" -> do+                sendCmd s "end"+                error "Language not supported"+            Just _ -> do+                putStrLn "Language supported."+                r <- evalStateT m (MossSt s 1 cfg)+                sendCmd s "end"+                return r++{-send = withSocketsDo $ do+    h <- connectTo mossServer mossPort+    hClose h-}++-- | 'uploadFile' @index name path@ uploads a file located at @path@ to Moss+-- and assigns it to the collection of files at @index@ (e.g. representing+-- a student) with the name given by @name@.+uploadFile :: Int -> String -> FilePath -> Moss ()+uploadFile i dn fp = do+    s <- gets mossSocket+    MossCfg{..} <- gets mossCfg++    liftIO $ do+        size <- fileSize <$> getFileStatus fp+        sendCmd s ( "file "+             <> C.pack (show i) <> " "+             <> C.pack (show mossLanguage) <> " "+             <> C.pack (show size) <> " "+             <> C.pack dn)++        xs <- BS.readFile fp+        send s xs++-- | 'addBaseFile' @file@ adds @file@ as part of the skeleton code.+addBaseFile :: String -> FilePath -> Moss ()+addBaseFile = uploadFile 0++-- | 'addFile' @name file@ adds @file@ as a submission to Moss with @name@.+addFile :: String -> FilePath -> Moss ()+addFile desc fp = do+    st <- get+    uploadFile (mossCounter st) desc fp+    put $ st { mossCounter = mossCounter st + 1 }++-- | 'addFilesForStudent' @filesWithNames@ uploads multiple files for+-- the same student. I.e. in the Moss submission they will share the same ID.+addFilesForStudent :: [(String, FilePath)] -> Moss ()+addFilesForStudent fs = do+    st <- get+    forM_ fs $ \(dn,fn) ->+        uploadFile (mossCounter st) dn fn+    put $ st { mossCounter = mossCounter st + 1 }++-- | 'query' @comment@ runs the plagiarism check on all submitted files+query :: BS.ByteString -> Moss (Maybe BS.ByteString)+query cmt = do+    s <- gets mossSocket+    liftIO $ do+        putStrLn "Querying, this may take several minutes..."+        sendCmd s ("query 0 " <> cmt)+        recv s 1024++--------------------------------------------------------------------------------