Skip to content

Commit a7a1859

Browse files
committed
WIP migration to PosixPath
1 parent 94d6f36 commit a7a1859

File tree

8 files changed

+53
-26
lines changed

8 files changed

+53
-26
lines changed

evdev-examples/evdev-examples.cabal

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ executable evtest
1313
bytestring,
1414
evdev,
1515
evdev-streamly,
16+
filepath,
1617
pretty-simple,
1718
streamly,
1819
ghc-options:
@@ -66,6 +67,7 @@ executable evdev-replay
6667
base,
6768
evdev,
6869
evdev-streamly,
70+
filepath,
6971
mtl,
7072
streamly,
7173
time,

evdev-examples/evtest/Main.hs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
module Main (main) where
22

33
import qualified Data.ByteString.Char8 as BS
4+
import Data.Maybe (fromMaybe)
5+
import System.OsPath.Posix (PosixPath, (</>))
6+
import System.OsString.Posix (fromBytes)
47
import Text.Pretty.Simple (pPrint)
58

69
import qualified Streamly.Prelude as S
@@ -17,9 +20,13 @@ main = do
1720
readEventsMany
1821
if null ns
1922
then allDevices <> newDevices
20-
else makeDevices $ S.fromFoldable $ map ((evdevDir <> "/event") <>) ns
23+
else makeDevices $ S.fromFoldable $ map ((evdevDir </>) . fromBytes' . ("event" <>)) ns
2124

2225
printDevice :: Device -> IO ()
2326
printDevice dev = do
2427
name <- deviceName dev
2528
BS.putStrLn $ devicePath dev <> ":\n " <> name
29+
30+
-- TODO `filepath` docs explicitly say this is a no-op on Posix, so why doesn't it export a safe version?
31+
fromBytes' :: BS.ByteString -> PosixPath
32+
fromBytes' = fromMaybe (error "invalid path") . fromBytes

evdev-examples/replay/Main.hs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import Control.Concurrent
44
import Control.Monad
55
import Data.Foldable
66
import Data.Maybe
7-
import Data.String
87
import Data.Time
98
import System.Environment
9+
import System.OsPath.Posix
1010
import Text.Read
1111

1212
import Streamly.Prelude qualified as S
@@ -18,8 +18,8 @@ import Evdev.Uinput qualified as Uinput
1818

1919
main :: IO ()
2020
main = getArgs >>= \case
21-
"record" : dev : ((\case ["grab"] -> Just True; [] -> Just False; _ -> Nothing) -> Just grab) -> do
22-
d <- newDevice $ fromString dev
21+
"record" : (encodeUtf -> Just dev) : ((\case ["grab"] -> Just True; [] -> Just False; _ -> Nothing) -> Just grab) -> do
22+
d <- newDevice dev
2323
when grab $ grabDevice d
2424
S.mapM_ print $ readEvents d
2525
["replay"] -> do

evdev-streamly/evdev-streamly.cabal

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ library
3030
bytestring ^>= {0.10, 0.11, 0.12},
3131
containers ^>= {0.6.2, 0.7},
3232
evdev ^>= {2.1, 2.2, 2.3},
33+
directory ^>= {1.3.8},
3334
extra ^>= {1.6.18, 1.7},
34-
filepath-bytestring ^>= {1.4.2, 1.5},
35+
filepath ^>= {1.4.100},
3536
mtl ^>= {2.2, 2.3},
36-
rawfilepath ^>= {1.0, 1.1},
3737
streamly ^>= {0.9, 0.10},
3838
streamly-fsnotify ^>= 1.1.1,
3939
unix ^>= 2.8,

evdev-streamly/src/Evdev/Stream.hs

+23-11
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,25 @@ module Evdev.Stream (
1313
import Data.Bool
1414
import Data.Either.Extra
1515
import Data.Functor
16+
import Data.Maybe
1617
import System.IO
1718
import System.IO.Error
1819

1920
import Control.Concurrent (threadDelay)
2021
import Data.Set (Set)
2122
import qualified Data.Set as Set
22-
import qualified Data.ByteString.Char8 as BS
23-
import RawFilePath.Directory (RawFilePath,doesFileExist,listDirectory)
2423
import qualified Streamly.FSNotify as N
2524
import Streamly.FSNotify (FSEntryType(NotDir),watchDirectory)
26-
import System.FilePath.ByteString ((</>))
25+
import qualified System.Directory.OsPath
26+
import System.OsPath.Posix (PosixPath, (</>), decodeUtf, encodeUtf)
2727

2828
import Streamly.Prelude (AsyncT, IsStream, MonadAsync, SerialT)
2929
import qualified Streamly.Prelude as S
3030

3131
import Evdev
3232

33+
import System.OsString.Internal.Types (OsString(..))
34+
3335
--TODO provide a 'group' operation on streams, representing packets as sets
3436

3537
-- | Read all events from a device.
@@ -48,7 +50,7 @@ readEventsMany ds = S.fromAsync $ do
4850
readEvents' :: Device -> SerialT IO Event
4951

5052
-- | Create devices for all paths in the stream.
51-
makeDevices :: IsStream t => t IO RawFilePath -> t IO Device
53+
makeDevices :: IsStream t => t IO PosixPath -> t IO Device
5254
makeDevices = S.mapM newDevice
5355

5456
-- | All events on all valid devices (in /\/dev\/input/).
@@ -77,15 +79,15 @@ allDevices =
7779
newDevices :: (IsStream t, Monad (t IO)) => t IO Device
7880
newDevices =
7981
let -- 'watching' keeps track of the set of paths which have been added, but don't yet have the right permissions
80-
watch :: Set RawFilePath -> N.Event -> IO (Maybe Device, Set RawFilePath)
82+
watch :: Set PosixPath -> N.Event -> IO (Maybe Device, Set PosixPath)
8183
watch watching = \case
82-
N.Added (BS.pack -> p) _ NotDir ->
84+
N.Added (enc -> p) _ NotDir ->
8385
tryNewDevice p <&> \case
8486
Right d -> -- success - return new device
8587
(Just d, watching)
8688
Left e -> -- fail - if it's only a permission error then watch for changes on device
8789
(Nothing, applyWhen (isPermissionError e) (Set.insert p) watching)
88-
N.Modified (BS.pack -> p) _ NotDir ->
90+
N.Modified (enc -> p) _ NotDir ->
8991
if p `elem` watching then
9092
tryNewDevice p <&> \case
9193
Right d -> -- success - no longer watch for changes
@@ -94,12 +96,14 @@ newDevices =
9496
(Nothing, watching)
9597
else -- this isn't an event we care about
9698
return (Nothing, watching)
97-
N.Removed (BS.pack -> p) _ NotDir -> -- device is gone - no longer watch for changes
99+
N.Removed (enc -> p) _ NotDir -> -- device is gone - no longer watch for changes
98100
return (Nothing, Set.delete p watching)
99101
_ -> return (Nothing, watching)
100102
tryNewDevice = printIOError . newDevice
103+
enc = fromMaybe (error "bad fsnotify path conversion") . encodeUtf
104+
dec = fromMaybe (error "bad fsnotify path conversion") . decodeUtf
101105
in do
102-
(_,es) <- S.fromEffect $ watchDirectory (BS.unpack evdevDir) N.everything
106+
(_,es) <- S.fromEffect $ watchDirectory (dec evdevDir) N.everything
103107
scanMaybe watch Set.empty es
104108

105109
--TODO just fix 'newDevices'
@@ -108,13 +112,15 @@ newDevices =
108112
newDevices' :: (IsStream t, Monad (t IO)) => Int -> t IO Device
109113
newDevices' delay =
110114
let f = \case
111-
N.Added (BS.pack -> p) _ NotDir -> do
115+
N.Added (enc -> p) _ NotDir -> do
112116
threadDelay delay
113117
eitherToMaybe <$> tryNewDevice p
114118
_ -> return Nothing
115119
tryNewDevice = printIOError . newDevice
120+
enc = fromMaybe (error "bad fsnotify path conversion") . encodeUtf
121+
dec = fromMaybe (error "bad fsnotify path conversion") . decodeUtf
116122
in do
117-
(_,es) <- S.fromEffect $ watchDirectory (BS.unpack evdevDir) N.everything
123+
(_,es) <- S.fromEffect $ watchDirectory (dec evdevDir) N.everything
118124
S.mapMaybeM f es
119125

120126

@@ -147,3 +153,9 @@ printIOError' = fmap eitherToMaybe . printIOError
147153
-- apply the function iff the guard passes
148154
applyWhen :: Bool -> (a -> a) -> a -> a
149155
applyWhen = flip $ bool id
156+
157+
-- TODO hmm unsure what to do here - at the very least move these...
158+
doesFileExist :: PosixPath -> IO Bool
159+
doesFileExist = System.Directory.OsPath.doesFileExist . OsString
160+
listDirectory :: PosixPath -> IO [PosixPath]
161+
listDirectory = fmap (map getOsString) . System.Directory.OsPath.listDirectory . OsString

evdev/evdev.cabal

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ common common
2222
base >= 4.11 && < 5,
2323
bytestring ^>= {0.10, 0.11, 0.12},
2424
containers ^>= {0.6.2, 0.7},
25+
directory ^>= {1.3.8},
2526
extra ^>= {1.6.18, 1.7},
26-
filepath-bytestring ^>= {1.4.2, 1.5},
27+
filepath ^>= {1.4.100},
2728
monad-loops ^>= 0.4.3,
2829
mtl ^>= {2.2, 2.3},
29-
rawfilepath ^>= {1.0, 1.1},
3030
time ^>= {1.9.3, 1.10, 1.11, 1.12, 1.13, 1.14},
3131
unix ^>= 2.8,
3232
default-language: GHC2021

evdev/src/Evdev.hs

+5-5
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ import Data.Tuple.Extra (uncurry3)
6767
import Data.Word (Word16)
6868
import Foreign ((.|.))
6969
import Foreign.C (CUInt)
70+
import System.OsPath.Posix (PosixPath, encodeUtf)
7071
import System.Posix.Process (getProcessID)
7172
import System.Posix.Files (readSymbolicLink)
72-
import System.Posix.ByteString (Fd, RawFilePath)
73-
import System.Posix.IO.ByteString (OpenMode (..), defaultFileFlags, openFd)
73+
import System.Posix.PosixString (Fd, OpenMode (..), defaultFileFlags, openFd)
7474

7575
import qualified Evdev.LowLevel as LL
7676
import Evdev.Codes
@@ -204,7 +204,7 @@ toCTimeVal t = LL.CTimeVal n (round $ f * 1_000_000)
204204
{- | Create a device from a valid path - usually /\/dev\/input\/eventX/ for some numeric /X/.
205205
Use 'newDeviceFromFd' if you need more control over how the device is created.
206206
-}
207-
newDevice :: RawFilePath -> IO Device
207+
newDevice :: PosixPath -> IO Device
208208
newDevice path = newDeviceFromFd =<< openFd path ReadWrite defaultFileFlags
209209

210210
{- | Generalisation of 'newDevice', in case one needs control over the file descriptor,
@@ -223,8 +223,8 @@ newDeviceFromFd fd = do
223223
return $ Device{cDevice = dev, devicePath = pack path}
224224

225225
-- | The usual directory containing devices (/"\/dev\/input"/).
226-
evdevDir :: RawFilePath
227-
evdevDir = "/dev/input"
226+
evdevDir :: PosixPath
227+
evdevDir = fromMaybe (error "evdevDir invalid") $ encodeUtf "/dev/input"
228228

229229
deviceName :: Device -> IO ByteString
230230
deviceName = join . LL.deviceName . cDevice

evdev/test/Test.hs

+8-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ import Data.Time
1212
import Evdev
1313
import Evdev.Codes
1414
import qualified Evdev.Uinput as Uinput
15-
import RawFilePath
16-
import System.FilePath.ByteString
15+
import qualified System.Directory.OsPath
1716
import System.IO.Error
17+
import System.OsPath.Posix
1818
import Test.Tasty
1919
import Test.Tasty.HUnit
2020
import Test.Tasty.QuickCheck
2121

22+
import System.OsString.Internal.Types (OsString(..))
23+
2224
main :: IO ()
2325
main = defaultMain $ testGroup "Tests" [smoke, inverses]
2426

@@ -83,3 +85,7 @@ retryIf p x = go 100
8385
go tries =
8486
x `catch` \e ->
8587
if p e && tries /= 0 then threadDelay 10_000 >> go (tries - 1) else throw e
88+
89+
-- TODO copied from `evdev-streamly` - see there for issues
90+
listDirectory :: PosixPath -> IO [PosixPath]
91+
listDirectory = fmap (map getOsString) . System.Directory.OsPath.listDirectory . OsString

0 commit comments

Comments
 (0)