Skip to content
This repository was archived by the owner on Mar 22, 2021. It is now read-only.

Commit 1875476

Browse files
committed
Make it so!
0 parents  commit 1875476

10 files changed

Lines changed: 504 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/dist
2+
/.ghc.environment.*
3+
/.stack-work

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Revision history for hslua-module-system
2+
3+
## 0.1.0.0 -- 2019-04-26
4+
5+
* First version. Released on an unsuspecting world.

LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2019 Albert Krewinkel
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included
12+
in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
HsLua Module: System
2+
====================
3+
4+
This module provides access to system information and functionality via
5+
Haskell's `System` module.
6+
7+
Intended usage for this package is to preload it by adding the loader
8+
function to `package.preload`. Note that the Lua `package` library must
9+
have already been loaded before the loader can be added.
10+
11+
12+
Example
13+
-------
14+
15+
``` haskell
16+
loadProg :: Lua Status
17+
loadProg = do
18+
openlibs
19+
preloadModule "system"
20+
-- create a temporary directory, print it's path, then delete it again.
21+
dostring $ "system = require 'system'\n"
22+
++ "system.with_tmpdir('.', 'foo', print)"
23+
```
24+
25+
26+
Documentation
27+
-------------
28+
29+
### currentdir {#system-currentdir}
30+
31+
`currentdir ()`
32+
33+
Obtain the current working directory as an absolute path.
34+
35+
Returns:
36+
37+
- The current working directory (string).
38+
39+
### ls {#system-ls}
40+
41+
`ls ([dir])`
42+
43+
List the contents of a directory.
44+
45+
Parameters:
46+
47+
`dir`:
48+
: Path of the directory whose contents should be listed (string).
49+
Defaults to `.`.
50+
51+
Returns:
52+
53+
- A table of all entries in `dir` without the special entries (`.` and
54+
`..`).
55+
56+
### pwd {#system-pwd}
57+
58+
`pwd ()`
59+
60+
An alias for [`currentdir`](#system-currentdir)
61+
62+
### tmpdirname {#system-tmpdirname}
63+
64+
`tmpdirname ()`
65+
66+
Returns the current directory for temporary files.
67+
68+
On Unix, `tmpdirname()` returns the value of the `TMPDIR` environment
69+
variable or "/tmp" if the variable isn't defined. On Windows, the
70+
function checks for the existence of environment variables in the
71+
following order and uses the first path found:
72+
73+
- TMP environment variable.
74+
- TEMP environment variable.
75+
- USERPROFILE environment variable.
76+
- The Windows directory
77+
78+
The operation may fail if the operating system has no notion of
79+
temporary directory.
80+
81+
The function doesn't verify whether the path exists.
82+
83+
Returns:
84+
85+
- The current directory for temporary files (string).
86+
87+
### with\_tmpdir {#system-with_tmpdir}
88+
89+
`with_tmpdir ([parent_dir,] templ, callback)`
90+
91+
Create and use a temporary directory inside the given directory.
92+
The directory is deleted after use.
93+
94+
Parameters:
95+
96+
`parent_dir`:
97+
: Parent directory to create the directory in (string). If this
98+
parameter is omitted, the system's canonical temporary directory is
99+
used.
100+
101+
`templ`:
102+
: Directory name template (string).
103+
104+
`callback`:
105+
: Function which takes the name of the temporary directory as its
106+
first argument (function).
107+
108+
Returns:
109+
110+
- The result of the call to `callback`.
111+
112+
113+
License
114+
-------
115+
116+
This package is licensed under the MIT license. See [`LICENSE`](LICENSE)
117+
for details.

Setup.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain

hslua-module-system.cabal

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: hslua-module-system
2+
version: 0.1.0.0
3+
synopsis: Lua module wrapper around Haskell's System module.
4+
homepage: https://github.com/hslua/hslua-module-system
5+
license: MIT
6+
license-file: LICENSE
7+
author: Albert Krewinkel
8+
maintainer: albert+hslua@zeitkraut.de
9+
copyright: Albert Krewinkel <albert+hslua@zeitkraut.de>
10+
category: Foreign
11+
build-type: Simple
12+
extra-source-files: CHANGELOG.md
13+
cabal-version: >=1.10
14+
15+
source-repository head
16+
type: git
17+
location: https://github.com/hslua/hslua-module-system.git
18+
19+
library
20+
build-depends: base >= 4.9 && < 5
21+
, directory >= 1.3 && < 1.4
22+
, hslua >= 1.0 && < 1.2
23+
, temporary >= 1.2 && < 1.4
24+
default-extensions: LambdaCase
25+
default-language: Haskell2010
26+
exposed-modules: Foreign.Lua.Module.System
27+
hs-source-dirs: src
28+
other-extensions: OverloadedStrings
29+
30+
test-suite test-hslua-module-system
31+
default-language: Haskell2010
32+
type: exitcode-stdio-1.0
33+
main-is: test-hslua-module-system.hs
34+
hs-source-dirs: test
35+
ghc-options: -Wall -threaded
36+
build-depends: base
37+
, hslua
38+
, hslua-module-system
39+
, tasty
40+
, tasty-hunit
41+
, text

src/Foreign/Lua/Module/System.hs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
{-# LANGUAGE ScopedTypeVariables #-}
2+
{-|
3+
Module : Foreign.Lua.Module.System
4+
Copyright : © 2019 Albert Krewinkel
5+
License : MIT
6+
Maintainer : Albert Krewinkel <albert+hslua@zeitkraut.de>
7+
Stability : alpha
8+
Portability : Requires language extensions ForeignFunctionInterface,
9+
OverloadedStrings.
10+
11+
Provide a Lua module containing a selection of @'System'@ functions.
12+
-}
13+
module Foreign.Lua.Module.System
14+
( pushModule
15+
, preloadModule
16+
)
17+
where
18+
19+
import Control.Applicative ((<$>))
20+
import Control.Exception (IOException, catch, evaluate, try)
21+
import Data.Maybe (fromMaybe)
22+
import Foreign.Lua (Lua, NumResults(..), Optional (..), Peekable, Pushable,
23+
StackIndex, ToHaskellFunction)
24+
import System.IO.Error (IOError, isDoesNotExistError)
25+
26+
import qualified Foreign.Lua as Lua
27+
import qualified System.Directory as Directory
28+
import qualified System.IO.Temp as Temp
29+
30+
-- | Pushes the @text@ module to the lua stack.
31+
pushModule :: Lua NumResults
32+
pushModule = do
33+
Lua.newtable
34+
addFunction "chdir" chdir
35+
addFunction "currentdir" currentdir
36+
addFunction "ls" ls
37+
addFunction "pwd" currentdir
38+
addFunction "tmpdirname" tmpdirname
39+
addFunction "with_tmpdir" with_tmpdir
40+
return 1
41+
42+
-- | Add the text module under the given name to the table of preloaded
43+
-- packages.
44+
preloadModule :: String -> Lua ()
45+
preloadModule = flip addPackagePreloader pushModule
46+
47+
-- | Registers a preloading function. Takes an module name and the Lua
48+
-- operation which produces the package.
49+
addPackagePreloader :: String -> Lua NumResults -> Lua ()
50+
addPackagePreloader name modulePusher = do
51+
Lua.getfield Lua.registryindex Lua.preloadTableRegistryField
52+
Lua.pushHaskellFunction modulePusher
53+
Lua.setfield (-2) name
54+
Lua.pop 1
55+
56+
-- | Attach a function to the table at the top of the stack, using the
57+
-- given name.
58+
addFunction :: ToHaskellFunction a => String -> a -> Lua ()
59+
addFunction name fn = do
60+
Lua.push name
61+
Lua.pushHaskellFunction fn
62+
Lua.rawset (-3)
63+
64+
-- | Lua callback function
65+
newtype Callback = Callback { callbackStackIndex :: StackIndex }
66+
67+
instance Peekable Callback where
68+
peek idx = do
69+
isFn <- Lua.isfunction idx
70+
if isFn
71+
then return (Callback idx)
72+
else Lua.throwException "Function expected"
73+
74+
instance Pushable Callback where
75+
push (Callback idx) = Lua.pushvalue idx
76+
77+
78+
-- | Any value of unknown type
79+
newtype AnyValue = AnyValue { fromAnyValue :: StackIndex }
80+
81+
instance Peekable AnyValue where
82+
peek = return . AnyValue
83+
84+
instance Pushable AnyValue where
85+
push (AnyValue idx) = Lua.pushvalue idx
86+
87+
with_tmpdir :: String -- ^ parent dir or template
88+
-> AnyValue -- ^ template or callback
89+
-> Optional Callback -- ^ callback or nil
90+
-> Lua NumResults
91+
with_tmpdir parentDir tmpl callback = do
92+
case fromOptional callback of
93+
Nothing -> do
94+
-- At most two args. The first arg (parent dir) has probably been
95+
-- omitted, so we shift arguments and use the system's canonical
96+
-- temporary directory.
97+
let tmpl' = parentDir
98+
callback' <- Lua.peek (fromAnyValue tmpl)
99+
Temp.withSystemTempDirectory tmpl' (callWithFilename callback')
100+
Just callback' -> do
101+
-- all args given. Second value must be converted to a string.
102+
tmpl' <- Lua.peek (fromAnyValue tmpl)
103+
Temp.withTempDirectory parentDir tmpl' (callWithFilename callback')
104+
105+
-- | Call Lua callback function with the given filename as its argument.
106+
callWithFilename :: Callback -> FilePath -> Lua NumResults
107+
callWithFilename callback filename = do
108+
oldTop <- Lua.gettop
109+
Lua.push callback
110+
Lua.push filename
111+
Lua.call (Lua.NumArgs 1) Lua.multret
112+
newTop <- Lua.gettop
113+
return . NumResults . fromIntegral . Lua.fromStackIndex $
114+
newTop - oldTop
115+
116+
tmpdirname :: Lua FilePath
117+
tmpdirname = do
118+
eitherTmpdir <- Lua.liftIO $ try Directory.getTemporaryDirectory
119+
case eitherTmpdir :: Either IOException FilePath of
120+
Right tmpdir -> return tmpdir
121+
Left _ -> Lua.throwException ("The operating system has no notion " ++
122+
"of temporary directory.")
123+
124+
-- | List the contents of a directory.
125+
ls :: Optional FilePath -> Lua [FilePath]
126+
ls fp = do
127+
let fp' = fromMaybe "." (fromOptional fp)
128+
ioToLua (Directory.listDirectory fp')
129+
130+
-- | Return the current working directory.
131+
currentdir :: Lua FilePath
132+
currentdir = ioToLua Directory.getCurrentDirectory
133+
134+
-- | Change current working directory.
135+
chdir :: FilePath -> Lua ()
136+
chdir fp = ioToLua $ Directory.setCurrentDirectory fp
137+
138+
-- | Convert a System IO operation to a Lua operation.
139+
ioToLua :: IO a -> Lua a
140+
ioToLua action = do
141+
result <- Lua.liftIO (try action)
142+
case result of
143+
Right result' -> return result'
144+
Left err -> Lua.throwException (show (err :: IOException))

0 commit comments

Comments
 (0)