Use haskell setenv library to clean up several ugly workarounds for inability to manipulate the environment on windows.

Didn't know that this library existed!

This includes making git-annex not re-exec itself on start on windows, and
making the test suite on Windows run tests without forking.
This commit is contained in:
Joey Hess 2014-10-15 20:33:52 -04:00
parent 65280d91e7
commit 1e59df083d
12 changed files with 40 additions and 79 deletions

View file

@ -35,24 +35,19 @@ checkEnvironment = do
liftIO checkEnvironmentIO liftIO checkEnvironmentIO
checkEnvironmentIO :: IO () checkEnvironmentIO :: IO ()
checkEnvironmentIO = checkEnvironmentIO = whenM (null <$> myUserGecos) $ do
#ifdef mingw32_HOST_OS username <- myUserName
noop ensureEnv "GIT_AUTHOR_NAME" username
#else ensureEnv "GIT_COMMITTER_NAME" username
whenM (null <$> myUserGecos) $ do
username <- myUserName
ensureEnv "GIT_AUTHOR_NAME" username
ensureEnv "GIT_COMMITTER_NAME" username
where where
#ifndef __ANDROID__ #ifndef __ANDROID__
-- existing environment is not overwritten -- existing environment is not overwritten
ensureEnv var val = void $ setEnv var val False ensureEnv var val = setEnv var val False
#else #else
-- Environment setting is broken on Android, so this is dealt with -- Environment setting is broken on Android, so this is dealt with
-- in runshell instead. -- in runshell instead.
ensureEnv _ _ = noop ensureEnv _ _ = noop
#endif #endif
#endif
{- Runs an action that commits to the repository, and if it fails, {- Runs an action that commits to the repository, and if it fails,
- sets user.email and user.name to a dummy value and tries the action again. -} - sets user.email and user.name to a dummy value and tries the action again. -}

View file

@ -52,7 +52,7 @@ unattendedUpgrade = do
prepUpgrade :: Assistant () prepUpgrade :: Assistant ()
prepUpgrade = do prepUpgrade = do
void $ addAlert upgradingAlert void $ addAlert upgradingAlert
void $ liftIO $ setEnv upgradedEnv "1" True liftIO $ setEnv upgradedEnv "1" True
prepRestart prepRestart
postUpgrade :: URLString -> Assistant () postUpgrade :: URLString -> Assistant ()

View file

