fradrive/.ports/assign.hs
2024-02-12 15:06:30 +00:00

65 lines
2.3 KiB
Haskell

-- SPDX-FileCopyrightText: 2024 David Mosbach <david.mosbach@uniworx.de>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
{-# Language OverloadedStrings, LambdaCase, TypeApplications #-}
import Data.Text (Text)
import qualified Data.Text as T
import System.Directory
import System.Environment
import System.IO
main :: IO ()
main = getArgs >>= \case
["--assign", offsetFile] -> parseOffsets offsetFile >>= uncurry nextOffset
["--remove", offset] -> removeOffset offset
_ -> fail "unsupported args"
parseOffsets :: FilePath -> IO (Int,Int)
parseOffsets offsetFile = do
user <- T.pack <$> getEnv "USER"
let pred x = "//" `T.isPrefixOf` x || T.null (T.strip x)
tokenise = map (filter (not . pred) . T.lines) . T.split (=='#')
extract = map tail . filter (\u -> not (null u) && user == (T.strip $ head u))
((extract . tokenise . T.pack) <$> readFile offsetFile) >>= \case
[[min,max]] -> return (read $ T.unpack min, read $ T.unpack max)
x -> print x >> fail "malformed offset file"
nextOffset :: Int -> Int -> IO ()
nextOffset min max
| min > max = nextOffset max min
| otherwise = do
home <- getEnv "HOME"
offset <- findFile [home] ".port-offsets" >>= \case
Nothing -> writeFile (home ++ "/.port-offsets") (show min) >> return min
Just path -> do
used <- (map (read @Int) . filter (not . null) . lines) <$> readFile path
o <- next min max used
appendFile path ('\n' : show o)
return o
print offset
where
next :: Int -> Int -> [Int] -> IO Int
next min max used
| min > max = fail "all offsets currently in use"
| min `elem` used = next (min+1) max used
| otherwise = return min
removeOffset :: String -> IO ()
removeOffset offset = do
home <- getEnv "HOME"
findFile [home] ".port-offsets" >>= \case
Nothing -> fail "offset file does not exist"
Just path -> do
remaining <- (filter (/= offset) . lines) <$> readFile path
run <- getEnv "XDG_RUNTIME_DIR"
(tempPath, fh) <- openTempFile run ".port-offsets"
let out = unlines remaining
hPutStr fh $ out
case T.null (T.strip $ T.pack out) of
True -> removeFile path
False -> writeFile path $ out
removeFile tempPath