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 +3/−0
- LICENSE +21/−0
- README.md +28/−0
- Setup.hs +2/−0
- moss.cabal +46/−0
- src/Stanford/Moss.hs +199/−0
+ 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++--------------------------------------------------------------------------------