2

For some reason I cannot make cd command work in shake/command Haskell library. It thinks directory I called with cd does not exist even though it is present in the filesystem.

Here is an excerpt of my code:

dataDir = "data"

data Settings = Settings {
  url :: String
} deriving (Eq, Show, Generic, JSON.ToJSON, JSON.FromJSON)

settings :: String -> Handler Settings
settings subfolder = let 
  gitPath = dataDir ++ "/" ++ subfolder ++ "/git/.git"
  in do
    pathExists <- liftIO $ doesPathExist gitPath 
    -- Stdout pwdOut <- liftIO $ cmd ("pwd" :: String)
    -- liftIO $ putStrLn $ pwdOut 
    if not pathExists
       then do
         liftIO $ (cmd_ ("mkdir -p" :: String) [gitPath] :: IO ())
         liftIO $ (cmd_ ("cd" :: String) [gitPath] :: IO ())
         liftIO $ (cmd_ ("git init" :: String) :: IO ())
         return $ Settings { url = ""}
       else do
         liftIO $ (cmd_ (Cwd ".") ("cd" :: String) [gitPath] :: IO ())
         Stdout out <- liftIO $ (cmd ("git config --get remote.origin.url" :: String))
         return $ Settings {url = out} 

It fails with an error cd: createProcess: runInteractiveProcess: exec: does not exist (No such file or directory) in both cases: if dir exists and when mkdir command is executed.

Cannot wrap my head around it. But before I submit a bug to the shake's github page, I want to make sure with you I am not doing anything stupid that might cause this kind of behavior.

Thanks in advance for help.

altern
  • 5,829
  • 5
  • 44
  • 72

2 Answers2

3

As described in the other answer, cd is not an executable, so if you wanted to run it, you would have to pass Shell to cmd.

However, it is almost certainly the case that you don't want to call cd in a command, as it does not change the directory for any subsequent command. Each cmd is a separate process, with a separate environment, so the subsequent command will be in a fresh environment, and the same working directory as before the cd. The solution is to pass (Cwd gitPath) to each command you want to operate with the given directory.

Neil Mitchell
  • 9,090
  • 1
  • 27
  • 85
2

Shake's Haddock page describes cmd_, and links to its source. There we can see that cmd_ eventually calls commandExplicitIO, which constructs a ProcessOpts with RawCommand and passes it to process. process then takes that ProcessOpts, pattern-matches it as a RawCommand (via cmdSpec), and calls proc. We have now entered the well-documented zone: you must give proc an executable, and cd is not an executable. (Why? Since processes cannot change the working directory of their parent, cd must be a shell builtin.)

jlwoodwa
  • 387
  • 2
  • 8