@ -5,17 +5,13 @@
- Licensed under the GNU GPL version 3 or higher. - Licensed under the GNU GPL version 3 or higher.
-} -}
{-# LANGUAGE CPP #-}
module Git.CurrentRepo where module Git.CurrentRepo where
import Common import Common
import Git.Types import Git.Types
import Git.Construct import Git.Construct
import qualified Git.Config import qualified Git.Config
#ifndef mingw32_HOST_OS
import Utility.Env import Utility.Env
#endif
{- Gets the current git repository. {- Gets the current git repository.
- -
@ -42,17 +38,13 @@ get = do
setCurrentDirectory d setCurrentDirectory d
return $ addworktree wt r return $ addworktree wt r
where where
#ifndef mingw32_HOST_OS
pathenv s = do pathenv s = do
v <- getEnv s v <- getEnv s
case v of case v of
Just d -> do Just d -> do
void $ unsetEnv s unsetEnv s
Just <$> absPath d Just <$> absPath d
Nothing -> return Nothing Nothing -> return Nothing
#else
pathenv _ = return Nothing
#endif
configure Nothing (Just r) = Git.Config.read r configure Nothing (Just r) = Git.Config.read r
configure (Just d) _ = do configure (Just d) _ = do

View file

@ -21,8 +21,8 @@ import Utility.Env
override :: FilePath -> IO (IO ()) override :: FilePath -> IO (IO ())
override index = do override index = do
res <- getEnv var res <- getEnv var
void $ setEnv var index True setEnv var index True
return $ void $ reset res return $ reset res
where where
var = "GIT_INDEX_FILE" var = "GIT_INDEX_FILE"
reset (Just v) = setEnv var v True reset (Just v) = setEnv var v True

View file

@ -1346,7 +1346,6 @@ test_add_subdirs testenv = intmpclonerepo testenv $ do
-- (when the OS allows) so test coverage collection works. -- (when the OS allows) so test coverage collection works.
git_annex :: TestEnv -> String -> [String] -> IO Bool git_annex :: TestEnv -> String -> [String] -> IO Bool
git_annex testenv command params = do git_annex testenv command params = do
#ifndef mingw32_HOST_OS
forM_ (M.toList testenv) $ \(var, val) -> forM_ (M.toList testenv) $ \(var, val) ->
Utility.Env.setEnv var val True Utility.Env.setEnv var val True
@ -1357,11 +1356,6 @@ git_annex testenv command params = do
Left _ -> return False Left _ -> return False
where where
run = GitAnnex.run (command:"-q":params) run = GitAnnex.run (command:"-q":params)
#else
Utility.SafeCommand.boolSystemEnv "git-annex"
(map Param $ command : params)
(Just $ M.toList testenv)
#endif
{- Runs git-annex and returns its output. -} {- Runs git-annex and returns its output. -}
git_annex_output :: TestEnv -> String -> [String] -> IO String git_annex_output :: TestEnv -> String -> [String] -> IO String

View file

@ -14,6 +14,7 @@ import Utility.Exception
import Control.Applicative import Control.Applicative
import Data.Maybe import Data.Maybe
import qualified System.Environment as E import qualified System.Environment as E
import qualified System.SetEnv
#else #else
import qualified System.Posix.Env as PE import qualified System.Posix.Env as PE
#endif #endif
@ -39,27 +40,27 @@ getEnvironment = PE.getEnvironment
getEnvironment = E.getEnvironment getEnvironment = E.getEnvironment
#endif #endif
{- Returns True if it could successfully set the environment variable. {- Sets an environment variable. To overwrite an existing variable,
- overwrite must be True.
- -
- There is, apparently, no way to do this in Windows. Instead, - On Windows, setting a variable to "" unsets it. -}
- environment varuables must be provided when running a new process. -} setEnv :: String -> String -> Bool -> IO ()
setEnv :: String -> String -> Bool -> IO Bool
#ifndef mingw32_HOST_OS #ifndef mingw32_HOST_OS
setEnv var val overwrite = do setEnv var val overwrite = PE.setEnv var val overwrite
PE.setEnv var val overwrite
return True
#else #else
setEnv _ _ _ = return False setEnv var val True = System.Setenv.setEnv var val
setEnv var val False = do
r <- getEnv var
case r of
Nothing -> setEnv var val True
Just _ -> return True
#endif #endif
{- Returns True if it could successfully unset the environment variable. -} unsetEnv :: String -> IO ()
unsetEnv :: String -> IO Bool
#ifndef mingw32_HOST_OS #ifndef mingw32_HOST_OS
unsetEnv var = do unsetEnv = PE.unsetEnv
PE.unsetEnv var
return True
#else #else
unsetEnv _ = return False unsetEnv = System.Setenv.unsetEnv
#endif #endif
{- Adds the environment variable to the input environment. If already {- Adds the environment variable to the input environment. If already

View file

@ -334,7 +334,7 @@ testHarness a = do
setup = do setup = do
base <- getTemporaryDirectory base <- getTemporaryDirectory
dir <- mktmpdir $ base </> "gpgtmpXXXXXX" dir <- mktmpdir $ base </> "gpgtmpXXXXXX"
void $ setEnv var dir True setEnv var dir True
-- For some reason, recent gpg needs a trustdb to be set up. -- For some reason, recent gpg needs a trustdb to be set up.
_ <- pipeStrict [Params "--trust-model auto --update-trustdb"] [] _ <- pipeStrict [Params "--trust-model auto --update-trustdb"] []
_ <- pipeStrict [Params "--import -q"] $ unlines _ <- pipeStrict [Params "--import -q"] $ unlines

View file

@ -32,7 +32,7 @@ setup = do
when (isAbsolute cmd) $ do when (isAbsolute cmd) $ do
path <- getSearchPath path <- getSearchPath
let path' = takeDirectory cmd : path let path' = takeDirectory cmd : path
void $ setEnv "PATH" (intercalate [searchPathSeparator] path') True setEnv "PATH" (intercalate [searchPathSeparator] path') True
{- Checks each of the files in a directory to find open files. {- Checks each of the files in a directory to find open files.
- Note that this will find hard links to files elsewhere that are open. -} - Note that this will find hard links to files elsewhere that are open. -}

4
debian/changelog vendored
View file

@ -6,6 +6,10 @@ git-annex (5.20141014) UNRELEASED; urgency=medium
it. it.
* initremote: Don't allow creating a special remote that has the same * initremote: Don't allow creating a special remote that has the same
name as an existing git remote. name as an existing git remote.
* Windows: Use haskell setenv library to clean up several ugly workarounds
for inability to manipulate the environment on windows. This includes
making git-annex not re-exec itself on start on windows, and making the
test suite on Windows run tests without forking.
-- Joey Hess <joeyh@debian.org> Tue, 14 Oct 2014 14:09:24 -0400 -- Joey Hess <joeyh@debian.org> Tue, 14 Oct 2014 14:09:24 -0400

View file

@ -19,10 +19,6 @@ usable!
* Deleting a git repository from inside the webapp fails "RemoveDirectory * Deleting a git repository from inside the webapp fails "RemoveDirectory
permision denied ... file is being used by another process" permision denied ... file is being used by another process"
* There are a lot of hacks to avoid setting environment on windows,
because I didn't know about <https://hackage.haskell.org/package/setenv>.
Those hacks should be removed!
## potential encoding problems ## potential encoding problems
[[bugs/Unicode_file_names_ignored_on_Windows]] is fixed, but some potential [[bugs/Unicode_file_names_ignored_on_Windows]] is fixed, but some potential

View file

@ -125,7 +125,7 @@ Executable git-annex
GHC-Options: -O2 GHC-Options: -O2
if (os(windows)) if (os(windows))
Build-Depends: Win32, Win32-extras, unix-compat (>= 0.4.1.3) Build-Depends: Win32, Win32-extras, unix-compat (>= 0.4.1.3), setenv
C-Sources: Utility/winprocess.c C-Sources: Utility/winprocess.c
else else
Build-Depends: unix Build-Depends: unix

View file

@ -19,9 +19,6 @@ import qualified Test
#ifdef mingw32_HOST_OS #ifdef mingw32_HOST_OS
import Utility.UserInfo import Utility.UserInfo
import Utility.Env import Utility.Env
import Config.Files
import System.Process
import System.Exit
#endif #endif
main :: IO () main :: IO ()
@ -33,7 +30,9 @@ main = do
| isshell n = CmdLine.GitAnnexShell.run ps | isshell n = CmdLine.GitAnnexShell.run ps
| otherwise = | otherwise =
#ifdef mingw32_HOST_OS #ifdef mingw32_HOST_OS
winEnv gitannex ps do
winEnv
gitannex ps
#else #else
gitannex ps gitannex ps
#endif #endif
@ -49,37 +48,17 @@ main = do
#ifdef mingw32_HOST_OS #ifdef mingw32_HOST_OS
{- On Windows, if HOME is not set, probe it and set it. {- On Windows, if HOME is not set, probe it and set it.
- This is a workaround for some Cygwin commands needing HOME to be set, - This is a workaround for some Cygwin commands needing HOME to be set.
- and for there being no known way to set environment variables on
- Windows, except by passing an environment in each call to a program.
- While ugly, this workaround is easier than trying to ensure HOME is set
- in all calls to the affected programs.
- -
- If TZ is set, unset it. - If TZ is set, unset it.
- TZ being set can interfere with workarounds for Windows timezone - TZ being set can interfere with workarounds for Windows timezone
- horribleness, and prevents getCurrentTimeZone from seeing the system - horribleness, and prevents getCurrentTimeZone from seeing the system
- time zone. - time zone.
-
- Due to Windows limitations, have to re-exec git-annex with the new
- environment.
-} -}
winEnv :: ([String] -> IO ()) -> [String] -> IO () winEnv :: IO ()
winEnv a ps = do winEnv = do
e <- getEnvironment
home <- myHomeDir home <- myHomeDir
let e' = wantedenv e home setEnv "HOME" home False
if (e' /= e) setEnv "CYGWIN" "nodosfilewarning" True
then do unsetEnv "TZ"
cmd <- readProgramFile
(_, _, _, pid) <- createProcess (proc cmd ps)
{ env = Just e' }
exitWith =<< waitForProcess pid
else a ps
where
wantedenv e home = delEntry "TZ" $ case lookup "HOME" e of
Nothing -> e
Just _ -> addEntries
[ ("HOME", home)
, ("CYGWIN", "nodosfilewarning")
] e
#endif #endif