diff --git a/cabal-install/tests/UnitTests/Distribution/Client/VCS.hs b/cabal-install/tests/UnitTests/Distribution/Client/VCS.hs
index a76dd39b082..97a771e74eb 100644
--- a/cabal-install/tests/UnitTests/Distribution/Client/VCS.hs
+++ b/cabal-install/tests/UnitTests/Distribution/Client/VCS.hs
@@ -216,22 +216,27 @@ prop_syncRepos_hg destRepoDirs syncTargetSetIterations seed =
testSetup
:: VCS Program
- -> ( Verbosity
- -> VCS ConfiguredProgram
- -> FilePath
- -> FilePath
- -> VCSTestDriver
- )
+ -> (MkVCSTestDriver -> VCSTestDriver)
-> RepoRecipe submodules
-> (VCSTestDriver -> FilePath -> RepoState -> IO a)
-> IO a
testSetup vcs mkVCSTestDriver repoRecipe theTest = do
- -- test setup
- vcs' <- configureVCS verbosity [] vcs
withTestDir verbosity "vcstest" $ \tmpdir -> do
+ -- test setup
+ vcs' <- configureVCS verbosity [] vcs
+
let srcRepoPath = tmpdir > "src"
submodulesPath = tmpdir > "submodules"
- vcsDriver = mkVCSTestDriver verbosity vcs' submodulesPath srcRepoPath
+ vcsDriver =
+ mkVCSTestDriver
+ MkVCSTestDriver
+ { mkVcsVerbosity = verbosity
+ , mkVcsVcs = vcs'
+ , mkVcsSubmoduleDir = submodulesPath
+ , mkVcsRepoRoot = srcRepoPath
+ , mkVcsTmpDir = tmpdir
+ }
+
repoState <- createRepo vcsDriver repoRecipe
-- actual test
@@ -252,12 +257,7 @@ testSetup vcs mkVCSTestDriver repoRecipe theTest = do
-- the working state is the same as the pure representation.
prop_framework
:: VCS Program
- -> ( Verbosity
- -> VCS ConfiguredProgram
- -> FilePath
- -> FilePath
- -> VCSTestDriver
- )
+ -> (MkVCSTestDriver -> VCSTestDriver)
-> RepoRecipe submodules
-> IO ()
prop_framework vcs mkVCSTestDriver repoRecipe =
@@ -288,12 +288,7 @@ prop_framework vcs mkVCSTestDriver repoRecipe =
prop_cloneRepo
:: VCS Program
- -> ( Verbosity
- -> VCS ConfiguredProgram
- -> FilePath
- -> FilePath
- -> VCSTestDriver
- )
+ -> (MkVCSTestDriver -> VCSTestDriver)
-> RepoRecipe submodules
-> IO ()
prop_cloneRepo vcs mkVCSTestDriver repoRecipe =
@@ -329,12 +324,7 @@ newtype PrngSeed = PrngSeed Int deriving (Show)
prop_syncRepos
:: VCS Program
- -> ( Verbosity
- -> VCS ConfiguredProgram
- -> FilePath
- -> FilePath
- -> VCSTestDriver
- )
+ -> (MkVCSTestDriver -> VCSTestDriver)
-> RepoDirSet
-> SyncTargetIterations
-> PrngSeed
@@ -839,237 +829,271 @@ data VCSTestDriver = VCSTestDriver
(TagName -> FilePath -> IO ())
}
+data MkVCSTestDriver = MkVCSTestDriver
+ { mkVcsVerbosity :: Verbosity
+ , mkVcsVcs :: VCS ConfiguredProgram
+ , mkVcsSubmoduleDir :: FilePath
+ , mkVcsRepoRoot :: FilePath
+ , mkVcsTmpDir :: FilePath
+ }
+
+vcsTestDriverGit :: MkVCSTestDriver -> VCSTestDriver
vcsTestDriverGit
- :: Verbosity
- -> VCS ConfiguredProgram
- -> FilePath
- -> FilePath
- -> VCSTestDriver
-vcsTestDriverGit verbosity vcs submoduleDir repoRoot =
- VCSTestDriver
- { vcsVCS = vcs'
- , vcsRepoRoot = repoRoot
- , vcsIgnoreFiles = Set.empty
- , vcsInit =
- git $ ["init"] ++ verboseArg
- , vcsAddFile = \_ filename ->
- git ["add", filename]
- , vcsCommitChanges = \_state -> do
- git $
- [ "-c"
- , "user.name=A"
- , "-c"
- , "user.email=a@example.com"
- , "commit"
- , "--all"
- , "--message=a patch"
- , "--author=A "
+ MkVCSTestDriver
+ { mkVcsVerbosity = verbosity
+ , mkVcsVcs = vcs
+ , mkVcsSubmoduleDir = submoduleDir
+ , mkVcsRepoRoot = repoRoot
+ , mkVcsTmpDir = tmpDir
+ } =
+ VCSTestDriver
+ { vcsVCS = vcs'
+ , vcsRepoRoot = repoRoot
+ , vcsIgnoreFiles = Set.empty
+ , vcsInit = do
+ createDirectoryIfMissing True home
+ gitconfigExists <- doesFileExist gitconfigPath
+ unless gitconfigExists $ do
+ writeFile gitconfigPath gitconfig
+ git $ ["init"] ++ verboseArg
+ , vcsAddFile = \_ filename ->
+ git ["add", filename]
+ , vcsCommitChanges = \_state -> do
+ git $
+ [ "commit"
+ , "--all"
+ , "--message=a patch"
+ ]
+ ++ verboseArg
+ commit <- git' ["rev-parse", "HEAD"]
+ let commit' = takeWhile (not . isSpace) commit
+ return (Just commit')
+ , vcsTagState = \_ tagname ->
+ git ["tag", "--force", "--no-sign", tagname]
+ , vcsSubmoduleDriver =
+ \newPath ->
+ pure $
+ vcsTestDriverGit
+ MkVCSTestDriver
+ { mkVcsVerbosity = verbosity
+ , mkVcsVcs = vcs'
+ , mkVcsSubmoduleDir = submoduleDir
+ , mkVcsRepoRoot = submoduleDir > newPath
+ , mkVcsTmpDir = tmpDir
+ }
+ , vcsAddSubmodule = \_ source dest -> do
+ destExists <-
+ (||)
+ <$> doesFileExist (repoRoot > dest)
+ <*> doesDirectoryExist (repoRoot > dest)
+ when destExists $ git ["rm", "-f", dest]
+ -- If there is an old submodule git dir with the same name, remove it.
+ -- It most likely has a different URL and `git submodule add` will fai.
+ submoduleGitDirExists <- doesDirectoryExist $ submoduleGitDir dest
+ when submoduleGitDirExists $ removeDirectoryRecursive (submoduleGitDir dest)
+ git ["submodule", "add", source, dest]
+ git ["submodule", "update", "--init", "--recursive", "--force"]
+ , vcsSwitchBranch = \RepoState{allBranches} branchname -> do
+ deinitAndRemoveCachedSubmodules
+ unless (branchname `Map.member` allBranches) $
+ git ["branch", branchname]
+ git $ ["checkout", branchname] ++ verboseArg
+ updateSubmodulesAndCleanup
+ , vcsCheckoutTag = Left $ \tagname -> do
+ deinitAndRemoveCachedSubmodules
+ git $ ["checkout", "--detach", "--force", tagname] ++ verboseArg
+ updateSubmodulesAndCleanup
+ }
+ where
+ home = tmpDir > "home"
+ gitconfigPath = home > ".gitconfig"
+ -- Git 2.38.1 and newer fails to clone from local paths with `fatal: transport 'file'
+ -- not allowed` unless `protocol.file.allow=always` is set.
+ --
+ -- This is not safe in general, but it's fine in the test suite.
+ --
+ -- See: https://github.blog/open-source/git/git-security-vulnerabilities-announced/#fn-67904-1
+ -- See: https://git-scm.com/docs/git-config#Documentation/git-config.txt-protocolallow
+ gitconfig =
+ unlines
+ [ "[protocol.file]"
+ , " allow = always"
+ , "[user]"
+ , " name = Puppy Doggy"
+ , " email = puppy.doggy@example.com"
]
- ++ verboseArg
- commit <- git' ["log", "--format=%H", "-1"]
- let commit' = takeWhile (not . isSpace) commit
- return (Just commit')
- , vcsTagState = \_ tagname ->
- git ["tag", "--force", "--no-sign", tagname]
- , vcsSubmoduleDriver =
- pure . vcsTestDriverGit verbosity vcs' submoduleDir . (submoduleDir >)
- , vcsAddSubmodule = \_ source dest -> do
- destExists <-
- (||)
- <$> doesFileExist (repoRoot > dest)
- <*> doesDirectoryExist (repoRoot > dest)
- when destExists $ git ["rm", "-f", dest]
- -- If there is an old submodule git dir with the same name, remove it.
- -- It most likely has a different URL and `git submodule add` will fai.
- submoduleGitDirExists <- doesDirectoryExist $ submoduleGitDir dest
- when submoduleGitDirExists $ removeDirectoryRecursive (submoduleGitDir dest)
- git ["submodule", "add", source, dest]
- git ["submodule", "update", "--init", "--recursive", "--force"]
- , vcsSwitchBranch = \RepoState{allBranches} branchname -> do
- deinitAndRemoveCachedSubmodules
- unless (branchname `Map.member` allBranches) $
- git ["branch", branchname]
- git $ ["checkout", branchname] ++ verboseArg
- updateSubmodulesAndCleanup
- , vcsCheckoutTag = Left $ \tagname -> do
- deinitAndRemoveCachedSubmodules
- git $ ["checkout", "--detach", "--force", tagname] ++ verboseArg
- updateSubmodulesAndCleanup
- }
- where
- -- Git 2.38.1 and newer fails to clone from local paths with `fatal: transport 'file'
- -- not allowed` unless `protocol.file.allow=always` is set.
- --
- -- This is not safe in general, but it's fine in the test suite.
- --
- -- See: https://github.blog/open-source/git/git-security-vulnerabilities-announced/#fn-67904-1
- -- See: https://git-scm.com/docs/git-config#Documentation/git-config.txt-protocolallow
- vcs' =
- vcs
- { vcsProgram =
- (vcsProgram vcs)
- { programDefaultArgs =
- programDefaultArgs (vcsProgram vcs)
- ++ [ "-c"
- , "protocol.file.allow=always"
- ]
- }
- }
- gitInvocation args =
- (programInvocation (vcsProgram vcs') args)
- { progInvokeCwd = Just repoRoot
- }
- git = runProgramInvocation verbosity . gitInvocation
- git' = getProgramInvocationOutput verbosity . gitInvocation
- verboseArg = ["--quiet" | verbosity < Verbosity.normal]
- submoduleGitDir path = repoRoot > ".git" > "modules" > path
- deinitAndRemoveCachedSubmodules = do
- git $ ["submodule", "deinit", "--force", "--all"] ++ verboseArg
- let gitModulesDir = repoRoot > ".git" > "modules"
- gitModulesExists <- doesDirectoryExist gitModulesDir
- when gitModulesExists $ removeDirectoryRecursive gitModulesDir
- updateSubmodulesAndCleanup = do
- git $ ["submodule", "sync", "--recursive"] ++ verboseArg
- git $ ["submodule", "update", "--init", "--recursive", "--force"] ++ verboseArg
- git $ ["submodule", "foreach", "--recursive"] ++ verboseArg ++ ["git clean -ffxdq"]
- git $ ["clean", "-ffxdq"] ++ verboseArg
+
+ vcs' =
+ vcs
+ { vcsProgram =
+ (vcsProgram vcs)
+ { programOverrideEnv =
+ programOverrideEnv (vcsProgram vcs)
+ ++ [ -- > Whether to skip reading settings from the system-wide $(prefix)/etc/gitconfig file.
+ ("GIT_CONFIG_NOSYSTEM", Just "1")
+ , ("GIT_CONFIG_GLOBAL", Just gitconfigPath)
+ , -- Setting the author and committer dates makes commit hashes deterministic between test runs.
+ ("GIT_AUTHOR_DATE", Just "1998-04-30T18:25:03-0400")
+ , ("GIT_COMMITTER_DATE", Just "1998-04-30T18:25:00-0400")
+ , ("HOME", Just home)
+ ]
+ }
+ }
+ gitInvocation args =
+ (programInvocation (vcsProgram vcs') args)
+ { progInvokeCwd = Just repoRoot
+ }
+ git = runProgramInvocation verbosity . gitInvocation
+ git' = getProgramInvocationOutput verbosity . gitInvocation
+ verboseArg = ["--quiet" | verbosity < Verbosity.normal]
+ submoduleGitDir path = repoRoot > ".git" > "modules" > path
+ deinitAndRemoveCachedSubmodules = do
+ git $ ["submodule", "deinit", "--force", "--all"] ++ verboseArg
+ let gitModulesDir = repoRoot > ".git" > "modules"
+ gitModulesExists <- doesDirectoryExist gitModulesDir
+ when gitModulesExists $ removeDirectoryRecursive gitModulesDir
+ updateSubmodulesAndCleanup = do
+ git $ ["submodule", "sync", "--recursive"] ++ verboseArg
+ git $ ["submodule", "update", "--init", "--recursive", "--force"] ++ verboseArg
+ git $ ["submodule", "foreach", "--recursive"] ++ verboseArg ++ ["git clean -ffxdq"]
+ git $ ["clean", "-ffxdq"] ++ verboseArg
type MTimeChange = Int
+vcsTestDriverDarcs :: MTimeChange -> MkVCSTestDriver -> VCSTestDriver
vcsTestDriverDarcs
- :: MTimeChange
- -> Verbosity
- -> VCS ConfiguredProgram
- -> FilePath
- -> FilePath
- -> VCSTestDriver
-vcsTestDriverDarcs mtimeChange verbosity vcs _ repoRoot =
- VCSTestDriver
- { vcsVCS = vcs
- , vcsRepoRoot = repoRoot
- , vcsIgnoreFiles = Set.singleton "_darcs"
- , vcsInit =
- darcs ["initialize"]
- , vcsAddFile = \state filename -> do
- threadDelay mtimeChange
- unless (filename `Map.member` currentWorking state) $
- darcs ["add", filename]
- , -- Darcs's file change tracking relies on mtime changes,
- -- so we have to be careful with doing stuff too quickly:
-
- vcsSubmoduleDriver = \_ ->
- fail "vcsSubmoduleDriver: darcs does not support submodules"
- , vcsAddSubmodule = \_ _ _ ->
- fail "vcsAddSubmodule: darcs does not support submodules"
- , vcsCommitChanges = \_state -> do
- threadDelay mtimeChange
- darcs ["record", "--all", "--author=author", "--name=a patch"]
- return Nothing
- , vcsTagState = \_ tagname ->
- darcs ["tag", "--author=author", tagname]
- , vcsSwitchBranch = \_ _ ->
- fail "vcsSwitchBranch: darcs does not support branches within a repo"
- , vcsCheckoutTag = Right $ \tagname dest ->
- darcs ["clone", "--lazy", "--tag=^" ++ tagname ++ "$", ".", dest]
- }
- where
- darcsInvocation args =
- (programInvocation (vcsProgram vcs) args)
- { progInvokeCwd = Just repoRoot
- }
- darcs = runProgramInvocation verbosity . darcsInvocation
+ mtimeChange
+ MkVCSTestDriver
+ { mkVcsVerbosity = verbosity
+ , mkVcsVcs = vcs
+ , mkVcsRepoRoot = repoRoot
+ } =
+ VCSTestDriver
+ { vcsVCS = vcs
+ , vcsRepoRoot = repoRoot
+ , vcsIgnoreFiles = Set.singleton "_darcs"
+ , vcsInit =
+ darcs ["initialize"]
+ , vcsAddFile = \state filename -> do
+ threadDelay mtimeChange
+ unless (filename `Map.member` currentWorking state) $
+ darcs ["add", filename]
+ , -- Darcs's file change tracking relies on mtime changes,
+ -- so we have to be careful with doing stuff too quickly:
+
+ vcsSubmoduleDriver = \_ ->
+ fail "vcsSubmoduleDriver: darcs does not support submodules"
+ , vcsAddSubmodule = \_ _ _ ->
+ fail "vcsAddSubmodule: darcs does not support submodules"
+ , vcsCommitChanges = \_state -> do
+ threadDelay mtimeChange
+ darcs ["record", "--all", "--author=author", "--name=a patch"]
+ return Nothing
+ , vcsTagState = \_ tagname ->
+ darcs ["tag", "--author=author", tagname]
+ , vcsSwitchBranch = \_ _ ->
+ fail "vcsSwitchBranch: darcs does not support branches within a repo"
+ , vcsCheckoutTag = Right $ \tagname dest ->
+ darcs ["clone", "--lazy", "--tag=^" ++ tagname ++ "$", ".", dest]
+ }
+ where
+ darcsInvocation args =
+ (programInvocation (vcsProgram vcs) args)
+ { progInvokeCwd = Just repoRoot
+ }
+ darcs = runProgramInvocation verbosity . darcsInvocation
+vcsTestDriverPijul :: MkVCSTestDriver -> VCSTestDriver
vcsTestDriverPijul
- :: Verbosity
- -> VCS ConfiguredProgram
- -> FilePath
- -> FilePath
- -> VCSTestDriver
-vcsTestDriverPijul verbosity vcs _ repoRoot =
- VCSTestDriver
- { vcsVCS = vcs
- , vcsRepoRoot = repoRoot
- , vcsIgnoreFiles = Set.empty
- , vcsInit =
- pijul $ ["init"]
- , vcsAddFile = \_ filename ->
- pijul ["add", filename]
- , vcsSubmoduleDriver = \_ ->
- fail "vcsSubmoduleDriver: pijul does not support submodules"
- , vcsAddSubmodule = \_ _ _ ->
- fail "vcsAddSubmodule: pijul does not support submodules"
- , vcsCommitChanges = \_state -> do
- pijul $
- [ "record"
- , "-a"
- , "-m 'a patch'"
- , "-A 'A '"
- ]
- commit <- pijul' ["log"]
- let commit' = takeWhile (not . isSpace) commit
- return (Just commit')
- , -- tags work differently in pijul...
- -- so this is wrong
- vcsTagState = \_ tagname ->
- pijul ["tag", tagname]
- , vcsSwitchBranch = \_ branchname -> do
- -- unless (branchname `Map.member` allBranches) $
- -- pijul ["from-branch", branchname]
- pijul $ ["checkout", branchname]
- , vcsCheckoutTag = Left $ \tagname ->
- pijul $ ["checkout", tagname]
- }
- where
- gitInvocation args =
- (programInvocation (vcsProgram vcs) args)
- { progInvokeCwd = Just repoRoot
- }
- pijul = runProgramInvocation verbosity . gitInvocation
- pijul' = getProgramInvocationOutput verbosity . gitInvocation
-
+ MkVCSTestDriver
+ { mkVcsVerbosity = verbosity
+ , mkVcsVcs = vcs
+ , mkVcsRepoRoot = repoRoot
+ } =
+ VCSTestDriver
+ { vcsVCS = vcs
+ , vcsRepoRoot = repoRoot
+ , vcsIgnoreFiles = Set.empty
+ , vcsInit =
+ pijul $ ["init"]
+ , vcsAddFile = \_ filename ->
+ pijul ["add", filename]
+ , vcsSubmoduleDriver = \_ ->
+ fail "vcsSubmoduleDriver: pijul does not support submodules"
+ , vcsAddSubmodule = \_ _ _ ->
+ fail "vcsAddSubmodule: pijul does not support submodules"
+ , vcsCommitChanges = \_state -> do
+ pijul $
+ [ "record"
+ , "-a"
+ , "-m 'a patch'"
+ , "-A 'A '"
+ ]
+ commit <- pijul' ["log"]
+ let commit' = takeWhile (not . isSpace) commit
+ return (Just commit')
+ , -- tags work differently in pijul...
+ -- so this is wrong
+ vcsTagState = \_ tagname ->
+ pijul ["tag", tagname]
+ , vcsSwitchBranch = \_ branchname -> do
+ -- unless (branchname `Map.member` allBranches) $
+ -- pijul ["from-branch", branchname]
+ pijul $ ["checkout", branchname]
+ , vcsCheckoutTag = Left $ \tagname ->
+ pijul $ ["checkout", tagname]
+ }
+ where
+ gitInvocation args =
+ (programInvocation (vcsProgram vcs) args)
+ { progInvokeCwd = Just repoRoot
+ }
+ pijul = runProgramInvocation verbosity . gitInvocation
+ pijul' = getProgramInvocationOutput verbosity . gitInvocation
+
+vcsTestDriverHg :: MkVCSTestDriver -> VCSTestDriver
vcsTestDriverHg
- :: Verbosity
- -> VCS ConfiguredProgram
- -> FilePath
- -> FilePath
- -> VCSTestDriver
-vcsTestDriverHg verbosity vcs _ repoRoot =
- VCSTestDriver
- { vcsVCS = vcs
- , vcsRepoRoot = repoRoot
- , vcsIgnoreFiles = Set.empty
- , vcsInit =
- hg $ ["init"] ++ verboseArg
- , vcsAddFile = \_ filename ->
- hg ["add", filename]
- , vcsSubmoduleDriver = \_ ->
- fail "vcsSubmoduleDriver: hg submodules not supported"
- , vcsAddSubmodule = \_ _ _ ->
- fail "vcsAddSubmodule: hg submodules not supported"
- , vcsCommitChanges = \_state -> do
- hg $
- [ "--user='A '"
- , "commit"
- , "--message=a patch"
- ]
- ++ verboseArg
- commit <- hg' ["log", "--template='{node}\\n' -l1"]
- let commit' = takeWhile (not . isSpace) commit
- return (Just commit')
- , vcsTagState = \_ tagname ->
- hg ["tag", "--force", tagname]
- , vcsSwitchBranch = \RepoState{allBranches} branchname -> do
- unless (branchname `Map.member` allBranches) $
- hg ["branch", branchname]
- hg $ ["checkout", branchname] ++ verboseArg
- , vcsCheckoutTag = Left $ \tagname ->
- hg $ ["checkout", "--rev", tagname] ++ verboseArg
- }
- where
- hgInvocation args =
- (programInvocation (vcsProgram vcs) args)
- { progInvokeCwd = Just repoRoot
- }
- hg = runProgramInvocation verbosity . hgInvocation
- hg' = getProgramInvocationOutput verbosity . hgInvocation
- verboseArg = ["--quiet" | verbosity < Verbosity.normal]
+ MkVCSTestDriver
+ { mkVcsVerbosity = verbosity
+ , mkVcsVcs = vcs
+ , mkVcsRepoRoot = repoRoot
+ } =
+ VCSTestDriver
+ { vcsVCS = vcs
+ , vcsRepoRoot = repoRoot
+ , vcsIgnoreFiles = Set.empty
+ , vcsInit =
+ hg $ ["init"] ++ verboseArg
+ , vcsAddFile = \_ filename ->
+ hg ["add", filename]
+ , vcsSubmoduleDriver = \_ ->
+ fail "vcsSubmoduleDriver: hg submodules not supported"
+ , vcsAddSubmodule = \_ _ _ ->
+ fail "vcsAddSubmodule: hg submodules not supported"
+ , vcsCommitChanges = \_state -> do
+ hg $
+ [ "--user='A '"
+ , "commit"
+ , "--message=a patch"
+ ]
+ ++ verboseArg
+ commit <- hg' ["log", "--template='{node}\\n' -l1"]
+ let commit' = takeWhile (not . isSpace) commit
+ return (Just commit')
+ , vcsTagState = \_ tagname ->
+ hg ["tag", "--force", tagname]
+ , vcsSwitchBranch = \RepoState{allBranches} branchname -> do
+ unless (branchname `Map.member` allBranches) $
+ hg ["branch", branchname]
+ hg $ ["checkout", branchname] ++ verboseArg
+ , vcsCheckoutTag = Left $ \tagname ->
+ hg $ ["checkout", "--rev", tagname] ++ verboseArg
+ }
+ where
+ hgInvocation args =
+ (programInvocation (vcsProgram vcs) args)
+ { progInvokeCwd = Just repoRoot
+ }
+ hg = runProgramInvocation verbosity . hgInvocation
+ hg' = getProgramInvocationOutput verbosity . hgInvocation
+ verboseArg = ["--quiet" | verbosity < Verbosity.normal]