aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/app/AddPath.hs
blob: df53326b5b04596ee19f11d6219957cf47797067 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
-- |
-- Copyright   : (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
-- License     : MIT
-- Maintainer  : Egor.Tensin@gmail.com
-- Stability   : experimental
-- Portability : Windows-only

module Main (main) where

import Control.Monad   (unless, void)
import Control.Monad.Trans.Except (catchE, runExceptT, throwE)
import Data.List       ((\\), nub)
import System.IO.Error (ioError, isDoesNotExistError)

import Options.Applicative

import qualified WindowsEnv

import Utils.Prompt
import Utils.PromptMessage

data Options = Options
    { optName   :: WindowsEnv.VarName
    , optYes     :: Bool
    , optGlobal  :: Bool
    , optPrepend :: Bool
    , optPaths   :: [WindowsEnv.VarValue]
    } deriving (Eq, Show)

optionParser :: Parser Options
optionParser = Options
    <$> optNameDesc
    <*> optYesDesc
    <*> optGlobalDesc
    <*> optPrependDesc
    <*> optPathsDesc
  where
    optNameDesc = strOption
         $ long "name" <> short 'n'
        <> metavar "NAME" <> value "PATH"
        <> help "Variable name ('PATH' by default)"
    optYesDesc = switch
         $ long "yes" <> short 'y'
        <> help "Skip confirmation prompt"
    optGlobalDesc = switch
         $ long "global" <> short 'g'
        <> help "Add for all users"
    optPrependDesc = switch
         $ long "prepend" <> short 'p'
        <> help "Prepend to the variable (instead of appending)"
    optPathsDesc = many $ argument str
         $ metavar "PATH"
        <> help "Directories to add"

main :: IO ()
main = execParser parser >>= addPath
  where
    parser = info (helper <*> optionParser) $
        fullDesc <> progDesc "Add directories to your PATH"

addPath :: Options -> IO ()
addPath options = runExceptT doAddPath >>= either ioError return
  where
    varName = optName options
    pathsToAdd = nub $ optPaths options

    forAllUsers = optGlobal options
    profile
        | forAllUsers = WindowsEnv.AllUsers
        | otherwise   = WindowsEnv.CurrentUser

    skipPrompt = optYes options

    prepend = optPrepend options
    append xs ys
        | prepend = ys ++ xs
        | otherwise = xs ++ ys

    emptyIfMissing e
        | isDoesNotExistError e = return ""
        | otherwise = throwE e

    doAddPath = do
        oldValue <- WindowsEnv.query profile varName `catchE` emptyIfMissing
        let oldPaths = WindowsEnv.pathSplit oldValue
        let newPaths = pathsToAdd \\ oldPaths
        unless (null newPaths) $ do
            let newValue = WindowsEnv.pathJoin $ append oldPaths newPaths
            let promptAnd = if skipPrompt
                then withoutPrompt
                else withPrompt $ oldNewMessage profile varName oldValue newValue
            let engrave = WindowsEnv.engrave profile varName newValue
            void $ promptAnd engrave