packages feed

darcs 2.3.1 → 2.4

raw patch · 251 files changed

+12183/−10399 lines, 251 filesdep ~arraydep ~containersdep ~hashed-storagesetup-changedbinary-added

Dependency ranges changed: array, containers, hashed-storage, unix

Files

Distribution/ShellHarness.hs view
@@ -4,16 +4,18 @@ import Prelude hiding( catch ) import System.Directory ( getCurrentDirectory, setPermissions,                           Permissions(..), getDirectoryContents,-                          findExecutable, createDirectoryIfMissing )+                          findExecutable, createDirectoryIfMissing,+                          renameFile, removeFile ) import System.Environment ( getEnv, getEnvironment ) import System.Exit ( ExitCode (..) ) import System.FilePath import System.IO+import System( system ) import System.Process ( ProcessHandle,                         runInteractiveProcess, waitForProcess,                         getProcessExitCode ) import Data.Maybe-import Data.List ( isInfixOf, isPrefixOf, (\\), nubBy )+import Data.List ( isInfixOf, isPrefixOf, (\\), nubBy, isSuffixOf ) import Control.Concurrent #if __GLASGOW_HASKELL__ >= 610 import Control.OldException@@ -40,12 +42,15 @@                          return True  run :: Maybe FilePath -> [String] -> IO [String]-run set_darcs_path tests= do+run set_darcs_path tests = do     cwd <-  getCurrentDirectory     path <- getEnv "PATH"     env <- getEnvironment+    bash <- find_bash     darcs_path <- case set_darcs_path of-                    Nothing -> get_darcs_path+                    Nothing -> case lookup "DARCS" env of+                                 Nothing -> return (cwd ++ "/..")+                                 Just d  -> return $ takeDirectory d                     Just x -> return x     let myenv = [("HOME",cwd)                 ,("TESTS_WD",cwd)@@ -55,40 +60,48 @@                 ,("PATH",(darcs_path++":"++path))                 ,("DARCS_DONT_COLOR","1")                 ,("DARCS_DONT_ESCAPE_ANYTHING","1")]-    bash <- find_bash-    let shell = takeWhile (/= '\n') bash+        shell = takeWhile (/= '\n') bash     putStrLn $ "Using bash shell in '"++shell++"'"-    set_prefs+    catch (appendFile (".darcs/defaults") "\nALL --ignore-times\n")+          (\e -> fail $ "Unable to set preferences: " ++ show e)     run_helper shell tests []  (set_env myenv env)-  where get_darcs_path = do-           env <- getEnvironment-           cwd <-  getCurrentDirectory-           case lookup "DARCS" env of-                Nothing -> return (cwd ++ "/..")-                Just d  -> return $ takeDirectory d-        set_prefs = do-            finally (catch (appendFile ".darcs/defaults" "\nALL --ignore-times\n")-                           (\e -> fail $ "Unable to set preferences: "-                                         ++ show e))-                    (createDirectoryIfMissing  False ".darcs")++data Status = Success | Failed | Skipped+ run_helper :: String -> [String] -> [String] ->                   [(String,String)] -> IO [String] run_helper _ [] fails _ = return fails run_helper shell (test:ts) fails env = do     putStr $ "Running " ++ test ++ " ..." ++ (replicate (36 - (length test)) ' ')-    (output,success) <- backtick shell test env-    if success then do putStrLn " passed."-                       cleanup_dirs-                       run_helper shell ts fails env-               else do putStrLn " failed."-                       putStrLn $ "Probable reason :" ++ output-                       cleanup_dirs-                       run_helper shell ts (fails++[test]) env-  where cleanup_dirs :: IO ()-        cleanup_dirs =+    (output,result) <- backtick shell test env+    cleanup+    case result of+      Skipped -> do putStrLn " skipped."+                    run_helper shell ts fails env+      Success -> do putStrLn " passed."+                    run_helper shell ts fails env+      Failed -> do putStrLn " failed."+                   putStrLn $ "Probable reason :" ++ output+                   run_helper shell ts (fails++[test]) env+  where cleanup :: IO ()+        cleanup =           do dirfiles <- getDirectoryContents (fromJust $ lookup "TESTS_WD" env)              let tempfiles = (filter ("temp" `isPrefixOf`) dirfiles) ++                              (filter ("tmp" `isPrefixOf`) dirfiles)+             when (isJust $ lookup "HPCTIXDIR" env) $ do+                 let tixdir = fromJust $ lookup "HPCTIXDIR" env+                 tixlist <- getDirectoryContents tixdir+                 oldsum <- if ("sum.tix" `elem` tixlist)+                              then do renameFile (tixdir </> "sum.tix")+                                                 (tixdir </> "oldsum.tix")+                                      return [tixdir </> "oldsum.tix"]+                              else return []+                 let tixfiles = oldsum ++ [ tixdir </> f | f <- tixlist+                                                         , "darcs-" `isPrefixOf` f+                                                         , ".tix" `isSuffixOf` f ]+                 system $ "hpc sum --union --output=" ++ tixdir </> "sum.tix" ++ " " ++ unwords tixfiles+                 forM tixfiles $ \f -> removeFile f+                 return ()              mapM_ (\x->                    setPermissions x (Permissions                                     {readable = True@@ -98,12 +111,13 @@                                    )                  ) tempfiles -backtick :: String -> String -> [(String, String)]-> IO (String,Bool)+backtick :: String -> String -> [(String, String)]-> IO (String,Status) backtick cmd args env = do    (exitcode,res) <- backtick_helper cmd args env    case exitcode of-        ExitSuccess -> return (res, True)-        ExitFailure _ -> return (res, False)+        ExitSuccess -> return (res, Success)+        ExitFailure 200 -> return (res, Skipped)+        ExitFailure _ -> return (res, Failed)  backtick_helper :: String -> String -> [(String,String)] ->                                       IO (ExitCode, String)
+ GNUmakefile view
@@ -0,0 +1,62 @@+### XXX we eventually want building of the manual to be part of Setup.lhs++# hardcode some bits+RUBBER=rubber++DARCS = dist/build/darcs/darcs+PREPROC=./dist/build/darcs/darcs --preprocess-manual+PREPROCHTML=--html+TEXSOURCES = src/darcs.tex $(wildcard src/*.tex) $(filter %.lhs,$(DARCS_FILES))+doc/manual/darcs.tex: $(TEXSOURCES) $(DARCS)+	$(PREPROC) darcs.tex $(PREPROCHTML) >$@+doc/manual/darcs_print.tex: $(TEXSOURCES) $(DARCS)+	$(PREPROC) darcs.tex >$@+doc/manual/patch-theory.tex: $(TEXSOURCES) $(UNIT_FILES) $(DARCS)+	$(PREPROC) Darcs/Patch/Properties.lhs >$@++%.pdf: %.tex+	cd $(<D) && $(RUBBER) --pdf $(<F)+%.ps: %.tex+	cd $(<D) && $(RUBBER) --ps $(<F)++ps pdf: %: doc/manual/darcs.% doc/manual/patch-theory.%+html: doc/manual/index.html+website: ps pdf html doc/manual/bigpage.html++### TODO use latex2html since bigpage seems to needslatex2html anyway;+###      we can restore hevea/tex4ht support when we move this to Setup.lhs+doc/manual/index.html: doc/manual/darcs.tex src/gpl.tex doc/darcs.css+	latex2html -split +1 -dir doc/manual doc/manual/darcs.tex+	cp -f doc/darcs.css doc/manual/darcs.css++doc/manual/bigpage.html: doc/manual/darcs.tex src/gpl.tex doc/darcs.css+	ln -sf darcs.tex doc/manual/bigpage.tex+	latex2html -split 0 -external_file darcs -prefix big \+		-no_auto_link -dir doc/manual doc/manual/bigpage.tex+	cp -f doc/darcs.css doc/manual/bigpage.css++doc/manual/darcs.ps: doc/manual/darcs_print.ps+	cp $< $@+doc/manual/darcs.pdf: doc/manual/darcs_print.pdf+	cp $< $@++# Good for tags.+DARCS_FILES = $(wildcard src/[A-Z]*.hs src/*/[A-Z]*.hs src/*/*/[A-Z]*.hs) \+	      $(wildcard src/[A-Z]*.lhs src/*/[A-Z]*.lhs src/*/*/[A-Z]*.lhs)++tags: $(DARCS_FILES) src/*.c+	hasktags -c $(filter %.lhs %.hs,$^)+	ctags -a $(filter %.c,$^)++# TAGS is for etags, whereas tags is for ctags+TAGS: $(DARCS_FILES) src/*.c+	hasktags -e $(filter %.lhs %.hs,$^)+	etags -a $(filter %.c,$^)++clean:+	rm -f TAGS tags+	rm -f doc/manual/bigpage.tex+	rm -f doc/manual/*.html doc/manual/darcs*.??? doc/manual/darcs.lg+	rm -f doc/manual/darcs.xref c_context.c doc/darcs_print.ps++.PHONY: ps pdf html clean website
README view
@@ -31,6 +31,7 @@ an executable in ~/.cabal/bin/darcs (this will also automatically fetch and build dependencies from the Hackage server). +    $ cabal update     $ cabal install  Otherwise, if you have the "cabal" package but not the "cabal-install"@@ -55,11 +56,11 @@ Hacking ======= For more information about darcs hacking and best practices please check-the darcs wiki at http://wiki.darcs.net/DarcsWiki+the darcs wiki at http://wiki.darcs.net  Of particular interest are the following documents:-  * http://wiki.darcs.net/index.html/DeveloperFAQ-  * http://wiki.darcs.net/index.html/DeveloperTips+  * http://wiki.darcs.net/Development/GettingStarted+  * http://wiki.darcs.net/Development/FAQ  Testing =======
Setup.lhs view
@@ -5,10 +5,12 @@  import Distribution.Simple          ( defaultMainWithHooks, UserHooks(..), simpleUserHooks )+import Distribution.ModuleName( toFilePath ) import Distribution.PackageDescription          ( PackageDescription(executables), Executable(buildInfo, exeName)          , BuildInfo(customFieldsBI), emptyBuildInfo-         , updatePackageDescription, cppOptions, ccOptions )+         , updatePackageDescription, cppOptions, ccOptions+         , library, libBuildInfo, otherModules ) import Distribution.Package          ( packageVersion ) import Distribution.Version@@ -42,7 +44,7 @@ import System.IO (openFile, IOMode (..)) import System.Process (runProcess) import System.IO.Error ( isDoesNotExistError )-import Data.List( isSuffixOf, sort, partition )+import Data.List( isPrefixOf, isSuffixOf, sort, partition )  import System.FilePath       ( (</>), splitDirectories, isAbsolute ) import Foreign.Marshal.Utils ( with )@@ -99,7 +101,7 @@                "bugs-darcs-2.dir",                "bugs-hashed.dir",                "bugs-old-fashioned-inventory.dir",-               "tests_network-.dir"],+               "tests-network.dir"],    sDistHook = \ pkg lbi hooks flags -> do     let pkgVer = packageVersion pkg@@ -108,8 +110,13 @@     y <- context verb pkgVer     rewriteFile "release/distributed-version" $ show x     rewriteFile "release/distributed-context" $ show y+    putStrLn "about to hand over"+    let pkg' = pkg { library = sanity (library pkg) }+        sanity (Just lib) = Just $ lib { libBuildInfo = sanity' $ libBuildInfo lib }+        sanity _ = error "eh"+        sanity' bi = bi { otherModules = [ m | m <- otherModules bi, toFilePath m /= "Version" ] } -    sDistHook simpleUserHooks pkg lbi hooks flags+    sDistHook simpleUserHooks pkg' lbi hooks flags }  -- | For @./Setup build@ and @./Setup haddock@, do some unusual@@ -117,17 +124,13 @@ commonBuildHook :: (UserHooks -> PackageDescription -> LocalBuildInfo -> t -> a)                 -> PackageDescription -> LocalBuildInfo -> t -> Verbosity -> IO a commonBuildHook runHook pkg lbi hooks verbosity = do-  -- Autoconf may have generated a context file.  Remove it before-  -- building, as its existence inexplicably breaks Cabal.-  removeFile "src/Context.hs"-    `catch` (\e -> unless (isDoesNotExistError e) (ioError e))+  (version, state) <- determineVersion verbosity pkg    -- Create our own context file.-  writeGeneratedModules verbosity pkg lbi+  generateVersionModule verbosity pkg lbi version state    -- Add custom -DFOO[=BAR] flags to the cpp (for .hs) and cc (for .c)   -- invocations, doing a dance to make the base hook aware of them.-  (version, state) <- determineVersion verbosity pkg   littleEndian <- testEndianness   let args = ("-DPACKAGE_VERSION=" ++ show' version) :              ("-DPACKAGE_VERSION_STATE=" ++ show' state) :@@ -168,14 +171,6 @@               (mandir (absoluteInstallDirs pkg lbi copy) </> "man1")               [(buildDir lbi </> "darcs", "darcs.1")] -writeGeneratedModules :: Verbosity-                      -> PackageDescription -> LocalBuildInfo -> IO ()-writeGeneratedModules verbosity pkg lbi = do-  createDirectoryIfMissingVerbose verbosity True (autogenModulesDir lbi)--  let contextModulePath = autogenModulesDir lbi </> "Context.hs"-  generateContextModule verbosity contextModulePath pkg- determineVersion :: Verbosity -> PackageDescription -> IO (String, String) determineVersion verbosity pkg = do   let darcsVersion  =  packageVersion pkg@@ -216,12 +211,16 @@  where   versionFile = "release/distributed-version" -generateContextModule :: (Package pkg) => Verbosity -> FilePath -> pkg -> IO ()-generateContextModule verbosity targetFile pkg = do+generateVersionModule :: Verbosity -> PackageDescription -> LocalBuildInfo+                      -> String -> String -> IO ()+generateVersionModule verbosity pkg lbi version state = do+  let dir = autogenModulesDir lbi+  createDirectoryIfMissingVerbose verbosity True dir   ctx <- context verbosity (packageVersion pkg)-  rewriteFile targetFile $ unlines-    ["module Context where"-    ,"context :: String"+  rewriteFile (dir </> "Version.hs") $ unlines+    ["module Version where"+    ,"version, context :: String"+    ,"version = \"" ++ version ++ " (" ++ state ++ ")\""     ,"context = " ++ case ctx of                        Just x -> show x                        Nothing -> show "context not available"@@ -263,36 +262,41 @@  data TestKind = Bug | Test | Network deriving Eq -instance Show TestKind where-    show Bug = "bugs"-    show Test = "tests"-    show Network = "tests/network"+testDir :: TestKind -> String+testDir Bug = "tests"+testDir Test = "tests"+testDir Network = "tests/network" -flat :: (Show a) => a -> String-flat a = [ if x == '/' then '_' else x | x <- show a ]+deslash :: Char -> Char+deslash '/' = '-'+deslash x  = x -isTest :: FilePath -> Bool-isTest = (".sh" `isSuffixOf`)+isSh :: FilePath -> Bool+isSh = (".sh" `isSuffixOf`) +-- | By convention, a test script starts with "failing-" iff it is+-- expected to fail, i.e. it is a bug that hasn't been fixed yet.+isTest :: TestKind -> FilePath -> Bool+isTest Bug = ("failing-" `isPrefixOf`)+isTest _   = not . isTest Bug+ execTests :: FilePath -> TestKind -> String -> [String] -> IO () execTests darcs_path k fmt tests = do-  let dir = (flat k) ++ "-" ++ fmt ++ ".dir"+  let dir = map deslash (testDir k) ++ (if null fmt then fmt else  "-" ++ fmt) ++ ".dir"   rmRf dir-  cloneTree (show k) dir+  cloneTree (testDir k) dir   withCurrentDirectory dir $ do     createDirectory ".darcs"     when (not $ null fmt) $ appendFile ".darcs/defaults" $ "ALL " ++ fmt ++ "\n"     putStrLn $ "Running tests for format: " ++ fmt-    exec- where exec = do-         fs <- case tests of-                  [] -> sort `fmap` getDirectoryContents "."-                  x -> return x-         cwd <- getCurrentDirectory-         let run = filter isTest fs-         res <- Harness.runTests (Just darcs_path) cwd run-         when ((not res) && (k /= Bug)) $ fail "Tests failed"-         return ()+    fs <- case tests of+            [] -> sort `fmap` getDirectoryContents "."+            x -> return x+    let run = filter (\f -> isSh f && isTest k f) fs+    cwd <- getCurrentDirectory+    res <- Harness.runTests (Just darcs_path) cwd run+    when ((not res) && (k /= Bug)) $ fail "Tests failed"+    return ()  individualTests :: FilePath -> [String] -> IO () individualTests darcs_path tests = do@@ -303,19 +307,18 @@             exec _ [] = return ()             exec kind to_run = allTests darcs_path kind to_run             find t = do-              let c = [t, t ++ ".sh"] ++ tryin "tests" t ++ tryin "bugs" t+              let c = [t, t ++ ".sh"] ++ tryin "tests" t                         ++ tryin "network" t               run <- map kindify `fmap` filterM doesFileExist c               return $ take 1 run             kindify test = case splitDirectories test of-                             [p, y] -> (parse_kind p, y)+                             [p, y] -> (parse_kind p y, y)                              _ -> error $ "Bad format in " ++ test ++                                           ": expected type/test"-            parse_kind "tests" = Test-            parse_kind "bugs" = Bug-            parse_kind "network" = Network-            parse_kind x = error $ "Test prefix must be one of " ++-                           "[tests, bugs, network] in " ++ x+            parse_kind "tests" y   = if isTest Bug y then Bug else Test+            parse_kind "network" _ = Network+            parse_kind x _ = error $ "Test prefix must be one of " +++                              "[tests, network] in " ++ x   allTests :: FilePath -> TestKind -> [String] -> IO ()
− bugs/add_permissions.sh
@@ -1,36 +0,0 @@-#!/usr/bin/env bash-## Darcs should refuse to add an unreadable file, because unreadable-## files aren't recordable.-##-## Copyright (C) 2005  Mark Stosberg-##-## Permission is hereby granted, free of charge, to any person-## obtaining a copy of this software and associated documentation-## files (the "Software"), to deal in the Software without-## restriction, including without limitation the rights to use, copy,-## modify, merge, publish, distribute, sublicense, and/or sell copies-## of the Software, and to permit persons to whom the Software is-## furnished to do so, subject to the following conditions:-##-## The above copyright notice and this permission notice shall be-## included in all copies or substantial portions of the Software.-##-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS-## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN-## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN-## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-## SOFTWARE.--. ../tests/lib--abort_windows                   # does not work on Windows.-rm -rf temp1                    # Another script may have left a mess.-darcs initialize --repodir temp1-touch temp1/unreadable-chmod a-r temp1/unreadable      # Make the file unreadable.-not darcs add --repodir temp1 no_perms.txt 2>temp1/log-fgrep -i 'permission denied' temp1/log-rm -rf temp1
− bugs/dist-v.sh
@@ -1,18 +0,0 @@-#!/usr/bin/env bash-set -ev--# tests for "darcs dist"--not () { "$@" && exit 1 || :; }--rm -rf temp1-mkdir temp1-cd temp1-darcs init-# needs fixed on FreeBSD-darcs dist -v 2> log-not grep error log-cd ..--rm -rf temp1-
− bugs/emailformat.sh
@@ -1,46 +0,0 @@-#!/usr/bin/env bash--# This appears to hang on Windows--set -ev-# TODO: is this really enough to make all commands interpret the given strings -# as latin1?-export LANG="en_US.ISO-8859-1"--rm -rf temp1-rm -rf temp2-mkdir temp1-mkdir temp2-cd temp1--seventysevenaddy="<aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@bbbbbbbbbb.cccccccccc.abrasoft.com>"--darcs init--echo "Have you seen the smørrebrød of René Çavésant?" > non_ascii_file-darcs add non_ascii_file-darcs record -am "non-ascii file add" -A test--cd ../temp2-darcs init-cd ../temp1--# long email adress: check that email adresses of <= 77 chars don't get split up-darcs send --from="Kjålt Überström $seventysevenaddy" \-           --subject "Un patch pour le répositoire" \-           --to="Un garçon français <garcon@francais.fr>" \-           --sendmail-command='cp /dev/stdin mail_as_file %<' \-           -a ../temp2--cat mail_as_file-# The long mail address should be in there as a whole-grep $seventysevenaddy mail_as_file--# Check that there are no non-ASCII characters in the mail-ghc -e 'getContents >>= return . not . any (> Data.Char.chr 127)' < mail_as_file | grep '^True$'---cd ..-rm -rf temp1-rm -rf temp2-
− bugs/issue1013_either_dependency.sh
@@ -1,53 +0,0 @@-#!/usr/bin/env bash-set -ev-export DARCS_EMAIL=test-rm -rf tmp_d1 tmp_d2 tmp_d-# Preparations:-# Set up two repos, each with a patch (d1 and d2 respectively) with both-# an individual change and a change that is identical in both repos,-# and thus auto-merge, i.e., they don't conflict in darcs2.  Pull them-# together and record a patch (problem) on top of the auto-merged change,-# so that it depends on EITHER of two patches.--mkdir tmp_d1; cd tmp_d1-darcs init --darcs-2-echo a > a-echo b > b-echo c > c-darcs rec -alm init-echo a-independent > a-echo c-common > c-darcs rec -am d1-cd ..-darcs get --to-patch init tmp_d1 tmp_d2-cd tmp_d2-echo b-independent > b-echo c-common > c-darcs rec -am d2-darcs pull -a ../tmp_d1-# no conflicts -- c-common is identical-echo c-problem > c-darcs rec -am problem-cd ..--# I want to pull the 'problem' patch, but expect darcs to get confused-# because it doesn't know how to select one of the two dependent patches.--darcs get --to-patch init tmp_d2 tmp_d-cd tmp_d-echo n/n/y |tr / \\012 |darcs pull ../tmp_d2-darcs cha--# This is weird, we got d2 though we said No.  I would have expected-# darcs to skip the 'problem' patch in this case.--# Try to pull d1 and unpull d2.--darcs pull -a ../tmp_d1-exit 1 # darcs hangs here (2.0.2+77)!-echo n/y/d |tr / \\012 |darcs obl -p d2--# The obliterate fails with: patches to commute_to_end does not commutex (1)--cd ..-rm -rf tmp_d1 tmp_d2 tmp_d
− bugs/issue1014_identical_patches.sh
@@ -1,60 +0,0 @@-#!/usr/bin/env bash-set -ev--# Set up a base repo. Our experiment will start from this point-mkdir base-cd base-darcs init --darcs-2-printf "Line1\nLine2\nLine3\n" > foo-darcs rec -alm Base-cd ..--# Now we want to record patch A, which will turn "Line2" into "Hello"-darcs get base a-cd a-printf "Line1\nHello\nLine3\n" > foo-darcs rec --ignore-times -am A-cd ..--# Make B the same as A-darcs get base b-cd b-printf "Line1\nHello\nLine3\n" > foo-darcs rec --ignore-times -am B-cd ..--# Now we make a patch C that depends on A-darcs get a ac-cd ac-printf "Line1\nWorld\nLine3\n" > foo-darcs rec --ignore-times -am C-cd ..--# Merge A and B-darcs get a ab-cd ab-darcs pull -a ../b-darcs revert -a-cd ..--# And merge in C too-darcs get ab abc-cd abc-darcs pull -a ../ac-darcs revert -a-cd ..--# Now we can pull just B and C into base-darcs get base bc-cd bc-darcs pull ../abc -ap 'B|C'-cd ..--# Now we have base, B and C in a repository.  At this point we're correct.--# Let's try merging AC with BC now, here we discover a bug.--darcs get ac abc2-cd abc2-darcs pull -a ../bc-
− bugs/issue1190_unmarked_hunk_replace_conflict.sh
@@ -1,43 +0,0 @@-#!/usr/bin/env bash-## Test for issue1190 - conflicts between HUNK and REPLACE are not-## marked by --mark-conflicts.-##-## Copyright (C) 2009  Trent W. Buck-##-## Permission is hereby granted, free of charge, to any person-## obtaining a copy of this software and associated documentation-## files (the "Software"), to deal in the Software without-## restriction, including without limitation the rights to use, copy,-## modify, merge, publish, distribute, sublicense, and/or sell copies-## of the Software, and to permit persons to whom the Software is-## furnished to do so, subject to the following conditions:-##-## The above copyright notice and this permission notice shall be-## included in all copies or substantial portions of the Software.-##-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS-## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN-## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN-## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-## SOFTWARE.--. ../tests/lib--rm -rf d e                      # Another script may have left a mess.-darcs init    --repo d/-printf %s\\n foo bar baz >d/f-darcs record  --repo d/ -lam f1-darcs get d/ e/-darcs replace --repo e/ --force bar baz f-darcs record  --repo e/ -lam replacement-printf %s\\n foo bar quux >d/f  # replace baz with quux-darcs record  --repo d/ -am f2--## There ought to be a conflict here, and there is.-darcs pull    --repo e/ d/ -a --mark-conflicts-## The file ought to now have conflict markers in it.-grep 'v v v' e/f-rm -rf d/ e/                    # Clean up after ourselves.
− bugs/issue1196_whatsnew_falsely_lists_all_changes.sh
@@ -1,21 +0,0 @@-#!/usr/bin/env bash-set -ev--not () { "$@" && exit 1 || :; }--rm -rf temp1-mkdir temp1-cd temp1--darcs init-touch aargh-darcs add aargh-echo utrecht > aargh--darcs wh foo foo/../foo/. > out-cat out-not grep utrecht out--cd ..-rm -rf temp1-
− bugs/issue1266_init_inside_a_repo.sh
@@ -1,33 +0,0 @@-#!/usr/bin/env bash-## Test for issue1266 - attempting to initialize a repository inside-## another repository should cause a warning, because while perfectly-## legitimate, it is likely to be accidental.-##-## Copyright (C) 2009  Trent W. Buck-##-## Permission is hereby granted, free of charge, to any person-## obtaining a copy of this software and associated documentation-## files (the "Software"), to deal in the Software without-## restriction, including without limitation the rights to use, copy,-## modify, merge, publish, distribute, sublicense, and/or sell copies-## of the Software, and to permit persons to whom the Software is-## furnished to do so, subject to the following conditions:-##-## The above copyright notice and this permission notice shall be-## included in all copies or substantial portions of the Software.-##-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS-## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN-## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN-## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-## SOFTWARE.--. ../tests/lib--rm -rf temp1 out                # Another script may have left a mess.-darcs init --repodir temp1-darcs init --repodir temp1/temp2 2>&1 | tee out-grep -i WARNING out             # A warning should be printed.
− bugs/issue1327.sh
@@ -1,27 +0,0 @@-#!/usr/bin/env bash-set -ev--# See issue1327.-# results in the error:-# patches to commute_to_end does not commutex (1) at src/Darcs/Patch/Depends.hs:452---rm -rf temp1 temp2-mkdir temp1-cd temp1-darcs init-echo fileA version 1 > fileA-echo fileB version 1 > fileB-darcs add fileA fileB-darcs record --author foo@bar --ignore-times --all -m "Add fileA and fileB"-echo fileA version 2 > fileA-darcs record --author foo@bar --ignore-times --all -m "Modify fileA"-cd ..-darcs get temp1 temp2-cd temp2-darcs obliterate -p "Modify fileA" --all-darcs unrecord -p "Add fileA and fileB" --all-darcs record --author foo@bar --ignore-times --all fileA -m "Add just fileA"-cd ../temp1-darcs pull --all ../temp2-echo y | darcs obliterate --dont-prompt-for-dependencies -p "Add fileA and fileB"
− bugs/issue1337_darcs_changes_false_positives.sh
@@ -1,37 +0,0 @@-#!/usr/bin/env bash-## Test for issue1337 - darcs changes shows unrelated patches-## Asking "darcs changes" about an unrecorded file d/f will list the-## patch that creates the parent directory d/ (instead of no patches).-##-## Copyright (C) 2009  Trent W. Buck-##-## Permission is hereby granted, free of charge, to any person-## obtaining a copy of this software and associated documentation-## files (the "Software"), to deal in the Software without-## restriction, including without limitation the rights to use, copy,-## modify, merge, publish, distribute, sublicense, and/or sell copies-## of the Software, and to permit persons to whom the Software is-## furnished to do so, subject to the following conditions:-##-## The above copyright notice and this permission notice shall be-## included in all copies or substantial portions of the Software.-##-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS-## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN-## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN-## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-## SOFTWARE.--. ../tests/lib--rm -rf temp1-darcs init --repodir temp1-cd temp1-mkdir d-darcs record -lam d d-# We use --match 'touch d/f' instead of simply d/f because the latter-# prints "Changes to d/f:\n" before the count.-test 0 -eq "$(darcs changes --count --match 'touch d/f')"
− bugs/issue1396_changepref-conflict.sh
@@ -1,32 +0,0 @@-#!/usr/bin/env bash-set -ev--. ../tests/lib--rm -rf temp1 temp1a temp1b--mkdir temp1-cd temp1-darcs init-darcs setpref test 'echo nothing'-darcs record -am 'null pref'-cd ..--darcs get temp1 temp1a-cd temp1a-darcs setpref test 'echo a'-darcs record -am 'pref a'-cd ..--darcs get temp1 temp1b-cd temp1b-darcs setpref test 'echo b'-darcs record -am 'pref b'-cd ..--cd temp1-darcs pull -a ../temp1a --dont-allow-conflicts-not darcs pull -a ../temp1b --dont-allow-conflicts-cd ..--rm -rf temp1 temp1a temp1b
− bugs/issue1401_bug_in_get_extra.sh
@@ -1,44 +0,0 @@-#!/usr/bin/env bash-## Test for issue1401 - when two repos share a HUNK patch, but that-## patch's ADDFILE dependency is met by different patches in each-## repo, it becomes impossible to pull between the two repos.-##-## Copyright (C) 2009  Trent W. Buck-##-## Permission is hereby granted, free of charge, to any person-## obtaining a copy of this software and associated documentation-## files (the "Software"), to deal in the Software without-## restriction, including without limitation the rights to use, copy,-## modify, merge, publish, distribute, sublicense, and/or sell copies-## of the Software, and to permit persons to whom the Software is-## furnished to do so, subject to the following conditions:-##-## The above copyright notice and this permission notice shall be-## included in all copies or substantial portions of the Software.-##-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS-## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN-## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN-## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-## SOFTWARE.--. ../tests/lib--## This bug only affects darcs-2 repositories.-fgrep darcs-2 ~/.darcs/defaults &>/dev/null || exit 0--rm -rf d e                      # Another script may have left a mess.-darcs initialize --repodir d/-darcs initialize --repodir e/-touch d/f d/g e/f-darcs record     --repodir d/ -lam 'Add f and g'-darcs record     --repodir e/ -lam 'Add f'-echo >d/f-darcs record     --repodir d/ -am 'Change f'-darcs pull       --repodir e/ -a d/-darcs obliterate --repodir e/ -ap 'Add f and g'-darcs pull       --repodir e/ -a d/-rm -rf d/ e/                    # Clean up after ourselves.
− bugs/issue1406.sh
@@ -1,19 +0,0 @@-#!/bin/sh-rm -rf temp1-darcs init --repodir temp1--cd temp1--echo "test exit 1" > _darcs/prefs/prefs-echo "name" > _darcs/prefs/author-echo "a" > a-darcs record --look-for-adds --no-test --all --patch-name=p1-echo "b" >> a-echo "y" | darcs amend-record --all --patch=p1--# There should be one patch in the repo-test 1 -eq `darcs changes --count` || exit 1--# Another check: there should be nothing new after a is restored-echo "a" > a-darcs whatsnew -l && exit 1 || exit 0
− bugs/issue1442_encoding_round-trip.sh
@@ -1,50 +0,0 @@-#!/usr/bin/env bash-## -*- coding: utf-8 -*--## Test for issue1442 - if we disable Darcs escaping and don't change-## our encoding, the bytes in a filename should be the same bytes that-## "darcs changes -v" prints to the right of "addfile" and "hunk".-##-## Copyright (C) 2009  Trent W. Buck-##-## Permission is hereby granted, free of charge, to any person-## obtaining a copy of this software and associated documentation-## files (the "Software"), to deal in the Software without-## restriction, including without limitation the rights to use, copy,-## modify, merge, publish, distribute, sublicense, and/or sell copies-## of the Software, and to permit persons to whom the Software is-## furnished to do so, subject to the following conditions:-##-## The above copyright notice and this permission notice shall be-## included in all copies or substantial portions of the Software.-##-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS-## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN-## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN-## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-## SOFTWARE.--. ../tests/lib--rm -rf R                        # Another script may have left a mess.--## Use the first UTF-8 locale we can find.-export LC_ALL=$(locale -a | egrep 'utf8|UTF-8' | head -1)-export DARCS_DONT_ESCAPE_ANYTHING=True--## If LC_ALL is the empty string, this system doesn't support UTF-8.-if test -z "$LC_ALL"-then exit 1-fi--darcs init      --repo R-echo '首頁 = א₀' >R/'首頁 = א₀'-darcs record    --repo R -lam '首頁 = א₀' '首頁 = א₀'-darcs changes   --repo R -v '首頁 = א₀' >R/log-#cat R/log                      # Show the humans what the output was.-grep -c '首頁 = א₀' R/log >R/count-echo 5 >R/expected-count-cmp R/count R/expected-count    # Both count files should contain "5\n".-rm -rf R                        # Clean up after ourselves.
− bugs/issue1461_case_folding.sh
@@ -1,83 +0,0 @@-#!/usr/bin/env bash-## Test for issue1461 - patches to files whose names only differ by-## case can be wrongly applied to the same file in the working directory.-##-## Copyright (C) 2009 Eric Kow-##-## Permission is hereby granted, free of charge, to any person-## obtaining a copy of this software and associated documentation-## files (the "Software"), to deal in the Software without-## restriction, including without limitation the rights to use, copy,-## modify, merge, publish, distribute, sublicense, and/or sell copies-## of the Software, and to permit persons to whom the Software is-## furnished to do so, subject to the following conditions:-##-## The above copyright notice and this permission notice shall be-## included in all copies or substantial portions of the Software.-##-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS-## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN-## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN-## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-## SOFTWARE.--. ../tests/lib                  # Load some portability helpers.-rm -rf lower upper joint        # Another script may have left a mess.-mkdir lower upper--cd lower-darcs init-cat > a << EOF-1-2-3-EOF-darcs add a-darcs record -am 'lower init a'-cd ..--cd upper-darcs init-cat > A << EOF-1-2-3-EOF-darcs add A-darcs record -am 'upper init A'-cd ..--darcs get lower joint-cd joint-darcs pull -a ../upper-cd ..--cd lower-cat > a << EOF-one lower-2-3-EOF-darcs record -am 'lower modify'-cd ..--cd upper-cat > A << EOF-1-2-three upper-EOF-darcs record -am 'upper modify'-cd ..--cd joint-darcs pull ../lower -a-darcs pull ../upper -a-grep one a && not grep three a-grep three A && not grep one A-cd ..-# clean up after ourselves-rm -rf lower upper joint
− bugs/issue1473_annotate_repodir.sh
@@ -1,21 +0,0 @@-#!/usr/bin/env bash-set -ev--. ../tests/lib-rm -rf temp-mkdir temp-cd temp-darcs init-mkdir a b-touch a/a b/b-darcs add --rec .-darcs record -a -m ab -A test-darcs annotate a/a-# annotate --repodir=something '.' should work-cd ..-darcs annotate --repodir temp '.'-cd temp--cd ..-rm -rf temp-
− bugs/issue27.sh
@@ -1,43 +0,0 @@-#!/bin/sh--set -ev--rm -rf temp1 temp2-mkdir temp1 temp2-cd temp1-darcs init-echo first > a-darcs add a-darcs record --pipe --all --patch-name=first <<EOF-Thu Sep 18 22:37:06 MSD 2008-author-EOF--echo first > b-darcs add b-darcs record --pipe --all --patch-name=first <<EOF-Thu Sep 18 22:37:06 MSD 2008-author-EOF--cd ../temp2-darcs init-darcs pull --all --dont-allow-conflicts ../temp1-echo second >> a-darcs record --pipe --all --patch-name=second <<EOF-Thu Sep 18 22:37:07 MSD 2008-author-EOF--cd ../temp1-echo second >> b-darcs record --pipe --all --patch-name=second <<EOF-Thu Sep 18 22:37:07 MSD 2008-author-EOF--darcs pull --all --dont-allow-conflicts ../temp2-test `darcs changes --count` = "4"-cd ..--rm -rf temp1 temp2
− bugs/issue390_whatsnew.sh
@@ -1,33 +0,0 @@-#!/usr/bin/env bash--# For issue390: darcs whatsnew somefile" lstats every file in the working copy and pristine/ directory--set -ev--if ! test -x "$(which strace)"-then echo skipping test since strace was not found-     exit-fi--rm -rf temp-mkdir temp-cd temp-darcs init-date > file1-date > file2-darcs add file*-darcs record -am "test"--strace darcs whatsnew file1 &> out-# we should be accessing file1-grep file1 out-# but shouldn't be accessing file2-if grep file2 out-then-    echo A whatsnew for file1 should not involve a 'stat' call to file2-    exit 1-else-    echo Yay.  We pass.-fi--rm -rf temp
− bugs/issue558_broken_pipe.sh
@@ -1,29 +0,0 @@-#!/usr/bin/env bash--# For issue588, "amend-record --look-for-adds end up with two "addfile" entries"--set -ev-rm -rf temp1-darcs init --repodir temp1--export EMAIL=me--cd temp1--date > f-darcs add f-darcs rec -am p1-for (( i=0 ; i < 500; i=i+1 )); do-  echo $i >> f;-  darcs rec -am p$i-done--darcs changes 2> err | head--touch correcterr--diff correcterr err--cd ..--rm -rf temp1
− bugs/issue944_partial_inventory.sh
@@ -1,46 +0,0 @@-#!/usr/bin/env bash--set -ev--test $DARCS || DARCS=$PWD/../darcs-ACTUAL_DARCS=`which $DARCS`-DARCSPATH=`dirname $ACTUAL_DARCS`-PATH="$DARCSPATH:$PATH"-export PATH--# create base repository-rm -rf temp1-mkdir temp1-cd temp1-darcs init--echo first > a-darcs add a-darcs record -am first-darcs tag --checkpoint 'Tag 1'--echo second > b-darcs add b-darcs record -am second-darcs tag --checkpoint 'Tag 2'--echo third > c-darcs add c-darcs record -am third-darcs tag --checkpoint 'Tag 3'--# create a partial copy of the base repository and modify it-cd ..-rm -rf temp2-darcs get --partial temp1 temp2-cd temp2--# instead of the following three commands one could also use darcs optimize-echo mistake > a-darcs record -am mistake-darcs unrecord -ap mistake--# now check the repository-darcs check-# => darcs: failed to read patch: ...-
− bugs/merging_newlines.sh
@@ -1,47 +0,0 @@-#!/usr/bin/env bash-set -ev--# Note that this is fixed, the lines marked # BUG HERE-# should be moved back into merging_newlines.sh--# trick: requiring something to fail-not () { "$@" && exit 1 || :; }--rm -rf temp1 temp2--# set up the repository-mkdir temp1-cd temp1-darcs init-cd ..--cd temp1-echo "apply allow-conflicts" > _darcs/prefs/defaults-# note: to make this pass, change echo to echo -n-# is that right?-echo "from temp1" > one.txt-darcs add one.txt-darcs record -A bar -am "add one.txt"-echo >> one.txt-darcs wh -u-cd ..--darcs get temp1 temp2-cd temp2-# reality check-darcs show files | grep one.txt-echo "in tmp2" >> one.txt-darcs whatsnew -s | grep M-darcs record -A bar -am "add extra line"-darcs annotate -p . -u-darcs push -av > log-cat log-not grep -i conflicts log-# BUG HERE-# after a conflict, darcs resolve should report a conflict-darcs mark-conflicts > log 2>&1-cat log-not grep -i 'no conflicts' log-cd ..--rm -rf temp1 temp2
− bugs/newlines.sh
@@ -1,28 +0,0 @@-#!/usr/bin/env bash-set -ev--rm -rf temp1 temp2--# set up the repository-mkdir temp1-cd temp1-darcs init-cd ..--cd temp1-echo -n "from temp1" > one.txt-darcs add one.txt-darcs record -A bar -am "add one.txt"-echo >> one.txt-cd ..--darcs get temp1 temp2-cd temp2-echo "in tmp2" >> one.txt-darcs record -A bar -am "add extra line"-lines_added=`darcs changes -v --last=1 | grep '\+' | wc -l`-echo $lines_added-test $lines_added -eq 1-cd ..--rm -rf temp1 temp2
− bugs/nfs-failure.sh
@@ -1,35 +0,0 @@-#!/bin/sh--set -ev--rm -rf temp1 temp2-mkdir temp1-cd temp1-darcs init-echo first > a-darcs add a-darcs record --pipe --all --patch-name=first <<EOF-Thu Sep 18 22:37:06 MSD 2008-author-EOF--echo first > b-darcs add b-darcs record --pipe --all --patch-name=first <<EOF-Thu Sep 18 22:37:06 MSD 2008-author-EOF--# it seems that somehow the following occasionally fails on an nfs-# filesystem when darcs is compiled with ghc 6.6.--darcs get . ../temp2--# it fails with something like:--# darcs: ./_darcs/patches/20080918223706-f64cd-6b512400a8108808b7ba7057f0eac2adf473b3ae.gz: copyFile: resource busy (file is locked)---cd ..--rm -rf temp1 temp2
− bugs/record-scaling.sh
@@ -1,36 +0,0 @@-#!/usr/bin/env bash-## Test for issueN - darcs record shouldn't access old inventories!-##-## Copyright (C) 2008  David Roundy-##-## Permission is hereby granted, free of charge, to any person-## obtaining a copy of this software and associated documentation-## files (the "Software"), to deal in the Software without-## restriction, including without limitation the rights to use, copy,-## modify, merge, publish, distribute, sublicense, and/or sell copies-## of the Software, and to permit persons to whom the Software is-## furnished to do so, subject to the following conditions:-##-## The above copyright notice and this permission notice shall be-## included in all copies or substantial portions of the Software.-##-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS-## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN-## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN-## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-## SOFTWARE.--. ../tests/lib                  # Load some portability helpers.-which strace                    # This test requires strace(1).-rm -rf R                        # Another script may have left a mess.-darcs init      --repo R        # Create our test repo.-touch R/a-unique-filename-strace -eopen -oR/trace \-  darcs record  --repo R -lam 'A unique commit message.'-grep a-unique-filename R/trace-grep _darcs/hashed_inventory R/trace-not grep _darcs/inventories/ R/trace-rm -rf R                        # Clean up after ourselves.
− bugs/time-stamps.sh
@@ -1,52 +0,0 @@-#!/usr/bin/env bash--# test for broken time stamps--set -ev--. lib.sh--rm -rf temp-mkdir temp-cd temp-darcs init --hashed--echo this is my favorite test > foobar-darcs add foobar-sleep 2 # so the time stamps won't accidentally be identical-darcs record -am 'add foobar'--HASHVAL=0000000025-4cbbfd8ce543076b132b13b60ae06d0189ee80b4d5908abb5e060d331d25eb5c--if test -d _darcs/pristine.hashed;-then-  ls _darcs/pristine.hashed-  test -f _darcs/pristine.hashed/$HASHVAL-  # verify that the modification time of the file in the pristine cache-  # is identical to the modification time of the file in the working-  # directory.-  not test foobar -ot _darcs/pristine.hashed/$HASHVAL-  not test foobar -nt _darcs/pristine.hashed/$HASHVAL-else-  not test foobar -ot _darcs/pristine/foobar-  not test foobar -nt _darcs/pristine/foobar-fi--# Now let's verify that the test actually works...--sleep 1-touch foobar--if test -d _darcs/pristine.hashed;-then-  not test foobar -ot _darcs/pristine.hashed/$HASHVAL-  test foobar -nt _darcs/pristine.hashed/$HASHVAL-else-  not test foobar -ot _darcs/pristine/foobar-  test foobar -nt _darcs/pristine/foobar-fi---cd ..--rm -rf temp
− contrib/cgi/README.in
@@ -1,42 +0,0 @@-darcs.cgi is the darcs repository viewer.  It provides a web interface-for viewing darcs repositories, using XSLT to transform darcs' XML-output into XHTML. It is written in perl and is more featureful than-the older haskell cgi program darcs_cgi.lhs (seen in URLs as "darcs").--dependencies--  darcs.cgi requires with the following tools and has been tested with-  the version mentioned:--  darcs-1.0.1           http://www.darcs.net-  libxslt-1.1.6         http://xmlsoft.org/XSLT/-  perl-5.8.0            http://www.perl.com--installation--  1) copy darcs.cgi to your webserver's cgi directory, eg-     /usr/lib/cgi-bin. A symlink probably won't do. Make-     sure it's executable.-  2) copy cgi.conf to @sysconfdir@/darcs/cgi.conf and edit appropriately.-     You can overwrite the cgi.conf used by the old darcs cgi script.-     You probably don't need to change anything here.-  3) copy the xslt directory to @datadir@/darcs/xslt-  4) copy xslt/styles.css to @sysconfdir@/darcs/styles.css--  Test by browsing "http://<host>/cgi-bin/darcs.cgi/".--troubleshooting--  if the configuration is incorrect error messages will be printed to-  the webserver's error log, for example "/var/log/apache/error.log".--  you can also double check the configuration by running darcs.cgi-  from the command line and supplying a --check argument:--     $ ./darcs.cgi --check--character encodings--  if your repositories contain files with characters encoded in-  something other than ASCII or UTF-8, change the 'xml_encoding'-  setting in cgi.conf to the appropriate encoding.
− contrib/cgi/cgi.conf.in
@@ -1,31 +0,0 @@-# This is an example for cgi.conf--# reposdir is the directory containing the repositories--reposdir = /var/www/repos--# cachedir is a directory writable by www-data (or whatever user your cgi-# scripts run as) which is used to cache the web pages.--cachedir = /var/cache/darcs--# The following are used by darcs.cgi (not darcs_cgi)-PATH = /bin:/usr/bin:/usr/local/bin--# paths to executables, or just the executables if they are in 'PATH'-#darcs = darcs-#xsltproc = xsltproc--# Path to XSLT templates (default is /usr/local/share/darcs/xslt)-xslt_dir = @datadir@/darcs/xslt--# HTTP request path of the style sheet, the default will magically read -# @sysconfdir@/darcs/styles.css-#stylesheet = /cgi-bin/darcs.cgi/styles.css--css_styles  = @sysconfdir@/darcs/styles.css--# encoding to include in XML declaration.  Set this to the encoding used-# by the files in your repositories.--xml_encoding = UTF-8
− contrib/cgi/darcs.cgi.in
@@ -1,491 +0,0 @@-#!/usr/bin/perl -T-#-# darcs.cgi - the darcs repository viewer-#-# Copyright (c) 2004 Will Glozer-#-# Permission is hereby granted, free of charge, to any person obtaining-# a copy of this software and associated documentation files (the-# "Software"), to deal in the Software without restriction, including-# without limitation the rights to use, copy, modify, merge, publish,-# distribute, sublicense, and/or sell copies of the Software, and to-# permit persons to whom the Software is furnished to do so, subject to-# the following conditions-#-# The above copyright notice and this permission notice shall be-# included in all copies or substantial portions of the Software.-#-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.--#-# This program calls darcs (or its own subroutines) to generate XML-# which is rendered into HTML by XSLT.  It is capable of displaying-# the files in a repository, various patch histories, annotations, etc.-#--use strict;--use CGI qw( :standard );-use CGI::Util;-use File::Basename;-use File::stat;-use IO::File;-use POSIX;--## the following variables can be customized to reflect your system-## configuration by defining them appropriately in the file-## "@sysconfdir@/darcs/cgi.conf".  The syntax accepts equals signs or simply-## blanks separating values from assignments.--$ENV{'PATH'} = read_conf('PATH', $ENV{'PATH'});--# path to executables, or just the executable if they are in $ENV{'PATH'}-my $darcs_program    = read_conf("darcs", "darcs");-my $xslt_program     = read_conf("xsltproc", "xsltproc");--# directory containing repositories-my $repository_root  = read_conf("reposdir", "/var/www");--# XSLT template locations-my $template_root = read_conf("xslt_dir", '@datadir@/darcs/xslt');--my $xslt_annotate = "$template_root/annotate.xslt";-my $xslt_browse   = "$template_root/browse.xslt";-my $xslt_patches  = "$template_root/patches.xslt";-my $xslt_repos    = "$template_root/repos.xslt";-my $xslt_rss      = "$template_root/rss.xslt";--my $xslt_errors   = "$template_root/errors.xslt";--# CSS stylesheet that XSLT templates refer to.  This is a HTTP request-# path, not a local file system path. The default will cause darcs.cgi-# to serve the stylesheet rather than the web server.-my $stylesheet = read_conf("stylesheet", "/cgi-bin/darcs.cgi/styles.css");--# location of the CSS stylesheet that darcs.cgi will serve if it-# receives a request for '/styles.css'-my $css_styles = read_conf("css_styles", '@sysconfdir@/darcs/styles.css');--# location of the favicon that darcs.cgi will serve if it-# receives a request for '/[\w\-]+/favicon.ico'-my $favicon = read_conf("favicon", "/cgi-bin/favicon.ico");--# XML source for the error pages-my $xml_errors = "$template_root/errors.xml";--# encoding to include in XML declaration-my $xml_encoding = read_conf("xml_encoding", "UTF-8");--## end customization--# ------------------------------------------------------------------------# read a value from the cgi.conf file.-{-  my(%conf);--  sub read_conf {-    my ($flag, $val) = @_;-    $val = "" if !defined($val);-    -    if (!%conf && open(CGI_CONF, '@sysconfdir@/darcs/cgi.conf')) {-      while (<CGI_CONF>) {-        chomp;-	next if /^\s*(?:\#.*)?$/;   # Skip blank lines and comment lines-        if (/^\s*(\S+)\s*(?:\=\s*)?(\S+)\s*$/) {-           $conf{$1} = $2;-	   # print "read_conf: $1 = $2\n";-        } else {-           warn "read_conf: $_\n";-        }-      }-      close(CGI_CONF);-    }--    $val = $conf{$flag} if exists($conf{$flag});--    return $val;-  }-}--# open xsltproc to transform and output `xml' with stylesheet file `xslt'-sub transform {-    my ($xslt, $args, $content_type) = @_;--    $| = 1;-    printf "Content-type: %s\r\n\r\n", $content_type || "text/html";-    my $pipe = new IO::File "| $xslt_program $args $xslt -";-    $pipe->autoflush(0);-    return $pipe;-}--sub pristine_dir {-    my ($repo) = @_;-    my $pristine = "current";-    if (! -d "${repository_root}/${repo}/_darcs/$pristine") {-        $pristine = "pristine";-    }-    return "${repository_root}/${repo}/_darcs/$pristine";-}--# begin an XML document with a root element and the repository path-sub make_xml {-    my ($fh, $repo, $dir, $file) = @_;-    my ($full_path, $path) = '/';--    printf $fh qq(<?xml version="1.0" encoding="$xml_encoding"?>\n);--    printf $fh qq(<darcs repository="$repo" target="%s/%s%s">\n),-        $repo, ($dir ? "$dir/" : ''), ($file ? "$file" : '');--    print $fh qq(<path>\n);-    foreach $path (split('/', "$repo/$dir")) {-        $full_path .= "$path/";-        print $fh qq(<directory full-path="$full_path">$path</directory>\n);-    }-    if ($file) {-        print $fh qq(<file full-path="$full_path$file">$file</file>\n) if $file;-    }-    print $fh qq(</path>\n\n);-}--# finish XML output-sub finish_xml {-    my ($fh) = @_;-    print $fh "\n</darcs>\n";-    $fh->flush;-}--# run darcs and wrap the output in an XML document-sub darcs_xml {-    my ($fh, $repo, $cmd, $args, $dir, $file) = @_;--    make_xml($fh, $repo, $dir, $file);--    push(@$args, '--xml-output');-    darcs($fh, $repo, $cmd, $args, $dir, $file);--    finish_xml($fh);-}--# run darcs with output redirected to the specified file handle-sub darcs {-    my ($fh, $repo, $cmd, $args, $dir, $file) = @_;-    my (@darcs_argv) = ($darcs_program, $cmd, @$args);--    # push target only if there is one, otherwise darcs will get an empty param-    if ($dir || $file) {-        push(@darcs_argv, sprintf("%s%s%s", $dir, ($dir ? '/' : ''), $file));-    }--    my($pid) = fork;-    if ($pid) {-	# in the parent process-	my($status) = waitpid($pid, 0);-	die "$darcs_program exited with status $?\n" if $?;-    } elsif(defined($pid)) {-	# in the child process-	open(STDIN, '/dev/null');-	if (defined($fh)) {-	    open(STDOUT, '>&', $fh)-		|| die "can't dup to stdout: $!\n";-	}-	chdir "$repository_root/$repo"-	    || die "chdir: $repository_root/$repo: $!\n";-	exec @darcs_argv;-	die "can't exec ".$darcs_argv[0].": $!\n";-    } else {-	# fork failed-	die "can't fork: $!\n";-    }-}--# get a directory listing as XML output-sub dir_listing {-    my ($fh, $repo, $dir) = @_;-    make_xml($fh, $repo, $dir, '');--    print $fh "<files>\n";-    my $dir_ = pristine_dir ($repo) . "/$dir";-    opendir(DH, $dir_);-    while( defined (my $file_ = readdir(DH)) ) {-        next if $file_ =~ /^\.\.?$/;-        my $file = "$dir_/$file_";-        my $secs  = stat($file)->mtime;-        my $mtime = localtime($secs);-        my $ts = POSIX::strftime("%Y%m%d%H%M%S", gmtime $secs);--        my ($name, $type);--         if (-d $file) {-             ($name, $type) = (basename($file) . '/', 'directory');-         } else {-             ($name, $type) = (basename($file), 'file');-         }-         print $fh qq(  <$type name="$name" modified="$mtime" ts="$ts" />\n);-    }-    closedir(DH);-    print $fh "</files>\n";--    finish_xml($fh);-}--# get a repository listing as XML output-sub repo_listing {-    my($fh) = @_;--    make_xml($fh, "", "", "");--    print $fh "<repositories>\n";-    opendir(DH, $repository_root);-    while( defined (my $name = readdir(DH)) ) {-        next if $name =~ /^\.\.?$/;-        if (-d "$repository_root/$name/_darcs") {-            print $fh qq(  <repository name="$name" />\n);-        }-    }-    closedir(DH);-    print $fh "</repositories>\n";--    finish_xml($fh);-    return $fh;-}--# show an error page-sub show_error {-    my ($type, $code, $message) = @_;-    my $xml;--    # set the xslt processing arguments-    my $xslt_args = qq {-        --stringparam error-type '$type'-        --stringparam stylesheet '$stylesheet'-    };-    $xslt_args =~ s/\s+/ /gm;--    print "Status: $code $message\r\n\r\n";-    system("$xslt_program $xslt_args $xslt_errors $xml_errors");-}--# check if the requested resource has been modified since the client last-# saw it. If not send HTTP status code 304, otherwise set the Last-modified-# and Cache-control headers.-sub is_cached {-    my ($path) = @_;-    my ($stat) = stat($path);--    # stat may fail because the path was renamed or deleted but still referred-    # to by older darcs patches-    if ($stat) {-        my $last_modified = CGI::expires($stat->mtime);--        if (http('If-Modified-Since') eq $last_modified) {-            print("Status: 304 Not Modified\r\n\r\n");-            return 1;-        }--        print("Cache-control: max-age=0, must-revalidate\r\n");-        print("Last-modified: $last_modified\r\n");-    }-    return 0;-}--# safely extract a parameter from the http request.  This applies a regexp-# to the parameter which should group only the appropriate parameter value-sub safe_param {-    my ($param, $regex, $default) = @_;-    my $value = CGI::Util::unescape(param($param));-    return ($value =~ $regex) ? $1 : $default;-}--# common regular expressions for validating passed parameters-my $hash_regex = qr/^([\w\-.]+)$/;-my $path_regex = qr@^([^\\!\$\^&*()\[\]{}<>`|';"?\r\n]+)$@;--# respond to a CGI request-sub respond {-    # untaint the full URL to this CGI-    my $cgi_url = CGI::Util::unescape(url());-    $cgi_url =~ $path_regex or die qq(bad url "$cgi_url");-    $cgi_url = $1;--    # untaint script_name, reasonable to expect only \w, -, /, and . in the name-    my $script_name = CGI::Util::unescape(script_name());-    $script_name =~ qr~^([\w/.\-\~]+)$~ or die qq(bad script_name "$script_name");-    $script_name = $1;--    # untaint simple parameters, which can only have chars matching \w+-    my $cmd  = safe_param('c', '^(\w+)$', 'browse');-    my $sort = safe_param('s', '^(\w+)$', '');--    # set the xslt processing arguments-    my $xslt_args = qq {-        --stringparam cgi-program '$script_name'-        --stringparam cgi-url '$cgi_url'-        --stringparam sort-by '$sort'-        --stringparam stylesheet '$stylesheet'-    };-    $xslt_args =~ s/\s+/ /gm;--    my ($path) = CGI::Util::unescape(path_info());-    # don't allow ./ or ../ in paths-    $path =~ s|[.]+/||g;--    # check whether we're asking for styles.css-    if ($path eq '/styles.css') {-        return if is_cached($css_styles);--        open (STYLES_CSS, $css_styles) or die qq(couldn't open "${css_styles}");-        my $size = stat($css_styles)->size;--        print "Content-length: $size\r\n";-        print "Content-type: text/css\r\n\r\n";--        while (<STYLES_CSS>) {-          print $_;-        }-        close (STYLES_CSS);-        return;-    }--    # check whether we're asking for favicon.ico-    if ($path =~ '/[\w\-]+/favicon.ico') {-        return if is_cached($favicon);--        open (FAVICON, $favicon) or die qq(couldn't open "${favicon}");-        my $size = stat($favicon)->size;--        print "Content-length: $size\r\n";-        print "Content-type: image/x-icon\r\n\r\n";--        while (<FAVICON>) {-          print $_;-        }-        close (FAVICON);-        return;-    }--    # when no repository is requested display available repositories-    if (length($path) < 2) {-        my $fh = transform($xslt_repos, $xslt_args);-        repo_listing($fh);-        return;-    }--    # don't allow any shell meta characters in paths-    $path =~ $path_regex or die qq(bad path_info "$path");-    my @path = split('/', substr($1, 1));--    # split the path into a repository, directory, and file-    my ($repo, $dir, $file, @bits) = ('', '', '');-    while (@path > 0) {-        $repo = join('/', @path);-        # check if remaining path elements refer to a repo-        if (-d "${repository_root}/${repo}/_darcs") {-            if (@bits > 1) {-                $dir  = join('/', @bits[0..$#bits - 1]);-            }-            $file = $bits[$#bits];-            # check if last element of path, stored in $file, is really a dir-            if (-d (pristine_dir ($repo) . "/${dir}/${file}")) {-                $dir = ($dir ? "$dir/$file" : $file);-                $file = '';-            }-            last;-        } else {-            $repo = '';-            unshift(@bits, pop @path);-        }-    }--    # make sure the repository exists-    unless ($repo) {-        show_error('invalid-repository', '404', 'Invalid repository');-        return;-    }--    # don't generate output unless the requested path has been-    # modified since the client last saw it.-    return if is_cached(pristine_dir ($repo) . "/$dir/$file");--    # untaint patches and tags. Tags can have arbitrary values, so-    # never pass these unquoted, on pain of pain!-    my $patch = safe_param('p', $hash_regex);-    my $tag   = safe_param('t', '^(.+)$');--    my @darcs_args;-    push(@darcs_args, '--match', "hash $patch") if $patch;-    push(@darcs_args, '-t', $tag) if $tag;--    # process the requested command-    if ($cmd eq 'browse') {-        my $fh = transform($xslt_browse, $xslt_args);-        dir_listing($fh, $repo, $dir);-    } elsif ($cmd eq 'patches') {-        # patches as an option is used to support "--patches"-        if (my $patches = safe_param('patches','^(.+)$')) {-            push @darcs_args, '--patches', $patches;-        }--        my $fh = transform($xslt_patches, $xslt_args);-        darcs_xml($fh, $repo, "changes", \@darcs_args, $dir, $file);-    } elsif ($cmd eq 'annotate') {-        push(@darcs_args, '--summary');--        my $creator_hash  = safe_param('ch', $hash_regex);-        my $original_path = safe_param('o', $path_regex);-        my $fh = transform($xslt_annotate, $xslt_args);--        # use the creator hash and original file name when available so-        # annotations can span renames-        if ($creator_hash ne '' && $original_path ne '') {-            push(@darcs_args, '--creator-hash', $creator_hash);-            darcs_xml($fh, $repo, "annotate", \@darcs_args, '', $original_path);-        } else {-            darcs_xml($fh, $repo, "annotate", \@darcs_args, $dir, $file);-        }-    } elsif ($cmd eq 'diff') {-        push(@darcs_args, '-u');-        print "Content-type: text/plain\r\n\r\n";-        darcs(undef, $repo, "diff", \@darcs_args, $dir, $file);-    } elsif ($cmd eq 'rss') {-        push(@darcs_args, '--last', '25');--        my $fh = transform($xslt_rss, $xslt_args, "application/rss+xml");-        darcs_xml($fh, $repo, "changes", \@darcs_args, $dir, $file);-    } else {-        show_error('invalid-command', '400', 'Invalid command');-    }-}--# run a self-test when the --check argument is supplied-if ($ARGV[0] eq '--check') {-    (read_conf("css_styles", "abc") ne "abc") ||-        die "cannot read config file: $!\n";--    (`$darcs_program`) ||-        die "cannot execute darcs as '$darcs_program': $!\n";-    (`$xslt_program`) ||-        die "cannot execute xstlproc as '$xslt_program': $!\n";--    (-d $repository_root && -r $repository_root) ||-        die "cannot read repository root directory '$repository_root': $!\n";-    (-d $template_root && -r $template_root) ||-        die "cannot read template root directory '$template_root': $!\n";-    (-f $css_styles) ||-        die "cannot read css stylesheet '$css_styles': $!\n";-    (-f $xml_errors) ||-        die "cannot read error messages '$xml_errors': $!\n";--    exit 0;-}--# handle the CGI request-respond();-
− contrib/cgi/xslt/annotate.xslt
@@ -1,390 +0,0 @@-<?xml version="1.0" encoding="utf-8"?>--<!--- template for converting darcs' `annotate` output from XML to XHTML.  This- template expects the following external variables:--   cgi-program    - path to the CGI executable, to place in links-   sort-by        - field to sort by-   stylesheet     - path to the CSS stylesheet---->-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">-  <xsl:strip-space elements="*"/>--  <xsl:include href="common.xslt"/>--  <xsl:template match="path">-    <h1 class="target">-        annotations for <span class="path"><a href="{$cgi-program}">projects</a></span> / <span class="path"><xsl:apply-templates/></span>-    </h1>-  </xsl:template>--  <!-- patch annotate tags -->-  <xsl:template match="/darcs/patch">-    <xsl:call-template name="show-patch-info">-      <xsl:with-param name="patch" select="."/>-      <xsl:with-param name="show-comment" select="true()"/>-      <xsl:with-param name="show-author" select="true()"/>-      <xsl:with-param name="show-date" select="true()"/>-    </xsl:call-template>-  </xsl:template>-  -  <xsl:template match="summary">-    <xsl:variable name="hash" select="../patch/@hash"/>-      -    <table>-      <tr class="annotate">-        <th>file</th>-        <th>change</th>-        <th></th>-        <th></th>-      </tr>--      <xsl:apply-templates/>-    </table>--    <form action="{$command}" method="get">-      <p>-        <input type="submit" name="c" value="diff"/>-        <input type="hidden" name="p" value="{$hash}"/>-      </p>-    </form>-  </xsl:template>-  -  <xsl:template match="modify_file">-    <xsl:variable name="file" select="text()"/>-    <xsl:variable name="hash" select="/darcs/patch/@hash" />-      -    <tr class="modified-file">-      <td><xsl:value-of select="$file"/></td>--      <td class="line-count">-        <xsl:for-each select="added_lines">-          +<xsl:value-of select="@num"/>/-        </xsl:for-each>-        <xsl:for-each select="removed_lines">-<xsl:value-of select="@num"/>-        </xsl:for-each>-        lines-      </td>--      <td><a href="{$command}{$file}?c=annotate&amp;p={$hash}">annotate</a></td>-      <td><a href="{$command}{$file}?c=patches">patches</a></td>-    </tr>-  </xsl:template>--  <xsl:template match="add_file">-    <xsl:variable name="file" select="text()"/>-    <xsl:variable name="hash" select="/darcs/patch/@hash" />-    -    <tr class="add-remove-file">-      <td><xsl:value-of select="$file"/></td>-      <td>added file</td>-      <td><a href="{$command}{$file}?c=annotate&amp;p={$hash}">annotate</a></td>-      <td><a href="{$command}{$file}?c=patches">patches</a></td>-    </tr>-  </xsl:template>--  <xsl:template match="move">-    <xsl:variable name="file" select="@to"/>-    <xsl:variable name="old-file" select="@from"/>    -    <xsl:variable name="hash" select="/darcs/patch/@hash" />-    -    <tr class="add-remove-file">-      <td><xsl:value-of select="$file"/></td>-      <td>moved from <xsl:value-of select="$old-file"/></td>-      <td><a href="{$command}{$file}?c=annotate&amp;p={$hash}">annotate</a></td>-      <td><a href="{$command}{$file}?c=patches">patches</a></td>-    </tr>-  </xsl:template>--  <xsl:template match="remove_file">-    <xsl:variable name="file" select="text()"/>-    <xsl:variable name="hash" select="/darcs/patch/@hash" />-    -    <tr class="add-remove-file">-      <td><xsl:value-of select="$file"/></td>-      <td>removed file</td>-      <td><a href="{$command}{$file}?c=annotate&amp;p={$hash}">annotate</a></td>-      <td><a href="{$command}{$file}?c=patches">patches</a></td>-    </tr>-  </xsl:template>--  <xsl:template match="add_directory">-    <xsl:variable name="dir" select="text()"/>-    <xsl:variable name="hash" select="/darcs/patch/@hash" />-    -    <tr class="add-remove-file">-      <td><xsl:value-of select="$dir"/></td>-      <td>added directory</td>-      <td><a href="{$command}{$dir}/?c=annotate&amp;p={$hash}">annotate</a></td>-      <td><a href="{$command}{$dir}/?c=patches">patches</a></td>-    </tr>-  </xsl:template>--  <xsl:template match="remove_directory">-    <xsl:variable name="dir" select="text()"/>-    <xsl:variable name="hash" select="/darcs/patch/@hash" />-    -    <tr class="add-remove-file">-      <td><xsl:value-of select="$dir"/></td>-      <td>removed directory</td>-      <td><a href="{$command}{$dir}/?c=annotate&amp;p={$hash}">annotate</a></td>-      <td><a href="{$command}{$dir}/?c=patches">patches</a></td>-    </tr>-  </xsl:template>-  -  <!-- directory annotate templates -->-  <xsl:template match="/darcs/directory">-    <xsl:call-template name="show-patch-info">-      <xsl:with-param name="patch" select="modified/patch"/>-    </xsl:call-template>--    <table>-      <tr class="annotate">-        <th>file</th>-        <th>change</th>-        <th></th>-        <th></th>-      </tr>--      <xsl:apply-templates/>-    </table>-  </xsl:template>-  -  <xsl:template match="directory/modified/modified_how">-    <xsl:variable name="hash" select="../patch/@hash" />-    <xsl:variable name="how" select="substring(text(), 0, 10)"/>-    <xsl:variable name="target" select="/darcs/@target"/>--    <!---      annotating a directory outputs the directory itself as well as-      any contents.  this ugly code checks if the matching element is-      the original directory so that the 'annotate' and 'patch' links-      don't append the directory twice.-    -->-    <xsl:variable name="last" select="//darcs/path/directory[last()]"/>-    <xsl:variable name="name" select="../../@name"/>-    <xsl:variable name="dir">-      <xsl:choose>-        <xsl:when test="$last = $name"></xsl:when>-        <xsl:otherwise><xsl:value-of select="$name"/>/</xsl:otherwise>-      </xsl:choose>-    </xsl:variable>--    <tr class="add-remove-file">-      <td><xsl:value-of select="$name"/></td>-      <td>-        <xsl:choose>-          <xsl:when test="$how = 'Dir added'">added directory</xsl:when>-          <xsl:when test="$how = 'Dir moved'">moved directory</xsl:when>-          <xsl:when test="$how = 'Dir remov'">removed directory</xsl:when>-        </xsl:choose>-      </td>-      <td>-        <a href="{$command}{$dir}?c=annotate&amp;p={$hash}">annotate</a>-      </td>-      <td><a href="{$command}{$dir}?c=patches">patches</a></td>-    </tr>-  </xsl:template>--  <xsl:template match="directory/file/modified/modified_how">-    <xsl:variable name="file" select="../../@name"/>-    <xsl:variable name="hash" select="../patch/@hash" />-    <xsl:variable name="how" select="substring(text(), 0, 11)"/>-    -    <tr class="add-remove-file">-      <td><xsl:value-of select="$file"/></td>-      <td>-        <xsl:choose>-          <xsl:when test="$how = 'File added'">added file</xsl:when>-          <xsl:when test="$how = 'File moved'">moved file</xsl:when>-          <xsl:when test="$how = 'File remov'">removed file</xsl:when>-        </xsl:choose>-      </td>-      <td><a href="{$command}{$file}?c=annotate&amp;p={$hash}">annotate</a></td>-      <td><a href="{$command}{$file}?c=patches">patches</a></td>-    </tr>-  </xsl:template>-   -  <!-- file annotate templates -->-  <xsl:template match="/darcs/file">-    <xsl:variable name="modified_how" select="modified/modified_how/text()"/>-    -    <xsl:call-template name="show-patch-info">-      <xsl:with-param name="patch" select="modified/patch"/>-    </xsl:call-template>--    <!-- don't display table of changes when file's contents are modified -->-    <xsl:if test="$modified_how != 'File modified'">-      <xsl:variable name="file" select="@name"/>-      <xsl:variable name="how" select="substring($modified_how, 0, 11)"/>--      <xsl:variable name="annotate-href">-        <xsl:call-template name="make-annotate-href">-          <xsl:with-param name="hash" select="modified/patch/@hash"/>-        </xsl:call-template>-      </xsl:variable>-      -      <table>-        <tr class="annotate">-          <th>file</th>-          <th>change</th>-          <th></th>-          <th></th>-        </tr>--        <tr class="add-remove-file">-          <td><xsl:value-of select="$file"/></td>-          <td>-            <xsl:choose>-              <xsl:when test="$how = 'File added'">added file</xsl:when>-              <xsl:when test="$how = 'File moved'">moved file</xsl:when>-              <xsl:when test="$how = 'File remov'">removed file</xsl:when>-            </xsl:choose>-          </td>-          <td><a href="{$annotate-href}">annotate</a></td>-          <td><a href="{$command}?c=patches">patches</a></td>-        </tr>-      </table>-    </xsl:if>--    <!-- the empty <p/> element is a Konqueror bug workaround -->-    <pre xml:space="preserve"><p/>-      <xsl:apply-templates/>-    </pre>-  </xsl:template>-  -  <xsl:template match="added_line">-    <xsl:variable name="annotate-href">-      <xsl:call-template name="make-annotate-href">-        <xsl:with-param name="hash" select="preceding::modified/patch/@hash"/>-      </xsl:call-template>-    </xsl:variable>--    <xsl:variable name="annotate-name" select="preceding::modified/patch/name"/>-    <xsl:variable name="author" select="preceding::modified/patch/@author"/>-    -    <a class="added-line" href="{$annotate-href}" title="added with '{$annotate-name}' by '{$author}'">-      <pre><xsl:value-of select="text()"/></pre>-    </a>-    <xsl:call-template name="check-removed-by"/>-  </xsl:template>--  <xsl:template match="normal_line">-    <xsl:variable name="annotate-href">-      <xsl:call-template name="make-annotate-href">-        <xsl:with-param name="hash" select="*/patch/@hash"/>-      </xsl:call-template>-    </xsl:variable>--    <xsl:variable name="annotate-name" select="*/patch/name"/>-    <xsl:variable name="author" select="*/patch/@author"/>--    <a class="normal-line" href="{$annotate-href}" title="last changed with '{$annotate-name}' by '{$author}'">-      <pre><xsl:value-of select="text()"/></pre>-    </a>-    <xsl:call-template name="check-removed-by"/>-  </xsl:template>--  <xsl:template match="removed_line">-    <xsl:variable name="annotate-href">-      <xsl:call-template name="make-annotate-href">-        <xsl:with-param name="hash" select="*/patch/@hash"/>-      </xsl:call-template>-    </xsl:variable>--    <xsl:variable name="annotate-name" select="*/patch/name"/>-    <xsl:variable name="author" select="*/patch/@author"/>-    -    <!-- don't display removed lines when a file is removed -->-    <xsl:if test="../modified/modified_how/text() != 'File removed'">-      -        <a class="removed-line" href="{$annotate-href}" title="removed with '{$annotate-name}' by '{$author}'">-        <pre><xsl:value-of select="text()"/></pre>-      </a>-      <xsl:call-template name="check-removed-by"/>-    </xsl:if>-  </xsl:template>--  <xsl:template name="check-removed-by">-    <xsl:variable name="hash" select="removed_by/patch/@hash"/>-    -    <xsl:variable name="annotate-href">-      <xsl:call-template name="make-annotate-href">-        <xsl:with-param name="hash" select="$hash"/>-      </xsl:call-template>-    </xsl:variable>-    -    <xsl:choose>-      <xsl:when test="$hash != ''">-        <a class="removed-by" href="{$annotate-href}">-</a>-      </xsl:when>-    </xsl:choose>--    <!-- put a newline after the hyperlink -->      -    <xsl:text xml:space="preserve">-    </xsl:text>-  </xsl:template>--  <xsl:template name="show-patch-info">-    <xsl:param name="patch"/>-    <xsl:param name="show-comment"/>-    <xsl:param name="show-author"/>-    <xsl:param name="show-date"/>-    -    <xsl:variable name="hash" select="$patch/@hash"/>-    <xsl:variable name="name" select="$patch/name"/>-    <xsl:variable name="author" select="$patch/@author"/>-    <xsl:variable name="local_date" select="$patch/@local_date"/>-    -    <h2 class="patch">-      patch "<span class="path">-      <a href="{$cgi-program}/{$repo}/?c=annotate&amp;p={$hash}">-        <xsl:value-of select="$name"/>-      </a>-      </span>"-    </h2>--    <xsl:if test="$show-comment">-        <xsl:if test="$patch/comment">-          <h2 class="patch">-            comment "<span class="comment">-            <xsl:value-of select="$patch/comment"/>-            </span>"-            </h2>-        </xsl:if>-        </xsl:if>--      <xsl:if test="$show-author"> -          <h2 class="author">-        by <span class="author">-        <xsl:value-of select="$patch/@author"/>-        </span>--      <xsl:if test="$show-date"> -        on <span class="local_date">-        <xsl:value-of select="$patch/@local_date"/>-        </span>-    </xsl:if>-    </h2>-    </xsl:if>--  </xsl:template>--  <xsl:template name="make-annotate-href" xml:space="default">-    <xsl:param name="hash"/>--    <xsl:variable name="created-as" select="/darcs/*/created_as"/>-    <xsl:variable name="creator-hash" select="$created-as/patch/@hash"/>-    <xsl:variable name="original-name" select="$created-as/@original_name"/>-    -    <xsl:value-of select="$command"/>?c=annotate&amp;p=<xsl:value-of select="$hash"/>&amp;ch=<xsl:value-of select="$creator-hash"/>&amp;o=<xsl:value-of select="$original-name"/>-  </xsl:template>--  <!-- ignore <name>, <comment> and <modified_how> children -->-  <xsl:template match="name"/>-  <xsl:template match="comment"/>-  <xsl:template match="author"/>-  <xsl:template match="modified_how"/>-</xsl:stylesheet>
− contrib/cgi/xslt/browse.xslt
@@ -1,110 +0,0 @@-<?xml version="1.0" encoding="utf-8"?>--<!--- template for converting a darcs current/ directory listing from XML to- XHTML.  This template expects the following external variables:--   cgi-program    - path to the CGI executable, to place in links-   sort-by        - field to sort by-   stylesheet     - path to the CSS stylesheet-- the input XML must have the following structure, aside from what common.xslt- expects:-- <files>-   <directory name="" modified=""/>-   <file name="" modified=""/>- </files>--->-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">-  <xsl:include href="common.xslt"/>--  <xsl:template match="path">-    <h1 class="target">-      files in <span class="path"><a href="{$cgi-program}">projects</a></span> / <span class="path"><xsl:apply-templates/></span>-    </h1>-  </xsl:template>-  -  <xsl:template match="files">-    <table>-      <tr class="browse">-        <th>-          <a class="sort" href="{$command}?c=browse&amp;s=name">name</a>-          <a class="revsort" href="{$command}?c=browse&amp;s=revname"> (rev)</a>-        </th>-        <th>-          <a class="sort" href="{$command}?c=browse&amp;s=ts">modified</a>-          <a class="revsort" href="{$command}?c=browse&amp;s=revts"> (rev)</a>-        </th>-        <th></th>-        <th></th>-      </tr>-      -      <xsl:choose>-        <xsl:when test="$sort-by = 'ts'">-          <xsl:apply-templates>-            <xsl:sort select="name(self::node())"/>-            <xsl:sort select="@ts"/>-          </xsl:apply-templates>-        </xsl:when>-        <xsl:when test="$sort-by = 'revts'">-          <xsl:apply-templates>-            <xsl:sort select="name(self::node())"/>-            <xsl:sort select="@ts" order="descending"/>-          </xsl:apply-templates>-        </xsl:when>-        <xsl:when test="$sort-by = 'name'">-          <xsl:apply-templates>-            <xsl:sort select="name(self::node())"/>-            <xsl:sort select="@name"/>-          </xsl:apply-templates>-        </xsl:when>-        <xsl:when test="$sort-by = 'revname'">-          <xsl:apply-templates>-            <xsl:sort select="name(self::node())"/>-            <xsl:sort select="@name" order="descending"/>-          </xsl:apply-templates>-        </xsl:when>-        <xsl:otherwise>-          <xsl:apply-templates>-            <xsl:sort select="name(self::node())"/>-            <xsl:sort select="@name"/>-          </xsl:apply-templates>-        </xsl:otherwise>-      </xsl:choose>-    </table>-  </xsl:template>-  -  <xsl:template match="directory">-    <xsl:variable name="name" select="@name"/>-    <xsl:variable name="type" select="@type"/>-    -    <tr class="directory">-      <td>-        <a href="{$command}{$name}?c=browse"><xsl:value-of select="@name"/></a>-      </td>-      <td><xsl:value-of select="@modified"/></td>-      <td>-        <a href="{$command}{$name}?c=annotate">annotate</a>-      </td>-      <td>-        <a href="{$command}{$name}?c=patches">patches</a>-      </td>-    </tr>--    <xsl:apply-templates/>-  </xsl:template>--  <xsl:template match="file">-    <xsl:variable name="name" select="@name"/>-    -    <tr class="file">-      <td><xsl:value-of select="@name"/></td>-      <td><xsl:value-of select="@modified"/></td>-      <td><a href="{$command}{$name}?c=annotate">annotate</a></td>-      <td><a href="{$command}{$name}?c=patches">patches</a></td>-    </tr>--    <xsl:apply-templates/>-  </xsl:template>-</xsl:stylesheet>
− contrib/cgi/xslt/common.xslt
@@ -1,66 +0,0 @@-<!--- templates fragments shared by all templates.  This template expects- the following external variables:--   cgi-program    - path to the CGI executable, to place in links-   stylesheet     - path to the CSS stylesheet-- the input XML must have the following structure, plus any elements- that are not common to all templates:-- <darcs repository="">-   <path>-     <element full-path=""></element>-   </path>--   ...- - </darcs>--->-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">-  <xsl:variable name="command">-    <xsl:value-of select="$cgi-program"/>/<xsl:value-of select="/darcs/@target"/>-  </xsl:variable>--  <xsl:variable name="repo" select="/darcs/@repository"/>-  -  <xsl:template match="/darcs">-    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">-      <head>-        <title>darcs repository</title>-        <link rel="stylesheet" href="{$stylesheet}"/>-        <link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="{$command}?c=rss" />-      </head>--      <body>-        <xsl:apply-templates/>--        <form action="{$command}" method="get">-          <p>-            <input class="patches" type="submit" name="c" value="patches"/>-            -            <a href="{$command}?c=rss">rss</a>-            -            <span class="version">-              <a class="home" href="http://darcs.net/">darcs.cgi</a>-              v1.0-            </span>-          </p>-        </form>-      </body>-    </html>-  </xsl:template>--  <xsl:template match="path/directory">-    <xsl:variable name="full-path"  select="@full-path"/>-    -    <a href="{$cgi-program}{$full-path}?c=browse">-      <xsl:apply-templates/>-    </a> /-  </xsl:template>--  <xsl:template match="path/file">-    <xsl:apply-templates/>-  </xsl:template>-  -</xsl:stylesheet>
− contrib/cgi/xslt/errors.xml
@@ -1,22 +0,0 @@-<!---  HTML templates for all potential error pages.  Each <error> element-  should contain all of the HTML <body> content to be output if that-  error occurs--->-<errors>-  <error type="invalid-command" title="Invalid command">-    <h1>Invalid command</h1>--    <p>-      The requested command is invalid.-    </p>-  </error>--  <error type="invalid-repository" title="Invalid repository">-    <h1>Invalid repository</h1>--    <p>-      The requested repository does not exist on this server.-    </p>-  </error>-</errors>
− contrib/cgi/xslt/errors.xslt
@@ -1,36 +0,0 @@-<?xml version="1.0" encoding="utf-8"?>--<!--- template for converting selected content of errors.xml XML to XHTML. This- template expects the following external variables:--   error-type     - the type of error-   stylesheet     - path to the CSS stylesheet-- the input XML must have the following structure-- <errors>-   <error type="" title="">-     ...-   </error>- </errors>--->-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">-  <xsl:template match="error[@type = $error-type]">-    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">-      <head>-        <title>-          <xsl:value-of select="@title"/>-        </title>-        <link rel="stylesheet" href="{$stylesheet}"/>-      </head>--      <body>-        <xsl:copy-of select="*"/>-      </body>-    </html>-  </xsl:template>--  <!-- ignore errors that don't match -->-  <xsl:template match="error"/>-</xsl:stylesheet>
− contrib/cgi/xslt/patches.xslt
@@ -1,125 +0,0 @@-<?xml version="1.0" encoding="utf-8"?>--<!--- template for converting darcs' `changes` output from XML to XHTML.  This- template expects the following external variables:--   cgi-program    - path to the CGI executable, to place in links-   sort-by        - field to sort by-   stylesheet     - path to the CSS stylesheet-- the input XML must have the following structure, aside from what common.xslt- expects:-- <changelog>-   <patch author="" date="" localdate="" inverted="" hash="">-     <name></name>-   </patch>- </changelog>--->-<xsl:stylesheet version="1.0"-                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"-                xmlns:str="http://exslt.org/strings">-  -  <xsl:include href="common.xslt"/>--  <xsl:template match="path">-    <h1 class="target">-      patches applied to <span class="path"><a href="{$cgi-program}">projects</a></span> / <span class="path"><xsl:apply-templates/></span>-    </h1>-  </xsl:template>-  -  -  <xsl:template match="changelog">-    <table>-      <tr class="patches">-        <th>-          <a class="sort" href="{$command}?c=patches&amp;s=name">name</a>-          <a class="revsort" href="{$command}?c=patches&amp;s=revname"> (rev)</a>-        </th>-        <th>-          <a class="sort" href="{$command}?c=patches&amp;s=date">date</a>-          <a class="revsort" href="{$command}?c=patches&amp;s=revdate"> (rev)</a>-        </th>-        <th>-          <a class="sort" href="{$command}?c=patches&amp;s=author">author</a>-          <a class="revsort" href="{$command}?c=patches&amp;s=revauthor"> (rev)</a>-        </th>-        <th>-        </th>-      </tr>--      <xsl:choose>-        <xsl:when test="$sort-by = 'name'">-          <xsl:apply-templates>-            <xsl:sort select="name"/>-          </xsl:apply-templates>-        </xsl:when>-        <xsl:when test="$sort-by = 'revname'">-          <xsl:apply-templates>-            <xsl:sort select="name" order="descending"/>-          </xsl:apply-templates>-        </xsl:when>-        <xsl:when test="$sort-by = 'date'">-          <xsl:apply-templates>-            <xsl:sort select="@date"/>-          </xsl:apply-templates>-        </xsl:when>-        <xsl:when test="$sort-by = 'revdate'">-          <xsl:apply-templates>-            <xsl:sort select="@date" order="descending"/>-          </xsl:apply-templates>-        </xsl:when>-        <xsl:when test="$sort-by = 'author'">-          <xsl:apply-templates>-            <xsl:sort select="@author"/>-          </xsl:apply-templates>-        </xsl:when>-        <xsl:when test="$sort-by = 'revauthor'">-          <xsl:apply-templates>-            <xsl:sort select="@author" order="descending"/>-          </xsl:apply-templates>-        </xsl:when>-        <xsl:otherwise>-          <!-- use the repository's natural order -->-          <xsl:apply-templates/>-        </xsl:otherwise>-      </xsl:choose>-    </table>-  </xsl:template>--  <xsl:template match="patch">-    <xsl:variable name="author" select="@author"/>-    <xsl:variable name="hash"   select="@hash"/>-    <xsl:variable name="name"   select="name"/>-    <xsl:variable name="repo"   select="/darcs/@repository"/>--    <xsl:variable name="created-as" select="/darcs/changelog/created_as"/>-    <xsl:variable name="creator-hash" select="$created-as/patch/@hash"/>-    <xsl:variable name="original-name" select="$created-as/@original_name"/>--    <xsl:variable name="annotate-href">-      <xsl:value-of select="$command"/>?c=annotate&amp;p=<xsl:value-of select="$hash"/>--      <xsl:if test="$creator-hash">&amp;ch=<xsl:value-of select="$creator-hash"/></xsl:if>-      <xsl:if test="$original-name">&amp;o=<xsl:value-of select="$original-name"/></xsl:if>-    </xsl:variable>-    -    <tr class="patch">-      <td><a href="{$annotate-href}"><xsl:value-of select="name"/></a></td>-      <td><xsl:value-of select="@local_date"/></td>-      <td>-        <a href="mailto:{$author}"><xsl:value-of select="$author"/></a>-      </td>-      <td>-        <a href="{$cgi-program}/{$repo}/?c=annotate&amp;p={$hash}">detail</a>-      </td>-    </tr>-    <xsl:apply-templates/>-  </xsl:template>--  <!-- ignore <created_as>, <name> and <comment> children of <patch> -->-  <xsl:template match="created_as"/>-  <xsl:template match="name"/>-  <xsl:template match="comment"/>-</xsl:stylesheet>
− contrib/cgi/xslt/repos.xslt
@@ -1,59 +0,0 @@-<?xml version="1.0" encoding="utf-8"?>--<!--- template for displaying a list of available repositories, used when a- CGI request has no repository path information.  This template expects- the following external variables:--   cgi-program    - path to the CGI executable, to place in links-   stylesheet     - path to the CSS stylesheet-- the input XML must have the following structure:-- <darcs repository="">-   <repositories>-     <repository name=""/>-   </repositories>- </darcs>--->-<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">-  <xsl:variable name="command">-    <xsl:value-of select="$cgi-program"/>/<xsl:value-of select="/darcs/@target"/>-  </xsl:variable>-  -  <xsl:template match="/darcs">-    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">-      <head>-        <title>darcs repository viewer</title>-        <link rel="stylesheet" href="{$stylesheet}"/>-      </head>--      <body>-        <h1 class="target">Available Repositories</h1>--        <table>-          <xsl:apply-templates/>-        </table>-      </body>-    </html>-  </xsl:template>--  <xsl:template match="repositories">-    <xsl:apply-templates>-      <xsl:sort select="name(self::node())"/>-      <xsl:sort select="@name"/>-    </xsl:apply-templates>-  </xsl:template>--  <xsl:template match="repositories/repository">-    <xsl:variable name="repository"  select="@name"/>--    <tr>-      <td>-        <a href="{$cgi-program}/{$repository}/?c=browse">-          <xsl:value-of select="$repository"/>-        </a>-      </td>-    </tr>-  </xsl:template>-</xsl:stylesheet>
− contrib/cgi/xslt/rss.xslt
@@ -1,92 +0,0 @@-<?xml version="1.0" encoding="utf-8"?>--<!--- template for converting darcs' `changes` output from XML to RSS.  This- template expects the following external variables:--   cgi-url    - full URL to the CGI executable, to place in links-- the input XML must have the following structure:-- <darcs repository="">-   <changelog>-     <patch author="" date="" localdate="" inverted="" hash="">-       <name></name>-       <comment></comment>-     </patch>-   </changelog>- </darcs>--->-<xsl:stylesheet version="1.0"-                exclude-result-prefixes="str"-                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"-                xmlns:str="http://exslt.org/strings">--  <xsl:variable name="repo" select="/darcs/@repository"/>--  <xsl:variable name="command">-    <xsl:value-of select="$cgi-url"/>/<xsl:value-of select="/darcs/@target"/>-  </xsl:variable>--  <xsl:template match="changelog">-    <rss version="2.0">-      <channel>-        <title>changes to <xsl:value-of select="$repo"/></title>-        <link><xsl:value-of select="$command"/></link>-        <description>-          Recent patches applied to the darcs repository named-          "<xsl:value-of select='$repo'/>".-        </description>--        <xsl:apply-templates>-          <xsl:sort select="@date"/>-        </xsl:apply-templates>-      </channel>-    </rss>-  </xsl:template>--  <xsl:template match="patch">-    <xsl:variable name="hash"       select="@hash"/>--    <xsl:variable name="created-as" select="/darcs/changelog/created_as"/>-    <xsl:variable name="creator-hash" select="$created-as/patch/@hash"/>-    <xsl:variable name="original-name" select="$created-as/@original_name"/>--    <xsl:variable name="annotate-href">-      <xsl:value-of select="$command"/>?c=annotate&amp;p=<xsl:value-of select="$hash"/>--      <xsl:if test="$creator-hash">&amp;ch=<xsl:value-of select="$creator-hash"/></xsl:if>-      <xsl:if test="$original-name">&amp;o=<xsl:value-of select="$original-name"/></xsl:if>-    </xsl:variable>--    <xsl:variable name="date-nodes" select="str:tokenize(@local_date, ' ')"/>-    <xsl:variable name="rfc-date">-      <xsl:value-of select="$date-nodes[1]"/>-      <xsl:value-of select="', '"/>-      <xsl:if test="$date-nodes[3] &lt; 10">0</xsl:if>-      <xsl:value-of select="$date-nodes[3]"/>-      <xsl:value-of select="' '"/>-      <xsl:value-of select="$date-nodes[2]"/>-      <xsl:value-of select="' '"/>-      <xsl:value-of select="$date-nodes[6]"/>-      <xsl:value-of select="' '"/>-      <xsl:value-of select="$date-nodes[4]"/>-      <xsl:value-of select="' '"/>-      <xsl:value-of select="$date-nodes[5]"/>-    </xsl:variable>--    <item>-      <title><xsl:value-of select="name"/></title>-      <link><xsl:value-of select="$annotate-href"/></link>-      <author><xsl:value-of select="@author"/></author>-      <description><xsl:value-of select="comment"/></description>-      <pubDate><xsl:value-of select="$rfc-date"/></pubDate>-    </item>-  </xsl:template>--  <!-- ignore <path> <created_as>, <name> and <comment> children of <patch> -->-  <xsl:template match="path"/>-  <xsl:template match="created_as"/>-  <xsl:template match="name"/>-  <xsl:template match="comment"/>-</xsl:stylesheet>
− contrib/cgi/xslt/styles.css
@@ -1,91 +0,0 @@-/**- stylesheet for darcs repository browser-**/--a:link, a:visited {-  color: blue;-  text-decoration: none;-}--a:hover { text-decoration: underline; }-a.sort  { color: black; }-a.revsort  { -  color: black;-  font-size: 75%;-}-a.home  { color: #9292C9; }--body { margin: 10px 10px 10px 10px; }--h1.target {-  font-size: 150%;-  font-weight: bold;-}--h2.patch {-  font-size: 125%;-  font-weight: bold;-  margin-top: -10px;-  padding-left: 10px;-}--h2.author {-  font-size: smaller;-  margin-top: -10px;-  font-weight: bold;-  padding-left: 30px;-}--input.patches {  margin-right: 20px; }-label.tag     {  margin-right: 5px; }--span.path, span.path > a { color: #2A2A6B; }--span.version {-  color: #9292C9;  -  margin-left: 75px;-}--span.comment {-  color: #2A2A6B;-  white-space: pre;-}--th,td {-  text-align: left;-  padding: 5px 10px 5px 10px;  -}--tr.annotate { background-color: #FFAAAA; }-tr.browse { background-color: #FFFF99; }-tr.patches { background-color: #AAFFAA; }-tr.directory { background-color: #CFCFCF; }-tr.file, tr.patch, tr.modified-file { background-color: #DCDCDA; }-tr.modified-file, tr.add-remove-file { background-color: #DCDCDA; }--pre {-    margin: 0 0 0 0;-}--a.added-line {-    color: #00AA00;-    float: left;-}--a.normal-line {-    color: #000000;-    float: left;-}--a.removed-line {-    color: #CC0000;-    float: left;-    text-decoration: line-through;-}--a.removed-by {-    clear: right;-    color: #CC0000;-    float: right;-    font-size: 125%;-}
darcs.cabal view
@@ -1,5 +1,5 @@ Name:           darcs-version:        2.3.1+version:        2.4 License:        GPL License-file:   COPYING Author:         David Roundy <droundy@darcs.net>, <darcs-users@darcs.net>@@ -44,13 +44,12 @@   -- The contrib directory would make a sensible 'darcs-contrib' package   contrib/_darcs.zsh, contrib/darcs_completion,   contrib/cygwin-wrapper.bash, contrib/update_roundup.pl, contrib/upload.cgi,-  contrib/cgi/darcs.cgi.in, contrib/cgi/cgi.conf.in, contrib/cgi/README.in-  contrib/cgi/xslt/*.xslt, contrib/cgi/xslt/*.xml, contrib/cgi/xslt/*.css,    -- documentation files   src/best_practices.tex, src/building_darcs.tex, src/configuring_darcs.tex,-  src/features.tex, src/gpl.tex, src/switching.tex,-  contrib/cgi/README.in+  src/features.tex, src/formats.tex, src/gpl.tex, src/switching.tex, src/darcs.tex+  doc/manual/images.tex, doc/manual/bigimages.tex, doc/manual/patch-theory.tex,+  doc/darcs.css    README, NEWS @@ -65,8 +64,9 @@   tests/network/*.sh   tests/lib   tests/example_binary.png-  bugs/*.sh +  GNUmakefile+ source-repository head   type:     darcs   location: http://darcs.net/@@ -83,21 +83,17 @@ flag http   description: Use the pure Haskell HTTP package for HTTP support. --- SUNSET: this should be mandatory after the 2009-07 release is out-flag bytestring-  description: Use the external bytestring package.--flag zlib-  description: Use the external zlib binding package.-  default:     True---- SUNSET: this should be mandatory after the 2009-07 release is out-flag utf8-string-  description: Use the external utf8-string binding package.+flag static+  description: Build static binary+  default:     False  flag terminfo   description: Use the terminfo package for enhanced console support. +flag threaded+  description: Use threading and SMP support.+  default:     True+ flag type-witnesses   description: Use GADT type witnesses.   default:     False@@ -112,6 +108,13 @@   description: Compile unit tests (requires QuickCheck >= 2.1.0.0).   default:     False +flag hpc+  default:     False++flag deps-only+  default:     False+  description: A cunning trick to have cabal install build dependencies+ Executable          witnesses   main-is:          witnesses.hs   hs-source-dirs:   src@@ -120,16 +123,21 @@   -- FIXME...   c-sources:        src/atomic_create.c                     src/fpstring.c-                    src/c_compat.c                     src/maybe_relink.c                     src/umask.c                     src/Crypt/sha2.c++  extensions:+    CPP+    UndecidableInstances+    ScopedTypeVariables+    RankNTypes+    GADTs+    ImpredicativeTypes+   if !flag(type-witnesses)     buildable: False -  if !flag(zlib)-    extra-libraries:  z-   if os(windows)     hs-source-dirs: src/win32     include-dirs:   src/win32@@ -205,16 +213,14 @@                     Darcs.FilePathMonad                     Darcs.Flags                     Darcs.Global-                    Darcs.Gorsvet                     Darcs.Hopefully                     Darcs.IO                     Darcs.Lock                     Darcs.Match-                    Darcs.Ordered+                    Darcs.Witnesses.Ordered                     Darcs.Patch                     Darcs.Patch.Apply                     Darcs.Patch.Bundle-                    Darcs.Patch.Check                     Darcs.Patch.Choices                     Darcs.Patch.Commute                     Darcs.Patch.Core@@ -224,6 +230,7 @@                     Darcs.Patch.Match                     Darcs.Patch.MatchData                     Darcs.Patch.Non+                    Darcs.Patch.OldDate                     Darcs.Patch.Patchy                     Darcs.Patch.Permutations                     Darcs.Patch.Prim@@ -231,8 +238,10 @@                     Darcs.Patch.Read                     Darcs.Patch.ReadMonads                     Darcs.Patch.Real+                    Darcs.Patch.RegChars                     Darcs.Patch.Set                     Darcs.Patch.Show+                    Darcs.Patch.Split                     Darcs.Patch.TouchesFiles                     Darcs.Patch.Viewing                     Darcs.Population@@ -250,20 +259,24 @@                     Darcs.Repository.HashedIO                     Darcs.Repository.HashedRepo                     Darcs.Repository.Internal+                    Darcs.Repository.LowLevel+                    Darcs.Repository.Merge                     Darcs.Repository.InternalTypes                     Darcs.Repository.Motd                     Darcs.Repository.Prefs                     Darcs.Repository.Pristine                     Darcs.Repository.Repair+                    Darcs.Repository.State                     Darcs.Resolution                     Darcs.RunCommand-                    Darcs.Sealed+                    Darcs.Witnesses.Sealed                     Darcs.SelectChanges-                    Darcs.Show+                    Darcs.Witnesses.Show                     Darcs.SignalHandler                     Darcs.SlurpDirectory                     Darcs.SlurpDirectory.Internal                     Darcs.Test+                    Darcs.Test.Patch.Check                     Darcs.TheCommands                     Darcs.URL                     Darcs.Utils@@ -274,21 +287,18 @@                     HTTP                     IsoDate                     Lcs-                    OldDate                     Printer                     Progress-                    RegChars+                    Ratified                     SHA1                     Ssh                     URL-                    UTF8                     Workaround -  other-modules:    ThisVersion+  other-modules:    Version    c-sources:        src/atomic_create.c                     src/fpstring.c-                    src/c_compat.c                     src/maybe_relink.c                     src/umask.c                     src/Crypt/sha2.c@@ -313,23 +323,29 @@                    html         == 1.0.*,                    filepath     == 1.1.*,                    haskeline    >= 0.6.1 && < 0.7,-                   hashed-storage >= 0.3.8 && < 0.4+                   hashed-storage >= 0.4.7 && < 0.5    if !os(windows)-    build-depends: unix >= 1.0 && < 2.4+    build-depends: unix >= 1.0 && < 2.5    build-depends: base >= 3,+                 bytestring >= 0.9.0 && < 0.10,+                 utf8-string == 0.3.*,                    old-time   == 1.0.*,                    directory  == 1.0.*,                    process    == 1.0.*,-                   containers >= 0.1 && < 0.3,-                   array      >= 0.1 && < 0.3,+                   containers >= 0.1 && < 0.4,+                   array      >= 0.1 && < 0.4,                    random     == 1.0.* +   -- We need optimizations, regardless of what Hackage says-  ghc-options:      -Wall -O2 -funbox-strict-fields+  ghc-options:      -Wall -O2 -funbox-strict-fields -fwarn-tabs   ghc-prof-options: -prof -auto-all +  if flag(hpc)+    ghc-prof-options: -fhpc+   if flag(curl)     extra-libraries:   curl     includes:          curl/curl.h@@ -349,26 +365,14 @@       cpp-options:      -DHAVE_HTTP       x-have-http: -  if !flag(curl) && !flag(http)+  if (!flag(curl) && !flag(http)) || flag(deps-only)       buildable: False    if flag(mmap) && !os(windows)     build-depends:    mmap >= 0.2     cpp-options:      -DHAVE_MMAP -  if flag(bytestring)-    build-depends:    bytestring >= 0.9.0 && < 0.10-    cpp-options:      -DHAVE_BYTESTRING--  if flag(zlib)-    build-depends:    zlib >= 0.5.1.0 && < 0.6.0.0-    cpp-options:      -DHAVE_HASKELL_ZLIB-  else-    extra-libraries:  z--  if flag(utf8-string)-    build-depends:    utf8-string == 0.3.*-    cpp-options:      -DHAVE_UTF8STRING+  build-depends:    zlib >= 0.5.1.0 && < 0.6.0.0    -- The terminfo package cannot be built on Windows.   if flag(terminfo) && !os(windows)@@ -387,6 +391,7 @@     UndecidableInstances,     DeriveDataTypeable,     GADTs,+    ImpredicativeTypes,     TypeOperators,     ExistentialQuantification,     FlexibleContexts,@@ -409,18 +414,22 @@   include-dirs:     src   c-sources:        src/atomic_create.c                     src/fpstring.c-                    src/c_compat.c                     src/maybe_relink.c                     src/umask.c                     src/Crypt/sha2.c    -- We need optimizations, regardless of what Hackage says-  ghc-options:      -Wall -O2 -funbox-strict-fields -threaded+  ghc-options:      -Wall -O2 -funbox-strict-fields   ghc-prof-options: -prof -auto-all+  if flag(threaded)+    ghc-options:    -threaded -  if !flag(zlib)-    extra-libraries:  z+  if flag(static)+    ghc-options: -static -optl-static -optl-pthread +  if flag(hpc)+    ghc-prof-options: -fhpc+   cc-options:       -D_REENTRANT    if os(windows)@@ -444,17 +453,19 @@                    html         == 1.0.*,                    filepath     == 1.1.*,                    haskeline    >= 0.6.1 && < 0.7,-                   hashed-storage >= 0.3.8 && < 0.4+                   hashed-storage >= 0.4.4 && < 0.5    if !os(windows)-    build-depends: unix >= 1.0 && < 2.4+    build-depends: unix >= 1.0 && < 2.5    build-depends: base >= 3,+                 bytestring >= 0.9.0 && < 0.10,+                 utf8-string == 0.3.*,                    old-time   == 1.0.*,                    directory  == 1.0.*,                    process    == 1.0.*,-                   containers >= 0.1 && < 0.3,-                   array      >= 0.1 && < 0.3,+                   containers >= 0.1 && < 0.4,+                   array      >= 0.1 && < 0.4,                    random     == 1.0.*    if flag(curl)@@ -476,26 +487,14 @@       cpp-options:      -DHAVE_HTTP       x-have-http: -  if !flag(curl) && !flag(http)+  if (!flag(curl) && !flag(http)) || flag(deps-only)       buildable: False    if flag(mmap) && !os(windows)     build-depends:    mmap >= 0.2     cpp-options:      -DHAVE_MMAP -  if flag(bytestring)-    build-depends:    bytestring >= 0.9.0 && < 0.10-    cpp-options:      -DHAVE_BYTESTRING--  if flag(zlib)-    build-depends:    zlib >= 0.5.1.0 && < 0.6.0.0-    cpp-options:      -DHAVE_HASKELL_ZLIB-  else-    extra-libraries:  z--  if flag(utf8-string)-    build-depends:    utf8-string == 0.3.*-    cpp-options:      -DHAVE_UTF8STRING+  build-depends:    zlib >= 0.5.1.0 && < 0.6.0.0    -- The terminfo package cannot be built on Windows.   if flag(terminfo) && !os(windows)@@ -514,6 +513,7 @@     UndecidableInstances,     DeriveDataTypeable,     GADTs,+    ImpredicativeTypes,     TypeOperators,     ExistentialQuantification,     FlexibleContexts,@@ -536,14 +536,15 @@   include-dirs:     src   c-sources:        src/atomic_create.c                     src/fpstring.c-                    src/c_compat.c                     src/maybe_relink.c                     src/umask.c                     src/Crypt/sha2.c    -- We need optimizations, regardless of what Hackage says-  ghc-options:      -Wall -O2 -funbox-strict-fields -threaded+  ghc-options:      -Wall -O2 -funbox-strict-fields   ghc-prof-options: -prof -auto-all+  if flag(threaded)+    ghc-options:    -threaded    if !flag(test)     buildable: False@@ -562,9 +563,6 @@                      test-framework-quickcheck2 >= 0.2.2  -  if !flag(zlib)-    extra-libraries:  z-   cc-options:       -D_REENTRANT    if os(windows)@@ -581,29 +579,22 @@     cc-options:     -DHAVE_SIGINFO_H    if !os(windows)-    build-depends: unix >= 1.0 && < 2.4+    build-depends: unix >= 1.0 && < 2.5    build-depends: base >= 3,+                 bytestring >= 0.9.0 && < 0.10,                    old-time   == 1.0.*,                    directory  == 1.0.*,                    process    == 1.0.*,-                   containers >= 0.1 && < 0.3,-                   array      >= 0.1 && < 0.3,+                   containers >= 0.1 && < 0.4,+                   array      >= 0.1 && < 0.4,                    random     == 1.0.*    if flag(mmap) && !os(windows)     build-depends:    mmap >= 0.2     cpp-options:      -DHAVE_MMAP -  if flag(bytestring)-    build-depends:    bytestring >= 0.9.0 && < 0.10-    cpp-options:      -DHAVE_BYTESTRING--  if flag(zlib)-    build-depends:    zlib >= 0.5.1.0 && < 0.6.0.0-    cpp-options:      -DHAVE_HASKELL_ZLIB-  else-    extra-libraries:  z+  build-depends:    zlib >= 0.5.1.0 && < 0.6.0.0    -- The terminfo package cannot be built on Windows.   if flag(terminfo) && !os(windows)
+ doc/darcs.css view
@@ -0,0 +1,94 @@+BODY {+  background: white;+  color: black;+  font-family: arial,sans-serif;+  margin: 0;+  padding: 1em;+}++A:link {+  background: transparent;+  color: #494a82;+}++A:visited {+  background: transparent;+  color: #8081b3+}++IMG.thanks-left {+  float: left;+  margin-right: 5px;+  height: 50px;+}++IMG.thanks-right {+  float: right;+  margin-left: 5px;+  height: 50px;+}++PRE     {+  background: #eeeeee;+  border: 1px solid #888888;+  color: black;+  padding: 1em;+  white-space: pre;+}++H1      {+  color: #494a82;+  font-size: 24px ;+}++H2      {+  color: #494a82;+  font-size: 18px;+}++H3      {+  color: #494a82;+  font-size: 16px;+}++H4      {+  color: #494a82;+  font-size: 14px;+}++/* headers for darcs command options */+.cmd-opt-hdr     {+  color: #494a82;+  font-size: 14px;+  font-weight: bold;+}++/* begin styles for RSS Feed This is the most basic style to use for a list with no bullets */++.rss_title, rss_title a {+    margin: 0px 0;+    padding: 0;+}++.rss_items {+       list-style:none;+       margin:0;+       padding:0;+}++.rss_item  {+/*  font-size: x-small; */+  margin-bottom: 1em;;+}++.rss_item a:link, .rss_item a:visited, .rss_item a:active {++    }++.rss_item a:hover { ++    }+    +.rss_date {+    font-size: xx-small;+    }
+ doc/manual/bigimages.tex view
@@ -0,0 +1,605 @@+\batchmode+++\documentclass{book}+\RequirePackage{ifthen}+++++\usepackage{verbatim}+\usepackage{html}+\usepackage{fancyvrb}++%+\newenvironment{code}{\comment}{\endcomment} +++++\usepackage[dvips]{color}+++\pagecolor[gray]{.7}++\usepackage[latin1]{inputenc}++++\makeatletter++\makeatletter+\count@=\the\catcode`\_ \catcode`\_=8 +\newenvironment{tex2html_wrap}{}{}%+\catcode`\<=12\catcode`\_=\count@+\newcommand{\providedcommand}[1]{\expandafter\providecommand\csname #1\endcsname}%+\newcommand{\renewedcommand}[1]{\expandafter\providecommand\csname #1\endcsname{}%+  \expandafter\renewcommand\csname #1\endcsname}%+\newcommand{\newedenvironment}[1]{\newenvironment{#1}{}{}\renewenvironment{#1}}%+\let\newedcommand\renewedcommand+\let\renewedenvironment\newedenvironment+\makeatother+\let\mathon=$+\let\mathoff=$+\ifx\AtBeginDocument\undefined \newcommand{\AtBeginDocument}[1]{}\fi+\newbox\sizebox+\setlength{\hoffset}{0pt}\setlength{\voffset}{0pt}+\addtolength{\textheight}{\footskip}\setlength{\footskip}{0pt}+\addtolength{\textheight}{\topmargin}\setlength{\topmargin}{0pt}+\addtolength{\textheight}{\headheight}\setlength{\headheight}{0pt}+\addtolength{\textheight}{\headsep}\setlength{\headsep}{0pt}+\setlength{\textwidth}{349pt}+\newwrite\lthtmlwrite+\makeatletter+\let\realnormalsize=\normalsize+\global\topskip=2sp+\def\preveqno{}\let\real@float=\@float \let\realend@float=\end@float+\def\@float{\let\@savefreelist\@freelist\real@float}+\def\liih@math{\ifmmode$\else\bad@math\fi}+\def\end@float{\realend@float\global\let\@freelist\@savefreelist}+\let\real@dbflt=\@dbflt \let\end@dblfloat=\end@float+\let\@largefloatcheck=\relax+\let\if@boxedmulticols=\iftrue+\def\@dbflt{\let\@savefreelist\@freelist\real@dbflt}+\def\adjustnormalsize{\def\normalsize{\mathsurround=0pt \realnormalsize+ \parindent=0pt\abovedisplayskip=0pt\belowdisplayskip=0pt}%+ \def\phantompar{\csname par\endcsname}\normalsize}%+\def\lthtmltypeout#1{{\let\protect\string \immediate\write\lthtmlwrite{#1}}}%+\newcommand\lthtmlhboxmathA{\adjustnormalsize\setbox\sizebox=\hbox\bgroup\kern.05em }%+\newcommand\lthtmlhboxmathB{\adjustnormalsize\setbox\sizebox=\hbox to\hsize\bgroup\hfill }%+\newcommand\lthtmlvboxmathA{\adjustnormalsize\setbox\sizebox=\vbox\bgroup %+ \let\ifinner=\iffalse \let\)\liih@math }%+\newcommand\lthtmlboxmathZ{\@next\next\@currlist{}{\def\next{\voidb@x}}%+ \expandafter\box\next\egroup}%+\newcommand\lthtmlmathtype[1]{\gdef\lthtmlmathenv{#1}}%+\newcommand\lthtmllogmath{\dimen0\ht\sizebox \advance\dimen0\dp\sizebox+  \ifdim\dimen0>.95\vsize+   \lthtmltypeout{%+*** image for \lthtmlmathenv\space is too tall at \the\dimen0, reducing to .95 vsize ***}%+   \ht\sizebox.95\vsize \dp\sizebox\z@ \fi+  \lthtmltypeout{l2hSize %+:\lthtmlmathenv:\the\ht\sizebox::\the\dp\sizebox::\the\wd\sizebox.\preveqno}}%+\newcommand\lthtmlfigureA[1]{\let\@savefreelist\@freelist+       \lthtmlmathtype{#1}\lthtmlvboxmathA}%+\newcommand\lthtmlpictureA{\bgroup\catcode`\_=8 \lthtmlpictureB}%+\newcommand\lthtmlpictureB[1]{\lthtmlmathtype{#1}\egroup+       \let\@savefreelist\@freelist \lthtmlhboxmathB}%+\newcommand\lthtmlpictureZ[1]{\hfill\lthtmlfigureZ}%+\newcommand\lthtmlfigureZ{\lthtmlboxmathZ\lthtmllogmath\copy\sizebox+       \global\let\@freelist\@savefreelist}%+\newcommand\lthtmldisplayA{\bgroup\catcode`\_=8 \lthtmldisplayAi}%+\newcommand\lthtmldisplayAi[1]{\lthtmlmathtype{#1}\egroup\lthtmlvboxmathA}%+\newcommand\lthtmldisplayB[1]{\edef\preveqno{(\theequation)}%+  \lthtmldisplayA{#1}\let\@eqnnum\relax}%+\newcommand\lthtmldisplayZ{\lthtmlboxmathZ\lthtmllogmath\lthtmlsetmath}%+\newcommand\lthtmlinlinemathA{\bgroup\catcode`\_=8 \lthtmlinlinemathB}+\newcommand\lthtmlinlinemathB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA+  \vrule height1.5ex width0pt }%+\newcommand\lthtmlinlineA{\bgroup\catcode`\_=8 \lthtmlinlineB}%+\newcommand\lthtmlinlineB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA}%+\newcommand\lthtmlinlineZ{\egroup\expandafter\ifdim\dp\sizebox>0pt %+  \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetinline}+\newcommand\lthtmlinlinemathZ{\egroup\expandafter\ifdim\dp\sizebox>0pt %+  \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetmath}+\newcommand\lthtmlindisplaymathZ{\egroup %+  \centerinlinemath\lthtmllogmath\lthtmlsetmath}+\def\lthtmlsetinline{\hbox{\vrule width.1em \vtop{\vbox{%+  \kern.1em\copy\sizebox}\ifdim\dp\sizebox>0pt\kern.1em\else\kern.3pt\fi+  \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}}+\def\lthtmlsetmath{\hbox{\vrule width.1em\kern-.05em\vtop{\vbox{%+  \kern.1em\kern0.8 pt\hbox{\hglue.17em\copy\sizebox\hglue0.8 pt}}\kern.3pt%+  \ifdim\dp\sizebox>0pt\kern.1em\fi \kern0.8 pt%+  \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}}+\def\centerinlinemath{%+  \dimen1=\ifdim\ht\sizebox<\dp\sizebox \dp\sizebox\else\ht\sizebox\fi+  \advance\dimen1by.5pt \vrule width0pt height\dimen1 depth\dimen1 + \dp\sizebox=\dimen1\ht\sizebox=\dimen1\relax}++\def\lthtmlcheckvsize{\ifdim\ht\sizebox<\vsize +  \ifdim\wd\sizebox<\hsize\expandafter\hfill\fi \expandafter\vfill+  \else\expandafter\vss\fi}%+\providecommand{\selectlanguage}[1]{}%+\makeatletter \tracingstats = 1 +++\begin{document}+\pagestyle{empty}\thispagestyle{empty}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength hsize=\the\hsize}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength vsize=\the\vsize}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength hoffset=\the\hoffset}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength voffset=\the\voffset}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength topmargin=\the\topmargin}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength topskip=\the\topskip}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength headheight=\the\headheight}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength headsep=\the\headsep}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength parskip=\the\parskip}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength oddsidemargin=\the\oddsidemargin}\lthtmltypeout{}%+\makeatletter+\if@twoside\lthtmltypeout{latex2htmlLength evensidemargin=\the\evensidemargin}%+\else\lthtmltypeout{latex2htmlLength evensidemargin=\the\oddsidemargin}\fi%+\lthtmltypeout{}%+\makeatother+\setcounter{page}{1}+\onecolumn++% !!! IMAGES START HERE !!!++\stepcounter{chapter}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{chapter}+\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2771}%+$<$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2773}%+$>$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{paragraph}+\stepcounter{chapter}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{section}+\stepcounter{chapter}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2775}%+$+$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2777}%+$R_{c}$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2779}%+$f_1$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2781}%+$R_c$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2783}%+$R_1$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2787}%+$f_2$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2795}%+$R_2$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2835}%+$R_p$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2839}%+$R_l$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{chapter}+\stepcounter{chapter}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{subsection}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2841}%+$\backslash$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2847}%+$ R_1 \bigcup R_2+\bigcup R_3 \ldots$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2849}%+$ R_1 \bigcap R_2 \bigcap R_3 \ldots$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2851}%+$ S+\backslash S \rightarrow \emptyset $%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2853}%+$ R_1+\backslash (R_2 \bigcup R_3 \bigcup \ldots$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}++%+\providecommand{\pullwarning}[1]{+\textbf{WARNING:} #1 should not be run when there is a possibility+that another user may be pulling from the same repository.  Attempting to do so+may cause repository corruption.}%++\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsubsection}+\stepcounter{subsection}+\appendix+\stepcounter{section}+\stepcounter{paragraph}+++\addtolength{\itemsep}{-0.5\baselineskip}%++\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{paragraph}+++\addtolength{\itemsep}{-0.5\baselineskip}%++\stepcounter{paragraph}+\stepcounter{chapter}+\stepcounter{section}+\stepcounter{section}+\stepcounter{chapter}+++\newtheorem{thm}{Theorem}%++++\newtheorem{dfn}{Definition}%++\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2863}%+$P_1$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2865}%+$P_2$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2867}%+$P_2P_1$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2873}%+$P_1\parallel P_2$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2875}%+$P^{ -1}$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2877}%+$P$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2759}%+\( P^{ -1} P \)%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmldisplayA{displaymath2763}%+\begin{displaymath} (P_2 P_1)^{ -1} = P_1^{ -1} P_2^{ -1}. \end{displaymath}%+\lthtmldisplayZ+\lthtmlcheckvsize\clearpage}++\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{subsection}+\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2881}%+$O(n)$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{section}+\stepcounter{subsection}++%+\providecommand{\commutex}{\longleftrightarrow}%+++%+\providecommand{\commutes}{\longleftrightarrow}%++{\newpage\clearpage+\lthtmldisplayA{displaymath2764}%+\begin{displaymath} P_2 P_1 \longleftrightarrow {P_1}' {P_2}'. \end{displaymath}%+\lthtmldisplayZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2887}%+$P_1'$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2893}%+$P_2'$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2897}%+$\longleftrightarrow $%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2899}%+$==$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2901}%+$\ddot\frown$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{paragraph}++%+\providecommand{\merge}{\Longrightarrow}%++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2760}%+\( \Longrightarrow \)%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmldisplayA{displaymath2765}%+\begin{displaymath}  P_2 \parallel P_1 \Longrightarrow {P_2}' P_1 \longleftrightarrow {P_1}' P_2. \end{displaymath}%+\lthtmldisplayZ+\lthtmlcheckvsize\clearpage}++\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2911}%+$ P_2' P_1 \longleftrightarrow P_1' P_2 $%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2913}%+$ P_1'^{ -1}+P_2' \longleftrightarrow P_2 P_1^{ -1} $%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2915}%+$P_1'^{ -1}$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2917}%+$P_1^{ -1}$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmldisplayA{displaymath2766}%+\begin{displaymath}+A^{ -1} C \longleftrightarrow C' A'^{ -1}+\end{displaymath}%+\lthtmldisplayZ+\lthtmlcheckvsize\clearpage}++\stepcounter{section}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{chapter}+\stepcounter{chapter}+\addtocounter{enumi}{-1}+\stepcounter{section}++\end{document}
+ doc/manual/images.tex view
@@ -0,0 +1,605 @@+\batchmode+++\documentclass{book}+\RequirePackage{ifthen}+++++\usepackage{verbatim}+\usepackage{html}+\usepackage{fancyvrb}++%+\newenvironment{code}{\comment}{\endcomment} +++++\usepackage[dvips]{color}+++\pagecolor[gray]{.7}++\usepackage[latin1]{inputenc}++++\makeatletter++\makeatletter+\count@=\the\catcode`\_ \catcode`\_=8 +\newenvironment{tex2html_wrap}{}{}%+\catcode`\<=12\catcode`\_=\count@+\newcommand{\providedcommand}[1]{\expandafter\providecommand\csname #1\endcsname}%+\newcommand{\renewedcommand}[1]{\expandafter\providecommand\csname #1\endcsname{}%+  \expandafter\renewcommand\csname #1\endcsname}%+\newcommand{\newedenvironment}[1]{\newenvironment{#1}{}{}\renewenvironment{#1}}%+\let\newedcommand\renewedcommand+\let\renewedenvironment\newedenvironment+\makeatother+\let\mathon=$+\let\mathoff=$+\ifx\AtBeginDocument\undefined \newcommand{\AtBeginDocument}[1]{}\fi+\newbox\sizebox+\setlength{\hoffset}{0pt}\setlength{\voffset}{0pt}+\addtolength{\textheight}{\footskip}\setlength{\footskip}{0pt}+\addtolength{\textheight}{\topmargin}\setlength{\topmargin}{0pt}+\addtolength{\textheight}{\headheight}\setlength{\headheight}{0pt}+\addtolength{\textheight}{\headsep}\setlength{\headsep}{0pt}+\setlength{\textwidth}{349pt}+\newwrite\lthtmlwrite+\makeatletter+\let\realnormalsize=\normalsize+\global\topskip=2sp+\def\preveqno{}\let\real@float=\@float \let\realend@float=\end@float+\def\@float{\let\@savefreelist\@freelist\real@float}+\def\liih@math{\ifmmode$\else\bad@math\fi}+\def\end@float{\realend@float\global\let\@freelist\@savefreelist}+\let\real@dbflt=\@dbflt \let\end@dblfloat=\end@float+\let\@largefloatcheck=\relax+\let\if@boxedmulticols=\iftrue+\def\@dbflt{\let\@savefreelist\@freelist\real@dbflt}+\def\adjustnormalsize{\def\normalsize{\mathsurround=0pt \realnormalsize+ \parindent=0pt\abovedisplayskip=0pt\belowdisplayskip=0pt}%+ \def\phantompar{\csname par\endcsname}\normalsize}%+\def\lthtmltypeout#1{{\let\protect\string \immediate\write\lthtmlwrite{#1}}}%+\newcommand\lthtmlhboxmathA{\adjustnormalsize\setbox\sizebox=\hbox\bgroup\kern.05em }%+\newcommand\lthtmlhboxmathB{\adjustnormalsize\setbox\sizebox=\hbox to\hsize\bgroup\hfill }%+\newcommand\lthtmlvboxmathA{\adjustnormalsize\setbox\sizebox=\vbox\bgroup %+ \let\ifinner=\iffalse \let\)\liih@math }%+\newcommand\lthtmlboxmathZ{\@next\next\@currlist{}{\def\next{\voidb@x}}%+ \expandafter\box\next\egroup}%+\newcommand\lthtmlmathtype[1]{\gdef\lthtmlmathenv{#1}}%+\newcommand\lthtmllogmath{\dimen0\ht\sizebox \advance\dimen0\dp\sizebox+  \ifdim\dimen0>.95\vsize+   \lthtmltypeout{%+*** image for \lthtmlmathenv\space is too tall at \the\dimen0, reducing to .95 vsize ***}%+   \ht\sizebox.95\vsize \dp\sizebox\z@ \fi+  \lthtmltypeout{l2hSize %+:\lthtmlmathenv:\the\ht\sizebox::\the\dp\sizebox::\the\wd\sizebox.\preveqno}}%+\newcommand\lthtmlfigureA[1]{\let\@savefreelist\@freelist+       \lthtmlmathtype{#1}\lthtmlvboxmathA}%+\newcommand\lthtmlpictureA{\bgroup\catcode`\_=8 \lthtmlpictureB}%+\newcommand\lthtmlpictureB[1]{\lthtmlmathtype{#1}\egroup+       \let\@savefreelist\@freelist \lthtmlhboxmathB}%+\newcommand\lthtmlpictureZ[1]{\hfill\lthtmlfigureZ}%+\newcommand\lthtmlfigureZ{\lthtmlboxmathZ\lthtmllogmath\copy\sizebox+       \global\let\@freelist\@savefreelist}%+\newcommand\lthtmldisplayA{\bgroup\catcode`\_=8 \lthtmldisplayAi}%+\newcommand\lthtmldisplayAi[1]{\lthtmlmathtype{#1}\egroup\lthtmlvboxmathA}%+\newcommand\lthtmldisplayB[1]{\edef\preveqno{(\theequation)}%+  \lthtmldisplayA{#1}\let\@eqnnum\relax}%+\newcommand\lthtmldisplayZ{\lthtmlboxmathZ\lthtmllogmath\lthtmlsetmath}%+\newcommand\lthtmlinlinemathA{\bgroup\catcode`\_=8 \lthtmlinlinemathB}+\newcommand\lthtmlinlinemathB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA+  \vrule height1.5ex width0pt }%+\newcommand\lthtmlinlineA{\bgroup\catcode`\_=8 \lthtmlinlineB}%+\newcommand\lthtmlinlineB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA}%+\newcommand\lthtmlinlineZ{\egroup\expandafter\ifdim\dp\sizebox>0pt %+  \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetinline}+\newcommand\lthtmlinlinemathZ{\egroup\expandafter\ifdim\dp\sizebox>0pt %+  \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetmath}+\newcommand\lthtmlindisplaymathZ{\egroup %+  \centerinlinemath\lthtmllogmath\lthtmlsetmath}+\def\lthtmlsetinline{\hbox{\vrule width.1em \vtop{\vbox{%+  \kern.1em\copy\sizebox}\ifdim\dp\sizebox>0pt\kern.1em\else\kern.3pt\fi+  \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}}+\def\lthtmlsetmath{\hbox{\vrule width.1em\kern-.05em\vtop{\vbox{%+  \kern.1em\kern0.8 pt\hbox{\hglue.17em\copy\sizebox\hglue0.8 pt}}\kern.3pt%+  \ifdim\dp\sizebox>0pt\kern.1em\fi \kern0.8 pt%+  \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}}+\def\centerinlinemath{%+  \dimen1=\ifdim\ht\sizebox<\dp\sizebox \dp\sizebox\else\ht\sizebox\fi+  \advance\dimen1by.5pt \vrule width0pt height\dimen1 depth\dimen1 + \dp\sizebox=\dimen1\ht\sizebox=\dimen1\relax}++\def\lthtmlcheckvsize{\ifdim\ht\sizebox<\vsize +  \ifdim\wd\sizebox<\hsize\expandafter\hfill\fi \expandafter\vfill+  \else\expandafter\vss\fi}%+\providecommand{\selectlanguage}[1]{}%+\makeatletter \tracingstats = 1 +++\begin{document}+\pagestyle{empty}\thispagestyle{empty}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength hsize=\the\hsize}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength vsize=\the\vsize}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength hoffset=\the\hoffset}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength voffset=\the\voffset}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength topmargin=\the\topmargin}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength topskip=\the\topskip}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength headheight=\the\headheight}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength headsep=\the\headsep}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength parskip=\the\parskip}\lthtmltypeout{}%+\lthtmltypeout{latex2htmlLength oddsidemargin=\the\oddsidemargin}\lthtmltypeout{}%+\makeatletter+\if@twoside\lthtmltypeout{latex2htmlLength evensidemargin=\the\evensidemargin}%+\else\lthtmltypeout{latex2htmlLength evensidemargin=\the\oddsidemargin}\fi%+\lthtmltypeout{}%+\makeatother+\setcounter{page}{1}+\onecolumn++% !!! IMAGES START HERE !!!++\stepcounter{chapter}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{chapter}+\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2771}%+$<$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2773}%+$>$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{paragraph}+\stepcounter{chapter}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{section}+\stepcounter{chapter}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2775}%+$+$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2777}%+$R_{c}$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2779}%+$f_1$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2781}%+$R_c$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2783}%+$R_1$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2787}%+$f_2$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2795}%+$R_2$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2835}%+$R_p$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2839}%+$R_l$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{chapter}+\stepcounter{chapter}+\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{subsection}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2841}%+$\backslash$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2847}%+$ R_1 \bigcup R_2+\bigcup R_3 \ldots$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2849}%+$ R_1 \bigcap R_2 \bigcap R_3 \ldots$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2851}%+$ S+\backslash S \rightarrow \emptyset $%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2853}%+$ R_1+\backslash (R_2 \bigcup R_3 \bigcup \ldots$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}++%+\providecommand{\pullwarning}[1]{+\textbf{WARNING:} #1 should not be run when there is a possibility+that another user may be pulling from the same repository.  Attempting to do so+may cause repository corruption.}%++\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{subsubsection}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{subsubsection}+\stepcounter{subsection}+\appendix+\stepcounter{section}+\stepcounter{paragraph}+++\addtolength{\itemsep}{-0.5\baselineskip}%++\stepcounter{paragraph}+\stepcounter{section}+\stepcounter{paragraph}+++\addtolength{\itemsep}{-0.5\baselineskip}%++\stepcounter{paragraph}+\stepcounter{chapter}+\stepcounter{section}+\stepcounter{section}+\stepcounter{chapter}+++\newtheorem{thm}{Theorem}%++++\newtheorem{dfn}{Definition}%++\stepcounter{section}+\stepcounter{section}+\stepcounter{section}+\stepcounter{subsection}+\stepcounter{subsection}+\stepcounter{section}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2863}%+$P_1$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2865}%+$P_2$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2867}%+$P_2P_1$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2873}%+$P_1\parallel P_2$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2875}%+$P^{ -1}$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2877}%+$P$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2759}%+\( P^{ -1} P \)%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmldisplayA{displaymath2763}%+\begin{displaymath} (P_2 P_1)^{ -1} = P_1^{ -1} P_2^{ -1}. \end{displaymath}%+\lthtmldisplayZ+\lthtmlcheckvsize\clearpage}++\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{subsection}+\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2881}%+$O(n)$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{section}+\stepcounter{subsection}++%+\providecommand{\commutex}{\longleftrightarrow}%+++%+\providecommand{\commutes}{\longleftrightarrow}%++{\newpage\clearpage+\lthtmldisplayA{displaymath2764}%+\begin{displaymath} P_2 P_1 \longleftrightarrow {P_1}' {P_2}'. \end{displaymath}%+\lthtmldisplayZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2887}%+$P_1'$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2893}%+$P_2'$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2897}%+$\longleftrightarrow $%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2899}%+$==$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2901}%+$\ddot\frown$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++\stepcounter{paragraph}++%+\providecommand{\merge}{\Longrightarrow}%++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2760}%+\( \Longrightarrow \)%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmldisplayA{displaymath2765}%+\begin{displaymath}  P_2 \parallel P_1 \Longrightarrow {P_2}' P_1 \longleftrightarrow {P_1}' P_2. \end{displaymath}%+\lthtmldisplayZ+\lthtmlcheckvsize\clearpage}++\stepcounter{subsection}+{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2911}%+$ P_2' P_1 \longleftrightarrow P_1' P_2 $%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2913}%+$ P_1'^{ -1}+P_2' \longleftrightarrow P_2 P_1^{ -1} $%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2915}%+$P_1'^{ -1}$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmlinlinemathA{tex2html_wrap_inline2917}%+$P_1^{ -1}$%+\lthtmlinlinemathZ+\lthtmlcheckvsize\clearpage}++{\newpage\clearpage+\lthtmldisplayA{displaymath2766}%+\begin{displaymath}+A^{ -1} C \longleftrightarrow C' A'^{ -1}+\end{displaymath}%+\lthtmldisplayZ+\lthtmlcheckvsize\clearpage}++\stepcounter{section}+\stepcounter{section}+\stepcounter{paragraph}+\stepcounter{paragraph}+\stepcounter{chapter}+\stepcounter{chapter}+\addtocounter{enumi}{-1}+\stepcounter{section}++\end{document}
+ doc/manual/patch-theory.tex view
@@ -0,0 +1,79 @@+%% This file was automatically generated by preproc.+%  Copyright (C) 2007 David Roundy+%+%  This program is free software; you can redistribute it and/or modify+%  it under the terms of the GNU General Public License as published by+%  the Free Software Foundation; either version 2, or (at your option)+%  any later version.+%+%  This program is distributed in the hope that it will be useful,+%  but WITHOUT ANY WARRANTY; without even the implied warranty of+%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+%  GNU General Public License for more details.+%+%  You should have received a copy of the GNU General Public License+%  along with this program; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\documentclass{article}+%\usepackage{color}++\usepackage{verbatim}+\usepackage{hyperref}+\usepackage{fancyvrb}+\newenvironment{code}{\comment}{\endcomment}+% \newenvironment{code}{\color{blue}\verbatim}{\endverbatim}++\newcommand{\commutes}{\longleftrightarrow}++\begin{document}+++\section{Patch properties}++Darcs is built on a hierarchy of patch types.  At the lowest level are+``primitive'' patches, and from these building blocks, a whole hierarchy of+patch types are built.  Each of these patch types must support a number of+functions, which must obey a number of laws.++\subsection{Properties of identity}++\newtheorem{prp}{Property}++\begin{prp}[Identity commutes trivially]+  The identity patch must commute with any patch without modifying said patch.+\end{prp}+++\begin{prp}[Inverse doesn't commute]+  A patch and its inverse will always commute, unless that patch is an+  identity patch (or an identity-like patch that has no effect).+\end{prp}+++\subsection{Commute properties}++\begin{prp}[Recommute]+  $AB \commutes B'A'$ if and only if $B'A' \commutes AB$+\end{prp}+++\begin{prp}[Commute inverses]+  $AB \commutes B'A'$ if and only if $B^{-1}A^{-1} \commutes A'^{-1}B'^{-1}$+\end{prp}+++\begin{prp}[Patch and inverse]+  If $AB \commutes B'A'$ then $A^{-1}B' \commutes BA'^{-1}$+\end{prp}++This property is only true of primitive patches.+++\begin{prp}[Permutivity]+  (to be added...)+\end{prp}+++\end{document}
release/distributed-context view
@@ -1,1 +1,1 @@-Just "\nContext:\n\n[TAG 2.3.1\nReinier Lamers <tux_rocker@reinier.de>**20090920174331\n Ignore-this: a5da37b9925e1dfe3e81f0b67183ef1f\n] \n"+Just "\nContext:\n\n[TAG 2.4\nReinier Lamers <tux_rocker@reinier.de>**20100226180900\n Ignore-this: 36ce0456c214345f55a7bc5fc142e985\n] \n"
src/ByteStringUtils.hs view
@@ -18,7 +18,6 @@ module ByteStringUtils (          unsafeWithInternals,-        unpackPSfromUTF8,          -- IO with mmap or gzip         gzReadFilePS,@@ -28,9 +27,7 @@          -- gzip handling         isGZFile,-#ifdef HAVE_HASKELL_ZLIB         gzDecompress,-#endif          -- list utilities         ifHeadThenTail,@@ -59,27 +56,22 @@ import Data.ByteString (intercalate, uncons) import Data.ByteString.Internal (fromForeignPtr) -#if defined (HAVE_MMAP) || ! defined (HAVE_HASKELL_ZLIB)+#if defined (HAVE_MMAP) import Control.Exception        ( catch ) #endif import System.IO import System.IO.Unsafe         ( unsafePerformIO )  import Foreign.Storable         ( peekElemOff, peek )-import Foreign.Marshal.Alloc    ( free )-import Foreign.Marshal.Array    ( mallocArray, peekArray, advancePtr )+import Foreign.Marshal.Array    ( advancePtr ) import Foreign.C.Types          ( CInt )  import Data.Bits                ( rotateL )-import Data.Char                ( chr, ord, isSpace )+import Data.Char                ( ord, isSpace ) import Data.Word                ( Word8 ) import Data.Int                 ( Int32 ) import Control.Monad            ( when ) -#ifndef HAVE_HASKELL_ZLIB-import Foreign.Ptr              ( nullPtr )-import Foreign.ForeignPtr       ( ForeignPtr )-#endif import Foreign.Ptr              ( plusPtr, Ptr ) import Foreign.ForeignPtr       ( withForeignPtr ) @@ -88,14 +80,10 @@ import Foreign.Ptr              ( FunPtr ) #endif -#if HAVE_HASKELL_ZLIB import qualified Data.ByteString.Lazy as BL import qualified Codec.Compression.GZip as GZ import qualified Codec.Compression.Zlib.Internal as ZI import Darcs.Global ( addCRCWarning )-#else-import Foreign.C.String ( CString, withCString )-#endif  #ifdef HAVE_MMAP import System.IO.MMap( mmapFileByteString )@@ -106,22 +94,6 @@ -- ----------------------------------------------------------------------------- -- obsolete debugging code -# ifndef HAVE_HASKELL_ZLIB-debugForeignPtr :: ForeignPtr a -> String -> IO ()-#ifdef DEBUG_PS-foreign import ccall unsafe "static fpstring.h debug_alloc" debug_alloc-    :: Ptr a -> CString -> IO ()-foreign import ccall unsafe "static fpstring.h & debug_free" debug_free-    :: FunPtr (Ptr a -> IO ())-debugForeignPtr fp n =-    withCString n $ \cname-> withForeignPtr fp $ \p->-    do debug_alloc p cname-       addForeignPtrFinalizer debug_free fp-#else-debugForeignPtr _ _ = return ()-#endif-#endif- -- ----------------------------------------------------------------------------- -- unsafeWithInternals @@ -142,26 +114,6 @@ readIntPS = BC.readInt . BC.dropWhile isSpace  -- -------------------------------------------------------------------------------- Destructor functions (taking PackedStrings apart)--unpackPSfromUTF8 :: B.ByteString -> String-unpackPSfromUTF8 ps =- case BI.toForeignPtr ps of-   (_,_, 0) -> ""-   (x,s,l)  ->-    unsafePerformIO $ withForeignPtr x $ \p->-    do outbuf <- mallocArray l-       lout <- fromIntegral `fmap`-               utf8_to_ints outbuf (p `plusPtr` s) (fromIntegral l)-       when (lout < 0) $ error "Bad UTF8!"-       str <- (map (chr . fromIntegral)) `fmap` peekArray lout outbuf-       free outbuf-       return str--foreign import ccall unsafe "static fpstring.h utf8_to_ints" utf8_to_ints-    :: Ptr Int -> Ptr Word8 -> CInt -> IO CInt---- ----------------------------------------------------------------------------- -- List-mimicking functions for PackedStrings  {-# INLINE ifHeadThenTail #-}@@ -343,8 +295,6 @@ -- ----------------------------------------------------------------------------- -- gzReadFilePS -#ifdef HAVE_HASKELL_ZLIB- -- |Decompress the given bytestring into a lazy list of chunks, along with a boolean -- flag indicating (if True) that the CRC was corrupted. -- Inspecting the flag will cause the entire list of chunks to be evaluated (but if@@ -353,7 +303,7 @@ gzDecompress mbufsize =     -- This is what the code would be without the bad CRC recovery logic:     -- return . BL.toChunks . GZ.decompressWith decompressParams-    toListWarn . ZI.decompressWithErrors ZI.GZip decompressParams+    toListWarn . ZI.decompressWithErrors ZI.gzipFormat decompressParams   where         decompressParams = case mbufsize of                               Just bufsize -> GZ.defaultDecompressParams { GZ.decompressBufferSize = bufsize }@@ -378,19 +328,6 @@         handleBad ZI.DataError "incorrect data check" = ([], True)         handleBad _ msg = error msg -#else--foreign import ccall unsafe "static zlib.h gzopen" c_gzopen-    :: CString -> CString -> IO (Ptr ())-foreign import ccall unsafe "static zlib.h gzclose" c_gzclose-    :: Ptr () -> IO ()-foreign import ccall unsafe "static zlib.h gzread" c_gzread-    :: Ptr () -> Ptr Word8 -> CInt -> IO CInt-foreign import ccall unsafe "static zlib.h gzwrite" c_gzwrite-    :: Ptr () -> Ptr Word8 -> CInt -> IO CInt--#endif- isGZFile :: FilePath -> IO (Maybe Int) isGZFile f = do     h <- openBinaryFile f ReadMode@@ -411,7 +348,6 @@     case mlen of        Nothing -> mmapFilePS f        Just len ->-#ifdef HAVE_HASKELL_ZLIB             do -- Passing the length to gzDecompress means that it produces produces one chunk,                -- which in turn means that B.concat won't need to copy data.                -- If the length is wrong this will just affect efficiency, not correctness@@ -420,19 +356,6 @@                                             return res                compressed <- (BL.fromChunks . return) `fmap` mmapFilePS f                B.concat `fmap` doDecompress compressed-#else-               withCString f $ \fstr-> withCString "rb" $ \rb-> do-                 gzf <- c_gzopen fstr rb-                 when (gzf == nullPtr) $ fail $ "problem opening file "++f-                 fp <- BI.mallocByteString len-                 debugForeignPtr fp $ "gzReadFilePS "++f-                 lread <- withForeignPtr fp $ \p ->-                          c_gzread gzf p (fromIntegral len)-                 c_gzclose gzf-                 when (fromIntegral lread /= len) $-                      fail $ "problem gzreading file "++f-                 return $ fromForeignPtr fp 0 len-#endif  hGetLittleEndInt :: Handle -> IO Int hGetLittleEndInt h = do@@ -447,26 +370,7 @@  gzWriteFilePSs :: FilePath -> [B.ByteString] -> IO () gzWriteFilePSs f pss  =-#ifdef HAVE_HASKELL_ZLIB     BL.writeFile f $ GZ.compress $ BL.fromChunks pss-#else-    withCString f $ \fstr -> withCString "wb" $ \wb -> do-    gzf <- c_gzopen fstr wb-    when (gzf == nullPtr) $ fail $ "problem gzopening file for write: "++f-    mapM_ (gzWriteToGzf gzf) pss `catch`-              \_ -> fail $ "problem gzwriting file: "++f-    c_gzclose gzf--gzWriteToGzf :: Ptr () -> B.ByteString -> IO ()-gzWriteToGzf gzf ps = case BI.toForeignPtr ps of- (_,_,0) -> return () -- avoid calling gzwrite with 0 length this would-                      -- trouble on some versions of zlib, and is always-                      -- unnecessary.- (x,s,l) -> do-    lw <- withForeignPtr x $ \p -> c_gzwrite gzf (p `plusPtr` s)-                                                 (fromIntegral l)-    when (fromIntegral lw /= l) $ fail $ "problem in gzWriteToGzf"-#endif  -- ----------------------------------------------------------------------------- -- mmapFilePS
src/CommandLine.hs view
@@ -109,7 +109,7 @@ parseCmd ftable s = parse (commandline ftable) "" s  urlEncode :: String -> String-urlEncode s = concat $ map escapeC s+urlEncode s = concatMap escapeC s     where escapeC x = if allowed x then [x] else '%':(intToHex $ ord x)           intToHex i = map intToDigit [i `div` 16, i `mod` 16]               allowed x = x `elem` ['a' .. 'z'] ++ ['A' .. 'Z'] ++ ['0' .. '9']
src/Darcs/ArgumentDefaults.lhs view
@@ -22,10 +22,10 @@ import Darcs.Arguments ( DarcsFlag,                          DarcsOption( DarcsArgOption, DarcsNoArgOption, DarcsMultipleChoiceOption ),                          arein, isin )-import Darcs.Commands ( CommandControl( Command_data ),-                        command_alloptions )-import Darcs.Commands.Help ( command_control_list )-import Darcs.Repository.Prefs ( get_global, get_preflist )+import Darcs.Commands ( CommandControl( CommandData ),+                        commandAlloptions )+import Darcs.Commands.Help ( commandControlList )+import Darcs.Repository.Prefs ( getGlobal, getPreflist ) \end{code}  \paragraph{defaults}\label{defaults}@@ -118,8 +118,8 @@ \begin{code} get_default_flags :: String -> [DarcsOption] -> [DarcsFlag] -> IO [DarcsFlag] get_default_flags com com_opts already = do-    repo_defs   <- default_content $ get_preflist "defaults"-    global_defs <- default_content $ get_global   "defaults"+    repo_defs   <- default_content $ getPreflist "defaults"+    global_defs <- default_content $ getGlobal   "defaults"     let repo_flags = get_flags_from com com_opts already repo_defs         global_flags = get_flags_from com com_opts                                           (already++repo_flags) global_defs@@ -132,8 +132,8 @@     where com_defs = filter (\ (c,_,_) -> c == com) defs           all_defs = filter (\ (c,_,_) -> c == "ALL") defs           options_for d o ao = concatMap (find_option o ao already) d-          all_opts = concatMap get_opts command_control_list-          get_opts (Command_data c) = let (o1, o2) = command_alloptions c+          all_opts = concatMap get_opts commandControlList+          get_opts (CommandData c) = let (o1, o2) = commandAlloptions c                                       in o1 ++ o2           get_opts _                = [] 
src/Darcs/Arguments.lhs view
@@ -16,8 +16,8 @@ %  Boston, MA 02110-1301, USA.  \begin{code}-{-# OPTIONS_GHC -cpp #-}-{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -cpp -XPatternGuards #-}+{-# LANGUAGE CPP, PatternGuards #-}  #include "gadts.h" @@ -27,87 +27,96 @@                          definePatches, defineChanges,                          fixFilePathOrStd, fixUrl,                          fixSubPaths, areFileArgs,-                         DarcsOption( .. ), option_from_darcsoption,-                         help, list_options, list_files,-                         any_verbosity, disable, restrict_paths,-                         notest, test, working_repo_dir,+                         DarcsOption( .. ), optionFromDarcsoption,+                         help, listOptions, listFiles,+                         anyVerbosity, disable, restrictPaths,+                         notest, test, workingRepoDir,                          testByDefault,-                         remote_repo,-                         leave_test_dir,-                         possibly_remote_repo_dir, get_repourl,-                         list_registered_files, list_unregistered_files,-                         author, get_author, get_easy_author, get_sendmail_cmd,-                         patchname_option, distname_option,-                         logfile, rmlogfile, from_opt, subject, get_subject,-                         in_reply_to, get_in_reply_to,-                         target, cc, get_cc, output, output_auto_name,-                         recursive, inventory_choices, get_inventory_choices,+                         remoteRepo,+                         leaveTestDir,+                         possiblyRemoteRepoDir, getRepourl,+                         listRegisteredFiles, listUnregisteredFiles,+                         author, getAuthor, getEasyAuthor, getSendmailCmd,+                         fileHelpAuthor, environmentHelpEmail,+                         patchnameOption, distnameOption,+                         logfile, rmlogfile, fromOpt, subject, getSubject,+                         inReplyTo, getInReplyTo,+                         target, ccSend, ccApply, getCc, output, outputAutoName,+                         recursive, inventoryChoices, getInventoryChoices,+                         upgradeFormat,                          askdeps, ignoretimes, lookforadds,-                         ask_long_comment, sendmail_cmd,+                         askLongComment, sendmailCmd,                          environmentHelpSendmail,-                         sign, verify, edit_description,-                         reponame, tagname, creatorhash,-                         apply_conflict_options, reply,-                         pull_conflict_options, use_external_merge,-                         deps_sel, nocompress,-                         uncompress_nocompress, repo_combinator,-                         options_latex, reorder_patches,-                         noskip_boring, allow_problematic_filenames,-                         applyas, human_readable,-                         changes_reverse, only_to_files,-                         changes_format, match_one_context, match_one_nontag,-                         match_maxcount,-                         send_to_context,-                         get_context,-                         pipe_interactive, all_interactive,-                         all_pipe_interactive,+                         sign, verify, editDescription,+                         reponame, creatorhash,+                         applyConflictOptions, reply,+                         pullConflictOptions, useExternalMerge,+                         depsSel, nocompress,+                         uncompressNocompress, repoCombinator,+                         optionsLatex, reorderPatches,+                         noskipBoring, allowProblematicFilenames,+                         applyas, humanReadable,+                         changesReverse, onlyToFiles,+                         changesFormat, matchOneContext, matchOneNontag,+                         matchMaxcount,+                         sendToContext,+                         getContext,+                         pipeInteractive, allInteractive,+                         allPipeInteractive,                          summary, unified, tokens,-                         checkpoint, partial, partial_check,-                         diff_cmd_flag, diffflags, unidiff, xmloutput,-                         force_replace, dry_run, dry_run_noxml,-                         print_dry_run_message_and_exit, showFriendly,-                         match_one, match_several, match_range,-                         match_several_or_range, happy_forwarding,-                         match_several_or_last,-                         set_default,-                         fancy_move_add,-                         set_scripts_executable,-                         sibling, flagsToSiblings, relink, relink_pristine, nolinks,+                         partial, partialCheck,+                         diffCmdFlag, diffflags, unidiff, xmloutput,+                         forceReplace, dryRun, dryRunNoxml,+                         printDryRunMessageAndExit, showFriendly,+                         matchOne, matchSeveral, matchRange,+                         matchSeveralOrRange, happyForwarding,+                         matchSeveralOrLast,+                         setDefault,+                         fancyMoveAdd,+                         setScriptsExecutableOption,+                         sibling, flagsToSiblings, relink, relinkPristine, nolinks,                          files, directories, pending,-                         posthook_cmd, posthook_prompt,-                         get_posthook_cmd,-                         prehook_cmd, prehook_prompt,-                         get_prehook_cmd, nullFlag,-                         umask_option,-                         store_in_memory,-                         patch_select_flag,-                         network_options, no_cache,-                         allow_unrelated_repos,-                         check_or_repair, just_this_repo+                         posthookCmd, posthookPrompt,+                         getPosthookCmd,+                         prehookCmd, prehookPrompt,+                         getPrehookCmd, nullFlag,+                         umaskOption,+                         storeInMemory,+                         patchSelectFlag,+                         networkOptions, noCache,+                         allowUnrelatedRepos,+                         checkOrRepair, justThisRepo, optimizePristine                       ) where import System.Console.GetOpt import System.Directory ( doesDirectoryExist )++import Storage.Hashed.AnchoredPath( anchorPath )+import Storage.Hashed.Plain( readPlainTree )+import Storage.Hashed.Tree( list, expand, emptyTree )+ import Data.List ( (\\), nub ) import Data.Maybe ( fromMaybe, listToMaybe ) import System.Exit ( ExitCode(ExitSuccess), exitWith ) import Data.Maybe ( catMaybes ) import Control.Monad ( when, unless )+import Control.Applicative( (<$>) ) import Data.Char ( isDigit ) #ifndef WIN32 import Printer ( renderString ) import System.Posix.Env ( setEnv )-import Darcs.Patch ( list_touched_files )+import Darcs.Patch ( listTouchedFiles ) import Progress ( beginTedious, endTedious, tediousSize, finishedOneIO ) #endif  import Darcs.Hopefully ( PatchInfoAnd, info, hopefullyM )-import Darcs.Patch ( RepoPatch, Patchy, showNicely, description, xml_summary )+import Darcs.Patch ( RepoPatch, Patchy, showNicely, description, xmlSummary ) import Darcs.Patch.Info ( to_xml )-import Darcs.Ordered ( FL, mapFL )+import Darcs.Witnesses.Ordered ( FL, mapFL ) import qualified Darcs.Patch ( summary ) import Darcs.Utils ( askUser, maybeGetEnv, firstNotBlank, firstJustIO,                      withCurrentDirectory )-import Darcs.Repository.Prefs ( boring_file_filter, get_preflist, get_global )+import Darcs.Repository.Prefs ( getPreflist, getGlobal )+import Darcs.Repository.State ( restrictBoring, readRecordedAndPending ) import Darcs.URL ( is_file ) import Darcs.RepoPath ( AbsolutePath, AbsolutePathOrStd, SubPath, toFilePath,                         makeSubPathOf, simpleSubPath,@@ -115,9 +124,7 @@                         makeAbsolute, makeAbsoluteOrStd, rootDirectory ) import Darcs.Patch.MatchData ( patch_match ) import Darcs.Flags ( DarcsFlag(..), maxCount )-import Darcs.Repository ( slurp_pending, withRepository, ($-) )-import Darcs.Repository.HashedRepo ( slurp_all_but_darcs )-import Darcs.SlurpDirectory ( list_slurpy )+import Darcs.Repository ( withRepository ) import Darcs.Global ( darcsdir ) import Printer ( Doc, putDocLn, text, vsep, ($$), vcat, insert_before_lastline,                  prefix )@@ -132,7 +139,7 @@ -- guarantees that isAnAbsolute, isa, flagToString, etc also work -- properly) --- | 'get_content' returns the content of a flag, if any.+-- | 'getContentString' returns the content of a flag, if any. -- For instance, the content of @Author \"Louis Aragon\"@ is @StringContent -- \"Louis Aragon\"@, while the content of @Pipe@ is @NoContent@ getContent :: DarcsFlag -> FlagContent@@ -144,6 +151,7 @@ getContent Test = NoContent getContent NoTest = NoContent getContent OnlyChangesToFiles = NoContent+getContent ChangesToAllFiles = NoContent getContent LeaveTestDir = NoContent getContent NoLeaveTestDir = NoContent getContent Timings = NoContent@@ -183,6 +191,7 @@ getContent AskDeps = NoContent getContent NoAskDeps = NoContent getContent RmLogFile = NoContent+getContent DontRmLogFile = NoContent getContent (DistName s) = StringContent s getContent (CreatorHash s) = StringContent s getContent (SignAs s) = StringContent s@@ -190,18 +199,22 @@ getContent (Verify s) = AbsoluteContent s getContent (VerifySSL s) = AbsoluteContent s getContent IgnoreTimes = NoContent+getContent DontIgnoreTimes = NoContent getContent LookForAdds = NoContent getContent NoLookForAdds = NoContent getContent AnyOrder = NoContent getContent Intersection = NoContent getContent Unified = NoContent+getContent NonUnified = NoContent getContent Union = NoContent getContent Complement = NoContent getContent Sign = NoContent getContent NoSign = NoContent getContent HappyForwarding = NoContent+getContent NoHappyForwarding = NoContent getContent SSHControlMaster = NoContent getContent NoSSHControlMaster = NoContent+getContent (RemoteDarcs s) = StringContent s getContent (Toks s) = StringContent s getContent (WorkRepoDir s) = StringContent s getContent (WorkRepoUrl s) = StringContent s@@ -216,9 +229,13 @@ getContent AllowConflicts = NoContent getContent MarkConflicts = NoContent getContent NoAllowConflicts = NoContent+getContent SkipConflicts = NoContent getContent Boring = NoContent+getContent SkipBoring = NoContent getContent AllowCaseOnly = NoContent+getContent DontAllowCaseOnly = NoContent getContent AllowWindowsReserved = NoContent+getContent DontAllowWindowsReserved = NoContent getContent DontGrabDeps = NoContent getContent DontPromptForDependencies = NoContent getContent PromptForDependencies = NoContent@@ -240,7 +257,7 @@ getContent (UpToPattern _) = NoContent -- FIXME!!! getContent (AfterPattern _) = NoContent -- FIXME!!! getContent Reverse = NoContent-getContent CheckPoint = NoContent+getContent Forward = NoContent getContent Partial = NoContent getContent Complete = NoContent getContent Lazy = NoContent@@ -265,6 +282,7 @@ getContent PristinePlain = NoContent getContent PristineNone = NoContent getContent NoUpdateWorking = NoContent+getContent UpgradeFormat = NoContent getContent Relink = NoContent getContent RelinkPristine = NoContent getContent NoLinks = NoContent@@ -283,6 +301,7 @@ getContent RunPrehook = NoContent getContent AskPrehook = NoContent getContent StoreInMemory = NoContent+getContent ApplyOnDisk = NoContent getContent HTTPPipelining = NoContent getContent NoHTTPPipelining = NoContent getContent NoCache = NoContent@@ -293,16 +312,18 @@ getContent Check = NoContent getContent Repair = NoContent getContent JustThisRepo = NoContent+getContent OptimizePristine = NoContent -get_content :: DarcsFlag -> Maybe String-get_content f = do StringContent s <- Just $ getContent f-                   return s+getContentString :: DarcsFlag -> Maybe String+getContentString f =+   do StringContent s <- Just $ getContent f+      return s  -- | @a `'isa'` b@ tests whether @a@ is flag @b@ with a string argument. -- @b@ typically is a Flag constructor expecting a string -- For example, @(Author \"Ted Hughes\") `isa` Author@ returns true. isa :: DarcsFlag -> (String -> DarcsFlag) -> Bool-a `isa` b = case get_content a of+a `isa` b = case getContentString a of             Nothing -> False             Just s -> a == b s @@ -378,35 +399,35 @@     -- ^ A constructor for grouping related options together, such as     -- @--hashed@, @--darcs-2@ and @--old-fashioned-inventory@. -option_from_darcsoption :: AbsolutePath -> DarcsOption -> [OptDescr DarcsFlag]-option_from_darcsoption _ (DarcsNoArgOption a b c h) = [Option a b (NoArg c) h]-option_from_darcsoption _ (DarcsArgOption a b c n h) = [Option a b (ReqArg c n) h]-option_from_darcsoption wd (DarcsMultipleChoiceOption os) = concatMap (option_from_darcsoption wd) os-option_from_darcsoption wd (DarcsAbsPathOrStdOption a b c n h) = [Option a b (ReqArg (c . makeAbsoluteOrStd wd) n) h]-option_from_darcsoption wd (DarcsAbsPathOption a b c n h) = [Option a b (ReqArg (c . makeAbsolute wd) n) h]-option_from_darcsoption wd (DarcsOptAbsPathOption a b d c n h) = [Option a b (OptArg (c . makeAbsolute wd . fromMaybe d) n) h]+optionFromDarcsoption :: AbsolutePath -> DarcsOption -> [OptDescr DarcsFlag]+optionFromDarcsoption _ (DarcsNoArgOption a b c h) = [Option a b (NoArg c) h]+optionFromDarcsoption _ (DarcsArgOption a b c n h) = [Option a b (ReqArg c n) h]+optionFromDarcsoption wd (DarcsMultipleChoiceOption os) = concatMap (optionFromDarcsoption wd) os+optionFromDarcsoption wd (DarcsAbsPathOrStdOption a b c n h) = [Option a b (ReqArg (c . makeAbsoluteOrStd wd) n) h]+optionFromDarcsoption wd (DarcsAbsPathOption a b c n h) = [Option a b (ReqArg (c . makeAbsolute wd) n) h]+optionFromDarcsoption wd (DarcsOptAbsPathOption a b d c n h) = [Option a b (OptArg (c . makeAbsolute wd . fromMaybe d) n) h]  -- | 'concat_option' creates a DarcsMultipleChoiceOption from a list of -- option, flattening any DarcsMultipleChoiceOption in the list.-concat_options :: [DarcsOption] -> DarcsOption-concat_options os = DarcsMultipleChoiceOption $ concatMap from_option os+concatOptions :: [DarcsOption] -> DarcsOption+concatOptions os = DarcsMultipleChoiceOption $ concatMap from_option os  where   from_option (DarcsMultipleChoiceOption xs) = xs   from_option x = [x] -extract_fix_path :: [DarcsFlag] -> Maybe (AbsolutePath, AbsolutePath)-extract_fix_path [] = Nothing-extract_fix_path ((FixFilePath repo orig):_)  = Just (repo, orig)-extract_fix_path (_:fs) = extract_fix_path fs+extractFixPath :: [DarcsFlag] -> Maybe (AbsolutePath, AbsolutePath)+extractFixPath [] = Nothing+extractFixPath ((FixFilePath repo orig):_)  = Just (repo, orig)+extractFixPath (_:fs) = extractFixPath fs  fixFilePath :: [DarcsFlag] -> FilePath -> IO AbsolutePath-fixFilePath opts f = case extract_fix_path opts of+fixFilePath opts f = case extractFixPath opts of                        Nothing -> bug "Can't fix path in fixFilePath"                        Just (_,o) -> withCurrentDirectory o $ ioAbsolute f  fixFilePathOrStd :: [DarcsFlag] -> FilePath -> IO AbsolutePathOrStd fixFilePathOrStd opts f =-    case extract_fix_path opts of+    case extractFixPath opts of       Nothing -> bug "Can't fix path in fixFilePathOrStd"       Just (_,o) -> withCurrentDirectory o $ ioAbsoluteOrStd f @@ -424,7 +445,7 @@               putStrLn $ "Ignoring non-repository paths: " ++ unwords bad        return $ nub good  where-    (r,o) = case extract_fix_path flags of+    (r,o) = case extractFixPath flags of             Just xxx -> xxx             Nothing -> bug "Can't fix path in fixSubPaths"     fixit p = do ap <- ioAbsolute p@@ -441,13 +462,13 @@ areFileArgs rps = concatMap toFilePath rps /= ""  -- | 'list_option' is an option which lists the command's arguments-list_options :: DarcsOption-list_options = DarcsNoArgOption [] ["list-options"] ListOptions+listOptions :: DarcsOption+listOptions = DarcsNoArgOption [] ["list-options"] ListOptions                "simply list the command's arguments"  flagToString :: [DarcsOption] -> DarcsFlag -> Maybe String flagToString x f = maybeHead $ catMaybes $ map f2o x-    where f2o (DarcsArgOption _ (s:_) c _ _) = do arg <- get_content f+    where f2o (DarcsArgOption _ (s:_) c _ _) = do arg <- getContentString f                                                   if c arg == f                                                       then return $ unwords [('-':'-':s), arg]                                                       else Nothing@@ -458,31 +479,29 @@           maybeHead [] = Nothing  reponame :: DarcsOption-tagname :: DarcsOption-deps_sel :: DarcsOption-checkpoint :: DarcsOption+depsSel :: DarcsOption partial :: DarcsOption-partial_check :: DarcsOption+partialCheck :: DarcsOption tokens :: DarcsOption-working_repo_dir :: DarcsOption-possibly_remote_repo_dir :: DarcsOption+workingRepoDir :: DarcsOption+possiblyRemoteRepoDir :: DarcsOption disable :: DarcsOption-restrict_paths :: DarcsOption+restrictPaths :: DarcsOption -pipe_interactive, all_pipe_interactive, all_interactive, all_patches, interactive, pipe,-  human_readable, diffflags, allow_problematic_filenames, noskip_boring,-  ask_long_comment, match_one_nontag, changes_reverse, creatorhash,-  changes_format, match_one_context, happy_forwarding, send_to_context,-  diff_cmd_flag, store_in_memory, use_external_merge,-  pull_conflict_options, target, cc, apply_conflict_options, reply, xmloutput,-  distname_option, patchname_option, edit_description,-  output, output_auto_name, unidiff, repo_combinator,-  unified, summary, uncompress_nocompress, subject, in_reply_to,-  nocompress, match_several_or_range, match_several_or_last,-  author, askdeps, lookforadds, ignoretimes, test, notest, help, force_replace,-  allow_unrelated_repos,-  match_one, match_range, match_several, fancy_move_add, sendmail_cmd,-  logfile, rmlogfile, leave_test_dir, from_opt, set_default+pipeInteractive, allPipeInteractive, allInteractive, all_patches, interactive, pipe,+  humanReadable, diffflags, allowProblematicFilenames, noskipBoring,+  askLongComment, matchOneNontag, changesReverse, creatorhash,+  changesFormat, matchOneContext, happyForwarding, sendToContext,+  diffCmdFlag, storeInMemory, useExternalMerge,+  pullConflictOptions, target, ccSend, ccApply, applyConflictOptions, reply, xmloutput,+  distnameOption, patchnameOption, editDescription,+  output, outputAutoName, unidiff, repoCombinator,+  unified, summary, uncompressNocompress, subject, inReplyTo,+  nocompress, matchSeveralOrRange, matchSeveralOrLast,+  author, askdeps, lookforadds, ignoretimes, test, notest, help, forceReplace,+  allowUnrelatedRepos,+  matchOne, matchRange, matchSeveral, fancyMoveAdd, sendmailCmd,+  logfile, rmlogfile, leaveTestDir, fromOpt, setDefault        :: DarcsOption @@ -527,8 +546,8 @@ \end{options} Most commands also accept the \verb!--verbose! option, which tells darcs to provide additional output.  The amount of verbosity varies from command to-command.  Commands that accept \verb!--verbose\verb! also accept \verb!--quiet\verb!,-which surpresses non-error output, and \verb!--normal-verbosity\verb! which can be+command.  Commands that accept \verb!--verbose! also accept \verb!--quiet!,+which surpresses non-error output, and \verb!--normal-verbosity! which can be used to restore the default verbosity if \verb!--verbose! or \verb!--quiet! is in the defaults file. @@ -540,8 +559,8 @@ would not be interesting. Option \verb!--debug-http! makes darcs output debugging info for libcurl. \begin{code}-any_verbosity :: [DarcsOption]-any_verbosity =[DarcsMultipleChoiceOption+anyVerbosity :: [DarcsOption]+anyVerbosity =[DarcsMultipleChoiceOption                 [DarcsNoArgOption [] ["debug"] Debug                  "give only debug output",                  DarcsNoArgOption [] ["debug-verbose"] DebugVerbose@@ -569,18 +588,18 @@ when running \verb'apply' from a mailer.  \begin{code}-working_repo_dir = DarcsArgOption [] ["repodir"] WorkRepoDir "DIRECTORY"+workingRepoDir = DarcsArgOption [] ["repodir"] WorkRepoDir "DIRECTORY"              "specify the repository directory in which to run"-possibly_remote_repo_dir = DarcsArgOption [] ["repo"] WorkRepoUrl "URL"+possiblyRemoteRepoDir = DarcsArgOption [] ["repo"] WorkRepoUrl "URL"              "specify the repository URL" --- | 'get_repourl' takes a list of flags and returns the url of the+-- | 'getRepourl' takes a list of flags and returns the url of the -- repository specified by @Repodir \"directory\"@ in that list of flags, if any. -- This flag is present if darcs was invoked with @--repodir=DIRECTORY@-get_repourl :: [DarcsFlag] -> Maybe String-get_repourl [] = Nothing-get_repourl (WorkRepoUrl d:_) | not (is_file d) = Just d-get_repourl (_:fs) = get_repourl fs+getRepourl :: [DarcsFlag] -> Maybe String+getRepourl [] = Nothing+getRepourl (WorkRepoUrl d:_) | not (is_file d) = Just d+getRepourl (_:fs) = getRepourl fs \end{code}  \begin{options}@@ -597,10 +616,10 @@ (and the default repository may be overwritten).  \begin{code}--- | 'remote_repo' is the option used to specify the URL of the remote+-- | 'remoteRepo' is the option used to specify the URL of the remote -- repository to work with-remote_repo :: DarcsOption-remote_repo = DarcsArgOption [] ["remote-repo"] RemoteRepo "URL"+remoteRepo :: DarcsOption+remoteRepo = DarcsArgOption [] ["remote-repo"] RemoteRepo "URL"              "specify the remote repository URL to work with" \end{code} @@ -608,13 +627,13 @@ \input{Darcs/Patch/Match.lhs}  \begin{code}-patchname_option = DarcsArgOption ['m'] ["patch-name"] PatchName "PATCHNAME"+patchnameOption = DarcsArgOption ['m'] ["patch-name"] PatchName "PATCHNAME"                    "name of patch" -send_to_context = DarcsAbsPathOption [] ["context"] Context "FILENAME"+sendToContext = DarcsAbsPathOption [] ["context"] Context "FILENAME"                   "send to context stored in FILENAME" -match_one_context =+matchOneContext =     DarcsMultipleChoiceOption     [DarcsArgOption [] ["to-match"] mp "PATTERN"      "select changes up to a patch matching PATTERN",@@ -626,16 +645,16 @@     ]     where mp s = OnePattern (patch_match s) -match_one = concat_options [__match, __patch, __tag, __index]-match_one_nontag = concat_options [__match, __patch, __index]-match_several    = concat_options [__matches, __patches, __tags]-match_range            = concat_options [match_to, match_from, __match, __patch, __last, __indexes]-match_several_or_range = concat_options [match_to, match_from, __last, __indexes,+matchOne = concatOptions [__match, __patch, __tag, __index]+matchOneNontag = concatOptions [__match, __patch, __index]+matchSeveral    = concatOptions [__matches, __patches, __tags]+matchRange            = concatOptions [matchTo, matchFrom, __match, __patch, __last, __indexes]+matchSeveralOrRange = concatOptions [matchTo, matchFrom, __last, __indexes,                                          __matches, __patches, __tags]-match_several_or_last  = concat_options [match_from, __last, __matches, __patches, __tags]+matchSeveralOrLast  = concatOptions [matchFrom, __last, __matches, __patches, __tags] -match_to, match_from :: DarcsOption-match_to = DarcsMultipleChoiceOption+matchTo, matchFrom :: DarcsOption+matchTo = DarcsMultipleChoiceOption             [DarcsArgOption [] ["to-match"] uptop "PATTERN"              "select changes up to a patch matching PATTERN",              DarcsArgOption [] ["to-patch"] UpToPatch "REGEXP"@@ -643,7 +662,7 @@              DarcsArgOption [] ["to-tag"] UpToTag "REGEXP"              "select changes up to a tag matching REGEXP"]     where uptop s = UpToPattern (patch_match s)-match_from = DarcsMultipleChoiceOption+matchFrom = DarcsMultipleChoiceOption               [DarcsArgOption [] ["from-match"] fromp "PATTERN"                "select changes starting with a patch matching PATTERN",                DarcsArgOption [] ["from-patch"] AfterPatch "REGEXP"@@ -673,7 +692,7 @@  __last = DarcsArgOption [] ["last"] lastn "NUMBER"          "select the last NUMBER patches"-    where lastn = LastN . number_string+    where lastn = LastN . numberString  __index = DarcsArgOption ['n'] ["index"] indexrange "N" "select one patch"     where indexrange s = if all isDigit s@@ -690,17 +709,17 @@                          else PatchIndexRange 0 0           isokay c = isDigit c || c == '-' -match_maxcount :: DarcsOption-match_maxcount = DarcsArgOption [] ["max-count"] mc "NUMBER"+matchMaxcount :: DarcsOption+matchMaxcount = DarcsArgOption [] ["max-count"] mc "NUMBER"          "return only NUMBER results"-    where mc = MaxCount . number_string+    where mc = MaxCount . numberString  --- | 'get_context' takes a list of flags and returns the context+-- | 'getContext' takes a list of flags and returns the context -- specified by @Context c@ in that list of flags, if any. -- This flag is present if darcs was invoked with @--context=FILE@-get_context :: [DarcsFlag] -> Maybe AbsolutePath-get_context xs = listToMaybe [ c | Context c <- xs ]+getContext :: [DarcsFlag] -> Maybe AbsolutePath+getContext xs = listToMaybe [ c | Context c <- xs ]  notest = DarcsMultipleChoiceOption          [DarcsNoArgOption [] ["no-test"] NoTest "don't run the test script",@@ -708,7 +727,7 @@ test = DarcsMultipleChoiceOption           [DarcsNoArgOption [] ["test"] Test "run the test script",            DarcsNoArgOption [] ["no-test"] NoTest "don't run the test script"]-leave_test_dir = DarcsMultipleChoiceOption+leaveTestDir = DarcsMultipleChoiceOption                  [DarcsNoArgOption [] ["leave-test-directory"]                   LeaveTestDir "don't remove the test directory",                   DarcsNoArgOption [] ["remove-test-directory"]@@ -719,7 +738,7 @@ \end{code}  \begin{options}---ignore-times+--ignore-times, --no-ignore-times \end{options} Darcs optimizes its operations by keeping track of the modification times of your files.  This dramatically speeds up commands such as@@ -732,16 +751,22 @@ \verb!--ignore-times! option, which instructs darcs not to trust the file modification times, but instead to check each file's contents explicitly. \begin{code}-ignoretimes = DarcsNoArgOption [] ["ignore-times"] IgnoreTimes-              "don't trust the file modification times"+ignoretimes = +    DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["ignore-times"] IgnoreTimes+                         "don't trust the file modification times"+    ,DarcsNoArgOption [] ["no-ignore-times"] DontIgnoreTimes+                      "trust modification times to find modified files [DEFAULT]"+    ]+ lookforadds =     DarcsMultipleChoiceOption     [DarcsNoArgOption ['l'] ["look-for-adds"] LookForAdds      "look for (non-boring) files that could be added",-     DarcsNoArgOption [] ["dont-look-for-adds"] NoLookForAdds+     DarcsNoArgOption [] ["dont-look-for-adds","no-look-for-adds"] NoLookForAdds      "don't look for any files that could be added [DEFAULT]"] -fancy_move_add =+fancyMoveAdd =     DarcsMultipleChoiceOption     [DarcsNoArgOption [] ["date-trick"] FancyMoveAdd      "add files with date appended to avoid conflict [EXPERIMENTAL] ",@@ -755,7 +780,7 @@      DarcsNoArgOption [] ["no-ask-deps"] NoAskDeps      "don't ask for extra dependencies"] -ask_long_comment =+askLongComment =     DarcsMultipleChoiceOption     [DarcsNoArgOption [] ["edit-long-comment"] EditLongComment      "edit the long comment by default",@@ -768,45 +793,45 @@ \begin{options} --author \end{options}-\label{env:DARCS_EMAIL}-Several commands need to be able to identify you.  Conventionally, you-provide an email address for this purpose, which can include comments,-e.g.\ \verb!David Roundy <droundy@abridgegame.org>!.  The easiest way to do-this is-to define an environment variable \verb!EMAIL! or \verb!DARCS_EMAIL! (with-the latter overriding the former).  You can also override this using the-\verb!--author! flag to any command.  Alternatively, you could set your-email address on a per-repository basis using the ``defaults'' mechanism-for ``ALL'' commands, as described in Appendix~\ref{repository_format}.-Or, you could specify the author on a per-repository basis using the-\verb!_darcs/prefs/author! file as described in section~\ref{author_prefs}.--Also, a global author file can be created in your home directory with the name-\verb!.darcs/author!, on MS Windows~\ref{ms_win}.  This file overrides the-contents of the environment variables, but a repository-specific author-file overrides the global author file.+\darcsEnv{DARCS_EMAIL}  \begin{code} logfile = DarcsAbsPathOption [] ["logfile"] LogFile "FILE"           "give patch name and comment in file" -rmlogfile = DarcsNoArgOption [] ["delete-logfile"] RmLogFile-            "delete the logfile when done"+rmlogfile = DarcsMultipleChoiceOption+            [DarcsNoArgOption [] ["delete-logfile"] RmLogFile+            "delete the logfile when done",+             DarcsNoArgOption [] ["no-delete-logfile"] DontRmLogFile+            "keep the logfile when done [DEFAULT]"]  author = DarcsArgOption ['A'] ["author"] Author "EMAIL" "specify author id"-from_opt = DarcsArgOption [] ["from"] Author "EMAIL" "specify email address"+fromOpt = DarcsArgOption [] ["from"] Author "EMAIL" "specify email address" --- | 'get_author' takes a list of flags and returns the author of the+fileHelpAuthor :: [String]+fileHelpAuthor = [+ "Each patch is attributed to its author, usually by email address (for",+ "example, `Fred Bloggs <fred@example.net>').  Darcs looks in several",+ "places for this author string: the --author option, the files",+ "_darcs/prefs/author (in the repository) and ~/.darcs/author (in your",+ "home directory), and the environment variables $DARCS_EMAIL and",+ "$EMAIL.  If none of those exist, Darcs will prompt you for an author",+ "string and write it to _darcs/prefs/author."]++environmentHelpEmail :: ([String], [String])+environmentHelpEmail = (["DARCS_EMAIL","EMAIL"], fileHelpAuthor)++-- | 'getAuthor' takes a list of flags and returns the author of the -- change specified by @Author \"Leo Tolstoy\"@ in that list of flags, if any. -- Otherwise, if @Pipe@ is present, asks the user who is the author and -- returns the answer. If neither are present, try to guess the author, -- from @_darcs/prefs@, and if it's not possible, ask the user.-get_author :: [DarcsFlag] -> IO String-get_author (Author a:_) = return a-get_author (Pipe:_) = do askUser "Who is the author? "-get_author (_:flags) = get_author flags-get_author [] = do-  easy_author <- get_easy_author+getAuthor :: [DarcsFlag] -> IO String+getAuthor (Author a:_) = return a+getAuthor (Pipe:_) = do askUser "Who is the author? "+getAuthor (_:flags) = getAuthor flags+getAuthor [] = do+  easy_author <- getEasyAuthor   case easy_author of     Just a -> return a     Nothing -> do@@ -822,16 +847,17 @@             text "If you move that file to ~/.darcs/author, it will be used for patches" $$             text "you record in ALL repositories."           add <- askUser "What is your email address? "-          writeFile (darcsdir++"/prefs/author") add+          writeFile (darcsdir ++ "/prefs/author") $+                    unlines ["# " ++ line | line <- fileHelpAuthor] ++ "\n" ++ add           return add         else askUser "What is your email address (e.g. Fred Bloggs <fred@example.net>)? " --- | 'get_easy_author' tries to get the author name first from the repository preferences,+-- | 'getEasyAuthor' tries to get the author name first from the repository preferences, -- then from global preferences, then from environment variables. Returns 'Nothing' if it -- could not get it.-get_easy_author :: IO (Maybe String)-get_easy_author = firstJustIO [ firstNotBlank `fmap` get_preflist "author",-                                firstNotBlank `fmap` get_global "author",+getEasyAuthor :: IO (Maybe String)+getEasyAuthor = firstJustIO [ firstNotBlank `fmap` getPreflist "author",+                                firstNotBlank `fmap` getGlobal "author",                                 maybeGetEnv "DARCS_EMAIL",                                 maybeGetEnv "EMAIL" ] \end{code}@@ -845,13 +871,13 @@ file.  \begin{code}-nocompress = concat_options [__compress, __dont_compress]-uncompress_nocompress = concat_options [__compress, __dont_compress, __uncompress]+nocompress = concatOptions [__compress, __dontCompress]+uncompressNocompress = concatOptions [__compress, __dontCompress, __uncompress] -__compress, __dont_compress, __uncompress :: DarcsOption+__compress, __dontCompress, __uncompress :: DarcsOption __compress = DarcsNoArgOption [] ["compress"] Compress             "create compressed patches"-__dont_compress = DarcsNoArgOption [] ["dont-compress"] NoCompress+__dontCompress = DarcsNoArgOption [] ["dont-compress","no-compress"] NoCompress                   "don't create compressed patches" __uncompress = DarcsNoArgOption [] ["uncompress"] UnCompress                "uncompress patches"@@ -859,24 +885,37 @@ summary = DarcsMultipleChoiceOption           [DarcsNoArgOption ['s'] ["summary"] Summary "summarize changes",            DarcsNoArgOption [] ["no-summary"] NoSummary "don't summarize changes"]-unified = DarcsNoArgOption ['u'] ["unified"] Unified-          "output patch in a darcs-specific format similar to diff -u"-unidiff = DarcsNoArgOption ['u'] ["unified"] Unified-          "pass -u option to diff"-diff_cmd_flag = DarcsArgOption [] ["diff-command"]+unified = DarcsMultipleChoiceOption+          [DarcsNoArgOption ['u'] ["unified"] Unified+          "output patch in a darcs-specific format similar to diff -u",+           DarcsNoArgOption  [] ["no-unified"] NonUnified+          "output patch in darcs' usual format"]++unidiff = DarcsMultipleChoiceOption+          [DarcsNoArgOption ['u'] ["unified"] Unified+          "pass -u option to diff",+           DarcsNoArgOption  [] ["no-unified"] NonUnified+          "output patch in diff's dumb format"]++diffCmdFlag = DarcsArgOption [] ["diff-command"]        DiffCmd "COMMAND" "specify diff command (ignores --diff-opts)"-store_in_memory = DarcsNoArgOption [] ["store-in-memory"] StoreInMemory-          "do patch application in memory rather than on disk" +storeInMemory = DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["store-in-memory"] StoreInMemory+     "do patch application in memory rather than on disk",+     DarcsNoArgOption [] ["no-store-in-memory"] ApplyOnDisk+     "do patch application on disk [DEFAULT]"]+ target = DarcsArgOption [] ["to"] Target "EMAIL" "specify destination email"-cc = DarcsArgOption [] ["cc"] Cc "EMAIL" "mail results to additional EMAIL(s). Requires --reply"+ccSend = DarcsArgOption [] ["cc"] Cc "EMAIL" "mail results to additional EMAIL(s)"+ccApply = DarcsArgOption [] ["cc"] Cc "EMAIL" "mail results to additional EMAIL(s). Requires --reply" --- |'get_cc' takes a list of flags and returns the addresses to send a copy of+-- |'getCc' takes a list of flags and returns the addresses to send a copy of -- the patch bundle to when using @darcs send@. -- looks for a cc address specified by @Cc \"address\"@ in that list of flags. -- Returns the addresses as a comma separated string.-get_cc :: [DarcsFlag] -> String-get_cc fs = lt $ catMaybes $ map whatcc fs+getCc :: [DarcsFlag] -> String+getCc fs = lt $ catMaybes $ map whatcc fs             where whatcc (Cc t) = Just t                   whatcc _ = Nothing                   lt [t] = t@@ -886,44 +925,44 @@  subject = DarcsArgOption [] ["subject"] Subject "SUBJECT" "specify mail subject" --- |'get_subject' takes a list of flags and returns the subject of the mail+-- |'getSubject' takes a list of flags and returns the subject of the mail -- to be sent by @darcs send@. Looks for a subject specified by -- @Subject \"subject\"@ in that list of flags, if any. -- This flag is present if darcs was invoked with @--subject=SUBJECT@-get_subject :: [DarcsFlag] -> Maybe String-get_subject (Subject s:_) = Just s-get_subject (_:fs) = get_subject fs-get_subject [] = Nothing+getSubject :: [DarcsFlag] -> Maybe String+getSubject (Subject s:_) = Just s+getSubject (_:fs) = getSubject fs+getSubject [] = Nothing -in_reply_to = DarcsArgOption [] ["in-reply-to"] InReplyTo "EMAIL" "specify in-reply-to header"-get_in_reply_to :: [DarcsFlag] -> Maybe String-get_in_reply_to (InReplyTo s:_) = Just s-get_in_reply_to (_:fs) = get_in_reply_to fs-get_in_reply_to [] = Nothing+inReplyTo = DarcsArgOption [] ["in-reply-to"] InReplyTo "EMAIL" "specify in-reply-to header"+getInReplyTo :: [DarcsFlag] -> Maybe String+getInReplyTo (InReplyTo s:_) = Just s+getInReplyTo (_:fs) = getInReplyTo fs+getInReplyTo [] = Nothing  output = DarcsAbsPathOrStdOption ['o'] ["output"] Output "FILE"          "specify output filename" -output_auto_name = DarcsOptAbsPathOption ['O'] ["output-auto-name"] "." OutputAutoName "DIRECTORY"+outputAutoName = DarcsOptAbsPathOption ['O'] ["output-auto-name"] "." OutputAutoName "DIRECTORY"                    "output to automatically named file in DIRECTORY, default: current directory" -edit_description =+editDescription =     DarcsMultipleChoiceOption     [DarcsNoArgOption [] ["edit-description"] EditDescription                           "edit the patch bundle description",-     DarcsNoArgOption [] ["dont-edit-description"] NoEditDescription+     DarcsNoArgOption [] ["dont-edit-description","no-edit-description"] NoEditDescription                       "don't edit the patch bundle description"] -distname_option = DarcsArgOption ['d'] ["dist-name"] DistName "DISTNAME"+distnameOption = DarcsArgOption ['d'] ["dist-name"] DistName "DISTNAME"                   "name of version"  recursive h     = DarcsMultipleChoiceOption       [DarcsNoArgOption ['r'] ["recursive"] Recursive h,-       DarcsNoArgOption [] ["not-recursive"] NoRecursive ("don't "++h)]+       DarcsNoArgOption [] ["not-recursive","no-recursive"] NoRecursive ("don't "++h)] -inventory_choices :: DarcsOption-inventory_choices =+inventoryChoices :: DarcsOption+inventoryChoices =     DarcsMultipleChoiceOption     [DarcsNoArgOption [] ["hashed"] UseHashedInventory                           "Some new features. Compatible with older repos",@@ -932,14 +971,19 @@      DarcsNoArgOption [] ["old-fashioned-inventory"] UseOldFashionedInventory                           "Minimal features. What older repos use."] -get_inventory_choices :: DarcsOption-get_inventory_choices =+getInventoryChoices :: DarcsOption+getInventoryChoices =     DarcsMultipleChoiceOption     [DarcsNoArgOption [] ["hashed"] UseHashedInventory                           "Convert darcs-1 format to hashed format",      DarcsNoArgOption [] ["old-fashioned-inventory"] UseOldFashionedInventory                           "Convert from hashed to darcs-1 format"] +upgradeFormat :: DarcsOption+upgradeFormat =+    DarcsNoArgOption [] ["upgrade"] UpgradeFormat+         "upgrade repository to latest compatible format"+ xmloutput = DarcsNoArgOption [] ["xml-output"] XMLOutput         "generate XML formatted output" @@ -953,16 +997,21 @@         "sign the patch with a given keyid",         DarcsArgOption [] ["sign-ssl"] SignSSL "IDFILE"         "sign the patch using openssl with a given private key",-        DarcsNoArgOption [] ["dont-sign"] NoSign+        DarcsNoArgOption [] ["dont-sign","no-sign"] NoSign         "don't sign the patch"] applyas = DarcsMultipleChoiceOption            [DarcsArgOption [] ["apply-as"] ApplyAs "USERNAME"             "apply patch as another user using sudo",-            DarcsNoArgOption [] ["apply-as-myself"] NonApply+            DarcsNoArgOption [] ["no-apply-as"] NonApply             "don't use sudo to apply as another user [DEFAULT]"]-happy_forwarding = DarcsNoArgOption [] ["happy-forwarding"] HappyForwarding-                   "forward unsigned messages without extra header"-set_default = DarcsMultipleChoiceOption++happyForwarding = DarcsMultipleChoiceOption+                   [DarcsNoArgOption [] ["happy-forwarding"] HappyForwarding+                   "forward unsigned messages without extra header",+                    DarcsNoArgOption [] ["no-happy-forwarding"] NoHappyForwarding+                   "don't forward unsigned messages without extra header [DEFAULT]"]++setDefault = DarcsMultipleChoiceOption               [DarcsNoArgOption [] ["set-default"] SetDefault                "set default repository [DEFAULT]",                DarcsNoArgOption [] ["no-set-default"] NoSetDefault@@ -979,22 +1028,18 @@ reponame = DarcsArgOption [] ["repo-name","repodir"] NewRepo "DIRECTORY"            "path of output directory" --repodir is there for compatibility                                       --should be removed eventually-tagname = DarcsArgOption ['t'] ["tag"] TagName "TAGNAME"-          "name of version to checkpoint"-deps_sel = DarcsMultipleChoiceOption+depsSel = DarcsMultipleChoiceOption        [DarcsNoArgOption [] ["no-deps"] DontGrabDeps         "don't automatically fulfill dependencies",         DarcsNoArgOption [] ["dont-prompt-for-dependencies"] DontPromptForDependencies         "don't ask about patches that are depended on by matched patches (with --match or --patch)",         DarcsNoArgOption [] ["prompt-for-dependencies"] PromptForDependencies         "prompt about patches that are depended on by matched patches [DEFAULT]"]-checkpoint = DarcsNoArgOption [] ["checkpoint"] CheckPoint-             "create a checkpoint file (see get --partial)" tokens = DarcsArgOption [] ["token-chars"] Toks "\"[CHARS]\""          "define token to contain these characters" -partial       = concat_options [__partial, __lazy, __ephemeral, __complete]-partial_check = concat_options [__complete, __partial]+partial       = concatOptions [__partial, __lazy, __ephemeral, __complete]+partialCheck = concatOptions [__complete, __partial]  __partial, __lazy, __ephemeral, __complete :: DarcsOption __partial = DarcsNoArgOption [] ["partial"] Partial@@ -1006,14 +1051,14 @@ __complete = DarcsNoArgOption [] ["complete"] Complete              "get a complete copy of the repository" -force_replace = DarcsMultipleChoiceOption+forceReplace = DarcsMultipleChoiceOption                 [DarcsNoArgOption ['f'] ["force"] ForceReplace                  "proceed with replace even if 'new' token already exists",                  DarcsNoArgOption [] ["no-force"]                  NonForce "don't force the replace if it looks scary"]  reply = DarcsArgOption [] ["reply"] Reply "FROM" "reply to email-based patch using FROM address"-apply_conflict_options+applyConflictOptions     = DarcsMultipleChoiceOption       [DarcsNoArgOption [] ["mark-conflicts"]        MarkConflicts "mark conflicts",@@ -1021,17 +1066,23 @@        AllowConflicts "allow conflicts, but don't mark them",        DarcsNoArgOption [] ["no-resolve-conflicts"] NoAllowConflicts        "equivalent to --dont-allow-conflicts, for backwards compatibility",-       DarcsNoArgOption [] ["dont-allow-conflicts"]-       NoAllowConflicts "fail on patches that create conflicts [DEFAULT]"]-pull_conflict_options+       DarcsNoArgOption [] ["dont-allow-conflicts","no-allow-conflicts"]+       NoAllowConflicts "fail if there are patches that would create conflicts [DEFAULT]",+       DarcsNoArgOption [] ["skip-conflicts"]+       SkipConflicts "filter out any patches that would create conflicts"+      ]+pullConflictOptions     = DarcsMultipleChoiceOption       [DarcsNoArgOption [] ["mark-conflicts"]        MarkConflicts "mark conflicts [DEFAULT]",        DarcsNoArgOption [] ["allow-conflicts"]        AllowConflicts "allow conflicts, but don't mark them",-       DarcsNoArgOption [] ["dont-allow-conflicts"]-       NoAllowConflicts "fail on patches that create conflicts"]-use_external_merge = DarcsArgOption [] ["external-merge"]+       DarcsNoArgOption [] ["dont-allow-conflicts","no-allow-conflicts"]+       NoAllowConflicts "fail if there patches that would create conflicts",+       DarcsNoArgOption [] ["skip-conflicts"]+       SkipConflicts "filter out any patches that would create conflicts"+      ]+useExternalMerge = DarcsArgOption [] ["external-merge"]                      ExternalMerge "COMMAND" "use external tool to merge conflicts" \end{code} @@ -1079,15 +1130,15 @@ An exclamation mark appears next to any option that has a conflict.  \begin{code}--- NOTE: I'd rather work to have no uses of dry_run_noxml, so that any time+-- NOTE: I'd rather work to have no uses of dryRunNoxml, so that any time -- --dry-run is a possibility, automated users can examine the results more -- easily with --xml.-dry_run_noxml :: DarcsOption-dry_run_noxml = DarcsNoArgOption [] ["dry-run"] DryRun+dryRunNoxml :: DarcsOption+dryRunNoxml = DarcsNoArgOption [] ["dry-run"] DryRun                 "don't actually take the action" -dry_run :: [DarcsOption]-dry_run = [dry_run_noxml, xmloutput]+dryRun :: [DarcsOption]+dryRun = [dryRunNoxml, xmloutput]  -- | @'showFriendly' flags patch@ returns a 'Doc' representing the right -- way to show @patch@ given the list @flags@ of flags darcs was invoked with.@@ -1096,14 +1147,14 @@                     | Summary `elem` opts = Darcs.Patch.summary p                     | otherwise           = description p --- | @'print_dry_run_message_and_exit' action opts patches@ prints a string+-- | @'printDryRunMessageAndExit' action opts patches@ prints a string -- representing the action that would be taken if the @--dry-run@ option -- had not been passed to darcs. Then darcs exits successfully. -- @action@ is the name of the action being taken, like @\"push\"@ -- @opts@ is the list of flags which were sent to darcs -- @patches@ is the sequence of patches which would be touched by @action@.-print_dry_run_message_and_exit :: RepoPatch p => String -> [DarcsFlag] -> FL (PatchInfoAnd p) C(x y) -> IO ()-print_dry_run_message_and_exit action opts patches =+printDryRunMessageAndExit :: RepoPatch p => String -> [DarcsFlag] -> FL (PatchInfoAnd p) C(x y) -> IO ()+printDryRunMessageAndExit action opts patches =      do when (DryRun `elem` opts) $ do           putInfo $ text $ "Would " ++ action ++ " the following changes:"           putDocLn $ put_mode@@ -1125,7 +1176,7 @@                         xml_with_summary hp                | Just p <- hopefullyM hp = insert_before_lastline-                                            (to_xml $ info hp) (indent $ xml_summary p)+                                            (to_xml $ info hp) (indent $ xmlSummary p)            xml_with_summary hp = to_xml (info hp)            indent = prefix "    " @@ -1135,33 +1186,48 @@ \input{Darcs/Resolution.lhs}  \begin{code}-noskip_boring = DarcsNoArgOption [] ["boring"]-                Boring "don't skip boring files"-allow_problematic_filenames = DarcsMultipleChoiceOption+noskipBoring = DarcsMultipleChoiceOption+                [DarcsNoArgOption [] ["boring"]+                 Boring "don't skip boring files",+                 DarcsNoArgOption [] ["no-boring"]+                 SkipBoring "skip borign files [DEFAULT]"]++allowProblematicFilenames = DarcsMultipleChoiceOption                 [DarcsNoArgOption [] ["case-ok"] AllowCaseOnly                  "don't refuse to add files differing only in case"+                ,DarcsNoArgOption [] ["no-case-ok"] DontAllowCaseOnly+                 "refuse to add files whose name differ only in case [DEFAULT]"                 ,DarcsNoArgOption [] ["reserved-ok"] AllowWindowsReserved                  "don't refuse to add files with Windows-reserved names"-                ]+                ,DarcsNoArgOption [] ["no-reserved-ok"] DontAllowWindowsReserved+                 "refuse to add files with Windows-reserved names [DEFAULT]"]+ diffflags = DarcsArgOption [] ["diff-opts"]             DiffFlags "OPTIONS" "options to pass to diff" -changes_format = DarcsMultipleChoiceOption+changesFormat = DarcsMultipleChoiceOption                  [DarcsNoArgOption [] ["context"]                   (Context rootDirectory) "give output suitable for get --context",                   xmloutput,-                  human_readable,+                  humanReadable,                   DarcsNoArgOption [] ["number"] NumberPatches "number the changes",                   DarcsNoArgOption [] ["count"] Count "output count of changes"                  ]-changes_reverse = DarcsNoArgOption [] ["reverse"] Reverse-                  "show changes in reverse order"+changesReverse = DarcsMultipleChoiceOption+                  [DarcsNoArgOption [] ["reverse"] Reverse+                   "show changes in reverse order"+                  ,DarcsNoArgOption [] ["no-reverse"] Forward+                   "show changes in the usual order [DEFAULT]"] -only_to_files :: DarcsOption-only_to_files = DarcsNoArgOption [] ["only-to-files"] OnlyChangesToFiles-                "show only changes to specified files"+onlyToFiles :: DarcsOption+onlyToFiles = DarcsMultipleChoiceOption+    [DarcsNoArgOption [] ["only-to-files"] OnlyChangesToFiles+     "show only changes to specified files",+     DarcsNoArgOption [] ["no-only-to-files"] ChangesToAllFiles+     "show changes to all files [DEFAULT]"] -human_readable = DarcsNoArgOption [] ["human-readable"]++humanReadable = DarcsNoArgOption [] ["human-readable"]                  HumanReadable "give human-readable output" pipe = DarcsNoArgOption [] ["pipe"] Pipe "ask user interactively for the patch metadata" @@ -1170,15 +1236,15 @@                          "prompt user interactively" all_patches = DarcsNoArgOption ['a'] ["all"] All "answer yes to all patches" -all_interactive = DarcsMultipleChoiceOption [all_patches, interactive]+allInteractive = DarcsMultipleChoiceOption [all_patches, interactive] -all_pipe_interactive+allPipeInteractive     = DarcsMultipleChoiceOption [all_patches,pipe,interactive] -pipe_interactive =+pipeInteractive =     DarcsMultipleChoiceOption [pipe, interactive] -repo_combinator =+repoCombinator =     DarcsMultipleChoiceOption     [DarcsNoArgOption [] ["intersection"] Intersection      "take intersection of all repositories",@@ -1187,80 +1253,76 @@      DarcsNoArgOption [] ["complement"] Complement      "take complement of repositories (in order listed)"] --- | 'list_files' returns the list of all non-boring files in the repository-list_files :: IO [String]-list_files = do s <- slurp_all_but_darcs "."-                skip_boring <- boring_file_filter-                return (map drop_dotslash $ skip_boring $ list_slurpy s)--drop_dotslash :: String -> String-drop_dotslash ('.':'/':x) = drop_dotslash x-drop_dotslash x = x+-- | Get a list of all non-boring files and directories in the working copy.+listFiles :: IO [String]+listFiles =  do nonboring <- restrictBoring emptyTree+                working <- expand =<< nonboring <$> readPlainTree "."+                return $ map (anchorPath "" . fst) $ list working --- | 'list_unregistered_files' returns the list of all non-boring unregistered+-- | 'listUnregisteredFiles' returns the list of all non-boring unregistered -- files in the repository.-list_unregistered_files :: IO [String]-list_unregistered_files = withRepository [] $- \repository ->-    do s <- slurp_all_but_darcs "."-       skip_boring <- boring_file_filter-       regs <- slurp_pending repository-       return $ map drop_dotslash $ (skip_boring $ list_slurpy s) \\ (list_slurpy regs)+listUnregisteredFiles :: IO [String]+listUnregisteredFiles =+    do unregd <- listFiles+       regd <- listRegisteredFiles+       return $ unregd \\ regd -- (inefficient) --- | 'list_registered_files' returns the list of all registered files in the repository.-list_registered_files :: IO [String]-list_registered_files =-    (map drop_dotslash . list_slurpy) `fmap` (withRepository [] slurp_pending)+-- | 'listRegisteredFiles' returns the list of all registered files in the repository.+listRegisteredFiles :: IO [String]+listRegisteredFiles =+    do recorded <- expand =<< withRepository [] readRecordedAndPending+       return $ map (anchorPath "" . fst) $ list recorded -options_latex :: [DarcsOption] -> String-options_latex opts = "\\begin{tabular}{lll}\n"++-                     unlines (map option_latex opts)+++optionsLatex :: [DarcsOption] -> String+optionsLatex opts = "\\begin{tabular}{lll}\n"+++                     unlines (map optionLatex opts)++                      "\\end{tabular}\n" -latex_help :: String -> String-latex_help h+latexHelp :: String -> String+latexHelp h     = "\\begin{minipage}{7cm}\n\\raggedright\n" ++ h ++ "\\end{minipage}\n" -option_latex :: DarcsOption -> String-option_latex (DarcsNoArgOption a b _ h) =-    show_short_options a ++ show_long_options b ++ latex_help h ++ "\\\\"-option_latex (DarcsArgOption a b _ arg h) =-    show_short_options a ++-    show_long_options (map (++(" "++arg)) b) ++ latex_help h ++ "\\\\"-option_latex (DarcsAbsPathOrStdOption a b _ arg h) =-    show_short_options a ++-    show_long_options (map (++(" "++arg)) b) ++ latex_help h ++ "\\\\"-option_latex (DarcsAbsPathOption a b _ arg h) =-    show_short_options a ++-    show_long_options (map (++(" "++arg)) b) ++ latex_help h ++ "\\\\"-option_latex (DarcsOptAbsPathOption a b _ _ arg h) =-    show_short_options a ++-    show_long_options (map (++("[="++arg++"]")) b) ++ latex_help h ++ "\\\\"-option_latex (DarcsMultipleChoiceOption os) =-    unlines (map option_latex os)+optionLatex :: DarcsOption -> String+optionLatex (DarcsNoArgOption a b _ h) =+    showShortOptions a ++ showLongOptions b ++ latexHelp h ++ "\\\\"+optionLatex (DarcsArgOption a b _ arg h) =+    showShortOptions a +++    showLongOptions (map (++(" "++arg)) b) ++ latexHelp h ++ "\\\\"+optionLatex (DarcsAbsPathOrStdOption a b _ arg h) =+    showShortOptions a +++    showLongOptions (map (++(" "++arg)) b) ++ latexHelp h ++ "\\\\"+optionLatex (DarcsAbsPathOption a b _ arg h) =+    showShortOptions a +++    showLongOptions (map (++(" "++arg)) b) ++ latexHelp h ++ "\\\\"+optionLatex (DarcsOptAbsPathOption a b _ _ arg h) =+    showShortOptions a +++    showLongOptions (map (++("[="++arg++"]")) b) ++ latexHelp h ++ "\\\\"+optionLatex (DarcsMultipleChoiceOption os) =+    unlines (map optionLatex os) -show_short_options :: [Char] -> String-show_short_options [] = "&"-show_short_options [c] = "\\verb!-"++[c]++"! &"-show_short_options (c:cs) = "\\verb!-"++[c]++"!,"++show_short_options cs+showShortOptions :: [Char] -> String+showShortOptions [] = "&"+showShortOptions [c] = "\\verb!-"++[c]++"! &"+showShortOptions (c:cs) = "\\verb!-"++[c]++"!,"++showShortOptions cs -show_long_options :: [String] -> String-show_long_options [] = " &"-show_long_options [s] = "\\verb!--" ++ s ++ "! &"-show_long_options (s:ss)-    = "\\verb!--" ++ s ++ "!,"++ show_long_options ss+showLongOptions :: [String] -> String+showLongOptions [] = " &"+showLongOptions [s] = "\\verb!--" ++ s ++ "! &"+showLongOptions (s:ss)+    = "\\verb!--" ++ s ++ "!,"++ showLongOptions ss -set_scripts_executable :: DarcsOption-set_scripts_executable = DarcsMultipleChoiceOption+setScriptsExecutableOption :: DarcsOption+setScriptsExecutableOption = DarcsMultipleChoiceOption                               [DarcsNoArgOption [] ["set-scripts-executable"] SetScriptsExecutable                                "make scripts executable",-                               DarcsNoArgOption [] ["dont-set-scripts-executable"] DontSetScriptsExecutable+                               DarcsNoArgOption [] ["dont-set-scripts-executable","no-set-scripts-executable"] DontSetScriptsExecutable                                "don't make scripts executable"] -relink, relink_pristine, sibling :: DarcsOption+relink, relinkPristine, sibling :: DarcsOption relink = DarcsNoArgOption [] ["relink"] Relink          "relink random internal data to a sibling" -relink_pristine = DarcsNoArgOption [] ["relink-pristine"] RelinkPristine+relinkPristine = DarcsNoArgOption [] ["relink-pristine"] RelinkPristine                   "relink pristine tree (not recommended)"  sibling = DarcsAbsPathOption [] ["sibling"] Sibling "URL"@@ -1276,8 +1338,8 @@ nolinks = DarcsNoArgOption [] ["nolinks"] NoLinks           "do not link repository or pristine to sibling" -reorder_patches :: DarcsOption-reorder_patches = DarcsNoArgOption [] ["reorder-patches"] Reorder+reorderPatches :: DarcsOption+reorderPatches = DarcsNoArgOption [] ["reorder-patches"] Reorder                   "reorder the patches in the repository" \end{code} \begin{options}@@ -1286,7 +1348,7 @@ \darcsEnv{SENDMAIL}  \begin{code}-sendmail_cmd = DarcsArgOption [] ["sendmail-command"] SendmailCmd "COMMAND" "specify sendmail command"+sendmailCmd = DarcsArgOption [] ["sendmail-command"] SendmailCmd "COMMAND" "specify sendmail command"  environmentHelpSendmail :: ([String], [String]) environmentHelpSendmail = (["SENDMAIL"], [@@ -1303,15 +1365,15 @@ -- * on a multi-user system without an MTA and on which you haven't --   got root, can be msmtp. --- |'get_sendmail_cmd' takes a list of flags and returns the sendmail command+-- |'getSendmailCmd' takes a list of flags and returns the sendmail command -- to be used by @darcs send@. Looks for a command specified by -- @SendmailCmd \"command\"@ in that list of flags, if any. -- This flag is present if darcs was invoked with @--sendmail-command=COMMAND@ -- Alternatively the user can set @$S@@ENDMAIL@ which will be used as a fallback if present.-get_sendmail_cmd :: [DarcsFlag] -> IO String -get_sendmail_cmd (SendmailCmd a:_) = return a-get_sendmail_cmd (_:flags) = get_sendmail_cmd flags-get_sendmail_cmd [] = do easy_sendmail <- firstJustIO [ maybeGetEnv "SENDMAIL" ]+getSendmailCmd :: [DarcsFlag] -> IO String +getSendmailCmd (SendmailCmd a:_) = return a+getSendmailCmd (_:flags) = getSendmailCmd flags+getSendmailCmd [] =   do easy_sendmail <- firstJustIO [ maybeGetEnv "SENDMAIL" ]                          case easy_sendmail of                             Just a -> return a                             Nothing -> return ""@@ -1341,6 +1403,9 @@ nullFlag = DarcsNoArgOption ['0'] ["null"] NullFlag        "separate file names by NUL characters" \end{code}++\subsection{Posthooks}+ \begin{options} --posthook=COMMAND, --no-posthook \end{options}@@ -1382,7 +1447,7 @@                                                  vcat (mapFL (to_xml . info) ps) $$                                                  text "</patches>")                       finishedOneIO k "DARCS_FILES"-                      setEnvCautiously "DARCS_FILES" (unlines$ list_touched_files ps)+                      setEnvCautiously "DARCS_FILES" (unlines$ listTouchedFiles ps)                       endTedious k  setEnvCautiously :: String -> String -> IO ()@@ -1398,32 +1463,35 @@  defineChanges :: Patchy p => p C(x y) -> IO () #ifndef WIN32-defineChanges ps = setEnvCautiously "DARCS_FILES" (unlines $ list_touched_files ps)+defineChanges ps = setEnvCautiously "DARCS_FILES" (unlines $ listTouchedFiles ps) #else defineChanges _ = return () #endif -posthook_cmd :: DarcsOption-posthook_cmd = DarcsMultipleChoiceOption+posthookCmd :: DarcsOption+posthookCmd = DarcsMultipleChoiceOption                [DarcsArgOption [] ["posthook"] PosthookCmd                 "COMMAND" "specify command to run after this darcs command",                 DarcsNoArgOption [] ["no-posthook"] NoPosthook                 "don't run posthook command"] -posthook_prompt :: DarcsOption-posthook_prompt = DarcsMultipleChoiceOption+posthookPrompt :: DarcsOption+posthookPrompt = DarcsMultipleChoiceOption                   [DarcsNoArgOption [] ["prompt-posthook"] AskPosthook                    "prompt before running posthook [DEFAULT]",                    DarcsNoArgOption [] ["run-posthook"] RunPosthook                    "run posthook command without prompting"] --- | 'get_posthook_cmd' takes a list of flags and returns the posthook command+-- | 'getPosthookCmd' takes a list of flags and returns the posthook command --  specified by @PosthookCmd a@ in that list of flags, if any.-get_posthook_cmd :: [DarcsFlag] -> Maybe String-get_posthook_cmd (PosthookCmd a:_) = Just a-get_posthook_cmd (_:flags) = get_posthook_cmd flags-get_posthook_cmd [] = Nothing+getPosthookCmd :: [DarcsFlag] -> Maybe String+getPosthookCmd (PosthookCmd a:_) = Just a+getPosthookCmd (_:flags) = getPosthookCmd flags+getPosthookCmd [] = Nothing \end{code}++\subsection{Prehooks}+ \begin{options} --prehook=COMMAND, --no-prehook \end{options}@@ -1438,26 +1506,26 @@ These options control prompting before running the prehook.  See the posthook documentation above for details. \begin{code}-prehook_cmd :: DarcsOption-prehook_cmd = DarcsMultipleChoiceOption+prehookCmd :: DarcsOption+prehookCmd = DarcsMultipleChoiceOption                [DarcsArgOption [] ["prehook"] PrehookCmd                 "COMMAND" "specify command to run before this darcs command",                 DarcsNoArgOption [] ["no-prehook"] NoPrehook                 "don't run prehook command"] -prehook_prompt :: DarcsOption-prehook_prompt = DarcsMultipleChoiceOption+prehookPrompt :: DarcsOption+prehookPrompt = DarcsMultipleChoiceOption                   [DarcsNoArgOption [] ["prompt-prehook"] AskPrehook                    "prompt before running prehook [DEFAULT]",                    DarcsNoArgOption [] ["run-prehook"] RunPrehook                    "run prehook command without prompting"] --- | 'get_prehook_cmd' takes a list of flags and returns the prehook command+-- | 'getPrehookCmd' takes a list of flags and returns the prehook command --  specified by @PrehookCmd a@ in that list of flags, if any.-get_prehook_cmd :: [DarcsFlag] -> Maybe String-get_prehook_cmd (PrehookCmd a:_) = Just a-get_prehook_cmd (_:flags) = get_prehook_cmd flags-get_prehook_cmd [] = Nothing+getPrehookCmd :: [DarcsFlag] -> Maybe String+getPrehookCmd (PrehookCmd a:_) = Just a+getPrehookCmd (_:flags) = getPrehookCmd flags+getPrehookCmd [] = Nothing \end{code}  \begin{options}@@ -1486,8 +1554,8 @@  Do not use patch caches. \begin{code}-network_options :: [DarcsOption]-network_options =+networkOptions :: [DarcsOption]+networkOptions =     [DarcsMultipleChoiceOption      [DarcsNoArgOption [] ["ssh-cm"] SSHControlMaster                            "use SSH ControlMaster feature",@@ -1498,7 +1566,7 @@                            pipelining_description,       DarcsNoArgOption [] ["no-http-pipelining"] NoHTTPPipelining                            no_pipelining_description],-      no_cache+      noCache, remote_darcs      ]     where pipelining_description =               "enable HTTP pipelining"++@@ -1507,9 +1575,17 @@               "disable HTTP pipelining"++               (if pipeliningEnabledByDefault then "" else " [DEFAULT]") -no_cache :: DarcsOption-no_cache = DarcsNoArgOption [] ["no-cache"] NoCache+remote_darcs :: DarcsOption+remote_darcs =  DarcsArgOption [] ["remote-darcs"] RemoteDarcs "COMMAND"+                "name of the darcs executable on the remote server"++noCache :: DarcsOption+noCache = DarcsNoArgOption [] ["no-cache"] NoCache                           "don't use patch caches"++optimizePristine :: DarcsOption+optimizePristine = DarcsNoArgOption [] ["pristine"] OptimizePristine+                          "optimize hashed pristine layout" \end{code} \begin{options} --umask@@ -1519,8 +1595,8 @@ writing to the repository.  \begin{code}-umask_option :: DarcsOption-umask_option =+umaskOption :: DarcsOption+umaskOption =     DarcsArgOption [] ["umask"] UMask "UMASK"         "specify umask to use when writing" \end{code}@@ -1545,11 +1621,11 @@ the command line, when pulling or applying unknown patches.  \begin{code}-restrict_paths =+restrictPaths =     DarcsMultipleChoiceOption     [DarcsNoArgOption [] ["restrict-paths"] RestrictPaths      "don't allow darcs to touch external files or repo metadata",-     DarcsNoArgOption [] ["dont-restrict-paths"] DontRestrictPaths+     DarcsNoArgOption [] ["dont-restrict-paths","no-restrict-paths"] DontRestrictPaths      "allow darcs to modify any file or directory (unsafe)"] \end{code} @@ -1560,13 +1636,13 @@ doing pull, push and send. This option makes darcs skip this check.  \begin{code}-allow_unrelated_repos =+allowUnrelatedRepos =     DarcsNoArgOption [] ["ignore-unrelated-repos"] AllowUnrelatedRepos                          "do not check if repositories are unrelated" \end{code}  \begin{code}-just_this_repo :: DarcsOption+justThisRepo :: DarcsOption \end{code}  \begin{options}@@ -1576,13 +1652,13 @@ omits any caches or other repos listed as a source of patches.  \begin{code}-just_this_repo =+justThisRepo =     DarcsNoArgOption [] ["just-this-repo"] JustThisRepo                         "Limit the check or repair to the current repo" \end{code}  \begin{code}-check, repair, check_or_repair :: DarcsOption+check, repair, checkOrRepair :: DarcsOption \end{code}  \begin{options}@@ -1606,30 +1682,31 @@     DarcsNoArgOption [] ["repair"] Repair                         "Specify repair mode" -check_or_repair = concat_options [check, repair]+checkOrRepair = concatOptions [check, repair] --- | @'patch_select_flag' f@ holds whenever @f@ is a way of selecting+-- | @'patchSelectFlag' f@ holds whenever @f@ is a way of selecting -- patches such as @PatchName n@.-patch_select_flag :: DarcsFlag -> Bool-patch_select_flag All = True-patch_select_flag (PatchName _) = True-patch_select_flag (OnePatch _) = True-patch_select_flag (SeveralPatch _) = True-patch_select_flag (AfterPatch _) = True-patch_select_flag (UpToPatch _) = True-patch_select_flag (TagName _) = True-patch_select_flag (LastN _) = True-patch_select_flag (OneTag _) = True-patch_select_flag (AfterTag _) = True-patch_select_flag (UpToTag _) = True-patch_select_flag (OnePattern _) = True-patch_select_flag (SeveralPattern _) = True-patch_select_flag (AfterPattern _) = True-patch_select_flag (UpToPattern _) = True-patch_select_flag _ = False+patchSelectFlag :: DarcsFlag -> Bool+patchSelectFlag All = True+patchSelectFlag (PatchName _) = True+patchSelectFlag (OnePatch _) = True+patchSelectFlag (SeveralPatch _) = True+patchSelectFlag (AfterPatch _) = True+patchSelectFlag (UpToPatch _) = True+patchSelectFlag (TagName _) = True+patchSelectFlag (LastN _) = True+patchSelectFlag (OneTag _) = True+patchSelectFlag (AfterTag _) = True+patchSelectFlag (UpToTag _) = True+patchSelectFlag (OnePattern _) = True+patchSelectFlag (SeveralPattern _) = True+patchSelectFlag (AfterPattern _) = True+patchSelectFlag (UpToPattern _) = True+patchSelectFlag _ = False  -- | The integer corresponding to a string, if it's only composed of digits. --   Otherwise, -1.-number_string :: String -> Int-number_string s = if and (map isDigit s) then read s else (-1)+numberString :: String -> Int+numberString "" = -1+numberString s = if all isDigit s then read s else (-1) \end{code}
src/Darcs/Commands.lhs view
@@ -16,39 +16,40 @@ %  Boston, MA 02110-1301, USA.  \begin{code}-module Darcs.Commands ( CommandControl( Command_data, Hidden_command, Group_name ),-                       DarcsCommand( DarcsCommand, command_name,-                                     command_help, command_description,-                                     command_basic_options, command_advanced_options,-                                     command_command,-                                     command_prereq,-                                     command_extra_arg_help,-                                     command_extra_args,-                                     command_argdefaults,-                                     command_get_arg_possibilities,+module Darcs.Commands ( CommandControl( CommandData, HiddenCommand, GroupName ),+                       DarcsCommand( DarcsCommand, commandName,+                                     commandHelp, commandDescription,+                                     commandBasicOptions, commandAdvancedOptions,+                                     commandCommand,+                                     commandPrereq,+                                     commandExtraArgHelp,+                                     commandExtraArgs,+                                     commandArgdefaults,+                                     commandGetArgPossibilities,                                      SuperCommand,-                                     command_sub_commands ),-                       command_alias, command_stub,-                       command_options, command_alloptions,-                       disambiguate_commands, CommandArgs(..),-                       get_command_help, get_command_mini_help,-                       get_subcommands,-                       usage, subusage, chomp_newline,-                       extract_commands,-                       super_name,+                                     commandSubCommands ),+                       commandAlias, commandStub,+                       commandOptions, commandAlloptions,+                       disambiguateCommands, CommandArgs(..),+                       getCommandHelp, getCommandMiniHelp,+                       getSubcommands,+                       usage, subusage, chompNewline,+                       extractCommands,+                       superName,                        nodefaults,-                       loggers,+                       putInfo, putVerbose, putWarning, abortRun                      ) where  import System.Console.GetOpt( OptDescr, usageInfo )+import Control.Monad (when, unless)  import Data.List ( sort, isPrefixOf )-import Darcs.Arguments ( DarcsFlag, DarcsOption, disable, help,-                         any_verbosity, posthook_cmd, posthook_prompt,-                         prehook_cmd, prehook_prompt, option_from_darcsoption )+import Darcs.Arguments ( DarcsFlag(Quiet,Verbose, DryRun), DarcsOption, disable, help,+                         anyVerbosity, posthookCmd, posthookPrompt,+                         prehookCmd, prehookPrompt, optionFromDarcsoption ) import Darcs.RepoPath ( AbsolutePath, rootDirectory )-import Darcs.Utils ( putStrLnError )-import Printer ( Doc, putDocLn )+import Printer ( Doc, putDocLn, hPutDocLn, text, (<+>), errorDoc )+import System.IO ( stderr ) \end{code}  The general format of a darcs command is@@ -114,78 +115,78 @@ \end{center}  \begin{code}-extract_commands, extract_hidden_commands :: [CommandControl] -> [DarcsCommand]-extract_commands cs = concatMap (\x -> case x of { Command_data cmd_d -> [cmd_d]; _ -> []}) cs-extract_hidden_commands cs = concatMap (\x -> case x of { Hidden_command cmd_d -> [cmd_d]; _ -> []}) cs+extractCommands, extractHiddenCommands :: [CommandControl] -> [DarcsCommand]+extractCommands cs = concatMap (\x -> case x of { CommandData cmd_d -> [cmd_d]; _ -> []}) cs+extractHiddenCommands cs = concatMap (\x -> case x of { HiddenCommand cmd_d -> [cmd_d]; _ -> []}) cs \end{code}  \input{Darcs/Arguments.lhs}  \begin{code}-data CommandControl = Command_data DarcsCommand-                    | Hidden_command DarcsCommand-                    | Group_name String+data CommandControl = CommandData DarcsCommand+                    | HiddenCommand DarcsCommand+                    | GroupName String  data DarcsCommand =-    DarcsCommand {command_name, command_help, command_description :: String,-                  command_extra_args :: Int,-                  command_extra_arg_help :: [String],-                  command_command :: [DarcsFlag] -> [String] -> IO (),-                  command_prereq :: [DarcsFlag] -> IO (Either String ()),-                  command_get_arg_possibilities :: IO [String],-                  command_argdefaults :: [DarcsFlag] -> AbsolutePath -> [String] -> IO [String],-                  command_basic_options :: [DarcsOption],-                  command_advanced_options :: [DarcsOption]}-  | SuperCommand {command_name, command_help, command_description :: String,-                  command_prereq :: [DarcsFlag] -> IO (Either String ()),-                  command_sub_commands :: [CommandControl]}+    DarcsCommand {commandName, commandHelp, commandDescription :: String,+                  commandExtraArgs :: Int,+                  commandExtraArgHelp :: [String],+                  commandCommand :: [DarcsFlag] -> [String] -> IO (),+                  commandPrereq :: [DarcsFlag] -> IO (Either String ()),+                  commandGetArgPossibilities :: IO [String],+                  commandArgdefaults :: [DarcsFlag] -> AbsolutePath -> [String] -> IO [String],+                  commandBasicOptions :: [DarcsOption],+                  commandAdvancedOptions :: [DarcsOption]}+  | SuperCommand {commandName, commandHelp, commandDescription :: String,+                  commandPrereq :: [DarcsFlag] -> IO (Either String ()),+                  commandSubCommands :: [CommandControl]} -command_alloptions :: DarcsCommand -> ([DarcsOption], [DarcsOption])-command_alloptions DarcsCommand { command_basic_options = opts1-                                , command_advanced_options = opts2 }+commandAlloptions :: DarcsCommand -> ([DarcsOption], [DarcsOption])+commandAlloptions DarcsCommand { commandBasicOptions = opts1+                                , commandAdvancedOptions = opts2 }     = (opts1 ++ [disable, help],-       any_verbosity ++ opts2 ++-                [posthook_cmd, posthook_prompt-                ,prehook_cmd, prehook_prompt])+       anyVerbosity ++ opts2 +++                [posthookCmd, posthookPrompt+                ,prehookCmd, prehookPrompt])  --  Supercommands cannot be disabled.-command_alloptions SuperCommand { } = ([help],[])+commandAlloptions SuperCommand { } = ([help],[])  --  Obtain options suitable as input to --  System.Console.Getopt, including the --disable option (which is --  not listed explicitly in the DarcsCommand definitions).-command_options :: AbsolutePath -> DarcsCommand -> ([OptDescr DarcsFlag], [OptDescr DarcsFlag])-command_options cwd c = (convert basic, convert advanced)- where (basic, advanced) = command_alloptions c-       convert = concatMap (option_from_darcsoption cwd)+commandOptions :: AbsolutePath -> DarcsCommand -> ([OptDescr DarcsFlag], [OptDescr DarcsFlag])+commandOptions cwd c = (convert basic, convert advanced)+ where (basic, advanced) = commandAlloptions c+       convert = concatMap (optionFromDarcsoption cwd)  nodefaults :: [DarcsFlag] -> AbsolutePath -> [String] -> IO [String] nodefaults _ _ xs = return xs -get_subcommands :: DarcsCommand -> [CommandControl]-get_subcommands c@(SuperCommand {}) = command_sub_commands c-get_subcommands _ = []+getSubcommands :: DarcsCommand -> [CommandControl]+getSubcommands c@(SuperCommand {}) = commandSubCommands c+getSubcommands _ = [] -command_alias :: String -> DarcsCommand -> DarcsCommand-command_alias n c =-  c { command_name = n-    , command_description = "Alias for `darcs " ++ command_name c ++ "'."-    , command_help = "The `darcs " ++ n ++ "' command is an alias for " ++-                     "`darcs " ++ command_name c ++ "'.\n" ++-                     command_help c+commandAlias :: String -> DarcsCommand -> DarcsCommand+commandAlias n c =+  c { commandName = n+    , commandDescription = "Alias for `darcs " ++ commandName c ++ "'."+    , commandHelp = "The `darcs " ++ n ++ "' command is an alias for " +++                     "`darcs " ++ commandName c ++ "'.\n" +++                     commandHelp c     } -command_stub :: String -> String -> String -> DarcsCommand -> DarcsCommand-command_stub n h d c =-  c { command_name = n-    , command_help = h-    , command_description = d-    , command_command = \_ _ -> putStr h+commandStub :: String -> String -> String -> DarcsCommand -> DarcsCommand+commandStub n h d c =+  c { commandName = n+    , commandHelp = h+    , commandDescription = d+    , commandCommand = \_ _ -> putStr h     }  usage :: [CommandControl] -> String usage cs = "Usage: darcs COMMAND ...\n\nCommands:\n" ++-           usage_helper cs ++ "\n" +++           usageHelper cs ++ "\n" ++            "Use 'darcs COMMAND --help' for help on a single command.\n" ++            "Use 'darcs --version' to see the darcs version number.\n" ++            "Use 'darcs --exact-version' to get the exact version of this darcs instance.\n" ++@@ -197,67 +198,67 @@ subusage :: DarcsCommand -> String subusage super =     (usageInfo-     ("Usage: darcs "++command_name super++" SUBCOMMAND ... " ++-      "\n\n"++ command_description super++-      "\n\nSubcommands:\n" ++ usage_helper (get_subcommands super) ++ "\nOptions:")-     (option_from_darcsoption rootDirectory help))-    ++ "\n" ++ command_help super+     ("Usage: darcs "++commandName super++" SUBCOMMAND ... " +++      "\n\n"++ commandDescription super+++      "\n\nSubcommands:\n" ++ usageHelper (getSubcommands super) ++ "\nOptions:")+     (optionFromDarcsoption rootDirectory help))+    ++ "\n" ++ commandHelp super -usage_helper :: [CommandControl] -> String-usage_helper [] = ""-usage_helper (Hidden_command _:cs) = usage_helper cs-usage_helper ((Command_data c):cs) = "  "++pad_spaces (command_name c) 15 ++-                      chomp_newline (command_description c)++"\n"++usage_helper cs-usage_helper ((Group_name n):cs) = "\n" ++ n ++ "\n" ++ usage_helper cs+usageHelper :: [CommandControl] -> String+usageHelper [] = ""+usageHelper (HiddenCommand _:cs) = usageHelper cs+usageHelper ((CommandData c):cs) = "  "++padSpaces (commandName c) 15 +++                      chompNewline (commandDescription c)++"\n"++usageHelper cs+usageHelper ((GroupName n):cs) = "\n" ++ n ++ "\n" ++ usageHelper cs -chomp_newline :: String -> String-chomp_newline "" = ""-chomp_newline s = if last s == '\n' then init s else s+chompNewline :: String -> String+chompNewline "" = ""+chompNewline s = if last s == '\n' then init s else s -pad_spaces :: String -> Int -> String-pad_spaces s n = s ++ replicate (n - length s) ' '+padSpaces :: String -> Int -> String+padSpaces s n = s ++ replicate (n - length s) ' ' -super_name :: Maybe DarcsCommand -> String-super_name Nothing  = ""-super_name (Just x) = command_name x ++ " "+superName :: Maybe DarcsCommand -> String+superName Nothing  = ""+superName (Just x) = commandName x ++ " " -get_command_mini_help :: Maybe DarcsCommand -> DarcsCommand -> String-get_command_mini_help msuper cmd =-  get_command_help_core msuper cmd +++getCommandMiniHelp :: Maybe DarcsCommand -> DarcsCommand -> String+getCommandMiniHelp msuper cmd =+  getCommandHelpCore msuper cmd ++   "\n\nSee darcs help "-  ++ (maybe "" (\c -> command_name c ++ " ") msuper)-  ++ command_name cmd ++ " for details."+  ++ (maybe "" (\c -> commandName c ++ " ") msuper)+  ++ commandName cmd ++ " for details." -get_command_help :: Maybe DarcsCommand -> DarcsCommand -> String-get_command_help msuper cmd =+getCommandHelp :: Maybe DarcsCommand -> DarcsCommand -> String+getCommandHelp msuper cmd =     unlines (reverse basicR)     ++ (if null advanced then ""         else "\nAdvanced options:\n" ++ unlines (reverse advancedR))-    ++ "\n" ++ command_help cmd+    ++ "\n" ++ commandHelp cmd     where -- we could just call usageInfo twice, but then the advanced           -- options might not line up with the basic ones (no short flags)           (advancedR, basicR) =              splitAt (length advanced) $ reverse $ lines combinedUsage           combinedUsage = usageInfo-            (get_command_help_core msuper cmd ++ subcommands ++ "\n\nOptions:")+            (getCommandHelpCore msuper cmd ++ subcommands ++ "\n\nOptions:")             (basic ++ advanced)-          (basic, advanced) = command_options rootDirectory cmd+          (basic, advanced) = commandOptions rootDirectory cmd           subcommands =             case msuper of-            Nothing -> case get_subcommands cmd of+            Nothing -> case getSubcommands cmd of                        [] -> []-                       s  -> "\n\nSubcommands:\n" ++ (usage_helper s)+                       s  -> "\n\nSubcommands:\n" ++ (usageHelper s)             -- we don't want to list subcommands if we're already specifying them             Just _  -> "" -get_command_help_core :: Maybe DarcsCommand -> DarcsCommand -> String-get_command_help_core msuper cmd =-    "Usage: darcs "++super_name msuper++command_name cmd+++getCommandHelpCore :: Maybe DarcsCommand -> DarcsCommand -> String+getCommandHelpCore msuper cmd =+    "Usage: darcs "++superName msuper++commandName cmd++     " [OPTION]... " ++ unwords args_help ++-    "\n"++ command_description cmd+    "\n"++ commandDescription cmd     where args_help = case cmd of             (DarcsCommand _ _ _ _ _ _ _ _ _ _ _) ->-              command_extra_arg_help cmd+              commandExtraArgHelp cmd             _ -> []  data CommandArgs = CommandOnly      DarcsCommand@@ -265,11 +266,11 @@                  | SuperCommandSub  DarcsCommand DarcsCommand  -- Parses a darcs command line with potentially abbreviated commands-disambiguate_commands :: [CommandControl] -> String -> [String]+disambiguateCommands :: [CommandControl] -> String -> [String]                       -> Either String (CommandArgs, [String])-disambiguate_commands allcs cmd args =+disambiguateCommands allcs cmd args =  do c <- extract cmd allcs-    case (get_subcommands c, args) of+    case (getSubcommands c, args) of       ([], _)         -> return (CommandOnly c, args)       (_ ,[])         -> return (SuperCommandOnly c, args)       (subcs, (a:as)) -> case extract a subcs of@@ -278,17 +279,31 @@  extract :: String -> [CommandControl] -> Either String DarcsCommand extract cmd cs =- case [ c | c <- extract_commands cs, cmd `isPrefixOf` command_name c ] ++-      [ h | h <- extract_hidden_commands cs,    cmd == command_name h ] of+ case [ c | c <- extractCommands cs, cmd `isPrefixOf` commandName c ] +++      [ h | h <- extractHiddenCommands cs,    cmd == commandName h ] of    []  -> Left $ "No such command '" ++ cmd ++ "'\n"    [c] -> Right c    cs' -> Left $ "Ambiguous command...\n\n" ++                     "The command '"++cmd++"' could mean one of:\n" ++-                    unwords (sort $ map command_name cs')+                    unwords (sort $ map commandName cs') --- | Output functions equivalent to (putStrLn, hPutStrLn stderr, putDocLn)-loggers :: [DarcsFlag] -> ( String -> IO ()-                          , String -> IO ()-                          , Doc -> IO ())-loggers _ = (putStrLn, putStrLnError, putDocLn)+amVerbose :: [DarcsFlag] -> Bool+amVerbose = elem Verbose++amQuiet :: [DarcsFlag] -> Bool+amQuiet = elem Quiet++putVerbose :: [DarcsFlag] -> Doc -> IO ()+putVerbose opts = when (amVerbose opts) . putDocLn+     +putInfo :: [DarcsFlag] -> Doc -> IO ()+putInfo opts = unless (amQuiet opts) . putDocLn++putWarning :: [DarcsFlag] -> Doc -> IO ()+putWarning opts = unless (amQuiet opts) . hPutDocLn stderr++abortRun :: [DarcsFlag] -> Doc -> IO ()+abortRun opts msg = if DryRun `elem` opts+                    then putInfo opts $ text "NOTE:" <+> msg+                    else errorDoc msg \end{code}
src/Darcs/Commands/Add.lhs view
@@ -17,44 +17,43 @@  \darcsCommand{add} \begin{code}-module Darcs.Commands.Add ( add ) where+module Darcs.Commands.Add ( add, expandDirs ) where  import Data.List ( (\\), nub) -import Darcs.Commands-import Darcs.Arguments (noskip_boring, allow_problematic_filenames,-                       fancy_move_add,-                       recursive, working_repo_dir, dry_run_noxml, umask_option,-                       list_files, list_unregistered_files,-                        DarcsFlag (AllowCaseOnly, AllowWindowsReserved, Boring, Recursive,-                                   Verbose, Quiet, FancyMoveAdd, DryRun),+import Darcs.Commands(DarcsCommand(..), putVerbose, putWarning, nodefaults)+import Darcs.Arguments (noskipBoring, allowProblematicFilenames,+                       fancyMoveAdd,+                       recursive, workingRepoDir, dryRunNoxml, umaskOption,+                       listFiles, listUnregisteredFiles,+                        DarcsFlag ( Recursive, FancyMoveAdd, DryRun, Verbose),                         fixSubPaths,                       )+import Darcs.Flags( includeBoring, doAllowCaseOnly, doAllowWindowsReserved,) import Darcs.Utils ( withCurrentDirectory, nubsort ) import IsoDate ( getIsoDateTime ) import Darcs.Repository ( amInRepository, withRepoLock, ($-),                     slurp_pending, add_to_pending )-import Darcs.Patch ( Prim, apply_to_slurpy, addfile, adddir, move )-import Darcs.Ordered ( FL(..), unsafeFL, concatFL, nullFL )+import Darcs.Patch ( Prim, applyToSlurpy, addfile, adddir, move )+import Darcs.Witnesses.Ordered ( FL(..), unsafeFL, concatFL, nullFL ) import Darcs.SlurpDirectory ( Slurpy, slurp_has_anycase, slurp_has,                         isFileReallySymlink, doesDirectoryReallyExist,                          doesFileReallyExist, slurp_hasdir,                       ) import Darcs.Patch.FileName ( fp2fn )-import Darcs.RepoPath ( toFilePath )-import Control.Monad ( when, unless )-import Darcs.Repository.Prefs ( darcsdir_filter, boring_file_filter )-import Data.Maybe ( maybeToList )+import Darcs.RepoPath ( SubPath, toFilePath, simpleSubPath, toPath )+import Control.Monad ( when, unless, liftM )+import Darcs.Repository.Prefs ( darcsdirFilter, boringFileFilter )+import Data.Maybe ( maybeToList, fromJust ) import System.FilePath.Posix ( takeDirectory, (</>) )-import System.IO ( hPutStrLn, stderr ) import qualified System.FilePath.Windows as WindowsFilePath-import Darcs.Gorsvet( invalidateIndex )+import Printer( text ) -add_description :: String-add_description = "Add one or more new files or directories."+addDescription :: String+addDescription = "Add one or more new files or directories." -add_help :: String-add_help =+addHelp :: String+addHelp =  "Generally a repository contains both files that should be version\n" ++  "controlled (such as source code) and files that Darcs should ignore\n" ++  "(such as executables compiled from the source code).  The `darcs add'\n" ++@@ -67,24 +66,24 @@  "Adding symbolic links (symlinks) is not supported.\n\n"  add :: DarcsCommand-add = DarcsCommand {command_name = "add",-                    command_help = add_help ++ add_help' ++ add_help'',-                    command_description = add_description,-                    command_extra_args = -1,-                    command_extra_arg_help = ["<FILE or DIRECTORY> ..."],-                    command_command = add_cmd,-                    command_prereq = amInRepository,-                    command_get_arg_possibilities = list_unregistered_files,-                    command_argdefaults = nodefaults,-                    command_advanced_options = [umask_option],-                    command_basic_options =-                    [noskip_boring, allow_problematic_filenames,+add = DarcsCommand {commandName = "add",+                    commandHelp = addHelp ++ addHelp' ++ addHelp'',+                    commandDescription = addDescription,+                    commandExtraArgs = -1,+                    commandExtraArgHelp = ["<FILE or DIRECTORY> ..."],+                    commandCommand = addCmd,+                    commandPrereq = amInRepository,+                    commandGetArgPossibilities = listUnregisteredFiles,+                    commandArgdefaults = nodefaults,+                    commandAdvancedOptions = [umaskOption],+                    commandBasicOptions =+                    [noskipBoring, allowProblematicFilenames,                      recursive "add contents of subdirectories",-                     fancy_move_add,-                     working_repo_dir, dry_run_noxml]}+                     fancyMoveAdd,+                     workingRepoDir, dryRunNoxml]} -add_help' :: String-add_help' =+addHelp' :: String+addHelp' =  "Darcs will ignore all files and folders that look `boring'.  The\n" ++  "--boring option overrides this behaviour.\n" ++  "\n" ++@@ -95,28 +94,27 @@  "`ReadMe' and `README').  If --case-ok is used, the repository might be\n" ++  "unusable on those systems!\n\n" -add_cmd :: [DarcsFlag] -> [String] -> IO ()-add_cmd opts args = withRepoLock opts $- \repository ->+addCmd :: [DarcsFlag] -> [String] -> IO ()+addCmd opts args = withRepoLock opts $- \repository ->  do cur <- slurp_pending repository-    origfiles <- map toFilePath `fmap` fixSubPaths opts args+    origfiles <- fixSubPaths opts args     when (null origfiles) $        putStrLn "Nothing specified, nothing added." >>        putStrLn "Maybe you wanted to say `darcs add --recursive .'?"-    parlist <- get_parents cur origfiles+    parlist <- getParents cur (map toFilePath origfiles)     flist' <- if Recursive `elem` opts-              then expand_dirs origfiles+              then expandDirs origfiles               else return origfiles-    let flist = nubsort (parlist ++ flist')+    let flist = nubsort (parlist ++ toFilePath `map` flist')     -- refuse to add boring files recursively:-    nboring <- if Boring `elem` opts-               then return darcsdir_filter-               else boring_file_filter-    let putInfoLn = if Quiet `elem` opts then \_ -> return () else putStrLn-    mapM_ (putInfoLn . ((msg_skipping msgs ++ " boring file ")++)) $+    nboring <- if includeBoring opts+               then return darcsdirFilter+               else boringFileFilter+    let fixedOpts = if DryRun `elem` opts then Verbose:opts else opts+    mapM_ (putWarning fixedOpts . text . ((msg_skipping msgs ++ " boring file ")++)) $       flist \\ nboring flist     date <- getIsoDateTime-    invalidateIndex repository-    ps <- addp msgs opts date cur $ nboring flist+    ps <- addp msgs fixedOpts date cur $ nboring flist     when (nullFL ps && not (null args)) $         fail "No files were added"     unless gotDryRun $ add_to_pending repository ps@@ -164,8 +162,8 @@                         msg_are msgs ++ " already in the repository"                       else return $                         "The following files " ++ msg_are msgs ++ " already in the repository")-       putInfo $ dupMsg ++ caseMsg-       mapM_ putInfo uniq_dups+       putWarning opts . text $ dupMsg ++ caseMsg+       mapM_ (putWarning opts . text) uniq_dups     return $ concatFL $ unsafeFL ps  where   addp' :: Slurpy -> FilePath -> IO (Slurpy, Maybe (FL Prim), Maybe FilePath)@@ -174,7 +172,8 @@     then return (cur, Nothing, Just f)     else     if is_badfilename-       then do putInfo $ "The filename " ++ f ++ " is invalid under Windows.\nUse --reserved-ok to allow it."+       then do putWarning opts . text $+                              "The filename " ++ f ++ " is invalid under Windows.\nUse --reserved-ok to allow it."                return add_failure        else do       isdir <- doesDirectoryReallyExist f@@ -185,8 +184,9 @@                     then trypatch $ myaddfile f                     else do islink <- isFileReallySymlink f                             if islink then-                               putInfo $ "Sorry, file " ++ f ++ " is a symbolic link, which is unsupported by darcs."-                               else putInfo $ "File "++ f ++" does not exist!"+                               putWarning opts . text $+                                 "Sorry, file " ++ f ++ " is a symbolic link, which is unsupported by darcs."+                               else putWarning opts . text $ "File "++ f ++" does not exist!"                             return add_failure       where already_has = if gotAllowCaseOnly                           then slurp_has f cur@@ -194,10 +194,10 @@             is_badfilename = not (gotAllowWindowsReserved || WindowsFilePath.isValid f)             add_failure = (cur, Nothing, Nothing)             trypatch p =-                case apply_to_slurpy p cur of-                Nothing -> do putInfo $ msg_skipping msgs ++ " '" ++ f ++ "' ... " ++ parent_error+                case applyToSlurpy p cur of+                Nothing -> do putWarning opts . text $ msg_skipping msgs ++ " '" ++ f ++ "' ... " ++ parent_error                               return (cur, Nothing, Nothing)-                Just s' -> do putVerbose $ msg_adding msgs++" '"++f++"'"+                Just s' -> do putVerbose opts . text $ msg_adding msgs++" '"++f++"'"                               return (s', Just p, Nothing)             parentdir = takeDirectory f             have_parentdir = slurp_hasdir (fp2fn parentdir) cur@@ -213,13 +213,9 @@                           then addfile (d++"-"++date) :>:                                move (d++"-"++date) d :>: NilFL                           else addfile d :>: NilFL-  putVerbose = if Verbose `elem` opts || DryRun `elem` opts-               then putStrLn-               else \_ -> return ()-  putInfo = if Quiet `elem` opts then \_ -> return () else hPutStrLn stderr   gotFancyMoveAdd = FancyMoveAdd `elem` opts-  gotAllowCaseOnly = AllowCaseOnly `elem` opts-  gotAllowWindowsReserved = AllowWindowsReserved `elem` opts+  gotAllowCaseOnly = doAllowCaseOnly opts+  gotAllowWindowsReserved = doAllowWindowsReserved opts  data AddMessages =     AddMessages@@ -247,31 +243,32 @@  -- |FIXME: this documentation makes *no* sense to me, and the -- ramifications of using this option are not clear. --twb, 2008-add_help'' :: String-add_help'' =+addHelp'' :: String+addHelp'' =  "The --date-trick option allows you to enable an experimental trick to\n" ++  "make add conflicts, in which two users each add a file or directory\n" ++  "with the same name, less problematic.  While this trick is completely\n" ++  "safe, it is not clear to what extent it is beneficial.\n" -expand_dirs :: [FilePath] -> IO [FilePath]-expand_dirs fs = concat `fmap` mapM expand_one fs-expand_one :: FilePath -> IO [FilePath]-expand_one "" = list_files-expand_one f = do+expandDirs :: [SubPath] -> IO [SubPath]+expandDirs fs = liftM (map (fromJust . simpleSubPath)) (concat `fmap` mapM (expandOne . toPath) fs)++expandOne :: FilePath -> IO [FilePath]+expandOne "" = listFiles+expandOne f = do   isdir <- doesDirectoryReallyExist f   if not isdir then return [f]-     else do fs <- withCurrentDirectory f list_files+     else do fs <- withCurrentDirectory f listFiles              return $ f: map (f </>) fs -get_parents :: Slurpy -> [FilePath] -> IO [FilePath]-get_parents cur fs =-  concat `fmap` mapM (get_parent cur) fs-get_parent :: Slurpy -> FilePath -> IO [FilePath]-get_parent cur f =+getParents :: Slurpy -> [FilePath] -> IO [FilePath]+getParents cur fs =+  concat `fmap` mapM (getParent cur) fs+getParent :: Slurpy -> FilePath -> IO [FilePath]+getParent cur f =   if slurp_hasdir (fp2fn parentdir) cur   then return []-  else do grandparents <- get_parent cur parentdir+  else do grandparents <- getParent cur parentdir           return (grandparents ++ [parentdir])     where parentdir = takeDirectory f \end{code}
src/Darcs/Commands/AmendRecord.lhs view
@@ -20,52 +20,52 @@ module Darcs.Commands.AmendRecord ( amendrecord ) where import Data.List ( sort ) import Data.Maybe ( isJust )+import System.Directory ( removeFile ) import System.Exit ( ExitCode(..), exitWith ) import Control.Monad ( when )  import Darcs.Flags ( DarcsFlag(Author, LogFile, PatchName,                                EditLongComment, PromptLongComment) ) import Darcs.Lock ( world_readable_temp )-import Darcs.RepoPath ( toFilePath, sp2fn )+import Darcs.RepoPath ( toFilePath ) import Darcs.Hopefully ( PatchInfoAnd, n2pia, hopefully, info )-import Darcs.Repository ( withRepoLock, ($-), withGutsOf,-                    get_unrecorded_in_files, get_unrecorded_in_files_unsorted,+import Darcs.Repository ( Repository, withRepoLock, ($-), withGutsOf,                     tentativelyRemovePatches, tentativelyAddPatch, finalizeRepositoryChanges,-                    sync_repo, amInRepository,+                    amInRepository+                        , invalidateIndex, unrecordedChanges                   ) import Darcs.Patch ( RepoPatch, description, Prim, fromPrims,                      infopatch, getdeps, adddeps, effect,-                     sort_coalesceFL,-                     canonize )+                   )+import Darcs.Patch.Prim ( canonizeFL ) import Darcs.Patch.Info ( pi_author, pi_name, pi_log,                           PatchInfo, patchinfo, is_inverted, invert_name,                         )-import Darcs.Ordered ( FL(..), (:>)(..), (+>+),-                             nullFL, mapFL_FL, concatFL )+import Darcs.Patch.Split ( primSplitter )+import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), (+>+), nullFL ) import Darcs.SelectChanges ( with_selected_changes_to_files',                              with_selected_patch_from_repo ) import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Commands.Record ( get_date, get_log )+import Darcs.Commands.Record ( getDate, getLog ) import Darcs.Arguments ( DarcsFlag ( All ),                          areFileArgs, fixSubPaths, defineChanges,-                        all_interactive, ignoretimes,-                        ask_long_comment, author, patchname_option,-                        leave_test_dir, nocompress, lookforadds,-                         working_repo_dir,-                        match_one_nontag, umask_option,-                        notest, testByDefault, list_registered_files,-                        get_easy_author, set_scripts_executable+                        allInteractive, ignoretimes,+                        askLongComment, author, patchnameOption,+                        leaveTestDir, nocompress, lookforadds,+                         workingRepoDir,+                        matchOneNontag, umaskOption,+                        notest, testByDefault, listRegisteredFiles,+                        getEasyAuthor, setScriptsExecutableOption                       )-import Darcs.Utils ( askUser )+import Darcs.Utils ( askUser, clarifyErrors ) import Printer ( putDocLn )-import Darcs.Gorsvet( invalidateIndex ) -amendrecord_description :: String-amendrecord_description =+amendrecordDescription :: String+amendrecordDescription =  "Improve a patch before it leaves your repository." -amendrecord_help :: String-amendrecord_help =+amendrecordHelp :: String+amendrecordHelp =  "Amend-record updates a `draft' patch with additions or improvements,\n" ++  "resulting in a single `finished' patch.  This is better than recording\n" ++  "the additions and improvements as separate patches, because then\n" ++@@ -100,96 +100,107 @@  "On Windows use C:/Documents And Settings/user/Application Data/darcs/defaults\n"  amendrecord :: DarcsCommand-amendrecord = DarcsCommand {command_name = "amend-record",-                            command_help = amendrecord_help,-                            command_description = amendrecord_description,-                            command_extra_args = -1,-                            command_extra_arg_help = ["[FILE or DIRECTORY]..."],-                            command_command = amendrecord_cmd,-                            command_prereq = amInRepository,-                            command_get_arg_possibilities = list_registered_files,-                            command_argdefaults = nodefaults,-                            command_advanced_options = [nocompress, ignoretimes, umask_option,-                                                        set_scripts_executable],-                            command_basic_options = [match_one_nontag,+amendrecord = DarcsCommand {commandName = "amend-record",+                            commandHelp = amendrecordHelp,+                            commandDescription = amendrecordDescription,+                            commandExtraArgs = -1,+                            commandExtraArgHelp = ["[FILE or DIRECTORY]..."],+                            commandCommand = amendrecordCmd,+                            commandPrereq = amInRepository,+                            commandGetArgPossibilities = listRegisteredFiles,+                            commandArgdefaults = nodefaults,+                            commandAdvancedOptions = [nocompress, ignoretimes, umaskOption,+                                                        setScriptsExecutableOption],+                            commandBasicOptions = [matchOneNontag,                                                      notest,-                                                    leave_test_dir,-                                                    all_interactive,-                                                    author, patchname_option, ask_long_comment,+                                                    leaveTestDir,+                                                    allInteractive,+                                                    author, patchnameOption, askLongComment,                                                     lookforadds,-                                                    working_repo_dir]}+                                                    workingRepoDir]} -amendrecord_cmd :: [DarcsFlag] -> [String] -> IO ()-amendrecord_cmd opts args =-    let edit_metadata = has_edit_metadata opts in+amendrecordCmd :: [DarcsFlag] -> [String] -> IO ()+amendrecordCmd opts args =     withRepoLock (testByDefault opts) $- \repository -> do     files  <- sort `fmap` fixSubPaths opts args     when (areFileArgs files) $          putStrLn $ "Amending changes in "++unwords (map show files)++":\n"     with_selected_patch_from_repo "amend" repository opts $ \ (_ :> oldp) -> do-        ch <- if All `elem` opts -              then get_unrecorded_in_files_unsorted repository (map sp2fn files)-              else get_unrecorded_in_files repository (map sp2fn files)+        ch <- unrecordedChanges opts repository files         case ch of-          NilFL | not edit_metadata -> putStrLn "No changes!"-          _ -> do-              date <- get_date opts-              with_selected_changes_to_files' "add" (filter (==All) opts)-                (map toFilePath files) ch $ \ (chs:>_) ->-                  if (nullFL chs && not edit_metadata)+          NilFL | not (hasEditMetadata opts) -> putStrLn "No changes!"+          _ ->+               with_selected_changes_to_files' "add" (filter (==All) opts) (Just primSplitter)+                (map toFilePath files) ch $ addChangesToPatch opts repository oldp++addChangesToPatch :: forall t p . (RepoPatch p) => [DarcsFlag] -> Repository p -> PatchInfoAnd p+                  -> (FL Prim :> t) -> IO ()+addChangesToPatch opts repository oldp (chs:>_) =    +                  if (nullFL chs && not (hasEditMetadata opts))                   then putStrLn "You don't want to record anything!"                   else do+                       (mlogf, newp) <- updatePatchHeader opts oldp chs+                       defineChanges newp+                       invalidateIndex repository+                       withGutsOf repository $ do+                         tentativelyRemovePatches repository opts (hopefully oldp :>: NilFL)+                         tentativelyAddPatch repository opts newp+                         let failmsg = maybe "" (\lf -> "\nLogfile left in "++lf++".") mlogf+                         finalizeRepositoryChanges repository `clarifyErrors` failmsg+                       maybe (return ()) removeFile mlogf+                       putStrLn "Finished amending patch:"+                       putDocLn $ description newp++updatePatchHeader :: forall p. (RepoPatch p) => [DarcsFlag] -> PatchInfoAnd p -> FL Prim+                  -> IO (Maybe String, PatchInfoAnd p)+updatePatchHeader opts oldp chs = do                        let old_pinf = info oldp                            prior    = (pi_name old_pinf, pi_log old_pinf)                            make_log = world_readable_temp "darcs-amend-record"                            old_author = pi_author old_pinf-                       author_here <- get_easy_author-                       case author_here of-                         Nothing -> return ()-                         Just ah -> let edit_author = isJust (get_author opts)-                                    in if (edit_author || ah == old_author)-                                       then return ()-                                       else do yorn <- askUser $ "You're not "++old_author-                                                                 ++"! Amend anyway? "-                                               case yorn of ('y':_) -> return ()-                                                            _ -> exitWith $ ExitSuccess-                       (new_name, new_log, _) <- get_log opts (Just prior) make_log chs-                       let new_author = case get_author opts of+                       date <- getDate opts+                       warnIfHijacking opts old_author+                       (new_name, new_log, mlogf) <- getLog opts (Just prior) make_log chs+                       let new_author = case getAuthor opts of                                         Just a  -> a                                         Nothing -> pi_author old_pinf                            maybe_invert = if is_inverted old_pinf then invert_name else id                        new_pinf <- maybe_invert `fmap` patchinfo date new_name                                                                  new_author new_log-                       let newp = fixp oldp chs new_pinf-                       defineChanges newp-                       invalidateIndex repository-                       withGutsOf repository $ do-                         tentativelyRemovePatches repository opts (hopefully oldp :>: NilFL)-                         tentativelyAddPatch repository opts newp-                         finalizeRepositoryChanges repository-                       sync_repo repository-                       putStrLn "Finished amending patch:"-                       putDocLn $ description newp+                       return $ (mlogf, fixp oldp chs new_pinf) -has_edit_metadata :: [DarcsFlag] -> Bool-has_edit_metadata (Author _:_) = True-has_edit_metadata (LogFile _:_) = True-has_edit_metadata (PatchName _:_) = True-has_edit_metadata (EditLongComment:_) = True-has_edit_metadata (PromptLongComment:_) = True-has_edit_metadata (_:fs) = has_edit_metadata fs-has_edit_metadata [] = False+warnIfHijacking :: [DarcsFlag] -> String -> IO ()+warnIfHijacking opts old_author = do+  author_here <- getEasyAuthor+  case author_here of+    Nothing -> return ()+    Just ah -> let edit_author = isJust (getAuthor opts)+              in if (edit_author || ah == old_author)+                 then return ()+                 else do yorn <- askUser $ +                                "You're not "++old_author ++"! Amend anyway? "+                         case yorn of ('y':_) -> return ()+                                      _ -> exitWith $ ExitSuccess -get_author :: [DarcsFlag] -> Maybe String-get_author (Author a:_) = Just a-get_author (_:as) = get_author as-get_author []     = Nothing+hasEditMetadata :: [DarcsFlag] -> Bool+hasEditMetadata (Author _:_) = True+hasEditMetadata (LogFile _:_) = True+hasEditMetadata (PatchName _:_) = True+hasEditMetadata (EditLongComment:_) = True+hasEditMetadata (PromptLongComment:_) = True+hasEditMetadata (_:fs) = hasEditMetadata fs+hasEditMetadata [] = False +getAuthor :: [DarcsFlag] -> Maybe String+getAuthor (Author a:_) = Just a+getAuthor (_:as) = getAuthor as+getAuthor []     = Nothing+ fixp :: RepoPatch p => PatchInfoAnd p -> FL Prim -> PatchInfo -> PatchInfoAnd p fixp oldp chs new_pinf =     let pdeps = getdeps $ hopefully oldp         oldchs = effect oldp         infodepspatch pinfo deps p = adddeps (infopatch pinfo p) deps-    in n2pia $ infodepspatch new_pinf pdeps $ fromPrims $ concatFL $ mapFL_FL canonize-           $ sort_coalesceFL $ concatFL $ mapFL_FL canonize $ oldchs +>+ chs+    in n2pia $ infodepspatch new_pinf pdeps $ fromPrims $ canonizeFL+             $ oldchs +>+ chs \end{code}
src/Darcs/Commands/Annotate.lhs view
@@ -22,25 +22,26 @@  #include "gadts.h" -module Darcs.Commands.Annotate ( annotate, created_as_xml ) where+module Darcs.Commands.Annotate ( annotate, createdAsXml ) where  import Control.Monad ( when ) import Data.List ( sort )  import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag(..), working_repo_dir,-                         summary, unified, human_readable,+import Darcs.Arguments ( DarcsFlag(..), workingRepoDir,+                         summary, unified, humanReadable,                         xmloutput, creatorhash,                         fixSubPaths,-                        list_registered_files,-                        match_one,+                        listRegisteredFiles,+                        matchOne,                       )-import Darcs.SlurpDirectory ( slurp )+import Darcs.Flags ( isUnified )+import Storage.Hashed.Plain( readPlainTree ) import Darcs.Repository ( Repository, PatchSet, amInRepository, withRepository, ($-), read_repo,                           getMarkedupFile )-import Darcs.Patch ( RepoPatch, Named, LineMark(..), patch2patchinfo, xml_summary )+import Darcs.Patch ( RepoPatch, Named, LineMark(..), patch2patchinfo, xmlSummary ) import qualified Darcs.Patch ( summary )-import Darcs.Ordered ( mapRL, concatRL )+import Darcs.Witnesses.Ordered ( mapRL, concatRL ) import qualified Data.ByteString.Char8 as BC ( unpack, ByteString ) import Darcs.PrintPatch ( printPatch, contextualPrintPatch ) import Darcs.Patch.Info ( PatchInfo, human_friendly, to_xml, make_filename,@@ -54,70 +55,66 @@                   ) import Darcs.Hopefully ( info ) import Darcs.RepoPath ( SubPath, toFilePath )-import Darcs.Match ( match_patch, have_nonrange_match, get_first_match )+import Darcs.Match ( matchPatch, haveNonrangeMatch, getFirstMatch ) import Darcs.Lock ( withTempDir )-import Darcs.Sealed ( Sealed2(..), unseal2 )+import Darcs.Witnesses.Sealed ( Sealed2(..), unseal2 ) import Printer ( putDocLn, text, errorDoc, ($$), prefix, (<+>),                  Doc, empty, vcat, (<>), renderString, packedString ) #include "impossible.h" -annotate_description :: String-annotate_description = "Display which patch last modified something."+annotateDescription :: String+annotateDescription = "Display which patch last modified something." -annotate_help :: String-annotate_help =- "Annotate displays which patches created or last modified a directory\n"++- "file or line. It can also display the contents of a particular patch\n"++- "in darcs format.\n"+annotateHelp :: String+annotateHelp =+ "The `darcs annotate' command provides two unrelated operations.  When\n" +++ "called on a file, it will find the patch that last modified each line\n" +++ "in that file.  When called on a patch (e.g. using --patch), it will\n" +++ "print the internal representation of that patch.\n" +++ "\n" +++ "The --summary option will result in a summarized patch annotation,\n" +++ "similar to `darcs whatsnew'.  It has no effect on file annotations.\n" +++ "\n" +++ "By default, output is in a human-readable format.  The --xml-output\n" +++ "option can be used to generate output for machine postprocessing.\n"  annotate :: DarcsCommand-annotate = DarcsCommand {command_name = "annotate",-                         command_help = annotate_help,-                         command_description = annotate_description,-                         command_extra_args = -1,-                         command_extra_arg_help = ["[FILE or DIRECTORY]..."],-                         command_command = annotate_cmd,-                         command_prereq = amInRepository,-                         command_get_arg_possibilities = list_registered_files,-                         command_argdefaults = nodefaults,-                         command_advanced_options = [],-                         command_basic_options = [summary,unified,-                                                 human_readable,+annotate = DarcsCommand {commandName = "annotate",+                         commandHelp = annotateHelp,+                         commandDescription = annotateDescription,+                         commandExtraArgs = -1,+                         commandExtraArgHelp = ["[FILE or DIRECTORY]..."],+                         commandCommand = annotateCmd,+                         commandPrereq = amInRepository,+                         commandGetArgPossibilities = listRegisteredFiles,+                         commandArgdefaults = nodefaults,+                         commandAdvancedOptions = [],+                         commandBasicOptions = [summary,unified,+                                                 humanReadable,                                                  xmloutput,-                                                 match_one, creatorhash,-                                                 working_repo_dir]}-\end{code}--\begin{options}---human-readable, --summary, --unified, --xml--output-\end{options}--When called with just a patch name, annotate outputs the patch in darcs format,-which is the same as \verb!--human-readable!.--\verb!--xml-output! is the alternative to \verb!--human-readable!.--\verb!--summary! can be used with either the \verb!--xml-output! or the  -\verb!--human-readable! options to alter the results. It is documented-fully in the `common options' portion of the manual. +                                                 matchOne, creatorhash,+                                                 workingRepoDir]} +\end{code}+%% FIXME: AFAICT -u does nothing.  Remove it from anno's options?+%% --twb, 2009-09-20 Giving the \verb!--unified! flag implies \verb!--human-readable!, and causes the output to remain in a darcs-specific format that is similar to that produced by \verb!diff --unified!. \begin{code}-annotate_cmd :: [DarcsFlag] -> [String] -> IO ()-annotate_cmd opts [] = withRepository opts $- \repository -> do-  when (not $ have_nonrange_match opts) $+annotateCmd :: [DarcsFlag] -> [String] -> IO ()+annotateCmd opts [] = withRepository opts $- \repository -> do+  when (not $ haveNonrangeMatch opts) $       fail $ "Annotate requires either a patch pattern or a " ++                "file or directory argument."-  Sealed2 p <- match_patch opts `fmap` read_repo repository+  Sealed2 p <- matchPatch opts `fmap` read_repo repository   if Summary `elem` opts      then do putDocLn $ showpi $ patch2patchinfo p              putDocLn $ show_summary p-     else if Unified `elem` opts+     else if isUnified opts           then withTempDir "context" $ \_ ->-               do get_first_match repository opts-                  c <- slurp "."+               do getFirstMatch repository opts+                  c <- readPlainTree "."                   contextualPrintPatch c p           else printPatch p     where showpi | MachineReadable `elem` opts = showPatchInfo@@ -125,7 +122,7 @@                  | otherwise                   = human_friendly           show_summary :: RepoPatch p => Named p C(x y) -> Doc           show_summary = if XMLOutput `elem` opts-                         then xml_summary+                         then xmlSummary                          else Darcs.Patch.summary \end{code} @@ -143,25 +140,25 @@ that patch was applied.  If a directory and a tag name are given, the details of the patches involved in the specified tagged version will be output. \begin{code}-annotate_cmd opts args@[_] = withRepository opts $- \repository -> do+annotateCmd opts args@[_] = withRepository opts $- \repository -> do   r <- read_repo repository   (rel_file_or_directory:_) <- fixSubPaths opts args   let file_or_directory = rel_file_or_directory-  pinfo <- if have_nonrange_match opts-           then return $ patch2patchinfo `unseal2` (match_patch opts r)+  pinfo <- if haveNonrangeMatch opts+           then return $ patch2patchinfo `unseal2` (matchPatch opts r)            else case mapRL info $ concatRL r of                 [] -> fail "Annotate does not currently work correctly on empty repositories."                 (x:_) -> return x   pop <- getRepoPopVersion "." pinfo    -- deal with --creator-hash option-  let maybe_creation_pi = find_creation_patchinfo opts r+  let maybe_creation_pi = findCreationPatchinfo opts r       lookup_thing = case maybe_creation_pi of                      Nothing -> lookup_pop                      Just cp -> lookup_creation_pop cp    if toFilePath file_or_directory == ""-    then case pop of (Pop _ pt) -> annotate_pop opts pinfo pt+    then case pop of (Pop _ pt) -> annotatePop opts pinfo pt     else case lookup_thing (toFilePath file_or_directory) pop of       Nothing -> fail $ "There is no file or directory named '"++                  toFilePath file_or_directory++"'"@@ -170,18 +167,18 @@               errorDoc $ text ("The directory '" ++ toFilePath rel_file_or_directory ++                                "' was removed by")                       $$ human_friendly (modifiedByI i)-          | otherwise -> annotate_pop opts pinfo pt+          | otherwise -> annotatePop opts pinfo pt       Just (Pop _ pt@(PopFile i))           | modifiedHowI i == RemovedFile && modifiedByI i /= pinfo ->               errorDoc $ text ("The file '" ++ toFilePath rel_file_or_directory ++                                "' was removed by")                       $$ human_friendly (modifiedByI i)-          | otherwise -> annotate_file repository opts pinfo file_or_directory pt+          | otherwise -> annotateFile repository opts pinfo file_or_directory pt -annotate_cmd _ _ = fail "annotate accepts at most one argument"+annotateCmd _ _ = fail "annotate accepts at most one argument" -annotate_pop :: [DarcsFlag] -> PatchInfo -> PopTree -> IO ()-annotate_pop opts pinfo pt = putDocLn $ p2format pinfo pt+annotatePop :: [DarcsFlag] -> PatchInfo -> PopTree -> IO ()+annotatePop opts pinfo pt = putDocLn $ p2format pinfo pt     where p2format = if XMLOutput `elem` opts                      then p2xml                      else p2s@@ -234,8 +231,8 @@   | x == z    = y ++ (strReplace x y zs)   | otherwise = z : (strReplace x y zs) -created_as_xml :: PatchInfo -> String -> Doc-created_as_xml pinfo as = text "<created_as original_name='"+createdAsXml :: PatchInfo -> String -> Doc+createdAsXml pinfo as = text "<created_as original_name='"                        <> escapeXML as                        <> text "'>"                     $$    to_xml pinfo@@ -243,37 +240,37 @@ --removed_by_xml :: PatchInfo -> String --removed_by_xml pinfo = "<removed_by>\n"++to_xml pinfo++"</removed_by>\n" -p2xml_open :: PatchInfo -> PopTree -> Doc-p2xml_open _ (PopFile inf) =+p2xmlOpen :: PatchInfo -> PopTree -> Doc+p2xmlOpen _ (PopFile inf) =     text "<file name='" <> escapeXML f <> text "'>"  $$ created  $$ modified     where f = BC.unpack $ nameI inf           created = case createdByI inf of                     Nothing -> empty-                    Just ci -> created_as_xml ci+                    Just ci -> createdAsXml ci                                (BC.unpack $ fromJust $ creationNameI inf)           modified = modified_to_xml inf-p2xml_open _ (PopDir inf _) =+p2xmlOpen _ (PopDir inf _) =     text "<directory name='" <> escapeXML f <> text "'>"  $$ created  $$ modified     where f = BC.unpack $ nameI inf           created = case createdByI inf of                     Nothing -> empty-                    Just ci -> created_as_xml ci+                    Just ci -> createdAsXml ci                                (BC.unpack $ fromJust $ creationNameI inf)           modified = modified_to_xml inf -p2xml_close :: PatchInfo -> PopTree -> Doc-p2xml_close _(PopFile _) = text "</file>"-p2xml_close _ (PopDir _ _) = text "</directory>"+p2xmlClose :: PatchInfo -> PopTree -> Doc+p2xmlClose _(PopFile _) = text "</file>"+p2xmlClose _ (PopDir _ _) = text "</directory>"  p2xml :: PatchInfo -> PopTree -> Doc-p2xml pinf p@(PopFile _) = p2xml_open pinf p $$ p2xml_close pinf p-p2xml pinf p@(PopDir _ pops) = p2xml_open pinf p+p2xml pinf p@(PopFile _) = p2xmlOpen pinf p $$ p2xmlClose pinf p+p2xml pinf p@(PopDir _ pops) = p2xmlOpen pinf p                             $$ vcat (map (p2xml pinf) $ sort pops)-                            $$ p2xml_close pinf p+                            $$ p2xmlClose pinf p \end{code}  If a file name is given, the last modifying patch details of that file will be output, along@@ -283,40 +280,40 @@ that patch was applied.  \begin{code}-annotate_file :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> PatchInfo -> SubPath -> PopTree -> IO ()-annotate_file repository opts pinfo f (PopFile inf) = do+annotateFile :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> PatchInfo -> SubPath -> PopTree -> IO ()+annotateFile repository opts pinfo f (PopFile inf) = do   if XMLOutput `elem` opts-     then putDocLn $ p2xml_open pinfo (PopFile inf)+     then putDocLn $ p2xmlOpen pinfo (PopFile inf)      else if createdByI inf /= Nothing           then putAnn $ text ("File "++toFilePath f++" created by ")                      <> showPatchInfo ci <> text (" as " ++ createdname)           else putAnn $ text $ "File "++toFilePath f   mk <- getMarkedupFile repository ci createdname   old_pis <- (dropWhile (/= pinfo).mapRL info.concatRL) `fmap` read_repo repository-  mapM_ (annotate_markedup opts pinfo old_pis) mk-  when (XMLOutput `elem` opts) $  putDocLn $ p2xml_close pinfo (PopFile inf)+  mapM_ (annotateMarkedup opts pinfo old_pis) mk+  when (XMLOutput `elem` opts) $  putDocLn $ p2xmlClose pinfo (PopFile inf)   where ci = fromJust $ createdByI inf         createdname = BC.unpack $ fromJust $ creationNameI inf-annotate_file _ _ _ _ _ = impossible+annotateFile _ _ _ _ _ = impossible -annotate_markedup :: [DarcsFlag] -> PatchInfo -> [PatchInfo]+annotateMarkedup :: [DarcsFlag] -> PatchInfo -> [PatchInfo]                   -> (BC.ByteString, LineMark) -> IO ()-annotate_markedup opts | XMLOutput `elem` opts = xml_markedup-                       | otherwise = text_markedup+annotateMarkedup opts | XMLOutput `elem` opts = xmlMarkedup+                       | otherwise = textMarkedup -text_markedup :: PatchInfo -> [PatchInfo] -> (BC.ByteString, LineMark) -> IO ()-text_markedup _ _ (l,None) = putLine ' ' l-text_markedup pinfo old_pis (l,RemovedLine wheni)+textMarkedup :: PatchInfo -> [PatchInfo] -> (BC.ByteString, LineMark) -> IO ()+textMarkedup _ _ (l,None) = putLine ' ' l+textMarkedup pinfo old_pis (l,RemovedLine wheni)     | wheni == pinfo       = putLine '-' l     | wheni `elem` old_pis = return ()     | otherwise            = putLine ' ' l-text_markedup pinfo old_pis (l,AddedLine wheni)+textMarkedup pinfo old_pis (l,AddedLine wheni)     | wheni == pinfo       = putLine '+' l     | wheni `elem` old_pis = do putAnn $ text "Following line added by "                                       <> showPatchInfo wheni                                 putLine ' ' l     | otherwise            = return ()-text_markedup pinfo old_pis (l,AddedRemovedLine whenadd whenrem)+textMarkedup pinfo old_pis (l,AddedRemovedLine whenadd whenrem)     | whenadd == pinfo = do putAnn $ text "Following line removed by "                                   <> showPatchInfo whenrem                             putLine '+' l@@ -334,9 +331,9 @@ putAnn :: Doc -> IO () putAnn s = putDocLn $ prefix "# " s -xml_markedup :: PatchInfo -> [PatchInfo] -> (BC.ByteString, LineMark) -> IO ()-xml_markedup _ _ (l,None) = putLine ' ' l-xml_markedup pinfo old_pis (l,RemovedLine wheni)+xmlMarkedup :: PatchInfo -> [PatchInfo] -> (BC.ByteString, LineMark) -> IO ()+xmlMarkedup _ _ (l,None) = putLine ' ' l+xmlMarkedup pinfo old_pis (l,RemovedLine wheni)     | wheni == pinfo       = putDocLn $ text "<removed_line>"                              $$ escapeXML (BC.unpack l)                              $$ text "</removed_line>"@@ -347,7 +344,7 @@                              $$ text "</removed_by>"                              $$ escapeXML (BC.unpack l)                              $$ text "</normal_line>"-xml_markedup pinfo old_pis (l,AddedLine wheni)+xmlMarkedup pinfo old_pis (l,AddedLine wheni)     | wheni == pinfo       = putDocLn $ text "<added_line>"                              $$ escapeXML (BC.unpack l)                              $$ text "</added_line>"@@ -358,7 +355,7 @@                              $$ escapeXML (BC.unpack l)                              $$ text "</normal_line>"     | otherwise            = return ()-xml_markedup pinfo old_pis (l,AddedRemovedLine whenadd whenrem)+xmlMarkedup pinfo old_pis (l,AddedRemovedLine whenadd whenrem)     | whenadd == pinfo =         putDocLn $ text "<added_line>"                 $$ text "<removed_by>"@@ -398,14 +395,14 @@ examine a file even if it has been renamed multiple times.  \begin{code}-find_creation_patchinfo :: [DarcsFlag] -> PatchSet p C(x) -> Maybe PatchInfo-find_creation_patchinfo [] _ = Nothing-find_creation_patchinfo (CreatorHash h:_) r = find_hash h $ mapRL info $ concatRL r-find_creation_patchinfo (_:fs) r = find_creation_patchinfo fs r+findCreationPatchinfo :: [DarcsFlag] -> PatchSet p C(x) -> Maybe PatchInfo+findCreationPatchinfo [] _ = Nothing+findCreationPatchinfo (CreatorHash h:_) r = findHash h $ mapRL info $ concatRL r+findCreationPatchinfo (_:fs) r = findCreationPatchinfo fs r -find_hash :: String -> [PatchInfo] -> Maybe PatchInfo-find_hash _ [] = Nothing-find_hash h (pinf:pinfs)+findHash :: String -> [PatchInfo] -> Maybe PatchInfo+findHash _ [] = Nothing+findHash h (pinf:pinfs)     | take (length h) (make_filename pinf) == h = Just pinf-    | otherwise = find_hash h pinfs+    | otherwise = findHash h pinfs \end{code}
src/Darcs/Commands/Apply.lhs view
@@ -27,38 +27,37 @@ import Control.Exception ( catch, throw, Exception( ExitException ) ) import Control.Monad ( when ) -import Darcs.Hopefully ( n2pia, conscientiously, info )+import Darcs.Hopefully ( PatchInfoAnd, n2pia, conscientiously, info ) import Darcs.SignalHandler ( withSignalsBlocked )-import Darcs.Commands ( DarcsCommand(..) )+import Darcs.Commands ( DarcsCommand(..), putVerbose ) import Darcs.CommandsAux ( check_paths )-import Darcs.Arguments ( DarcsFlag( Reply, Interactive, All,-                                    Verbose, HappyForwarding ),+import Darcs.Arguments ( DarcsFlag( Reply, Interactive, All ),                          definePatches,-                         get_cc, working_repo_dir,-                        notest, nocompress, apply_conflict_options,-                        use_external_merge,-                        ignoretimes, get_sendmail_cmd,-                        reply, verify, list_files,-                        fixFilePathOrStd, umask_option,-                        all_interactive, sendmail_cmd,-                        leave_test_dir, happy_forwarding, -                        dry_run, print_dry_run_message_and_exit,-                        set_scripts_executable, restrict_paths+                         getCc, workingRepoDir,+                        notest, nocompress, applyConflictOptions,+                        useExternalMerge,+                        ignoretimes, getSendmailCmd,+                        reply, verify, listFiles,+                        fixFilePathOrStd, umaskOption,+                        allInteractive, sendmailCmd,+                        leaveTestDir, happyForwarding, +                        dryRun, printDryRunMessageAndExit,+                        setScriptsExecutableOption, restrictPaths                       )-import qualified Darcs.Arguments as DarcsArguments ( cc )+import Darcs.Flags(doHappyForwarding)++import qualified Darcs.Arguments as DarcsArguments ( ccApply ) import Darcs.RepoPath ( toFilePath, useAbsoluteOrStd )-import Darcs.Repository ( SealedPatchSet, withRepoLock, ($-), amInRepository,+import Darcs.Repository ( Repository, SealedPatchSet, withRepoLock, ($-), amInRepository,                           tentativelyMergePatches,-                    sync_repo, read_repo,+                    read_repo,                     finalizeRepositoryChanges,-                    applyToWorking,+                    applyToWorking, invalidateIndex                   ) import Darcs.Patch ( RepoPatch, description )-import Darcs.Patch.Info ( human_friendly )-import Darcs.Ordered ( (:\/:)(..), (:>)(..), unsafeUnRL,-                             mapFL, nullFL, mapFL_FL, mapRL, concatRL, reverseRL )-import Darcs.SlurpDirectory ( wait_a_moment )-+import Darcs.Patch.Info ( PatchInfo, human_friendly )+import Darcs.Witnesses.Ordered ( FL, RL, (:\/:)(..), (:>)(..),+                       mapFL, nullFL, mapFL_FL, mapRL, concatRL, reverseRL ) import ByteStringUtils ( linesPS, unlinesPS ) import qualified Data.ByteString as B (ByteString, null, readFile, hGetContents, init, take, drop) import qualified Data.ByteString.Char8 as BC (unpack, last, pack)@@ -68,60 +67,86 @@ import Darcs.Email ( read_email ) import Darcs.Lock ( withStdoutTemp, readBinFile ) import Darcs.Patch.Depends ( get_common_and_uncommon_or_missing )-import Darcs.SelectChanges ( with_selected_changes )+import Darcs.SelectChanges ( with_selected_changes, filterOutConflicts ) import Darcs.Patch.Bundle ( scan_bundle )-import Darcs.Sealed ( Sealed(Sealed) )-import Printer ( packedString, putDocLn, vcat, text, ($$), errorDoc, empty )-import Darcs.Gorsvet( invalidateIndex )+import Darcs.Witnesses.Sealed ( Sealed(Sealed) )+import Printer ( packedString, vcat, text, ($$), errorDoc, empty )+ #include "impossible.h" -apply_description :: String-apply_description = "Apply a patch bundle created by `darcs send'."+#include "gadts.h" -apply_help :: String-apply_help =- "Apply is used to apply a bundle of patches to this repository.\n"++- "Such a bundle may be created using send.\n"+applyDescription :: String+applyDescription = "Apply a patch bundle created by `darcs send'." +applyHelp :: String+applyHelp =+ "The `darcs apply' command takes a patch bundle and attempts to insert\n" +++ "it into the current repository.  In addition to invoking it directly\n" +++ "on bundles created by `darcs send', it is used internally by `darcs\n" +++ "push' and `darcs put' on the remote end of an SSH connection.\n" +++ "\n" +++ "If no file is supplied, the bundle is read from standard input.\n" +++ "\n" +++ "If given an email instead of a patch bundle, Darcs will look for the\n" +++ "bundle as a MIME attachment to that email.  Currently this will fail\n" +++ "if the MIME boundary is rewritten, such as in Courier and Mail.app.\n" +++ "\n" +++ "If the `--reply noreply@example.net' option is used, and the bundle is\n" +++ "attached to an email, Darcs will send a report (indicating success or\n" +++ "failure) to the sender of the bundle (the To field).  The argument to\n" +++ "noreply is the address the report will appear to originate FROM.\n" +++ "\n" +++ "The --cc option will cause the report to be CC'd to another address,\n" +++ "for example `--cc reports@lists.example.net,admin@lists.example.net'.\n" +++ "Using --cc without --reply is undefined.\n" +++ "\n" +++ "If gpg(1) is installed, you can use `--verify pubring.gpg' to reject\n" +++ "bundles that aren't signed by a key in pubring.gpg.\n" +++ "\n" +++ "If --test is supplied and a test is defined (see `darcs setpref'), the\n" +++ "bundle will be rejected if the test fails after applying it.  In that\n" +++ "case, the rejection email from --reply will include the test output.\n"+ stdindefault :: a -> [String] -> IO [String] stdindefault _ [] = return ["-"] stdindefault _ x = return x apply :: DarcsCommand-apply = DarcsCommand {command_name = "apply",-                      command_help = apply_help,-                      command_description = apply_description,-                      command_extra_args = 1,-                      command_extra_arg_help = ["<PATCHFILE>"],-                      command_command = apply_cmd,-                      command_prereq = amInRepository,-                      command_get_arg_possibilities = list_files,-                      command_argdefaults = const stdindefault,-                      command_advanced_options = [reply, DarcsArguments.cc,-                                                  happy_forwarding,-                                                  sendmail_cmd,+apply = DarcsCommand {commandName = "apply",+                      commandHelp = applyHelp ++ "\n" ++ applyHelp',+                      commandDescription = applyDescription,+                      commandExtraArgs = 1,+                      commandExtraArgHelp = ["<PATCHFILE>"],+                      commandCommand = applyCmd,+                      commandPrereq = amInRepository,+                      commandGetArgPossibilities = listFiles,+                      commandArgdefaults = const stdindefault,+                      commandAdvancedOptions = [reply, DarcsArguments.ccApply,+                                                  happyForwarding,+                                                  sendmailCmd,                                                   ignoretimes, nocompress,-                                                  set_scripts_executable, umask_option,-                                                  restrict_paths],-                      command_basic_options = [verify,-                                              all_interactive]++dry_run++-                                              [apply_conflict_options,-                                              use_external_merge,+                                                  setScriptsExecutableOption, umaskOption,+                                                  restrictPaths],+                      commandBasicOptions = [verify,+                                              allInteractive]++dryRun+++                                              [applyConflictOptions,+                                              useExternalMerge,                                               notest,-                                              leave_test_dir,-                                              working_repo_dir]}+                                              leaveTestDir,+                                              workingRepoDir]} -apply_cmd :: [DarcsFlag] -> [String] -> IO ()-apply_cmd _ [""] = fail "Empty filename argument given to apply!"-apply_cmd opts [unfixed_patchesfile] = withRepoLock opts $- \repository -> do+applyCmd :: [DarcsFlag] -> [String] -> IO ()+applyCmd _ [""] = fail "Empty filename argument given to apply!"+applyCmd opts [unfixed_patchesfile] = withRepoLock opts $- \repository -> do   patchesfile <- fixFilePathOrStd opts unfixed_patchesfile   ps <- useAbsoluteOrStd (B.readFile . toFilePath) (B.hGetContents stdin) patchesfile-  am_verbose <- return $ Verbose `elem` opts-  let from_whom = get_from ps+  let from_whom = getFrom ps   us <- read_repo repository-  either_them <- get_patch_bundle opts ps-  them <- case either_them of-          Right (Sealed t) -> return t-          Left er -> do forwarded <- consider_forwarding opts ps+  either_them <- getPatchBundle opts ps+  Sealed them+     <- case either_them of+          Right t -> return t+          Left er -> do forwarded <- considerForwarding opts ps                         if forwarded                           then exitWith ExitSuccess                           else fail er@@ -131,47 +156,57 @@                                 then cannotApplyPartialRepo pinfo ""                                 else cannotApplyMissing pinfo                          Right x -> return x-  when (null $ unsafeUnRL $ head $ unsafeUnRL them') $+  let their_ps = mapFL_FL (n2pia . conscientiously (text ("We cannot apply this patch "+                                                          ++"bundle, since we're missing:") $$))+                 $ reverseRL them'+  (hadConflicts, Sealed their_ps_filtered) <- filterOutConflicts opts us' repository their_ps+  when hadConflicts $ putStrLn "Skipping some patches which would cause conflicts."+  when (nullFL their_ps_filtered) $        do putStr $ "All these patches have already been applied.  " ++                      "Nothing to do.\n"           exitWith ExitSuccess-  let their_ps = mapFL_FL (n2pia . conscientiously (text ("We cannot apply this patch "-                                                          ++"bundle, since we're missing:") $$))-                 $ reverseRL $ head $ unsafeUnRL them'-  with_selected_changes "apply" fixed_opts their_ps $-                            \ (to_be_applied:>_) -> do-   print_dry_run_message_and_exit "apply" opts to_be_applied+  with_selected_changes "apply" fixed_opts Nothing their_ps_filtered $+                            \ (to_be_applied:>_) ->+                                applyItNow opts from_whom repository us' to_be_applied+    where fixed_opts = if Interactive `elem` opts+                         then opts+                         else All : opts+applyCmd _ _ = impossible++applyItNow :: FORALL(p r u t x y z) RepoPatch p =>+             [DarcsFlag] -> String -> Repository p C(r u t)+           -> RL (PatchInfoAnd p) C(x r) -> FL (PatchInfoAnd p) C(x z) -> IO ()+applyItNow opts from_whom repository us' to_be_applied = do+   printDryRunMessageAndExit "apply" opts to_be_applied    when (nullFL to_be_applied) $         do putStrLn "You don't want to apply any patches, so I'm exiting!"            exitWith ExitSuccess    check_paths opts to_be_applied-   redirect_output opts from_whom $ do-    when am_verbose $ putStrLn "We have the following extra patches:"-    when am_verbose $ putDocLn $ vcat $ mapRL description $ head $ unsafeUnRL us'-    when am_verbose $ putStrLn "Will apply the following patches:"-    when am_verbose $ putDocLn $ vcat $ mapFL description to_be_applied+   redirectOutput opts from_whom $ do+    putVerbose opts $ text "We have the following extra patches:"+    putVerbose opts . vcat $ mapRL description us'+    putVerbose opts $ text "Will apply the following patches:"+    putVerbose opts . vcat $ mapFL description to_be_applied     definePatches to_be_applied     Sealed pw <- tentativelyMergePatches repository "apply" opts-                 (reverseRL $ head $ unsafeUnRL us') to_be_applied+                 (reverseRL us') to_be_applied     invalidateIndex repository     withSignalsBlocked $ do finalizeRepositoryChanges repository-                            wait_a_moment -- so work will be more recent than rec                             applyToWorking repository opts pw `catch` \e ->                                 fail ("Error applying patch to working dir:\n" ++ show e)-    sync_repo repository     putStrLn "Finished applying..."-     where fixed_opts = if Interactive `elem` opts-                        then opts-                        else All : opts-           cannotApplyMissing pinfo-               = errorDoc $ text "Cannot apply this patch bundle, since we're missing:"-                         $$ human_friendly pinfo-           cannotApplyPartialRepo pinfo e-               = errorDoc $ text ("Cannot apply this patch bundle, "-                               ++ "this is a \"--partial repository")-                         $$ text "We don't have the following patch:"-                         $$ human_friendly pinfo $$ text e-apply_cmd _ _ = impossible++cannotApplyMissing :: PatchInfo -> a+cannotApplyMissing pinfo+    = errorDoc $ text "Cannot apply this patch bundle, since we're missing:"+      $$ human_friendly pinfo++cannotApplyPartialRepo :: PatchInfo -> String -> a+cannotApplyPartialRepo pinfo e+    = errorDoc $ text ("Cannot apply this patch bundle, "+                       ++ "this is a \"--partial repository")+      $$ text "We don't have the following patch:"+             $$ human_friendly pinfo $$ text e \end{code}  Darcs apply accepts a single argument, which is the name of the patch@@ -184,14 +219,11 @@ --verify \end{options} -If you specify the \verb!--verify PUBRING! option, darcs will check that-the patch was GPG-signed by a key which is in \verb!PUBRING! and will-refuse to apply the patch otherwise.- \begin{code}-get_patch_bundle :: RepoPatch p => [DarcsFlag] -> B.ByteString++getPatchBundle :: RepoPatch p => [DarcsFlag] -> B.ByteString                  -> IO (Either String (SealedPatchSet p))-get_patch_bundle opts fps = do+getPatchBundle opts fps = do     mps <- verifyPS opts $ read_email fps     mops <- verifyPS opts fps     case (mps, mops) of@@ -216,81 +248,28 @@                 stripline p | B.null p = p                             | BC.last p == '\r' = B.init p                             | otherwise = p-\end{code} -\begin{options}---cc, --reply-\end{options}--If you give the \verb!--reply FROM! option to \verb!darcs apply!, it will send the-results of the application to the sender of the patch.  This only works if-the patch is in the form of email with its headers intact, so that darcs-can actually know the origin of the patch.  The reply email will indicate-whether or not the patch was successfully applied.  The \verb!FROM! flag is-the email address that will be used as the ``from'' address when replying.-If the darcs apply is being done automatically, it is important that this-address not be the same as the address at which the patch was received, in-order to avoid automatic email loops.--If you want to also send the apply email to another address (for example,-to create something like a ``commits'' mailing list), you can use the-\verb!--cc! option to specify additional recipients.  Note that the-\verb!--cc! option \emph{requires} the \verb!--reply! option, which-provides the ``From'' address.--The \verb!--reply! feature of apply is intended primarily for two uses.-When used by itself, it is handy for when you want to apply patches sent to-you by other developers so that they will know when their patch has been-applied.  For example, in my \verb!.muttrc! (the config file for my mailer)-I have:-\begin{verbatim}-macro pager A "<pipe-entry>darcs apply --verbose \-        --reply droundy@abridgegame.org --repodir ~/darcs-\end{verbatim}-which allows me to apply a patch to darcs directly from my mailer, with the-originator of that patch being sent a confirmation when the patch is-successfully applied.  NOTE: In an attempt to make sure no one else-can read your email, mutt seems to set the umask-such that patches created with the above macro are not world-readable, so-use it with care.--When used in combination with the \verb!--verify! option, the-\verb!--reply! option allows for a nice pushable repository.  When these-two options are used together, any patches that don't pass the verify will-be forwarded to the \verb!FROM! address of the \verb!--reply! option.  This-allows you to set up a repository so that anyone who is authorized can push-to it and have it automatically applied, but if a stranger pushes to it,-the patch will be forwarded to you.  Please (for your own sake!)\ be certain-that the \verb!--reply FROM! address is different from the one used to send-patches to a pushable repository, since otherwise an unsigned patch will be-forwarded to the repository in an infinite loop.--If you use \verb!darcs apply --verify PUBRING --reply! to create a-pushable repository by applying patches automatically as they are received by-email, you will also want to use the \verb!--dont-allow-conflicts! option.--\begin{options}---dont-allow-conflicts-\end{options}-The \verb!--dont-allow-conflicts! flag causes apply to fail when applying a-patch would cause conflicts.  This flag is recommended on repositories-which will be pushed to or sent to.--\begin{options}---allow-conflicts-\end{options}--\verb!--allow-conflicts! will allow conflicts, but will keep the local and-recorded versions in sync on the repository.  This means the conflict will exist-in both locations until it is resolved.--\begin{options}---mark-conflicts-\end{options}--\verb!--mark-conflicts! will add conflict markers to illustrate the the-conflict.+applyHelp' :: String+applyHelp' =+ "A patch bundle may introduce unresolved conflicts with existing\n" +++ "patches or with the working tree.  By default, Darcs will add conflict\n" +++ "markers (see `darcs mark-conflicts').\n" +++ "\n" +++ "The --allow-conflicts option will skip conflict marking; this is\n" +++ "useful when you want to treat a repository as just a bunch of patches,\n" +++ "such as using `darcs pull --union' to download of your co-workers\n" +++ "patches before going offline.\n" +++ "\n" +++ "This can mess up unrecorded changes in the working tree, forcing you\n" +++ "to resolve the conflict immediately.  To simply reject bundles that\n" +++ "introduce unresolved conflicts, using the --dont-allow-conflicts\n" +++ "option.  Making this the default in push-based workflows is strongly\n" +++ "recommended.\n" +++ "\n" +++ "Unlike most Darcs commands, `darcs apply' defaults to --all.  Use the\n" +++ "--interactive option to pick which patches to apply from a bundle.\n" +\end{code} \begin{options} --external-merge \end{options}@@ -300,16 +279,6 @@ subsection~\ref{resolution}.  \begin{options}---all, --interactive-\end{options}--If you provide the \verb!--interactive! flag, darcs will-ask you for each change in the patch bundle whether or not you wish to-apply that change.  The opposite is the \verb!--all! flag, which can be-used to override an \verb!interactive! which might be set in your-``defaults'' file.--\begin{options} --sendmail-command \end{options} @@ -326,17 +295,17 @@   \begin{code}-get_from :: B.ByteString -> String-get_from ps = readFrom $ linesPS ps+getFrom :: B.ByteString -> String+getFrom ps = readFrom $ linesPS ps     where readFrom [] = ""           readFrom (x:xs)-           | B.take 5 x == from_start = BC.unpack $ B.drop 5 x+           | B.take 5 x == fromStart = BC.unpack $ B.drop 5 x            | otherwise = readFrom xs -redirect_output :: [DarcsFlag] -> String -> IO a -> IO a-redirect_output opts to doit = ro opts+redirectOutput :: [DarcsFlag] -> String -> IO a -> IO a+redirectOutput opts to doit = ro opts     where-  cc = get_cc opts+  cc = getCc opts   ro [] = doit   ro (Reply f:_) =     withStdoutTemp $ \tempf-> do {a <- doit;@@ -362,7 +331,7 @@ -- To:, Subject:, CC:, and mail body sendSanitizedEmail :: [DarcsFlag] -> String -> String -> String -> String -> String -> IO () sendSanitizedEmail opts file to subject cc mailtext =-    do scmd <- get_sendmail_cmd opts+    do scmd <- getSendmailCmd opts        body <- sanitizeFile mailtext        sendEmail file to subject cc scmd body @@ -384,25 +353,25 @@ throwIO :: Exception -> IO a throwIO e = return $ throw e -forwarding_message :: B.ByteString-forwarding_message = BC.pack $+forwardingMessage :: B.ByteString+forwardingMessage = BC.pack $     "The following patch was either unsigned, or signed by a non-allowed\n"++     "key, or there was a GPG failure.\n" -consider_forwarding :: [DarcsFlag] -> B.ByteString -> IO Bool-consider_forwarding opts m = cf opts (get_cc opts)+considerForwarding :: [DarcsFlag] -> B.ByteString -> IO Bool+considerForwarding opts m = cf opts (getCc opts)     where cf [] _ = return False           cf (Reply t:_) cc =               case break is_from (linesPS m) of               (m1, f:m2) ->-                  let m_lines = forwarding_message:m1 ++ m2+                  let m_lines = forwardingMessage:m1 ++ m2                       m' = unlinesPS m_lines                       f' = BC.unpack (B.drop 5 f) in                       if t == f' || t == init f'                       then return False -- Refuse possible email loop.                       else do-                        scmd <- get_sendmail_cmd opts-                        if HappyForwarding `elem` opts+                        scmd <- getSendmailCmd opts+                        if doHappyForwarding opts                          then resendEmail t scmd m                          else sendEmailDoc f' t "A forwarded darcs patch" cc                                            scmd (Just (empty,empty))@@ -410,22 +379,8 @@                         return True               _ -> return False -- Don't forward emails lacking headers!           cf (_:fs) cc = cf fs cc-          is_from l = B.take 5 l == from_start+          is_from l = B.take 5 l == fromStart -from_start :: B.ByteString-from_start = BC.pack "From:"+fromStart :: B.ByteString+fromStart = BC.pack "From:" \end{code}--\begin{options}---no-test, --test-\end{options}--If you specify the \verb!--test! option, apply will run the test (if a test-exists) prior to applying the patch.  If the test fails, the patch is not-applied.  In this case, if the \verb!--reply! option was used, the results-of the test are sent in the reply email.  You can also specify the-\verb!--no-test! option, which will override the \verb!--test! option, and-prevent the test from being run.  This is helpful when setting up a-pushable repository, to keep users from running code.--
src/Darcs/Commands/Changes.lhs view
@@ -20,7 +20,8 @@ {-# OPTIONS_GHC -cpp -fglasgow-exts #-} {-# LANGUAGE CPP, PatternGuards #-} -module Darcs.Commands.Changes ( changes ) where+module Darcs.Commands.Changes ( changes, log ) where+import Prelude hiding ( log )  import Data.List ( intersect, sort ) import Data.Maybe ( fromMaybe )@@ -28,96 +29,96 @@  import Darcs.Hopefully ( hopefullyM, info ) import Darcs.Patch.Depends ( slightly_optimize_patchset )-import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias ) import Darcs.Arguments ( DarcsFlag(Context, HumanReadable, MachineReadable,-                                   Interactive, OnlyChangesToFiles, Count,+                                   Interactive, Count,                                    NumberPatches, XMLOutput, Summary,-                                   Reverse, Verbose, Debug),-                         fixSubPaths, changes_format,-                         possibly_remote_repo_dir, get_repourl,-                         working_repo_dir, only_to_files,-                         summary, changes_reverse,-                         match_several_or_range,-                         match_maxcount, maxCount,-                         all_interactive, showFriendly,-                         network_options+                                   Verbose, Debug),+                         fixSubPaths, changesFormat,+                         possiblyRemoteRepoDir, getRepourl,+                         workingRepoDir, onlyToFiles,+                         summary, changesReverse,+                         matchSeveralOrRange,+                         matchMaxcount, maxCount,+                         allInteractive, showFriendly,+                         networkOptions                       )+import Darcs.Flags ( doReverse, showChangesOnlyToFiles ) import Darcs.RepoPath ( toFilePath, rootDirectory ) import Darcs.Patch.FileName ( fp2fn, fn2fp, norm_path ) import Darcs.Repository ( Repository, PatchSet, PatchInfoAnd,-                          get_unrecorded_in_files_unsorted,                           withRepositoryDirectory, ($-), findRepository,-                          read_repo )+                          read_repo, unrecordedChanges ) import Darcs.Patch.Info ( to_xml, showPatchInfo ) import Darcs.Patch.Depends ( get_common_and_uncommon ) import Darcs.Patch.TouchesFiles ( look_touch )-import Darcs.Patch ( RepoPatch, invert, xml_summary, description, apply_to_filepaths,-                     list_touched_files, effect, identity )-import Darcs.Ordered ( (:\/:)(..), RL(..), unsafeFL, unsafeUnRL, concatRL,+import Darcs.Patch ( RepoPatch, invert, xmlSummary, description, applyToFilepaths,+                     listTouchedFiles, effect, identity )+import Darcs.Witnesses.Ordered ( (:\/:)(..), RL(..), unsafeFL, unsafeUnRL, concatRL,                              EqCheck(..), filterFL )-import Darcs.Match ( first_match, second_match,-               match_a_patchread, have_nonrange_match,-               match_first_patchset, match_second_patchset,+import Darcs.Match ( firstMatch, secondMatch,+               matchAPatchread, haveNonrangeMatch,+               matchFirstPatchset, matchSecondPatchset,              )-import Darcs.Commands.Annotate ( created_as_xml )+import Darcs.Commands.Annotate ( createdAsXml ) import Printer ( Doc, putDocLnWith, simplePrinters, (<+>),                  renderString, prefix, text, vcat, vsep,                   ($$), empty, errorDoc, insert_before_lastline ) import Darcs.ColorPrinter ( fancyPrinters ) import Progress ( setProgressMode, debugMessage ) import Darcs.SelectChanges ( view_changes )-import Darcs.Sealed ( unsafeUnseal )+import Darcs.Witnesses.Sealed ( unsafeUnseal ) #include "impossible.h" -changes_description :: String-changes_description = "List patches in the repository."+changesDescription :: String+changesDescription = "List patches in the repository." -changes_help :: String-changes_help =+changesHelp :: String+changesHelp =  "The `darcs changes' command lists the patches that constitute the\n" ++- "current repository.  Without options or arguments, ALL patches will be\n" ++- "listed.\n" ++- "\n" ++ changes_help' ++- "\n" ++ changes_help''+ "current repository or, with --repo, a remote repository.  Without\n" +++ "options or arguments, ALL patches will be listed.\n" +++ "\n" ++ changesHelp' +++ "\n" ++ changesHelp''  changes :: DarcsCommand-changes = DarcsCommand {command_name = "changes",-                        command_help = changes_help,-                        command_description = changes_description,-                        command_extra_args = -1,-                        command_extra_arg_help = ["[FILE or DIRECTORY]..."],-                        command_get_arg_possibilities = return [],-                        command_command = changes_cmd,-                        command_prereq = findRepository,-                        command_argdefaults = nodefaults,-                        command_advanced_options = network_options,-                        command_basic_options = [match_several_or_range,-                                                 match_maxcount,-                                                 only_to_files,-                                                 changes_format,+changes = DarcsCommand {commandName = "changes",+                        commandHelp = changesHelp,+                        commandDescription = changesDescription,+                        commandExtraArgs = -1,+                        commandExtraArgHelp = ["[FILE or DIRECTORY]..."],+                        commandGetArgPossibilities = return [],+                        commandCommand = changesCmd,+                        commandPrereq = findRepository,+                        commandArgdefaults = nodefaults,+                        commandAdvancedOptions = networkOptions,+                        commandBasicOptions = [matchSeveralOrRange,+                                                 matchMaxcount,+                                                 onlyToFiles,+                                                 changesFormat,                                                  summary,-                                                 changes_reverse,-                                                 possibly_remote_repo_dir,-                                                 working_repo_dir,-                                                 all_interactive]}+                                                 changesReverse,+                                                 possiblyRemoteRepoDir,+                                                 workingRepoDir,+                                                 allInteractive]} -changes_cmd :: [DarcsFlag] -> [String] -> IO ()-changes_cmd [Context _] [] = return ()-changes_cmd opts args | Context rootDirectory `elem` opts =-  let repodir = fromMaybe "." (get_repourl opts) in+changesCmd :: [DarcsFlag] -> [String] -> IO ()+changesCmd [Context _] [] = return ()+changesCmd opts args | Context rootDirectory `elem` opts =+  let repodir = fromMaybe "." (getRepourl opts) in   withRepositoryDirectory opts repodir $- \repository -> do   when (args /= []) $ fail "changes --context cannot accept other arguments"-  changes_context repository opts-changes_cmd opts args =-  let repodir = fromMaybe "." (get_repourl opts) in+  changesContext repository opts+changesCmd opts args =+  let repodir = fromMaybe "." (getRepourl opts) in   withRepositoryDirectory opts repodir $- \repository -> do   unless (Debug `elem` opts) $ setProgressMode False   files <- sort `fmap` fixSubPaths opts args   unrec <- if null files then return identity-             else get_unrecorded_in_files_unsorted repository (map (fp2fn . toFilePath) files)+             else unrecordedChanges opts repository files            `catch` \_ -> return identity -- this is triggered when repository is remote-  let filez = map (fn2fp . norm_path . fp2fn) $ apply_to_filepaths (invert unrec) $ map toFilePath files-      filtered_changes p = maybe_reverse $ get_changes_info opts filez p+  let filez = map (fn2fp . norm_path . fp2fn) $ applyToFilepaths (invert unrec) $ map toFilePath files+      filtered_changes p = maybe_reverse $ getChangesInfo opts filez p   debugMessage "About to read the repository..."   patches <- read_repo repository   debugMessage "Done reading the repository."@@ -132,15 +133,15 @@             ps <- read_repo repository -- read repo again to prevent holding onto                                        -- values forced by filtered_changes             putDocLnWith printers $ changelog opts ps $ filtered_changes patches-  where maybe_reverse (xs,b,c) = if Reverse `elem` opts+  where maybe_reverse (xs,b,c) = if doReverse opts                                  then (reverse xs, b, c)                                  else (xs, b, c)   -- FIXME: this prose is unreadable. --twb, 2009-08-changes_help' :: String-changes_help' =- "When given one or more files or directories as an argument, only\n" +++changesHelp' :: String+changesHelp' =+ "When given one or more files or directories as arguments, only\n" ++  "patches which affect those files or directories are listed. This\n" ++  "includes changes that happened to files before they were moved or\n" ++  "renamed.\n" ++@@ -156,18 +157,18 @@  "whereas `darcs changes --last 3 foo.c' will, of the last three\n" ++  "patches, print only those that affect foo.c.\n" -get_changes_info :: RepoPatch p => [DarcsFlag] -> [FilePath] -> PatchSet p+getChangesInfo :: RepoPatch p => [DarcsFlag] -> [FilePath] -> PatchSet p                  -> ([(PatchInfoAnd p, [FilePath])], [FilePath], Doc)-get_changes_info opts plain_fs ps =+getChangesInfo opts plain_fs ps =   case get_common_and_uncommon (p2s,p1s) of-  (_,us:\/:_) -> filter_patches_by_names (maxCount opts) fs $ filter pf $ unsafeUnRL $ concatRL us+  (_,us:\/:_) -> filterPatchesByNames (maxCount opts) fs $ filter pf $ unsafeUnRL us   where fs = map (\x -> "./" ++ x) $ plain_fs-        p1s = if first_match opts then unsafeUnseal $ match_first_patchset opts ps+        p1s = if firstMatch opts then unsafeUnseal $ matchFirstPatchset opts ps                                   else NilRL:<:NilRL-        p2s = if second_match opts then unsafeUnseal $ match_second_patchset opts ps+        p2s = if secondMatch opts then unsafeUnseal $ matchSecondPatchset opts ps                                    else ps-        pf = if have_nonrange_match opts-             then match_a_patchread opts+        pf = if haveNonrangeMatch opts+             then matchAPatchread opts              else \_ -> True  -- | Take a list of filenames and patches and produce a list of@@ -178,30 +179,30 @@ -- limit" -- maxcount, that could be Nothing (return everything) or -- "Just n" -- returns at most n patches touching the file (starting -- from the beginning of the patch list).-filter_patches_by_names :: RepoPatch p =>+filterPatchesByNames :: RepoPatch p =>                            Maybe Int -- ^ maxcount                         -> [FilePath] -- ^ filenames                         -> [PatchInfoAnd p] -- ^ patchlist                         -> ([(PatchInfoAnd p,[FilePath])], [FilePath], Doc)-filter_patches_by_names (Just 0) _ _ = ([], [], empty)-filter_patches_by_names _ _ [] = ([], [], empty)-filter_patches_by_names maxcount [] (hp:ps) =-    (hp, []) -:- filter_patches_by_names (subtract 1 `fmap` maxcount) [] ps-filter_patches_by_names maxcount fs (hp:ps)+filterPatchesByNames (Just 0) _ _ = ([], [], empty)+filterPatchesByNames _ _ [] = ([], [], empty)+filterPatchesByNames maxcount [] (hp:ps) =+    (hp, []) -:- filterPatchesByNames (subtract 1 `fmap` maxcount) [] ps+filterPatchesByNames maxcount fs (hp:ps)     | Just p <- hopefullyM hp =     case look_touch fs (invert p) of     (True, []) -> ([(hp, fs)], fs, empty)-    (True, fs') -> (hp, fs) -:- filter_patches_by_names+    (True, fs') -> (hp, fs) -:- filterPatchesByNames                                 (subtract 1 `fmap` maxcount) fs' ps-    (False, fs') -> filter_patches_by_names maxcount fs' ps-filter_patches_by_names _ _ (hp:_) =+    (False, fs') -> filterPatchesByNames maxcount fs' ps+filterPatchesByNames _ _ (hp:_) =     ([], [], text "Can't find changes prior to:" $$ description hp)  -- | Note, lazy pattern matching is required to make functions like--- filter_patches_by_names lazy in case you are only not interested in+-- filterPatchesByNames lazy in case you are only not interested in -- the first element. E.g.: -----   let (fs, _, _) = filter_patches_by_names ...+--   let (fs, _, _) = filterPatchesByNames ... (-:-) :: a -> ([a],b,c) -> ([a],b,c) x -:- ~(xs,y,z) = (x:xs,y,z) @@ -224,25 +225,25 @@     | otherwise = vsep (map (number_patch description') pis_and_fs)                $$ errstring     where change_with_summary (hp, fs)-              | Just p <- hopefullyM hp = if OnlyChangesToFiles `elem` opts+              | Just p <- hopefullyM hp = if showChangesOnlyToFiles opts                                           then description hp $$ text "" $$                                                indent (showFriendly opts (filterFL xx $ effect p))                                           else showFriendly opts p               | otherwise = description hp                             $$ indent (text "[this patch is unavailable]")-              where xx x = case list_touched_files x of+              where xx x = case listTouchedFiles x of                              ys | null $ ys `intersect` fs -> IsEq                              _ -> NotEq           xml_with_summary hp               | Just p <- hopefullyM hp = insert_before_lastline-                                           (to_xml $ info hp) (indent $ xml_summary p)+                                           (to_xml $ info hp) (indent $ xmlSummary p)           xml_with_summary hp = to_xml (info hp)           indent = prefix "    "           actual_xml_changes = if Summary `elem` opts                                then map xml_with_summary pis                                else map (to_xml.info) pis-          xml_file_names = map (created_as_xml first_change) orig_fs-          first_change = if Reverse `elem` opts+          xml_file_names = map (createdAsXml first_change) orig_fs+          first_change = if doReverse opts                          then info $ head pis                          else info $ last pis           number_patch f x = if NumberPatches `elem` opts@@ -260,8 +261,8 @@           description' = description . fst  -- FIXME: this prose is unreadable. --twb, 2009-08-changes_help'' :: String-changes_help'' =+changesHelp'' :: String+changesHelp'' =  "Three output formats exist.  The default is --human-readable.  You can\n" ++  "also select --context, which is the internal format (as seen in patch\n" ++  "bundles) that can be re-read by Darcs (e.g. `darcs get --context').\n" ++@@ -277,17 +278,20 @@  "WILL be output for a knowledgeable human to recreate the current state\n" ++  "of the repository.\n" -changes_context :: RepoPatch p => Repository p -> [DarcsFlag] -> IO ()-changes_context repository opts = do+changesContext :: RepoPatch p => Repository p -> [DarcsFlag] -> IO ()+changesContext repository opts = do   r <- read_repo repository   putStrLn "\nContext:\n"   when (not $ null (unsafeUnRL r) || null (unsafeUnRL $ head $ unsafeUnRL r)) $     putDocLnWith simplePrinters $ changelog opts' NilRL $-                 get_changes_info opts' []+                 getChangesInfo opts' []                  (headRL (slightly_optimize_patchset r) :<: NilRL)     where opts' = if HumanReadable `elem` opts || XMLOutput `elem` opts                   then opts                   else MachineReadable : opts           headRL (x:<:_) = x           headRL NilRL = impossible++log :: DarcsCommand+log = commandAlias "log" changes \end{code}
src/Darcs/Commands/Check.lhs view
@@ -19,28 +19,33 @@ \begin{code} module Darcs.Commands.Check ( check ) where import Control.Monad ( when )+import Control.Applicative( (<$>) ) import System.Exit ( ExitCode(..), exitWith ) -import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag( Quiet ),-                        partial_check, notest, testByDefault,-                        leave_test_dir, working_repo_dir,+++import Darcs.Commands ( DarcsCommand(..), nodefaults, putInfo )+import Darcs.Arguments ( DarcsFlag(Quiet),+                        partialCheck, notest, testByDefault,+                        leaveTestDir, workingRepoDir, ignoretimes                       )-import Darcs.Repository.Repair( replayRepository,-                              RepositoryConsistency(..) )-import Darcs.Repository ( Repository, amInRepository, withRepository, slurp_recorded,-                          testRecorded )+import Darcs.Flags(willIgnoreTimes)+import Darcs.Repository.Repair( replayRepository, checkIndex+                              , RepositoryConsistency(..) )+import Darcs.Repository ( Repository, amInRepository, withRepository,+                          testRecorded, readRecorded ) import Darcs.Patch ( RepoPatch, showPatch )-import Darcs.Ordered ( FL(..) )-import Darcs.Diff ( unsafeDiff )-import Darcs.Repository.Prefs ( filetype_function )-import Printer ( putDocLn, text, ($$), (<+>) )+import Darcs.Witnesses.Ordered ( FL(..) )+import Darcs.Repository.Prefs ( filetypeFunction )+import Darcs.Diff( treeDiff )+import Printer ( text, ($$), (<+>) ) -check_description :: String-check_description = "Check the repository for consistency." -check_help :: String-check_help =+checkDescription :: String+checkDescription = "Check the repository for consistency."++checkHelp :: String+checkHelp =  "This command verifies that the patches in the repository, when applied\n" ++  "successively to an empty tree, result in the pristine tree.  If not,\n" ++  "the differences are printed and Darcs exits unsucessfully (with a\n" ++@@ -55,51 +60,57 @@  "by `darcs check'.  Use the --no-test option to disable this.\n"  check :: DarcsCommand-check = DarcsCommand {command_name = "check",-                      command_help = check_help,-                      command_description = check_description,-                      command_extra_args = 0,-                      command_extra_arg_help = [],-                      command_command = check_cmd,-                      command_prereq = amInRepository,-                      command_get_arg_possibilities = return [],-                      command_argdefaults = nodefaults,-                      command_advanced_options = [],-                      command_basic_options = [partial_check,+check = DarcsCommand {commandName = "check",+                      commandHelp = checkHelp,+                      commandDescription = checkDescription,+                      commandExtraArgs = 0,+                      commandExtraArgHelp = [],+                      commandCommand = checkCmd,+                      commandPrereq = amInRepository,+                      commandGetArgPossibilities = return [],+                      commandArgdefaults = nodefaults,+                      commandAdvancedOptions = [],+                      commandBasicOptions = [partialCheck,                                               notest,-                                              leave_test_dir,-                                              working_repo_dir+                                              leaveTestDir,+                                              workingRepoDir,+                                               ignoretimes                                              ]} -check_cmd :: [DarcsFlag] -> [String] -> IO ()-check_cmd opts _ = withRepository opts (check' opts)+checkCmd :: [DarcsFlag] -> [String] -> IO ()+checkCmd opts _ = withRepository opts (check' opts)  check' :: (RepoPatch p) => [DarcsFlag] -> Repository p -> IO () check' opts repository = do-    replayRepository repository (testByDefault opts) $ \ state -> do+    failed <- replayRepository repository (testByDefault opts) $ \ state -> do       case state of         RepositoryConsistent -> do-          putInfo $ text "The repository is consistent!"+          putInfo opts $ text "The repository is consistent!"           testRecorded repository-          exitWith ExitSuccess+          return False         BrokenPristine newpris -> do           brokenPristine newpris-          exitWith $ ExitFailure 1+          return True         BrokenPatches newpris _ -> do           brokenPristine newpris-          putInfo $ text "Found broken patches."-          exitWith $ ExitFailure 1-   where +          putInfo opts $ text "Found broken patches."+          return True+    bad_index <- case willIgnoreTimes opts of+                   False -> not <$> checkIndex repository (Quiet `elem` opts)+                   True -> return False+    when bad_index $ putInfo opts $ text "Bad index."+    exitWith $ if failed || bad_index then ExitFailure 1 else ExitSuccess+   where      brokenPristine newpris = do-         putInfo $ text "Looks like we have a difference..."-         mc <- slurp_recorded repository-         ftf <- filetype_function-         putInfo $ case unsafeDiff opts ftf newpris mc of+         putInfo opts $ text "Looks like we have a difference..."+         mc <- readRecorded repository+         ftf <- filetypeFunction+         diff <- treeDiff ftf newpris mc+         putInfo opts $ case diff of                         NilFL -> text "Nothing"                         patch -> text "Difference: " <+> showPatch patch-         putInfo $ text ""+         putInfo opts $ text ""                      $$ text "Inconsistent repository!"-     putInfo s = when (not $ Quiet `elem` opts) $ putDocLn s  \end{code} %% FIXME: this should go in "common options" or something, since
src/Darcs/Commands/Convert.lhs view
@@ -33,47 +33,46 @@ import Data.Maybe ( catMaybes )  import Darcs.Hopefully ( PatchInfoAnd, n2pia, info, hopefully )-import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Commands ( DarcsCommand(..), nodefaults, putInfo, putVerbose ) import Darcs.Arguments ( DarcsFlag( AllowConflicts, NewRepo,-                                    SetScriptsExecutable, UseFormat2, NoUpdateWorking,-                                    Verbose, Quiet ),+                                    SetScriptsExecutable, UseFormat2, NoUpdateWorking),                         reponame,-                        set_scripts_executable,-                        network_options )+                        setScriptsExecutableOption,+                        networkOptions ) import Darcs.Repository ( Repository, withRepoLock, ($-), withRepositoryDirectory, read_repo,-                          createRepository,+                          createRepository, invalidateIndex,                           slurp_recorded, optimizeInventory,                           tentativelyMergePatches, patchSetToPatches,                           createPristineDirectoryTree,-                          revertRepositoryChanges, finalizeRepositoryChanges, sync_repo )+                          revertRepositoryChanges, finalizeRepositoryChanges ) import Darcs.Global ( darcsdir ) import Darcs.Patch ( RealPatch, Patch, Named, showPatch, patch2patchinfo, fromPrims, infopatch,-                     modernize_patch,-                     adddeps, getdeps, effect, flattenFL, is_merger, patchcontents )-import Darcs.Ordered ( FL(..), RL(..), EqCheck(..), (=/\=), bunchFL, mapFL, mapFL_FL,+                     modernizePatch,+                     adddeps, getdeps, effect, flattenFL, isMerger, patchcontents )+import Darcs.Witnesses.Ordered ( FL(..), RL(..), EqCheck(..), (=/\=), bunchFL, mapFL, mapFL_FL,                              concatFL, concatRL, mapRL ) import Darcs.Patch.Info ( pi_rename, pi_tag, is_tag ) import Darcs.Patch.Commute ( public_unravel ) import Darcs.Patch.Real ( mergeUnravelled ) import Darcs.RepoPath ( ioAbsoluteOrRemote, toPath )+import Darcs.Repository.Format(identifyRepoFormat, formatHas, RepoProperty(Darcs2)) import Darcs.Repository.Motd ( show_motd )-import Darcs.Utils ( clarify_errors, askUser )+import Darcs.Utils ( clarifyErrors, askUser ) import Darcs.ProgressPatches ( progressFL )-import Darcs.Sealed ( FlippedSeal(..) )-import Printer ( text, putDocLn, ($$) )+import Darcs.Witnesses.Sealed ( FlippedSeal(..) )+import Printer ( text, ($$) ) import Darcs.ColorPrinter ( traceDoc ) import Darcs.SlurpDirectory ( list_slurpy_files ) import Darcs.Lock ( writeBinFile ) import Workaround ( setExecutable ) import qualified Data.ByteString as B (isPrefixOf, readFile) import qualified Data.ByteString.Char8 as BC (pack)-import Darcs.Gorsvet( invalidateIndex ) -convert_description :: String-convert_description = "Convert a repository from a legacy format."+convertDescription :: String+convertDescription = "Convert a repository from a legacy format." -convert_help :: String-convert_help =+convertHelp :: String+convertHelp =  "The current repository format is called `darcs-2'.  It was introduced\n" ++  "in Darcs 2.0 and became the default for new projects in Darcs 2.2.\n" ++  "The `darcs convert' command allows existing projects to migrate to\n" ++@@ -83,7 +82,7 @@  "repository is created.  It is safe to run this command more than once\n" ++  "on a repository (e.g. for testing), before the final conversion.\n" ++  "\n" ++- convert_help' +++ convertHelp' ++  "\n" ++  "Due to this limitation, migrating a multi-branch project is a little\n" ++  "awkward.  Sorry!  Here is the recommended process:\n" ++@@ -98,8 +97,8 @@  -- | This part of the help is split out because it is used twice: in -- the help string, and in the prompt for confirmation.-convert_help' :: String-convert_help' =+convertHelp' :: String+convertHelp' =  "WARNING: the repository produced by this command is not understood by\n" ++  "Darcs 1.x, and patches cannot be exchanged between repositories in\n" ++  "darcs-1 and darcs-2 formats.\n" ++@@ -111,31 +110,38 @@  "than once.)\n"  convert :: DarcsCommand-convert = DarcsCommand {command_name = "convert",-                    command_help = convert_help,-                    command_description = convert_description,-                    command_extra_args = -1,-                    command_extra_arg_help = ["<SOURCE>", "[<DESTINATION>]"],-                    command_command = convert_cmd,-                    command_prereq = \_ -> return $ Right (),-                    command_get_arg_possibilities = return [],-                    command_argdefaults = nodefaults,-                    command_advanced_options = network_options,-                    command_basic_options = [reponame,set_scripts_executable]}+convert = DarcsCommand {commandName = "convert",+                    commandHelp = convertHelp,+                    commandDescription = convertDescription,+                    commandExtraArgs = -1,+                    commandExtraArgHelp = ["<SOURCE>", "[<DESTINATION>]"],+                    commandCommand = convertCmd,+                    commandPrereq = \_ -> return $ Right (),+                    commandGetArgPossibilities = return [],+                    commandArgdefaults = nodefaults,+                    commandAdvancedOptions = networkOptions,+                    commandBasicOptions = [reponame,setScriptsExecutableOption]} -convert_cmd :: [DarcsFlag] -> [String] -> IO ()-convert_cmd opts [inrepodir, outname] = convert_cmd (NewRepo outname:opts) [inrepodir]-convert_cmd orig_opts [inrepodir] = do-  putStrLn convert_help'+convertCmd :: [DarcsFlag] -> [String] -> IO ()+convertCmd opts [inrepodir, outname] = convertCmd (NewRepo outname:opts) [inrepodir]+convertCmd orig_opts [inrepodir] = do+  +  typed_repodir <- ioAbsoluteOrRemote inrepodir+  let repodir = toPath typed_repodir+  +  --test for converting darcs-2 repository+  Right format <- identifyRepoFormat repodir -- just fail in case of error +  when (formatHas Darcs2 format) $ fail "Repository is already in darcs 2 format."+    +  putStrLn convertHelp'   let vow = "I understand the consequences of my action"   putStrLn "Please confirm that you have read and understood the above"   vow' <- askUser ("by typing `" ++ vow ++ "': ")   when (vow' /= vow) $ fail "User didn't understand the consequences."+     let opts = UseFormat2:orig_opts-  typed_repodir <- ioAbsoluteOrRemote inrepodir-  let repodir = toPath typed_repodir   show_motd opts repodir-  mysimplename <- make_repo_name opts repodir+  mysimplename <- makeRepoName opts repodir   createDirectory mysimplename   setCurrentDirectory mysimplename   createRepository opts@@ -170,7 +176,7 @@                      Just d -> p : concatMap fixDep d                      Nothing -> [p]           convertOne :: Patch -> FL RealPatch-          convertOne x | is_merger x = case mergeUnravelled $ public_unravel $ modernize_patch x of+          convertOne x | isMerger x = case mergeUnravelled $ public_unravel $ modernizePatch x of                                        Just (FlippedSeal y) ->                                            case effect y =/\= effect x of                                            IsEq -> y :>: NilFL@@ -200,45 +206,40 @@       invalidateIndex repository       revertable $ createPristineDirectoryTree repository "."       when (SetScriptsExecutable `elem` opts) $-               do putVerbose $ text "Making scripts executable"+               do putVerbose opts $ text "Making scripts executable"                   c <- list_slurpy_files `fmap` slurp_recorded repository                   let setExecutableIfScript f =                             do contents <- B.readFile f                                when (BC.pack "#!" `B.isPrefixOf` contents) $ do-                                 putVerbose $ text ("Making executable: " ++ f)+                                 putVerbose opts $ text ("Making executable: " ++ f)                                  setExecutable f True                   mapM_ setExecutableIfScript c-      sync_repo repository       optimizeInventory repository-      putInfo $ text "Finished converting."-      where am_verbose = Verbose `elem` orig_opts-            am_informative = not $ Quiet `elem` orig_opts-            putVerbose s = when am_verbose $ putDocLn s-            putInfo s = when am_informative $ putDocLn s-            revertable x = x `clarify_errors` unlines+      putInfo opts $ text "Finished converting."+      where revertable x = x `clarifyErrors` unlines                   ["An error may have left your new working directory an inconsistent",                    "but recoverable state. You should be able to make the new",                    "repository consistent again by running darcs revert -a."] -convert_cmd _ _ = fail "You must provide 'convert' with either one or two arguments."+convertCmd _ _ = fail "You must provide 'convert' with either one or two arguments." -make_repo_name :: [DarcsFlag] -> FilePath -> IO String-make_repo_name (NewRepo n:_) _ =+makeRepoName :: [DarcsFlag] -> FilePath -> IO String+makeRepoName (NewRepo n:_) _ =     do exists <- doesDirectoryExist n        file_exists <- doesFileExist n        if exists || file_exists           then fail $ "Directory or file named '" ++ n ++ "' already exists."           else return n-make_repo_name (_:as) d = make_repo_name as d-make_repo_name [] d =+makeRepoName (_:as) d = makeRepoName as d+makeRepoName [] d =   case dropWhile (=='.') $ reverse $        takeWhile (\c -> c /= '/' && c /= ':') $        dropWhile (=='/') $ reverse d of-  "" -> modify_repo_name "anonymous_repo"-  base -> modify_repo_name base+  "" -> modifyRepoName "anonymous_repo"+  base -> modifyRepoName base -modify_repo_name :: String -> IO String-modify_repo_name name =+modifyRepoName :: String -> IO String+modifyRepoName name =     if head name == '/'     then mrn name (-1)     else do cwd <- getCurrentDirectory
src/Darcs/Commands/Diff.lhs view
@@ -20,7 +20,7 @@ {-# OPTIONS_GHC -cpp #-} {-# LANGUAGE CPP #-} -module Darcs.Commands.Diff ( diff_command ) where+module Darcs.Commands.Diff ( diffCommand ) where  import System.FilePath.Posix ( takeFileName ) import System.Directory ( setCurrentDirectory )@@ -32,58 +32,61 @@ import Darcs.External( diff_program ) import CommandLine ( parseCmd ) import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag(DiffFlags, Unified, DiffCmd,+import Darcs.Arguments ( DarcsFlag(DiffFlags, DiffCmd,                                    LastN, AfterPatch),-                        match_range, store_in_memory, -                        diff_cmd_flag, diffflags, unidiff,-                         working_repo_dir, fixSubPaths,+                        matchRange, storeInMemory, +                        diffCmdFlag, diffflags, unidiff,+                         workingRepoDir, fixSubPaths,                       )+import Darcs.Flags ( isUnified ) import Darcs.Hopefully ( info ) import Darcs.RepoPath ( toFilePath, sp2fn )-import Darcs.Match ( get_partial_first_match, get_partial_second_match,-                     first_match, second_match,-                     match_first_patchset, match_second_patchset )+import Darcs.Match ( getPartialFirstMatch, getPartialSecondMatch,+                     firstMatch, secondMatch,+                     matchFirstPatchset, matchSecondPatchset ) import Darcs.Repository ( PatchSet, withRepository, ($-), read_repo,                           amInRepository, slurp_recorded_and_unrecorded,                           createPristineDirectoryTree,                           createPartialsPristineDirectoryTree ) import Darcs.SlurpDirectory ( get_path_list, writeSlurpy ) import Darcs.Patch ( RepoPatch )-import Darcs.Ordered ( mapRL, concatRL )+import Darcs.Witnesses.Ordered ( mapRL, concatRL ) import Darcs.Patch.Info ( PatchInfo, human_friendly ) import Darcs.External ( execPipeIgnoreError, clonePaths ) import Darcs.Lock ( withTempDir )-import Darcs.Sealed ( unsafeUnseal )+import Darcs.Witnesses.Sealed ( unseal ) import Printer ( Doc, putDoc, vcat, empty, ($$) ) #include "impossible.h" -diff_description :: String-diff_description = "Create a diff between two versions of the repository."+#include "gadts.h" -diff_help :: String-diff_help =+diffDescription :: String+diffDescription = "Create a diff between two versions of the repository."++diffHelp :: String+diffHelp =  "Diff can be used to create a diff between two versions which are in your\n"++  "repository.  Specifying just --from-patch will get you a diff against\n"++  "your working copy.  If you give diff no version arguments, it gives\n"++  "you the same information as whatsnew except that the patch is\n"++  "formatted as the output of a diff command\n" -diff_command :: DarcsCommand-diff_command = DarcsCommand {command_name = "diff",-                             command_help = diff_help,-                             command_description = diff_description,-                             command_extra_args = -1,-                             command_extra_arg_help+diffCommand :: DarcsCommand+diffCommand = DarcsCommand {commandName = "diff",+                             commandHelp = diffHelp,+                             commandDescription = diffDescription,+                             commandExtraArgs = -1,+                             commandExtraArgHelp                                  = ["[FILE or DIRECTORY]..."],-                             command_command = diff_cmd,-                             command_prereq = amInRepository,-                             command_get_arg_possibilities = return [],-                             command_argdefaults = nodefaults,-                             command_advanced_options = [],-                             command_basic_options = [match_range,-                                                     diff_cmd_flag,+                             commandCommand = diffCmd,+                             commandPrereq = amInRepository,+                             commandGetArgPossibilities = return [],+                             commandArgdefaults = nodefaults,+                             commandAdvancedOptions = [],+                             commandBasicOptions = [matchRange,+                                                     diffCmdFlag,                                                      diffflags, unidiff,-                                                     working_repo_dir, store_in_memory]}+                                                     workingRepoDir, storeInMemory]} \end{code}  \begin{options}@@ -110,31 +113,32 @@ to your \verb!_darcs/prefs/defaults! file.  \begin{code}-get_diff_opts :: [DarcsFlag] -> [String]-get_diff_opts [] = []-get_diff_opts (Unified:fs) = "-u" : get_diff_opts fs-get_diff_opts (DiffFlags f:fs) = f : get_diff_opts fs-get_diff_opts (_:fs) = get_diff_opts fs+getDiffOpts :: [DarcsFlag] -> [String]+getDiffOpts opts | isUnified opts = "-u" : get_nonU_diff_opts opts+                   | otherwise      = get_nonU_diff_opts opts+    where get_nonU_diff_opts (DiffFlags f:fs) = f : get_nonU_diff_opts fs+          get_nonU_diff_opts (_:fs) = get_nonU_diff_opts fs+          get_nonU_diff_opts [] = [] -has_diff_cmd_flag :: [DarcsFlag] -> Bool-has_diff_cmd_flag (DiffCmd _:_) = True-has_diff_cmd_flag (_:t) = has_diff_cmd_flag t-has_diff_cmd_flag []  = False+hasDiffCmdFlag :: [DarcsFlag] -> Bool+hasDiffCmdFlag (DiffCmd _:_) = True+hasDiffCmdFlag (_:t) = hasDiffCmdFlag t+hasDiffCmdFlag []  = False  -- | Returns the command we should use for diff as a tuple (command, arguments). -- This will either be whatever the user specified via --diff-command  or the -- default 'diff_program'.  Note that this potentially involves parsing the -- user's diff-command, hence the possibility for failure with an exception.-get_diff_cmd_and_args :: String -> [DarcsFlag] -> String -> String+getDiffCmdAndArgs :: String -> [DarcsFlag] -> String -> String                       -> Either String (String, [String])-get_diff_cmd_and_args cmd opts f1 f2 = helper opts where+getDiffCmdAndArgs cmd opts f1 f2 = helper opts where   helper (DiffCmd c:_) =     case parseCmd [ ('1', f1) , ('2', f2) ] c of     Left err        -> Left $ show err     Right ([],_)    -> bug $ "parseCmd should never return empty list"     Right ((h:t),_) -> Right (h,t)   helper [] = -- if no command specified, use 'diff'-    Right (cmd, ("-rN":get_diff_opts opts++[f1,f2]))+    Right (cmd, ("-rN":getDiffOpts opts++[f1,f2]))   helper (_:t) = helper t \end{code} @@ -173,8 +177,8 @@ Note also that the \verb!--diff-opts! flag is ignored if you use this option.  \begin{code}-diff_cmd :: [DarcsFlag] -> [String] -> IO ()-diff_cmd opts args = withRepository opts $- \repository -> do+diffCmd :: [DarcsFlag] -> [String] -> IO ()+diffCmd opts args = withRepository opts $- \repository -> do   when (not (null [i | LastN i <- opts])        && not (null [p | AfterPatch p <- opts])        ) $@@ -190,15 +194,15 @@   withTempDir ("old-"++thename) $ \odir -> do     setCurrentDirectory formerdir     withTempDir ("new-"++thename) $ \ndir -> do-    if first_match opts+    if firstMatch opts        then withCurrentDirectory odir $-            get_partial_first_match repository opts path_list+            getPartialFirstMatch repository opts path_list        else if null path_list             then createPristineDirectoryTree repository (toFilePath odir)             else createPartialsPristineDirectoryTree repository path_list (toFilePath odir)-    if second_match opts+    if secondMatch opts        then withCurrentDirectory ndir $-            get_partial_second_match repository opts path_list+            getPartialSecondMatch repository opts path_list        else do (_, s) <- slurp_recorded_and_unrecorded repository                let ps = concatMap (get_path_list s . toFilePath) path_list                if null path_list@@ -212,15 +216,15 @@                                (takeFileName (toFilePath odir) ++ "/" ++ toFilePath f)                                (takeFileName (toFilePath ndir) ++ "/" ++ toFilePath f)) fs     morepatches <- read_repo repository-    putDoc $ changelog (get_diff_info opts morepatches)+    putDoc $ changelog (getDiffInfo opts morepatches)             $$ thediff     where rundiff :: String -> String -> IO Doc           rundiff f1 f2 = do             cmd <- diff_program-            case get_diff_cmd_and_args cmd opts f1 f2 of+            case getDiffCmdAndArgs cmd opts f1 f2 of              Left err -> fail err              Right (d_cmd, d_args) ->-              let other_diff = has_diff_cmd_flag opts in+              let other_diff = hasDiffCmdFlag opts in               do when other_diff $ putStrLn $                    "Running command '" ++ unwords (d_cmd:d_args) ++ "'"                  output <- execPipeIgnoreError d_cmd d_args empty@@ -229,15 +233,14 @@                     return ()                  return output -get_diff_info :: RepoPatch p => [DarcsFlag] -> PatchSet p -> [PatchInfo]-get_diff_info opts ps =-    let pi1s = mapRL info $ concatRL $ if first_match opts-                                       then unsafeUnseal $ match_first_patchset opts ps-                                       else ps-        pi2s = mapRL info $ concatRL $ if second_match opts-                                       then unsafeUnseal $ match_second_patchset opts ps-                                       else ps-        in pi2s \\ pi1s+getDiffInfo :: RepoPatch p => [DarcsFlag] -> PatchSet p C(x) -> [PatchInfo]+getDiffInfo opts ps =+    let infos = mapRL info . concatRL+        handle (match_cond, do_match)+          | match_cond opts = unseal infos (do_match opts ps)+          | otherwise = infos ps+    in handle (secondMatch, matchSecondPatchset)+         \\ handle (firstMatch, matchFirstPatchset)  changelog :: [PatchInfo] -> Doc changelog pis = vcat $ map human_friendly pis
src/Darcs/Commands/Dist.lhs view
@@ -26,30 +26,30 @@ import Data.Char ( isAlphaNum ) import Control.Monad ( when ) -import Darcs.Commands ( DarcsCommand(DarcsCommand, command_name, command_help,-                        command_description, command_extra_args,-                        command_extra_arg_help, command_command,-                        command_prereq, command_get_arg_possibilities,-                        command_argdefaults,-                        command_advanced_options, command_basic_options),+import Darcs.Commands ( DarcsCommand(DarcsCommand, commandName, commandHelp,+                        commandDescription, commandExtraArgs,+                        commandExtraArgHelp, commandCommand,+                        commandPrereq, commandGetArgPossibilities,+                        commandArgdefaults,+                        commandAdvancedOptions, commandBasicOptions),                         nodefaults )-import Darcs.Arguments ( DarcsFlag(Verbose, DistName), distname_option,-                         working_repo_dir, match_one, store_in_memory,+import Darcs.Arguments ( DarcsFlag(Verbose, DistName), distnameOption,+                         workingRepoDir, matchOne, storeInMemory,                          fixSubPaths )-import Darcs.Match ( get_nonrange_match, have_nonrange_match )+import Darcs.Match ( getNonrangeMatch, haveNonrangeMatch ) import Darcs.Repository ( amInRepository, withRepoReadLock, ($-), --withRecorded,                           createPartialsPristineDirectoryTree )-import Darcs.Repository.Prefs ( get_prefval )+import Darcs.Repository.Prefs ( getPrefval ) import Darcs.Lock ( withTemp, withTempDir, readBinFile ) import Darcs.RepoPath ( AbsolutePath, toFilePath ) import Darcs.Utils ( withCurrentDirectory ) import Exec ( exec, Redirect(..) ) -dist_description :: String-dist_description = "Create a distribution tarball."+distDescription :: String+distDescription = "Create a distribution tarball." -dist_help :: String-dist_help =+distHelp :: String+distHelp =  "The `darcs dist' command creates a compressed archive (a `tarball') in\n" ++  "the repository's root directory, containing the recorded state of the\n" ++  "working tree (unrecorded changes and the _darcs directory are\n" ++@@ -81,26 +81,26 @@  -}  dist :: DarcsCommand-dist = DarcsCommand {command_name = "dist",-                     command_help = dist_help,-                     command_description = dist_description,-                     command_extra_args = 0,-                     command_extra_arg_help = [],-                     command_command = dist_cmd,-                     command_prereq = amInRepository,-                     command_get_arg_possibilities = return [],-                     command_argdefaults = nodefaults,-                     command_advanced_options = [],-                     command_basic_options = [distname_option,-                                              working_repo_dir,-                                              match_one,-                                              store_in_memory]}+dist = DarcsCommand {commandName = "dist",+                     commandHelp = distHelp,+                     commandDescription = distDescription,+                     commandExtraArgs = 0,+                     commandExtraArgHelp = [],+                     commandCommand = distCmd,+                     commandPrereq = amInRepository,+                     commandGetArgPossibilities = return [],+                     commandArgdefaults = nodefaults,+                     commandAdvancedOptions = [],+                     commandBasicOptions = [distnameOption,+                                              workingRepoDir,+                                              matchOne,+                                              storeInMemory]} -dist_cmd :: [DarcsFlag] -> [String] -> IO ()-dist_cmd opts args = withRepoReadLock opts $- \repository -> do-  distname <- get_dist_name opts+distCmd :: [DarcsFlag] -> [String] -> IO ()+distCmd opts args = withRepoReadLock opts $- \repository -> do+  distname <- getDistName opts   verb <- return $ Verbose `elem` opts-  predist <- get_prefval "predist"+  predist <- getPrefval "predist"   formerdir <- getCurrentDirectory   path_list <- if null args                then return [""]@@ -110,12 +110,12 @@     withTempDir "darcsdist" $ \tempdir -> do       setCurrentDirectory (formerdir)       withTempDir (toFilePath tempdir </> takeFileName distname) $ \ddir -> do-        if have_nonrange_match opts-          then withCurrentDirectory ddir $ get_nonrange_match repository opts+        if haveNonrangeMatch opts+          then withCurrentDirectory ddir $ getNonrangeMatch repository opts           else createPartialsPristineDirectoryTree repository path_list (toFilePath ddir)         ec <- case predist of Nothing -> return ExitSuccess                               Just pd -> system pd-        if (ec == ExitSuccess) then do_dist verb tarfile tempdir ddir resultfile+        if (ec == ExitSuccess) then doDist verb tarfile tempdir ddir resultfile             else                 do                 putStrLn "Dist aborted due to predist failure"@@ -124,8 +124,8 @@ -- | This function performs the actual distribution action itself. -- NB - it does /not/ perform the pre-dist, that should already -- have completed successfully before this is invoked.-do_dist :: Bool -> FilePath -> AbsolutePath -> AbsolutePath -> FilePath -> IO ()-do_dist verb tarfile tempdir ddir resultfile = do+doDist :: Bool -> FilePath -> AbsolutePath -> AbsolutePath -> FilePath -> IO ()+doDist verb tarfile tempdir ddir resultfile = do   setCurrentDirectory (toFilePath tempdir)   exec "tar" ["-cf", "-", safename $ takeFileName $ toFilePath ddir]              (Null, File tarfile, AsIs)@@ -141,16 +141,16 @@     safename n@(c:_) | isAlphaNum c  = n     safename n = "./" ++ n -guess_repo_name :: IO String-guess_repo_name = do+guessRepoName :: IO String+guessRepoName = do   pwd <- getCurrentDirectory   if '/' `elem` pwd      then return $ reverse $ takeWhile (/='/') $ reverse pwd      else return "cantguessreponame" -get_dist_name :: [DarcsFlag] -> IO String-get_dist_name (DistName dn:_) = return dn-get_dist_name (_:fs) = get_dist_name fs-get_dist_name _ = guess_repo_name+getDistName :: [DarcsFlag] -> IO String+getDistName (DistName dn:_) = return dn+getDistName (_:fs) = getDistName fs+getDistName _ = guessRepoName \end{code} 
src/Darcs/Commands/GZCRCs.lhs view
@@ -1,19 +1,24 @@ %  Copyright (C) 2009 Ganesh Sittampalam %-%  This program is free software; you can redistribute it and/or modify-%  it under the terms of the GNU General Public License as published by-%  the Free Software Foundation; either version 2, or (at your option)-%  any later version.+% Permission is hereby granted, free of charge, to any person+% obtaining a copy of this software and associated documentation+% files (the "Software"), to deal in the Software without+% restriction, including without limitation the rights to use, copy,+% modify, merge, publish, distribute, sublicense, and/or sell copies+% of the Software, and to permit persons to whom the Software is+% furnished to do so, subject to the following conditions: %-%  This program is distributed in the hope that it will be useful,-%  but WITHOUT ANY WARRANTY; without even the implied warranty of-%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-%  GNU General Public License for more details.+% The above copyright notice and this permission notice shall be+% included in all copies or substantial portions of the Software. %-%  You should have received a copy of the GNU General Public License-%  along with this program; see the file COPYING.  If not, write to-%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,-%  Boston, MA 02110-1301, USA.+% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+% BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+% ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+% CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+% SOFTWARE.  \subsection{darcs gzcrcs} \darcsCommand{gzcrcs}@@ -21,7 +26,7 @@ {-# LANGUAGE CPP #-} module Darcs.Commands.GZCRCs ( gzcrcs, doCRCWarnings ) where -import Control.Arrow ( (***) )+import Control.Arrow ( first ) import Control.Monad ( when, unless ) import Control.Monad.Trans ( liftIO ) import Control.Monad.Writer ( runWriterT, tell )@@ -33,10 +38,11 @@  import System.Directory ( getDirectoryContents, doesFileExist, doesDirectoryExist ) import System.Exit ( ExitCode(..), exitWith )+import Data.IORef ( newIORef, readIORef, writeIORef )  import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag( Quiet, Verbose, Check, Repair, JustThisRepo ),-                        check_or_repair, working_repo_dir, just_this_repo+                        checkOrRepair, workingRepoDir, justThisRepo                       ) import Darcs.Repository ( Repository, amInRepository, withRepository ) import Darcs.Patch ( RepoPatch )@@ -52,30 +58,16 @@ import Darcs.Repository.Cache ( Cache(..), writable, isthisrepo, hashedFilePath, allHashedDirs )  -#ifdef HAVE_HASKELL_ZLIB import Darcs.Global ( getCRCWarnings, resetCRCWarnings ) import ByteStringUtils ( gzDecompress )-#else--- These functions aren't available unless we have the Haskell zlib.--- The gzcrcs command shouldn't be enabled in this case, but we would--- still like to typecheck this module as much as possible so we include--- dummy versions -noChecking :: String -> a-noChecking what = error $ "Darcs.Commands.GZCRCs." ++ what ++ ": gz CRC checking is not possible unless " ++-                          "darcs has been built with the Haskell zlib. This code should be unreachable."-getCRCWarnings :: IO [FilePath]-getCRCWarnings = noChecking "getCRCWarnings"-resetCRCWarnings :: IO ()-resetCRCWarnings = noChecking "resetCRCWarnings"-gzDecompress :: Maybe Int -> BL.ByteString -> ([B.ByteString], Bool)-gzDecompress = noChecking "gzDecompress"-#endif -gzcrcs_description :: String-gzcrcs_description = "Check or repair the CRCs of compressed files in the repository."+#include "gadts.h" -gzcrcs_help :: String-gzcrcs_help = formatText+gzcrcsDescription :: String+gzcrcsDescription = "Check or repair the CRCs of compressed files in the repository."++gzcrcsHelp :: String+gzcrcsHelp = formatText   [    "Versions of darcs >=1.0.4 and <2.2.0 had a bug that caused compressed files " ++    "with bad CRCs (but valid data) to be written out. CRCs were not checked on " ++@@ -109,7 +101,7 @@ para w = para'   where para' [] = []         para' xs = uncurry (:) $ para'' w xs-        para'' r (x:xs) | w == r || length x < r = ((x:) *** id) $ para'' (r - length x - 1) xs+        para'' r (x:xs) | w == r || length x < r = first (x:) $ para'' (r - length x - 1) xs         para'' _ xs = ([], para' xs)  -- |This is designed for use in an atexit handler, e.g. in Darcs.RunCommand@@ -126,32 +118,33 @@       when verbose $ putStrLn $ unlines ("The following corrupt files were found:":files)  gzcrcs :: DarcsCommand-gzcrcs = DarcsCommand {command_name = "gzcrcs",-                       command_help = gzcrcs_help,-                       command_description = gzcrcs_description,-                       command_extra_args = 0,-                       command_extra_arg_help = [],-                       command_command = gzcrcs_cmd,-                       command_prereq = amInRepository,-                       command_get_arg_possibilities = return [],-                       command_argdefaults = nodefaults,-                       command_advanced_options = [],-                       command_basic_options = [check_or_repair,-                                                just_this_repo,-                                                working_repo_dir+gzcrcs = DarcsCommand {commandName = "gzcrcs",+                       commandHelp = gzcrcsHelp,+                       commandDescription = gzcrcsDescription,+                       commandExtraArgs = 0,+                       commandExtraArgHelp = [],+                       commandCommand = gzcrcsCmd,+                       commandPrereq = amInRepository,+                       commandGetArgPossibilities = return [],+                       commandArgdefaults = nodefaults,+                       commandAdvancedOptions = [],+                       commandBasicOptions = [checkOrRepair,+                                                justThisRepo,+                                                workingRepoDir                                                ]} -gzcrcs_cmd :: [DarcsFlag] -> [String] -> IO ()-gzcrcs_cmd opts _ | Check `elem` opts || Repair `elem` opts = withRepository opts (gzcrcs' opts)-gzcrcs_cmd _ _ = error "You must specify --check or --repair for gzcrcs"+gzcrcsCmd :: [DarcsFlag] -> [String] -> IO ()+gzcrcsCmd opts _ | Check `elem` opts || Repair `elem` opts = withRepository opts (gzcrcs' opts)+gzcrcsCmd _ _ = error "You must specify --check or --repair for gzcrcs" -#ifdef GADT_WITNESSES-gzcrcs' :: (RepoPatch p) => [DarcsFlag] -> Repository p r u t -> IO ()-#else-gzcrcs' :: (RepoPatch p) => [DarcsFlag] -> Repository p -> IO ()-#endif+gzcrcs'+   :: (RepoPatch p) => [DarcsFlag] -> Repository p C(r u t) -> IO () gzcrcs' opts repo = do   let Ca locs = extractCache repo+  -- Somewhat ugly IORef use here because it's convenient, would be nicer+  -- to pre-filter the list of locs to check and then decide whether to+  -- print the message up front.+  warnRelatedRepos <- newIORef (JustThisRepo `notElem` opts)   ((), Any checkFailed) <- runWriterT $ flip mapM_ locs $ \loc -> do     unless (JustThisRepo `elem` opts && not (isthisrepo loc)) $ do      let w = writable loc@@ -159,6 +152,11 @@         let dir = hashedFilePath loc hdir ""         exists <- liftIO $ doesDirectoryExist dir         when exists $ do+           liftIO $ do+              warn <- readIORef warnRelatedRepos+              when (warn && not (isthisrepo loc)) $ do+                 writeIORef warnRelatedRepos False+                 putInfo $ text "Also checking related repos and caches; use --just-this-repo to disable."            liftIO $ putInfo $ text $ "Checking " ++ dir ++ (if w then "" else " (readonly)")            files <- liftIO $ getDirectoryContents dir            ((), Sum count) <- runWriterT $ flip mapM_ files $ \file -> do
src/Darcs/Commands/Get.lhs view
@@ -28,21 +28,22 @@ import Data.Maybe ( isJust ) import Control.Monad ( when ) -import Darcs.Commands ( DarcsCommand(..), nodefaults, command_alias )+import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias, putInfo ) import Darcs.Arguments ( DarcsFlag( NewRepo, Partial, Lazy,                                     UseFormat2, UseOldFashionedInventory, UseHashedInventory,-                                    SetScriptsExecutable, Quiet, OnePattern ),-                        get_context, get_inventory_choices,+                                    SetScriptsExecutable, OnePattern ),+                        getContext, getInventoryChoices,                         partial, reponame,-                        match_one_context, set_default, set_scripts_executable, nolinks,-                        network_options )+                        matchOneContext, setDefault, setScriptsExecutableOption, nolinks,+                        networkOptions ) import Darcs.Repository ( Repository, withRepository, ($-), withRepoLock, identifyRepositoryFor, read_repo,                           createPristineDirectoryTree,                           tentativelyRemovePatches, patchSetToPatches, patchSetToRepository,                           copyRepository, tentativelyAddToPending,-                          finalizeRepositoryChanges, sync_repo, setScriptsExecutable )+                          finalizeRepositoryChanges, setScriptsExecutable+                        , invalidateIndex ) import Darcs.Repository.Format ( identifyRepoFormat, RepoFormat,-                                 RepoProperty ( Darcs2, HashedInventory ), format_has )+                                 RepoProperty ( Darcs2, HashedInventory ), formatHas ) import Darcs.Repository.DarcsRepo ( write_inventory ) import qualified Darcs.Repository.DarcsRepo as DR ( read_repo ) import Darcs.Repository ( PatchSet, SealedPatchSet, copy_oldrepo_patches,@@ -51,31 +52,30 @@ import Darcs.Repository.Checkpoint ( write_checkpoint_patch, get_checkpoint ) import Darcs.Patch ( RepoPatch, Patch, apply, patch2patchinfo, invert,                      effect, description )-import Darcs.Ordered ( (:\/:)(..), RL(..), unsafeUnRL, mapRL, concatRL, reverseRL, lengthFL )+import Darcs.Witnesses.Ordered ( (:\/:)(..), RL(..), mapRL, concatRL, reverseRL, lengthFL ) import Darcs.External ( copyFileOrUrl, Cachable(..) ) import Darcs.Patch.Depends ( get_common_and_uncommon, get_patches_beyond_tag )-import Darcs.Repository.Prefs ( set_defaultrepo )+import Darcs.Repository.Prefs ( setDefaultrepo ) import Darcs.Repository.Motd ( show_motd ) import Darcs.Repository.Pristine ( identifyPristine, createPristineFromWorking, ) import Darcs.SignalHandler ( catchInterrupt ) import Darcs.Commands.Init ( initialize )-import Darcs.Match ( have_patchset_match, get_one_patchset )+import Darcs.Match ( havePatchsetMatch, getOnePatchset ) import Darcs.Utils ( catchall, formatPath, withCurrentDirectory, prettyError ) import Progress ( debugMessage )-import Printer ( text, vcat, errorDoc, ($$), Doc, putDocLn, )+import Printer ( text, vcat, errorDoc, ($$) ) import Darcs.Lock ( writeBinFile ) import Darcs.RepoPath ( toFilePath, toPath, ioAbsoluteOrRemote)-import Darcs.Sealed ( Sealed(..), unsafeUnflippedseal )+import Darcs.Witnesses.Sealed ( Sealed(..), unsafeUnflippedseal ) import Darcs.Global ( darcsdir ) import English ( englishNum, Noun(..) )-import Darcs.Gorsvet( invalidateIndex ) #include "impossible.h" -get_description :: String-get_description = "Create a local copy of a repository."+getDescription :: String+getDescription = "Create a local copy of a repository." -get_help :: String-get_help =+getHelp :: String+getHelp =  "Get creates a local copy of a repository.  The optional second\n" ++  "argument specifies a destination directory for the new copy; if\n" ++  "omitted, it is inferred from the source location.\n" ++@@ -100,10 +100,10 @@  "Darcs get will not copy unrecorded changes to the source repository's\n" ++  "working tree.\n" ++  "\n" ++- get_help_tag +++ getHelpTag ++  "\n" ++  -- The remaining help text covers backwards-compatibility options.- get_help_partial +++ getHelpPartial ++  "\n" ++  "A repository created by `darcs get' will be in the best available\n" ++  "format: it will be able to exchange patches with the source\n" ++@@ -112,31 +112,31 @@  "is required.\n"  get :: DarcsCommand-get = DarcsCommand {command_name = "get",-                    command_help = get_help,-                    command_description = get_description,-                    command_extra_args = -1,-                    command_extra_arg_help = ["<REPOSITORY>", "[<DIRECTORY>]"],-                    command_command = get_cmd,-                    command_prereq = contextExists,-                    command_get_arg_possibilities = return [],-                    command_argdefaults = nodefaults,-                    command_advanced_options = network_options ++-                                               command_advanced_options initialize,-                    command_basic_options = [reponame,+get = DarcsCommand {commandName = "get",+                    commandHelp = getHelp,+                    commandDescription = getDescription,+                    commandExtraArgs = -1,+                    commandExtraArgHelp = ["<REPOSITORY>", "[<DIRECTORY>]"],+                    commandCommand = getCmd,+                    commandPrereq = contextExists,+                    commandGetArgPossibilities = return [],+                    commandArgdefaults = nodefaults,+                    commandAdvancedOptions = networkOptions +++                                               commandAdvancedOptions initialize,+                    commandBasicOptions = [reponame,                                             partial,-                                            match_one_context,-                                            set_default,-                                            set_scripts_executable,+                                            matchOneContext,+                                            setDefault,+                                            setScriptsExecutableOption,                                              nolinks,-                                             get_inventory_choices]}+                                             getInventoryChoices]}  clone :: DarcsCommand-clone = command_alias "clone" get+clone = commandAlias "clone" get -get_cmd :: [DarcsFlag] -> [String] -> IO ()-get_cmd opts [inrepodir, outname] = get_cmd (NewRepo outname:opts) [inrepodir]-get_cmd opts [inrepodir] = do+getCmd :: [DarcsFlag] -> [String] -> IO ()+getCmd opts [inrepodir, outname] = getCmd (NewRepo outname:opts) [inrepodir]+getCmd opts [inrepodir] = do   debugMessage "Starting work on get..."   typed_repodir <- ioAbsoluteOrRemote inrepodir   let repodir = toPath typed_repodir@@ -146,24 +146,24 @@   rfsource <- case rfsource_or_e of Left e -> fail e                                     Right x -> return x   debugMessage $ "Found the format of "++repodir++"..."-  mysimplename <- make_repo_name opts repodir+  mysimplename <- makeRepoName opts repodir   createDirectory mysimplename   setCurrentDirectory mysimplename-  when (format_has Darcs2 rfsource && UseOldFashionedInventory `elem` opts) $-    putInfo $ text "Warning: 'old-fashioned-inventory' is ignored with a darcs-2 repository\n"-  let opts' = if format_has Darcs2 rfsource+  when (formatHas Darcs2 rfsource && UseOldFashionedInventory `elem` opts) $+    putInfo opts $ text "Warning: 'old-fashioned-inventory' is ignored with a darcs-2 repository\n"+  let opts' = if formatHas Darcs2 rfsource               then UseFormat2:opts               else if not (UseOldFashionedInventory `elem` opts)                    then UseHashedInventory:filter (/= UseFormat2) opts                    else UseOldFashionedInventory:filter (/= UseFormat2) opts   createRepository opts'   debugMessage "Finished initializing new directory."-  set_defaultrepo repodir opts+  setDefaultrepo repodir opts    rf_or_e <- identifyRepoFormat "."   rf <- case rf_or_e of Left e -> fail e                         Right x -> return x-  if format_has HashedInventory rf -- refactor this into repository+  if formatHas HashedInventory rf -- refactor this into repository     then writeBinFile (darcsdir++"/hashed_inventory") ""     else write_inventory "." (NilRL:<:NilRL :: PatchSet Patch) @@ -172,48 +172,60 @@     then withRepository opts $- \repository -> do       debugMessage "Using economical get --to-match handling"       fromrepo <- identifyRepositoryFor  repository repodir-      Sealed patches_to_get <- get_one_patchset fromrepo opts+      Sealed patches_to_get <- getOnePatchset fromrepo opts       patchSetToRepository fromrepo patches_to_get opts       debugMessage "Finished converting selected patch set to new repository"-    else copy_repo_and_go_to_chosen_version opts repodir rfsource rf putInfo-        where am_informative = not $ Quiet `elem` opts-              putInfo s = when am_informative $ putDocLn s--get_cmd _ _ = fail "You must provide 'get' with either one or two arguments."+    else copyRepoAndGoToChosenVersion opts repodir rfsource rf+getCmd _ _ = fail "You must provide 'get' with either one or two arguments." --- | called by get_cmd+-- | called by getCmd -- assumes that the target repo of the get is the current directory, and that an inventory in the -- right format has already been created.-copy_repo_and_go_to_chosen_version :: [DarcsFlag] -> String -> RepoFormat -> RepoFormat -> (Doc -> IO ()) -> IO ()-copy_repo_and_go_to_chosen_version opts repodir rfsource rf putInfo = do-  copy_repo `catchInterrupt` (putInfo $ text "Using lazy repository.")-  withRepository opts $- \repository -> go_to_chosen_version repository putInfo opts-  putInfo $ text "Finished getting."+copyRepoAndGoToChosenVersion :: [DarcsFlag] -> String -> RepoFormat -> RepoFormat -> IO ()+copyRepoAndGoToChosenVersion opts repodir rfsource rf = do+  copy_repo `catchInterrupt` (when (formatHas HashedInventory rfsource)+                                   (putInfo opts $ text "Using lazy repository."))+  withRepository opts $- \repository -> goToChosenVersion repository opts+  putInfo opts $ text "Finished getting."       where copy_repo =                 withRepository opts $- \repository -> do-                  if format_has HashedInventory rf || format_has HashedInventory rfsource-                     then do debugMessage "Identifying and copying repository..."-                             identifyRepositoryFor repository repodir >>= copyRepository-                             when (SetScriptsExecutable `elem` opts) setScriptsExecutable-                     else copy_repo_old_fashioned repository opts repodir+                  let hashUs   = formatHas HashedInventory rf+                      hashThem = formatHas HashedInventory rfsource+                  case () of _ | hashUs && hashThem -> do+                                   debugMessage "Identifying and copying repository..."+                                   copyRepoHashed repository+                               | hashUs -> do+                                   putInfo opts $  text "Converting old-fashioned repository to hashed format..."+                                               $$ text "*******************************************************************************"+                                               $$ text "Fetching a hashed repository would be faster.  Perhaps you could persuade"+                                               $$ text "the maintainer to run darcs optimize --upgrade with darcs 2.4.0 or higher?"+                                               $$ text "*******************************************************************************"+                                   copyRepoHashed repository+                               | hashThem -> do+                                   putInfo opts $ text "Fetching a hashed repository as an old-fashioned one..."+                                   copyRepoHashed repository+                               | otherwise -> copyRepoOldFashioned repository opts repodir+            copyRepoHashed repository =+              do identifyRepositoryFor repository repodir >>= copyRepository+                 when (SetScriptsExecutable `elem` opts) setScriptsExecutable -make_repo_name :: [DarcsFlag] -> FilePath -> IO String-make_repo_name (NewRepo n:_) _ =+makeRepoName :: [DarcsFlag] -> FilePath -> IO String+makeRepoName (NewRepo n:_) _ =     do exists <- doesDirectoryExist n        file_exists <- doesFileExist n        if exists || file_exists           then fail $ "Directory or file named '" ++ n ++ "' already exists."           else return n-make_repo_name (_:as) d = make_repo_name as d-make_repo_name [] d =+makeRepoName (_:as) d = makeRepoName as d+makeRepoName [] d =   case dropWhile (=='.') $ reverse $        takeWhile (\c -> c /= '/' && c /= ':') $        dropWhile (=='/') $ reverse d of-  "" -> modify_repo_name "anonymous_repo"-  base -> modify_repo_name base+  "" -> modifyRepoName "anonymous_repo"+  base -> modifyRepoName base -modify_repo_name :: String -> IO String-modify_repo_name name =+modifyRepoName :: String -> IO String+modifyRepoName name =     if head name == '/'     then mrn name (-1)     else do cwd <- getCurrentDirectory@@ -232,8 +244,8 @@        else mrn n $ i+1     where thename = if i == -1 then n else n++"_"++show i -get_help_tag :: String-get_help_tag =+getHelpTag :: String+getHelpTag =  "It is often desirable to make a copy of a repository that excludes\n" ++  "some patches.  For example, if releases are tagged then `darcs get\n" ++  "--tag .' would make a copy of the repository as at the latest release.\n" ++@@ -254,27 +266,27 @@  contextExists :: [DarcsFlag] -> IO (Either String ()) contextExists opts =-   case get_context opts of+   case getContext opts of      Nothing -> return $ Right ()      Just f  -> do exists <- doesFileExist $ toFilePath f                    if exists                       then return $ Right ()                       else return . Left $ "Context file "++toFilePath f++" does not exist" -go_to_chosen_version :: RepoPatch p => Repository p -> (Doc -> IO ())+goToChosenVersion :: RepoPatch p => Repository p                      -> [DarcsFlag] -> IO ()-go_to_chosen_version repository putInfo opts =-    when (have_patchset_match opts) $ do+goToChosenVersion repository opts =+    when (havePatchsetMatch opts) $ do        debugMessage "Going to specified version..."        patches <- read_repo repository-       Sealed context <- get_one_patchset repository opts+       Sealed context <- getOnePatchset repository opts        let (_,us':\/:them') = get_common_and_uncommon (patches, context)        case them' of-           NilRL:<:NilRL -> return ()+           NilRL -> return ()            _ -> errorDoc $ text "Missing these patches from context:"-                        $$ (vcat $ mapRL description $ head $ unsafeUnRL them')-       let ps = patchSetToPatches us'-       putInfo $ text $ "Unapplying " ++ (show $ lengthFL ps) ++ " " +++                        $$ (vcat $ mapRL description them')+       let ps = patchSetToPatches (us':<:NilRL)+       putInfo opts $ text $ "Unapplying " ++ (show $ lengthFL ps) ++ " " ++                    (englishNum (lengthFL ps) (Noun "patch") "")        invalidateIndex repository        withRepoLock opts $- \_ ->@@ -283,11 +295,10 @@               finalizeRepositoryChanges repository               apply opts (invert $ effect ps) `catch` \e ->                   fail ("Couldn't undo patch in working dir.\n" ++ show e)-              sync_repo repository  -get_help_partial :: String-get_help_partial =+getHelpPartial :: String+getHelpPartial =  "If the source repository is in a legacy darcs-1 format and contains at\n" ++  "least one checkpoint (see `darcs optimize'), the --partial option will\n" ++  "create a partial repository.  A partial repository discards history\n" ++@@ -295,8 +306,8 @@  "For modern darcs-2 repositories, --partial is a deprecated alias for\n" ++  "the --lazy option.\n" -copy_repo_old_fashioned :: RepoPatch p => Repository p -> [DarcsFlag] -> String -> IO ()-copy_repo_old_fashioned repository opts repodir = do+copyRepoOldFashioned :: RepoPatch p => Repository p -> [DarcsFlag] -> String -> IO ()+copyRepoOldFashioned repository opts repodir = do   myname <- getCurrentDirectory   fromrepo <- identifyRepositoryFor repository repodir   mch <- get_checkpoint fromrepo@@ -329,7 +340,7 @@        if Partial `elem` opts && isJust mch           then let Sealed p_ch = fromJust mch                    pi_ch = patch2patchinfo p_ch-                   needed_patches = reverseRL $ concatRL $ unsafeUnflippedseal $+                   needed_patches = reverseRL $ unsafeUnflippedseal $                                     get_patches_beyond_tag pi_ch local_patches                    in do write_checkpoint_patch p_ch                          apply opts p_ch `catch`@@ -340,8 +351,5 @@   pristine <- identifyPristine   createPristineFromWorking pristine   setCurrentDirectory myname-  debugMessage "Syncing the repository..."-  sync_repo repository-  debugMessage "Repository synced."  \end{code}
src/Darcs/Commands/Help.lhs view
@@ -18,19 +18,19 @@ \darcsCommand{help} \begin{code} module Darcs.Commands.Help (- help_cmd,- command_control_list, environmentHelp,          -- these are for preproc.hs- print_version,- list_available_commands ) where+ helpCmd,+ commandControlList, environmentHelp,          -- these are for preproc.hs+ printVersion,+ listAvailableCommands ) where -import Darcs.Arguments ( DarcsFlag(..), environmentHelpSendmail )+import Darcs.Arguments ( DarcsFlag(..), environmentHelpEmail, environmentHelpSendmail ) import Darcs.Commands (  CommandArgs(..), CommandControl(..), DarcsCommand(..),- disambiguate_commands, extract_commands, get_command_help, nodefaults, usage )+ disambiguateCommands, extractCommands, getCommandHelp, nodefaults, usage ) import Darcs.External ( viewDoc ) import Darcs.Lock ( environmentHelpTmpdir, environmentHelpKeepTmpdir ) import Darcs.Patch.Match ( helpOnMatchers )-import Darcs.Repository.Prefs ( binaries_file_help, environmentHelpHome )+import Darcs.Repository.Prefs ( binariesFileHelp, environmentHelpHome ) import Darcs.Utils ( withCurrentDirectory, environmentHelpEditor, environmentHelpPager ) import Data.Char ( isAlphaNum, toLower ) import Data.List ( groupBy )@@ -38,59 +38,59 @@ import Printer ( text ) import Ssh ( environmentHelpSsh, environmentHelpScp, environmentHelpSshPort ) import System.Exit ( ExitCode(..), exitWith )-import ThisVersion ( darcs_version )+import Version ( version ) import URL (environmentHelpProxy, environmentHelpProxyPassword) import Workaround ( getCurrentDirectory ) import qualified Darcs.TheCommands as TheCommands -help_description :: String-help_description = "Display help about darcs and darcs commands."+helpDescription :: String+helpDescription = "Display help about darcs and darcs commands." -help_help :: String-help_help =+helpHelp :: String+helpHelp =  "Without arguments, `darcs help' prints a categorized list of darcs\n" ++  "commands and a short description of each one.  With an extra argument,\n" ++  "`darcs help foo' prints detailed help about the darcs command foo.\n"  help :: DarcsCommand-help = DarcsCommand {command_name = "help",-                     command_help = help_help,-                     command_description = help_description,-                     command_extra_args = -1,-                     command_extra_arg_help = ["[<DARCS_COMMAND> [DARCS_SUBCOMMAND]]  "],-                     command_command = \ x y -> help_cmd x y >> exitWith ExitSuccess,-                     command_prereq = \_ -> return $ Right (),-                     command_get_arg_possibilities = return [],-                     command_argdefaults = nodefaults,-                     command_advanced_options = [],-                     command_basic_options = []}+help = DarcsCommand {commandName = "help",+                     commandHelp = helpHelp,+                     commandDescription = helpDescription,+                     commandExtraArgs = -1,+                     commandExtraArgHelp = ["[<DARCS_COMMAND> [DARCS_SUBCOMMAND]]  "],+                     commandCommand = \ x y -> helpCmd x y >> exitWith ExitSuccess,+                     commandPrereq = \_ -> return $ Right (),+                     commandGetArgPossibilities = return [],+                     commandArgdefaults = nodefaults,+                     commandAdvancedOptions = [],+                     commandBasicOptions = []} -help_cmd :: [DarcsFlag] -> [String] -> IO ()-help_cmd _ ["manpage"] = putStr $ unlines manpageLines-help_cmd _ ["patterns"] = viewDoc $ text $ helpOnMatchers-help_cmd _ ["environment"] = viewDoc $ text $ helpOnEnvironment-help_cmd _ [] = viewDoc $ text $ usage command_control_list+helpCmd :: [DarcsFlag] -> [String] -> IO ()+helpCmd _ ["manpage"] = putStr $ unlines manpageLines+helpCmd _ ["patterns"] = viewDoc $ text $ helpOnMatchers+helpCmd _ ["environment"] = viewDoc $ text $ helpOnEnvironment+helpCmd _ [] = viewDoc $ text $ usage commandControlList -help_cmd _ (cmd:args) =-    let disambiguated = disambiguate_commands command_control_list cmd args+helpCmd _ (cmd:args) =+    let disambiguated = disambiguateCommands commandControlList cmd args     in case disambiguated of          Left err -> fail err          Right (cmds,_) ->              let msg = case cmds of-                         CommandOnly c       -> get_command_help Nothing  c-                         SuperCommandOnly c  -> get_command_help Nothing  c-                         SuperCommandSub c s -> get_command_help (Just c) s+                         CommandOnly c       -> getCommandHelp Nothing  c+                         SuperCommandOnly c  -> getCommandHelp Nothing  c+                         SuperCommandSub c s -> getCommandHelp (Just c) s              in viewDoc $ text msg -list_available_commands :: IO ()-list_available_commands =+listAvailableCommands :: IO ()+listAvailableCommands =     do here <- getCurrentDirectory-       is_valid <- sequence $ map-                   (\c-> withCurrentDirectory here $ (command_prereq c) [])-                   (extract_commands command_control_list)-       putStr $ unlines $ map (command_name . fst) $+       is_valid <- mapM+                   (\c-> withCurrentDirectory here $ (commandPrereq c) [])+                   (extractCommands commandControlList)+       putStr $ unlines $ map (commandName . fst) $                 filter (isRight.snd) $-                zip (extract_commands command_control_list) is_valid+                zip (extractCommands commandControlList) is_valid        putStrLn "--help"        putStrLn "--version"        putStrLn "--exact-version"@@ -98,14 +98,17 @@     where isRight (Right _) = True           isRight _ = False -print_version :: IO () -print_version = putStrLn $ "darcs version " ++ darcs_version+printVersion :: IO ()+printVersion = putStrLn $ "darcs version " ++ version  -- avoiding a module import cycle between Help and TheCommands-command_control_list :: [CommandControl] -command_control_list =-  Command_data help : TheCommands.command_control_list+commandControlList :: [CommandControl]+commandControlList =+  CommandData help : TheCommands.commandControlList +-- FIXME: the "grouping" comments below should made subsections in the+-- manpage, as we already do for DarcsCommand groups. --twb, 2009+ -- | Help on each environment variable in which Darcs is interested. environmentHelp :: [([String], [String])] environmentHelp = [@@ -115,6 +118,7 @@  environmentHelpPager,  environmentHelpTmpdir,  environmentHelpKeepTmpdir,+ environmentHelpEmail,  environmentHelpSendmail,  -- Remote Repositories  environmentHelpSsh,@@ -144,7 +148,7 @@ -- | The lines of the manpage to be printed. manpageLines :: [String] manpageLines = [- ".TH DARCS 1 \"" ++ darcs_version ++ "\"",+ ".TH DARCS 1 \"" ++ version ++ "\"",  ".SH NAME",  "darcs \\- an advanced revision control system",  ".SH SYNOPSIS",@@ -190,7 +194,7 @@  unlines environment,  ".SH FILES",  ".SS \"_darcs/prefs/binaries\"",- escape $ unlines binaries_file_help,+ escape $ unlines binariesFileHelp,  ".SH BUGS",  "At http://bugs.darcs.net/ you can find a list of known",  "bugs in Darcs.  Unknown bugs can be reported at that",@@ -209,19 +213,19 @@       -- necessary to avoid blank lines from Hidden_commands, as groff       -- translates them into annoying vertical padding (unlike TeX).       synopsis :: [String]-      synopsis = foldl iter [] command_control_list+      synopsis = foldl iter [] commandControlList           where iter :: [String] -> CommandControl -> [String]-                iter acc (Group_name _) = acc-                iter acc (Hidden_command _) = acc-                iter acc (Command_data c@SuperCommand {}) =+                iter acc (GroupName _) = acc+                iter acc (HiddenCommand _) = acc+                iter acc (CommandData c@SuperCommand {}) =                     acc ++ concatMap-                            (render (command_name c ++ " "))-                            (extract_commands (command_sub_commands c))-                iter acc (Command_data c) = acc ++ render "" c+                            (render (commandName c ++ " "))+                            (extractCommands (commandSubCommands c))+                iter acc (CommandData c) = acc ++ render "" c                 render :: String -> DarcsCommand -> [String]                 render prefix c =-                    [".B darcs " ++ prefix ++ command_name c] ++-                    (map mangle_args $ command_extra_arg_help c) +++                    [".B darcs " ++ prefix ++ commandName c] +++                    (map mangle_args $ commandExtraArgHelp c) ++                     -- In the output, we want each command to be on its own                     -- line, but we don't want blank lines between them.                     -- AFAICT this can only be achieved with the .br@@ -231,20 +235,20 @@       -- | As 'synopsis', but make each group a subsection (.SS), and       -- include the help text for each command.       commands :: [String]-      commands = foldl iter [] command_control_list+      commands = foldl iter [] commandControlList           where iter :: [String] -> CommandControl -> [String]-                iter acc (Group_name x) = acc ++ [".SS \"" ++ x ++ "\""]-                iter acc (Hidden_command _) = acc-                iter acc (Command_data c@SuperCommand {}) =+                iter acc (GroupName x) = acc ++ [".SS \"" ++ x ++ "\""]+                iter acc (HiddenCommand _) = acc+                iter acc (CommandData c@SuperCommand {}) =                     acc ++ concatMap-                            (render (command_name c ++ " "))-                            (extract_commands (command_sub_commands c))-                iter acc (Command_data c) = acc ++ render "" c+                            (render (commandName c ++ " "))+                            (extractCommands (commandSubCommands c))+                iter acc (CommandData c) = acc ++ render "" c                 render :: String -> DarcsCommand -> [String]                 render prefix c =-                    [".B darcs " ++ prefix ++ command_name c] ++-                    (map mangle_args $ command_extra_arg_help c) ++-                    [".RS 4", escape $ command_help c, ".RE"]+                    [".B darcs " ++ prefix ++ commandName c] +++                    (map mangle_args $ commandExtraArgHelp c) +++                    [".RS 4", escape $ commandHelp c, ".RE"]        -- | Now I'm showing off: mangle the extra arguments of Darcs commands       -- so as to use the ideal format for manpages, italic words and roman
src/Darcs/Commands/Init.lhs view
@@ -17,17 +17,17 @@  \darcsCommand{initialize} \begin{code}-module Darcs.Commands.Init ( initialize, initialize_cmd ) where+module Darcs.Commands.Init ( initialize, initializeCmd ) where import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag, working_repo_dir,-                        inventory_choices )+import Darcs.Arguments ( DarcsFlag, workingRepoDir,+                        inventoryChoices ) import Darcs.Repository ( amNotInRepository, createRepository ) -initialize_description :: String-initialize_description = "Make the current directory a repository."+initializeDescription :: String+initializeDescription = "Make the current directory a repository." -initialize_help :: String-initialize_help =+initializeHelp :: String+initializeHelp =  "The `darcs initialize' command turns the current directory into a\n" ++  "Darcs repository.  Any existing files and subdirectories become\n" ++  "UNSAVED changes in the working tree: record them with `darcs add -r'\n" ++@@ -70,20 +70,20 @@  "Initialize is commonly abbreviated to `init'.\n"  initialize :: DarcsCommand-initialize = DarcsCommand {command_name = "initialize",-                         command_help = initialize_help,-                         command_description = initialize_description,-                         command_extra_args = 0,-                         command_extra_arg_help = [],-                         command_prereq = amNotInRepository,-                         command_command = initialize_cmd,-                         command_get_arg_possibilities = return [],-                         command_argdefaults = nodefaults,-                         command_advanced_options = [],-                         command_basic_options = [inventory_choices,-                                                  working_repo_dir]}+initialize = DarcsCommand {commandName = "initialize",+                         commandHelp = initializeHelp,+                         commandDescription = initializeDescription,+                         commandExtraArgs = 0,+                         commandExtraArgHelp = [],+                         commandPrereq = amNotInRepository,+                         commandCommand = initializeCmd,+                         commandGetArgPossibilities = return [],+                         commandArgdefaults = nodefaults,+                         commandAdvancedOptions = [],+                         commandBasicOptions = [inventoryChoices,+                                                  workingRepoDir]} -initialize_cmd :: [DarcsFlag] -> [String] -> IO ()-initialize_cmd opts _ = createRepository opts+initializeCmd :: [DarcsFlag] -> [String] -> IO ()+initializeCmd opts _ = createRepository opts \end{code} 
src/Darcs/Commands/MarkConflicts.lhs view
@@ -25,25 +25,25 @@ import Darcs.SignalHandler ( withSignalsBlocked ) import Control.Monad ( when ) -import Darcs.Commands ( DarcsCommand(..), nodefaults, command_alias )-import Darcs.Arguments ( DarcsFlag, ignoretimes, working_repo_dir, umask_option )+import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias )+import Darcs.Arguments ( DarcsFlag, ignoretimes, workingRepoDir, umaskOption ) import Darcs.Repository ( withRepoLock, ($-), amInRepository, add_to_pending,                     applyToWorking,-                    read_repo, sync_repo, get_unrecorded_unsorted,+                    read_repo, unrecordedChanges                     ) import Darcs.Patch ( invert )-import Darcs.Ordered ( FL(..) )-import Darcs.Sealed ( Sealed(Sealed) )+import Darcs.Witnesses.Ordered ( FL(..) )+import Darcs.Witnesses.Sealed ( Sealed(Sealed) ) import Darcs.Resolution ( patchset_conflict_resolutions ) import Darcs.Utils ( promptYorn ) #include "impossible.h" -markconflicts_description :: String-markconflicts_description =+markconflictsDescription :: String+markconflictsDescription =  "Mark unresolved conflicts in working tree, for manual resolution." -markconflicts_help :: String-markconflicts_help =+markconflictsHelp :: String+markconflictsHelp =  "Darcs requires human guidance to unify changes to the same part of a\n" ++  "source file.  When a conflict first occurs, darcs will add both\n" ++  "choices to the working tree, delimited by the markers `v v v',\n" ++@@ -63,22 +63,22 @@  "alias still exists for backwards-compatibility.\n"  markconflicts :: DarcsCommand-markconflicts = DarcsCommand {command_name = "mark-conflicts",-                              command_help = markconflicts_help,-                              command_description = markconflicts_description,-                              command_extra_args = 0,-                              command_extra_arg_help = [],-                              command_command = markconflicts_cmd,-                              command_prereq = amInRepository,-                              command_get_arg_possibilities = return [],-                              command_argdefaults = nodefaults,-                              command_advanced_options = [umask_option],-                              command_basic_options = [ignoretimes,-                                                      working_repo_dir]}+markconflicts = DarcsCommand {commandName = "mark-conflicts",+                              commandHelp = markconflictsHelp,+                              commandDescription = markconflictsDescription,+                              commandExtraArgs = 0,+                              commandExtraArgHelp = [],+                              commandCommand = markconflictsCmd,+                              commandPrereq = amInRepository,+                              commandGetArgPossibilities = return [],+                              commandArgdefaults = nodefaults,+                              commandAdvancedOptions = [umaskOption],+                              commandBasicOptions = [ignoretimes,+                                                      workingRepoDir]} -markconflicts_cmd :: [DarcsFlag] -> [String] -> IO ()-markconflicts_cmd opts [] = withRepoLock opts $- \repository -> do-  pend <- get_unrecorded_unsorted repository+markconflictsCmd :: [DarcsFlag] -> [String] -> IO ()+markconflictsCmd opts [] = withRepoLock opts $- \repository -> do+  pend <- unrecordedChanges opts repository []   r <- read_repo repository   Sealed res <- return $ patchset_conflict_resolutions r   case res of NilFL -> do putStrLn "No conflicts to mark."@@ -86,21 +86,20 @@               _ -> return ()   case pend of     NilFL -> return ()-    _ ->      do yorn <- promptYorn-                         ("This will trash any unrecorded changes"++-                          " in the working directory.\nAre you sure? ")+    _ ->      do putStrLn ("This will trash any unrecorded changes"+++                          " in the working directory.")+                 yorn <- promptYorn "Are you sure? "                  when (yorn /= 'y') $ exitWith ExitSuccess                  applyToWorking repository opts (invert pend) `catch` \e ->                     bug ("Can't undo pending changes!" ++ show e)-                 sync_repo repository   withSignalsBlocked $     do add_to_pending repository res        applyToWorking repository opts res `catch` \e ->            bug ("Problem marking conflicts in mark-conflicts!" ++ show e)   putStrLn "Finished marking conflicts."-markconflicts_cmd _ _ = impossible+markconflictsCmd _ _ = impossible  -- |resolve is an alias for mark-conflicts. resolve :: DarcsCommand-resolve = command_alias "resolve" markconflicts+resolve = commandAlias "resolve" markconflicts \end{code}
src/Darcs/Commands/Move.lhs view
@@ -25,11 +25,12 @@ import Data.Maybe ( catMaybes ) import Darcs.SignalHandler ( withSignalsBlocked ) -import Darcs.Commands ( DarcsCommand(..), nodefaults, command_alias )-import Darcs.Arguments ( DarcsFlag( AllowCaseOnly, AllowWindowsReserved ),-                         fixSubPaths, working_repo_dir,-                        list_files, allow_problematic_filenames, umask_option,+import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias )+import Darcs.Arguments ( DarcsFlag(),+                         fixSubPaths, workingRepoDir,+                        listFiles, allowProblematicFilenames, umaskOption,                       )+import Darcs.Flags ( doAllowCaseOnly, doAllowWindowsReserved ) import Darcs.RepoPath ( toFilePath, sp2fn ) import System.FilePath.Posix ( (</>), takeFileName ) import System.Directory ( renameDirectory )@@ -37,28 +38,27 @@ import Darcs.Repository ( Repository, withRepoLock, ($-), amInRepository,                     slurp_pending, add_to_pending,                   )-import Darcs.Ordered ( FL(..), unsafeFL )+import Darcs.Witnesses.Ordered ( FL(..), unsafeFL ) import Darcs.Global ( debugMessage ) import qualified Darcs.Patch import Darcs.Patch ( RepoPatch, Prim ) import Darcs.SlurpDirectory ( Slurpy, slurp, slurp_has, slurp_has_anycase,                         slurp_remove, slurp_hasdir, slurp_hasfile )-import Darcs.Patch.FileName ( fp2fn, fn2fp, super_name )+import Darcs.Patch.FileName ( fp2fn, fn2fp, superName ) import qualified System.FilePath.Windows as WindowsFilePath -import Darcs.Gorsvet( invalidateIndex ) #include "impossible.h" -move_description :: String-move_description = "Move or rename files."+moveDescription :: String+moveDescription = "Move or rename files." -move_help :: String-move_help =+moveHelp :: String+moveHelp =  "Darcs cannot reliably distinguish between a file being deleted and a\n" ++  "new one added, and a file being moved.  Therefore Darcs always assumes\n" ++  "the former, and provides the `darcs mv' command to let Darcs know when\n" ++  "you want the latter.  This command will also move the file in the\n" ++- "working tree (unlike `darcs remove').\n" +++ "working tree (unlike `darcs remove'), unless it has already been moved.\n" ++  "\n" ++  -- Note that this paragraph is very similar to one in ./Add.lhs.  "Darcs will not rename a file if another file in the same folder has\n" ++@@ -69,51 +69,50 @@  "unusable on those systems!\n"  move :: DarcsCommand-move = DarcsCommand {command_name = "move",-                   command_help = move_help,-                   command_description = move_description,-                   command_extra_args = -1,-                   command_extra_arg_help = ["<SOURCE> ... <DESTINATION>"],-                   command_command = move_cmd,-                   command_prereq = amInRepository,-                   command_get_arg_possibilities = list_files,-                   command_argdefaults = nodefaults,-                   command_advanced_options = [umask_option],-                   command_basic_options = [allow_problematic_filenames, working_repo_dir]}-move_cmd :: [DarcsFlag] -> [String] -> IO ()-move_cmd _ [] = fail "The `darcs move' command requires at least two arguments."-move_cmd _ [_] = fail "The `darcs move' command requires at least two arguments."+move = DarcsCommand {commandName = "move",+                   commandHelp = moveHelp,+                   commandDescription = moveDescription,+                   commandExtraArgs = -1,+                   commandExtraArgHelp = ["<SOURCE> ... <DESTINATION>"],+                   commandCommand = moveCmd,+                   commandPrereq = amInRepository,+                   commandGetArgPossibilities = listFiles,+                   commandArgdefaults = nodefaults,+                   commandAdvancedOptions = [umaskOption],+                   commandBasicOptions = [allowProblematicFilenames, workingRepoDir]}+moveCmd :: [DarcsFlag] -> [String] -> IO ()+moveCmd _ [] = fail "The `darcs move' command requires at least two arguments."+moveCmd _ [_] = fail "The `darcs move' command requires at least two arguments." -move_cmd opts args@[_,_] = withRepoLock opts $- \repository -> do+moveCmd opts args@[_,_] = withRepoLock opts $- \repository -> do   two_files <- fixSubPaths opts args   [old,new] <- return $ case two_files of                         [_,_] -> two_files                         [_] -> error "Cannot rename a file or directory onto itself!"-                        xs -> bug $ "Problem in move_cmd: " ++ show xs+                        xs -> bug $ "Problem in moveCmd: " ++ show xs   work <- slurp "."   let old_fp = toFilePath old       new_fp = toFilePath new   if slurp_hasdir (sp2fn new) work && slurp_has old_fp work-   then move_to_dir repository opts [old_fp] new_fp+   then moveToDir repository opts [old_fp] new_fp    else do     cur <- slurp_pending repository     addpatch <- check_new_and_old_filenames opts cur work (old_fp,new_fp)-    invalidateIndex repository     withSignalsBlocked $ do       case addpatch of         Nothing -> add_to_pending repository (Darcs.Patch.move old_fp new_fp :>: NilFL)         Just p -> add_to_pending repository (p :>: Darcs.Patch.move old_fp new_fp :>: NilFL)-      move_file_or_dir work old_fp new_fp+      moveFileOrDir work old_fp new_fp -move_cmd opts args =+moveCmd opts args =    withRepoLock opts $- \repository -> do      relpaths <- map toFilePath `fmap` fixSubPaths opts args      let moved = init relpaths          finaldir = last relpaths-     move_to_dir repository opts moved finaldir+     moveToDir repository opts moved finaldir -move_to_dir :: RepoPatch p => Repository p -> [DarcsFlag] -> [FilePath] -> FilePath -> IO ()-move_to_dir repository opts moved finaldir =+moveToDir :: RepoPatch p => Repository p -> [DarcsFlag] -> [FilePath] -> FilePath -> IO ()+moveToDir repository opts moved finaldir =   let movefns = map takeFileName moved       movetargets = map (finaldir </>) movefns       movepatches = zipWith Darcs.Patch.move moved movetargets@@ -121,31 +120,30 @@     cur <- slurp_pending repository     work <- slurp "."     addpatches <- mapM (check_new_and_old_filenames opts cur work) $ zip moved movetargets-    invalidateIndex repository     withSignalsBlocked $ do       add_to_pending repository $ unsafeFL $ catMaybes addpatches ++ movepatches-      zipWithM_ (move_file_or_dir work) moved movetargets+      zipWithM_ (moveFileOrDir work) moved movetargets  check_new_and_old_filenames     :: [DarcsFlag] -> Slurpy -> Slurpy -> (FilePath, FilePath) -> IO (Maybe Prim) check_new_and_old_filenames opts cur work (old,new) = do-  unless (AllowWindowsReserved `elem` opts || WindowsFilePath.isValid new) $+  unless (doAllowWindowsReserved opts || WindowsFilePath.isValid new) $      fail $ "The filename " ++ new ++ " is not valid under Windows.\n" ++             "Use --reserved-ok to allow such filenames."   maybe_add_file_thats_been_moved <-      if slurp_has old work -- We need to move the object-     then do unless (slurp_hasdir (super_name $ fp2fn new) work) $+     then do unless (slurp_hasdir (superName $ fp2fn new) work) $                     fail $ "The target directory " ++-                             (fn2fp $ super_name $ fp2fn new)+++                             (fn2fp $ superName $ fp2fn new)++                              " isn't known in working directory, did you forget to add it?"              when (it_has new work) $ fail $ already_exists "working directory"              return Nothing      else do unless (slurp_has new work) $ fail $ doesnt_exist "working directory"              return $ Just $ Darcs.Patch.addfile old   if slurp_has old cur-     then do unless (slurp_hasdir (super_name $ fp2fn new) cur) $+     then do unless (slurp_hasdir (superName $ fp2fn new) cur) $                     fail $ "The target directory " ++-                             (fn2fp $ super_name $ fp2fn new)+++                             (fn2fp $ superName $ fp2fn new)++                              " isn't known in working directory, did you forget to add it?"              when (it_has new cur) $ fail $ already_exists "repository"      else fail $ doesnt_exist "repository"@@ -154,11 +152,11 @@             let ms2 = slurp_remove (fp2fn old) s             in case ms2 of                Nothing -> False-               Just s2 -> if AllowCaseOnly `elem` opts +               Just s2 -> if doAllowCaseOnly opts                           then slurp_has f s2                           else slurp_has_anycase f s2           already_exists what_slurpy =-              if AllowCaseOnly `elem` opts+              if doAllowCaseOnly opts               then "A file or dir named "++new++" already exists in "                        ++ what_slurpy ++ "."               else "A file or dir named "++new++" (or perhaps differing"++@@ -169,18 +167,18 @@               "There is no file or dir named " ++ old ++               " in the "++ what_slurpy ++ "." -move_file_or_dir :: Slurpy -> FilePath -> FilePath -> IO ()-move_file_or_dir work old new =-    if slurp_hasfile (fp2fn old) work-       then do debugMessage $ unwords ["renameFile",old,new]-               renameFile old new-       else if slurp_hasdir (fp2fn old) work-            then do debugMessage $ unwords ["renameDirectory",old,new]-                    renameDirectory old new-            else return ()+moveFileOrDir :: Slurpy -> FilePath -> FilePath -> IO ()+moveFileOrDir work old new+  | slurp_hasfile (fp2fn old) work =+    do debugMessage $ unwords ["renameFile",old,new]+       renameFile old new+  | slurp_hasdir (fp2fn old) work =+    do debugMessage $ unwords ["renameDirectory",old,new]+       renameDirectory old new+  | otherwise = return ()  mv :: DarcsCommand-mv = command_alias "mv" move+mv = commandAlias "mv" move \end{code}  
src/Darcs/Commands/Optimize.lhs view
@@ -23,60 +23,81 @@ module Darcs.Commands.Optimize ( optimize ) where import Control.Monad ( when, unless ) import Data.Maybe ( isJust )-import Text.Regex ( mkRegex, matchRegex )-import System.Directory ( getDirectoryContents, doesDirectoryExist )+import System.Directory ( getDirectoryContents, doesDirectoryExist, doesFileExist )+import qualified Data.ByteString.Char8 as BS +import Storage.Hashed.Darcs( decodeDarcsSize )+ import Darcs.Hopefully ( hopefully, info ) import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag( Compress, UnCompress,+import Darcs.Arguments ( DarcsFlag( UpgradeFormat, UseHashedInventory,+                                    Compress, UnCompress,                                     NoCompress, Reorder,-                                    TagName, CheckPoint,-                                    Relink, RelinkPristine ),-                        tagname, checkpoint, reorder_patches,-                        uncompress_nocompress,-                        relink, relink_pristine, sibling,+                                    Relink, RelinkPristine, OptimizePristine ),+                        reorderPatches,+                        uncompressNocompress,+                        relink, relinkPristine, sibling,                         flagsToSiblings,-                        working_repo_dir, umask_option,+                        upgradeFormat,+                        workingRepoDir, umaskOption, optimizePristine                       )-import Darcs.Repository.Prefs ( get_preflist )+import Darcs.Repository.Prefs ( getPreflist ) import Darcs.Repository ( Repository, PatchSet, withRepoLock, ($-), withGutsOf,                           read_repo, optimizeInventory, slurp_recorded,                           tentativelyReplacePatches, cleanRepository,-                          amInRepository, finalizeRepositoryChanges )-import Darcs.Repository.Checkpoint ( write_checkpoint )-import Darcs.Ordered ( RL(..), unsafeUnRL, (+<+), mapFL_FL, reverseRL, mapRL, concatRL )-import Darcs.Patch.Info ( PatchInfo, just_name, human_friendly )+                          amInRepository, finalizeRepositoryChanges, replacePristine )+import Darcs.Witnesses.Ordered ( RL(..), unsafeUnRL, (+<+), mapFL_FL, reverseRL, mapRL, concatRL )+import Darcs.Patch.Info ( PatchInfo, just_name ) import Darcs.Patch ( RepoPatch ) import ByteStringUtils ( gzReadFilePS )-import Darcs.Patch.Depends ( deep_optimize_patchset, slightly_optimize_patchset,+import Darcs.Patch.Depends ( slightly_optimize_patchset,                  get_patches_beyond_tag, get_patches_in_tag,                ) import Darcs.Lock ( maybeRelink, gzWriteAtomicFilePS, writeAtomicFilePS ) import Darcs.RepoPath ( toFilePath ) import Darcs.Utils ( withCurrentDirectory ) import Progress ( debugMessage )-import Printer ( putDocLn, text, ($$) ) import Darcs.SlurpDirectory ( slurp, list_slurpy_files ) import Darcs.Repository.Pristine ( identifyPristine, pristineDirectory )-import Darcs.Sealed ( FlippedSeal(..), unsafeUnseal )+import Darcs.Witnesses.Sealed ( FlippedSeal(..), unsafeUnseal ) import Darcs.Global ( darcsdir ) #include "impossible.h"+-- imports for optimize --upgrade; to be tidied+import qualified Data.ByteString as B (empty)+import System.Directory ( createDirectoryIfMissing, removeFile )+import System.FilePath.Posix ( takeExtension, (</>) ) -optimize_description :: String-optimize_description = "Optimize the repository."+import Progress ( beginTedious, endTedious, tediousSize, progress )+import SHA1 ( sha1PS )+import Darcs.Flags ( compression )+import Darcs.Lock ( rm_recursive )+import Darcs.Witnesses.Ordered ( mapFL, mapRL_RL, bunchFL, lengthRL )+import Darcs.ProgressPatches ( progressFL )+import Darcs.Repository.Cache ( hashedDir, HashedDir(HashedPristineDir) )+import Darcs.Repository.Format ( identifyRepoFormat,+                                 createRepoFormat, writeRepoFormat, formatHas,+                                 RepoProperty ( HashedInventory ) )+import qualified Darcs.Repository.HashedRepo as HashedRepo+import Darcs.Repository.Prefs ( getCaches )+import Darcs.Repository.Repair ( replayRepository, RepositoryConsistency(..) )+import Darcs.Repository.State ( readRecorded )+import Darcs.Utils ( catchall )+#include "gadts.h" -optimize_help :: String-optimize_help =+optimizeDescription :: String+optimizeDescription = "Optimize the repository."++optimizeHelp :: String+optimizeHelp =  "The `darcs optimize' command modifies the current repository in an\n" ++  "attempt to reduce its resource requirements.  By default a single\n" ++  "fast, safe optimization is performed; additional optimization\n" ++  "techniques can be enabled by passing options to `darcs optimize'.\n" ++- "\n" ++ optimize_help_inventory +++ "\n" ++ optimizeHelpInventory ++  -- "\n" ++ optimize_help_reorder ++- "\n" ++ optimize_help_relink ++- -- checkpoints and uncompression are least useful, so they are last.- "\n" ++ optimize_help_compression ++- "\n" ++ optimize_help_checkpoint +++ "\n" ++ optimizeHelpRelink +++ -- uncompression is least useful, so it is last.+ "\n" ++ optimizeHelpCompression ++  "\n" ++  "There is one more optimization which CAN NOT be performed by this\n" ++  "command.  Every time your record a patch, a new inventory file is\n" ++@@ -89,102 +110,56 @@  "unversioned files in _darcs/prefs/ (such as _darcs/prefs/author).\n"  optimize :: DarcsCommand-optimize = DarcsCommand {command_name = "optimize",-                         command_help = optimize_help,-                         command_description = optimize_description,-                         command_extra_args = 0,-                         command_extra_arg_help = [],-                         command_command = optimize_cmd,-                         command_prereq = amInRepository,-                         command_get_arg_possibilities = return [],-                         command_argdefaults = nodefaults,-                         command_advanced_options = [uncompress_nocompress, umask_option],-                         command_basic_options = [checkpoint,-                                                 tagname,-                                                 working_repo_dir,-                                                 reorder_patches,+optimize = DarcsCommand {commandName = "optimize",+                         commandHelp = optimizeHelp,+                         commandDescription = optimizeDescription,+                         commandExtraArgs = 0,+                         commandExtraArgHelp = [],+                         commandCommand = optimizeCmd,+                         commandPrereq = amInRepository,+                         commandGetArgPossibilities = return [],+                         commandArgdefaults = nodefaults,+                         commandAdvancedOptions = [uncompressNocompress, umaskOption],+                         commandBasicOptions = [workingRepoDir,+                                                 reorderPatches,                                                  sibling, relink,-                                                 relink_pristine]}+                                                 relinkPristine,+                                                  upgradeFormat,+                                                 optimizePristine]} -optimize_cmd :: [DarcsFlag] -> [String] -> IO ()-optimize_cmd origopts _ = withRepoLock opts $- \repository -> do-    cleanRepository repository-    do_reorder opts repository-    do_optimize_inventory repository-    when (CheckPoint `elem` opts) $ do_checkpoint opts repository-    when (Compress `elem` opts || UnCompress `elem` opts) $ optimize_compression opts-    when (Relink `elem` opts || (RelinkPristine `elem` opts)) $-        do_relink opts repository+optimizeCmd :: [DarcsFlag] -> [String] -> IO ()+optimizeCmd origopts _ = do+    when (UpgradeFormat `elem` origopts) optimizeUpgradeFormat+    withRepoLock opts $- \repository -> do+    if (OptimizePristine `elem` opts)+       then doOptimizePristine repository+       else do cleanRepository repository+               doReorder opts repository+               doOptimizeInventory repository+               when (Compress `elem` opts || UnCompress `elem` opts) $+                    optimizeCompression opts+               when (Relink `elem` opts || (RelinkPristine `elem` opts)) $+                    doRelink opts repository     putStrLn "Done optimizing!"   where opts = if UnCompress `elem` origopts then NoCompress:origopts else origopts-is_tag :: PatchInfo -> Bool-is_tag pinfo = take 4 (just_name pinfo) == "TAG "+isTag :: PatchInfo -> Bool+isTag pinfo = take 4 (just_name pinfo) == "TAG " -optimize_help_inventory :: String-optimize_help_inventory =+optimizeHelpInventory :: String+optimizeHelpInventory =  "The default optimization moves recent patches (those not included in\n" ++  "the latest tag) to the `front', reducing the amount that a typical\n" ++  "remote command needs to download.  It should also reduce the CPU time\n" ++  "needed for some operations.\n" -do_optimize_inventory :: RepoPatch p => Repository p -> IO ()-do_optimize_inventory repository = do+doOptimizeInventory :: RepoPatch p => Repository p -> IO ()+doOptimizeInventory repository = do     debugMessage "Writing out a nice copy of the inventory."     optimizeInventory repository     debugMessage "Done writing out a nice copy of the inventory." -optimize_help_checkpoint :: String-optimize_help_checkpoint =- "If the repository is in `old-fashioned-inventory' format, the `darcs\n" ++- "optimize --checkpoint' command creates a checkpoint of the latest tag.\n" ++- "This checkpoint is used by `darcs get --partial' to create partial\n" ++- "repositories.  With the `--tag' option, checkpoints for older tags can\n" ++- "be created.  In newer repository formats, this feature has been\n" ++- "replaced by `darcs get --lazy', which does not require checkpoints.\n"--do_checkpoint :: RepoPatch p => [DarcsFlag] -> Repository p -> IO ()-do_checkpoint opts repository = do-    mpi <- get_tag opts repository-    case mpi of-      Nothing -> return ()-      Just pinfo -> do putDocLn $ text "Checkpointing tag:"-                               $$ human_friendly pinfo-                       write_checkpoint repository pinfo--get_tag :: RepoPatch p => [DarcsFlag] -> Repository p -> IO (Maybe PatchInfo)-get_tag [] r = do ps <- read_repo r-                  case filter is_tag $ lasts $ mapRL (mapRL info) ps of-                      [] -> do putStrLn "There is no tag to checkpoint!"-                               return Nothing-                      (pinfo:_) -> return $ Just pinfo-get_tag (TagName t:_) r =-    do ps <- read_repo r-       case filter (match_tag t) $ lasts $ mapRL (mapRL info) ps of-         (pinfo:_) -> return $ Just pinfo-         _ -> case filter (match_tag t) $-                   lasts $ mapRL (mapRL info) $ deep_optimize_patchset ps of-              (pinfo:_) -> return $ Just pinfo-              _ -> do putStr "Cannot checkpoint any tag "-                      putStr $ "matching '"++t++"'\n"-                      return Nothing-get_tag (_:fs) r = get_tag fs r--lasts :: [[a]] -> [a]-lasts [] = []-lasts (x@(_:_):ls) = last x : lasts ls-lasts ([]:ls) = lasts ls--mymatch :: String -> PatchInfo -> Bool-mymatch r = match_name $ matchRegex (mkRegex r)-match_name :: (String -> Maybe a) -> PatchInfo -> Bool-match_name ch pinfo = isJust $ ch (just_name pinfo)-match_tag :: String -> PatchInfo -> Bool-match_tag ('^':n) = mymatch $ "^TAG "++n-match_tag n = mymatch $ "^TAG .*"++n---optimize_help_compression :: String-optimize_help_compression =+optimizeHelpCompression :: String+optimizeHelpCompression =  "By default patches are compressed with zlib (RFC 1951) to reduce\n" ++  "storage (and download) size.  In exceptional circumstances, it may be\n" ++  "preferable to avoid compression.  In this case the `--dont-compress'\n" ++@@ -196,8 +171,8 @@  "repositories in the legacy `old-fashioned-inventory' format have a .gz\n" ++  "extension on patch files even when uncompressed.\n" -optimize_compression :: [DarcsFlag] -> IO ()-optimize_compression opts = do+optimizeCompression :: [DarcsFlag] -> IO ()+optimizeCompression opts = do     putStrLn "Optimizing (un)compression of patches..."     do_compress (darcsdir++"/patches")     putStrLn "Optimizing (un)compression of inventories..."@@ -213,8 +188,8 @@           notdot ('.':_) = False           notdot _ = True -optimize_help_relink :: String-optimize_help_relink =+optimizeHelpRelink :: String+optimizeHelpRelink =  "The `darcs optimize --relink' command hard-links patches that the\n" ++  "current repository has in common with its peers.  Peers are those\n" ++  "repositories listed in _darcs/prefs/sources, or defined with the\n" ++@@ -229,10 +204,24 @@  "generally SHOULD NOT be used.  It results in a relatively small space\n" ++  "saving at the cost of making many Darcs commands MUCH slower.\n" -do_relink :: RepoPatch p => [DarcsFlag] -> Repository p -> IO ()-do_relink opts repository =+doOptimizePristine :: RepoPatch p => Repository p -> IO ()+doOptimizePristine repo = do+  hashed <- doesFileExist $ "_darcs" </> "hashed_inventory"+  when hashed $ do+    inv <- BS.readFile ("_darcs" </> "hashed_inventory")+    let linesInv = BS.split '\n' inv+    case linesInv of+      [] -> return ()+      (pris_line:_) ->+          let size = decodeDarcsSize $ BS.drop 9 pris_line+           in when (isJust size) $ do putStrLn "Optimizing hashed pristine..."+                                      readRecorded repo >>= replacePristine repo+                                      cleanRepository repo++doRelink :: RepoPatch p => [DarcsFlag] -> Repository p -> IO ()+doRelink opts repository =     do some_siblings <- return (flagsToSiblings opts)-       defrepolist <- get_preflist "defaultrepo"+       defrepolist <- getPreflist "defaultrepo"        siblings <- return (map toFilePath some_siblings ++ defrepolist)        if (siblings == [])            then putStrLn "No siblings -- no relinking done."@@ -281,7 +270,7 @@ \begin{code}  -- FIXME: someone needs to grovel through the source and determine--- just how optimizeInventory differs from do_reorder.  The following+-- just how optimizeInventory differs from doReorder.  The following -- is purely speculation. --twb, 2009-04 -- optimize_help_reorder :: String -- optimize_help_reorder =@@ -289,26 +278,88 @@ --  "of the default optimization.  It reorders patches with respect to ALL\n" ++ --  "tags, rather than just the latest tag.\n" -do_reorder :: RepoPatch p => [DarcsFlag] -> Repository p -> IO ()-do_reorder opts _ | not (Reorder `elem` opts) = return ()-do_reorder opts repository = do+doReorder :: RepoPatch p => [DarcsFlag] -> Repository p -> IO ()+doReorder opts _ | not (Reorder `elem` opts) = return ()+doReorder opts repository = do     debugMessage "Reordering the inventory."-    psnew <- choose_order `fmap` read_repo repository+    psnew <- chooseOrder `fmap` read_repo repository     let ps = mapFL_FL hopefully $ reverseRL $ head $ unsafeUnRL psnew     withGutsOf repository $ do tentativelyReplacePatches repository opts ps                                finalizeRepositoryChanges repository     debugMessage "Done reordering the inventory." -choose_order :: RepoPatch p => PatchSet p -> PatchSet p-choose_order ps | isJust last_tag =+chooseOrder :: RepoPatch p => PatchSet p -> PatchSet p+chooseOrder ps | isJust last_tag =     case slightly_optimize_patchset $ unsafeUnseal $ get_patches_in_tag lt ps of      ((t:<:NilRL):<:pps) -> case get_patches_beyond_tag lt ps of-                           FlippedSeal (p :<: NilRL) -> (p+<+(t:<:NilRL)) :<: pps-                           _ -> impossible+                           FlippedSeal p -> (p+<+(t:<:NilRL)) :<: pps     _ -> impossible             -    where last_tag = case filter is_tag $ mapRL info $ concatRL ps of+    where last_tag = case filter isTag $ mapRL info $ concatRL ps of                      (t:_) -> Just t                      _ -> Nothing           lt = fromJust last_tag-choose_order ps = ps+chooseOrder ps = ps+\end{code}++The \verb|--upgrade| option for \verb!darcs optimize! performs an inplace+upgrade of your repository to the lastest \emph{compatible} format.  Right now+means that darcs 1 old-fashioned repositories will be upgraded to darcs-1+hashed repositories (and notably, not to darcs 2 repositories as that would not+be compatible; see \verb!darcs convert!).++\begin{code}+optimizeUpgradeFormat :: IO ()+optimizeUpgradeFormat = do+  debugMessage $ "Upgrading to hashed..."+  rf <- either fail return =<< identifyRepoFormat "."+  debugMessage $ "Found our format"+  if formatHas HashedInventory rf+     then putStrLn "No action taken because this repository already is hashed."+     else do putStrLn "Checking repository in case of corruption..."+             withRepoLock [] $- \repository -> do+             state <- replayRepository repository [] return+             case state of+               RepositoryConsistent -> do+                 putStrLn "The repository is consistent."+                 actuallyUpgradeFormat repository+               _repoIsBroken ->+                 putStrLn "Corruption detected! Please run darcs repair first."++actuallyUpgradeFormat :: RepoPatch p => Repository p C(r u t) -> IO ()+actuallyUpgradeFormat repository = do+  -- convert patches/inventory+  patches <- read_repo repository+  let k = "Hashing patch"+  beginTedious k+  tediousSize k (lengthRL $ concatRL patches)+  let patches' = mapRL_RL (mapRL_RL (progress k)) patches+  cache <- getCaches [] "."+  let compr = compression [] -- default compression+  HashedRepo.write_tentative_inventory cache compr patches'+  endTedious k+  -- convert pristine by applying patches+  -- the faster alternative would be to copy pristine, but the apply method is more reliable+  let patchesToApply = progressFL "Applying patch" $ reverseRL $ concatRL $ patches'+  createDirectoryIfMissing False $ darcsdir </> hashedDir HashedPristineDir+  writeFile (darcsdir </> hashedDir HashedPristineDir </> sha1PS B.empty) ""+  sequence_ $ mapFL (HashedRepo.apply_to_tentative_pristine cache []) $ bunchFL 100 patchesToApply+  -- now make it official+  HashedRepo.finalize_tentative_changes repository compr+  writeRepoFormat (createRepoFormat [UseHashedInventory]) (darcsdir </> "format")+  -- clean out old-fashioned junk+  debugMessage "Cleaning out old-fashioned repository files..."+  removeFile   $ darcsdir </> "inventory"+  removeFile   $ darcsdir </> "tentative_inventory"+  rm_recursive (darcsdir </> "pristine") `catchall` rm_recursive (darcsdir </> "current")+  rmGzsIn (darcsdir </> "patches")+  rmGzsIn (darcsdir </> "inventories")+  let checkpointDir = darcsdir </> "checkpoints"+  hasCheckPoints <- doesDirectoryExist checkpointDir+  when hasCheckPoints $ rm_recursive checkpointDir+  putStrLn "Done upgrading!"+ where+  rmGzsIn dir =+    withCurrentDirectory dir $ do+      gzs <- filter ((== ".gz") . takeExtension) `fmap` getDirectoryContents "."+      mapM_ removeFile gzs \end{code}
src/Darcs/Commands/Pull.lhs view
@@ -26,47 +26,48 @@ import Control.Monad ( when ) import Data.List ( nub ) -import Darcs.Commands ( DarcsCommand(..), loggers )+import Darcs.Commands ( DarcsCommand(..), putVerbose, putInfo ) import Darcs.CommandsAux ( check_paths )-import Darcs.Arguments ( DarcsFlag( Verbose, Quiet, DryRun, MarkConflicts, XMLOutput,-                                   Intersection, Complement, AllowConflicts, NoAllowConflicts ),+import Darcs.Arguments ( DarcsFlag( Verbose, DryRun, MarkConflicts,+                                   Intersection, Complement, AllowConflicts,+                                   NoAllowConflicts ),                          nocompress, ignoretimes, definePatches,-                         deps_sel, pull_conflict_options, use_external_merge,-                         match_several, fixUrl,-                         all_interactive, repo_combinator,-                         print_dry_run_message_and_exit,-                         test, dry_run,-                         set_default, summary, working_repo_dir, remote_repo,-                         set_scripts_executable, nolinks,-                         network_options, umask_option, allow_unrelated_repos, restrict_paths+                         depsSel, pullConflictOptions, useExternalMerge,+                         matchSeveral, fixUrl,+                         allInteractive, repoCombinator,+                         printDryRunMessageAndExit,+                         test, dryRun,+                         setDefault, summary, workingRepoDir, remoteRepo,+                         setScriptsExecutableOption, nolinks,+                         networkOptions, umaskOption, allowUnrelatedRepos, restrictPaths                       ) import Darcs.Repository ( Repository, SealedPatchSet, identifyRepositoryFor, withGutsOf,                           amInRepository, withRepoLock, ($-), tentativelyMergePatches,-                          sync_repo, finalizeRepositoryChanges, applyToWorking,-                          read_repo, checkUnrelatedRepos )+                          finalizeRepositoryChanges, applyToWorking,+                          read_repo, checkUnrelatedRepos, invalidateIndex ) import Darcs.Hopefully ( info ) import Darcs.Patch ( RepoPatch, description )-import Darcs.Ordered ( (:>)(..), (:\/:)(..), RL(..), unsafeUnRL, concatRL,+import Darcs.Witnesses.Ordered ( (:>)(..), (:\/:)(..), RL(..),                              mapFL, nullFL, reverseRL, mapRL ) import Darcs.Patch.Permutations ( partitionFL )-import Darcs.SlurpDirectory ( wait_a_moment )-import Darcs.Repository.Prefs ( add_to_preflist, defaultrepo, set_defaultrepo, get_preflist )+import Darcs.Repository.Prefs ( addToPreflist, defaultrepo, setDefaultrepo, getPreflist ) import Darcs.Repository.Motd (show_motd ) import Darcs.Patch.Depends ( get_common_and_uncommon,                              patchset_intersection, patchset_union )-import Darcs.SelectChanges ( with_selected_changes )-import Darcs.Utils ( clarify_errors, formatPath )-import Darcs.Sealed ( Sealed(..), seal )+import Darcs.SelectChanges ( with_selected_changes, filterOutConflicts )+import Darcs.Utils ( clarifyErrors, formatPath )+import Darcs.Witnesses.Sealed ( Sealed(..), seal ) import Printer ( putDocLn, vcat, ($$), text )-import Darcs.Gorsvet( invalidateIndex ) #include "impossible.h" -pull_description :: String-pull_description =+#include "gadts.h"++pullDescription :: String+pullDescription =  "Copy and apply patches from another repository to this one." -pull_help :: String-pull_help =+pullHelp :: String+pullHelp =  "Pull is used to bring changes made in another repository into the current\n"++  "repository (that is, either the one in the current directory, or the one\n"++  "specified with the --repodir option). Pull allows you to bring over all or\n"++@@ -76,99 +77,99 @@  "recently either pushed or pulled.\n"  pull :: DarcsCommand-pull = DarcsCommand {command_name = "pull",-                     command_help = pull_help,-                     command_description = pull_description,-                     command_extra_args = -1,-                     command_extra_arg_help = ["[REPOSITORY]..."],-                     command_command = pull_cmd,-                     command_prereq = amInRepository,-                     command_get_arg_possibilities = get_preflist "repos",-                     command_argdefaults = defaultrepo,-                     command_advanced_options = [repo_combinator,+pull = DarcsCommand {commandName = "pull",+                     commandHelp = pullHelp,+                     commandDescription = pullDescription,+                     commandExtraArgs = -1,+                     commandExtraArgHelp = ["[REPOSITORY]..."],+                     commandCommand = pullCmd,+                     commandPrereq = amInRepository,+                     commandGetArgPossibilities = getPreflist "repos",+                     commandArgdefaults = defaultrepo,+                     commandAdvancedOptions = [repoCombinator,                                                  nocompress, nolinks,                                                  ignoretimes,-                                                 remote_repo,-                                                 set_scripts_executable,-                                                 umask_option,-                                                 restrict_paths] ++-                                                network_options,-                     command_basic_options = [match_several,-                                              all_interactive,-                                              pull_conflict_options,-                                              use_external_merge,-                                              test]++dry_run++[summary,-                                              deps_sel,-                                              set_default,-                                              working_repo_dir,-                                              allow_unrelated_repos]}--pull_cmd :: [DarcsFlag] -> [String] -> IO ()+                                                 remoteRepo,+                                                 setScriptsExecutableOption,+                                                 umaskOption,+                                                 restrictPaths] +++                                                networkOptions,+                     commandBasicOptions = [matchSeveral,+                                              allInteractive,+                                              pullConflictOptions,+                                              useExternalMerge,+                                              test]++dryRun++[summary,+                                              depsSel,+                                              setDefault,+                                              workingRepoDir,+                                              allowUnrelatedRepos]} -pull_cmd opts unfixedrepodirs@(_:_) =-  let (logMessage, _, logDocLn) = loggers opts-      putInfo = if (Quiet `elem` opts || XMLOutput `elem` opts) then \_ -> return () else logDocLn-      putVerbose = if Verbose `elem` opts then putDocLn else \_ -> return ()-  in withRepoLock opts $- \repository -> do+pullCmd :: [DarcsFlag] -> [String] -> IO ()+pullCmd opts unfixedrepodirs@(_:_) = withRepoLock opts $- \repository -> do   here <- getCurrentDirectory   repodirs <- (nub . filter (/= here)) `fmap` mapM (fixUrl opts) unfixedrepodirs   -- Test to make sure we aren't trying to pull from the current repo   when (null repodirs) $         fail "Can't pull from current repository!"-  (Sealed them, Sealed compl) <- read_repos repository opts repodirs-  old_default <- get_preflist "defaultrepo"-  set_defaultrepo (head repodirs) opts-  mapM_ (add_to_preflist "repos") repodirs+  (Sealed them, Sealed compl) <- readRepos repository opts repodirs+  old_default <- getPreflist "defaultrepo"+  setDefaultrepo (head repodirs) opts+  mapM_ (addToPreflist "repos") repodirs   when (old_default == repodirs) $       let pulling = if DryRun `elem` opts then "Would pull" else "Pulling"-      in  putInfo $ text $ pulling++" from "++concatMap formatPath repodirs++"..."+      in  putInfo opts $ text $ pulling++" from "++concatMap formatPath repodirs++"..."   mapM_ (show_motd opts) repodirs   us <- read_repo repository   (common, us' :\/: them'') <- return $ get_common_and_uncommon (us, them)   (_     ,   _ :\/: compl') <- return $ get_common_and_uncommon (us, compl)   checkUnrelatedRepos opts common us them-  let avoided = mapRL info (concatRL compl')-  ps :> _ <- return $ partitionFL (not . (`elem` avoided) . info) $ reverseRL $ concatRL them''+  let avoided = mapRL info compl'+  ps :> _ <- return $ partitionFL (not . (`elem` avoided) . info) $ reverseRL them''   do when (Verbose `elem` opts) $           do case us' of-               (x@(_:<:_):<:_) -> putDocLn $ text "We have the following new (to them) patches:"-                                             $$ (vcat $ mapRL description x)+               (x@(_:<:_)) -> putDocLn $ text "We have the following new (to them) patches:"+                                         $$ (vcat $ mapRL description x)                _ -> return ()              when (not $ nullFL ps) $ putDocLn $ text "They have the following patches to pull:"-                                                 $$ (vcat $ mapFL description ps)-     when (nullFL ps) $ do putInfo $ text "No remote changes to pull in!"-                           definePatches ps+                      $$ (vcat $ mapFL description ps)+     let merge_opts | NoAllowConflicts `elem` opts = opts+                    | AllowConflicts   `elem` opts = opts+                    | otherwise                    = MarkConflicts : opts+     (hadConflicts, Sealed psFiltered) <- filterOutConflicts merge_opts us' repository ps+     when hadConflicts $ putStrLn "Skipping some patches which would cause conflicts."+     when (nullFL psFiltered)+                      $ do putInfo opts $ text "No remote changes to pull in!"+                           definePatches psFiltered                            exitWith ExitSuccess-     with_selected_changes "pull" opts ps $-      \ (to_be_pulled:>_) -> do-      print_dry_run_message_and_exit "pull" opts to_be_pulled-      definePatches to_be_pulled-      when (nullFL to_be_pulled) $ do-          logMessage "You don't want to pull any patches, and that's fine with me!"-          exitWith ExitSuccess-      check_paths opts to_be_pulled-      putVerbose $ text "Getting and merging the following patches:"-      putVerbose $ vcat $ mapFL description to_be_pulled-      let merge_opts | NoAllowConflicts `elem` opts = opts-                     | AllowConflicts   `elem` opts = opts-                     | otherwise                    = MarkConflicts : opts-      Sealed pw <- tentativelyMergePatches repository "pull" merge_opts-                   (reverseRL $ head $ unsafeUnRL us') to_be_pulled-      invalidateIndex repository-      withGutsOf repository $ do finalizeRepositoryChanges repository-                                 -- so work will be more recent than rec:-                                 revertable $ do wait_a_moment-                                                 applyToWorking repository opts pw-      sync_repo repository-      putInfo $ text "Finished pulling and applying."-          where revertable x = x `clarify_errors` unlines-                  ["Error applying patch to the working directory.","",-                   "This may have left your working directory an inconsistent",-                   "but recoverable state. If you had no un-recorded changes",-                   "by using 'darcs revert' you should be able to make your",-                   "working directory consistent again."]-pull_cmd _ [] = fail "No default repository to pull from, please specify one"+     with_selected_changes "pull" opts Nothing psFiltered $+      \ (to_be_pulled:>_) ->+         do+           printDryRunMessageAndExit "pull" opts to_be_pulled+           definePatches to_be_pulled+           when (nullFL to_be_pulled) $ do+                               putStrLn "You don't want to pull any patches, and that's fine with me!"+                               exitWith ExitSuccess+           check_paths opts to_be_pulled+           putVerbose opts $ text "Getting and merging the following patches:"+           putVerbose opts $ vcat $ mapFL description to_be_pulled+           Sealed pw <- tentativelyMergePatches repository "pull" merge_opts+                       (reverseRL us') to_be_pulled+           invalidateIndex repository+           withGutsOf repository $ do finalizeRepositoryChanges repository+                                      revertable $ applyToWorking repository opts pw+           putInfo opts $ text "Finished pulling and applying." +pullCmd _ [] = fail "No default repository to pull from, please specify one"++revertable :: IO a -> IO a+revertable x =+    x `clarifyErrors` unlines+          ["Error applying patch to the working directory.","",+           "This may have left your working directory an inconsistent",+           "but recoverable state. If you had no un-recorded changes",+           "by using 'darcs revert' you should be able to make your",+           "working directory consistent again."]+ {- Read in the specified pull-from repositories.  Perform Intersection, Union, or Complement read.  In patch-theory terms (stated in set algebra, where + is union and & is intersection@@ -182,14 +183,14 @@                               R1 = 1st specified pull repo                               R2, R3, Rn = other specified pull repo -Since Rc is not provided here yet, the result of read_repos is a+Since Rc is not provided here yet, the result of readRepos is a tuple: the first patchset(s) to be complemented against Rc and then the second patchset(s) to be complemented against Rc. -} -read_repos :: RepoPatch p => Repository p -> [DarcsFlag] -> [String] -> IO (SealedPatchSet p,SealedPatchSet p)-read_repos _ _ [] = impossible-read_repos to_repo opts us =+readRepos :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> [String] -> IO (SealedPatchSet p,SealedPatchSet p)+readRepos _ _ [] = impossible+readRepos to_repo opts us =     do rs <- mapM (\u -> do r <- identifyRepositoryFor to_repo u                             ps <- read_repo r                             return $ seal ps) us
src/Darcs/Commands/Push.lhs view
@@ -18,166 +18,173 @@ \darcsCommand{push} \begin{code} {-# OPTIONS_GHC -cpp #-}-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP, TypeOperators #-}  module Darcs.Commands.Push ( push ) where import System.Exit ( exitWith, ExitCode( ExitSuccess, ExitFailure ) ) import Control.Monad ( when ) import Data.Char ( toUpper ) import Workaround ( getCurrentDirectory )-import Darcs.Commands ( DarcsCommand(..) )-import Darcs.Arguments ( DarcsFlag( DryRun, Verbose, Quiet, Sign, SignAs, NoSign, SignSSL ),+import Darcs.Commands ( DarcsCommand(..), putVerbose, putInfo, abortRun )+import Darcs.Arguments ( DarcsFlag( DryRun, Sign, SignAs, NoSign, SignSSL ),                          definePatches,-                         working_repo_dir, summary,-                         print_dry_run_message_and_exit,-                         applyas, match_several, fixUrl, deps_sel,-                         all_interactive, dry_run, nolinks,-                         remote_repo, network_options,-                         set_default, sign, allow_unrelated_repos+                         workingRepoDir, summary,+                         printDryRunMessageAndExit,+                         applyas, matchSeveral, fixUrl, depsSel,+                         allInteractive, dryRun, nolinks,+                         remoteRepo, networkOptions,+                         setDefault, sign, allowUnrelatedRepos                       )-import Darcs.Hopefully ( hopefully )-import Darcs.Repository ( withRepoReadLock, ($-), identifyRepositoryFor,+import Darcs.Hopefully ( PatchInfoAnd, hopefully )+import Darcs.Repository ( Repository, withRepoReadLock, ($-), identifyRepositoryFor,                           read_repo, amInRepository, checkUnrelatedRepos )-import Darcs.Patch ( description )-import Darcs.Ordered ( RL(..), (:>)(..), (:\/:)(..),-                             nullFL, reverseRL, mapFL_FL, unsafeUnRL, mapRL, lengthRL )-import Darcs.Repository.Prefs ( defaultrepo, set_defaultrepo, get_preflist )+import Darcs.Patch ( RepoPatch, description )+import Darcs.Witnesses.Ordered ( (:>)(..), (:\/:)(..), RL, FL, nullRL,+                             nullFL, reverseRL, mapFL_FL, mapRL, lengthRL )+import Darcs.Repository.Prefs ( defaultrepo, setDefaultrepo, getPreflist ) import Darcs.External ( maybeURLCmd, signString ) import Darcs.URL ( is_url, is_file ) import Darcs.SelectChanges ( with_selected_changes ) import Darcs.Utils ( formatPath ) import Darcs.Patch.Depends ( get_common_and_uncommon ) import Darcs.Patch.Bundle ( make_bundle )-import Printer ( vcat, empty, text, ($$), (<+>), putDocLn, errorDoc )+import Darcs.Patch.Patchy( ShowPatch )+import Darcs.Patch.Info ( PatchInfo )+import Darcs.Patch.Set ( PatchSet )+import Printer ( Doc, vcat, empty, text, ($$) ) import Darcs.RemoteApply ( remote_apply, apply_as ) import Darcs.Email ( make_email ) import English (englishNum, Noun(..)) #include "impossible.h" -push_description :: String-push_description =+#include "gadts.h"++pushDescription :: String+pushDescription =  "Copy and apply patches from this repository to another one." -push_help :: String-push_help =+pushHelp :: String+pushHelp =  "Push is the opposite of pull.  Push allows you to copy changes from the\n"++  "current repository into another repository.\n"  push :: DarcsCommand-push = DarcsCommand {command_name = "push",-                     command_help = push_help,-                     command_description = push_description,-                     command_extra_args = 1,-                     command_extra_arg_help = ["[REPOSITORY]"],-                     command_command = push_cmd,-                     command_prereq = amInRepository,-                     command_get_arg_possibilities = get_preflist "repos",-                     command_argdefaults = defaultrepo,-                     command_advanced_options = [applyas,+push = DarcsCommand {commandName = "push",+                     commandHelp = pushHelp,+                     commandDescription = pushDescription,+                     commandExtraArgs = 1,+                     commandExtraArgHelp = ["[REPOSITORY]"],+                     commandCommand = pushCmd,+                     commandPrereq = amInRepository,+                     commandGetArgPossibilities = getPreflist "repos",+                     commandArgdefaults = defaultrepo,+                     commandAdvancedOptions = [applyas,                                                  nolinks,-                                                 remote_repo] ++-                                                network_options,-                     command_basic_options = [match_several, deps_sel,-                                              all_interactive,-                                              sign]++dry_run++[summary,-                                              working_repo_dir,-                                              set_default,-                                              allow_unrelated_repos]}+                                                 remoteRepo] +++                                                networkOptions,+                     commandBasicOptions = [matchSeveral, depsSel,+                                              allInteractive,+                                              sign]++dryRun++[summary,+                                              workingRepoDir,+                                              setDefault,+                                              allowUnrelatedRepos]} -push_cmd :: [DarcsFlag] -> [String] -> IO ()-push_cmd opts [""] = push_cmd opts []-push_cmd opts [unfixedrepodir] =-  let am_verbose = Verbose `elem` opts-      am_quiet = Quiet `elem` opts-      putVerbose s = when am_verbose $ putDocLn s-      putInfo s = when (not am_quiet) $ putDocLn s-  in+pushCmd :: [DarcsFlag] -> [String] -> IO ()+pushCmd _ [""] = impossible+pushCmd opts [unfixedrepodir] =  do  repodir <- fixUrl opts unfixedrepodir  -- Test to make sure we aren't trying to push to the current repo  here <- getCurrentDirectory+ checkOptionsSanity opts repodir  when (repodir == here) $        fail "Cannot push from repository to itself."        -- absolute '.' also taken into account by fix_filepath- (bundle,num_to_pull) <- withRepoReadLock opts $- \repository -> do-  if is_url repodir then do-       when (apply_as opts /= Nothing) $-           let msg = text "Cannot --apply-as when pushing to URLs" in-             if DryRun `elem` opts-             then putInfo $ text "NOTE: " <+> msg-                         $$ text ""-             else errorDoc msg-       maybeapply <- maybeURLCmd "APPLY" repodir-       when (maybeapply == Nothing) $-         let lprot = takeWhile (/= ':') repodir-             prot = map toUpper lprot-             msg = text ("Pushing to "++lprot++" URLs is not supported.\n"++-                         "You may be able to hack this to work"++-                         " using DARCS_APPLY_"++prot) in-           if DryRun `elem` opts-           then putInfo $ text "NOTE:" <+> msg-                       $$ text ""-           else errorDoc msg-   else do-       when (want_sign opts) $-        let msg = text "Signing doesn't make sense for local repositories or when pushing over ssh."-        in if DryRun `elem` opts-            then putInfo $ text "NOTE:" <+> msg-            else errorDoc msg+ (bundle) <- withRepoReadLock opts $-+                          prepareBundle opts repodir+ sbundle <- signString opts bundle+ let body = if is_file repodir+            then sbundle+            else make_email repodir [] Nothing sbundle Nothing+ rval <- remote_apply opts repodir body+ case rval of ExitFailure ec -> do putStrLn $ "Apply failed!"+                                   exitWith (ExitFailure ec)+              ExitSuccess -> putInfo opts $ text "Push successful."+pushCmd _ _ = impossible++prepareBundle :: forall p C(r u t) . (RepoPatch p) => [DarcsFlag] -> String -> Repository p C(r u t) ->+                IO (Doc)+prepareBundle opts repodir repository = do   them <- identifyRepositoryFor repository repodir >>= read_repo-  old_default <- get_preflist "defaultrepo"-  set_defaultrepo repodir opts+  old_default <- getPreflist "defaultrepo"+  setDefaultrepo repodir opts   when (old_default == [repodir]) $        let pushing = if DryRun `elem` opts then "Would push" else "Pushing"-       in  putInfo $ text $ pushing++" to "++formatPath repodir++"..."+       in  putInfo opts $ text $ pushing++" to "++formatPath repodir++"..."   us <- read_repo repository   case get_common_and_uncommon (us, them) of     (common, us' :\/: them') -> do-     checkUnrelatedRepos opts common us them-     putVerbose $ text "We have the following patches to push:"-               $$ (vcat $ mapRL description $ head $ unsafeUnRL us')-     firstUs <- case us' of-                   NilRL:<:NilRL -> do putInfo $ text "No recorded local changes to push!"-                                       exitWith ExitSuccess-                   NilRL -> bug "push_cmd: us' is empty!"-                   (x:<:_) -> return x-     with_selected_changes "push" opts (reverseRL firstUs) $-      \ (to_be_pushed:>_) -> do+      prePushChatter opts common us us' them them'+      with_selected_changes "push" opts Nothing (reverseRL us') $ bundlePatches opts common++prePushChatter :: forall p a C(x y t) . (ShowPatch a) =>+                 [DarcsFlag] -> [PatchInfo] -> PatchSet p C(x) ->+                 RL a C(t x) -> PatchSet p C(y) -> RL a C(t y) -> IO ()+prePushChatter opts common us us' them them' = do+  checkUnrelatedRepos opts common us them+  let num_to_pull = lengthRL them'+  let pull_reminder = if num_to_pull > 0+                      then text $ "The remote repository has " ++ show num_to_pull +                      ++ " " ++ englishNum num_to_pull (Noun "patch") " to pull."+                      else empty+  putVerbose opts $ text "We have the following patches to push:" $$ (vcat $ mapRL description us')+  when (not $ nullRL us') $ do putInfo opts $ pull_reminder+  when (nullRL us') $ do putInfo opts $ text "No recorded local changes to push!"+                         exitWith ExitSuccess++bundlePatches :: forall t p C(x y z w). RepoPatch p => [DarcsFlag] -> [PatchInfo]+                                          -> (FL (PatchInfoAnd p) :> t) C(z w)+                                          -> IO (Doc)+bundlePatches opts common (to_be_pushed :> _) =+    do       definePatches to_be_pushed-      print_dry_run_message_and_exit "push" opts to_be_pushed+      printDryRunMessageAndExit "push" opts to_be_pushed       when (nullFL to_be_pushed) $ do-          putInfo $+          putInfo opts $             text "You don't want to push any patches, and that's fine with me!"           exitWith ExitSuccess-      let num_to_pull = lengthRL $ head $ unsafeUnRL them'-          bundle = make_bundle []+      bundle <- make_bundle []                      (bug "using slurpy in make_bundle called from Push")                      common (mapFL_FL hopefully to_be_pushed)-      return (bundle, num_to_pull)- sbundle <- signString opts bundle- let body = if is_file repodir-            then sbundle-            else make_email repodir [] Nothing sbundle Nothing- rval <- remote_apply opts repodir body- let pull_reminder =-         if num_to_pull > 0-         then text $ "(By the way, the remote repository has " ++ show num_to_pull ++ " "-                     ++ englishNum num_to_pull (Noun "patch") " to pull.)"-         else empty- case rval of ExitFailure ec -> do putStrLn $ "Apply failed!"-                                   exitWith (ExitFailure ec)-              ExitSuccess -> putInfo $ text "Push successful." $$ pull_reminder--push_cmd _ _ = impossible+      return (bundle) -want_sign :: [DarcsFlag] -> Bool-want_sign opts = case opts of+wantSign :: [DarcsFlag] -> Bool+wantSign opts = case opts of     []            -> False     Sign:_        -> True     (SignAs _):_  -> True     (SignSSL _):_ -> True     NoSign:_      -> False-    _:opts'       -> want_sign opts'+    _:opts'       -> wantSign opts'+++checkOptionsSanity :: [DarcsFlag] -> String -> IO ()+checkOptionsSanity opts repodir =+  if is_url repodir then do+       when (apply_as opts /= Nothing) $+           abortRun opts $ text "Cannot --apply-as when pushing to URLs"+       maybeapply <- maybeURLCmd "APPLY" repodir+       when (maybeapply == Nothing) $+         let lprot = takeWhile (/= ':') repodir+             prot = map toUpper lprot+             msg = text ("Pushing to "++lprot++" URLs is not supported.\n"+++                         "You may be able to hack this to work"+++                         " using DARCS_APPLY_"++prot) in+         abortRun opts msg+   else do+       when (wantSign opts) $+        abortRun opts $ text "Signing doesn't make sense for local repositories or when pushing over ssh."+ \end{code}  For obvious reasons, you can only push to repositories to which you have
src/Darcs/Commands/Put.lhs view
@@ -8,38 +8,38 @@ import Control.Monad ( when ) import Data.Maybe ( catMaybes ) import System.Directory ( createDirectory )-import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag( Quiet, Verbose,-                                    UseFormat2, UseHashedInventory, UseOldFashionedInventory ),-                        applyas, match_one_context, fixUrl,-                        network_options, flagToString, get_inventory_choices,-                        set_scripts_executable, working_repo_dir, set_default+import Storage.Hashed.Tree( emptyTree )+import Darcs.Commands ( DarcsCommand(..), nodefaults, putVerbose, putInfo )+import Darcs.Arguments ( DarcsFlag( UseFormat2, UseHashedInventory, UseOldFashionedInventory ),+                        applyas, matchOneContext, fixUrl,+                        networkOptions, flagToString, getInventoryChoices,+                        setScriptsExecutableOption, workingRepoDir, setDefault                       ) import Darcs.Repository ( withRepoReadLock, ($-), patchSetToPatches, read_repo, amInRepository ) import Darcs.Repository.Format ( identifyRepoFormat,-                                 RepoProperty ( Darcs2, HashedInventory ), format_has )+                                 RepoProperty ( Darcs2, HashedInventory ), formatHas ) import Darcs.Patch.Bundle ( make_bundle2 )-import Darcs.Ordered ( FL(..) )-import Darcs.Match ( have_patchset_match, get_one_patchset )-import Darcs.Repository.Prefs ( get_preflist, set_defaultrepo )+import Darcs.Witnesses.Ordered ( FL(..) )+import Darcs.Match ( havePatchsetMatch, getOnePatchset )+import Darcs.Repository.Prefs ( getPreflist, setDefaultrepo ) import Darcs.URL ( is_url, is_file ) import Darcs.Utils ( withCurrentDirectory ) import Progress ( debugMessage ) import Darcs.RepoPath ( ioAbsoluteOrRemote, toPath )-import Darcs.SlurpDirectory ( empty_slurpy ) import Darcs.External ( execSSH ) import Darcs.RemoteApply ( remote_apply ) import Darcs.Commands.Init ( initialize ) import Darcs.Email ( make_email )-import Darcs.Sealed ( Sealed(..), seal )+import Darcs.Witnesses.Sealed ( Sealed(..), seal )+import Printer ( text ) #include "impossible.h" -put_description :: String -put_description =+putDescription :: String +putDescription =  "Makes a copy of the repository" -put_help :: String-put_help =+putHelp :: String+putHelp =  "The `darcs put' command creates a copy of the current repository.  It\n" ++  "is currently very inefficient, so when creating local copies you\n" ++  "should use `darcs get . x' instead of `darcs put x'.\n" ++@@ -50,27 +50,23 @@  "appropriate.  See those commands for an explanation of each option.\n"  put ::DarcsCommand-put = DarcsCommand {command_name = "put",-                    command_help = put_help,-                    command_description = put_description,-                    command_extra_args = 1,-                    command_extra_arg_help = ["<NEW REPOSITORY>"],-                    command_command = put_cmd,-                    command_prereq = amInRepository,-                    command_get_arg_possibilities = get_preflist "repos",-                    command_argdefaults = nodefaults,-                    command_advanced_options = [applyas] ++ network_options,-                    command_basic_options = [match_one_context, set_scripts_executable,-                                             get_inventory_choices,-                                             set_default, working_repo_dir]}+put = DarcsCommand {commandName = "put",+                    commandHelp = putHelp,+                    commandDescription = putDescription,+                    commandExtraArgs = 1,+                    commandExtraArgHelp = ["<NEW REPOSITORY>"],+                    commandCommand = putCmd,+                    commandPrereq = amInRepository,+                    commandGetArgPossibilities = getPreflist "repos",+                    commandArgdefaults = nodefaults,+                    commandAdvancedOptions = [applyas] ++ networkOptions,+                    commandBasicOptions = [matchOneContext, setScriptsExecutableOption,+                                             getInventoryChoices,+                                             setDefault, workingRepoDir]} -put_cmd :: [DarcsFlag] -> [String] -> IO ()-put_cmd _ [""] = fail "Empty repository argument given to put."-put_cmd opts [unfixedrepodir] =-  let am_quiet = Quiet `elem` opts-      putInfo s = when (not am_quiet) $ putStrLn s-      putVerbose = when (Verbose `elem` opts) . putStrLn-  in+putCmd :: [DarcsFlag] -> [String] -> IO ()+putCmd _ [""] = fail "Empty repository argument given to put."+putCmd opts [unfixedrepodir] =  do  repodir <- fixUrl opts unfixedrepodir  -- Test to make sure we aren't trying to push to the current repo@@ -83,52 +79,52 @@  when (is_url req_absolute_repo_dir) $ error "Can't put to a URL!"   debugMessage "Creating repository"- putVerbose "Creating repository"+ putVerbose opts $ text "Creating repository"  rf_or_e <- identifyRepoFormat "."  rf <- case rf_or_e of Left e -> fail e                        Right x -> return x- let initopts = if format_has Darcs2 rf+ let initopts = if formatHas Darcs2 rf                 then UseFormat2:filter (/= UseOldFashionedInventory) opts-                else if format_has HashedInventory rf &&+                else if formatHas HashedInventory rf &&                         not (UseOldFashionedInventory `elem` opts)                      then UseHashedInventory:filter (/= UseFormat2) opts                      else UseOldFashionedInventory:filter (/= UseFormat2) opts  if is_file req_absolute_repo_dir      then do createDirectory req_absolute_repo_dir-             withCurrentDirectory req_absolute_repo_dir $ (command_command initialize) initopts []+             withCurrentDirectory req_absolute_repo_dir $ (commandCommand initialize) initopts []      else do -- is_ssh req_absolute_repo_dir              remoteInit req_absolute_repo_dir initopts   withCurrentDirectory cur_absolute_repo_dir $                       withRepoReadLock opts $- \repository -> do-  set_defaultrepo req_absolute_repo_dir opts-  Sealed patchset <- if have_patchset_match opts-                     then get_one_patchset repository opts  -- todo: make sure get_one_patchset has the right type+  setDefaultrepo req_absolute_repo_dir opts+  Sealed patchset <- if havePatchsetMatch opts+                     then getOnePatchset repository opts  -- todo: make sure getOnePatchset has the right type                      else read_repo repository >>= (return . seal)-  Sealed patchset2 <- if have_patchset_match opts-                      then get_one_patchset repository opts  -- todo: make sure get_one_patchset has the right type+  Sealed patchset2 <- if havePatchsetMatch opts+                      then getOnePatchset repository opts  -- todo: make sure getOnePatchset has the right type                       else read_repo repository >>= (return . seal)   let patches = patchSetToPatches patchset       patches2 = patchSetToPatches patchset2       nullFL NilFL = True       nullFL _ = False   when (nullFL patches) $ do-          putInfo "No patches were selected to put. Nothing to be done."+          putInfo opts $ text "No patches were selected to put. Nothing to be done."           exitWith ExitSuccess-  let bundle = (make_bundle2 opts empty_slurpy [] patches patches2)-      message = if is_file req_absolute_repo_dir+  bundle <- make_bundle2 opts emptyTree [] patches patches2+  let message = if is_file req_absolute_repo_dir                 then bundle                 else make_email req_absolute_repo_dir [] Nothing bundle Nothing-  putVerbose "Applying patches in new repository..."+  putVerbose opts $ text "Applying patches in new repository..."   rval <- remote_apply opts req_absolute_repo_dir message   case rval of ExitFailure ec -> do putStrLn $ "Apply failed!"                                     exitWith (ExitFailure ec)-               ExitSuccess -> putInfo "Put successful."-put_cmd _ _ = impossible+               ExitSuccess -> putInfo opts $ text "Put successful."+putCmd _ _ = impossible  remoteInit :: FilePath -> [DarcsFlag] -> IO () remoteInit repo opts = do-    let args = catMaybes $ map (flagToString $ command_basic_options initialize) opts+    let args = catMaybes $ map (flagToString $ commandBasicOptions initialize) opts         command = "darcs initialize --repodir='" ++ path ++ "' " ++ unwords args     exitCode <- execSSH addr command     when (exitCode /= ExitSuccess) $ 
src/Darcs/Commands/Record.lhs view
@@ -17,148 +17,142 @@  \darcsCommand{record} \begin{code}-{-# OPTIONS_GHC -cpp -fglasgow-exts #-} {-# LANGUAGE CPP, PatternGuards #-} -module Darcs.Commands.Record ( record, commit, get_date, get_log, file_exists ) where+module Darcs.Commands.Record ( record, commit, getDate, getLog, fileExists ) where+import qualified Ratified( hGetContents ) import Control.Exception ( handleJust, Exception( ExitException ) ) import Control.Monad ( filterM, when )-import System.IO ( hGetContents, stdin )+import System.IO ( stdin ) import Data.List ( sort, isPrefixOf ) import System.Exit ( exitWith, exitFailure, ExitCode(..) ) import System.IO ( hPutStrLn ) import System.Directory ( doesFileExist, doesDirectoryExist, removeFile ) import Data.Maybe ( isJust ) -import Darcs.Lock ( readBinFile, writeBinFile, world_readable_temp, appendToFile, removeFileMayNotExist )+import Darcs.Lock ( readBinFile, writeBinFile, world_readable_temp, appendToFile ) import Darcs.Hopefully ( info, n2pia ) import Darcs.Repository ( Repository, amInRepository, withRepoLock, ($-),-                          get_unrecorded_in_files,-                          get_unrecorded_in_files_unsorted, withGutsOf,-                    sync_repo, read_repo,+                          withGutsOf,+                    read_repo,                     slurp_recorded,-                    tentativelyAddPatch, finalizeRepositoryChanges,-                  )+                    tentativelyAddPatch, finalizeRepositoryChanges+                        , invalidateIndex, unrecordedChanges ) import Darcs.Patch ( RepoPatch, Patch, Prim, namepatch, summary, anonymous,                      adddeps, fromPrims )-import Darcs.Ordered ( FL(..), RL(..), (:>)(..), (+>+),+import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (+>+),                              unsafeUnFL, unsafeCompare,                              reverseRL, mapFL, mapFL_FL, nullFL ) import Darcs.Patch.Info ( PatchInfo )+import Darcs.Patch.Split ( primSplitter ) import Darcs.SlurpDirectory ( slurp_hasfile, slurp_hasdir )-import Darcs.Patch.Choices ( patch_choices_tps, tp_patch,-                             force_first, get_choices, tag )+import Darcs.Patch.Choices ( patchChoicesTps, tpPatch,+                             forceFirst, getChoices, tag ) import Darcs.SelectChanges ( with_selected_changes_to_files',                              with_selected_changes_reversed ) import Darcs.RepoPath ( FilePathLike, SubPath, sp2fn, toFilePath ) import Darcs.SlurpDirectory ( Slurpy, empty_slurpy )-import Darcs.Commands ( DarcsCommand(..), nodefaults, loggers, command_stub )+import Darcs.Commands ( DarcsCommand(..), nodefaults, commandStub ) import Darcs.Arguments ( DarcsFlag( PromptLongComment, NoEditLongComment,-                                    EditLongComment, RmLogFile, LogFile, Pipe,+                                    EditLongComment, LogFile, Pipe,                                     PatchName, AskDeps, All ),-                         get_author, working_repo_dir, lookforadds,+                         fileHelpAuthor,+                         getAuthor, workingRepoDir, lookforadds,                          fixSubPaths, defineChanges, testByDefault,-                         ask_long_comment, askdeps, patch_select_flag,-                         all_pipe_interactive, leave_test_dir, notest,-                         author, patchname_option, umask_option, ignoretimes,-                         nocompress, rmlogfile, logfile, list_registered_files,-                         set_scripts_executable )-import Darcs.Utils ( askUser, promptYorn, edit_file, clarify_errors )+                         askLongComment, askdeps, patchSelectFlag,+                         allPipeInteractive, leaveTestDir, notest,+                         author, patchnameOption, umaskOption, ignoretimes,+                         nocompress, rmlogfile, logfile, listRegisteredFiles,+                         setScriptsExecutableOption )+import Darcs.Flags (willRemoveLogFile)+import Darcs.Utils ( askUser, promptYorn, edit_file, clarifyErrors ) import Progress ( debugMessage) import Darcs.ProgressPatches( progressFL) import IsoDate ( getIsoDateTime, cleanLocalDate )-import Printer ( hPutDocLn, text, wrap_text, ($$), renderString )-import Darcs.Gorsvet( invalidateIndex )+import Printer ( hPutDocLn, text, wrap_text, ($$) ) #include "impossible.h" -record_description :: String-record_description =- "Save changes in the working copy to the repository as a patch."-\end{code}+recordDescription :: String+recordDescription = "Create a patch from unrecorded changes." -If you provide one or more files or directories as additional arguments-to record, you will only be prompted to changes in those files or-directories.-\begin{code}-record_help :: String-record_help = renderString $ wrap_text 80 $- "Record is used to name a set of changes and record the patch to the "++- "repository."+recordHelp :: String+recordHelp =+ "The `darcs record' command is used to create a patch from changes in\n" +++ "the working tree.  If you specify a set of files and directories,\n" +++ "changes to other files will be skipped.\n" +++ "\n" ++ recordHelp' +++ "\n" ++ recordHelp''  record :: DarcsCommand-record = DarcsCommand {command_name = "record",-                       command_help = record_help,-                       command_description = record_description,-                       command_extra_args = -1,-                       command_extra_arg_help = ["[FILE or DIRECTORY]..."],-                       command_command = record_cmd,-                       command_prereq = amInRepository,-                       command_get_arg_possibilities = list_registered_files,-                       command_argdefaults = nodefaults,-                       command_advanced_options = [logfile, rmlogfile,+record = DarcsCommand {commandName = "record",+                       commandHelp = recordHelp,+                       commandDescription = recordDescription,+                       commandExtraArgs = -1,+                       commandExtraArgHelp = ["[FILE or DIRECTORY]..."],+                       commandCommand = recordCmd,+                       commandPrereq = amInRepository,+                       commandGetArgPossibilities = listRegisteredFiles,+                       commandArgdefaults = nodefaults,+                       commandAdvancedOptions = [logfile, rmlogfile,                                                    nocompress, ignoretimes,-                                                   umask_option,-                                                   set_scripts_executable],-                       command_basic_options = [patchname_option, author,+                                                   umaskOption,+                                                   setScriptsExecutableOption],+                       commandBasicOptions = [patchnameOption, author,                                                notest,-                                               leave_test_dir,-                                               all_pipe_interactive,+                                               leaveTestDir,+                                               allPipeInteractive,                                                askdeps,-                                               ask_long_comment,+                                               askLongComment,                                                lookforadds,-                                               working_repo_dir]}+                                               workingRepoDir]} -commit_description :: String-commit_description =- "Does not actually do anything, but offers advice on saving changes"+commitDescription :: String+commitDescription = "Redirect the user to record, push or send." -commit_help :: String-commit_help =+commitHelp :: String+commitHelp =  "This command does not do anything.\n"++  "If you want to save changes locally, use the `darcs record' command.\n"++  "If you want to save a recorded patch to another repository, use the\n"++  "`darcs push' or `darcs send' commands instead.\n"  commit :: DarcsCommand-commit = command_stub "commit" commit_help commit_description record+commit = commandStub "commit" commitHelp commitDescription record -file_exists :: Slurpy -> SubPath -> IO Bool-file_exists s rp = do file <- doesFileExist fp+fileExists :: Slurpy -> SubPath -> IO Bool+fileExists s rp =  do file <- doesFileExist fp                       dir <- doesDirectoryExist fp                       return (file || dir ||                               slurp_hasfile (sp2fn rp) s ||                               slurp_hasdir (sp2fn rp) s)                    where fp = toFilePath rp -record_cmd :: [DarcsFlag] -> [String] -> IO ()-record_cmd opts args = do-    check_name_is_not_option opts-    let (logMessage,_, _) = loggers opts+recordCmd :: [DarcsFlag] -> [String] -> IO ()+recordCmd opts args = do+    checkNameIsNotOption opts     withRepoLock (testByDefault opts) $- \repository -> do     rec <- if null args then return empty_slurpy            else slurp_recorded repository     files <- sort `fmap` fixSubPaths opts args     let non_repo_files = if null files && (not $ null args) then args else []-    existing_files <- filterM (file_exists rec) files-    non_existent_files <- filterM (fmap not . file_exists rec) files+    existing_files <- filterM (fileExists rec) files+    non_existent_files <- filterM (fmap not . fileExists rec) files     when (not $ null existing_files) $-         logMessage $ "Recording changes in "++unwords (map show existing_files)++":\n"+         putStrLn $ "Recording changes in "++unwords (map show existing_files)++":\n"     when (not $ null non_existent_files) $-         logMessage $ "Non existent files or directories: "++unwords (map show non_existent_files)++"\n"+         putStrLn $ "Non existent files or directories: "++unwords (map show non_existent_files)++"\n"     when (((not $ null non_existent_files) || (not $ null non_repo_files)) && null existing_files) $          fail "None of the files you specified exist!"     debugMessage "About to get the unrecorded changes."-    let existing_fns = map sp2fn existing_files-    changes <- if All `elem` opts then get_unrecorded_in_files_unsorted repository existing_fns-                                  else get_unrecorded_in_files repository existing_fns+    changes <- unrecordedChanges opts repository files     debugMessage "I've gotten unrecorded."     case allow_empty_with_askdeps changes of-      Nothing -> do when (Pipe `elem` opts) $ do get_date opts+      Nothing -> do when (Pipe `elem` opts) $ do getDate opts                                                  return ()                     if ((not $ null existing_files) || (not $ null non_existent_files))-                       then logMessage "No changes in selected files or directories!"-                       else logMessage "No changes!"-      Just ch -> do_record repository opts existing_files ch+                       then putStrLn "No changes in selected files or directories!"+                       else putStrLn "No changes!"+      Just ch -> doRecord repository opts existing_files ch     where allow_empty_with_askdeps NilFL               | AskDeps `elem` opts = Just NilFL               | otherwise = Nothing@@ -166,10 +160,9 @@   -- check that what we treat as the patch name is not accidentally a command  -- line flag-check_name_is_not_option :: [DarcsFlag] -> IO ()-check_name_is_not_option opts = do-    let (logMessage, _, _) = loggers opts-        patchNames = [n | PatchName n <- opts]+checkNameIsNotOption :: [DarcsFlag] -> IO ()+checkNameIsNotOption opts = do+    let patchNames = [n | PatchName n <- opts]     when (length patchNames == 1) $ do         let n = head patchNames             oneLetterName = length n == 1 || (length n == 2 && head n == '-')@@ -180,45 +173,45 @@                     case yorn of                          'y' -> return ()                         'n' -> do-                                   logMessage "Okay, aborting the record."+                                   putStrLn "Okay, aborting the record."                                    exitFailure                         _   -> keepAsking                 keepAsking             else return ()  -do_record :: RepoPatch p => Repository p -> [DarcsFlag] -> [SubPath] -> FL Prim -> IO ()-do_record repository opts files ps = do+doRecord :: RepoPatch p => Repository p -> [DarcsFlag] -> [SubPath] -> FL Prim -> IO ()+doRecord repository opts files ps = do     let make_log = world_readable_temp "darcs-record"-    date <- get_date opts-    my_author <- get_author opts+    date <- getDate opts+    my_author <- getAuthor opts     debugMessage "I'm slurping the repository."     debugMessage "About to select changes..."-    with_selected_changes_to_files' "record" opts+    with_selected_changes_to_files' "record" opts (Just primSplitter)       (map toFilePath files) ps $ \ (chs:>_) ->       do when (is_empty_but_not_askdeps chs) $               do putStrLn "Ok, if you don't want to record anything, that's fine!"                  exitWith ExitSuccess-         handleJust only_successful_exits (\_ -> return ()) $+         handleJust onlySuccessfulExits (\_ -> return ()) $              do deps <- if AskDeps `elem` opts-                        then ask_about_depends repository chs opts+                        then askAboutDepends repository chs opts                         else return []                 when (AskDeps `elem` opts) $ debugMessage "I've asked about dependencies."                 if nullFL chs && null deps                   then putStrLn "Ok, if you don't want to record anything, that's fine!"                   else do defineChanges chs-                          (name, my_log, logf) <- get_log opts Nothing make_log chs-                          do_actual_record repository opts name date+                          (name, my_log, logf) <- getLog opts Nothing make_log chs+                          doActualRecord repository opts name date                                  my_author my_log logf deps chs     where is_empty_but_not_askdeps l               | AskDeps `elem` opts = False                                       -- a "partial tag" patch; see below.               | otherwise = nullFL l -do_actual_record :: RepoPatch p => Repository p -> [DarcsFlag] -> String -> String -> String+doActualRecord :: RepoPatch p => Repository p -> [DarcsFlag] -> String -> String -> String                  -> [String] -> Maybe String                  -> [PatchInfo] -> FL Prim -> IO ()-do_actual_record repository opts name date my_author my_log logf deps chs =+doActualRecord repository opts name date my_author my_log logf deps chs =               do debugMessage "Writing the patch file..."                  mypatch <- namepatch date name my_author my_log $                             fromPrims $ progressFL "Writing changes:" chs@@ -226,62 +219,47 @@                  invalidateIndex repository                  debugMessage "Applying to pristine..."                  withGutsOf repository (finalizeRepositoryChanges repository)-                                    `clarify_errors` failuremessage+                                    `clarifyErrors` failuremessage                  debugMessage "Syncing timestamps..."-                 sync_repo repository                  when (isJust logf) $ removeFile (fromJust logf)-                 logMessage $ "Finished recording patch '"++name++"'"-    where (logMessage,_,_) = loggers opts-          failuremessage = "Failed to record patch '"++name++"'" +++                 putStrLn $ "Finished recording patch '"++name++"'"+    where failuremessage = "Failed to record patch '"++name++"'" ++                            case logf of Just lf -> "\nLogfile left in "++lf++"."                                         Nothing -> ""-\end{code}-Each patch is given a name, which typically would consist of a brief-description of the changes.  This name is later used to describe the patch.-The name must fit on one line (i.e.\ cannot have any embedded newlines).  If-you have more to say, stick it in the log.-\begin{code}-\end{code} -The patch is also flagged with the author of the change, taken by default-from the \verb!DARCS_EMAIL! environment variable, and if that doesn't-exist, from the \verb!EMAIL! environment variable.  The date on which the-patch was recorded is also included.  Currently there is no provision for-keeping track of when a patch enters a given repository.-\begin{code}-get_date :: [DarcsFlag] -> IO String-get_date opts- | Pipe `elem` opts = do cleanLocalDate `fmap` askUser "What is the date? "-get_date _ = getIsoDateTime-\end{code}-\label{DARCS_EDITOR}-Finally, each changeset should have a full log (which may be empty).  This-log is for detailed notes which are too lengthy to fit in the name.  If you-answer that you do want to create a comment file, darcs will open an editor-so that you can enter the comment in.  The choice of editor proceeds as-follows.  If one of the \verb!$DARCS_EDITOR!, \verb!$VISUAL! or-\verb!$EDITOR! environment variables is defined, its value is used (with-precedence proceeding in the order listed).  If not, ``vi'', ``emacs'',-``emacs~-nw'' and ``nano'' are tried in that order.--\begin{options}---logfile-\end{options}+recordHelp' :: String+recordHelp' =+ "Every patch has a name, an optional description, an author and a date.\n" +++ "\n" +++ "The patch name should be a short sentence that concisely describes the\n" +++ "patch, such as `Add error handling to main event loop.'  You can\n" +++ "supply it in advance with the -m option, or provide it when prompted.\n" +++ "\n" +++ "The patch description is an optional block of free-form text.  It is\n" +++ "used to supply additional information that doesn't fit in the patch\n" +++ "name.  For example, it might include a rationale of WHY the change was\n" +++ "necessary.  By default Darcs asks if you want to add a description;\n" +++ "the --edit-long-comment and --skip-long-comment can be used to answer\n" +++ "`yes' or `no' (respectively) to this prompt.  Finally, the --logfile\n" +++ "option allows you to supply a file that already contains the patch\n" +++ "name (first line) and patch description (subsequent lines).  This is\n" +++ "useful if a previous record failed and left a darcs-record-0 file.\n" +++ "\n" +++ unlines fileHelpAuthor +++ "\n" +++ "The patch date is generated automatically.  It can only be spoofed by\n" +++ "using the --pipe option.\n" -If you wish, you may specify the patch name and log using the-\verb!--logfile! flag.  If you do so, the first line of the specified file-will be taken to be the patch name, and the remainder will be the ``long-comment''.  This feature can be especially handy if you have a test that-fails several times on the record (thus aborting the record), so you don't-have to type in the long comment multiple times. The file's contents will-override the \verb!--patch-name! option.+getDate :: [DarcsFlag] -> IO String+getDate opts+ | Pipe `elem` opts = do cleanLocalDate `fmap` askUser "What is the date? "+getDate _ = getIsoDateTime -\begin{code} data PName = FlagPatchName String | PriorPatchName String | NoPatchName -get_log :: [DarcsFlag] -> Maybe (String, [String]) -> IO String -> FL Prim ->+getLog :: [DarcsFlag] -> Maybe (String, [String]) -> IO String -> FL Prim ->            IO (String, [String], Maybe String)-get_log opts m_old make_log chs = gl opts+getLog opts m_old make_log chs = gl opts     where patchname_specified = patchname_helper opts           patchname_helper (PatchName n:_) | take 4 n == "TAG " = FlagPatchName $ '.':n                                            | otherwise          = FlagPatchName n@@ -296,7 +274,7 @@                                   PriorPatchName p -> return p                                   NoPatchName      -> prompt_patchname False                            putStrLn "What is the log?"-                           thelog <- lines `fmap` hGetContents stdin -- ratify hGetContents: stdin not deleted+                           thelog <- lines `fmap` Ratified.hGetContents stdin                            return (p, thelog, Nothing)           gl (LogFile f:fs) =               do -- round 1 (patchname)@@ -311,8 +289,10 @@                  when (EditLongComment `elem` fs) $ do edit_file f                                                        return ()                  (name, thelog, _) <- read_long_comment f firstname-                 when (RmLogFile `elem` opts) $ removeFileMayNotExist f-                 return (name, thelog, Nothing)+                 let toRemove = if willRemoveLogFile opts+                        then Just $ toFilePath f+                        else Nothing+                 return (name, thelog, toRemove)           gl (EditLongComment:_) =                   case patchname_specified of                     FlagPatchName  p -> actually_get_log p@@ -408,49 +388,45 @@ depended-upon patches.  \begin{code}-ask_about_depends :: RepoPatch p => Repository p -> FL Prim -> [DarcsFlag] -> IO [PatchInfo]-ask_about_depends repository pa' opts = do+askAboutDepends :: RepoPatch p => Repository p -> FL Prim -> [DarcsFlag] -> IO [PatchInfo]+askAboutDepends repository pa' opts = do   pps <- read_repo repository   pa <- n2pia `fmap` anonymous (fromPrims pa')   let ps = (reverseRL $ headRL pps)+>+(pa:>:NilFL)-      (pc, tps) = patch_choices_tps ps-      ta = case filter ((pa `unsafeCompare`) . tp_patch) $ unsafeUnFL tps of+      (pc, tps) = patchChoicesTps ps+      ta = case filter ((pa `unsafeCompare`) . tpPatch) $ unsafeUnFL tps of                 [tp] -> tag tp-                [] -> error "ask_about_depends: []"-                _ -> error "ask_about_depends: many"-      ps' = mapFL_FL tp_patch $ middle_choice $ force_first ta pc-  with_selected_changes_reversed "depend on" (filter askdep_allowed opts) ps'+                [] -> error "askAboutDepends: []"+                _ -> error "askAboutDepends: many"+      ps' = mapFL_FL tpPatch $ middle_choice $ forceFirst ta pc+  with_selected_changes_reversed "depend on" (filter askdep_allowed opts) Nothing ps'              $ \(deps:>_) -> return $ mapFL info deps  where headRL (x:<:_) = x        headRL NilRL = impossible-       askdep_allowed = not . patch_select_flag-       middle_choice p = mc where (_ :> mc :> _) = get_choices p+       askdep_allowed = not . patchSelectFlag+       middle_choice p = mc where (_ :> mc :> _) = getChoices p  -only_successful_exits :: Exception -> Maybe ()-only_successful_exits (ExitException ExitSuccess) = Just ()-only_successful_exits _ = Nothing-\end{code}--\begin{options}---no-test,  --test-\end{options}--If you configure darcs to run a test suite, darcs will run this test on the-recorded repository to make sure it is valid.  Darcs first creates a pristine-copy of the source tree (in a temporary directory), then it runs the test,-using its return value to decide if the record is valid.  If it is not valid,-the record will be aborted.  This is a handy way to avoid making stupid-mistakes like forgetting to `darcs add' a new file.  It also can be-tediously slow, so there is an option (\verb!--no-test!) to skip the test.--\begin{options}---set-scripts-executable-\end{options}+onlySuccessfulExits :: Exception -> Maybe ()+onlySuccessfulExits (ExitException ExitSuccess) = Just ()+onlySuccessfulExits _ = Nothing -If you pass \verb!--set-scripts-executable! to \verb!darcs record!, darcs will set scripts-executable in the test directory before running the test.+recordHelp'' :: String+recordHelp'' =+ "If a test command has been defined with `darcs setpref', attempting to\n" +++ "record a patch will cause the test command to be run in a clean copy\n" +++ "of the working tree (that is, including only recorded changes).  If\n" +++ "the test fails, the record operation will be aborted.\n" +++ "\n" +++ "The --set-scripts-executable option causes scripts to be made\n" +++ "executable in the clean copy of the working tree, prior to running the\n" +++ "test.  See `darcs get' for an explanation of the script heuristic.\n" +++ "\n" +++ "If your test command is tediously slow (e.g. `make all') and you are\n" +++ "recording several patches in a row, you may wish to use --no-test to\n" +++ "skip all but the final test.\n" +\end{code} \begin{options} --pipe \end{options}
src/Darcs/Commands/Remove.lhs view
@@ -24,29 +24,38 @@  import Control.Monad ( when ) import Darcs.Commands ( DarcsCommand(..), nodefaults,-                        command_alias, command_stub,+                        commandAlias, commandStub,+                        putWarning                       )-import Darcs.Arguments ( DarcsFlag, fixSubPaths,-                        list_registered_files,-                        working_repo_dir, umask_option+import Darcs.Arguments ( DarcsFlag (Recursive), fixSubPaths,+                        listRegisteredFiles,+                        workingRepoDir, umaskOption,+                        recursive                        )-import Darcs.RepoPath ( SubPath, toFilePath, sp2fn )+import Darcs.RepoPath ( SubPath, sp2fn ) import Darcs.Repository ( Repository, withRepoLock, ($-), amInRepository,-                          slurp_pending, slurp_recorded,-                          get_unrecorded_in_files, add_to_pending )-import Darcs.Patch ( RepoPatch, Prim, apply_to_slurpy, adddir, rmdir, addfile, rmfile )-import Darcs.Ordered ( FL(..), (+>+) )-import Darcs.SlurpDirectory ( slurp_removedir, slurp_removefile )-import Darcs.Repository.Prefs ( filetype_function )-import Darcs.Diff ( unsafeDiff )-import Darcs.Gorsvet( invalidateIndex )-#include "impossible.h"+                          add_to_pending, readRecordedAndPending, readUnrecorded )+import Darcs.Diff( treeDiff )+import Darcs.Patch ( RepoPatch, Prim, adddir, rmdir, addfile, rmfile )+import Darcs.Patch.FileName( fn2fp )+import Darcs.Witnesses.Ordered ( FL(..), (+>+) )+import Darcs.Witnesses.Sealed ( Sealed(..) )+import Darcs.Repository.Prefs ( filetypeFunction )+import Storage.Hashed.Tree( TreeItem(..), find, modifyTree, expand, list )+import Storage.Hashed.AnchoredPath( anchorPath )+import Storage.Hashed( floatPath ) -remove_description :: String-remove_description = "Remove files from version control."+import Darcs.Commands.Add( expandDirs )+import Printer ( text )+import Debug.Trace -remove_help :: String-remove_help =+#include "gadts.h"++removeDescription :: String+removeDescription = "Remove files from version control."++removeHelp :: String+removeHelp =  "The `darcs remove' command exists primarily for symmetry with `darcs\n" ++  "add', as the normal way to remove a file from version control is\n" ++  "simply to delete it from the working tree.  This command is only\n" ++@@ -57,64 +66,70 @@  "the patch) will ALWAYS affect the working tree of that repository.\n"  remove :: DarcsCommand-remove = DarcsCommand {command_name = "remove",-                       command_help = remove_help,-                       command_description = remove_description,-                       command_extra_args = -1,-                       command_extra_arg_help = ["<FILE or DIRECTORY> ..."],-                       command_command = remove_cmd,-                       command_prereq = amInRepository,-                       command_get_arg_possibilities = list_registered_files,-                       command_argdefaults = nodefaults,-                       command_advanced_options = [umask_option],-                       command_basic_options =-                           [working_repo_dir]}+remove = DarcsCommand {commandName = "remove",+                       commandHelp = removeHelp,+                       commandDescription = removeDescription,+                       commandExtraArgs = -1,+                       commandExtraArgHelp = ["<FILE or DIRECTORY> ..."],+                       commandCommand = removeCmd,+                       commandPrereq = amInRepository,+                       commandGetArgPossibilities = listRegisteredFiles,+                       commandArgdefaults = nodefaults,+                       commandAdvancedOptions = [umaskOption],+                       commandBasicOptions =+                           [workingRepoDir, recursive "recurse into subdirectories"]} -remove_cmd :: [DarcsFlag] -> [String] -> IO ()-remove_cmd opts relargs =+removeCmd :: [DarcsFlag] -> [String] -> IO ()+removeCmd opts relargs =     withRepoLock opts $- \repository -> do-    args <- fixSubPaths opts relargs+    origfiles <- fixSubPaths opts relargs+    args <- if Recursive `elem` opts+            then reverse `fmap` expandDirs origfiles+            else return origfiles     when (null args) $       putStrLn "Nothing specified, nothing removed."-    p <- make_remove_patch repository args-    invalidateIndex repository+    Sealed p <- makeRemovePatch opts repository args     add_to_pending repository p -make_remove_patch :: RepoPatch p => Repository p -> [SubPath] -> IO (FL Prim)-make_remove_patch repository files =-                          do s <- slurp_pending repository-                             srecorded <- slurp_recorded repository-                             pend <- get_unrecorded_in_files repository (map sp2fn files)-                             let sunrec = fromJust $ apply_to_slurpy pend srecorded-                             wt <- filetype_function-                             mrp wt s sunrec files-    where mrp wt s sunrec (f:fs) =-              case slurp_removedir fn s of-              Just s' ->-                  case slurp_removedir fn sunrec of-                  Just sunrec' -> do rest <- mrp wt s' sunrec' fs-                                     return $ rmdir f_fp :>: rest-                  Nothing -> do rest <- mrp wt s' sunrec fs-                                return $ adddir f_fp :>: rmdir f_fp :>: rest-              Nothing ->-                  case slurp_removefile fn s of-                  Nothing -> fail $ "Can't remove "++f_fp-                  Just s' ->-                      case slurp_removefile fn sunrec of-                      Nothing -> do rest <- mrp wt s' sunrec fs-                                    return $ addfile f_fp :>: rmfile f_fp :>: rest-                      Just sunrec' -> do rest <- mrp wt s' sunrec' fs-                                         let newp = unsafeDiff [] wt sunrec sunrec'-                                         return $ newp +>+ rest-            where fn = sp2fn f-                  f_fp = toFilePath f-          mrp _ _ _ [] = return NilFL+makeRemovePatch :: RepoPatch p => [DarcsFlag] -> Repository p C(r u t)+                  -> [SubPath] -> IO (Sealed (FL Prim C(u)))+makeRemovePatch opts repository files =+                          do recorded <- expand =<< readRecordedAndPending repository+                             unrecorded <- readUnrecorded repository+                             ftf <- filetypeFunction+                             mrp ftf recorded unrecorded $ map (floatPath . fn2fp . sp2fn) files+    where mrp ftf recorded unrecorded (f:fs) = do+            let recorded' = modifyTree recorded f Nothing+                unrecorded' = modifyTree unrecorded f Nothing+            Sealed rest <- mrp ftf recorded' unrecorded' fs+            let f_fp = anchorPath "" f+                skipAndWarn reason =+                    do putWarning opts . text $ "Can't remove " ++ f_fp+                                                ++ " (" ++ reason ++ ")"+                       return $ Sealed rest -rm_description :: String-rm_description = "Help newbies find `darcs remove'."+            case (find recorded f, find unrecorded f) of+              (Just (SubTree _), Just (SubTree unrecordedChildren)) -> do+                  if not $ null (list unrecordedChildren)+                    then skipAndWarn "it is not empty"+                    else return . Sealed $ rmdir f_fp :>: rest+              (Just (File _), Just (File _)) ->+                  do diff <- treeDiff ftf unrecorded unrecorded'+                     return . Sealed $ diff +>+ rest+              (Just (File _), _) ->+                  return . Sealed $ addfile f_fp :>: rmfile f_fp :>: rest+              (Just (SubTree _), _) ->+                  return . Sealed $ adddir f_fp :>: rmdir f_fp :>: rest+              (_, _) -> skipAndWarn "it is not tracked by darcs"+                             -rm_help :: String-rm_help =+          mrp _ _ _ [] = return (Sealed NilFL)++rmDescription :: String+rmDescription = "Help newbies find `darcs remove'."++rmHelp :: String+rmHelp =  "The `darcs rm' command does nothing.\n" ++  "\n" ++  "The normal way to remove a file from version control is simply to\n" ++@@ -122,10 +137,10 @@  "control WITHOUT affecting the working tree, see `darcs remove'.\n"  rm :: DarcsCommand-rm = command_stub "rm" rm_help rm_description remove+rm = commandStub "rm" rmHelp rmDescription remove  unadd :: DarcsCommand-unadd = command_alias "unadd" remove+unadd = commandAlias "unadd" remove \end{code}  
src/Darcs/Commands/Repair.lhs view
@@ -17,54 +17,59 @@  \darcsCommand{repair} \begin{code}-module Darcs.Commands.Repair ( repair ) where+module Darcs.Commands.Repair ( repair, repairCmd ) where import System.IO+import Control.Monad( unless )+import System.Directory( renameFile )  import Darcs.Commands-import Darcs.Arguments ( DarcsFlag(),-                        working_repo_dir, umask_option,+import Darcs.Arguments ( DarcsFlag( Quiet ),+                        workingRepoDir, umaskOption,                       ) import Darcs.Repository ( withRepoLock, ($-), amInRepository,-                          replacePristineFromSlurpy, writePatchSet )-import Darcs.Repository.Repair( replayRepository,-                                RepositoryConsistency(..) )+                          replacePristine, writePatchSet )+import Darcs.Repository.Repair( replayRepository, checkIndex+                              , RepositoryConsistency(..) ) -repair_description :: String-repair_description = "Repair a corrupted repository."+repairDescription :: String+repairDescription = "Repair a corrupted repository." -repair_help :: String-repair_help =+repairHelp :: String+repairHelp =  "The `darcs repair' command attempts to fix corruption in the current\n" ++  "repository.  Currently it can only repair damage to the pristine tree,\n" ++  "which is where most corruption occurs.\n"  repair :: DarcsCommand-repair = DarcsCommand {command_name = "repair",-                       command_help = repair_help,-                       command_description = repair_description,-                       command_extra_args = 0,-                       command_extra_arg_help = [],-                       command_command = repair_cmd,-                       command_prereq = amInRepository,-                       command_get_arg_possibilities = return [],-                       command_argdefaults = nodefaults,-                       command_advanced_options = [umask_option],-                       command_basic_options = [working_repo_dir]}+repair = DarcsCommand {commandName = "repair",+                       commandHelp = repairHelp,+                       commandDescription = repairDescription,+                       commandExtraArgs = 0,+                       commandExtraArgHelp = [],+                       commandCommand = repairCmd,+                       commandPrereq = amInRepository,+                       commandGetArgPossibilities = return [],+                       commandArgdefaults = nodefaults,+                       commandAdvancedOptions = [umaskOption],+                       commandBasicOptions = [workingRepoDir]} -repair_cmd :: [DarcsFlag] -> [String] -> IO ()-repair_cmd opts _ = withRepoLock opts $- \repository -> do+repairCmd :: [DarcsFlag] -> [String] -> IO ()+repairCmd opts _ = withRepoLock opts $- \repository -> do   replayRepository repository opts $ \state ->     case state of       RepositoryConsistent ->           putStrLn "The repository is already consistent, no changes made."-      BrokenPristine s -> do+      BrokenPristine tree -> do                putStrLn "Fixing pristine tree..."-               replacePristineFromSlurpy repository s-      BrokenPatches s newps  -> do+               replacePristine repository tree+      BrokenPatches tree newps  -> do                putStrLn "Writing out repaired patches..."                writePatchSet newps opts                putStrLn "Fixing pristine tree..."-               replacePristineFromSlurpy repository s+               replacePristine repository tree                return ()+  index_ok <- checkIndex repository (Quiet `elem` opts)+  unless index_ok $ do renameFile "_darcs/index" "_darcs/index.bad"+                       putStrLn "Bad index discarded."  \end{code}
src/Darcs/Commands/Replace.lhs view
@@ -23,37 +23,46 @@ module Darcs.Commands.Replace ( replace ) where  import Data.Maybe ( isJust )-import Control.Monad ( unless )+import Control.Monad ( unless, filterM )+import Control.Applicative( (<$>) ) -import Darcs.Commands ( DarcsCommand(DarcsCommand, command_name, command_help,-                        command_description, command_extra_args,-                        command_extra_arg_help, command_command, command_prereq,-                        command_get_arg_possibilities, command_argdefaults,-                        command_advanced_options, command_basic_options),+import Darcs.Commands ( DarcsCommand(DarcsCommand, commandName, commandHelp,+                        commandDescription, commandExtraArgs,+                        commandExtraArgHelp, commandCommand, commandPrereq,+                        commandGetArgPossibilities, commandArgdefaults,+                        commandAdvancedOptions, commandBasicOptions),                         nodefaults )-import Darcs.Arguments ( DarcsFlag(ForceReplace, Toks), list_registered_files,-                         ignoretimes, umask_option, tokens, force_replace,-                         working_repo_dir, fixSubPaths )+import Darcs.Arguments ( DarcsFlag(ForceReplace, Toks), listRegisteredFiles,+                         ignoretimes, umaskOption, tokens, forceReplace,+                         workingRepoDir, fixSubPaths ) import Darcs.Repository ( withRepoLock, ($-),-                    add_to_pending, slurp_pending,-                    amInRepository, slurp_recorded_and_unrecorded,+                    add_to_pending,+                    amInRepository,                     applyToWorking,+                    readUnrecorded, readRecordedAndPending                   )-import Darcs.Patch ( Prim, apply_to_slurpy, tokreplace, force_replace_slurpy )-import Darcs.Ordered ( FL(..), unsafeFL, (+>+), concatFL )-import Darcs.SlurpDirectory ( slurp_hasfile, Slurpy )-import RegChars ( regChars )+import Darcs.Patch ( Prim, tokreplace, applyToTree )+import Darcs.Patch.Apply ( forceTokReplace )+import Darcs.Patch.FileName( fn2fp )+import Darcs.Patch.Patchy ( Apply )+import Darcs.Witnesses.Ordered ( FL(..), unsafeFL, (+>+), concatFL )+import Darcs.Patch.RegChars ( regChars ) import Data.Char ( isSpace )-import Darcs.Diff ( unsafeDiff )-import Darcs.RepoPath ( SubPath, sp2fn, toFilePath )+import Darcs.RepoPath ( SubPath, toFilePath, sp2fn ) import Darcs.Repository.Prefs ( FileType(TextFile) )+import Darcs.Diff( treeDiff )+import Storage.Hashed.Tree( readBlob, modifyTree , findFile, TreeItem(..), Tree, makeBlobBS )+import Storage.Hashed.AnchoredPath( AnchoredPath, floatPath )++import qualified Data.ByteString.Lazy as BL+import qualified Data.ByteString as BS #include "impossible.h" -replace_description :: String-replace_description = "Substitute one word for another."+replaceDescription :: String+replaceDescription = "Substitute one word for another." -replace_help :: String-replace_help =+replaceHelp :: String+replaceHelp =  "In addition to line-based patches, Darcs supports a limited form of\n" ++  "lexical substitution.  Files are treated as sequences of words, and\n" ++  "each occurrence of the old word is replaced by the new word.\n" ++@@ -135,85 +144,99 @@ \begin{code}  replace :: DarcsCommand-replace = DarcsCommand {command_name = "replace",-                        command_help = replace_help,-                        command_description = replace_description,-                        command_extra_args = -1,-                        command_extra_arg_help = ["<OLD>","<NEW>",+replace = DarcsCommand {commandName = "replace",+                        commandHelp = replaceHelp,+                        commandDescription = replaceDescription,+                        commandExtraArgs = -1,+                        commandExtraArgHelp = ["<OLD>","<NEW>",                                                   "<FILE> ..."],-                        command_command = replace_cmd,-                        command_prereq = amInRepository,-                        command_get_arg_possibilities = list_registered_files,-                        command_argdefaults = nodefaults,-                        command_advanced_options = [ignoretimes, umask_option],-                        command_basic_options =-                            [tokens, force_replace, working_repo_dir]}+                        commandCommand = replaceCmd,+                        commandPrereq = amInRepository,+                        commandGetArgPossibilities = listRegisteredFiles,+                        commandArgdefaults = nodefaults,+                        commandAdvancedOptions = [ignoretimes, umaskOption],+                        commandBasicOptions =+                            [tokens, forceReplace, workingRepoDir]} -replace_cmd :: [DarcsFlag] -> [String] -> IO ()-replace_cmd opts (old:new:relfs) = withRepoLock opts $- \repository -> do+replaceCmd :: [DarcsFlag] -> [String] -> IO ()+replaceCmd opts (old:new:relfs) = withRepoLock opts $- \repository -> do   fs <- fixSubPaths opts relfs-  toks <- choose_toks opts old new+  toks <- chooseToks opts old new   let checkToken tok =-        unless (is_tok toks tok) $ fail $ "'"++tok++"' is not a valid token!"+        unless (isTok toks tok) $ fail $ "'"++tok++"' is not a valid token!"   checkToken old   checkToken new-  (_, work) <- slurp_recorded_and_unrecorded repository-  cur <- slurp_pending repository-  pswork <- (concatFL . unsafeFL) `fmap` sequence (map (repl toks cur work) fs)+  work <- readUnrecorded repository+  cur <- readRecordedAndPending repository+  files <- filterM (exists work) fs+  pswork <- concatFL . unsafeFL <$> mapM (repl toks cur work) files   add_to_pending repository pswork   applyToWorking repository opts pswork `catch` \e ->       fail $ "Can't do replace on working!\n"           ++ "Perhaps one of the files already contains '"++ new++"'?\n"           ++ show e   where ftf _ = TextFile--        repl :: String -> Slurpy -> Slurpy -> SubPath -> IO (FL Prim)+        skipmsg f = "Skipping file '" ++ toFilePath f ++ "' which isn't in the repository."+        exists tree file = if isJust $ findFile tree (floatSubPath file)+                              then return True+                              else do putStrLn $ skipmsg file+                                      return False+        repl :: String -> Tree IO -> Tree IO -> SubPath -> IO (FL Prim)         repl toks cur work f =-          if not $ slurp_hasfile (sp2fn f) work-          then do putStrLn $ "Skipping file '"++f_fp++"' which isn't in the repository."-                  return NilFL-          else if ForceReplace `elem` opts ||-                  isJust (apply_to_slurpy (tokreplace f_fp toks old new) work) ||-                  isJust (apply_to_slurpy (tokreplace f_fp toks old new) cur)-               then return (get_force_replace f toks work)-               else do putStrLn $ "Skipping file '"++f_fp++"'"-                       putStrLn $ "Perhaps the recorded version of this " ++-                                  "file already contains '" ++new++"'?"-                       putStrLn $ "Use the --force option to override."-                       return NilFL+          do work_replaced <- maybeApplyToTree replace_patch work+             cur_replaced <- maybeApplyToTree replace_patch cur+             if ForceReplace `elem` opts || isJust work_replaced || isJust cur_replaced+                then get_force_replace f toks work+                else do putStrLn $ "Skipping file '"++f_fp++"'"+                        putStrLn $ "Perhaps the recorded version of this " +++                                   "file already contains '" ++new++"'?"+                        putStrLn $ "Use the --force option to override."+                        return NilFL           where f_fp = toFilePath f+                replace_patch = tokreplace f_fp toks old new -        get_force_replace :: SubPath -> String -> Slurpy -> FL Prim-        get_force_replace f toks s =-            case force_replace_slurpy (tokreplace f_fp toks new old) s of-            Nothing -> bug "weird forcing bug in replace."-            Just s' -> case unsafeDiff [] ftf s s' of-                       pfix -> pfix +>+ (tokreplace f_fp toks old new :>: NilFL)+        get_force_replace :: SubPath -> String -> Tree IO -> IO (FL Prim)+        get_force_replace f toks tree = do+            let path = floatSubPath f+            content <- readBlob $ fromJust $ findFile tree path+            let newcontent = forceTokReplace toks new old (BS.concat $ BL.toChunks content)+                tree' = modifyTree tree path (File . makeBlobBS <$> newcontent)+            case newcontent of+              Nothing -> bug "weird forcing bug in replace."+              Just _ -> do pfix <- treeDiff ftf tree tree'+                           return $ pfix +>+ (tokreplace f_fp toks old new :>: NilFL)             where f_fp = toFilePath f -replace_cmd _ _ = fail "Usage: darcs replace OLD NEW [FILES]"+replaceCmd _ _ = fail "Usage: darcs replace OLD NEW [FILES]" -default_toks :: String-default_toks = "A-Za-z_0-9"-filename_toks :: String-filename_toks = "A-Za-z_0-9\\-\\."+floatSubPath :: SubPath -> AnchoredPath+floatSubPath = floatPath . fn2fp . sp2fn +maybeApplyToTree :: Apply p => p -> Tree IO -> IO (Maybe (Tree IO))+maybeApplyToTree patch tree = catch (Just `fmap` applyToTree patch tree)+                                    (\_ -> return Nothing)++defaultToks :: String+defaultToks = "A-Za-z_0-9"+filenameToks :: String+filenameToks = "A-Za-z_0-9\\-\\."+ -- | Given a set of characters and a string, returns true iff the -- string contains only characters from the set.  A set beginning with -- a caret (@^@) is treated as a complementary set.-is_tok :: String -> String -> Bool-is_tok _ "" = False-is_tok toks s = and $ map (regChars toks) s+isTok :: String -> String -> Bool+isTok _ "" = False+isTok toks s = and $ map (regChars toks) s  -- | This function checks for @--token-chars@ on the command-line.  If -- found, it validates the argument and returns it, without the -- surrounding square brackets.  Otherwise, it returns either--- 'default_toks' or 'filename_toks' as explained in 'replace_help'.+-- 'defaultToks' or 'filenameToks' as explained in 'replaceHelp'. --  -- Note: Limitations in the current replace patch file format prevents -- tokens and token-char specifiers from containing any whitespace.-choose_toks :: [DarcsFlag] -> String -> String -> IO String-choose_toks (Toks t:_) a b+chooseToks :: [DarcsFlag] -> String -> String -> IO String+chooseToks (Toks t:_) a b     | length t <= 2 =         bad_token_spec $ "It must contain more than 2 characters, because " ++                          "it should be enclosed in square brackets"@@ -225,16 +248,16 @@         bad_token_spec "Space is not allowed in the spec"     | any isSpace a = bad_token_spec $ spacey_token a     | any isSpace b = bad_token_spec $ spacey_token b-    | not (is_tok tok a) = bad_token_spec $ not_a_token a-    | not (is_tok tok b) = bad_token_spec $ not_a_token b+    | not (isTok tok a) = bad_token_spec $ not_a_token a+    | not (isTok tok b) = bad_token_spec $ not_a_token b     | otherwise          = return tok     where tok = init $ tail t :: String           bad_token_spec msg = fail $ "Bad token spec: '"++ t ++"' ("++ msg ++")"           spacey_token x = x ++ " must not contain any space"           not_a_token x = x ++ " is not a token, according to your spec"-choose_toks (_:fs) a b = choose_toks fs a b-choose_toks [] a b = if is_tok default_toks a && is_tok default_toks b-                     then return default_toks-                     else return filename_toks+chooseToks (_:fs) a b = chooseToks fs a b+chooseToks [] a b = if isTok defaultToks a && isTok defaultToks b+                     then return defaultToks+                     else return filenameToks \end{code} 
src/Darcs/Commands/Revert.lhs view
@@ -25,33 +25,31 @@ import English (englishNum, This(..), Noun(..)) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag( All, Debug ),-                        ignoretimes, working_repo_dir,-                        all_interactive,+                        ignoretimes, workingRepoDir,+                        allInteractive,                         fixSubPaths, areFileArgs,-                        list_registered_files, umask_option,+                        listRegisteredFiles, umaskOption,                       ) import Darcs.Utils ( askUser )-import Darcs.RepoPath ( toFilePath, sp2fn )+import Darcs.RepoPath ( toFilePath ) import Darcs.Repository ( withRepoLock, ($-), withGutsOf,-                    get_unrecorded_in_files,-                    get_unrecorded_in_files_unsorted,-                    add_to_pending, sync_repo,+                    add_to_pending,                     applyToWorking,-                    amInRepository, slurp_recorded,+                    amInRepository, readRecorded,+                    unrecordedChanges                   )-import Darcs.Patch ( invert, apply_to_filepaths, commute )-import Darcs.Ordered ( FL(..), (:>)(..), lengthFL, nullFL, (+>+) )+import Darcs.Patch ( invert, applyToFilepaths, commute )+import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), lengthFL, nullFL, (+>+) ) import Darcs.SelectChanges ( with_selected_last_changes_to_files' ) import Darcs.Patch.TouchesFiles ( choose_touching )-import Darcs.Commands.Unrevert ( write_unrevert )-import Darcs.Sealed ( unsafeUnseal )-import Darcs.Gorsvet( invalidateIndex )+import Darcs.Commands.Unrevert ( writeUnrevert )+import Darcs.Witnesses.Sealed ( unsafeUnseal ) -revert_description :: String-revert_description = "Discard unrecorded changes."+revertDescription :: String+revertDescription = "Discard unrecorded changes." -revert_help :: String-revert_help =+revertHelp :: String+revertHelp =  "The `darcs revert' command discards unrecorded changes the working\n" ++  "tree.  As with `darcs record', you will be asked which hunks (changes)\n" ++  "to revert.  The --all switch can be used to avoid such prompting. If\n" ++@@ -65,33 +63,30 @@  "revert' ran.\n"  revert :: DarcsCommand-revert = DarcsCommand {command_name = "revert",-                       command_help = revert_help,-                       command_description = revert_description,-                       command_extra_args = -1,-                       command_extra_arg_help = ["[FILE or DIRECTORY]..."],-                       command_command = revert_cmd,-                       command_prereq = amInRepository,-                       command_get_arg_possibilities = list_registered_files,-                       command_argdefaults = nodefaults,-                       command_advanced_options = [ignoretimes, umask_option],-                       command_basic_options = [all_interactive,-                                               working_repo_dir]}+revert = DarcsCommand {commandName = "revert",+                       commandHelp = revertHelp,+                       commandDescription = revertDescription,+                       commandExtraArgs = -1,+                       commandExtraArgHelp = ["[FILE or DIRECTORY]..."],+                       commandCommand = revertCmd,+                       commandPrereq = amInRepository,+                       commandGetArgPossibilities = listRegisteredFiles,+                       commandArgdefaults = nodefaults,+                       commandAdvancedOptions = [ignoretimes, umaskOption],+                       commandBasicOptions = [allInteractive,+                                               workingRepoDir]} -revert_cmd :: [DarcsFlag] -> [String] -> IO ()-revert_cmd opts args = withRepoLock opts $- \repository -> do+revertCmd :: [DarcsFlag] -> [String] -> IO ()+revertCmd opts args = withRepoLock opts $- \repository -> do   files <- sort `fmap` fixSubPaths opts args-  let files_fn = map sp2fn files   when (areFileArgs files) $        putStrLn $ "Reverting changes in "++unwords (map show files)++"..\n"-  changes <- if All `elem` opts-                   then get_unrecorded_in_files_unsorted repository files_fn-                   else get_unrecorded_in_files repository files_fn-  let pre_changed_files = apply_to_filepaths (invert changes) (map toFilePath files)-  rec <- slurp_recorded repository+  changes <- unrecordedChanges opts repository files+  let pre_changed_files = applyToFilepaths (invert changes) (map toFilePath files)+  rec <- readRecorded repository   case unsafeUnseal $ choose_touching pre_changed_files changes of     NilFL -> putStrLn "There are no changes to revert!"-    _ -> with_selected_last_changes_to_files' "revert" opts+    _ -> with_selected_last_changes_to_files' "revert" opts Nothing                pre_changed_files changes $ \ (norevert:>p) ->         if nullFL p         then putStrLn $ "If you don't want to revert after all," ++@@ -104,16 +99,14 @@              case yorn of ('y':_) -> return ()                           _ -> exitWith $ ExitSuccess              withGutsOf repository $ do-                 invalidateIndex repository                  add_to_pending repository $ invert p                  when (Debug `elem` opts) $ putStrLn "About to write the unrevert file."                  case commute (norevert:>p) of-                   Just (p':>_) -> write_unrevert repository p' rec NilFL-                   Nothing -> write_unrevert repository (norevert+>+p) rec NilFL+                   Just (p':>_) -> writeUnrevert repository p' rec NilFL+                   Nothing -> writeUnrevert repository (norevert+>+p) rec NilFL                  when (Debug `elem` opts) $ putStrLn "About to apply to the working directory."                  applyToWorking repository opts (invert p) `catch` \e ->                      fail ("Unable to apply inverse patch!" ++ show e)-  sync_repo repository   putStrLn "Finished reverting." \end{code} 
src/Darcs/Commands/Rollback.lhs view
@@ -28,54 +28,45 @@ import Data.Maybe ( isJust ) import System.Directory ( removeFile ) -import Darcs.Commands ( DarcsCommand(..), nodefaults, loggers )-import Darcs.Arguments ( DarcsFlag(MarkConflicts), fixSubPaths, get_author,+import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag(MarkConflicts), fixSubPaths, getAuthor,                          definePatches,-                         working_repo_dir, nocompress,-                         author, patchname_option, ask_long_comment,-                         leave_test_dir, notest, list_registered_files,-                         match_several_or_last, all_interactive, umask_option+                         workingRepoDir, nocompress,+                         author, patchnameOption, askLongComment,+                         leaveTestDir, notest, listRegisteredFiles,+                         matchSeveralOrLast, allInteractive, umaskOption                        ) import Darcs.RepoPath ( toFilePath )-import Darcs.Repository ( amInRepository, withRepoLock, ($-), applyToWorking,+import Darcs.Repository ( Repository, amInRepository, withRepoLock, ($-),+                          applyToWorking,                           read_repo, slurp_recorded,                           tentativelyMergePatches, withGutsOf,-                          finalizeRepositoryChanges, sync_repo )-import Darcs.Patch ( summary, invert, namepatch, effect, fromPrims,-                     sort_coalesceFL, canonize )-import Darcs.Ordered-import Darcs.Hopefully ( n2pia )+                          finalizeRepositoryChanges, invalidateIndex )+import Darcs.Patch ( RepoPatch, summary, invert, namepatch, effect, fromPrims,+                     sortCoalesceFL, canonize )+import Darcs.Patch.Prim ( Prim )+import Darcs.Witnesses.Ordered+import Darcs.Hopefully ( PatchInfoAnd, n2pia ) import Darcs.Lock ( world_readable_temp )-import Darcs.SlurpDirectory ( empty_slurpy, wait_a_moment )-import Darcs.Match ( first_match )+import Darcs.SlurpDirectory ( empty_slurpy )+import Darcs.Match ( firstMatch ) import Darcs.SelectChanges ( with_selected_last_changes_to_files_reversed,                              with_selected_last_changes_to_files' )-import Darcs.Commands.Record ( file_exists, get_log )-import Darcs.Commands.Unrecord ( get_last_patches )-import Darcs.Utils ( clarify_errors )+import Darcs.Commands.Record ( fileExists, getLog )+import Darcs.Commands.Unrecord ( getLastPatches )+import Darcs.Utils ( clarifyErrors ) import Printer ( renderString ) import Progress ( debugMessage )-import Darcs.Sealed ( Sealed(..), FlippedSeal(..) )+import Darcs.Witnesses.Sealed ( Sealed(..), FlippedSeal(..) ) import IsoDate ( getIsoDateTime )-import Darcs.Gorsvet( invalidateIndex ) #include "impossible.h" -rollback_description :: String-rollback_description =+rollbackDescription :: String+rollbackDescription =  "Record a new patch reversing some recorded changes."-\end{code} -If you decide you didn't want to roll back a patch-after all, you can reverse its effect by obliterating the rolled-back patch.--Rollback can actually allow you to roll back a subset of the changes made-by the selected patch or patches.  Many of the options available in-rollback behave similarly to the options for unrecord~\ref{unrecord} and-record~\ref{record}.--\begin{code}-rollback_help :: String-rollback_help =+rollbackHelp :: String+rollbackHelp =  "Rollback is used to undo the effects of one or more patches without actually\n"++  "deleting them.  Instead, it creates a new patch reversing selected portions.\n"++  "of those changes. Unlike obliterate and unrecord (which accomplish a similar\n"++@@ -83,57 +74,60 @@  "of its changes.\n"  rollback :: DarcsCommand-rollback = DarcsCommand {command_name = "rollback",-                         command_help = rollback_help,-                         command_description = rollback_description,-                         command_extra_args = -1,-                         command_extra_arg_help = ["[FILE or DIRECTORY]..."],-                         command_command = rollback_cmd,-                         command_prereq = amInRepository,-                         command_get_arg_possibilities = list_registered_files,-                         command_argdefaults = nodefaults,-                         command_advanced_options = [nocompress,umask_option],-                         command_basic_options = [match_several_or_last,-                                                  all_interactive,-                                                  author, patchname_option, ask_long_comment,-                                                  notest, leave_test_dir,-                                                  working_repo_dir]}+rollback = DarcsCommand {commandName = "rollback",+                         commandHelp = rollbackHelp,+                         commandDescription = rollbackDescription,+                         commandExtraArgs = -1,+                         commandExtraArgHelp = ["[FILE or DIRECTORY]..."],+                         commandCommand = rollbackCmd,+                         commandPrereq = amInRepository,+                         commandGetArgPossibilities = listRegisteredFiles,+                         commandArgdefaults = nodefaults,+                         commandAdvancedOptions = [nocompress,umaskOption],+                         commandBasicOptions = [matchSeveralOrLast,+                                                  allInteractive,+                                                  author, patchnameOption, askLongComment,+                                                  notest, leaveTestDir,+                                                  workingRepoDir]} -rollback_cmd :: [DarcsFlag] -> [String] -> IO ()-rollback_cmd opts args = withRepoLock opts $- \repository -> do-  let (logMessage,_,_) = loggers opts+rollbackCmd :: [DarcsFlag] -> [String] -> IO ()+rollbackCmd opts args = withRepoLock opts $- \repository -> do   rec <- if null args then return empty_slurpy          else slurp_recorded repository   files <- sort `fmap` fixSubPaths opts args-  existing_files <- map toFilePath `fmap` filterM (file_exists rec) files-  non_existent_files <- map toFilePath `fmap` filterM (fmap not . file_exists rec) files+  existing_files <- map toFilePath `fmap` filterM (fileExists rec) files+  non_existent_files <- map toFilePath `fmap` filterM (fmap not . fileExists rec) files   when (not $ null existing_files) $-       logMessage $ "Recording changes in "++unwords existing_files++":\n"+       putStrLn $ "Recording changes in "++unwords existing_files++":\n"   when (not $ null non_existent_files) $-       logMessage $ "Non existent files or directories: "++unwords non_existent_files++"\n"+       putStrLn $ "Non existent files or directories: "++unwords non_existent_files++"\n"   when ((not $ null non_existent_files) && null existing_files) $        fail "None of the files you specified exist!"   allpatches <- read_repo repository-  FlippedSeal patches <- return $ if first_match opts-                                  then get_last_patches opts allpatches+  FlippedSeal patches <- return $ if firstMatch opts+                                  then getLastPatches opts allpatches                                   else FlippedSeal $ concatRL allpatches-  with_selected_last_changes_to_files_reversed "rollback" opts existing_files-      (reverseRL patches) $-    \ (_ :> ps) ->-    do when (nullFL ps) $ do logMessage "No patches selected!"-                             exitWith ExitSuccess-       definePatches ps-       with_selected_last_changes_to_files' "rollback" opts-               existing_files (concatFL $ mapFL_FL canonize $-                               sort_coalesceFL $ effect ps) $ \ (_:>ps'') ->-         do when (nullFL ps'') $ do logMessage "No changes selected!"+  with_selected_last_changes_to_files_reversed "rollback" opts Nothing existing_files+      (reverseRL patches) $ \ (_ :> ps) ->+          do when (nullFL ps) $ do putStrLn "No patches selected!"+                                   exitWith ExitSuccess+             definePatches ps+             with_selected_last_changes_to_files' "rollback" opts Nothing+               existing_files (concatFL $ mapFL_FL canonize $ sortCoalesceFL $ effect ps)+               (rollItBackNow opts repository ps)++rollItBackNow :: (RepoPatch p1, RepoPatch p) =>+                [DarcsFlag] -> Repository p1 ->  FL (PatchInfoAnd p)+                            -> (t :> FL Prim) -> IO ()+rollItBackNow opts repository  ps (_ :> ps'') =+         do when (nullFL ps'') $ do putStrLn "No changes selected!"                                     exitWith ExitSuccess             let make_log = world_readable_temp "darcs-rollback"                 newlog = Just ("", "":"rolling back:":"":lines (renderString $ summary ps ))             --tentativelyRemovePatches repository opts (mapFL_FL hopefully ps)-            (name, my_log, logf) <- get_log opts newlog make_log $ invert ps''+            (name, my_log, logf) <- getLog opts newlog make_log $ invert ps''             date <- getIsoDateTime-            my_author <- get_author opts+            my_author <- getAuthor opts             rbp <- n2pia `fmap` namepatch date name my_author my_log                                           (fromPrims $ invert ps'')             debugMessage "Adding rollback patch to repository."@@ -144,13 +138,10 @@             withGutsOf repository $ do               finalizeRepositoryChanges repository               debugMessage "About to apply rolled-back changes to working directory."-              -- so work will be more recent than rec:-              revertable $ do wait_a_moment-                              applyToWorking repository opts pw+              revertable $ applyToWorking repository opts pw             when (isJust logf) $ removeFile (fromJust logf)-            sync_repo repository-            logMessage $ "Finished rolling back."-          where revertable x = x `clarify_errors` unlines+            putStrLn "Finished rolling back."+          where revertable x = x `clarifyErrors` unlines                   ["Error applying patch to the working directory.","",                    "This may have left your working directory an inconsistent",                    "but recoverable state. If you had no un-recorded changes",
src/Darcs/Commands/Send.lhs view
@@ -28,33 +28,34 @@ import Control.Monad ( when, unless, forM_ ) import Data.Maybe ( isJust, isNothing ) -import Darcs.Commands ( DarcsCommand(..) )-import Darcs.Arguments ( DarcsFlag( EditDescription, LogFile, RmLogFile,+import Darcs.Commands ( DarcsCommand(..), putInfo, putVerbose )+import Darcs.Arguments ( DarcsFlag( EditDescription, LogFile,                                     Target, OutputAutoName, Output, Context,-                                    DryRun, Verbose, Quiet, Unified+                                    DryRun, Quiet, Unified                                   ),                          fixUrl, definePatches,-                         get_cc, get_author, working_repo_dir,-                         edit_description, logfile, rmlogfile,-                         sign, get_subject, deps_sel, get_in_reply_to,-                         match_several, set_default, output_auto_name,-                         output, cc, subject, target, author, sendmail_cmd,-                         in_reply_to, remote_repo, network_options,-                         all_interactive, get_sendmail_cmd,-                         print_dry_run_message_and_exit,-                         summary, allow_unrelated_repos,-                         from_opt, dry_run, send_to_context,+                         getCc, getAuthor, workingRepoDir,+                         editDescription, logfile, rmlogfile,+                         sign, getSubject, depsSel, getInReplyTo,+                         matchSeveral, setDefault, outputAutoName,+                         output, ccSend, subject, target, author, sendmailCmd,+                         inReplyTo, remoteRepo, networkOptions,+                         allInteractive, getSendmailCmd,+                         printDryRunMessageAndExit,+                         summary, allowUnrelatedRepos,+                         fromOpt, dryRun, sendToContext,                        )+import Darcs.Flags ( willRemoveLogFile ) import Darcs.Hopefully ( PatchInfoAnd, hopefully, info ) import Darcs.Repository ( PatchSet, Repository,                           amInRepository, identifyRepositoryFor, withRepoReadLock, ($-),-                          read_repo, slurp_recorded, prefsUrl, checkUnrelatedRepos )-import Darcs.Patch ( RepoPatch, description, apply_to_slurpy, invert )-import Darcs.Ordered ( FL(..), RL(..), (:>)(..), (:\/:)(..), unsafeUnRL,+                          read_repo, readRecorded, prefsUrl, checkUnrelatedRepos )+import Darcs.Patch ( RepoPatch, description, applyToTree, invert )+import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (:\/:)(..),                        mapRL_RL, mapFL, mapRL, reverseRL, mapFL_FL, lengthFL, nullFL ) import Darcs.Patch.Bundle ( make_bundle, scan_context ) import Darcs.Patch.Info ( just_name )-import Darcs.Repository.Prefs ( defaultrepo, set_defaultrepo, get_preflist )+import Darcs.Repository.Prefs ( defaultrepo, setDefaultrepo, getPreflist ) import Darcs.External ( signString, sendEmailDoc, fetchFilePS, Cachable(..), generateEmail ) import ByteStringUtils ( mmapFilePS ) import qualified Data.ByteString.Char8 as BC (unpack)@@ -64,18 +65,20 @@ import Darcs.Utils ( askUser, catchall, edit_file, formatPath ) import Progress ( debugMessage ) import Darcs.Email ( make_email )-import Printer ( Doc, vsep, vcat, text, ($$), putDocLn, putDoc )-import Darcs.RepoPath ( toFilePath, AbsolutePath, AbsolutePathOrStd,+import Printer ( Doc, vsep, vcat, text, ($$), (<+>), (<>), putDoc )+import Darcs.RepoPath ( FilePathLike, toFilePath, AbsolutePath, AbsolutePathOrStd,                         getCurrentDirectory, makeAbsoluteOrStd, useAbsoluteOrStd ) import HTTP ( postUrl ) #include "impossible.h" -send_description :: String-send_description =+#include "gadts.h"++sendDescription :: String+sendDescription =  "Send by email a bundle of one or more patches." -send_help :: String-send_help =+sendHelp :: String+sendHelp =  "Send is used to prepare a bundle of patches that can be applied to a target\n"++  "repository.  Send accepts the URL of the repository as an argument.  When\n"++  "called without an argument, send will use the most recent repository that\n"++@@ -109,36 +112,36 @@  \begin{code} send :: DarcsCommand-send = DarcsCommand {command_name = "send",-                     command_help = send_help,-                     command_description = send_description,-                     command_extra_args = 1,-                     command_extra_arg_help = ["[REPOSITORY]"],-                     command_command = send_cmd,-                     command_prereq = amInRepository,-                     command_get_arg_possibilities = get_preflist "repos",-                     command_argdefaults = defaultrepo,-                     command_advanced_options = [logfile, rmlogfile,-                                                 remote_repo,-                                                 send_to_context] ++-                                                network_options,-                     command_basic_options = [match_several, deps_sel,-                                              all_interactive,-                                              from_opt, author,-                                              target,cc,subject, in_reply_to,-                                              output,output_auto_name,sign]-                                              ++dry_run++[summary,-                                              edit_description,-                                              set_default, working_repo_dir,-                                              sendmail_cmd,-                                              allow_unrelated_repos]}+send = DarcsCommand {commandName = "send",+                     commandHelp = sendHelp,+                     commandDescription = sendDescription,+                     commandExtraArgs = 1,+                     commandExtraArgHelp = ["[REPOSITORY]"],+                     commandCommand = sendCmd,+                     commandPrereq = amInRepository,+                     commandGetArgPossibilities = getPreflist "repos",+                     commandArgdefaults = defaultrepo,+                     commandAdvancedOptions = [logfile, rmlogfile,+                                                 remoteRepo,+                                                 sendToContext] +++                                                networkOptions,+                     commandBasicOptions = [matchSeveral, depsSel,+                                              allInteractive,+                                              fromOpt, author,+                                              target,ccSend,subject, inReplyTo,+                                              output,outputAutoName,sign]+                                              ++dryRun++[summary,+                                              editDescription,+                                              setDefault, workingRepoDir,+                                              sendmailCmd,+                                              allowUnrelatedRepos]} -send_cmd :: [DarcsFlag] -> [String] -> IO ()-send_cmd input_opts [""] = send_cmd input_opts []-send_cmd input_opts [unfixedrepodir] = withRepoReadLock input_opts $- \repository -> do+sendCmd :: [DarcsFlag] -> [String] -> IO ()+sendCmd input_opts [""] = sendCmd input_opts []+sendCmd input_opts [unfixedrepodir] = withRepoReadLock input_opts $- \repository -> do   context_ps <- the_context input_opts   case context_ps of-    Just them -> send_to_them repository input_opts [] "CONTEXT" them+    Just them -> sendToThem repository input_opts [] "CONTEXT" them     Nothing -> do         repodir <- fixUrl input_opts unfixedrepodir         -- Test to make sure we aren't trying to push to the current repo@@ -147,88 +150,84 @@            fail ("Can't send to current repository! Did you mean send -"++"-context?")         repo <- identifyRepositoryFor repository repodir         them <- read_repo repo-        old_default <- get_preflist "defaultrepo"-        set_defaultrepo repodir input_opts+        old_default <- getPreflist "defaultrepo"+        setDefaultrepo repodir input_opts         when (old_default == [repodir] && not (Quiet `elem` input_opts)) $              putStrLn $ "Creating patch to "++formatPath repodir++"..."-        wtds <- decide_on_behavior input_opts repo-        send_to_them repository input_opts wtds repodir them+        wtds <- decideOnBehavior input_opts repo+        sendToThem repository input_opts wtds repodir them     where the_context [] = return Nothing           the_context (Context foo:_)               = (Just . scan_context )`fmap` mmapFilePS (toFilePath foo)           the_context (_:fs) = the_context fs-send_cmd _ _ = impossible+sendCmd _ _ = impossible -send_to_them :: RepoPatch p => Repository p -> [DarcsFlag] -> [WhatToDo] -> String -> PatchSet p -> IO ()-send_to_them repo opts wtds their_name them = do-  let am_verbose = Verbose `elem` opts-      am_quiet = Quiet `elem` opts-      putVerbose s = when am_verbose $ putDocLn s-      putInfo s = when (not am_quiet) $ putStrLn s-      patch_desc p = just_name $ info p-      make_fname tbs = patch_filename $ patch_desc $ headFL tbs-      headFL (x:>:_) = x-      headFL _ = impossible+sendToThem :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> [WhatToDo] -> String -> PatchSet p C(x) -> IO ()+sendToThem repo opts wtds their_name them = do   us <- read_repo repo   case get_common_and_uncommon (us, them) of     (common, us' :\/: _) -> do      checkUnrelatedRepos opts common us them-     case us' of-         NilRL:<:NilRL -> do putInfo "No recorded local changes to send!"-                             exitWith ExitSuccess-         _ -> putVerbose $ text "We have the following patches to send:"-                        $$ (vcat $ mapRL description $ head $ unsafeUnRL us')-     s <- slurp_recorded repo-     let our_ps = reverseRL $ head $ unsafeUnRL us'-     with_selected_changes "send" opts our_ps $+     (case us' of+         NilRL -> do putInfo opts $ text "No recorded local changes to send!"+                     exitWith ExitSuccess+         _ -> putVerbose opts $ text "We have the following patches to send:"+                        $$ (vcat $ mapRL description us')) :: IO ()+     pristine <- readRecorded repo+     let our_ps = reverseRL us'+     with_selected_changes "send" opts Nothing our_ps $       \ (to_be_sent :> _) -> do-      print_dry_run_message_and_exit "send" opts to_be_sent+      printDryRunMessageAndExit "send" opts to_be_sent       when (nullFL to_be_sent) $ do-          putInfo "You don't want to send any patches, and that's fine with me!"+          putInfo opts $ text "You don't want to send any patches, and that's fine with me!"           exitWith ExitSuccess       definePatches to_be_sent-      bundle <- signString opts $ make_bundle (Unified:opts)-                (fromJust $ apply_to_slurpy-                 (invert $-                  mapRL_RL hopefully $ head $ unsafeUnRL us') s)-                common (mapFL_FL hopefully to_be_sent)-      let outname = get_output opts (make_fname to_be_sent)+      pristine' <- applyToTree (invert $ mapRL_RL hopefully us') pristine+      unsig_bundle <- make_bundle (Unified:opts) pristine' common (mapFL_FL hopefully to_be_sent)+      bundle <- signString opts unsig_bundle+      let make_fname (tb:>:_) = patchFilename $ patchDesc tb+          make_fname _ = impossible+          fname = make_fname to_be_sent+          outname = getOutput opts fname       case outname of-        Just fname -> do (d,f) <- get_description opts to_be_sent-                         let putabs a = do writeDocBinFile a (d $$ bundle)-                                           putStrLn $ "Wrote patch to " ++ toFilePath a ++ "."-                             putstd = putDoc (d $$ bundle)-                         useAbsoluteOrStd putabs putstd fname-                         cleanup f-        Nothing ->+        Just fname' -> writeBundleToFile opts to_be_sent bundle fname' their_name+        Nothing -> sendBundle opts to_be_sent bundle fname wtds their_name++patchDesc :: forall p C(x y) . PatchInfoAnd p C(x y) -> String+patchDesc p = just_name $ info p++sendBundle :: forall p C(x y) . (RepoPatch p) => [DarcsFlag] -> FL (PatchInfoAnd p) C(x y)+             -> Doc -> String -> [WhatToDo] -> String -> IO ()+sendBundle opts to_be_sent bundle fname wtds their_name=          let-           auto_subject (p:>:NilFL)  = "darcs patch: " ++ trim (patch_desc p) 57-           auto_subject (p:>:ps) = "darcs patch: " ++ trim (patch_desc p) 43 +++           auto_subject :: forall pp C(x y) . FL (PatchInfoAnd pp) C(x y) -> String+           auto_subject (p:>:NilFL)  = "darcs patch: " ++ trim (patchDesc p) 57+           auto_subject (p:>:ps) = "darcs patch: " ++ trim (patchDesc p) 43 ++                             " (and " ++ show (lengthFL ps) ++ " more)"            auto_subject _ = error "Tried to get a name from empty patch list."            trim st n = if length st <= n then st                        else take (n-3) st ++ "..."            in do-           thetargets <- get_targets wtds-           from <- get_author opts-           let thesubject = case get_subject opts of+           thetargets <- getTargets wtds+           from <- getAuthor opts+           let thesubject = case getSubject opts of                             Nothing -> auto_subject to_be_sent                             Just subj -> subj-           (mailcontents, mailfile) <- get_description opts to_be_sent+           (mailcontents, mailfile) <- getDescription opts their_name to_be_sent            let body = make_email their_name-                        (maybe [] (\x -> [("In-Reply-To", x), ("References", x)]) . get_in_reply_to $ opts)+                        (maybe [] (\x -> [("In-Reply-To", x), ("References", x)]) . getInReplyTo $ opts)                         (Just mailcontents)                         bundle-                        (Just $ make_fname to_be_sent)+                        (Just fname)                contentAndBundle = Just (mailcontents, bundle)                                sendmail = do-                 sm_cmd <- get_sendmail_cmd opts-                 (sendEmailDoc from (lt [t | SendMail t <- thetargets]) (thesubject) (get_cc opts)+                 sm_cmd <- getSendmailCmd opts+                 (sendEmailDoc from (lt [t | SendMail t <- thetargets]) (thesubject) (getCc opts)                                sm_cmd contentAndBundle body >>-                  putInfo ("Successfully sent patch bundle to: "+                  (putInfo opts . text $ ("Successfully sent patch bundle to: "                             ++ lt [ t | SendMail t <- thetargets ]-                            ++ ccs (get_cc opts) ++"."))+                            ++ ccs (getCc opts) ++".")))                  `catch` \e -> let msg = "Email body left in " in                                do case mailfile of                                     Just mf -> putStrLn $ msg++mf++"."@@ -239,32 +238,44 @@             when (null [ p | Post p <- thetargets]) sendmail            nbody <- withOpenTemp $ \ (fh,fn) -> do-               generateEmail fh from (lt [t | SendMail t <- thetargets]) thesubject (get_cc opts) body+               generateEmail fh from (lt [t | SendMail t <- thetargets]) thesubject (getCc opts) body                hClose fh                mmapFilePS fn            forM_ [ p | Post p <- thetargets]              (\url -> do-                putInfo $ "Posting patch to " ++ url+                putInfo opts . text $ "Posting patch to " ++ url                 postUrl url (BC.unpack nbody) "message/rfc822")              `catch` const sendmail-           cleanup mailfile+           cleanup opts mailfile+         where+          lt [t] = t+          lt [t,""] = t+          lt (t:ts) = t++" , "++lt ts+          lt [] = "" -      where cleanup (Just mailfile) = when (isNothing (get_fileopt opts) || (RmLogFile `elem` opts)) $+cleanup :: (FilePathLike t) => [DarcsFlag] -> Maybe t -> IO ()+cleanup opts (Just mailfile) = when (isNothing (getFileopt opts) || (willRemoveLogFile opts)) $                                       removeFileMayNotExist mailfile-            cleanup Nothing = return ()-            lt [t] = t-            lt [t,""] = t-            lt (t:ts) = t++" , "++lt ts-            lt [] = ""+cleanup _ Nothing = return () +writeBundleToFile :: forall p C(x y) . (RepoPatch p) => [DarcsFlag] -> FL (PatchInfoAnd p) C(x y) -> Doc ->+                    AbsolutePathOrStd -> String -> IO ()+writeBundleToFile opts to_be_sent bundle fname their_name =+    do (d,f) <- getDescription opts their_name to_be_sent+       let putabs a = do writeDocBinFile a (d $$ bundle)+                         putStrLn $ "Wrote patch to " ++ toFilePath a ++ "."+           putstd = putDoc (d $$ bundle)+       useAbsoluteOrStd putabs putstd fname+       cleanup opts f+ safeFileChar :: Char -> Char safeFileChar c | isAlpha c = toLower c                | isDigit c = c                | isSpace c = '-' safeFileChar _ = '_' -patch_filename :: String -> String-patch_filename the_summary = name ++ ".dpatch"+patchFilename :: String -> String+patchFilename the_summary = name ++ ".dpatch"     where name = map safeFileChar the_summary \end{code} @@ -317,11 +328,11 @@     | SendMail String    -- ^ send patch via email  -decide_on_behavior :: RepoPatch p => [DarcsFlag] -> Repository p -> IO [WhatToDo]-decide_on_behavior opts the_remote_repo =+decideOnBehavior :: RepoPatch p => [DarcsFlag] -> Repository p C(r u t) -> IO [WhatToDo]+decideOnBehavior opts the_remote_repo =     case the_targets of     [] ->-          if isJust $ get_output opts ""+          if isJust $ getOutput opts ""           then return []           else           do wtds <- check_post@@ -329,7 +340,7 @@              return wtds     ts -> do announce_recipients ts              return ts-    where the_targets = collect_targets opts+    where the_targets = collectTargets opts #ifdef HAVE_HTTP           -- the ifdef above is to so that darcs only checks the remote           -- _darcs/post if we have an implementation of postUrl.  See@@ -352,27 +363,26 @@                           `catchall` return ""                  if '@' `elem` email then return . map SendMail $ lines email                                      else return []-          putInfoLn s = unless (Quiet `elem` opts) $ putStrLn s           announce_recipients emails =             let pn (SendMail s) = s                 pn (Post p) = p             in if DryRun `elem` opts-            then putInfoLn $ "Patch bundle would be sent to: "++unwords (map pn emails)+            then putInfo opts . text $ "Patch bundle would be sent to: "++unwords (map pn emails)             else when (null the_targets) $-                 putInfoLn $ "Patch bundle will be sent to: "++unwords (map pn emails)+                 putInfo opts . text $ "Patch bundle will be sent to: "++unwords (map pn emails) -get_output :: [DarcsFlag] -> FilePath -> Maybe AbsolutePathOrStd-get_output (Output a:_) _ = return a-get_output (OutputAutoName a:_) f = return $ makeAbsoluteOrStd a f-get_output (_:flags) f = get_output flags f-get_output [] _ = Nothing+getOutput :: [DarcsFlag] -> FilePath -> Maybe AbsolutePathOrStd+getOutput (Output a:_) _ = return a+getOutput (OutputAutoName a:_) f = return $ makeAbsoluteOrStd a f+getOutput (_:flags) f = getOutput flags f+getOutput [] _ = Nothing -get_targets :: [WhatToDo] -> IO [WhatToDo]-get_targets [] = do fmap ((:[]) . SendMail) $ askUser "What is the target email address? "-get_targets wtds = return wtds+getTargets :: [WhatToDo] -> IO [WhatToDo]+getTargets [] = do fmap ((:[]) . SendMail) $ askUser "What is the target email address? "+getTargets wtds = return wtds -collect_targets :: [DarcsFlag] -> [WhatToDo]-collect_targets flags = [ f t | Target t <- flags ] where+collectTargets :: [DarcsFlag] -> [WhatToDo]+collectTargets flags = [ f t | Target t <- flags ] where     f url@('h':'t':'t':'p':':':_) = Post url     f em = SendMail em @@ -416,12 +426,12 @@ \end{verbatim}  \begin{code}-get_description :: RepoPatch p => [DarcsFlag] -> FL (PatchInfoAnd p) -> IO (Doc, Maybe String)-get_description opts patches =+getDescription :: RepoPatch p => [DarcsFlag] -> String -> FL (PatchInfoAnd p) C(x y) -> IO (Doc, Maybe String)+getDescription opts their_name patches =     case get_filename of         Just f -> do file <- f                      when (EditDescription `elem` opts) $ do-                       when (isNothing $ get_fileopt opts) $+                       when (isNothing $ getFileopt opts) $                             writeDocBinFile file patchdesc                        debugMessage $ "About to edit file " ++ file                        edit_file file@@ -429,16 +439,21 @@                      doc <- readDocBinFile file                      return (doc, Just file)         Nothing -> return (patchdesc, Nothing)-    where patchdesc = vsep $ mapFL description patches-          get_filename = case get_fileopt opts of+    where patchdesc = text (if lengthFL patches == 1+                               then "1 patch"+                               else show (lengthFL patches) ++ " patches")+                      <+> text "for repository" <+> text their_name <> text ":"+                      $$ text ""+                      $$ vsep (mapFL description patches)+          get_filename = case getFileopt opts of                                 Just f -> Just $ return $ toFilePath f                                 Nothing -> if EditDescription `elem` opts                                               then Just tempfile                                               else Nothing           tempfile = world_readable_temp "darcs-temp-mail" -get_fileopt :: [DarcsFlag] -> Maybe AbsolutePath-get_fileopt (LogFile f:_) = Just f-get_fileopt (_:flags) = get_fileopt flags-get_fileopt [] = Nothing+getFileopt :: [DarcsFlag] -> Maybe AbsolutePath+getFileopt (LogFile f:_) = Just f+getFileopt (_:flags) = getFileopt flags+getFileopt [] = Nothing \end{code}
src/Darcs/Commands/SetPref.lhs view
@@ -26,31 +26,31 @@ import Control.Monad (when)  import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag, working_repo_dir, umask_option )+import Darcs.Arguments ( DarcsFlag, workingRepoDir, umaskOption ) import Darcs.Repository ( amInRepository, add_to_pending, withRepoLock, ($-) ) import Darcs.Patch ( changepref )-import Darcs.Ordered ( FL(..) )-import Darcs.Repository.Prefs ( get_prefval, change_prefval, )+import Darcs.Witnesses.Ordered ( FL(..) )+import Darcs.Repository.Prefs ( getPrefval, changePrefval, ) import English ( orClauses ) #include "impossible.h"  -- | A list of all valid preferences for @_darcs/prefs/prefs@.-valid_pref_data :: [(String, String)] -- ^ (name, one line description)-valid_pref_data =+validPrefData :: [(String, String)] -- ^ (name, one line description)+validPrefData =     [("test", "a shell command that runs regression tests"),      ("predist", "a shell command to run before `darcs dist'"),      ("boringfile", "the path to a version-controlled boring file"),      ("binariesfile", "the path to a version-controlled binaries file")] -valid_prefs :: [String]-valid_prefs = map fst valid_pref_data+validPrefs :: [String]+validPrefs = map fst validPrefData -setpref_description :: String-setpref_description =-    "Set a preference (" ++ orClauses valid_prefs ++ ")."+setprefDescription :: String+setprefDescription =+    "Set a preference (" ++ orClauses validPrefs ++ ")." -setpref_help :: String-setpref_help =+setprefHelp :: String+setprefHelp =  "When working on project with multiple repositories and contributors,\n" ++  "it is sometimes desirable for a preference to be set consistently\n" ++  "project-wide.  This is achieved by treating a preference set with\n" ++@@ -59,7 +59,7 @@  "\n" ++  "Valid preferences are:\n" ++  "\n" ++- unlines ["  "++x++" -- "++y | (x,y) <- valid_pref_data] +++ unlines ["  "++x++" -- "++y | (x,y) <- validPrefData] ++  "\n" ++  "For example, a project using GNU autotools, with a `make test' target\n" ++  "to perform regression tests, might enable Darcs' integrated regression\n" ++@@ -73,36 +73,36 @@  "low-priority bug, because preferences are seldom set.\n"  setpref :: DarcsCommand-setpref = DarcsCommand {command_name = "setpref",-                        command_help = setpref_help,-                        command_description = setpref_description,-                        command_extra_args = 2,-                        command_extra_arg_help = ["<PREF>",+setpref = DarcsCommand {commandName = "setpref",+                        commandHelp = setprefHelp,+                        commandDescription = setprefDescription,+                        commandExtraArgs = 2,+                        commandExtraArgHelp = ["<PREF>",                                                   "<VALUE>"],-                        command_command = setpref_cmd,-                        command_prereq = amInRepository,-                        command_get_arg_possibilities = return valid_prefs,-                        command_argdefaults = nodefaults,-                        command_advanced_options = [umask_option],-                        command_basic_options =-                            [working_repo_dir]}+                        commandCommand = setprefCmd,+                        commandPrereq = amInRepository,+                        commandGetArgPossibilities = return validPrefs,+                        commandArgdefaults = nodefaults,+                        commandAdvancedOptions = [umaskOption],+                        commandBasicOptions =+                            [workingRepoDir]} -setpref_cmd :: [DarcsFlag] -> [String] -> IO ()-setpref_cmd opts [pref,val] = withRepoLock opts $- \repository -> do+setprefCmd :: [DarcsFlag] -> [String] -> IO ()+setprefCmd opts [pref,val] = withRepoLock opts $- \repository -> do   when (' ' `elem` pref) $ do     putStrLn $ "'"++pref++                "' is not a valid preference name:  no spaces allowed!"     exitWith $ ExitFailure 1-  when (not $ pref `elem` valid_prefs) $ do+  when (not $ pref `elem` validPrefs) $ do     putStrLn $ "'"++pref++"' is not a valid preference name!"-    putStrLn $ "Try one of: " ++ unwords valid_prefs+    putStrLn $ "Try one of: " ++ unwords validPrefs     exitWith $ ExitFailure 1-  oval <- get_prefval pref+  oval <- getPrefval pref   old <- case oval of Just v -> return v                       Nothing -> return ""-  change_prefval pref old val+  changePrefval pref old val   putStrLn $ "Changing value of "++pref++" from '"++old++"' to '"++val++"'"   add_to_pending repository (changepref pref old val :>: NilFL)-setpref_cmd _ _ = impossible+setprefCmd _ _ = impossible \end{code} 
src/Darcs/Commands/Show.lhs view
@@ -16,52 +16,52 @@ %  Boston, MA 02110-1301, USA.  \begin{code}-module Darcs.Commands.Show ( show_command, list, query ) where+module Darcs.Commands.Show ( showCommand, list, query ) where  import Darcs.Commands ( DarcsCommand(..),-                        CommandControl(Command_data, Hidden_command),-                        command_alias,+                        CommandControl(CommandData, HiddenCommand),+                        commandAlias,                       )-import Darcs.Commands.ShowAuthors ( show_authors )-import Darcs.Commands.ShowBug ( show_bug )-import Darcs.Commands.ShowContents ( show_contents )-import Darcs.Commands.ShowFiles ( show_files, show_manifest )-import Darcs.Commands.ShowTags ( show_tags )-import Darcs.Commands.ShowRepo ( show_repo )-import Darcs.Commands.ShowIndex ( show_index, show_pristine )+import Darcs.Commands.ShowAuthors ( showAuthors )+import Darcs.Commands.ShowBug ( showBug )+import Darcs.Commands.ShowContents ( showContents )+import Darcs.Commands.ShowFiles ( showFiles, showManifest )+import Darcs.Commands.ShowTags ( showTags )+import Darcs.Commands.ShowRepo ( showRepo )+import Darcs.Commands.ShowIndex ( showIndex, showPristine ) import Darcs.Repository ( amInRepository ) -show_description :: String-show_description = "Show information which is stored by darcs."+showDescription :: String+showDescription = "Show information which is stored by darcs." -show_help :: String-show_help =+showHelp :: String+showHelp =  "Use the --help option with the subcommands to obtain help for\n"++  "subcommands (for example, \"darcs show files --help\").\n" ++  "\n" ++  "In previous releases, this command was called `darcs query'.\n" ++  "Currently this is a deprecated alias.\n" -show_command :: DarcsCommand-show_command = SuperCommand {command_name = "show",-                      command_help = show_help,-                      command_description = show_description,-                      command_prereq = amInRepository,-                      command_sub_commands = [Hidden_command show_bug,-                                              Command_data show_contents,-                                              Command_data show_files, Hidden_command show_manifest,-                                              Command_data show_index,-                                              Command_data show_pristine,-                                              Command_data show_repo,-                                              Command_data show_authors,-                                              Command_data show_tags]+showCommand :: DarcsCommand+showCommand = SuperCommand {commandName = "show",+                      commandHelp = showHelp,+                      commandDescription = showDescription,+                      commandPrereq = amInRepository,+                      commandSubCommands = [HiddenCommand showBug,+                                              CommandData showContents,+                                              CommandData showFiles, HiddenCommand showManifest,+                                              CommandData showIndex,+                                              CommandData showPristine,+                                              CommandData showRepo,+                                              CommandData showAuthors,+                                              CommandData showTags]                      }  query :: DarcsCommand-query = command_alias "query" show_command+query = commandAlias "query" showCommand  list :: DarcsCommand-list = command_alias "list" show_command+list = commandAlias "list" showCommand \end{code}  \subsection{darcs show}
src/Darcs/Commands/ShowAuthors.lhs view
@@ -1,4 +1,4 @@-%  Copyright (C) 2004-2009 David Roundy, Eric Kow, Simon Michael+%  Copyright (C) 2004-2009 David Roundy, Eric Kow, Simon Michael, Tomas Caithaml % %  This program is free software; you can redistribute it and/or modify %  it under the terms of the GNU General Public License as published by@@ -17,30 +17,37 @@  \darcsCommand{show authors} \begin{code}-{-# OPTIONS_GHC -cpp #-}-module Darcs.Commands.ShowAuthors ( show_authors ) where+module Darcs.Commands.ShowAuthors ( showAuthors ) where +import qualified Ratified( readFile ) import Control.Arrow ((&&&), (***))-import Data.List ( sort, sortBy, group, groupBy, isInfixOf, isPrefixOf )+import Data.List ( isInfixOf, sortBy, groupBy, group, sort) import Data.Ord (comparing) import Data.Char ( toLower, isSpace )+import Data.Maybe( isJust )+import Text.ParserCombinators.Parsec hiding (lower, count, Line)+import Text.ParserCombinators.Parsec.Error import Text.Regex ( Regex, mkRegexWithOpts, matchRegex ) -import Darcs.Arguments ( DarcsFlag(..), working_repo_dir )-import Darcs.Commands ( DarcsCommand(..), nodefaults )+import Darcs.Arguments ( DarcsFlag(..), workingRepoDir )+import Darcs.Commands ( DarcsCommand(..), nodefaults, putWarning ) import Darcs.External ( viewDoc ) import Darcs.Hopefully ( info ) import Darcs.Repository ( amInRepository, read_repo, withRepository, ($-) ) import Darcs.Patch.Info ( pi_author )-import Darcs.Ordered ( mapRL, concatRL )+import Darcs.Witnesses.Ordered ( mapRL, concatRL ) import Printer ( text ) import Data.Function (on) -show_authors_description :: String-show_authors_description = "List authors by patch count."+data Spelling = Spelling String String [Regex] -- name, email, regexps+type ParsedLine = Maybe Spelling -- Nothing for blank lines -show_authors_help :: String-show_authors_help =++showAuthorsDescription :: String+showAuthorsDescription = "List authors by patch count."++showAuthorsHelp :: String+showAuthorsHelp =  "The `darcs show authors' command lists the authors of the current\n" ++  "repository, sorted by the number of patches contributed.  With the\n" ++  "--verbose option, this command simply lists the author of each patch\n" ++@@ -50,14 +57,23 @@  "when multiple author strings refer to the same individual, create an\n" ++  "`.authorspellings' file in the root of the working tree.  Each line in\n" ++  "this file begins with an author's canonical name and address, and may\n" ++- "be followed by a comma and zero or more extended regular expressions,\n" ++- "separated by commas.  Blank lines and lines beginning with two\n" ++- "hyphens, are ignored.\n" +++ "be followed by a comma separated list of extended regular expressions.\n" +++ "Blank lines and lines beginning with two hyphens are ignored.\n" +++ "The format of .authorspelling can be described by this pattern:\n" ++  "\n" +++ " name <address> [, regexp ]*\n" +++ "\n" +++ "There are some pitfalls concerning special characters:\n" +++ "Whitespaces are stripped, if you need space in regexp use [ ]. \n" +++ "Because comma serves as a separator you have to escape it if you want\n" +++ "it in regexp. Note that .authorspelingfile use extended regular\n" +++ "expressions so +, ? and so on are metacharacters and you need to \n" +++ "escape them to be interpreted literally.\n" +++ "\n" ++  "Any patch with an author string that matches the canonical address or\n" ++  "any of the associated regexps is considered to be the work of that\n" ++  "author.  All matching is case-insensitive and partial (it can match a\n" ++- "substring).\n" +++ "substring). Use ^,$ to match the whole string in regexps\n" ++  "\n" ++  "Currently this canonicalization step is done only in `darcs show\n" ++  "authors'.  Other commands, such as `darcs changes' use author strings\n" ++@@ -67,26 +83,27 @@  "\n" ++  "    -- This is a comment.\n" ++  "    Fred Nurk <fred@example.com>\n" ++- "    John Snagge <snagge@bbc.co.uk>, John, snagge@, js@(si|mit).edu\n"+ "    John Snagge <snagge@bbc.co.uk>, John, snagge@, js@(si|mit).edu\n" +++ "    Chuck Jones\\, Jr. <chuck@pobox.com>, cj\\+user@example.com\n" -show_authors :: DarcsCommand-show_authors = DarcsCommand {-  command_name = "authors",-  command_help = show_authors_help,-  command_description = show_authors_description,-  command_extra_args = 0,-  command_extra_arg_help = [],-  command_command = authors_cmd,-  command_prereq = amInRepository,-  command_get_arg_possibilities = return [],-  command_argdefaults = nodefaults,-  command_advanced_options = [],-  command_basic_options = [working_repo_dir] }+showAuthors :: DarcsCommand+showAuthors = DarcsCommand {+  commandName = "authors",+  commandHelp = showAuthorsHelp,+  commandDescription = showAuthorsDescription,+  commandExtraArgs = 0,+  commandExtraArgHelp = [],+  commandCommand = authorsCmd,+  commandPrereq = amInRepository,+  commandGetArgPossibilities = return [],+  commandArgdefaults = nodefaults,+  commandAdvancedOptions = [],+  commandBasicOptions = [workingRepoDir] } -authors_cmd :: [DarcsFlag] -> [String] -> IO ()-authors_cmd opts _ = withRepository opts $- \repository -> do+authorsCmd :: [DarcsFlag] -> [String] -> IO ()+authorsCmd opts _ = withRepository opts $- \repository -> do   patches <- read_repo repository-  spellings <- compiled_author_spellings+  spellings <- compiledAuthorSpellings opts   let authors = mapRL (pi_author . info) $ concatRL patches   viewDoc $ text $ unlines $    if Verbose `elem` opts@@ -105,56 +122,72 @@       -- Because it would take a long time to canonize "foo" into       -- "foo <foo@bar.baz>" once per patch, the code below       -- generates a list [(count, canonized name)].-      map (length &&& (canonize_author spellings . head)) $+      map (length &&& (canonizeAuthor spellings . head)) $       group $ sort authors -canonize_author :: [(String,[Regex])] -> String -> String-canonize_author [] a = a-canonize_author spellings a = safehead a $ canonicalsfor a-    where-      safehead x xs = if null xs then x else head xs-      canonicalsfor s = map fst $ filter (ismatch s) spellings-      ismatch s (canonical,regexps) =-          (not (null email) && (s `contains` email)) || (any (s `contains_regex`) regexps)-          where email = takeWhile (/= '>') $ drop 1 $ dropWhile (/= '<') canonical--contains :: String -> String -> Bool-a `contains` b = lower b `isInfixOf` (lower a) where lower = map toLower+canonizeAuthor :: [Spelling] -> String -> String+canonizeAuthor spells author = getName canonicals+ where+   getName [] = author+   getName ((Spelling name email _):_) = name ++ " <" ++ email ++ ">"+   canonicals = filter (ismatch author) spells+   ismatch s (Spelling _ mail regexps) =+     s `correspondsTo` mail || any (s `contains_regex`) regexps+   contains_regex a r = isJust $ matchRegex r a+   correspondsTo a b = lower b `isInfixOf` lower a+   lower = map toLower -contains_regex :: String -> Regex -> Bool-a `contains_regex` r = case matchRegex r a of-                         Just _ -> True-                         _ -> False+compiledAuthorSpellings :: [DarcsFlag] -> IO [Spelling]+compiledAuthorSpellings opts = do+  let as_file = ".authorspellings"+  contents <- (Ratified.readFile -- never unlinked from within darcs+               as_file `catch` (\_ -> return ""))+  let parse_results = map (parse sentence as_file) $ lines contents+  clean 1 parse_results+ where+  clean :: Int -> [Either ParseError ParsedLine] -> IO [Spelling]+  clean _ [] = return []+  -- print parse error+  clean n ((Left err):xs) = do+    let npos = setSourceLine (errorPos err) n+    putWarning opts . text . show $ setErrorPos npos err+    clean (n+1) xs+  -- skip blank line+  clean n ((Right Nothing):xs)  = clean (n+1) xs+  -- unwrap Spelling+  clean n ((Right (Just a):xs)) = do+    as <- clean (n+1) xs+    return (a:as) -compiled_author_spellings :: IO [(String,[Regex])]-compiled_author_spellings = do-  ss <- author_spellings_from_file-  return $ map compile $ ss-    where-      compile [] = error "each author spelling should contain at least the canonical form"-      compile (canonical:pats) = (canonical, map mkregex pats)-      mkregex pat = mkRegexWithOpts pat True False+----------+-- PARSERS -authorspellingsfile :: FilePath-authorspellingsfile = ".authorspellings"+sentence :: Parser ParsedLine+sentence = spaces >> (comment <|> blank <|> addressline)+  where+    comment = string "--" >> return Nothing+    blank = eof >> return Nothing -author_spellings_from_file :: IO [[String]]-author_spellings_from_file = do-  s <- readFile -- ratify readFile: never unlinked from within darcs-         authorspellingsfile `catch` (\_ -> return "")-  let noncomments = filter (not . ("--" `isPrefixOf`)) $-                    filter (not . null) $ map strip $ lines s-  return $ map (map strip . split_on ',') noncomments+addressline :: Parser ParsedLine+addressline = do+  name <- canonicalName <?> "Canonical name"+  addr <- between (char '<') (char '>') (many1 (noneOf ">")) <?> "Address"+  spaces+  rest <- option [] (char ',' >> regexp `sepBy` char ',') <?> "List of regexps"+  return $ Just $ Spelling (strip name) addr (compile rest)+  where+    strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse+    makeRegex s = mkRegexWithOpts s True False+    compile = map makeRegex . filter (not . null) . map strip -split_on :: Eq a => a -> [a] -> [[a]]-split_on e l =-    case dropWhile (e==) l of-      [] -> []-      l' -> first : split_on e rest-        where-          (first,rest) = break (e==) l'+regexp :: Parser String+regexp = many1 p <?> "Regular expression"+  where p = try (string "\\," >> return ',')+            <|> noneOf "," -strip :: String -> String-strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse+canonicalName :: Parser String+canonicalName = many1 p+  where p = try (string "\\," >> return ',')+            <|> noneOf ",<"  \end{code}
src/Darcs/Commands/ShowBug.lhs view
@@ -20,34 +20,34 @@ {-# OPTIONS_GHC -cpp #-} {-# LANGUAGE CPP #-} -module Darcs.Commands.ShowBug ( show_bug ) where+module Darcs.Commands.ShowBug ( showBug ) where  import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag, working_repo_dir )+import Darcs.Arguments ( DarcsFlag, workingRepoDir ) import Darcs.Repository ( findRepository ) #include "impossible.h" -show_bug_description :: String-show_bug_description = "Simulate a run-time failure."+showBugDescription :: String+showBugDescription = "Simulate a run-time failure." -show_bug_help :: String-show_bug_help =+showBugHelp :: String+showBugHelp =   "Show bug can be used to see what darcs would show you if you encountered.\n"   ++"a bug in darcs.\n" -show_bug :: DarcsCommand-show_bug = DarcsCommand {command_name = "bug",-                         command_help = show_bug_help,-                         command_description = show_bug_description,-                         command_extra_args = 0,-                         command_extra_arg_help = [],-                         command_command = show_bug_cmd,-                         command_prereq = findRepository,-                         command_get_arg_possibilities = return [],-                         command_argdefaults = nodefaults,-                         command_advanced_options = [],-                         command_basic_options = [working_repo_dir]}+showBug :: DarcsCommand+showBug = DarcsCommand {commandName = "bug",+                         commandHelp = showBugHelp,+                         commandDescription = showBugDescription,+                         commandExtraArgs = 0,+                         commandExtraArgHelp = [],+                         commandCommand = showBugCmd,+                         commandPrereq = findRepository,+                         commandGetArgPossibilities = return [],+                         commandArgdefaults = nodefaults,+                         commandAdvancedOptions = [],+                         commandBasicOptions = [workingRepoDir]} -show_bug_cmd :: [DarcsFlag] -> [String] -> IO ()-show_bug_cmd _ _ = bug "This is actually a fake bug in darcs."+showBugCmd :: [DarcsFlag] -> [String] -> IO ()+showBugCmd _ _ = bug "This is actually a fake bug in darcs." \end{code}
src/Darcs/Commands/ShowContents.lhs view
@@ -17,56 +17,70 @@  \darcsCommand{show contents} \begin{code}-module Darcs.Commands.ShowContents ( show_contents ) where+module Darcs.Commands.ShowContents ( showContents ) where -import Control.Monad ( filterM )+import Control.Monad ( filterM, forM_, unless )+import Control.Monad.Trans( liftIO ) import System.IO ( stdout )-import System.FilePath.Posix ( takeFileName )+import Data.Maybe( fromJust )  import qualified Data.ByteString as B-import Workaround ( getCurrentDirectory )  import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag, match_one,-                         working_repo_dir, fixSubPaths )-import Darcs.RepoPath ( toFilePath, sp2fn )+import Darcs.Arguments ( DarcsFlag, matchOne,+                         workingRepoDir, fixSubPaths )+import Darcs.RepoPath ( sp2fn ) import Darcs.IO ( mReadFilePS, mDoesFileExist )-import Darcs.Match ( get_partial_nonrange_match, have_nonrange_match )-import Darcs.Repository ( withRepository, ($-), findRepository,-                          createPartialsPristineDirectoryTree )-import Darcs.Lock ( withTempDir )+import Darcs.Patch.Match( Matcher )+import Darcs.Match ( haveNonrangeMatch, applyInvToMatcher, nonrangeMatcher+                   , InclusiveOrExclusive(..), matchExists )+import Darcs.Repository ( withRepository, ($-), findRepository, read_repo, readRecorded )+import Darcs.Patch( RepoPatch )+import Storage.Hashed.Monad( virtualTreeIO ) -show_contents_description :: String-show_contents_description = "Outputs a specific version of a file."+showContentsDescription :: String+showContentsDescription = "Outputs a specific version of a file." -show_contents_help :: String-show_contents_help =+showContentsHelp :: String+showContentsHelp =   "Show contents can be used to display an earlier version of some file(s).\n"++   "If you give show contents no version arguments, it displays the recorded\n"++   "version of the file(s).\n" -show_contents :: DarcsCommand-show_contents = DarcsCommand {command_name = "contents",-                              command_help = show_contents_help,-                              command_description = show_contents_description,-                              command_extra_args = -1,-                              command_extra_arg_help+showContents :: DarcsCommand+showContents = DarcsCommand {commandName = "contents",+                              commandHelp = showContentsHelp,+                              commandDescription = showContentsDescription,+                              commandExtraArgs = -1,+                              commandExtraArgHelp                                     = ["[FILE]..."],-                              command_command = show_contents_cmd,-                              command_prereq = findRepository,-                              command_get_arg_possibilities = return [],-                              command_argdefaults = nodefaults,-                              command_advanced_options = [],-                              command_basic_options = [match_one, working_repo_dir]}+                              commandCommand = showContentsCmd,+                              commandPrereq = findRepository,+                              commandGetArgPossibilities = return [],+                              commandArgdefaults = nodefaults,+                              commandAdvancedOptions = [],+                              commandBasicOptions = [matchOne, workingRepoDir]} -show_contents_cmd :: [DarcsFlag] -> [String] -> IO ()-show_contents_cmd opts args = withRepository opts $- \repository -> do-  formerdir <- getCurrentDirectory+getMatcher :: (RepoPatch p) => [DarcsFlag] -> Matcher p+getMatcher = fromJust . nonrangeMatcher++showContentsCmd :: [DarcsFlag] -> [String] -> IO ()+showContentsCmd _ [] = fail+ "show contents needs at least one argument."+showContentsCmd opts args = withRepository opts $- \repository -> do   path_list <- map sp2fn `fmap` fixSubPaths opts args-  thename <- return $ takeFileName formerdir-  withTempDir thename $ \dir -> do-     if have_nonrange_match opts-        then get_partial_nonrange_match repository opts path_list-        else createPartialsPristineDirectoryTree repository path_list (toFilePath dir)-     filterM mDoesFileExist path_list >>= mapM_ (\f -> mReadFilePS f >>= B.hPut stdout)+  pristine <- readRecorded repository+  let matcher = getMatcher opts+      unapply_to_match = applyInvToMatcher Exclusive matcher+  matched <- if (haveNonrangeMatch opts)+                 then do patchset <- read_repo repository+                         unless (matchExists matcher patchset) $+                                fail $ "Couldn't match pattern " ++ show matcher+                         snd `fmap` virtualTreeIO (unapply_to_match patchset) pristine+                 else return pristine+  let dump = do okpaths <- filterM mDoesFileExist path_list+                forM_ okpaths $ \f -> do content <- mReadFilePS f+                                         liftIO (B.hPut stdout content)+  virtualTreeIO dump matched+  return () \end{code}
src/Darcs/Commands/ShowFiles.lhs view
@@ -20,20 +20,24 @@ {-# OPTIONS_GHC -cpp #-} {-# LANGUAGE CPP #-} #include "gadts.h"-module Darcs.Commands.ShowFiles ( show_files, show_manifest ) where-import Darcs.Arguments ( DarcsFlag(..), working_repo_dir,-                        files, directories, pending, nullFlag )-import Darcs.Commands ( DarcsCommand(..), nodefaults, command_alias )+module Darcs.Commands.ShowFiles ( showFiles, showManifest ) where+import Darcs.Arguments ( DarcsFlag(..), workingRepoDir,+                        files, directories, pending, nullFlag, matchOne )+import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias ) import Darcs.Repository ( Repository, amInRepository, slurp_pending, slurp_recorded,                           withRepository ) import Darcs.Patch ( RepoPatch )-import Darcs.SlurpDirectory ( Slurpy, list_slurpy, list_slurpy_files, list_slurpy_dirs )+import Darcs.SlurpDirectory ( Slurpy, list_slurpy, list_slurpy_files, list_slurpy_dirs, slurp )+import Data.List( isPrefixOf ) -show_files_description :: String-show_files_description = "Show version-controlled files in the working copy."+import Darcs.Match ( haveNonrangeMatch, getNonrangeMatch )+import Workaround ( getCurrentDirectory )+import Darcs.Lock ( withDelayedDir )+showFilesDescription :: String+showFilesDescription = "Show version-controlled files in the working copy." -show_files_help :: String-show_files_help =+showFilesHelp :: String+showFilesHelp =  "The `darcs show files' command lists those files and directories in\n" ++  "the working tree that are under version control.  This command is\n" ++  "primarily for scripting purposes; end users will probably want `darcs\n" ++@@ -57,43 +61,65 @@  "\n" ++  "    darcs show files -0 | xargs -0 ls -ldS\n" -show_files :: DarcsCommand-show_files = DarcsCommand {-  command_name = "files",-  command_help = show_files_help,-  command_description = show_files_description,-  command_extra_args = 0,-  command_extra_arg_help = [],-  command_command = manifest_cmd to_list_files,-  command_prereq = amInRepository,-  command_get_arg_possibilities = return [],-  command_argdefaults = nodefaults,-  command_advanced_options = [],-  command_basic_options = [files, directories, pending, nullFlag,-                          working_repo_dir] }+showFiles :: DarcsCommand+showFiles = DarcsCommand {+  commandName = "files",+  commandHelp = showFilesHelp,+  commandDescription = showFilesDescription,+  commandExtraArgs = -1,+  commandExtraArgHelp = ["[FILE or DIRECTORY]..."],+  commandCommand = manifestCmd toListFiles,+  commandPrereq = amInRepository,+  commandGetArgPossibilities = return [],+  commandArgdefaults = nodefaults,+  commandAdvancedOptions = [],+  commandBasicOptions = [files, directories, pending, nullFlag, matchOne,+                          workingRepoDir] } -show_manifest :: DarcsCommand-show_manifest = command_alias "manifest" show_files {-  command_command = manifest_cmd to_list_manifest+showManifest :: DarcsCommand+showManifest = commandAlias "manifest" showFiles {+  commandCommand = manifestCmd toListManifest } -to_list_files, to_list_manifest :: [DarcsFlag] -> Slurpy -> [FilePath]-to_list_files    opts = files_dirs (NoFiles `notElem` opts) (NoDirectories `notElem` opts)-to_list_manifest opts = files_dirs (NoFiles `notElem` opts) (Directories `elem` opts)+toListFiles, toListManifest :: [DarcsFlag] -> Slurpy -> [FilePath]+toListFiles    opts = filesDirs (NoFiles `notElem` opts) (NoDirectories `notElem` opts)+toListManifest opts = filesDirs (NoFiles `notElem` opts) (Directories `elem` opts) -files_dirs :: Bool -> Bool -> Slurpy -> [FilePath]-files_dirs False False = \_ -> []-files_dirs False True  = list_slurpy_dirs-files_dirs True  False = list_slurpy_files-files_dirs True  True  = list_slurpy+filesDirs :: Bool -> Bool -> Slurpy -> [FilePath]+filesDirs False False = \_ -> []+filesDirs False True  = list_slurpy_dirs+filesDirs True  False = list_slurpy_files+filesDirs True  True  = list_slurpy -manifest_cmd :: ([DarcsFlag] -> Slurpy -> [FilePath]) -> [DarcsFlag] -> [String] -> IO ()-manifest_cmd to_list opts _ = do-    list <- (to_list opts) `fmap` withRepository opts slurp-    mapM_ output list-    where slurp :: RepoPatch p => Repository p C(r u r) -> IO Slurpy-          slurp = if NoPending `notElem` opts-                  then slurp_pending else slurp_recorded+manifestCmd :: ([DarcsFlag] -> Slurpy -> [FilePath]) -> [DarcsFlag] -> [String] -> IO ()+manifestCmd to_list opts argList = do+    list <- (to_list opts) `fmap` withRepository opts myslurp+    case argList of +        [] -> mapM_ output list+        prefixes -> mapM_ output (onlysubdirs prefixes list)+    where myslurp :: RepoPatch p => Repository p C(r u r) -> IO Slurpy+          myslurp = do let fRevisioned = haveNonrangeMatch opts+                           fPending = Pending `elem` opts+                           fNoPending = NoPending `elem` opts +                       -- this covers all 8 options+                       case (fRevisioned,fPending,fNoPending) of+                            (True,False,_) -> slurp_revision opts+                            (True,True,_) -> error $ "can't mix revisioned and pending flags"+                            (False,False,True) -> slurp_recorded+                            (False,_,False) -> slurp_pending -- pending is default+                            (False,True,True) -> error $ "can't mix pending and no-pending flags"           output_null name = do { putStr name ; putChar '\0' }           output = if NullFlag `elem` opts then output_null else putStrLn+          isParentDir a b = a == b  +                            || (a  ++ "/") `isPrefixOf` b +                            || ("./" ++ a ++ "/") `isPrefixOf` b +                            || "./" ++ a == b+          onlysubdirs suffixes = filter $ or . mapM isParentDir suffixes++slurp_revision :: RepoPatch p => [DarcsFlag] -> Repository p C(r u r) -> IO Slurpy+slurp_revision opts r = withDelayedDir "revisioned.showfiles" $ \_ -> do +  getNonrangeMatch r opts +  slurp =<< getCurrentDirectory++ \end{code}
src/Darcs/Commands/ShowIndex.lhs view
@@ -25,56 +25,57 @@ {-# OPTIONS_GHC -cpp #-} {-# LANGUAGE CPP #-} #include "gadts.h"-module Darcs.Commands.ShowIndex ( show_index, show_pristine ) where-import Darcs.Arguments ( DarcsFlag(..), working_repo_dir,+module Darcs.Commands.ShowIndex ( showIndex, showPristine ) where+import Darcs.Arguments ( DarcsFlag(..), workingRepoDir,                         files, directories, nullFlag )-import Darcs.Commands ( DarcsCommand(..), nodefaults, command_alias )-import Darcs.Repository ( amInRepository, withRepository, ($-) )+import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias )+import Darcs.Repository ( amInRepository, withRepository, ($-), readIndex )+import Darcs.Repository.State ( readRecorded ) -import Darcs.Gorsvet( readIndex )-import Storage.Hashed( readDarcsPristine, floatPath )-import Storage.Hashed.Darcs( darcsFormatHash )+import Storage.Hashed( floatPath )+import Storage.Hashed.Hash( encodeBase16, Hash( NoHash ) ) import Storage.Hashed.Tree( list, expand, itemHash, Tree, TreeItem( SubTree ) )+import Storage.Hashed.Index( updateIndex ) import Storage.Hashed.AnchoredPath( anchorPath )  import qualified Data.ByteString.Char8 as BS -show_index :: DarcsCommand-show_index = DarcsCommand {-  command_name = "index",-  command_description = "Dump contents of working tree index.",-  command_help =+showIndex :: DarcsCommand+showIndex = DarcsCommand {+  commandName = "index",+  commandDescription = "Dump contents of working tree index.",+  commandHelp =       "The `darcs show index' command lists all version-controlled files and " ++       "directories along with their hashes as stored in _darcs/index. " ++       "For files, the fields correspond to file size, sha256 of the current " ++       "file content and the filename.",-  command_extra_args = 0,-  command_extra_arg_help = [],-  command_command = show_index_cmd,-  command_prereq = amInRepository,-  command_get_arg_possibilities = return [],-  command_argdefaults = nodefaults,-  command_advanced_options = [],-  command_basic_options = [files, directories, nullFlag, working_repo_dir] }+  commandExtraArgs = 0,+  commandExtraArgHelp = [],+  commandCommand = showIndexCmd,+  commandPrereq = amInRepository,+  commandGetArgPossibilities = return [],+  commandArgdefaults = nodefaults,+  commandAdvancedOptions = [],+  commandBasicOptions = [files, directories, nullFlag, workingRepoDir] } -show_pristine :: DarcsCommand-show_pristine = command_alias "pristine" show_index {-  command_command = show_pristine_cmd,-  command_description = "Dump contents of pristine cache.",-  command_help =+showPristine :: DarcsCommand+showPristine = commandAlias "pristine" showIndex {+  commandCommand = showPristineCmd,+  commandDescription = "Dump contents of pristine cache.",+  commandHelp =       "The `darcs show pristine' command lists all version-controlled files " ++       "and directories along with the hashes of their pristine copies. " ++       "For files, the fields correspond to file size, sha256 of the pristine " ++       "file content and the filename." } -dump :: [DarcsFlag] -> Tree -> IO ()+dump :: [DarcsFlag] -> Tree IO -> IO () dump opts tree = do   let line | NullFlag `elem` opts = \t -> putStr t >> putChar '\0'            | otherwise = putStrLn       output (p, i) = do         let hash = case itemHash i of-                     Just h -> BS.unpack $ darcsFormatHash h-                     Nothing -> "(no hash available)"+                     NoHash -> "(no hash available)"+                     h -> BS.unpack $ encodeBase16 h             path = anchorPath "" p             isdir = case i of                       SubTree _ -> "/"@@ -83,12 +84,12 @@   x <- expand tree   mapM_ output $ (floatPath ".", SubTree x) : list x -show_index_cmd :: [DarcsFlag] -> [String] -> IO ()-show_index_cmd opts _ = withRepository opts $- \repo -> do-  readIndex repo >>= dump opts+showIndexCmd :: [DarcsFlag] -> [String] -> IO ()+showIndexCmd opts _ = withRepository opts $- \repo -> do+  readIndex repo >>= updateIndex >>= dump opts -show_pristine_cmd :: [DarcsFlag] -> [String] -> IO ()-show_pristine_cmd opts _ = withRepository opts $- \_ -> do-  readDarcsPristine "." >>= dump opts+showPristineCmd :: [DarcsFlag] -> [String] -> IO ()+showPristineCmd opts _ = withRepository opts $- \repo -> do+  readRecorded repo >>= dump opts  \end{code}
src/Darcs/Commands/ShowRepo.lhs view
@@ -17,89 +17,60 @@  \darcsCommand{show repo} -The \verb!show repo! displays information about-the current repository: the location, the type, etc.--This is provided as informational output for two purposes: curious-users and scripts invoking darcs.  For the latter, this information-can be parsed to facilitate the script; for example,-\verb!darcs show repo | grep Root: | awk {print $2}!-can be used to locate the-top-level \verb!_darcs! directory from anyplace within a darcs repository-working directory.- \begin{code} {-# OPTIONS_GHC -cpp #-} {-# LANGUAGE CPP #-} #include "gadts.h"-module Darcs.Commands.ShowRepo ( show_repo ) where+module Darcs.Commands.ShowRepo ( showRepo ) where  import Data.Char ( toLower, isSpace ) import Data.List ( intersperse ) import Control.Monad ( when, unless ) import Text.Html ( tag, stringToHtml )-import Darcs.Arguments ( DarcsFlag(..), working_repo_dir, files, xmloutput )+import Darcs.Arguments ( DarcsFlag(..), workingRepoDir, files, xmloutput ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Repository ( withRepository, ($-), amInRepository, read_repo ) import Darcs.Repository.Internal ( Repository(..), RepoType(..) ) import Darcs.Repository.Format ( RepoFormat(..) )-import Darcs.Repository.Prefs ( get_preflist )+import Darcs.Repository.Prefs ( getPreflist ) import Darcs.Repository.Motd ( get_motd ) import Darcs.Patch ( RepoPatch )-import Darcs.Ordered ( lengthRL, concatRL )+import Darcs.Witnesses.Ordered ( lengthRL, concatRL ) import qualified Data.ByteString.Char8 as BC  (unpack) -show_repo_help :: String-show_repo_help =- "The repo command displays information about the current repository\n" ++- "(location, type, etc.).  Some of this information is already available\n" ++- "by inspecting files within the _darcs directory and some is internal\n" ++- "information that is informational only (i.e. for developers).  This\n" ++- "command collects all of the repository information into a readily\n" ++- "available source.\n"--show_repo_description :: String-show_repo_description = "Show repository summary information"--show_repo :: DarcsCommand-show_repo = DarcsCommand { command_name = "repo",-                           command_help = show_repo_help,-                           command_description = show_repo_description,-                           command_extra_args = 0,-                           command_extra_arg_help = [],-                           command_command = repo_cmd,-                           command_prereq = amInRepository,-                           command_get_arg_possibilities = return [],-                           command_argdefaults = nodefaults,-                           command_advanced_options = [],-                           command_basic_options = [working_repo_dir, files, xmloutput] }-\end{code}--\begin{options}---files, --no-files-\end{options}--If the \verb!--files! option is specified (the default), then the-\verb!show repo! operation will read patch information from the-repository and display the number of patches in the repository.  The-\verb!--no-files! option can be used to suppress this operation (and-improve performance).+showRepoHelp :: String+showRepoHelp =+ "The `darcs show repo' command displays statistics about the current\n" +++ "repository, allowing third-party scripts to access this information\n" +++ "without inspecting _darcs directly (and without breaking when the\n" +++ "_darcs format changes).\n" +++ "\n" +++ "By default, the number of patches is shown.  If this data isn't\n" +++ "needed, use --no-files to accelerate this command from O(n) to O(1).\n" +++ "\n" +++ "By default, output is in a human-readable format.  The --xml-output\n" +++ "option can be used to generate output for machine postprocessing.\n" -\begin{code}-repo_cmd :: [DarcsFlag] -> [String] -> IO ()-repo_cmd opts _ = let put_mode = if XMLOutput `elem` opts then showInfoXML else showInfoUsr-                  in withRepository opts $- \repository -> showRepo (putInfo put_mode) repository-\end{code}+showRepoDescription :: String+showRepoDescription = "Show repository summary information" -\begin{options}---human-readable, --xml-output-\end{options}+showRepo :: DarcsCommand+showRepo = DarcsCommand { commandName = "repo",+                           commandHelp = showRepoHelp,+                           commandDescription = showRepoDescription,+                           commandExtraArgs = 0,+                           commandExtraArgHelp = [],+                           commandCommand = repoCmd,+                           commandPrereq = amInRepository,+                           commandGetArgPossibilities = return [],+                           commandArgdefaults = nodefaults,+                           commandAdvancedOptions = [],+                           commandBasicOptions = [workingRepoDir, files, xmloutput] } -By default, the \verb!show repo! displays output in human readable-form, but the \verb!--xml-output! option can be used to obtain-XML-formatted to facilitate regular parsing by external tools.+repoCmd :: [DarcsFlag] -> [String] -> IO ()+repoCmd opts _ = let put_mode = if XMLOutput `elem` opts then showInfoXML else showInfoUsr+                  in withRepository opts $- \repository -> actuallyShowRepo (putInfo put_mode) repository -\begin{code} -- Some convenience functions to output a labelled text string or an -- XML tag + value (same API).  If no value, output is suppressed -- entirely.  Borrow some help from Text.Html to perform XML output.@@ -129,8 +100,8 @@ -- sub-displays.  The `out' argument is one of the above operations to -- output a labelled text string or an XML tag and contained value. -showRepo :: RepoPatch p => PutInfo -> Repository p C(r u r) -> IO ()-showRepo out r@(Repo loc opts rf rt) = do+actuallyShowRepo :: RepoPatch p => PutInfo -> Repository p C(r u r) -> IO ()+actuallyShowRepo out r@(Repo loc opts rf rt) = do          when (XMLOutput `elem` opts) (putStr "<repository>\n")          showRepoType out rt          when (Verbose `elem` opts) (out "Show" $ show r)@@ -162,9 +133,9 @@  showRepoPrefs :: PutInfo -> IO () showRepoPrefs out = do-    get_preflist "prefs" >>= mapM_ prefOut-    get_preflist "author" >>= out "Author" . unlines-    get_preflist "defaultrepo" >>= out "Default Remote" . unlines+    getPreflist "prefs" >>= mapM_ prefOut+    getPreflist "author" >>= out "Author" . unlines+    getPreflist "defaultrepo" >>= out "Default Remote" . unlines   where prefOut = uncurry out . (\(p,v) -> (p++" Pref", (dropWhile isSpace v))) . break isSpace  showRepoMOTD :: RepoPatch p => PutInfo -> Repository p C(r u r) -> IO ()
src/Darcs/Commands/ShowTags.lhs view
@@ -17,21 +17,21 @@  \darcsCommand{show tags} \begin{code}-module Darcs.Commands.ShowTags ( show_tags ) where-import Darcs.Arguments ( DarcsFlag(..), working_repo_dir )+module Darcs.Commands.ShowTags ( showTags ) where+import Darcs.Arguments ( DarcsFlag(..), workingRepoDir ) import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Hopefully ( info ) import Darcs.Repository ( amInRepository, read_repo, withRepository, ($-) ) import Darcs.Patch.Info ( pi_tag )-import Darcs.Ordered ( mapRL, concatRL )+import Darcs.Witnesses.Ordered ( mapRL, concatRL ) import System.IO ( stderr, hPutStrLn ) -- import Printer ( renderPS ) -show_tags_description :: String-show_tags_description = "Show all tags in the repository."+showTagsDescription :: String+showTagsDescription = "Show all tags in the repository." -show_tags_help :: String-show_tags_help =+showTagsHelp :: String+showTagsHelp =  "The tags command writes a list of all tags in the repository to standard\n"++  "output.\n" ++  "\n" ++@@ -39,22 +39,22 @@  "for better interoperability with shell tools.  A warning is printed if\n" ++  "this happens." -show_tags :: DarcsCommand-show_tags = DarcsCommand {-  command_name = "tags",-  command_help = show_tags_help,-  command_description = show_tags_description,-  command_extra_args = 0,-  command_extra_arg_help = [],-  command_command = tags_cmd,-  command_prereq = amInRepository,-  command_get_arg_possibilities = return [],-  command_argdefaults = nodefaults,-  command_advanced_options = [],-  command_basic_options = [working_repo_dir] }+showTags :: DarcsCommand+showTags = DarcsCommand {+  commandName = "tags",+  commandHelp = showTagsHelp,+  commandDescription = showTagsDescription,+  commandExtraArgs = 0,+  commandExtraArgHelp = [],+  commandCommand = tagsCmd,+  commandPrereq = amInRepository,+  commandGetArgPossibilities = return [],+  commandArgdefaults = nodefaults,+  commandAdvancedOptions = [],+  commandBasicOptions = [workingRepoDir] } -tags_cmd :: [DarcsFlag] -> [String] -> IO ()-tags_cmd opts _ = withRepository opts $- \repository -> do+tagsCmd :: [DarcsFlag] -> [String] -> IO ()+tagsCmd opts _ = withRepository opts $- \repository -> do   patches <- read_repo repository   sequence_ $ mapRL process $ concatRL patches   where process hp =
src/Darcs/Commands/Tag.lhs view
@@ -18,36 +18,36 @@ \darcsCommand{tag} \begin{code} module Darcs.Commands.Tag ( tag ) where+import System.Directory ( removeFile ) import Control.Monad ( when ) -import Darcs.Commands ( DarcsCommand(DarcsCommand, command_name, command_help,-                        command_description, command_extra_args,-                        command_extra_arg_help, command_command, command_prereq,-                        command_get_arg_possibilities, command_argdefaults,-                        command_advanced_options, command_basic_options),+import Darcs.Commands ( DarcsCommand(DarcsCommand, commandName, commandHelp,+                        commandDescription, commandExtraArgs,+                        commandExtraArgHelp, commandCommand, commandPrereq,+                        commandGetArgPossibilities, commandArgdefaults,+                        commandAdvancedOptions, commandBasicOptions),                         nodefaults )-import Darcs.Arguments ( nocompress, umask_option, patchname_option, author,-                         checkpoint, pipe_interactive, ask_long_comment,-                         working_repo_dir, get_author )+import Darcs.Arguments ( nocompress, umaskOption, patchnameOption, author,+                         pipeInteractive, askLongComment,+                         workingRepoDir, getAuthor ) import Darcs.Hopefully ( n2pia ) import Darcs.Repository ( amInRepository, withRepoLock, ($-), read_repo,                     tentativelyAddPatch, finalizeRepositoryChanges,                    )-import Darcs.Repository.Checkpoint ( write_recorded_checkpoint ) import Darcs.Patch ( infopatch, identity, adddeps ) import Darcs.Patch.Info ( patchinfo ) import Darcs.Patch.Depends ( get_tags_right )-import Darcs.Commands.Record ( get_date, get_log )-import Darcs.Ordered ( FL(..) )+import Darcs.Commands.Record ( getDate, getLog )+import Darcs.Witnesses.Ordered ( FL(..) ) import Darcs.Lock ( world_readable_temp ) import Darcs.Flags ( DarcsFlag(..) ) import System.IO ( hPutStr, stderr ) -tag_description :: String-tag_description = "Name the current repository state for future reference."+tagDescription :: String+tagDescription = "Name the current repository state for future reference." -tag_help :: String-tag_help =+tagHelp :: String+tagHelp =  "The `darcs tag' command names the current repository state, so that it\n" ++  "can easily be referred to later.  Every `important' state should be\n" ++  "tagged; in particular it is good practice to tag each stable release\n" ++@@ -67,46 +67,44 @@  "A tag can have any name, but it is generally best to pick a naming\n" ++  "scheme and stick to it.\n" ++  "\n" ++- "The `darcs tag' command accepts the --pipe and --checkpoint options,\n" ++- "which behave as described in `darcs record' and `darcs optimize'\n" ++- "respectively.\n"+ "The `darcs tag' command accepts the --pipe option, which behaves as\n" +++ "described in `darcs record'.\n"  tag :: DarcsCommand-tag = DarcsCommand {command_name = "tag",-                    command_help = tag_help,-                    command_description = tag_description,-                    command_extra_args = -1,-                    command_extra_arg_help = ["[TAGNAME]"],-                    command_command = tag_cmd,-                    command_prereq = amInRepository,-                    command_get_arg_possibilities = return [],-                    command_argdefaults = nodefaults,-                    command_advanced_options = [nocompress,umask_option],-                    command_basic_options = [patchname_option, author,-                                            checkpoint,-                                            pipe_interactive,-                                            ask_long_comment,-                                            working_repo_dir]}+tag = DarcsCommand {commandName = "tag",+                    commandHelp = tagHelp,+                    commandDescription = tagDescription,+                    commandExtraArgs = -1,+                    commandExtraArgHelp = ["[TAGNAME]"],+                    commandCommand = tagCmd,+                    commandPrereq = amInRepository,+                    commandGetArgPossibilities = return [],+                    commandArgdefaults = nodefaults,+                    commandAdvancedOptions = [nocompress,umaskOption],+                    commandBasicOptions = [patchnameOption, author,+                                            pipeInteractive,+                                            askLongComment,+                                            workingRepoDir]} -tag_cmd :: [DarcsFlag] -> [String] -> IO ()-tag_cmd opts args = withRepoLock opts $- \repository -> do-    date <- get_date opts-    the_author <- get_author opts+tagCmd :: [DarcsFlag] -> [String] -> IO ()+tagCmd opts args = withRepoLock opts $- \repository -> do+    date <- getDate opts+    the_author <- getAuthor opts     deps <- get_tags_right `fmap` read_repo repository-    (name, long_comment)  <- get_name_log opts args+    (name, long_comment, mlogf)  <- get_name_log opts args     myinfo <- patchinfo date name the_author long_comment     let mypatch = infopatch myinfo identity     tentativelyAddPatch repository opts $ n2pia $ adddeps mypatch deps     finalizeRepositoryChanges repository-    when (CheckPoint `elem` opts) $ write_recorded_checkpoint repository myinfo+    maybe (return ()) removeFile mlogf     putStrLn $ "Finished tagging patch '"++name++"'"-  where  get_name_log :: [DarcsFlag] -> [String] -> IO (String, [String])+  where  get_name_log :: [DarcsFlag] -> [String] -> IO (String, [String], Maybe String)          get_name_log o a = do let o2 = if null a then o else (add_patch_name o (unwords a))-                               (name, comment, _) <- get_log o2 Nothing (world_readable_temp "darcs-tag") NilFL+                               (name, comment, mlogf) <- getLog o2 Nothing (world_readable_temp "darcs-tag") NilFL                                when (length name < 2) $ hPutStr stderr $                                  "Do you really want to tag '"                                  ++name++"'? If not type: darcs obliterate --last=1\n"-                               return ("TAG " ++ name, comment)+                               return ("TAG " ++ name, comment, mlogf)          add_patch_name :: [DarcsFlag] -> String -> [DarcsFlag]          add_patch_name o a| has_patch_name o = o                            | otherwise = [PatchName a] ++ o
src/Darcs/Commands/TrackDown.lhs view
@@ -25,22 +25,24 @@ import Control.Monad( when )  import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag(SetScriptsExecutable), working_repo_dir,-                         set_scripts_executable )+import Darcs.Arguments ( DarcsFlag(SetScriptsExecutable), workingRepoDir,+                         setScriptsExecutableOption ) import Darcs.Hopefully ( hopefully ) import Darcs.Repository ( amInRepository, read_repo, withRepoReadLock, ($-), withRecorded,                           setScriptsExecutable )-import Darcs.Ordered ( unsafeUnRL, concatRL )-import Darcs.Patch ( RepoPatch, Named, description, apply, invert )+import Darcs.Witnesses.Ordered ( FL(..), mapRL_RL, concatRL )+import Darcs.Patch ( RepoPatch, Named, description, apply, invert, invertRL ) import Printer ( putDocLn ) import Darcs.Test ( get_test ) import Darcs.Lock ( withTempDir ) -trackdown_description :: String-trackdown_description = "Locate the most recent version lacking an error."+#include "gadts.h" -trackdown_help :: String-trackdown_help =+trackdownDescription :: String+trackdownDescription = "Locate the most recent version lacking an error."++trackdownHelp :: String+trackdownHelp =  "Trackdown tries to find the most recent version in the repository which\n"++  "passes a test.  Given no arguments, it uses the default repository test.\n"++  "Given one argument, it treats it as a test command.  Given two arguments,\n"++@@ -48,21 +50,21 @@  "second is the test command.\n"  trackdown :: DarcsCommand-trackdown = DarcsCommand {command_name = "trackdown",-                          command_help = trackdown_help,-                          command_description = trackdown_description,-                          command_extra_args = -1,-                          command_extra_arg_help = ["[[INITIALIZATION]",+trackdown = DarcsCommand {commandName = "trackdown",+                          commandHelp = trackdownHelp,+                          commandDescription = trackdownDescription,+                          commandExtraArgs = -1,+                          commandExtraArgHelp = ["[[INITIALIZATION]",                                                     "COMMAND]"],-                          command_command = trackdown_cmd,-                          command_prereq = amInRepository,-                          command_get_arg_possibilities = return [],-                          command_argdefaults = nodefaults,-                          command_advanced_options = [set_scripts_executable],-                          command_basic_options = [working_repo_dir]}+                          commandCommand = trackdownCmd,+                          commandPrereq = amInRepository,+                          commandGetArgPossibilities = return [],+                          commandArgdefaults = nodefaults,+                          commandAdvancedOptions = [setScriptsExecutableOption],+                          commandBasicOptions = [workingRepoDir]} -trackdown_cmd :: [DarcsFlag] -> [String] -> IO ()-trackdown_cmd opts args = withRepoReadLock opts $- \repository -> do+trackdownCmd :: [DarcsFlag] -> [String] -> IO ()+trackdownCmd opts args = withRepoReadLock opts $- \repository -> do   patches <- read_repo repository   (init,test) <- case args of           [] ->@@ -79,10 +81,10 @@   withRecorded repository (withTempDir "trackingdown") $ \_ -> do     when (SetScriptsExecutable `elem` opts) setScriptsExecutable     init-    track_next opts test $ map (invert . hopefully) $ unsafeUnRL $ concatRL patches+    trackNext opts test . invertRL . mapRL_RL hopefully . concatRL $ patches -track_next :: RepoPatch p => [DarcsFlag] -> (IO ExitCode) -> [Named p] -> IO ()-track_next opts test (p:ps) = do+trackNext :: RepoPatch p => [DarcsFlag] -> (IO ExitCode) -> FL (Named p) C(x y) -> IO ()+trackNext opts test (p:>:ps) = do     test_result <- test     if test_result == ExitSuccess        then putStrLn "Success!"@@ -90,8 +92,8 @@                putStrLn "Trying without the patch:"                putDocLn $ description $ invert p                hFlush stdout-               track_next opts test ps-track_next _ _ [] = putStrLn "Noone passed the test!"+               trackNext opts test ps+trackNext _ _ NilFL = putStrLn "Noone passed the test!" \end{code}  Trackdown is helpful for locating when something was broken.  It creates
src/Darcs/Commands/TransferMode.lhs view
@@ -21,7 +21,7 @@ {-# LANGUAGE CPP, PatternGuards #-}  -- The pragma above is only for pattern guards.-module Darcs.Commands.TransferMode ( transfer_mode ) where+module Darcs.Commands.TransferMode ( transferMode ) where  import Prelude hiding ( catch ) import Control.Exception ( catch )@@ -29,18 +29,18 @@  import Darcs.Utils ( withCurrentDirectory, prettyException ) import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag, working_repo_dir )+import Darcs.Arguments ( DarcsFlag, workingRepoDir ) import Darcs.Repository ( amInRepository ) import Progress ( setProgressMode ) import Darcs.Global ( darcsdir )  import qualified Data.ByteString as B (hPut, readFile, length, ByteString) -transfer_mode_description :: String-transfer_mode_description = "Internal command for efficient ssh transfers."+transferModeDescription :: String+transferModeDescription = "Internal command for efficient ssh transfers." -transfer_mode_help :: String-transfer_mode_help =+transferModeHelp :: String+transferModeHelp =  "When pulling from or pushing to a remote repository over ssh, if both\n" ++  "the local and remote ends have Darcs 2, the `transfer-mode' command\n" ++  "will be invoked on the remote end.  This allows Darcs to intelligently\n" ++@@ -51,21 +51,21 @@  "who do not run ssh-agent will be prompted for the ssh password tens or\n" ++  "hundreds of times!\n" -transfer_mode :: DarcsCommand-transfer_mode = DarcsCommand {command_name = "transfer-mode",-                              command_help = transfer_mode_help,-                              command_description = transfer_mode_description,-                              command_extra_args = 0,-                              command_extra_arg_help = [],-                              command_get_arg_possibilities = return [],-                              command_command = transfer_mode_cmd,-                              command_prereq = amInRepository,-                              command_argdefaults = nodefaults,-                              command_advanced_options = [],-                              command_basic_options = [working_repo_dir]}+transferMode :: DarcsCommand+transferMode = DarcsCommand {commandName = "transfer-mode",+                              commandHelp = transferModeHelp,+                              commandDescription = transferModeDescription,+                              commandExtraArgs = 0,+                              commandExtraArgHelp = [],+                              commandGetArgPossibilities = return [],+                              commandCommand = transferModeCmd,+                              commandPrereq = amInRepository,+                              commandArgdefaults = nodefaults,+                              commandAdvancedOptions = [],+                              commandBasicOptions = [workingRepoDir]} -transfer_mode_cmd :: [DarcsFlag] -> [String] -> IO ()-transfer_mode_cmd _ _ = do setProgressMode False+transferModeCmd :: [DarcsFlag] -> [String] -> IO ()+transferModeCmd _ _ =   do setProgressMode False                            putStrLn "Hello user, I am darcs transfer mode"                            hFlush stdout                            withCurrentDirectory darcsdir $ transfer
src/Darcs/Commands/Unrecord.lhs view
@@ -20,41 +20,41 @@ {-# OPTIONS_GHC -cpp #-} {-# LANGUAGE CPP #-} -module Darcs.Commands.Unrecord ( unrecord, unpull, obliterate, get_last_patches ) where+module Darcs.Commands.Unrecord ( unrecord, unpull, obliterate, getLastPatches ) where import Control.Monad ( when ) import System.Exit ( exitWith, ExitCode( ExitSuccess ) ) -import Darcs.SlurpDirectory ( wait_a_moment )+import Printer ( text ) import Darcs.Hopefully ( hopefully )-import Darcs.Commands ( DarcsCommand(..), nodefaults, loggers, command_alias )-import Darcs.Arguments ( DarcsFlag( Verbose ),-                         working_repo_dir, nocompress, definePatches,-                        match_several_or_last, deps_sel,+import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias,+                        putVerbose )+import Darcs.Arguments ( DarcsFlag,+                         workingRepoDir, nocompress, definePatches,+                        matchSeveralOrLast, depsSel,                         ignoretimes,-                        all_interactive, umask_option, summary+                        allInteractive, umaskOption, summary, dryRun,+                        printDryRunMessageAndExit                       )-import Darcs.Match ( first_match, match_first_patchset, match_a_patchread )+import Darcs.Match ( firstMatch, matchFirstPatchset, matchAPatchread ) import Darcs.Repository ( PatchSet, PatchInfoAnd, withGutsOf,                           withRepoLock, ($-),                     tentativelyRemovePatches, finalizeRepositoryChanges,                     tentativelyAddToPending,                     applyToWorking,-                    get_unrecorded, read_repo, amInRepository,-                    sync_repo,-                  )-import Darcs.Patch ( Patchy, RepoPatch, invert, commutex, effect )-import Darcs.Ordered ( RL(..), (:<)(..), (:>)(..), (:\/:)(..), (+<+),+                    read_repo, amInRepository+                        , invalidateIndex, unrecordedChanges )+import Darcs.Patch ( Patchy, RepoPatch, invert, commute, effect )+import Darcs.Witnesses.Ordered ( RL(..), (:>)(..), (:\/:)(..), (+<+),                              mapFL_FL, nullFL,-                             concatRL, reverseRL, mapRL )+                             reverseRL, mapRL ) import Darcs.Patch.Depends ( get_common_and_uncommon ) import Darcs.SelectChanges ( with_selected_last_changes_reversed ) import Progress ( debugMessage )-import Darcs.Sealed ( Sealed(..), FlippedSeal(..), mapFlipped )-import Darcs.Gorsvet( invalidateIndex )+import Darcs.Witnesses.Sealed ( Sealed(..), FlippedSeal(..), mapFlipped ) #include "gadts.h" -unrecord_description :: String-unrecord_description =+unrecordDescription :: String+unrecordDescription =  "Remove recorded patches without changing the working copy." \end{code} @@ -124,8 +124,8 @@ more or fewer patches.  \begin{code}-unrecord_help :: String-unrecord_help =+unrecordHelp :: String+unrecordHelp =  "Unrecord does the opposite of record in that it makes the changes from\n"++  "patches active changes again which you may record or revert later.  The\n"++  "working copy itself will not change.\n"++@@ -134,56 +134,54 @@  "another user may have already pulled the patch.\n"  unrecord :: DarcsCommand-unrecord = DarcsCommand {command_name = "unrecord",-                         command_help = unrecord_help,-                         command_description = unrecord_description,-                         command_extra_args = 0,-                         command_extra_arg_help = [],-                         command_command = unrecord_cmd,-                         command_prereq = amInRepository,-                         command_get_arg_possibilities = return [],-                         command_argdefaults = nodefaults,-                         command_advanced_options = [nocompress,umask_option],-                         command_basic_options = [match_several_or_last,-                                                 deps_sel,-                                                 all_interactive,-                                                 working_repo_dir]}+unrecord = DarcsCommand {commandName = "unrecord",+                         commandHelp = unrecordHelp,+                         commandDescription = unrecordDescription,+                         commandExtraArgs = 0,+                         commandExtraArgHelp = [],+                         commandCommand = unrecordCmd,+                         commandPrereq = amInRepository,+                         commandGetArgPossibilities = return [],+                         commandArgdefaults = nodefaults,+                         commandAdvancedOptions = [nocompress,umaskOption],+                         commandBasicOptions = [matchSeveralOrLast,+                                                 depsSel,+                                                 allInteractive,+                                                 workingRepoDir]} -unrecord_cmd :: [DarcsFlag] -> [String] -> IO ()-unrecord_cmd opts _ = withRepoLock opts $- \repository -> do-  let (logMessage,_,_) = loggers opts+unrecordCmd :: [DarcsFlag] -> [String] -> IO ()+unrecordCmd opts _ = withRepoLock opts $- \repository -> do   allpatches <- read_repo repository-  FlippedSeal patches <- return $ if first_match opts-                                  then get_last_patches opts allpatches+  FlippedSeal patches <- return $ if firstMatch opts+                                  then getLastPatches opts allpatches                                   else matchingHead opts allpatches-  with_selected_last_changes_reversed "unrecord" opts+  with_selected_last_changes_reversed "unrecord" opts Nothing       (reverseRL patches) $     \ (_ :> to_unrecord) -> do-       when (nullFL to_unrecord) $ do logMessage "No patches selected!"+       when (nullFL to_unrecord) $ do putStrLn "No patches selected!"                                       exitWith ExitSuccess-       when (Verbose `elem` opts) $-            logMessage "About to write out (potentially) modified patches..."+       putVerbose opts $ text +                      "About to write out (potentially) modified patches..."        definePatches to_unrecord        invalidateIndex repository        withGutsOf repository $ do tentativelyRemovePatches repository opts $                                                            mapFL_FL hopefully to_unrecord                                   finalizeRepositoryChanges repository-       sync_repo repository-       logMessage "Finished unrecording."+       putStrLn "Finished unrecording." -get_last_patches :: RepoPatch p => [DarcsFlag] -> PatchSet p C(r)+getLastPatches :: RepoPatch p => [DarcsFlag] -> PatchSet p C(r)                  -> FlippedSeal (RL (PatchInfoAnd p)) C(r)-get_last_patches opts ps =-  case match_first_patchset opts ps of+getLastPatches opts ps =+  case matchFirstPatchset opts ps of   Sealed p1s -> case get_common_and_uncommon (ps,p1s) of-                (_,us :\/: _) -> FlippedSeal $ concatRL us+                (_,us :\/: _) -> FlippedSeal us -unpull_description :: String-unpull_description =+unpullDescription :: String+unpullDescription =  "Opposite of pull; unsafe if patch is not in remote repository." -unpull_help :: String-unpull_help =+unpullHelp :: String+unpullHelp =  "Unpull completely removes recorded patches from your local repository.\n"++  "The changes will be undone in your working copy and the patches will not be\n"++  "shown in your changes list anymore.\n"++@@ -191,24 +189,24 @@  "will lose precious code by unpulling!\n"  unpull :: DarcsCommand-unpull = (command_alias "unpull" obliterate)-                      {command_help = unpull_help,-                       command_description = unpull_description,-                       command_command = unpull_cmd}+unpull = (commandAlias "unpull" obliterate)+                      {commandHelp = unpullHelp,+                       commandDescription = unpullDescription,+                       commandCommand = unpullCmd} -unpull_cmd :: [DarcsFlag] -> [String] -> IO ()-unpull_cmd = generic_obliterate_cmd "unpull"+unpullCmd :: [DarcsFlag] -> [String] -> IO ()+unpullCmd = genericObliterateCmd "unpull"  \end{code} \darcsCommand{obliterate} \begin{code} -obliterate_description :: String-obliterate_description =+obliterateDescription :: String+obliterateDescription =  "Delete selected patches from the repository. (UNSAFE!)" -obliterate_help :: String-obliterate_help =+obliterateHelp :: String+obliterateHelp =  "Obliterate completely removes recorded patches from your local repository.\n"++  "The changes will be undone in your working copy and the patches will not be\n"++  "shown in your changes list anymore.\n"++@@ -260,67 +258,65 @@  \begin{code} obliterate :: DarcsCommand-obliterate = DarcsCommand {command_name = "obliterate",-                           command_help = obliterate_help,-                           command_description = obliterate_description,-                           command_extra_args = 0,-                           command_extra_arg_help = [],-                           command_command = obliterate_cmd,-                           command_prereq = amInRepository,-                           command_get_arg_possibilities = return [],-                           command_argdefaults = nodefaults,-                           command_advanced_options = [nocompress,ignoretimes,umask_option],-                           command_basic_options = [match_several_or_last,-                                                   deps_sel,-                                                   all_interactive,-                                                   working_repo_dir,-                                                   summary]}-obliterate_cmd :: [DarcsFlag] -> [String] -> IO ()-obliterate_cmd = generic_obliterate_cmd "obliterate"+obliterate = DarcsCommand {commandName = "obliterate",+                           commandHelp = obliterateHelp,+                           commandDescription = obliterateDescription,+                           commandExtraArgs = 0,+                           commandExtraArgHelp = [],+                           commandCommand = obliterateCmd,+                           commandPrereq = amInRepository,+                           commandGetArgPossibilities = return [],+                           commandArgdefaults = nodefaults,+                           commandAdvancedOptions = [nocompress,ignoretimes,umaskOption],+                           commandBasicOptions = [matchSeveralOrLast,+                                                   depsSel,+                                                   allInteractive,+                                                   workingRepoDir,+                                                   summary]+++                                                   dryRun}+obliterateCmd :: [DarcsFlag] -> [String] -> IO ()+obliterateCmd = genericObliterateCmd "obliterate" --- | generic_obliterate_cmd is the function that executes the "obliterate" and+-- | genericObliterateCmd is the function that executes the "obliterate" and --   "unpull" commands.-generic_obliterate_cmd :: String      -- ^ The name under which the command is invoked (@unpull@ or @obliterate@)+genericObliterateCmd :: String      -- ^ The name under which the command is invoked (@unpull@ or @obliterate@)                        -> [DarcsFlag] -- ^ The flags given on the command line                        -> [String]    -- ^ Files given on the command line (unused)                        -> IO ()-generic_obliterate_cmd cmdname opts _ = withRepoLock opts $- \repository -> do-  let (logMessage,_,_) = loggers opts-  pend <- get_unrecorded repository+genericObliterateCmd cmdname opts _ = withRepoLock opts $- \repository -> do+  pend <- unrecordedChanges opts repository []   allpatches <- read_repo repository-  FlippedSeal patches <- return $ if first_match opts-                                  then get_last_patches opts allpatches+  FlippedSeal patches <- return $ if firstMatch opts+                                  then getLastPatches opts allpatches                                   else matchingHead opts allpatches-  with_selected_last_changes_reversed cmdname opts+  with_selected_last_changes_reversed cmdname opts Nothing       (reverseRL patches) $     \ (_ :> ps) ->-    case commutex (pend :< effect ps) of+    case commute (effect ps :> pend) of     Nothing -> fail $ "Can't "++ cmdname ++                " patch without reverting some unrecorded change."-    Just (p_after_pending:<_) -> do-        when (nullFL ps) $ do logMessage "No patches selected!"+    Just (_ :> p_after_pending) -> do+        when (nullFL ps) $ do putStrLn "No patches selected!"                               exitWith ExitSuccess+        printDryRunMessageAndExit "obliterate" opts ps         definePatches ps         invalidateIndex repository         withGutsOf repository $                              do tentativelyRemovePatches repository opts (mapFL_FL hopefully ps)                                 tentativelyAddToPending repository opts $ invert $ effect ps                                 finalizeRepositoryChanges repository-                                debugMessage "Waiting a bit for timestamps to differ..."-                                wait_a_moment                                 debugMessage "Applying patches to working directory..."                                 applyToWorking repository opts (invert p_after_pending) `catch` \e ->                                     fail ("Couldn't undo patch in working dir.\n" ++ show e)-        sync_repo repository-        logMessage $ "Finished " ++ present_participle cmdname ++ "."+        putStrLn $ "Finished " ++ presentParticiple cmdname ++ "."  matchingHead :: Patchy p => [DarcsFlag] -> PatchSet p C(r) -> FlippedSeal (RL (PatchInfoAnd p)) C(r)-matchingHead opts (x:<:_) | or (mapRL (match_a_patchread opts) x) = FlippedSeal x+matchingHead opts (x:<:_) | or (mapRL (matchAPatchread opts) x) = FlippedSeal x matchingHead opts (x:<:xs) = (x +<+) `mapFlipped` matchingHead opts xs matchingHead _ NilRL = FlippedSeal NilRL -present_participle :: String -> String-present_participle v | last v == 'e' = init v ++ "ing"+presentParticiple :: String -> String+presentParticiple v | last v == 'e' = init v ++ "ing"                      | otherwise = v ++ "ing" \end{code} 
src/Darcs/Commands/Unrevert.lhs view
@@ -18,30 +18,29 @@ \darcsCommand{unrevert} \begin{code} {-# OPTIONS_GHC -cpp #-}-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP, GADTs #-}  #include "gadts.h" -module Darcs.Commands.Unrevert ( unrevert, write_unrevert ) where+module Darcs.Commands.Unrevert ( unrevert, writeUnrevert ) where import System.Exit ( ExitCode(..), exitWith )+import Storage.Hashed.Tree( Tree )  import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Arguments ( DarcsFlag( Unified, MarkConflicts ),-                         ignoretimes, working_repo_dir,-                        all_interactive, umask_option,+                         ignoretimes, workingRepoDir,+                        allInteractive, umaskOption,                       ) import Darcs.Repository ( SealedPatchSet, Repository, withRepoLock, ($-),                           unrevertUrl, considerMergeToWorking,                           tentativelyAddToPending, finalizeRepositoryChanges,-                          sync_repo, get_unrecorded,                           read_repo, amInRepository,-                          slurp_recorded,-                          applyToWorking )-import Darcs.Patch ( RepoPatch, Prim, commutex, namepatch, fromPrims )-import Darcs.Ordered ( RL(..), FL(..), (:<)(..), (:>)(..), (:\/:)(..), reverseRL,+                          readRecorded,+                          applyToWorking, unrecordedChanges )+import Darcs.Patch ( RepoPatch, Prim, commute, namepatch, fromPrims )+import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), (:\/:)(..), reverseRL,                        (+>+) ) import Darcs.SelectChanges ( with_selected_changes_to_files' )-import Darcs.SlurpDirectory ( Slurpy ) import qualified Data.ByteString as B import Darcs.Lock ( writeDocBinFile, removeFileMayNotExist ) import Darcs.Patch.Depends ( get_common_and_uncommon )@@ -50,15 +49,15 @@ import IsoDate ( getIsoDateTime ) import Darcs.SignalHandler ( withSignalsBlocked ) import Progress ( debugMessage )-import Darcs.Sealed ( Sealed(Sealed) )+import Darcs.Witnesses.Sealed ( Sealed(Sealed) ) #include "impossible.h" -unrevert_description :: String-unrevert_description =+unrevertDescription :: String+unrevertDescription =  "Undo the last revert (may fail if changes after the revert)." -unrevert_help :: String-unrevert_help =+unrevertHelp :: String+unrevertHelp =  "Unrevert is a rescue command in case you accidentally reverted\n" ++  "something you wanted to keep (for example, typing `darcs rev -a'\n" ++  "instead of `darcs rec -a').\n" ++@@ -68,31 +67,31 @@  "interactive command that will DEFINITELY prevent unreversion.\n"  unrevert :: DarcsCommand-unrevert = DarcsCommand {command_name = "unrevert",-                         command_help = unrevert_help,-                         command_description = unrevert_description,-                         command_extra_args = 0,-                         command_extra_arg_help = [],-                         command_command = unrevert_cmd,-                         command_prereq = amInRepository,-                         command_get_arg_possibilities = return [],-                         command_argdefaults = nodefaults,-                         command_advanced_options = [umask_option],-                         command_basic_options = [ignoretimes,-                                                  all_interactive,-                                                  working_repo_dir]}+unrevert = DarcsCommand {commandName = "unrevert",+                         commandHelp = unrevertHelp,+                         commandDescription = unrevertDescription,+                         commandExtraArgs = 0,+                         commandExtraArgHelp = [],+                         commandCommand = unrevertCmd,+                         commandPrereq = amInRepository,+                         commandGetArgPossibilities = return [],+                         commandArgdefaults = nodefaults,+                         commandAdvancedOptions = [umaskOption],+                         commandBasicOptions = [ignoretimes,+                                                  allInteractive,+                                                  workingRepoDir]} -unrevert_cmd :: [DarcsFlag] -> [String] -> IO ()-unrevert_cmd opts [] = withRepoLock opts $- \repository -> do+unrevertCmd :: [DarcsFlag] -> [String] -> IO ()+unrevertCmd opts [] = withRepoLock opts $- \repository -> do   us <- read_repo repository-  Sealed them <- unrevert_patch_bundle repository-  rec <- slurp_recorded repository-  unrec <- get_unrecorded repository+  Sealed them <- unrevertPatchBundle repository+  rec <- readRecorded repository+  unrec <- unrecordedChanges opts repository []   case get_common_and_uncommon (us, them) of-    (_, (h_us:<:NilRL) :\/: (h_them:<:NilRL)) -> do+    (_, h_us :\/: h_them) -> do       Sealed pw <- considerMergeToWorking repository "pull" (MarkConflicts:opts)                    (reverseRL h_us) (reverseRL h_them)-      with_selected_changes_to_files' "unrevert" opts [] pw $+      with_selected_changes_to_files' "unrevert" opts Nothing [] pw $                             \ (p :> skipped) -> do         tentativelyAddToPending repository opts p         withSignalsBlocked $@@ -100,34 +99,33 @@              applyToWorking repository opts p `catch` \e ->                  fail ("Error applying unrevert to working directory...\n"                        ++ show e)-             debugMessage "I'm about to write_unrevert."-             write_unrevert repository skipped rec (unrec+>+p)-        sync_repo repository+             debugMessage "I'm about to writeUnrevert."+             writeUnrevert repository skipped rec (unrec+>+p)         debugMessage "Finished unreverting."-    _ -> impossible-unrevert_cmd _ _ = impossible+unrevertCmd _ _ = impossible -write_unrevert :: RepoPatch p => Repository p C(r u t) -> FL Prim C(x y) -> Slurpy -> FL Prim C(r x) -> IO ()-write_unrevert repository NilFL _ _ = removeFileMayNotExist $ unrevertUrl repository-write_unrevert repository ps rec pend = do-  case commutex (ps :< pend) of+writeUnrevert :: RepoPatch p => Repository p C(r u t) -> FL Prim C(x y)+               -> Tree IO -> FL Prim C(r x) -> IO ()+writeUnrevert repository NilFL _ _ = removeFileMayNotExist $ unrevertUrl repository+writeUnrevert repository ps rec pend = do+  case commute (pend :> ps) of     Nothing -> do really <- askUser "You will not be able to unrevert this operation! Proceed? "                   case really of ('y':_) -> return ()                                  _ -> exitWith $ ExitSuccess-                  write_unrevert repository NilFL rec pend-    Just (_ :< p') -> do+                  writeUnrevert repository NilFL rec pend+    Just (p' :> _) -> do         rep <- read_repo repository         case get_common_and_uncommon (rep,rep) of             (common,_ :\/: _) -> do                 date <- getIsoDateTime                 np <- namepatch date "unrevert" "anon" [] (fromRepoPrims repository p')-                writeDocBinFile (unrevertUrl repository) $-                             make_bundle [Unified] rec common (np :>: NilFL)+                bundle <- make_bundle [Unified] rec common (np :>: NilFL)+                writeDocBinFile (unrevertUrl repository) bundle                 where fromRepoPrims :: RepoPatch p => Repository p C(r u t) -> FL Prim C(r y) -> p C(r y)                       fromRepoPrims _ xs = fromPrims xs -unrevert_patch_bundle :: RepoPatch p => Repository p C(r u t) -> IO (SealedPatchSet p)-unrevert_patch_bundle repository = do+unrevertPatchBundle :: RepoPatch p => Repository p C(r u t) -> IO (SealedPatchSet p)+unrevertPatchBundle repository = do   pf <- B.readFile (unrevertUrl repository)         `catchall` fail "There's nothing to unrevert!"   case scan_bundle pf of
src/Darcs/Commands/WhatsNew.lhs view
@@ -24,43 +24,43 @@  module Darcs.Commands.WhatsNew ( whatsnew ) where import System.Exit ( ExitCode(..), exitWith )-import Data.List ( sort )+import Data.List ( sort, (\\) ) import Control.Monad ( when )  import Darcs.Commands ( DarcsCommand(..), nodefaults )-import Darcs.Arguments ( DarcsFlag(..), working_repo_dir, lookforadds,-                        ignoretimes, noskip_boring,-                        unified, summary, no_cache,+import Darcs.Arguments ( DarcsFlag(..), workingRepoDir, lookforadds,+                        ignoretimes, noskipBoring,+                        unified, summary, noCache,                          areFileArgs, fixSubPaths,-                        list_registered_files,+                        listRegisteredFiles,                       )+import Darcs.Flags( isUnified ) import Darcs.RepoPath ( SubPath, sp2fn ) -import Darcs.Repository ( Repository, withRepository, ($-), slurp_recorded,-                          get_unrecorded_no_look_for_adds,-                          get_unrecorded_in_files, amInRepository )-import Darcs.Repository.Prefs ( filetype_function )-import Darcs.Diff ( unsafeDiff )-import Darcs.Patch ( RepoPatch, Prim, summarize, apply_to_slurpy, is_hunk )+import Darcs.Repository ( Repository, withRepository, ($-),+                          amInRepository+                        , unrecordedChanges, readRecordedAndPending, readRecorded, readUnrecorded )+import Darcs.Repository.State( restrictBoring )+import Darcs.Repository.Prefs ( filetypeFunction )+import Darcs.Patch ( RepoPatch, Prim, plainSummary, primIsHunk, applyToTree ) import Darcs.Patch.Permutations ( partitionRL ) import Darcs.Patch.Real ( RealPatch, prim2real ) import Darcs.Patch.FileName ( fn2fp ) import Darcs.PrintPatch ( printPatch, contextualPrintPatch )-import Darcs.Ordered ( FL(..), mapFL_FL, reverseRL, reverseFL, (:>)(..), nullFL )+import Darcs.Witnesses.Ordered ( FL(..), mapFL_FL, reverseRL, reverseFL, (:>)(..), nullFL )+import Darcs.Diff( treeDiff ) -import Darcs.Gorsvet( unrecordedChanges, restrictBoring, readRecordedAndPending ) import Storage.Hashed.Monad( virtualTreeIO, exists ) import Storage.Hashed( readPlainTree ) import Storage.Hashed( floatPath )  import Printer ( putDocLn, renderString, vcat, text )-#include "impossible.h" -whatsnew_description :: String-whatsnew_description = "List unrecorded changes in the working tree."+whatsnewDescription :: String+whatsnewDescription = "List unrecorded changes in the working tree." -whatsnew_help :: String-whatsnew_help =+whatsnewHelp :: String+whatsnewHelp =  "The `darcs whatsnew' command lists unrecorded changes to the working\n" ++  "tree.  If you specify a set of files and directories, only unrecorded\n" ++  "changes to those files and directories are listed.\n" ++@@ -89,26 +89,29 @@  "there are no unrecorded changes.\n"  whatsnew :: DarcsCommand-whatsnew = DarcsCommand {command_name = "whatsnew",-                         command_help = whatsnew_help,-                         command_description = whatsnew_description,-                         command_extra_args = -1,-                         command_extra_arg_help = ["[FILE or DIRECTORY]..."],-                         command_command = whatsnew_cmd,-                         command_prereq = amInRepository,-                         command_get_arg_possibilities = list_registered_files,-                         command_argdefaults = nodefaults,-                         command_advanced_options = [ignoretimes, noskip_boring, no_cache],-                         command_basic_options = [summary, unified,+whatsnew = DarcsCommand {commandName = "whatsnew",+                         commandHelp = whatsnewHelp,+                         commandDescription = whatsnewDescription,+                         commandExtraArgs = -1,+                         commandExtraArgHelp = ["[FILE or DIRECTORY]..."],+                         commandCommand = whatsnewCmd,+                         commandPrereq = amInRepository,+                         commandGetArgPossibilities = listRegisteredFiles,+                         commandArgdefaults = nodefaults,+                         commandAdvancedOptions = [ignoretimes, noskipBoring, noCache],+                         commandBasicOptions = [summary, unified,                                                  lookforadds,-                                                 working_repo_dir]}+                                                 workingRepoDir]} -announce_files :: (RepoPatch p) => Repository p C(r u t) -> [SubPath] -> IO ()-announce_files repo files =+announceFiles :: (RepoPatch p) => Repository p C(r u t) -> [SubPath] -> IO ()+announceFiles repo files =     when (areFileArgs files) $ do-      nonboring <- restrictBoring-      working <- nonboring `fmap` readPlainTree "."       pristine <- readRecordedAndPending repo+      -- TODO this is slightly inefficient, since we should really somehow+      -- extract the unrecorded state as a side-effect of unrecordedChanges+      index <- readUnrecorded repo+      nonboring <- restrictBoring index+      working <- nonboring `fmap` readPlainTree "."       let paths = map (fn2fp . sp2fn) files           check = virtualTreeIO (mapM exists $ map floatPath paths)       (in_working, _) <- check working@@ -121,25 +124,27 @@               putStrLn $ "WARNING: File '" ++ file ++ "' not in repository!"           maybe_warn _ = return () -whatsnew_cmd :: [DarcsFlag] -> [String] -> IO ()-whatsnew_cmd opts' args +whatsnewCmd :: [DarcsFlag] -> [String] -> IO ()+whatsnewCmd opts' args    | LookForAdds `elem` opts' && NoSummary `notElem` opts' =     -- add Summary to the opts since 'darcs whatsnew --look-for-adds'     -- implies summary     withRepository (Summary:opts') $- \repository -> do     files <- fixSubPaths opts' args-    announce_files repository files-    all_changes <- get_unrecorded_in_files repository (map sp2fn files)-    chold <- get_unrecorded_no_look_for_adds repository (map sp2fn files)-    s <- slurp_recorded repository-    ftf <- filetype_function-    cho_adds :> _ <- return $ partitionRL is_hunk $ reverseFL chold-    cha :> _ <- return $ partitionRL is_hunk $ reverseFL all_changes-    let chn    = unsafeDiff [LookForAdds,Summary] ftf-                            (fromJust $ apply_to_slurpy (reverseRL cho_adds) s)-                            (fromJust $ apply_to_slurpy (reverseRL cha) s)+    announceFiles repository files+    all_changes <- unrecordedChanges opts' repository files+    chold <- unrecordedChanges (opts' \\ [LookForAdds]) repository files+    pristine <- readRecorded repository+    ftf <- filetypeFunction+    cho_adds :> _ <- return $ partitionRL primIsHunk $ reverseFL chold+    cha :> _ <- return $ partitionRL primIsHunk $ reverseFL all_changes++    cho_adds_t <- applyToTree (reverseRL cho_adds) pristine+    cha_t <- applyToTree (reverseRL cha) pristine+    chn <- treeDiff ftf cho_adds_t cha_t+     exitOnNoChanges (chn, chold)-    putDocLn $ summarize chold+    putDocLn $ plainSummary chold     printSummary chn     where lower_as x = vcat $ map (text . l_as) $ lines x           l_as ('A':x) = 'a':x@@ -150,21 +155,21 @@           exitOnNoChanges _ = return ()           printSummary :: FL Prim C(x y) -> IO ()           printSummary NilFL = return ()-          printSummary new = putDocLn $ lower_as $ renderString $ summarize new+          printSummary new = putDocLn $ lower_as $ renderString $ plainSummary new -whatsnew_cmd opts args+whatsnewCmd opts args   | otherwise =     withRepository opts $- \repository -> do     files <- sort `fmap` fixSubPaths opts args-    announce_files repository files+    announceFiles repository files     changes <- unrecordedChanges opts repository files     when (nullFL changes) $ putStrLn "No changes!" >> (exitWith $ ExitFailure 1)     printSummary repository $ mapFL_FL prim2real changes        where printSummary :: RepoPatch p => Repository p C(r u t) -> FL RealPatch C(r y) -> IO ()              printSummary _ NilFL = do putStrLn "No changes!"                                        exitWith $ ExitFailure 1-             printSummary r ch | Summary `elem` opts = putDocLn $ summarize ch-                               | Unified `elem` opts = do s <- slurp_recorded r-                                                          contextualPrintPatch s ch+             printSummary r ch | Summary `elem` opts = putDocLn $ plainSummary ch+                               | isUnified opts = do pristine <- readRecorded r+                                                     contextualPrintPatch pristine ch                                | otherwise           = printPatch ch \end{code}
src/Darcs/CommandsAux.hs view
@@ -23,9 +23,9 @@ module Darcs.CommandsAux ( check_paths, malicious_patches, has_malicious_path,                         ) where import Darcs.Flags ( DarcsFlag( RestrictPaths, DontRestrictPaths ) )-import Darcs.Patch ( Patchy, list_touched_files )-import Darcs.Ordered ( FL, mapFL )-import Darcs.Sealed ( Sealed2(..), unseal2 )+import Darcs.Patch ( Patchy, listTouchedFiles )+import Darcs.Witnesses.Ordered ( FL, mapFL )+import Darcs.Witnesses.Sealed ( Sealed2(..), unseal2 ) import Darcs.Global ( darcsdir ) import Data.List ( intersect ) import System.FilePath ( splitDirectories )@@ -74,7 +74,7 @@  malicious_paths :: Patchy p => p C(x y) -> [String] malicious_paths patch =-  let paths = list_touched_files patch in+  let paths = listTouchedFiles patch in     filter is_malicious_path paths  {-|
src/Darcs/Diff.hs view
@@ -1,375 +1,85 @@--- Copyright (C) 2002-2003 David Roundy+-- Copyright (C) 2009 Petr Rockai ----- This program is free software; you can redistribute it and/or modify--- it under the terms of the GNU General Public License as published by--- the Free Software Foundation; either version 2, or (at your option)--- any later version.+-- Permission is hereby granted, free of charge, to any person+-- obtaining a copy of this software and associated documentation+-- files (the "Software"), to deal in the Software without+-- restriction, including without limitation the rights to use, copy,+-- modify, merge, publish, distribute, sublicense, and/or sell copies+-- of the Software, and to permit persons to whom the Software is+-- furnished to do so, subject to the following conditions: ----- This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.+-- The above copyright notice and this permission notice shall be+-- included in all copies or substantial portions of the Software. ----- You should have received a copy of the GNU General Public License--- along with this program; see the file COPYING.  If not, write to--- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,--- Boston, MA 02110-1301, USA.--{-# OPTIONS_GHC -cpp -fglasgow-exts #-}-{-# LANGUAGE CPP #-}--#include "gadts.h"--module Darcs.Diff ( unsafeDiffAtPaths, unsafeDiff, sync, cmp-#ifndef GADT_WITNESSES-                  , diff_files-#endif-                  ) where--import System.Posix-     ( setFileTimes )-import System.IO ( IOMode(ReadMode), hFileSize, hClose )-import System.Directory ( doesDirectoryExist, doesFileExist,-                   getDirectoryContents,-                 )-import Control.Monad ( when )-import Data.List ( sort-#ifndef GADT_WITNESSES-                 , intersperse, isPrefixOf-#endif-                 )-#ifndef GADT_WITNESSES-import Data.Maybe ( catMaybes )-#endif--#ifndef GADT_WITNESSES-import ByteStringUtils ( is_funky, linesPS)-import qualified Data.ByteString.Char8 as BC (last)-import qualified Data.ByteString as B       (null, empty, take, ByteString)-#endif-import qualified Data.ByteString as B       (hGet, length)+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+-- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+-- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+-- SOFTWARE. -import Darcs.SlurpDirectory ( Slurpy, slurp_name, is_dir, is_file,-#ifndef GADT_WITNESSES-                        get_slurp,-#endif-                        get_dircontents, get_filecontents,-                        get_mtime, get_length,-                        undefined_time-#ifndef GADT_WITNESSES-                        , FileContents, undefined_size-#endif-                      )-#ifndef GADT_WITNESSES-import System.FilePath.Posix ( (</>) )-#endif-import Darcs.Patch ( Prim-#ifndef GADT_WITNESSES-                   , hunk, canonize, rmfile, rmdir-                   , addfile, adddir-                   , binary, invert-#endif-                   )-#ifndef GADT_WITNESSES-import Darcs.Patch.FileName( fp2fn, breakup )-#endif-import System.IO ( openBinaryFile )+module Darcs.Diff( treeDiff ) where+import Darcs.Witnesses.Ordered ( FL(..), (+>+) ) import Darcs.Repository.Prefs ( FileType(..) )-import Darcs.Flags ( DarcsFlag(..) )-import Darcs.Utils ( catchall )-import Darcs.Ordered ( FL(..)-#ifndef GADT_WITNESSES-                           , (+>+)-#endif-                           )-#ifndef GADT_WITNESSES-#include "impossible.h"-#endif---- | The unsafeDiffAtPaths function calls diff_at_path for a set of files and---   and directories, and returns all changes to those files. It recurses into---   given directories when searching for changes.------   Comparing paths and not slurpies is useful when the user---   requests a diff for a file that is created or removed in the working copy:---   then there is no slurpy for the file in the /current/ or /working/ slurpy---   respectively.------   The given paths must always be fixed repository paths starting with a---   ".". It is safe to pass overlapping paths.------   The booleans in the first argument tell whether to ignore mtimes, whether---   we must look for additions and if we're diffing for a summary only.------   It returns an FL of patches, that contains all the changes that have been---   made at all those paths.-unsafeDiffAtPaths :: (Bool, Bool, Bool) -> (FilePath -> FileType) ->-               Slurpy -> Slurpy -> [FilePath] -> FL Prim C(x y)-#ifdef GADT_WITNESSES-unsafeDiffAtPaths = undefined-#else-unsafeDiffAtPaths flags filetypeFunction s1 s2 paths =-    foldr (+>+) NilFL (catMaybes diffsPerPath)-  where diffsPerPath = map differ safePaths-        differ       = diff_at_path flags filetypeFunction s1 s2-        safePaths    = make_nonoverlapping_path_set paths+import Darcs.Patch ( Prim, hunk, canonize, binary+                   , addfile, rmfile, adddir, rmdir, invert) -diff_at_path :: (Bool, Bool, Bool) -> (FilePath -> FileType)-                -> Slurpy -> Slurpy -> FilePath -> Maybe (FL Prim)-diff_at_path (ignoreTimes, lookForAdds, summary) filetypeFunction s1 s2 path =-    case (pathIn1, pathIn2) of-        (Nothing, Nothing) -> Nothing-        (Nothing, Just s2PathSlurpy) -> do-            Just $ diff_added summary filetypeFunction initialFps s2PathSlurpy NilFL-        (Just s1PathSlurpy, Nothing) -> do-            Just $ diff_removed filetypeFunction initialFps s1PathSlurpy NilFL-        (Just s1PathSlurpy, Just s2PathSlurpy) ->-            Just $ gendiff (ignoreTimes, lookForAdds, summary) filetypeFunction-                           initialFps s1PathSlurpy s2PathSlurpy NilFL-  where pathIn1 = get_slurp (fp2fn path) s1-        pathIn2 = get_slurp (fp2fn path) s2-        initialFps = tail $ reverse (breakup path)+import Storage.Hashed.Tree( diffTrees, zipTrees, TreeItem(..), Tree+                          , readBlob, emptyBlob )+import Storage.Hashed.AnchoredPath( AnchoredPath, anchorPath ) -make_nonoverlapping_path_set :: [FilePath] -> [FilePath]-make_nonoverlapping_path_set = map unbreakup . delete_overlapping . map breakup . sort-  where-    delete_overlapping :: [[FilePath]] -> [[FilePath]]-    delete_overlapping (p1:p2:ps) = if p1 `isPrefixOf` p2-                                      then delete_overlapping (p1:ps)-                                      else p1 : delete_overlapping (p2:ps)-    delete_overlapping ps         = ps-    unbreakup = concat . intersperse "/"-#endif+import qualified Data.ByteString.Lazy.Char8 as BLC+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as BL+import ByteStringUtils( is_funky ) --- The diff function takes a recursive diff of two slurped-up directory trees.--- The code involved is actually pretty trivial.  \verb!paranoid_diff! runs a--- diff in which we don't make the assumption that files with the same--- modification time are identical.+#include "gadts.h" -unsafeDiff :: [DarcsFlag]-           -> (FilePath -> FileType) -> Slurpy -> Slurpy -> FL Prim C(x y)+treeDiff :: (FilePath -> FileType) -> Tree IO -> Tree IO -> IO (FL Prim C(x y)) #ifdef GADT_WITNESSES-unsafeDiff = undefined+treeDiff = undefined -- Sigh. #else-unsafeDiff opts wt s1 s2-    = case diff_at_path (ignoreTimes, lookForAdds, summary)  wt s1 s2 "" of-          Just d -> d-          _      -> impossible -- because "" always exists in a slurpy -  where -- NoSummary/Summary both present gives False-        -- Just Summary gives True-        -- Just NoSummary gives False-        -- Neither gives False-        summary = Summary `elem` opts && NoSummary `notElem` opts-        lookForAdds = LookForAdds `elem` opts-        ignoreTimes = IgnoreTimes `elem` opts--mk_filepath :: [FilePath] -> FilePath-mk_filepath fps = concat $ intersperse "/" $ reverse fps--gendiff :: (Bool,Bool,Bool)-        -> (FilePath -> FileType) -> [FilePath] -> Slurpy -> Slurpy-        -> (FL Prim -> FL Prim)-gendiff opts@(isparanoid,_,_) wt fps s1 s2-    | is_file s1 && is_file s2 = diff_regular_files isparanoid wt f s1 s2-    | is_dir s1 && is_dir s2 =-          let fps' = case n2 of-                         "." -> fps-                         _ -> n2:fps-          in fps' `seq` recur_diff opts (wt . (n2</>)) fps' dc1 dc2-    | otherwise = id-    where n2 = slurp_name s2-          f = mk_filepath (n2:fps)-          dc1 = get_dircontents s1-          dc2 = get_dircontents s2---- recur_diff or recursive diff--- First parameter is (IgnoreTimes?, LookforAdds?, Summary?)-recur_diff :: (Bool,Bool,Bool)-           -> (FilePath -> FileType) -> [FilePath] -> [Slurpy] -> [Slurpy]-           -> (FL Prim -> FL Prim)-recur_diff _ _ _ [] [] = id-recur_diff opts@(_,doadd,summary) wt fps (s:ss) (s':ss')-    -- this is the case if a file has been removed in the working directory-    | s < s' = diff_removed wt fps s . recur_diff opts wt fps ss (s':ss')-    -- this next case is when there is a file in the directory that is not-    -- in the repository (ie, not managed by darcs)-    | s > s' = let rest = recur_diff opts wt fps (s:ss) ss'-               in if not doadd then                        rest-                               else diff_added summary wt fps s' . rest-    -- actually compare the files because the names match-    | s == s' = gendiff opts wt fps s s' . recur_diff opts wt fps ss ss'-recur_diff opts wt fps (s:ss) [] =-    diff_removed wt fps s . recur_diff opts wt fps ss []-recur_diff opts@(_,True,summary) wt fps [] (s':ss') =-    diff_added summary wt fps s' . recur_diff opts wt fps [] ss'-recur_diff (_,False,_) _ _ [] _ = id-recur_diff _ _ _ _ _ = impossible---- diff, taking into account paranoidness and file type, two regular files-diff_regular_files :: Bool -> (FilePath -> FileType) -> FilePath -> Slurpy -> Slurpy -> (FL Prim -> FL Prim)-diff_regular_files ignoreTimes filetypeFunction f s1 s2 = -    if maybe_differ   -        then case filetypeFunction (slurp_name s2) of                                     -               TextFile -> diff_files f b1 b2                    -               BinaryFile -> if b1 /= b2 then (binary f b1 b2:>:)-                                         else id                 -        else id-  where maybe_differ = ignoreTimes-                     || get_mtime s1 == undefined_time-                     || get_mtime s1 /= get_mtime s2-                     || get_length s1 == undefined_size-                     || get_length s1 /= get_length s2-        b1 = get_filecontents s1-        b2 = get_filecontents s2---- creates a diff for a file or directory which needs to be added to the--- repository-diff_added :: Bool -> (FilePath -> FileType) -> [FilePath] -> Slurpy-           -> (FL Prim -> FL Prim)-diff_added summary wt fps s-    | is_file s = case wt n of-                  TextFile -> (addfile f:>:) .-                              (if summary-                               then id-                               else diff_from_empty id f (get_filecontents s))-                  BinaryFile -> (addfile f:>:) .-                                (if summary then id else-                                (bin_patch f B.empty (get_filecontents s)))-    | otherwise {- is_dir s -} =-        (adddir f:>:)-      . foldr (.) id (map (diff_added summary wt (n:fps)) (get_dircontents s))-    where n = slurp_name s-          f = mk_filepath (n:fps)--get_text :: FileContents -> [B.ByteString]-get_text = linesPS--empt :: FileContents-empt = B.empty--diff_files :: FilePath -> FileContents -> FileContents-           -> (FL Prim -> FL Prim)-diff_files f o n | get_text o == [B.empty] && get_text n == [B.empty] = id-                 | get_text o == [B.empty] = diff_from_empty id f n-                 | get_text n == [B.empty] = diff_from_empty invert f o-diff_files f o n = if o == n-                   then id-                   else if has_bin o || has_bin n-                        then (binary f o n:>:)-                        else (canonize (hunk f 1 (linesPS o) (linesPS n)) +>+)--diff_from_empty :: (Prim -> Prim) -> FilePath -> FileContents-                -> (FL Prim -> FL Prim)-diff_from_empty inv f b =-    if b == B.empty-    then id-    else let p = if has_bin b-                 then binary f B.empty b-                 else if BC.last b == '\n'-                      then hunk f 1 [] $ init $ linesPS b-                      else hunk f 1 [B.empty] $ linesPS b-         in (inv p:>:)--{- | We take a B.ByteString which represents a file's contents, and we check to see-whether it is a 'binary' file or a 'textual' file. We define a textual file as any file-which does not contain two magic characters, '\0' (the NULL character on Unix) and '^Z'-(Control-Z, a DOS convention).--Note that to improve performance, we won't examine *all* of the string, because that-falls down on large files, but just the first 4096 characters. -}-has_bin :: FileContents -> Bool-has_bin = is_funky . B.take 4096-#endif--#ifndef GADT_WITNESSES-bin_patch :: FilePath -> B.ByteString -> B.ByteString-          -> FL Prim -> FL Prim-bin_patch f o n | B.null o && B.null n = id-                | otherwise = (binary f o n:>:)-#endif--#ifndef GADT_WITNESSES-diff_removed :: (FilePath -> FileType) -> [FilePath] -> Slurpy-             -> (FL Prim -> FL Prim)-diff_removed wt fps s-    | is_file s = case wt n of-                  TextFile -> diff_files f (get_filecontents s) empt-                            . (rmfile f:>:)-                  BinaryFile -> (bin_patch f-                                 (get_filecontents s) B.empty)-                              . (rmfile f:>:)-    | otherwise {- is_dir s -}-        = foldr (.) (rmdir f:>:)-        $ map (diff_removed wt (n:fps)) (get_dircontents s)-    where n = slurp_name s-          f = mk_filepath (n:fps)+treeDiff ft t1 t2 = do+  (from, to) <- diffTrees t1 t2+  diffs <- sequence $ zipTrees diff from to+  return $ foldr (+>+) NilFL diffs+    where diff :: AnchoredPath -> Maybe (TreeItem IO) -> Maybe (TreeItem IO)+               -> IO (FL Prim)+          diff _ (Just (SubTree _)) (Just (SubTree _)) = return NilFL+          diff p (Just (SubTree _)) Nothing =+              return $ rmdir (anchorPath "" p) :>: NilFL+          diff p Nothing (Just (SubTree _)) =+              return $ adddir (anchorPath "" p) :>: NilFL+          diff p Nothing b'@(Just (File _)) =+              do diff' <- diff p (Just (File emptyBlob)) b'+                 return $ addfile (anchorPath "" p) :>: diff'+          diff p a'@(Just (File _)) Nothing =+              do diff' <- diff p a' (Just (File emptyBlob))+                 return $ diff' +>+ (rmfile (anchorPath "" p) :>: NilFL)+          diff p (Just (File a')) (Just (File b')) =+              do a <- readBlob a'+                 b <- readBlob b'+                 let path = anchorPath "" p+                 case ft path of+                   TextFile | no_bin a && no_bin b ->+                                return $ text_diff path a b+                   _ -> return $ if a /= b+                                    then binary path (strict a) (strict b) :>: NilFL+                                    else NilFL+          diff p _ _ = fail $ "Missing case at path " ++ show p+          text_diff p a b+              | BL.null a && BL.null b = NilFL+              | BL.null a = diff_from_empty p b+              | BL.null b = diff_to_empty p a+              | otherwise = line_diff p (linesB a) (linesB b)+          line_diff p a b = canonize (hunk p 1 a b)+          diff_to_empty p x | BLC.last x == '\n' = line_diff p (init $ linesB x) []+                            | otherwise = line_diff p (linesB x) [BS.empty]+          diff_from_empty p x = invert (diff_to_empty p x)+          no_bin = not . is_funky . strict . BL.take 4096+          linesB = map strict . BLC.split '\n'+          strict = BS.concat . BL.toChunks #endif -sync :: String -> Slurpy -> Slurpy -> IO ()-sync path s1 s2-    | is_file s1 && is_file s2 &&-      (get_mtime s1 == undefined_time || get_mtime s1 /= get_mtime s2) &&-      get_length s1 == get_length s2 &&-      get_filecontents s1 == get_filecontents s2 =-        set_mtime n (get_mtime s2)-    | is_dir s1 && is_dir s2-        = n2 `seq` recur_sync n (get_dircontents s1) (get_dircontents s2)-    | otherwise = return ()-    where n2 = slurp_name s2-          n = path++"/"++n2-          set_mtime fname ctime = setFileTimes fname ctime ctime-                       `catchall` return ()-          recur_sync _ [] _ = return ()-          recur_sync _ _ [] = return ()-          recur_sync p (s:ss) (s':ss')-              | s < s' = recur_sync p ss (s':ss')-              | s > s' = recur_sync p (s:ss) ss'-              | otherwise = do sync p s s'-                               recur_sync p ss ss'---cmp :: FilePath -> FilePath -> IO Bool-cmp p1 p2 = do-  dir1 <- doesDirectoryExist p1-  dir2 <- doesDirectoryExist p2-  file1 <- doesFileExist p1-  file2 <- doesFileExist p2-  if dir1 && dir2-     then cmpdir p1 p2-     else if file1 && file2-          then cmpfile p1 p2-          else return False-cmpdir :: FilePath -> FilePath -> IO Bool-cmpdir d1 d2 = do-  fn1 <- fmap (filter (\f->f/="." && f /="..")) $ getDirectoryContents d1-  fn2 <- fmap (filter (\f->f/="." && f /="..")) $ getDirectoryContents d2-  if sort fn1 /= sort fn2-     then return False-     else andIO $ map (\fn-> cmp (d1++"/"++fn) (d2++"/"++fn)) fn1-andIO :: [IO Bool] -> IO Bool-andIO (iob:iobs) = do b <- iob-                      if b then andIO iobs else return False-andIO [] = return True-cmpfile :: FilePath -> FilePath -> IO Bool-cmpfile f1 f2 = do-  h1 <- openBinaryFile f1 ReadMode-  h2 <- openBinaryFile f2 ReadMode-  l1 <- hFileSize h1-  l2 <- hFileSize h2-  if l1 /= l2-     then do hClose h1-             hClose h2-             putStrLn $ "different file lengths for "++f1++" and "++f2-             return False-     else do b <- hcmp h1 h2-             when (not b) $ putStrLn $ "files "++f1++" and "++f2++" differ"-             hClose h1-             hClose h2-             return b-    where hcmp h1 h2 = do c1 <- B.hGet h1 1024-                          c2 <- B.hGet h2 1024-                          if c1 /= c2-                             then return False-                             else if B.length c1 == 1024-                                  then hcmp h1 h2-                                  else return True
src/Darcs/Email.hs view
@@ -4,7 +4,7 @@  import Data.Char ( digitToInt, isHexDigit, ord, intToDigit, isPrint, toUpper ) import Data.List ( isInfixOf )-import qualified UTF8 ( encode )+import qualified Codec.Binary.UTF8.String as UTF8 ( encode ) import Printer ( Doc, ($$), (<+>), (<>), text, empty, packedString, renderPS)  import ByteStringUtils (dropSpace, linesPS, betweenLinesPS )@@ -53,7 +53,7 @@       -- character: 4 * 3, 4 UTF-8 bytes times 3 ASCII chars per byte       safeEncChunkLength = (qline_max - B.length encoded_word_start                                       - B.length encoded_word_end) `div` 12-      (curSpace, afterCurSpace) = break (not . (== ' ')) s+      (curSpace, afterCurSpace) = span (== ' ') s       (curWord,  afterCurWord)  = break (== ' ') afterCurSpace       qEncWord | lastWordEncoded = qEncode (curSpace ++ curWord)                | otherwise       = qEncode curWord
src/Darcs/External.hs view
@@ -10,17 +10,19 @@     execDocPipe, execPipeIgnoreError,     getTermNColors,     pipeDoc, pipeDocSSH, execSSH,+    remoteDarcsCmd,     maybeURLCmd,     Cachable(Cachable, Uncachable, MaxAge),     viewDoc, viewDocWith,-    sendmail_path, diff_program+    sendmail_path, diff_program, darcs_program   ) where +import qualified Ratified import Data.Maybe ( isJust, isNothing, maybeToList ) import Control.Monad ( when, zipWithM_, filterM, liftM2 ) import System.Exit ( ExitCode(..) )-import System.Environment ( getEnv )-import System.IO ( hPutStr, hPutStrLn, hGetContents, hClose,+import System.Environment ( getEnv, getProgName )+import System.IO ( hPutStr, hPutStrLn, hClose,                    openBinaryFile, IOMode( ReadMode ),                    openBinaryTempFile,                    hIsTerminalDevice, stdout, stderr, Handle )@@ -49,14 +51,14 @@ import System.FilePath.Posix ( (</>), takeDirectory, normalise )  import Darcs.Flags ( DarcsFlag( SignAs, Sign, SignSSL, NoLinks,-                                Verify, VerifySSL ) )+                                Verify, VerifySSL, RemoteDarcs ) ) import Darcs.RepoPath ( AbsolutePath, toFilePath ) import Darcs.Utils ( withCurrentDirectory, breakCommand, get_viewer, ortryrunning, ) import Progress ( withoutProgress, progressList, debugMessage )  import ByteStringUtils (gzReadFilePS, linesPS, unlinesPS)-import qualified Data.ByteString as B (ByteString, empty, null, readFile -- ratify readFile: Just an import from ByteString-            ,hGetContents, writeFile, hPut, length -- ratify hGetContents: importing from ByteString+import qualified Data.ByteString as B (ByteString, empty, null, readFile+            ,hGetContents, writeFile, hPut, length             ,take, concat, drop, isPrefixOf, singleton, append) import qualified Data.ByteString.Char8 as BC (unpack, pack) @@ -88,6 +90,11 @@   when (null l) $ fail "Cannot find the \"diff\" program."   return $ head l +-- |Get the name of the darcs executable (as supplied by @getProgName@)+darcs_program :: IO String+darcs_program = getProgName+-- Another option: getEnv "DARCS" `catch` \_ -> getProgName+ backupByRenaming :: FilePath -> IO () backupByRenaming = backupBy rename  where rename x y = do@@ -123,19 +130,23 @@ -- will use a cache as required by its second argument. fetchFilePS :: String -> Cachable -> IO B.ByteString fetchFilePS fou _ | is_file fou = B.readFile fou-fetchFilePS fou cache = withTemp $ \t -> do copyFileOrUrl [] fou t cache+fetchFilePS fou cache = withTemp $ \t -> do let opts = [] -- FIXME: no network flags+                                            copyFileOrUrl opts fou t cache                                             B.readFile t  gzFetchFilePS :: String -> Cachable -> IO B.ByteString gzFetchFilePS fou _ | is_file fou = gzReadFilePS fou-gzFetchFilePS fou cache = withTemp $ \t-> do copyFileOrUrl [] fou t cache+gzFetchFilePS fou cache = withTemp $ \t-> do let opts = [] -- FIXME: no network flags+                                             copyFileOrUrl opts fou t cache                                              gzReadFilePS t +remoteDarcsCmd :: [DarcsFlag] -> String+remoteDarcsCmd flags = head $ [ c | (RemoteDarcs c) <- flags ] ++ ["darcs"]  copyFileOrUrl :: [DarcsFlag] -> FilePath -> FilePath -> Cachable -> IO () copyFileOrUrl opts fou out _     | is_file fou = copyLocal opts fou out copyFileOrUrl _    fou out cache | is_url  fou = copyRemote fou out cache-copyFileOrUrl _    fou out _     | is_ssh  fou = copySSH fou out+copyFileOrUrl opts fou out _     | is_ssh  fou = copySSH (remoteDarcsCmd opts) fou out copyFileOrUrl _    fou _   _     = fail $ "unknown transport protocol: " ++ fou  speculateFileOrUrl :: String -> FilePath -> IO ()@@ -240,7 +251,7 @@ copyFilesOrUrls :: [DarcsFlag]->FilePath->[String]->FilePath->Cachable->IO () copyFilesOrUrls opts dou ns out _ | is_file dou = copyLocals opts dou ns out copyFilesOrUrls _ dou ns out c    | is_url  dou = copyRemotes dou ns out c-copyFilesOrUrls _ dou ns out _    | is_ssh  dou = copySSHs dou ns out+copyFilesOrUrls opts dou ns out _ | is_ssh  dou = copySSHs (remoteDarcsCmd opts) dou ns out copyFilesOrUrls _ dou _  _   _    = fail $ "unknown transport protocol: "++dou  @@ -306,11 +317,11 @@     do debugMessage $ unwords (c:args)        (i,o,e,pid) <- runInteractiveProcess c args Nothing Nothing        mvare <- newEmptyMVar-       forkIO ((hGetContents e >>= -- ratify hGetContents: it's immediately consumed+       forkIO ((Ratified.hGetContents e >>= -- ratify: immediately consumed                 hPutStr stderr)                `finally` putMVar mvare ())        mvaro <- newEmptyMVar-       forkIO ((hGetContents o >>= -- ratify hGetContents: it's immediately consumed+       forkIO ((Ratified.hGetContents o >>= -- ratify: immediately consumed                 hPutStr stdout)                `finally` putMVar mvaro ())        hPutDoc i inp@@ -485,7 +496,7 @@     do (i,o,e,pid) <- runInteractiveProcess c args Nothing Nothing        forkIO $ hPutDoc i instr >> hClose i        mvare <- newEmptyMVar-       forkIO ((hGetContents e >>= -- ratify hGetContents: it's immediately consumed+       forkIO ((Ratified.hGetContents e >>= -- ratify: immediately consumed                 hPutStr stderr)                `finally` putMVar mvare ())        out <- B.hGetContents o@@ -503,7 +514,7 @@     do (i,o,e,pid) <- runInteractiveProcess c args Nothing Nothing        forkIO $ hPutDoc i instr >> hClose i        mvare <- newEmptyMVar-       forkIO ((hGetContents e >>= -- ratify hGetContents: it's immediately consumed+       forkIO ((Ratified.hGetContents e >>= -- ratify: immediately consumed                 hPutStr stderr)                `finally` putMVar mvare ())        out <- B.hGetContents o@@ -620,8 +631,9 @@ viewDocWith pr msg = do   isTerminal <- hIsTerminalDevice stdout   if isTerminal && lengthGreaterThan (20 :: Int) (lines $ renderString msg)-     then do viewer <- get_viewer-             pipeDocToPager viewer [] pr msg+     then do viewerPlusArgs <- get_viewer+             let (viewer:args) = words viewerPlusArgs+             pipeDocToPager viewer args pr msg                `ortryrunning` pipeDocToPager  "less" [] pr msg                `ortryrunning` pipeDocToPager  "more" [] pr msg #ifdef WIN32
src/Darcs/FilePathMonad.hs view
@@ -25,7 +25,7 @@ import Data.Maybe ( catMaybes )  import Darcs.IO ( ReadableDirectory(..), WriteableDirectory(..) )-import Darcs.Patch.FileName ( FileName, fp2fn, fn2fp, super_name, break_on_dir,+import Darcs.Patch.FileName ( FileName, fp2fn, fn2fp, superName, break_on_dir,                               norm_path, movedirfilename ) #include "impossible.h" @@ -60,7 +60,7 @@                            if d == d' then Just f'                                       else Nothing     mGetDirectoryContents =-        FPM $ \fs -> (fs, filter (\f -> fp2fn "." == super_name f) fs)+        FPM $ \fs -> (fs, filter (\f -> fp2fn "." == superName f) fs)     mReadFilePS = bug "can't mReadFilePS in FilePathMonad!"  instance WriteableDirectory FilePathMonad where
src/Darcs/Flags.hs view
@@ -15,16 +15,21 @@ -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. -module Darcs.Flags ( DarcsFlag( .. ), Compression( .. ), compression, want_external_merge, isInteractive,-                     maxCount,+module Darcs.Flags ( DarcsFlag( .. ), Compression( .. ), compression, +                     want_external_merge, isInteractive,+                     maxCount, willIgnoreTimes, willRemoveLogFile, isUnified,+                     willStoreInMemory, doHappyForwarding, includeBoring,+                     doAllowCaseOnly, doAllowWindowsReserved, doReverse,+                     showChangesOnlyToFiles                    ) where+import Data.Maybe( fromMaybe ) import Darcs.Patch.MatchData ( PatchMatch ) import Darcs.RepoPath ( AbsolutePath, AbsolutePathOrStd )  -- | The 'DarcsFlag' type is a list of all flags that can ever be -- passed to darcs, or to one of its commands. data DarcsFlag = Help | ListOptions | NoTest | Test-               | OnlyChangesToFiles+               | OnlyChangesToFiles | ChangesToAllFiles                | LeaveTestDir | NoLeaveTestDir                | Timings | Debug | DebugVerbose | DebugHTTP                | Verbose | NormalVerbosity | Quiet@@ -38,22 +43,27 @@                | NumberPatches                | OneTag String | AfterTag String | UpToTag String                | Context AbsolutePath | Count-               | LogFile AbsolutePath | RmLogFile+               | LogFile AbsolutePath | RmLogFile | DontRmLogFile                | DistName String | All                | Recursive | NoRecursive | Reorder                | RestrictPaths | DontRestrictPaths-               | AskDeps | NoAskDeps | IgnoreTimes | LookForAdds | NoLookForAdds+               | AskDeps | NoAskDeps | IgnoreTimes | DontIgnoreTimes+               | LookForAdds | NoLookForAdds                | AnyOrder | CreatorHash String                | Intersection | Union | Complement                | Sign | SignAs String | NoSign | SignSSL String-               | HappyForwarding+               | HappyForwarding | NoHappyForwarding                | Verify AbsolutePath | VerifySSL AbsolutePath                | SSHControlMaster | NoSSHControlMaster+               | RemoteDarcs String                | EditDescription | NoEditDescription                | Toks String                | EditLongComment | NoEditLongComment | PromptLongComment                | AllowConflicts | MarkConflicts | NoAllowConflicts-               | Boring | AllowCaseOnly | AllowWindowsReserved+               | SkipConflicts+               | Boring | SkipBoring+               | AllowCaseOnly | DontAllowCaseOnly+               | AllowWindowsReserved | DontAllowWindowsReserved                | DontGrabDeps | DontPromptForDependencies | PromptForDependencies                | Compress | NoCompress | UnCompress                | WorkRepoDir String | WorkRepoUrl String | RemoteRepo String@@ -63,8 +73,8 @@                | Pipe | Interactive                | DiffCmd String                | ExternalMerge String | Summary | NoSummary-               | Unified | Reverse-               | CheckPoint | Partial | Complete | Lazy | Ephemeral+               | Unified | NonUnified | Reverse | Forward+               | Partial | Complete | Lazy | Ephemeral                | FixFilePath AbsolutePath AbsolutePath | DiffFlags String                | XMLOutput                | ForceReplace@@ -78,12 +88,14 @@                | UseFormat2                | PristinePlain | PristineNone | NoUpdateWorking                | Sibling AbsolutePath | Relink | RelinkPristine | NoLinks+               | OptimizePristine+               | UpgradeFormat                | Files | NoFiles | Directories | NoDirectories                | Pending | NoPending                | PosthookCmd String | NoPosthook | AskPosthook | RunPosthook                | PrehookCmd String  | NoPrehook  | AskPrehook  | RunPrehook                | UMask String-               | StoreInMemory+               | StoreInMemory | ApplyOnDisk                | HTTPPipelining | NoHTTPPipelining                | NoCache                | AllowUnrelatedRepos@@ -114,3 +126,43 @@ maxCount (MaxCount n : _) = Just n maxCount (_:xs) = maxCount xs maxCount [] = Nothing++-- | @lastWord [(flag, value)] default opts@ scans @opts@ for a flag+-- in the list and returns the value of the first match, or @default@+-- if none is found.+lastWord :: [(DarcsFlag,a)] -> a -> [DarcsFlag] -> a+lastWord known_flags = foldr . flip $ \ def -> fromMaybe def . flip lookup known_flags++getBoolFlag :: DarcsFlag -> DarcsFlag -> [DarcsFlag] -> Bool+getBoolFlag t f = lastWord [(t, True), (f, False)] False++willIgnoreTimes :: [DarcsFlag] -> Bool+willIgnoreTimes = getBoolFlag IgnoreTimes DontIgnoreTimes++willRemoveLogFile :: [DarcsFlag] -> Bool+willRemoveLogFile = getBoolFlag RmLogFile DontRmLogFile++isUnified :: [DarcsFlag] -> Bool+isUnified = getBoolFlag Unified NonUnified++willStoreInMemory :: [DarcsFlag] -> Bool+willStoreInMemory = getBoolFlag Unified NonUnified++doHappyForwarding :: [DarcsFlag] -> Bool+doHappyForwarding = getBoolFlag HappyForwarding NoHappyForwarding++includeBoring :: [DarcsFlag] -> Bool+includeBoring = getBoolFlag Boring SkipBoring++doAllowCaseOnly :: [DarcsFlag] -> Bool+doAllowCaseOnly = getBoolFlag AllowCaseOnly DontAllowCaseOnly+++doAllowWindowsReserved :: [DarcsFlag] -> Bool+doAllowWindowsReserved = getBoolFlag AllowWindowsReserved DontAllowWindowsReserved++doReverse :: [DarcsFlag] -> Bool+doReverse = getBoolFlag Reverse Forward++showChangesOnlyToFiles :: [DarcsFlag] -> Bool+showChangesOnlyToFiles = getBoolFlag OnlyChangesToFiles ChangesToAllFiles
src/Darcs/Global.hs view
@@ -26,9 +26,7 @@                       timingsMode, setTimingsMode,                       whenDebugMode, withDebugMode, setDebugMode,                       debugMessage, debugFail, putTiming,-#ifdef HAVE_HASKELL_ZLIB                       addCRCWarning, getCRCWarnings, resetCRCWarnings,-#endif                       darcsdir     ) where @@ -36,9 +34,7 @@ import Control.Concurrent.MVar import Control.Exception (bracket_, catch, block, unblock) import Data.IORef ( IORef, newIORef, readIORef, writeIORef )-#ifdef HAVE_HASKELL_ZLIB import Data.IORef ( modifyIORef )-#endif import System.IO.Unsafe (unsafePerformIO) import System.IO (hPutStrLn, hPutStr, stderr) import System.Time ( calendarTimeToString, toCalendarTime, getClockTime )@@ -139,7 +135,6 @@ sshControlMasterDisabled :: Bool sshControlMasterDisabled = unsafePerformIO $ readIORef _sshControlMasterDisabled -#ifdef HAVE_HASKELL_ZLIB type CRCWarningList = [FilePath] {-# NOINLINE _crcWarningList #-} _crcWarningList :: IORef CRCWarningList@@ -153,7 +148,6 @@  resetCRCWarnings :: IO () resetCRCWarnings = writeIORef _crcWarningList []-#endif  darcsdir :: String darcsdir = "_darcs"
− src/Darcs/Gorsvet.hs
@@ -1,256 +0,0 @@-{-# LANGUAGE CPP, FlexibleInstances #-}-{-# OPTIONS_GHC -cpp -fglasgow-exts -fno-warn-orphans #-}---- Copyright (C) 2009 Petr Rockai------ Permission is hereby granted, free of charge, to any person--- obtaining a copy of this software and associated documentation--- files (the "Software"), to deal in the Software without--- restriction, including without limitation the rights to use, copy,--- modify, merge, publish, distribute, sublicense, and/or sell copies--- of the Software, and to permit persons to whom the Software is--- furnished to do so, subject to the following conditions:------ The above copyright notice and this permission notice shall be--- included in all copies or substantial portions of the Software.------ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,--- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF--- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND--- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS--- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN--- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN--- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE--- SOFTWARE.--#include "gadts.h"--module Darcs.Gorsvet where--import Prelude hiding ( all, filter, lines, read, readFile, writeFile )---- darcs stuff-import ByteStringUtils( is_funky )-import Darcs.Repository ( Repository, slurp_pending )-import Darcs.Repository.Internal ( read_pending )-import Darcs.Patch ( RepoPatch, Prim, hunk, canonize, binary, apply-                   , sort_coalesceFL, addfile, rmfile, adddir, rmdir, invert)-import Darcs.Ordered ( FL(..), (+>+) )-import Darcs.Repository.Prefs ( filetype_function, FileType(..) )-import Darcs.IO-import Darcs.Sealed ( Sealed(Sealed), seal )-import Darcs.Patch( apply_to_filepaths )-import Darcs.Patch.Patchy ( Apply )-import Darcs.Patch.TouchesFiles ( choose_touching )-import Darcs.Patch.FileName ( fn2fp, FileName )--import qualified Data.ByteString.Lazy.Char8 as BL-import qualified Data.ByteString.Char8 as BS-import Control.Monad.State.Strict-import System.Directory( removeFile, doesFileExist )-import Data.Maybe-import Data.List( union )--import Darcs.Arguments ( DarcsFlag( LookForAdds, IgnoreTimes ) )-import Darcs.RepoPath ( SubPath, sp2fn )--import Text.Regex( matchRegex )-import Darcs.Repository.Prefs( boring_regexps )--import Storage.Hashed-import Storage.Hashed.Tree-import qualified Storage.Hashed.Index as I-import Storage.Hashed.AnchoredPath-import Storage.Hashed.Darcs( darcsFormatHash, darcsTreeHash )-import Storage.Hashed.Monad-    ( virtualTreeIO, hashedTreeIO, plainTreeIO-    , unlink, rename, createDirectory, writeFile-    , readFile -- ratify readFile: haskell_policy je natvrdlá-    , cwd, tree, TreeIO )-import Storage.Hashed--floatFn :: FileName -> AnchoredPath-floatFn = floatPath . fn2fp--instance ReadableDirectory TreeIO where-    mDoesDirectoryExist d = gets (\x -> isJust $ findTree (tree x) (floatFn d))-    mDoesFileExist f = gets (\x -> isJust $ findFile (tree x) (floatFn f))-    mInCurrentDirectory d action = do -- TODO bracket?-      wd <- gets cwd-      modify (\x -> x { cwd = floatFn d })-      x <- action-      modify (\x' -> x' { cwd = wd })-      return x-    mGetDirectoryContents = error "get dir contents"-    mReadFilePS p = do x <- readFile (floatFn p) -- ratify readFile: ...-                       return $ BS.concat (BL.toChunks x)--instance WriteableDirectory TreeIO where-    mWithCurrentDirectory = mInCurrentDirectory-    mSetFileExecutable _ _ = return ()-    mWriteFilePS p ps = writeFile -- ratify readFile: haskell_policy is stupid.-          (floatFn p) (BL.fromChunks [ps])-    mCreateDirectory p = createDirectory (floatFn p)-    mRename from to = rename (floatFn from) (floatFn to)-    mRemoveDirectory = unlink . floatFn-    mRemoveFile = unlink . floatFn--treeDiff :: (FilePath -> FileType) -> Tree -> Tree -> IO (FL Prim C(x y))-#ifdef GADT_WITNESSES-treeDiff = undefined -- Sigh.-#else-treeDiff ft t1 t2 = do-  (from, to) <- diffTrees t1 t2-  diffs <- sequence $ zipTrees diff from to-  return $ foldr (+>+) NilFL diffs-    where diff :: AnchoredPath -> Maybe TreeItem -> Maybe TreeItem-               -> IO (FL Prim)-          diff _ (Just (SubTree _)) (Just (SubTree _)) = return NilFL-          diff p (Just (SubTree _)) Nothing =-              return $ rmdir (anchorPath "" p) :>: NilFL-          diff p Nothing (Just (SubTree _)) =-              return $ adddir (anchorPath "" p) :>: NilFL-          diff p Nothing b'@(Just (File _)) =-              do diff' <- diff p (Just (File emptyBlob)) b'-                 return $ addfile (anchorPath "" p) :>: diff'-          diff p a'@(Just (File _)) Nothing =-              do diff' <- diff p a' (Just (File emptyBlob))-                 return $ diff' +>+ (rmfile (anchorPath "" p) :>: NilFL)-          diff p (Just (File a')) (Just (File b')) =-              do a <- read a'-                 b <- read b'-                 let path = anchorPath "" p-                 case ft path of-                   TextFile | no_bin a && no_bin b ->-                                return $ text_diff path a b-                   _ -> return $ if a /= b-                                    then binary path (strict a) (strict b) :>: NilFL-                                    else NilFL-          diff p _ _ = fail $ "Missing case at path " ++ show p-          text_diff p a b-              | BL.null a && BL.null b = NilFL-              | BL.null a = diff_from_empty p b-              | BL.null b = diff_to_empty p a-              | otherwise = line_diff p (lines a) (lines b)-          line_diff p a b = canonize (hunk p 1 a b)-          diff_to_empty p x | BL.last x == '\n' = line_diff p (init $ lines x) []-                            | otherwise = line_diff p (lines x) [BS.empty]-          diff_from_empty p x = invert (diff_to_empty p x)-          no_bin = not . is_funky . strict . BL.take 4096-          lines = map strict . BL.split '\n'-          strict = BS.concat . BL.toChunks-#endif--readRecorded :: (RepoPatch p) => Repository p C(r u t) -> IO Tree-readRecorded _ = readDarcsPristine "."--readRecordedAndPending :: (RepoPatch p) => Repository p C(r u t) -> IO Tree-readRecordedAndPending repo = do-  pristine <- readRecorded repo-  Sealed pending <- pendingChanges repo []-  applyToTree pending pristine--pendingChanges :: (RepoPatch p) => Repository p C(r u t)-               -> [SubPath] -> IO (Sealed (FL Prim C(r)))-pendingChanges repo paths = do-  slurp_pending repo -- XXX: only here to get us the "pending conflicts" check-                     -- that I don't know yet how to implement properly-  Sealed pending <- read_pending repo-  let files = map (fn2fp . sp2fn) paths-      pre_files = apply_to_filepaths (invert pending) files-      relevant = case paths of-                   [] -> seal pending-                   _ -> choose_touching pre_files pending-  return relevant--applyToTree :: (Apply p) => p C(x y) -> Tree -> IO Tree-applyToTree patch t = snd `fmap` virtualTreeIO (apply [] patch) t--unrecordedChanges :: (RepoPatch p) => [DarcsFlag] -> Repository p C(r u t)-                  -> [SubPath] -> IO (FL Prim C(r y))-unrecordedChanges opts repo paths = do-  pristine <- readDarcsPristine "."-  Sealed pending <- pendingChanges repo paths-  (_, current') <- virtualTreeIO (apply [] pending) pristine-  relevant <- restrictSubpaths repo paths-  nonboring <- restrictBoring--  let current = relevant current'-  working <- case (LookForAdds `elem` opts, IgnoreTimes `elem` opts) of-               (False, False) -> do-                 all <- readIndex repo-                 expand (relevant all)-               (False, True) -> do-                 guide <- expand current-                 all <- readPlainTree "."-                 return $ relevant $ (restrict guide) all-               -- TODO (True, False) could use a more efficient implementation...-               (True, _) -> do-                 all <- readPlainTree "."-                 return $ relevant $ nonboring all--  ft <- filetype_function-  diff <- treeDiff ft current working-  return $ sort_coalesceFL (pending +>+ diff)--applyToTentativePristine :: (Apply p) => t -> p C(x y) -> IO ()-applyToTentativePristine _ patches =-    do pristine <- readDarcsPristine "."-       (_, t) <- hashedTreeIO (apply [] patches)-                 pristine "_darcs/pristine.hashed"-       BS.writeFile "_darcs/tentative_pristine" $-         BS.concat [BS.pack "pristine:"-                   , darcsFormatHash (fromJust $ treeHash t)]--applyToWorking :: (RepoPatch p) => Repository p C(r u t)-               -> Sealed (FL Prim C(u)) -> IO Tree-applyToWorking repo (Sealed patches) =-    do working <- readIndex repo-       snd `fmap` plainTreeIO (apply [] patches) working "."--filter_paths :: [AnchoredPath] -> AnchoredPath -> t -> Bool-filter_paths files =-    \p _ -> any (\x -> x `isPrefix` p || p `isPrefix` x) files--restrict_paths :: [AnchoredPath] -> Tree -> Tree-restrict_paths files = if null files-                          then id-                          else filter $ filter_paths files--restrict_subpaths :: [SubPath] -> Tree -> Tree-restrict_subpaths = restrict_paths . map (floatPath . fn2fp . sp2fn)--restrictSubpaths :: (RepoPatch p) => Repository p C(r u t) -> [SubPath] -> IO (Tree -> Tree)-restrictSubpaths repo subpaths = do-  Sealed pending <- read_pending repo-  let paths = map (fn2fp . sp2fn) subpaths-      paths' = paths `union` apply_to_filepaths pending paths-      anchored = map floatPath paths'-  return $ restrict_paths anchored--restrictBoring :: IO (Tree -> Tree)-restrictBoring = do-  boring <- boring_regexps-  let boring' (AnchoredPath (Name x:_)) _ | x == BS.pack "_darcs" = False-      boring' p _ = not $ any (\rx -> isJust $ matchRegex rx p') boring-          where p' = anchorPath "" p-  return $ filter boring'--readIndex :: (RepoPatch p) => Repository p C(r u t) -> IO Tree-readIndex repo = do-  invalid <- doesFileExist "_darcs/index_invalid"-  exist <- doesFileExist "_darcs/index"-  format_valid <- if exist-                     then I.indexFormatValid "_darcs/index"-                     else return True-  when (exist && not format_valid) $ removeFile "_darcs/index"-  if (not exist || invalid || not format_valid)-     then do pris <- readRecordedAndPending repo-             idx <- I.updateIndexFrom "_darcs/index" darcsTreeHash pris-             when invalid $ removeFile "_darcs/index_invalid"-             return idx-     else I.readIndex "_darcs/index" darcsTreeHash--invalidateIndex :: t -> IO ()-invalidateIndex _ = do-  BS.writeFile "_darcs/index_invalid" BS.empty
src/Darcs/Hopefully.hs view
@@ -35,8 +35,8 @@ import Darcs.Patch.Prim ( Effect(..), Conflict(..) ) import Darcs.Patch.Patchy ( Patchy, ReadPatch(..), Apply(..), Invert(..),                             ShowPatch(..), Commute(..) )-import Darcs.Ordered ( MyEq, unsafeCompare, (:>)(..), (:\/:)(..), (:/\:)(..) )-import Darcs.Sealed ( Sealed(Sealed), seal, mapSeal )+import Darcs.Witnesses.Ordered ( MyEq, unsafeCompare, (:>)(..), (:\/:)(..), (:/\:)(..) )+import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal, mapSeal ) import Darcs.Utils ( prettyException )  -- | @'Hopefully' p C@ @(x y)@ is @'Either' String (p C@ @(x y))@ in a@@ -73,7 +73,7 @@ piap :: PatchInfo -> Named p C(a b) -> PatchInfoAnd p C(a b) piap i p = PIAP i (Hopefully $ Actually p) --- | @n2pia@ creates a PatchInfoAnd represeting a @Named@ patch.+-- | @n2pia@ creates a PatchInfoAnd representing a @Named@ patch. n2pia :: Named p C(x y) -> PatchInfoAnd p C(x y) n2pia x = patch2patchinfo x `piap` x @@ -140,9 +140,9 @@     showPatch (PIAP n p) = case hopefully2either p of                            Right x -> showPatch x                            Left _ -> human_friendly n-    showContextPatch s (PIAP n p) = case hopefully2either p of-                                    Right x -> showContextPatch s x-                                    Left _ -> human_friendly n+    showContextPatch (PIAP n p) = case hopefully2either p of+                                    Right x -> showContextPatch x+                                    Left _ -> return $ human_friendly n     description (PIAP n _) = human_friendly n     summary (PIAP n p) = case hopefully2either p of                          Right x -> summary x@@ -154,9 +154,10 @@ instance Commute p => Commute (PatchInfoAnd p) where     commute (x :> y) = do y' :> x' <- commute (hopefully x :> hopefully y)                           return $ (info y `piap` y') :> (info x `piap` x')-    list_touched_files = list_touched_files . hopefully+    listTouchedFiles = listTouchedFiles . hopefully     merge (x :\/: y) = case merge (hopefully x :\/: hopefully y) of                        y' :/\: x' -> (info y `piap` y') :/\: (info x `piap` x')+    hunkMatches _ _ = error "hunkmatches not implemented for PatchInfoAnd"  instance Apply p => Apply (PatchInfoAnd p) where     apply opts p = apply opts $ hopefully p@@ -176,8 +177,8 @@     effectRL = effectRL . hopefully  instance Conflict p => Conflict (PatchInfoAnd p) where-    list_conflicted_files = list_conflicted_files . hopefully-    resolve_conflicts = resolve_conflicts . hopefully+    listConflictedFiles = listConflictedFiles . hopefully+    resolveConflicts = resolveConflicts . hopefully     commute_no_conflicts (x:>y) = do y':>x' <- commute_no_conflicts (hopefully x :> hopefully y)                                      return (info y `piap` y' :> info x `piap` x')     conflictedEffect = conflictedEffect . hopefully
src/Darcs/IO.hs view
@@ -33,7 +33,8 @@                         )  import ByteStringUtils ( linesPS, unlinesPS)-import qualified Data.ByteString as B (ByteString, empty, null, readFile)+import qualified Data.ByteString as B (ByteString, empty, null, readFile, concat)+import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Char8 as BC (unpack, pack)  import Darcs.Utils ( withCurrentDirectory, prettyException )@@ -43,6 +44,9 @@ import Darcs.Lock ( writeBinFile, readBinFile, writeAtomicFilePS ) import Workaround ( setExecutable ) +import qualified Storage.Hashed.Monad as HSM+import Storage.Hashed.AnchoredPath( AnchoredPath, floatPath )+ class (Functor m, MonadPlus m) => ReadableDirectory m where     mDoesDirectoryExist :: FileName -> m Bool     mDoesFileExist :: FileName -> m Bool@@ -247,3 +251,23 @@  backup :: FileName -> IO () backup f = backupByRenaming $ fn2fp f++floatFn :: FileName -> AnchoredPath+floatFn = floatPath . fn2fp++instance (MonadPlus m, MonadError e m) => ReadableDirectory (HSM.TreeMonad m) where+    mDoesDirectoryExist d = HSM.directoryExists (floatFn d)+    mDoesFileExist f = HSM.fileExists (floatFn f)+    mInCurrentDirectory d action = HSM.withDirectory (floatFn d) action+    mGetDirectoryContents = error "get dir contents"+    mReadFilePS p = do x <- HSM.readFile (floatFn p)+                       return $ B.concat (BL.toChunks x)++instance (Functor m, MonadPlus m, MonadError e m) => WriteableDirectory (HSM.TreeMonad m) where+    mWithCurrentDirectory = mInCurrentDirectory+    mSetFileExecutable _ _ = return ()+    mWriteFilePS p ps = HSM.writeFile (floatFn p) (BL.fromChunks [ps])+    mCreateDirectory p = HSM.createDirectory (floatFn p)+    mRename from to = HSM.rename (floatFn from) (floatFn to)+    mRemoveDirectory = HSM.unlink . floatFn+    mRemoveFile = HSM.unlink . floatFn
src/Darcs/Lock.hs view
@@ -28,6 +28,7 @@               rm_recursive, removeFileMayNotExist,               canonFilename, maybeRelink,               world_readable_temp, tempdir_loc,+              editText,               environmentHelpTmpdir, environmentHelpKeepTmpdir             ) where @@ -48,7 +49,7 @@                  ) import System.FilePath.Posix ( splitDirectories ) import Workaround ( renameFile )-import Darcs.Utils ( withCurrentDirectory, maybeGetEnv, firstJustIO )+import Darcs.Utils ( withCurrentDirectory, maybeGetEnv, firstJustIO, run_editor ) import Control.Monad ( unless, when )  import Darcs.URL ( is_relative )@@ -57,7 +58,7 @@                         getCurrentDirectory, setCurrentDirectory )  import ByteStringUtils ( gzWriteFilePSs)-import qualified Data.ByteString as B (null, readFile, hPut, ByteString)+import qualified Data.ByteString as B (null, readFile, writeFile, hPut, ByteString) import qualified Data.ByteString.Char8 as BC (unpack)  import Darcs.SignalHandler ( withSignalsBlocked )@@ -272,13 +273,18 @@           wrt 100 = fail $ "Failure creating temp named "++f           wrt n = let f_new = f++"-"++show n                   in do ok <- takeFile f_new-                        if ok then do atexit $ removeFileMayNotExist f_new-                                      return f_new+                        if ok then return f_new                               else wrt (n+1)  withNamedTemp :: String -> (String -> IO a) -> IO a withNamedTemp n = bracket get_empty_file removeFileMayNotExist     where get_empty_file = world_readable_temp n++editText :: String -> B.ByteString -> IO B.ByteString+editText desc txt = withNamedTemp desc $ \f -> do+  B.writeFile f txt+  run_editor f+  B.readFile f  readBinFile :: FilePathLike p => p -> IO String readBinFile = fmap BC.unpack . B.readFile . toFilePath
src/Darcs/Match.lhs view
@@ -21,19 +21,20 @@  #include "gadts.h" -module Darcs.Match ( match_first_patchset, match_second_patchset,-               match_patch,-               match_a_patch, match_a_patchread,-               get_first_match, get_nonrange_match,-               get_partial_first_match, get_partial_second_match,-               get_partial_nonrange_match,-               first_match, second_match, have_nonrange_match,-               have_patchset_match, get_one_patchset,-               checkMatchSyntax,+module Darcs.Match ( matchFirstPatchset, matchSecondPatchset,+               matchPatch,+               matchAPatch, matchAPatchread,+               getFirstMatch, getNonrangeMatch,+               getPartialFirstMatch, getPartialSecondMatch,+               getPartialNonrangeMatch,+               firstMatch, secondMatch, haveNonrangeMatch,+               havePatchsetMatch, getOnePatchset,+               checkMatchSyntax, applyInvToMatcher, nonrangeMatcher,+               InclusiveOrExclusive(..), matchExists              ) where  import Text.Regex ( mkRegex, matchRegex )-import Control.Monad ( when )+import Control.Monad ( when, unless ) import Data.Maybe ( isJust )  import Darcs.Hopefully ( PatchInfoAnd, info, piap,@@ -44,17 +45,16 @@                     slurp_recorded, createPristineDirectoryTree ) import Darcs.Repository.ApplyPatches ( apply_patches ) import Darcs.Patch.Depends ( get_patches_in_tag, get_patches_beyond_tag )-import Darcs.Ordered ( RL(..), concatRL, consRLSealed )+import Darcs.Witnesses.Ordered ( RL(..), concatRL, consRLSealed )  import ByteStringUtils ( mmapFilePS ) import qualified Data.ByteString as B (ByteString)  import Darcs.Flags ( DarcsFlag( OnePatch, SeveralPatch, Context,-                                StoreInMemory,                                AfterPatch, UpToPatch, LastN, PatchIndexRange,                                OneTag, AfterTag, UpToTag,                                OnePattern, SeveralPattern,-                               AfterPattern, UpToPattern ) )+                               AfterPattern, UpToPattern ), willStoreInMemory ) import Darcs.Patch.Bundle ( scan_context ) import Darcs.Patch.Match ( Matcher, MatchFun, match_pattern, apply_matcher, make_matcher, parseMatch ) import Darcs.Patch.MatchData ( PatchMatch )@@ -63,8 +63,8 @@ import Darcs.RepoPath ( toFilePath ) import Darcs.IO ( WriteableDirectory(..), ReadableDirectory(..) ) import Darcs.SlurpDirectory ( SlurpMonad, writeSlurpy, withSlurpy )-import Darcs.Patch.FileName ( FileName, super_name, norm_path, (///) )-import Darcs.Sealed ( FlippedSeal(..), Sealed2(..),+import Darcs.Patch.FileName ( FileName, superName, norm_path, (///) )+import Darcs.Witnesses.Sealed ( FlippedSeal(..), Sealed2(..),                       seal, flipSeal, seal2, unsealFlipped, unseal2, unseal ) #include "impossible.h" \end{code}@@ -107,96 +107,96 @@ \begin{code} data InclusiveOrExclusive = Inclusive | Exclusive deriving Eq --- | @have_nonrange_match flags@ tells whether there is a flag in+-- | @haveNonrangeMatch flags@ tells whether there is a flag in -- @flags@ which corresponds to a match that is "non-range". Thus,--- @--match@, @--patch@ and @--index@ make @have_nonrange_match@+-- @--match@, @--patch@ and @--index@ make @haveNonrangeMatch@ -- true, but not @--from-patch@ or @--to-patch@.-have_nonrange_match :: [DarcsFlag] -> Bool-have_nonrange_match fs = isJust (has_index_range fs) || isJust (nonrange_matcher fs::Maybe (Matcher Patch))+haveNonrangeMatch :: [DarcsFlag] -> Bool+haveNonrangeMatch fs = isJust (hasIndexRange fs) || isJust (nonrangeMatcher fs::Maybe (Matcher Patch)) --- | @have_patchset_match flags@ tells whether there is a "patchset+-- | @havePatchsetMatch flags@ tells whether there is a "patchset -- match" in the flag list. A patchset match is @--match@ or -- @--patch@, or @--context@, but not @--from-patch@ nor (!) -- @--index@.--- Question: Is it supposed not to be a subset of @have_nonrange_match@?-have_patchset_match :: [DarcsFlag] -> Bool-have_patchset_match fs = isJust (nonrange_matcher fs::Maybe (Matcher Patch)) || hasC fs+-- Question: Is it supposed not to be a subset of @haveNonrangeMatch@?+havePatchsetMatch :: [DarcsFlag] -> Bool+havePatchsetMatch fs = isJust (nonrangeMatcher fs::Maybe (Matcher Patch)) || hasC fs     where hasC [] = False           hasC (Context _:_) = True           hasC (_:xs) = hasC xs -get_nonrange_match :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> IO ()-get_nonrange_match r fs = withRecordedMatchSmart fs r (get_nonrange_match_s fs)+getNonrangeMatch :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> IO ()+getNonrangeMatch r fs = withRecordedMatchSmart fs r (getNonrangeMatchS fs) -get_partial_nonrange_match :: RepoPatch p => Repository p C(r u t)+getPartialNonrangeMatch :: RepoPatch p => Repository p C(r u t)                            -> [DarcsFlag] -> [FileName] -> IO ()-get_partial_nonrange_match r fs files =-    withRecordedMatchOnlySomeSmart fs r files (get_nonrange_match_s fs)+getPartialNonrangeMatch r fs files =+    withRecordedMatchOnlySomeSmart fs r files (getNonrangeMatchS fs) -get_nonrange_match_s :: (MatchMonad m p, RepoPatch p) =>+getNonrangeMatchS :: (MatchMonad m p, RepoPatch p) =>                         [DarcsFlag] -> PatchSet p C(x) -> m ()-get_nonrange_match_s fs repo =-    case nonrange_matcher fs of-        Just m -> if nonrange_matcher_is_tag fs-                        then get_tag_s m repo-                        else get_matcher_s Exclusive m repo-        Nothing -> fail "Pattern not specified in get_nonrange_match."+getNonrangeMatchS fs repo =+    case nonrangeMatcher fs of+        Just m -> if nonrangeMatcherIsTag fs+                        then getTagS m repo+                        else getMatcherS Exclusive m repo+        Nothing -> fail "Pattern not specified in getNonrangeMatch." --- | @first_match fs@ tells whether @fs@ implies a "first match", that+-- | @firstMatch fs@ tells whether @fs@ implies a "first match", that -- is if we match against patches from a point in the past on, rather -- than against all patches since the creation of the repository.-first_match :: [DarcsFlag] -> Bool-first_match fs = isJust (has_lastn fs)-                 || isJust (first_matcher fs::Maybe (Matcher Patch))-                 || isJust (has_index_range fs)+firstMatch :: [DarcsFlag] -> Bool+firstMatch fs = isJust (hasLastn fs)+                 || isJust (firstMatcher fs::Maybe (Matcher Patch))+                 || isJust (hasIndexRange fs) -get_first_match :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> IO ()-get_first_match r fs = withRecordedMatchSmart fs r (get_first_match_s fs)+getFirstMatch :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> IO ()+getFirstMatch r fs = withRecordedMatchSmart fs r (getFirstMatchS fs) -get_partial_first_match :: RepoPatch p => Repository p C(r u t)+getPartialFirstMatch :: RepoPatch p => Repository p C(r u t)                         -> [DarcsFlag] -> [FileName] -> IO ()-get_partial_first_match r fs files =-    withRecordedMatchOnlySomeSmart fs r files (get_first_match_s fs)+getPartialFirstMatch r fs files =+    withRecordedMatchOnlySomeSmart fs r files (getFirstMatchS fs) -get_first_match_s :: (MatchMonad m p, RepoPatch p) =>+getFirstMatchS :: (MatchMonad m p, RepoPatch p) =>                      [DarcsFlag] -> PatchSet p C(x) -> m ()-get_first_match_s fs repo =-    case has_lastn fs of+getFirstMatchS fs repo =+    case hasLastn fs of     Just n -> applyInvRL `unsealFlipped` (safetake n $ concatRL repo)-    Nothing -> case first_matcher fs of-               Nothing -> fail "Pattern not specified in get_first_match."-               Just m -> if first_matcher_is_tag fs-                         then get_tag_s m repo-                         else get_matcher_s Inclusive m repo+    Nothing -> case firstMatcher fs of+               Nothing -> fail "Pattern not specified in getFirstMatch."+               Just m -> if firstMatcherIsTag fs+                         then getTagS m repo+                         else getMatcherS Inclusive m repo  --- | @second_match fs@ tells whether @fs@ implies a "second match", that+-- | @secondMatch fs@ tells whether @fs@ implies a "second match", that -- is if we match against patches up to a point in the past on, rather -- than against all patches until now.-second_match :: [DarcsFlag] -> Bool-second_match fs = isJust (second_matcher fs::Maybe (Matcher Patch)) || isJust (has_index_range fs)+secondMatch :: [DarcsFlag] -> Bool+secondMatch fs = isJust (secondMatcher fs::Maybe (Matcher Patch)) || isJust (hasIndexRange fs) -get_partial_second_match :: RepoPatch p => Repository p C(r u t)+getPartialSecondMatch :: RepoPatch p => Repository p C(r u t)                         -> [DarcsFlag] -> [FileName] -> IO ()-get_partial_second_match r fs files =+getPartialSecondMatch r fs files =     withRecordedMatchOnlySomeSmart fs r files $ \repo ->-    case second_matcher fs of+    case secondMatcher fs of     Nothing -> fail "Two patterns not specified in get_second_match."-    Just m -> if second_matcher_is_tag fs-              then get_tag_s m repo-              else get_matcher_s Exclusive m repo+    Just m -> if secondMatcherIsTag fs+              then getTagS m repo+              else getMatcherS Exclusive m repo  checkMatchSyntax :: [DarcsFlag] -> IO () checkMatchSyntax opts = do- case get_match_pattern opts of+ case getMatchPattern opts of   Nothing -> return ()   Just p  -> either fail (const $ return ()) $ (parseMatch p::Either String (MatchFun Patch)) -get_match_pattern :: [DarcsFlag] -> Maybe PatchMatch-get_match_pattern [] = Nothing-get_match_pattern (OnePattern m:_) = Just m-get_match_pattern (SeveralPattern m:_) = Just m-get_match_pattern (_:fs) = get_match_pattern fs+getMatchPattern :: [DarcsFlag] -> Maybe PatchMatch+getMatchPattern [] = Nothing+getMatchPattern (OnePattern m:_) = Just m+getMatchPattern (SeveralPattern m:_) = Just m+getMatchPattern (_:fs) = getMatchPattern fs  tagmatch :: String -> Matcher p tagmatch r = make_matcher ("tag-name "++r) tm@@ -219,138 +219,138 @@ -- subset. This subset is formed by the patches in a given interval -- which match a given criterion. If we represent time going left to -- right (which means the 'PatchSet' is written right to left), then--- we have (up to) three 'Matcher's: the 'nonrange_matcher' is the+-- we have (up to) three 'Matcher's: the 'nonrangeMatcher' is the -- criterion we use to select among patches in the interval, the--- 'first_matcher' is the left bound of the interval, and the+-- 'firstMatcher' is the left bound of the interval, and the -- 'last_matcher' is the right bound. Each of these matchers can be -- present or not according to the options. strictJust :: a -> Maybe a strictJust x = Just $! x --- | @nonrange_matcher@ is the criterion that is used to match against+-- | @nonrangeMatcher@ is the criterion that is used to match against -- patches in the interval. It is 'Just m' when the @--patch@, @--match@, -- @--tag@ options are passed (or their plural variants).-nonrange_matcher :: Patchy p => [DarcsFlag] -> Maybe (Matcher p)-nonrange_matcher [] = Nothing-nonrange_matcher (OnePattern m:_) = strictJust $ match_pattern m-nonrange_matcher (OneTag t:_) = strictJust $ tagmatch t-nonrange_matcher (OnePatch p:_) = strictJust $ mymatch p-nonrange_matcher (SeveralPattern m:_) = strictJust $ match_pattern m-nonrange_matcher (SeveralPatch p:_) = strictJust $ mymatch p-nonrange_matcher (_:fs) = nonrange_matcher fs+nonrangeMatcher :: Patchy p => [DarcsFlag] -> Maybe (Matcher p)+nonrangeMatcher [] = Nothing+nonrangeMatcher (OnePattern m:_) = strictJust $ match_pattern m+nonrangeMatcher (OneTag t:_) = strictJust $ tagmatch t+nonrangeMatcher (OnePatch p:_) = strictJust $ mymatch p+nonrangeMatcher (SeveralPattern m:_) = strictJust $ match_pattern m+nonrangeMatcher (SeveralPatch p:_) = strictJust $ mymatch p+nonrangeMatcher (_:fs) = nonrangeMatcher fs --- | @nonrange_matcher_is_tag@ returns true if the matching option was+-- | @nonrangeMatcherIsTag@ returns true if the matching option was -- '--tag'-nonrange_matcher_is_tag :: [DarcsFlag] -> Bool-nonrange_matcher_is_tag [] = False-nonrange_matcher_is_tag (OneTag _:_) = True-nonrange_matcher_is_tag (_:fs) = nonrange_matcher_is_tag fs+nonrangeMatcherIsTag :: [DarcsFlag] -> Bool+nonrangeMatcherIsTag [] = False+nonrangeMatcherIsTag (OneTag _:_) = True+nonrangeMatcherIsTag (_:fs) = nonrangeMatcherIsTag fs --- | @first_matcher@ returns the left bound of the matched interval.+-- | @firstMatcher@ returns the left bound of the matched interval. -- This left bound is also specified when we use the singular versions--- of @--patch@, @--match@ and @--tag@. Otherwise, @first_matcher@+-- of @--patch@, @--match@ and @--tag@. Otherwise, @firstMatcher@ -- returns @Nothing@.-first_matcher :: Patchy p => [DarcsFlag] -> Maybe (Matcher p)-first_matcher [] = Nothing-first_matcher (OnePattern m:_) = strictJust $ match_pattern m-first_matcher (AfterPattern m:_) = strictJust $ match_pattern m-first_matcher (AfterTag t:_) = strictJust $ tagmatch t-first_matcher (OnePatch p:_) = strictJust $ mymatch p-first_matcher (AfterPatch p:_) = strictJust $ mymatch p-first_matcher (_:fs) = first_matcher fs+firstMatcher :: Patchy p => [DarcsFlag] -> Maybe (Matcher p)+firstMatcher [] = Nothing+firstMatcher (OnePattern m:_) = strictJust $ match_pattern m+firstMatcher (AfterPattern m:_) = strictJust $ match_pattern m+firstMatcher (AfterTag t:_) = strictJust $ tagmatch t+firstMatcher (OnePatch p:_) = strictJust $ mymatch p+firstMatcher (AfterPatch p:_) = strictJust $ mymatch p+firstMatcher (_:fs) = firstMatcher fs -first_matcher_is_tag :: [DarcsFlag] -> Bool-first_matcher_is_tag [] = False-first_matcher_is_tag (AfterTag _:_) = True-first_matcher_is_tag (_:fs) = first_matcher_is_tag fs+firstMatcherIsTag :: [DarcsFlag] -> Bool+firstMatcherIsTag [] = False+firstMatcherIsTag (AfterTag _:_) = True+firstMatcherIsTag (_:fs) = firstMatcherIsTag fs -second_matcher :: Patchy p => [DarcsFlag] -> Maybe (Matcher p)-second_matcher [] = Nothing-second_matcher (OnePattern m:_) = strictJust $ match_pattern m-second_matcher (UpToPattern m:_) = strictJust $ match_pattern m-second_matcher (OnePatch p:_) = strictJust $ mymatch p-second_matcher (UpToPatch p:_) = strictJust $ mymatch p-second_matcher (UpToTag t:_) = strictJust $ tagmatch t-second_matcher (_:fs) = second_matcher fs+secondMatcher :: Patchy p => [DarcsFlag] -> Maybe (Matcher p)+secondMatcher [] = Nothing+secondMatcher (OnePattern m:_) = strictJust $ match_pattern m+secondMatcher (UpToPattern m:_) = strictJust $ match_pattern m+secondMatcher (OnePatch p:_) = strictJust $ mymatch p+secondMatcher (UpToPatch p:_) = strictJust $ mymatch p+secondMatcher (UpToTag t:_) = strictJust $ tagmatch t+secondMatcher (_:fs) = secondMatcher fs -second_matcher_is_tag :: [DarcsFlag] -> Bool-second_matcher_is_tag [] = False-second_matcher_is_tag (UpToTag _:_) = True-second_matcher_is_tag (_:fs) = second_matcher_is_tag fs+secondMatcherIsTag :: [DarcsFlag] -> Bool+secondMatcherIsTag [] = False+secondMatcherIsTag (UpToTag _:_) = True+secondMatcherIsTag (_:fs) = secondMatcherIsTag fs --- | @match_a_patchread fs p@ tells whether @p@ matches the matchers in+-- | @matchAPatchread fs p@ tells whether @p@ matches the matchers in -- the flags listed in @fs@.-match_a_patchread :: Patchy p => [DarcsFlag] -> PatchInfoAnd p C(x y) -> Bool-match_a_patchread fs = case nonrange_matcher fs of+matchAPatchread :: Patchy p => [DarcsFlag] -> PatchInfoAnd p C(x y) -> Bool+matchAPatchread fs = case nonrangeMatcher fs of                        Nothing -> const True                        Just m -> apply_matcher m --- | @match_a_patch fs p@ tells whether @p@ matches the matchers in+-- | @matchAPatch fs p@ tells whether @p@ matches the matchers in -- the flags @fs@-match_a_patch :: Patchy p => [DarcsFlag] -> Named p C(x y) -> Bool-match_a_patch fs p =-    case nonrange_matcher fs of+matchAPatch :: Patchy p => [DarcsFlag] -> Named p C(x y) -> Bool+matchAPatch fs p =+    case nonrangeMatcher fs of     Nothing -> True     Just m -> apply_matcher m (patch2patchinfo p `piap` p) -match_patch :: RepoPatch p => [DarcsFlag] -> PatchSet p C(x) -> Sealed2 (Named p)-match_patch fs ps =-    case has_index_range fs of+matchPatch :: RepoPatch p => [DarcsFlag] -> PatchSet p C(x) -> Sealed2 (Named p)+matchPatch fs ps =+    case hasIndexRange fs of     Just (a,a') | a == a' -> case (unseal myhead) $ dropn (a-1) ps of                              Just (Sealed2 p) -> seal2 $ hopefully p                              Nothing -> error "Patch out of range!"-                | otherwise -> bug ("Invalid index range match given to match_patch: "+++                | otherwise -> bug ("Invalid index range match given to matchPatch: "++                                     show (PatchIndexRange a a'))                 where myhead :: PatchSet p C(x) -> Maybe (Sealed2 (PatchInfoAnd p))                       myhead (NilRL:<:x) = myhead x                       myhead ((x:<:_):<:_) = Just $ seal2 x                       myhead NilRL = Nothing-    Nothing -> case nonrange_matcher fs of-                    Nothing -> bug "Couldn't match_patch"-                    Just m -> find_a_patch m ps+    Nothing -> case nonrangeMatcher fs of+                    Nothing -> bug "Couldn't matchPatch"+                    Just m -> findAPatch m ps -get_one_patchset :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> IO (SealedPatchSet p)-get_one_patchset repository fs =-    case nonrange_matcher fs of+getOnePatchset :: RepoPatch p => Repository p C(r u t) -> [DarcsFlag] -> IO (SealedPatchSet p)+getOnePatchset repository fs =+    case nonrangeMatcher fs of         Just m -> do ps <- read_repo repository-                     if nonrange_matcher_is_tag fs-                        then return $ get_matching_tag m ps-                        else return $ match_a_patchset m ps+                     if nonrangeMatcherIsTag fs+                        then return $ getMatchingTag m ps+                        else return $ matchAPatchset m ps         Nothing -> (seal . scan_context) `fmap` mmapFilePS (toFilePath $ context_f fs)     where context_f [] = bug "Couldn't match_nonrange_patchset"           context_f (Context f:_) = f           context_f (_:xs) = context_f xs --- | @has_lastn fs@ return the @--last@ argument in @fs@, if any.-has_lastn :: [DarcsFlag] -> Maybe Int-has_lastn [] = Nothing-has_lastn (LastN (-1):_) = error "--last requires a positive integer argument."-has_lastn (LastN n:_) = Just n-has_lastn (_:fs) = has_lastn fs+-- | @hasLastn fs@ return the @--last@ argument in @fs@, if any.+hasLastn :: [DarcsFlag] -> Maybe Int+hasLastn [] = Nothing+hasLastn (LastN (-1):_) = error "--last requires a positive integer argument."+hasLastn (LastN n:_) = Just n+hasLastn (_:fs) = hasLastn fs -has_index_range :: [DarcsFlag] -> Maybe (Int,Int)-has_index_range [] = Nothing-has_index_range (PatchIndexRange x y:_) = Just (x,y)-has_index_range (_:fs) = has_index_range fs+hasIndexRange :: [DarcsFlag] -> Maybe (Int,Int)+hasIndexRange [] = Nothing+hasIndexRange (PatchIndexRange x y:_) = Just (x,y)+hasIndexRange (_:fs) = hasIndexRange fs --- | @match_first_patchset fs ps@ returns the part of @ps@ before its+-- | @matchFirstPatchset fs ps@ returns the part of @ps@ before its -- first matcher, ie the one that comes first dependencywise. Hence,--- patches in @match_first_patchset fs ps@ are the ones we don't want.+-- patches in @matchFirstPatchset fs ps@ are the ones we don't want. -- -- Question: are they really? Florent-match_first_patchset :: RepoPatch p => [DarcsFlag] -> PatchSet p C(x) -> SealedPatchSet p-match_first_patchset fs patchset =-    case has_lastn fs of+matchFirstPatchset :: RepoPatch p => [DarcsFlag] -> PatchSet p C(x) -> SealedPatchSet p+matchFirstPatchset fs patchset =+    case hasLastn fs of     Just n -> dropn n patchset     Nothing ->-        case has_index_range fs of+        case hasIndexRange fs of         Just (_,b) -> dropn b patchset         Nothing ->-               case first_matcher fs of-               Nothing -> bug "Couldn't match_first_patchset"-               Just m -> unseal (dropn 1) $ if first_matcher_is_tag fs-                                            then get_matching_tag m patchset-                                            else match_a_patchset m patchset+               case firstMatcher fs of+               Nothing -> bug "Couldn't matchFirstPatchset"+               Just m -> unseal (dropn 1) $ if firstMatcherIsTag fs+                                            then getMatchingTag m patchset+                                            else matchAPatchset m patchset  -- | @dropn n ps@ drops the @n@ last patches from @ps@. dropn :: Int -> PatchSet p C(x) -> SealedPatchSet p@@ -359,67 +359,67 @@ dropn _ NilRL = seal $ NilRL:<:NilRL dropn n ((_:<:ps):<:xs) = dropn (n-1) $ ps:<:xs --- | @match_second_patchset fs ps@ returns the part of @ps@ before its+-- | @matchSecondPatchset fs ps@ returns the part of @ps@ before its -- second matcher, ie the one that comes last dependencywise.-match_second_patchset :: RepoPatch p => [DarcsFlag] -> PatchSet p C(x) -> SealedPatchSet p-match_second_patchset fs ps =-  case has_index_range fs of+matchSecondPatchset :: RepoPatch p => [DarcsFlag] -> PatchSet p C(x) -> SealedPatchSet p+matchSecondPatchset fs ps =+  case hasIndexRange fs of   Just (a,_) -> dropn (a-1) ps   Nothing ->-    case second_matcher fs of-    Nothing -> bug "Couldn't match_second_patchset"-    Just m -> if second_matcher_is_tag fs-              then get_matching_tag m ps-              else match_a_patchset m ps+    case secondMatcher fs of+    Nothing -> bug "Couldn't matchSecondPatchset"+    Just m -> if secondMatcherIsTag fs+              then getMatchingTag m ps+              else matchAPatchset m ps --- | @find_a_patch m ps@ returns the last patch in @ps@ matching @m@, and+-- | @findAPatch m ps@ returns the last patch in @ps@ matching @m@, and -- calls 'error' if there is none.-find_a_patch :: RepoPatch p => Matcher p -> PatchSet p C(x) -> Sealed2 (Named p)-find_a_patch m NilRL = error $ "Couldn't find patch matching " ++ show m-find_a_patch m (NilRL:<:xs) = find_a_patch m xs-find_a_patch m ((p:<:ps):<:xs) | apply_matcher m p = seal2 $ hopefully p-                               | otherwise = find_a_patch m (ps:<:xs)+findAPatch :: RepoPatch p => Matcher p -> PatchSet p C(x) -> Sealed2 (Named p)+findAPatch m NilRL = error $ "Couldn't find patch matching " ++ show m+findAPatch m (NilRL:<:xs) = findAPatch m xs+findAPatch m ((p:<:ps):<:xs) | apply_matcher m p = seal2 $ hopefully p+                               | otherwise = findAPatch m (ps:<:xs) --- | @match_a_patchset m ps@ returns a (the largest?) subset of @ps@+-- | @matchAPatchset m ps@ returns a (the largest?) subset of @ps@ -- ending in patch which matches @m@. Calls 'error' if there is none.-match_a_patchset :: RepoPatch p => Matcher p -> PatchSet p C(x) -> SealedPatchSet p-match_a_patchset m NilRL = error $ "Couldn't find patch matching " ++ show m-match_a_patchset m (NilRL:<:xs) = match_a_patchset m xs-match_a_patchset m ((p:<:ps):<:xs) | apply_matcher m p = seal ((p:<:ps):<:xs)-                                   | otherwise = match_a_patchset m (ps:<:xs)+matchAPatchset :: RepoPatch p => Matcher p -> PatchSet p C(x) -> SealedPatchSet p+matchAPatchset m NilRL = error $ "Couldn't find patch matching " ++ show m+matchAPatchset m (NilRL:<:xs) = matchAPatchset m xs+matchAPatchset m ((p:<:ps):<:xs) | apply_matcher m p = seal ((p:<:ps):<:xs)+                                   | otherwise = matchAPatchset m (ps:<:xs) --- | @get_matching_tag m ps@, where @m@ is a 'Matcher' which matches tags+-- | @getMatchingTag m ps@, where @m@ is a 'Matcher' which matches tags -- returns a 'SealedPatchSet' containing all patches in the last tag which -- matches @m@. Last tag means the most recent tag in repository order, -- i.e. the last one you'd see if you ran darcs changes -t @m@. Calls -- 'error' if there is no matching tag.-get_matching_tag :: RepoPatch p => Matcher p -> PatchSet p C(x) -> SealedPatchSet p-get_matching_tag m NilRL = error $ "Couldn't find a tag matching " ++ show m-get_matching_tag m (NilRL:<:xs) = get_matching_tag m xs-get_matching_tag m xxx@((p:<:ps):<:xs)+getMatchingTag :: RepoPatch p => Matcher p -> PatchSet p C(x) -> SealedPatchSet p+getMatchingTag m NilRL = error $ "Couldn't find a tag matching " ++ show m+getMatchingTag m (NilRL:<:xs) = getMatchingTag m xs+getMatchingTag m xxx@((p:<:ps):<:xs)     | apply_matcher m p = get_patches_in_tag (info p) xxx-    | otherwise = get_matching_tag m (ps:<:xs)+    | otherwise = getMatchingTag m (ps:<:xs) --- | @match_exists m ps@ tells whether there is a patch matching+-- | @matchExists m ps@ tells whether there is a patch matching -- @m@ in @ps@-match_exists :: Matcher p -> PatchSet p C(x) -> Bool-match_exists _ NilRL = False-match_exists m (NilRL:<:xs) = match_exists m xs-match_exists m ((p:<:ps):<:xs) | apply_matcher m $ p = True-                               | otherwise = match_exists m (ps:<:xs)+matchExists :: Matcher p -> PatchSet p C(x) -> Bool+matchExists _ NilRL = False+matchExists m (NilRL:<:xs) = matchExists m xs+matchExists m ((p:<:ps):<:xs) | apply_matcher m $ p = True+                               | otherwise = matchExists m (ps:<:xs) -apply_inv_to_matcher :: (RepoPatch p, WriteableDirectory m) => InclusiveOrExclusive -> Matcher p -> PatchSet p C(x) -> m ()-apply_inv_to_matcher _ _ NilRL = impossible-apply_inv_to_matcher ioe m (NilRL:<:xs) = apply_inv_to_matcher ioe m xs-apply_inv_to_matcher ioe m ((p:<:ps):<:xs)-    | apply_matcher m p = when (ioe == Inclusive) (apply_invp p)-    | otherwise = apply_invp p >> apply_inv_to_matcher ioe m (ps:<:xs)+applyInvToMatcher :: (RepoPatch p, WriteableDirectory m) => InclusiveOrExclusive -> Matcher p -> PatchSet p C(x) -> m ()+applyInvToMatcher _ _ NilRL = impossible+applyInvToMatcher ioe m (NilRL:<:xs) = applyInvToMatcher ioe m xs+applyInvToMatcher ioe m ((p:<:ps):<:xs)+    | apply_matcher m p = when (ioe == Inclusive) (applyInvp p)+    | otherwise = applyInvp p >> applyInvToMatcher ioe m (ps:<:xs) --- | @maybe_read_file@ recursively gets the contents of all files+-- | @maybeReadFile@ recursively gets the contents of all files -- in a directory, or just the contents of a file if called on a -- simple file.-maybe_read_file :: ReadableDirectory m => FileName -> m ([(FileName, B.ByteString)])-maybe_read_file file = do+maybeReadFile :: ReadableDirectory m => FileName -> m ([(FileName, B.ByteString)])+maybeReadFile file = do     d <- mDoesDirectoryExist file     if d       then do@@ -434,31 +434,30 @@            else return []   where maybe_read_files [] =  return []         maybe_read_files (f:fs) = do-                      x <- maybe_read_file f+                      x <- maybeReadFile f                       y <- maybe_read_files fs                       return $ concat [x,y] -get_matcher_s :: (MatchMonad m p, RepoPatch p) =>+getMatcherS :: (MatchMonad m p, RepoPatch p) =>                  InclusiveOrExclusive -> Matcher p -> PatchSet p C(x) -> m ()-get_matcher_s ioe m repo =-    if match_exists m repo-    then apply_inv_to_matcher ioe m repo+getMatcherS ioe m repo =+    if matchExists m repo+    then applyInvToMatcher ioe m repo     else fail $ "Couldn't match pattern "++ show m -get_tag_s :: (MatchMonad m p, RepoPatch p) =>+getTagS :: (MatchMonad m p, RepoPatch p) =>              Matcher p -> PatchSet p C(x) -> m ()-get_tag_s match repo = do-    let pinfo = patch2patchinfo `unseal2` (find_a_patch match repo)+getTagS match repo = do+    let pinfo = patch2patchinfo `unseal2` (findAPatch match repo)     case get_patches_beyond_tag pinfo repo of-        FlippedSeal (extras:<:NilRL) -> applyInvRL $ extras-        _ -> impossible+        FlippedSeal extras -> applyInvRL extras --- | @apply_invp@ tries to get the patch that's in a 'PatchInfoAnd+-- | @applyInvp@ tries to get the patch that's in a 'PatchInfoAnd -- patch', and to apply its inverse. If we fail to fetch the patch -- (presumably in a partial repositiory), then we share our sorrow -- with the user.-apply_invp :: (Patchy p, WriteableDirectory m) => PatchInfoAnd p C(x y) -> m ()-apply_invp hp = apply [] (invert $ fromHopefully hp)+applyInvp :: (Patchy p, WriteableDirectory m) => PatchInfoAnd p C(x y) -> m ()+applyInvp hp = apply [] (invert $ fromHopefully hp)     where fromHopefully = conscientiously $ \e ->                      text "Sorry, partial repository problem.  Patch not available:"                      $$ e@@ -495,7 +494,7 @@     withRecordedMatchOnlySomeFiles r _ j = withRecordedMatch r j     applyInvRL :: RL (PatchInfoAnd p) C(x r) -> m ()     applyInvRL NilRL = return ()-    applyInvRL (p:<:ps) = apply_invp p >> applyInvRL ps+    applyInvRL (p:<:ps) = applyInvp p >> applyInvRL ps  withRecordedMatchIO :: RepoPatch p => Repository p C(r u t)                     -> (PatchSet p C(r) -> IO ()) -> IO ()@@ -513,8 +512,8 @@                        -> (forall m. MatchMonad m p => PatchSet p C(r) -> m ())                        -> IO () withRecordedMatchSmart opts r j =- do if StoreInMemory `elem` opts then withSM r j-                                 else withRecordedMatchIO r j+ do if willStoreInMemory opts then withSM r j+                              else withRecordedMatchIO r j     where withSM :: RepoPatch p => Repository p C(r u t)                  -> (PatchSet p C(r) -> SlurpMonad ()) -> IO ()           withSM = withRecordedMatch@@ -529,8 +528,8 @@                        -> IO () withRecordedMatchOnlySomeSmart opts r [] j = withRecordedMatchSmart opts r j withRecordedMatchOnlySomeSmart opts r files j =- do if StoreInMemory `elem` opts then withSM r files j-                                 else withIO r files j+ do if willStoreInMemory opts then withSM r files j+                              else withIO r files j     where withSM :: RepoPatch p => Repository p C(r u t) -> [FileName]                  -> (PatchSet p C(r) -> SlurpMonad ()) -> IO ()           withSM = withRecordedMatchOnlySomeFiles@@ -553,16 +552,15 @@     withRecordedMatchOnlySomeFiles r fs job =         do ps <- read_repo r            s <- slurp_recorded r-           case withSlurpy s (job ps >> mapM maybe_read_file fs) of+           case withSlurpy s (job ps >> mapM maybeReadFile fs) of              Left err -> fail err              Right (_,fcs) -> mapM_ createAFile $ concat fcs-               where createAFile (p,c) = do ensureDirectories $ super_name p+               where createAFile (p,c) = do ensureDirectories $ superName p                                             mWriteFilePS p c                      ensureDirectories d =                          do isPar <- mDoesDirectoryExist d-                            if isPar-                              then return ()-                              else do ensureDirectories $ super_name d-                                      mCreateDirectory d+                            unless isPar $ do+                               ensureDirectories $ superName d+                               mCreateDirectory d  \end{code}
− src/Darcs/Ordered.hs
@@ -1,277 +0,0 @@--- Copyright (C) 2007 David Roundy------ This program is free software; you can redistribute it and/or modify--- it under the terms of the GNU General Public License as published by--- the Free Software Foundation; either version 2, or (at your option)--- any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; see the file COPYING.  If not, write to--- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,--- Boston, MA 02110-1301, USA.--{-# OPTIONS_GHC -cpp -fglasgow-exts #-}-{-# LANGUAGE CPP #-}--- , MagicHash, TypeOperators, GADTs #-}--#include "gadts.h"--module Darcs.Ordered ( EqCheck(..), isEq, (:>)(..), (:<)(..), (:\/:)(..), (:/\:)(..),-                             FL(..), RL(..),Proof(..),-#ifndef GADT_WITNESSES-                             unsafeUnFL, unsafeFL, unsafeRL, unsafeUnRL,-#endif-                             lengthFL, mapFL, mapFL_FL, spanFL, foldlFL, allFL,-                             splitAtFL, bunchFL, foldlRL,-                             lengthRL, isShorterThanRL, mapRL, mapRL_RL, zipWithFL,-                             unsafeMap_l2f, filterE, filterFL,-                             reverseFL, reverseRL, (+>+), (+<+),-                             nullFL, concatFL, concatRL, concatReverseFL, headRL,-                             MyEq, unsafeCompare, (=\/=), (=/\=),-                             consRLSealed, nullRL,-                             unsafeCoerceP, unsafeCoerceP2-                           ) where--#include "impossible.h"-import GHC.Base (unsafeCoerce#)-import Darcs.Show-import Darcs.Sealed ( FlippedSeal(..), flipSeal )--data EqCheck C(a b) where-    IsEq :: EqCheck C(a a)-    NotEq :: EqCheck C(a b)--instance Eq (EqCheck C(a b)) where-    IsEq == IsEq = True-    NotEq == NotEq = True-    _ == _ = False--isEq :: EqCheck C(a b) -> Bool-isEq IsEq = True-isEq NotEq = False--instance Show (EqCheck C(a b)) where-    show IsEq = "IsEq"-    show NotEq = "NotEq"--data Proof a C(x y) where-    Proof :: a -> Proof a C(x x)--data (a1 :> a2) C(x y) = FORALL(z) (a1 C(x z)) :> (a2 C(z y))-infixr 1 :>-data (a1 :< a2) C(x y) = FORALL(z) (a1 C(z y)) :< (a2 C(x z))-infix 1 :<-infix 1 :/\:, :\/:-data (a1 :\/: a2) C(x y) = FORALL(z) (a1 C(z x)) :\/: (a2 C(z y))-data (a1 :/\: a2) C(x y) = FORALL(z) (a1 C(x z)) :/\: (a2 C(y z))-class MyEq p where-    -- Minimal definition defines any one of unsafeCompare, =\/= and =/\=.-    unsafeCompare :: p C(a b) -> p C(c d) -> Bool-    unsafeCompare a b = IsEq == (a =/\= unsafeCoerceP b)-    (=\/=) :: p C(a b) -> p C(a c) -> EqCheck C(b c)-    a =\/= b | unsafeCompare a b = unsafeCoerceP IsEq-             | otherwise = NotEq-    (=/\=) :: p C(a c) -> p C(b c) -> EqCheck C(a b)-    a =/\= b | IsEq == (a =\/= unsafeCoerceP b) = unsafeCoerceP IsEq-             | otherwise = NotEq--infix 4 =\/=, =/\=--unsafeCoerceP :: a C(x y) -> a C(b c)-unsafeCoerceP = unsafeCoerce#--unsafeCoerceP2 :: t C(w x y z) -> t C(a b c d)-unsafeCoerceP2 = unsafeCoerce#--instance (Show2 a, Show2 b) => Show ( (a :> b) C(x y) ) where-    showsPrec d (x :> y) = showOp2 1 ":>" d x y--instance (Show2 a, Show2 b) => Show2 (a :> b) where-    showsPrec2 = showsPrec--instance (Show2 a, Show2 b) => Show ( (a :\/: b) C(x y) ) where-    showsPrec d (x :\/: y) = showOp2 9 ":\\/:" d x y--instance (Show2 a, Show2 b) => Show2 (a :\/: b) where-    showsPrec2 = showsPrec--infixr 5 :>:, :<:, +>+, +<+---- forward list-data FL a C(x z) where-    (:>:) :: a C(x y) -> FL a C(y z) -> FL a C(x z)-    NilFL :: FL a C(x x)--instance Show2 a => Show (FL a C(x z)) where-   showsPrec _ NilFL = showString "NilFL"-   showsPrec d (x :>: xs) = showParen (d > prec) $ showsPrec2 (prec + 1) x .-                            showString " :>: " . showsPrec (prec + 1) xs-       where prec = 5--instance Show2 a => Show2 (FL a) where-   showsPrec2 = showsPrec---- reverse list-data RL a C(x z) where-    (:<:) :: a C(y z) -> RL a C(x y) -> RL a C(x z)-    NilRL :: RL a C(x x)--nullFL :: FL a C(x z) -> Bool-nullFL NilFL = True-nullFL _ = False--nullRL :: RL a C(x z) -> Bool-nullRL NilRL = True-nullRL _ = False--filterFL :: (FORALL(x y) p C(x y) -> EqCheck C(x y)) -> FL p C(w z) -> FL p C(w z)-filterFL _ NilFL = NilFL-filterFL f (x:>:xs) | IsEq <- f x = filterFL f xs-                    | otherwise = x :>: filterFL f xs--filterE :: (a -> EqCheck C(x y)) -> [a] -> [Proof a C(x y)]-filterE _ [] = []-filterE p (x:xs)-    | IsEq <- p x = Proof x : filterE p xs-    | otherwise   = filterE p xs--(+>+) :: FL a C(x y) -> FL a C(y z) -> FL a C(x z)-NilFL +>+ ys = ys-(x:>:xs) +>+ ys = x :>: xs +>+ ys--(+<+) :: RL a C(y z) -> RL a C(x y) -> RL a C(x z)-NilRL +<+ ys = ys-(x:<:xs) +<+ ys = x :<: xs +<+ ys--reverseFL :: FL a C(x z) -> RL a C(x z)-reverseFL xs = r NilRL xs-  where r :: RL a C(l m) -> FL a C(m o) -> RL a C(l o)-        r ls NilFL = ls-        r ls (a:>:as) = r (a:<:ls) as--reverseRL :: RL a C(x z) -> FL a C(x z)-reverseRL xs = r NilFL xs -- r (xs :> NilFL)-  where r :: FL a C(m o) -> RL a C(l m) -> FL a C(l o)-        r ls NilRL = ls-        r ls (a:<:as) = r (a:>:ls) as--concatFL :: FL (FL a) C(x z) -> FL a C(x z)-concatFL NilFL = NilFL-concatFL (a:>:as) = a +>+ concatFL as--concatRL :: RL (RL a) C(x z) -> RL a C(x z)-concatRL NilRL = NilRL-concatRL (a:<:as) = a +<+ concatRL as--spanFL :: (FORALL(w y) a C(w y) -> Bool) -> FL a C(x z) -> (FL a :> FL a) C(x z)-spanFL f (x:>:xs) | f x = case spanFL f xs of-                            ys :> zs -> (x:>:ys) :> zs-spanFL _ xs = NilFL :> xs--splitAtFL :: Int -> FL a C(x z) -> (FL a :> FL a) C(x z)-splitAtFL 0 xs = NilFL :> xs-splitAtFL _ NilFL = NilFL :> NilFL-splitAtFL n (x:>:xs) = case splitAtFL (n-1) xs of-                       (xs':>xs'') -> (x:>:xs' :> xs'')---- 'bunchFL n' groups patches into batches of n, except that it always puts--- the first patch in its own group, this being a recognition that the--- first patch is often *very* large.--bunchFL :: Int -> FL a C(x y) -> FL (FL a) C(x y)-bunchFL _ NilFL = NilFL-bunchFL n (x:>:xs) = (x :>: NilFL) :>: bFL xs-    where bFL :: FL a C(x y) -> FL (FL a) C(x y)-          bFL NilFL = NilFL-          bFL bs = case splitAtFL n bs of-                   a :> b -> a :>: bFL b---allFL :: (FORALL(x y) a C(x y) -> Bool) -> FL a C(w z) -> Bool-allFL f xs = and $ mapFL f xs--foldlFL :: (FORALL(w y) a -> b C(w y) -> a) -> a -> FL b C(x z) -> a-foldlFL _ x NilFL = x-foldlFL f x (y:>:ys) = foldlFL f (f x y) ys--foldlRL :: (FORALL(w y) a -> b C(w y) -> a) -> a -> RL b C(x z) -> a-foldlRL _ x NilRL = x-foldlRL f x (y:<:ys) = foldlRL f (f x y) ys--mapFL_FL :: (FORALL(w y) a C(w y) -> b C(w y)) -> FL a C(x z) -> FL b C(x z)-mapFL_FL _ NilFL = NilFL-mapFL_FL f (a:>:as) = f a :>: mapFL_FL f as--zipWithFL :: (FORALL(x y) a -> p C(x y) -> q C(x y))-          -> [a] -> FL p C(w z) -> FL q C(w z)-zipWithFL f (x:xs) (y :>: ys) = f x y :>: zipWithFL f xs ys-zipWithFL _ _ NilFL = NilFL-zipWithFL _ [] (_:>:_) = bug "zipWithFL called with too short a list"--mapRL_RL :: (FORALL(w y) a C(w y) -> b C(w y)) -> RL a C(x z) -> RL b C(x z)-mapRL_RL _ NilRL = NilRL-mapRL_RL f (a:<:as) = f a :<: mapRL_RL f as--mapFL :: (FORALL(w z) a C(w z) -> b) -> FL a C(x y) -> [b]-mapFL _ NilFL = []-mapFL f (a :>: b) = f a : mapFL f b--mapRL :: (FORALL(w z) a C(w z) -> b) -> RL a C(x y) -> [b]-mapRL _ NilRL = []-mapRL f (a :<: b) = f a : mapRL f b--unsafeMap_l2f :: (FORALL(w z) a -> b C(w z)) -> [a] -> FL b C(x y)-unsafeMap_l2f _ [] = unsafeCoerceP NilFL-unsafeMap_l2f f (x:xs) = f x :>: unsafeMap_l2f f xs--lengthFL :: FL a C(x z) -> Int-lengthFL xs = l xs 0-  where l :: FL a C(x z) -> Int -> Int-        l NilFL n = n-        l (_:>:as) n = l as $! n+1--lengthRL :: RL a C(x z) -> Int-lengthRL xs = l xs 0-  where l :: RL a C(x z) -> Int -> Int-        l NilRL n = n-        l (_:<:as) n = l as $! n+1--isShorterThanRL :: RL a C(x y) -> Int -> Bool-isShorterThanRL _ n | n <= 0 = False-isShorterThanRL NilRL _ = True-isShorterThanRL (_:<:xs) n = isShorterThanRL xs (n-1)--concatReverseFL :: FL (RL a) C(x y) -> RL a C(x y)-concatReverseFL = concatRL . reverseFL--headRL :: RL a C(x y) -> FlippedSeal a C(y)-headRL (x:<:_) = flipSeal x-headRL _ = impossible--consRLSealed :: a C(y z) -> FlippedSeal (RL a) C(y) -> FlippedSeal (RL a) C(z)-consRLSealed a (FlippedSeal as) = flipSeal $ a :<: as--#ifndef GADT_WITNESSES--- These are useful for interfacing with modules outside of--- patch theory, such as Show.lhs-unsafeUnFL :: FL a -> [a]-unsafeUnFL NilFL = []-unsafeUnFL (a:>:as) = a : unsafeUnFL as--unsafeUnRL :: RL a -> [a]-unsafeUnRL NilRL = []-unsafeUnRL (a:<:as) = a : unsafeUnRL as--unsafeFL :: [a] -> FL a-unsafeFL [] = NilFL-unsafeFL (a:as) = a :>: unsafeFL as--unsafeRL :: [a] -> RL a-unsafeRL [] = NilRL-unsafeRL (a:as) = a :<: unsafeRL as-#endif
src/Darcs/Patch.lhs view
@@ -45,7 +45,7 @@ module Darcs.Patch ( RepoPatch, Prim, Patch, RealPatch, Named, Patchy,                      flattenFL, joinPatches,                      fromPrim, fromPrims,-               is_null_patch, nullP,+               isNullPatch, nullP,                rmfile, addfile, rmdir, adddir, move,                hunk, tokreplace, namepatch, anonymous,                binary,@@ -53,32 +53,33 @@                showContextPatch, showPatch, showNicely,                infopatch, changepref,                thing, things,-               is_similar, is_addfile, is_hunk, is_setpref,+               isSimilar, primIsAddfile, primIsHunk, primIsSetpref, #ifndef GADT_WITNESSES-               merger, is_merger, merge,-               commute, commutex, list_touched_files,+               merger, isMerger, merge,+               commute, listTouchedFiles, hunkMatches,                -- for PatchTest-               unravel, elegant_merge,+               unravel, elegantMerge, #else                Commute(..), #endif-               resolve_conflicts,+               resolveConflicts,                Effect, effect,-               is_binary, gzWritePatch, writePatch, is_adddir,+               primIsBinary, gzWritePatch, writePatch, primIsAdddir,                invert, invertFL, invertRL, identity,                commuteFL, commuteRL,                readPatch,-               canonize, sort_coalesceFL,-               try_to_shrink,-               apply_to_slurpy, patchname, patchcontents,-               apply_to_filepaths, force_replace_slurpy, apply,+               canonize, sortCoalesceFL,+               tryToShrink,+               applyToSlurpy, patchname, patchcontents,+               applyToFilepaths, forceReplaceSlurpy, apply,+               applyToTree,                patch2patchinfo,                LineMark(AddedLine, RemovedLine, AddedRemovedLine, None),-               MarkedUpFile, markup_file, empty_markedup_file,-               summary, summarize, xml_summary,+               MarkedUpFile, markupFile, emptyMarkedupFile,+               summary, plainSummary, xmlSummary,                adddeps, getdeps,-               list_conflicted_files,-               modernize_patch,+               listConflictedFiles,+               modernizePatch,                -- for Population                DirMark(..), patchChanges, applyToPop,              ) where@@ -88,10 +89,10 @@                           adddeps, namepatch,                           anonymous, #ifndef GADT_WITNESSES-                          is_merger,+                          isMerger, #endif                           getdeps,-                          is_null_patch, nullP, infopatch,+                          isNullPatch, nullP, infopatch,                           patch2patchinfo, patchname, patchcontents ) import Darcs.Patch.Read ( readPatch ) import Darcs.Patch.Patchy ( Patchy, writePatch, gzWritePatch,@@ -101,33 +102,33 @@                             commuteFL, commuteRL, apply,                             description, summary, #ifndef GADT_WITNESSES-                            commute, commutex, list_touched_files,+                            commute, listTouchedFiles, hunkMatches, #else                             Commute(..) #endif                           )-import Darcs.Patch.Viewing ( xml_summary, summarize )-import Darcs.Patch.Apply ( applyToPop, patchChanges, empty_markedup_file,-                           markup_file, force_replace_slurpy,-                           apply_to_filepaths, apply_to_slurpy,-                           LineMark(..), MarkedUpFile )-import Darcs.Patch.Commute ( modernize_patch,+import Darcs.Patch.Viewing ( xmlSummary, plainSummary )+import Darcs.Patch.Apply ( applyToPop, patchChanges, emptyMarkedupFile,+                           markupFile, forceReplaceSlurpy,+                           applyToFilepaths, applyToSlurpy,+                           LineMark(..), MarkedUpFile, applyToTree )+import Darcs.Patch.Commute ( modernizePatch, #ifndef GADT_WITNESSES                              unravel,-                             merger, merge, elegant_merge,+                             merger, merge, elegantMerge, #endif                             ) import Darcs.Patch.Prim ( FromPrims, fromPrims, joinPatches, FromPrim, fromPrim,-                          Conflict, Effect(effect), list_conflicted_files, resolve_conflicts,+                          Conflict, Effect(effect), listConflictedFiles, resolveConflicts,                           Prim, canonize,-                          sort_coalesceFL,+                          sortCoalesceFL,                           rmdir, rmfile, tokreplace, adddir, addfile,                           binary, changepref, hunk, move, -                          is_adddir, is_addfile,-                          is_hunk, is_binary, is_setpref,-                          is_similar,-                          try_to_shrink )-import Darcs.Ordered ( FL )+                          primIsAdddir, primIsAddfile,+                          primIsHunk, primIsBinary, primIsSetpref,+                          isSimilar,+                          tryToShrink )+import Darcs.Witnesses.Ordered ( FL ) import Darcs.Patch.Real ( RealPatch )  instance Patchy Patch
src/Darcs/Patch/Apply.lhs view
@@ -22,13 +22,14 @@  #include "gadts.h" -module Darcs.Patch.Apply ( apply_to_filepaths, apply_to_slurpy,+module Darcs.Patch.Apply ( applyToFilepaths, applyToSlurpy,                            forceTokReplace,-                           markup_file, empty_markedup_file,+                           markupFile, emptyMarkedupFile,                            patchChanges,                            applyToPop,+                           applyToTree,                            LineMark(..), MarkedUpFile,-                           force_replace_slurpy )+                           forceReplaceSlurpy )     where  import Prelude hiding ( catch, pi )@@ -54,14 +55,17 @@ import Darcs.Patch.Info ( PatchInfo ) import Control.Monad ( when ) import Darcs.SlurpDirectory ( FileContents, Slurpy, withSlurpy, slurp_modfile )-import RegChars ( regChars )-import Darcs.Repository.Prefs ( change_prefval )+import Darcs.Patch.RegChars ( regChars )+import Darcs.Repository.Prefs ( changePrefval ) import Darcs.Global ( darcsdir ) import Darcs.IO ( WriteableDirectory(..), ReadableDirectory(..) ) import Darcs.FilePathMonad ( withFilePaths ) #include "impossible.h"-import Darcs.Ordered ( FL(..), (:>)(..),+import Darcs.Witnesses.Ordered ( FL(..), (:>)(..),                              mapFL, mapFL_FL, spanFL, foldlFL )++import Storage.Hashed.Tree( Tree )+import Storage.Hashed.Monad( virtualTreeIO ) \end{code}  @@ -107,11 +111,11 @@   \begin{code}-apply_to_filepaths :: Apply p => p C(x y) -> [FilePath] -> [FilePath]-apply_to_filepaths pa fs = withFilePaths fs (apply [] pa)+applyToFilepaths :: Apply p => p C(x y) -> [FilePath] -> [FilePath]+applyToFilepaths pa fs = withFilePaths fs (apply [] pa) -apply_to_slurpy :: (Apply p, Monad m) => p C(x y) -> Slurpy -> m Slurpy-apply_to_slurpy p s = case withSlurpy s (apply [] p) of+applyToSlurpy :: (Apply p, Monad m) => p C(x y) -> Slurpy -> m Slurpy+applyToSlurpy p s = case withSlurpy s (apply [] p) of                           Left err -> fail err                           Right (s', ()) -> return s' @@ -127,10 +131,10 @@     applyAndTryToFix (ComP xs) = mapMaybeSnd ComP `fmap` applyAndTryToFix xs     applyAndTryToFix x = do mapMaybeSnd ComP `fmap` applyAndTryToFixFL x -force_replace_slurpy :: Prim C(x y) -> Slurpy -> Maybe Slurpy-force_replace_slurpy (FP f (TokReplace tcs old new)) s =+forceReplaceSlurpy :: Prim C(x y) -> Slurpy -> Maybe Slurpy+forceReplaceSlurpy (FP f (TokReplace tcs old new)) s =     slurp_modfile f (forceTokReplace tcs old new) s-force_replace_slurpy _ _ = bug "Can only force_replace_slurpy on a replace."+forceReplaceSlurpy _ _ = bug "Can only forceReplaceSlurpy on a replace."  instance Apply Prim where     apply opts (Split ps) = applyFL opts ps@@ -154,7 +158,7 @@     apply _ (Move f f') = mRename f f'     apply _ (ChangePref p f t) =         do b <- mDoesDirectoryExist (fp2fn $ darcsdir++"/prefs")-           when b $ change_prefval p f t+           when b $ changePrefval p f t     applyAndTryToFixFL (FP f RmFile) =         do x <- mReadFilePS f            if B.null x then do mRemoveFile f@@ -296,12 +300,12 @@               | AddedRemovedLine PatchInfo PatchInfo | None                 deriving (Show) type MarkedUpFile = [(B.ByteString, LineMark)]-empty_markedup_file :: MarkedUpFile-empty_markedup_file = [(B.empty, None)]+emptyMarkedupFile :: MarkedUpFile+emptyMarkedupFile = [(B.empty, None)] -markup_file :: Effect p => PatchInfo -> p C(x y)+markupFile :: Effect p => PatchInfo -> p C(x y)             -> (FilePath, MarkedUpFile) -> (FilePath, MarkedUpFile)-markup_file x p = mps (effect p)+markupFile x p = mps (effect p)     where mps :: FL Prim C(a b) -> (FilePath, MarkedUpFile) -> (FilePath, MarkedUpFile)           mps NilFL = id           mps (pp:>:pps) = mps pps . markup_prim x pp@@ -518,5 +522,10 @@ pname :: PopTree -> B.ByteString pname (PopDir i _) = nameI i pname (PopFile i) = nameI i++-- | Apply a patch to a 'Tree', yielding a new 'Tree'.+applyToTree :: (Apply p) => p C(x y) -> Tree IO -> IO (Tree IO)+applyToTree patch t = snd `fmap` virtualTreeIO (apply [] patch) t+ \end{code} 
src/Darcs/Patch/Bundle.hs view
@@ -24,31 +24,33 @@                      make_context, scan_context,                    ) where -import Darcs.Flags ( DarcsFlag( Unified ) )+import Darcs.Flags ( DarcsFlag, isUnified ) import Darcs.Hopefully ( PatchInfoAnd, piap,                          patchInfoAndPatch,                          unavailable, hopefully ) import Darcs.Patch ( RepoPatch, Named, showPatch, showContextPatch, readPatch ) import Darcs.Patch.Info ( PatchInfo, readPatchInfo, showPatchInfo, human_friendly, is_tag ) import Darcs.Patch.Set ( PatchSet, SealedPatchSet )-import Darcs.Ordered ( RL(..), FL(..), unsafeCoerceP,+import Darcs.Witnesses.Ordered ( RL(..), FL(..), unsafeCoerceP,                              reverseFL, (+<+), mapFL, mapFL_FL ) import Printer ( Doc, renderPS, newline, text, ($$),                  (<>), vcat, vsep, renderString )-import Darcs.SlurpDirectory ( Slurpy )  import ByteStringUtils ( linesPS, unlinesPS, dropSpace, substrPS) import qualified Data.ByteString as B (ByteString, length, null, drop, isPrefixOf) import qualified Data.ByteString.Char8 as BC (unpack, break, pack)  import SHA1( sha1PS )-import Darcs.Sealed ( Sealed(Sealed), mapSeal )+import Darcs.Witnesses.Sealed ( Sealed(Sealed), mapSeal ) +import Storage.Hashed.Tree( Tree )+import Storage.Hashed.Monad( virtualTreeIO )+ hash_bundle :: RepoPatch p => [PatchInfo] -> FL (Named p) C(x y) -> String hash_bundle _ to_be_sent = sha1PS $ renderPS                          $ vcat (mapFL showPatch to_be_sent) <> newline -make_bundle :: RepoPatch p => [DarcsFlag] -> Slurpy -> [PatchInfo] -> FL (Named p) C(x y) -> Doc+make_bundle :: RepoPatch p => [DarcsFlag] -> Tree IO -> [PatchInfo] -> FL (Named p) C(x y) -> IO Doc make_bundle opts the_s common to_be_sent = make_bundle2 opts the_s common to_be_sent to_be_sent  -- | In make_bundle2, it is presumed that the two patch sequences are@@ -56,23 +58,24 @@ -- patch sequences are passed, a bundle with a mismatched hash will be -- generated, which is not the end of the world, but isn't very useful -- either.-make_bundle2 :: RepoPatch p => [DarcsFlag] -> Slurpy -> [PatchInfo]-             -> FL (Named p) C(x y) -> FL (Named p) C(x y) -> Doc+make_bundle2 :: RepoPatch p => [DarcsFlag] -> Tree IO -> [PatchInfo]+             -> FL (Named p) C(x y) -> FL (Named p) C(x y) -> IO Doc make_bundle2 opts the_s common to_be_sent to_be_sent2 =-    text ""- $$ text "New patches:"- $$ text ""- $$ the_new- $$ text ""- $$ text "Context:"- $$ text ""- $$ (vcat $ map showPatchInfo common)- $$ text "Patch bundle hash:"- $$ text (hash_bundle common to_be_sent2)- $$ text ""-      where the_new = if Unified `elem` opts-                      then showContextPatch the_s to_be_sent-                      else vsep $ mapFL showPatch to_be_sent+    do patches <- case (isUnified opts) of+                    True -> fst `fmap` virtualTreeIO (showContextPatch to_be_sent) the_s+                    False -> return (vsep $ mapFL showPatch to_be_sent)+       return $ format patches+    where format the_new = text ""+                           $$ text "New patches:"+                           $$ text ""+                           $$ the_new+                           $$ text ""+                           $$ text "Context:"+                           $$ text ""+                           $$ (vcat $ map showPatchInfo common)+                           $$ text "Patch bundle hash:"+                           $$ text (hash_bundle common to_be_sent2)+                           $$ text ""  scan_bundle :: RepoPatch p => B.ByteString -> Either String (SealedPatchSet p) scan_bundle ps@@ -84,7 +87,7 @@         (Sealed patches, rest') ->             case silly_lex rest' of             ("Context:", rest'') ->-                case get_context rest'' of+                case getContext rest'' of                 (cont,maybe_hash) ->                     case substrPS (BC.pack "Patch bundle hash:")                          maybe_hash of@@ -102,7 +105,7 @@             (a,r) -> Left $ "Malformed patch bundle: '"++a++"' is not 'Context:'"                      ++ "\n" ++ BC.unpack r     ("Context:",rest) ->-        case get_context rest of+        case getContext rest of         (cont, rest') ->             case silly_lex rest' of             ("New patches:", rest'') ->@@ -153,11 +156,11 @@ pi_unavailable i = (i `patchInfoAndPatch`                       unavailable ("Patch not stored in patch bundle:\n" ++                                    renderString (human_friendly i)))-get_context :: B.ByteString -> ([PatchInfo],B.ByteString)-get_context ps =+getContext :: B.ByteString -> ([PatchInfo],B.ByteString)+getContext ps =     case readPatchInfo ps of     Just (pinfo,r') ->-        case get_context r' of+        case getContext r' of         (pis,r'') -> (pinfo:pis, r'')     Nothing -> ([],ps) (-:-) :: a C(x y) -> (Sealed (FL a C(y)),b) -> (Sealed (FL a C(x)),b)@@ -204,7 +207,7 @@   | otherwise =     case silly_lex ps of     ("Context:",rest) ->-        case get_context rest of+        case getContext rest of         (cont, _) -> unavailable_patches cont :<: NilRL     ("-----BEGIN PGP SIGNED MESSAGE-----",rest) ->             scan_context $ filter_gpg_dashes rest
− src/Darcs/Patch/Check.hs
@@ -1,335 +0,0 @@--- Copyright (C) 2002-2003 David Roundy------ This program is free software; you can redistribute it and/or modify--- it under the terms of the GNU General Public License as published by--- the Free Software Foundation; either version 2, or (at your option)--- any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; see the file COPYING.  If not, write to--- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,--- Boston, MA 02110-1301, USA.--module Darcs.Patch.Check ( PatchCheck(), do_check, file_exists, dir_exists,-                    remove_file, remove_dir, create_file, create_dir,-                    insert_line, delete_line, is_valid, do_verbose_check,-                    file_empty,-                    check_move, modify_file, FileContents(..)-                  ) where--import System.IO.Unsafe ( unsafePerformIO )-import qualified Data.ByteString as B (ByteString)-import Data.List ( isPrefixOf, inits )-import Control.Monad.State ( State, evalState, runState )-import Control.Monad.State.Class ( get, put, modify )--- use Map, not IntMap, because Map has mapKeys and IntMap hasn't-import Data.Map ( Map )-import qualified Data.Map as M ( mapKeys, delete, insert, empty, lookup, null )-import System.FilePath ( joinPath, splitDirectories )---- | File contents are represented by a map from line numbers to line contents.---   If for a certain line number, the line contents are Nothing, that means---   that we are sure that that line exists, but we don't know its contents.---   We must also store the greatest line number that is known to exist in a---   file, to be able to exclude the possibility of it being empty without---   knowing its contents.-data FileContents = FC { fc_lines   :: Map Int B.ByteString-                       , fc_maxline :: Int-                       } deriving (Eq, Show)-data Prop = FileEx String | DirEx String | NotEx String-          | FileLines String FileContents-            deriving (Eq)--- | A @KnownState@ is a simulated repository state. The repository is either--- inconsistent, or it has two lists of properties: one list with properties--- that hold for this repo, and one with properties that do not hold for this--- repo. These two lists may not have any common elements: if they had, the--- repository would be inconsistent.-data KnownState = P [Prop] [Prop]-                | Inconsistent-                  deriving (Show)-instance  Show Prop  where-    show (FileEx f) = "FileEx "++f-    show (DirEx d)  = "DirEx "++d-    show (NotEx f) = "NotEx"++f-    show (FileLines f l)  = "FileLines "++f++": "++show l---- | PatchCheck is a state monad with a simulated repository state-type PatchCheck = State KnownState---- | The @FileContents@ structure for an empty file-empty_filecontents :: FileContents-empty_filecontents = FC M.empty 0---- | Returns a given value if the repository state is inconsistent, and performs---   a given action otherwise.-handle_inconsistent :: a            -- ^ The value to return if the state is inconsistent-                   -> PatchCheck a -- ^ The action to perform otherwise-                   -> PatchCheck a-handle_inconsistent v a = do state <- get-                             case state of-                               Inconsistent -> return v-                               _            -> a--do_check :: PatchCheck a -> a-do_check p = evalState p (P [] [])---- | Run a check, and print the final repository state-do_verbose_check :: PatchCheck a -> a-do_verbose_check p =-    case runState p (P [] []) of-    (b, pc) -> unsafePerformIO $ do putStrLn $ show pc-                                    return b---- | Returns true if the current repository state is not inconsistent-is_valid :: PatchCheck Bool-is_valid = handle_inconsistent False (return True)--has :: Prop -> [Prop] -> Bool-has _ [] = False-has k (k':ks) = k == k' || has k ks--modify_file :: String-            -> (Maybe FileContents -> Maybe FileContents)-            -> PatchCheck Bool-modify_file f change = do-    file_exists f-    c <- file_contents f-    case change c of-      Nothing -> assert_not $ FileEx f -- shorthand for "FAIL"-      Just c' -> do set_contents f c'-                    is_valid--insert_line :: String -> Int -> B.ByteString -> PatchCheck Bool-insert_line f n l = do-    c <- file_contents f-    case c of-      Nothing -> assert_not $ FileEx f -- in this case, the repo is inconsistent-      Just c' -> do-        let lines'   = M.mapKeys (\k -> if k >= n then k+1 else k) (fc_lines c')-            lines''  = M.insert n l lines'-            maxline' = max n (fc_maxline c')-        set_contents f (FC lines'' maxline')-        return True---- deletes a line from a hunk patch (third argument) in the given file (first--- argument) at the given line number (second argument)-delete_line :: String -> Int -> B.ByteString -> PatchCheck Bool-delete_line f n l = do-    c <- file_contents f-    case c of-      Nothing -> assert_not $ FileEx f-      Just c' ->-        let flines  = fc_lines c'-            flines' = M.mapKeys (\k -> if k > n then k-1 else k)-                                (M.delete n flines)-            maxlinenum' | n <= fc_maxline c'  = fc_maxline c' - 1-                        | otherwise           = n - 1-            c'' = FC flines' maxlinenum'-            do_delete = do-              set_contents f c''-              is_valid-        in case M.lookup n flines of-          Nothing -> do_delete-          Just l' -> if l == l'-                       then do_delete-                       else assert_not $ FileEx f--set_contents :: String -> FileContents -> PatchCheck ()-set_contents f c = handle_inconsistent () $ do-    P ks nots <- get-    let ks' = FileLines f c : filter (not . is_file_lines_for f) ks-    put (P ks' nots)-  where is_file_lines_for file prop = case prop of -                                        FileLines f' _ -> file == f'-                                        _              -> False---- | Get (as much as we know about) the contents of a file in the current state.---   Returns Nothing if the state is inconsistent.-file_contents :: String -> PatchCheck (Maybe FileContents)-file_contents f = handle_inconsistent Nothing $ do-      P ks _ <- get-      return (fic ks)-    where fic (FileLines f' c:_) | f == f' = Just c-          fic (_:ks) = fic ks-          fic [] = Just empty_filecontents---- | Checks if a file is empty-file_empty :: String          -- ^ Name of the file to check-           -> PatchCheck Bool-file_empty f = do-  c <- file_contents f-  let empty = case c of-               Just c' -> fc_maxline c' == 0 && M.null (fc_lines c')-               Nothing -> True-  if empty-     then do set_contents f empty_filecontents-             is_valid-     -- Crude way to make it inconsistent and return false:-     else assert_not $ FileEx f-  return empty--movedirfilename :: String -> String -> String -> String-movedirfilename d d' f =-    if (d ++ "/") `isPrefixOf` f-    then d'++drop (length d) f-    else if f == d-         then d'-         else f---- | Replaces a filename by another in all paths. Returns True if the repository---   is consistent, False if it is not.-do_swap :: String -> String -> PatchCheck Bool-do_swap f f' = handle_inconsistent False $ do-    modify (\(P ks nots) -> P (map sw ks) (map sw nots))-    return True-  where sw (FileEx a) | f  `is_soe` a = FileEx $ movedirfilename f f' a-                      | f' `is_soe` a = FileEx $ movedirfilename f' f a-        sw (DirEx a) | f  `is_soe` a = DirEx $ movedirfilename f f' a-                     | f' `is_soe` a = DirEx $ movedirfilename f' f a-        sw (FileLines a c) | f  `is_soe` a = FileLines (movedirfilename f f' a) c-                           | f' `is_soe` a = FileLines (movedirfilename f' f a) c-        sw (NotEx a) | f `is_soe` a = NotEx $ movedirfilename f f' a-                     | f' `is_soe` a = NotEx $ movedirfilename f' f a-        sw p = p-        is_soe d1 d2 = -- is_superdir_or_equal-            d1 == d2 || (d1 ++ "/") `isPrefixOf` d2---- | Assert a property about the repository. If the property is already present--- in the repo state, nothing changes, and the function returns True. If it is--- not present yet, it is added to the repo state, and the function is True. If--- the property is already in the list of properties that do not hold for the--- repo, the state becomes inconsistent, and the function returns false.-assert :: Prop -> PatchCheck Bool-assert p = handle_inconsistent False $ do-    P ks nots <- get-    if has p nots-      then do-        put Inconsistent-        return False-      else if has p ks-             then return True-             else do-               put (P (p:ks) nots)-               return True---- | Like @assert@, but negatively: state that some property must not hold for---   the current repo.-assert_not :: Prop -> PatchCheck Bool-assert_not p = handle_inconsistent False $ do-    P ks nots <- get-    if has p ks-      then do-        put Inconsistent-        return False-      else if has p nots-             then return True-             else do-               put (P ks (p:nots))-               return True---- | Remove a property from the list of properties that do not hold for this--- repo (if it's there), and add it to the list of properties that hold.--- Returns False if the repo is inconsistent, True otherwise.-change_to_true :: Prop -> PatchCheck Bool-change_to_true p = handle_inconsistent False $ do-    modify (\(P ks nots) -> P (p:ks) (filter (p /=) nots))-    return True---- | Remove a property from the list of properties that hold for this repo (if--- it's in there), and add it to the list of properties that do not hold.--- Returns False if the repo is inconsistent, True otherwise.-change_to_false :: Prop -> PatchCheck Bool-change_to_false p = handle_inconsistent False $ do-    modify (\(P ks nots) -> P (filter (p /=) ks) (p:nots))-    return True--assert_file_exists :: String -> PatchCheck Bool-assert_file_exists f = do assert_not $ NotEx f-                          assert_not $ DirEx f-                          assert $ FileEx f-assert_dir_exists :: String -> PatchCheck Bool-assert_dir_exists d = do assert_not $ NotEx d-                         assert_not $ FileEx d-                         assert $ DirEx d-assert_exists :: String -> PatchCheck Bool-assert_exists f = assert_not $ NotEx f--assert_no_such :: String -> PatchCheck Bool-assert_no_such f = do assert_not $ FileEx f-                      assert_not $ DirEx f-                      assert $ NotEx f--create_file :: String -> PatchCheck Bool-create_file fn = do-  superdirs_exist fn-  assert_no_such fn-  change_to_true (FileEx fn)-  change_to_false (NotEx fn)--create_dir :: String -> PatchCheck Bool-create_dir fn = do-  substuff_dont_exist fn-  superdirs_exist fn-  assert_no_such fn-  change_to_true (DirEx fn)-  change_to_false (NotEx fn)--remove_file :: String -> PatchCheck Bool-remove_file fn = do-  superdirs_exist fn-  assert_file_exists fn-  file_empty fn-  change_to_false (FileEx fn)-  change_to_true (NotEx fn)--remove_dir :: String -> PatchCheck Bool-remove_dir fn = do-  substuff_dont_exist fn-  superdirs_exist fn-  assert_dir_exists fn-  change_to_false (DirEx fn)-  change_to_true (NotEx fn)--check_move :: String -> String -> PatchCheck Bool-check_move f f' = do-  superdirs_exist f-  superdirs_exist f'-  assert_exists f-  assert_no_such f'-  do_swap f f'--substuff_dont_exist :: String -> PatchCheck Bool-substuff_dont_exist d = handle_inconsistent False $ do-    P ks _ <- get-    if all noss ks-      then return True-      else do-        put Inconsistent-        return False-  where noss (FileEx f) = not (is_within_dir f)-        noss (DirEx f) = not (is_within_dir f)-        noss _ = True-        is_within_dir f = (d ++ "/") `isPrefixOf` f---- the init and tail calls dump the final init (which is just the path itself--- again), the first init (which is empty), and the initial "." from--- splitDirectories-superdirs_exist :: String -> PatchCheck Bool-superdirs_exist fn = and `fmap` mapM assert_dir_exists superdirs-  where superdirs =  map (("./"++) . joinPath) -                         (init (tail (inits (tail (splitDirectories fn)))))--file_exists :: String -> PatchCheck Bool-file_exists fn = do-  superdirs_exist fn-  assert_file_exists fn--dir_exists :: String -> PatchCheck Bool-dir_exists fn = do-  superdirs_exist fn-  assert_dir_exists fn
src/Darcs/Patch/Choices.hs view
@@ -29,7 +29,7 @@ -- type and associated functions are here to deal with many of the common -- cases that come up when choosing a subset of a group of patches. ----- 'force_last' tells PatchChoices that a particular patch is required to be in+-- 'forceLast' tells PatchChoices that a particular patch is required to be in -- the "last" group, which also means that any patches that depend on it -- must be in the "last" group. --@@ -40,17 +40,19 @@ -- about the first-middle-last language, it's because in some cases the -- "yes" answers will be last (as is the case for the revert command), and -- in others first (as in record, pull and push).-module Darcs.Patch.Choices ( PatchChoices, patch_choices, patch_choices_tps,-                      patch_slot,-                      get_choices,-                      separate_first_middle_from_last,-                      separate_first_from_middle_last,-                      force_first, force_firsts, force_last, force_lasts,-                      force_matching_first, force_matching_last,-                      select_all_middles,-                      make_uncertain, make_everything_later,-                      TaggedPatch, Tag, tag, tp_patch,+module Darcs.Patch.Choices ( PatchChoices, patchChoices, patchChoicesTps,+                             patchChoicesTpsSub,+                      patchSlot,+                      getChoices,+                      separateFirstMiddleFromLast,+                      separateFirstFromMiddleLast,+                      forceFirst, forceFirsts, forceLast, forceLasts,+                      forceMatchingFirst, forceMatchingLast,+                      selectAllMiddles,+                      makeUncertain, makeEverythingLater,+                      TaggedPatch, Tag, tag, tpPatch,                              Slot(..),+                      substitute,                     ) where  import System.IO.Unsafe ( unsafePerformIO )@@ -58,55 +60,86 @@ import Darcs.Patch import Darcs.Patch.Permutations ( commuteWhatWeCanRL ) import Darcs.Patch.Patchy ( Invert, Commute )-import Darcs.Ordered ( FL(..), RL(..), MyEq, unsafeCompare,-                             (:>)(..), (:\/:)(..), (:/\:)(..),-                             zipWithFL, mapFL_FL, mapFL,+import Darcs.Witnesses.Ordered ( FL(..), RL(..), MyEq, unsafeCompare, EqCheck(..),+                             (:>)(..), (:\/:)(..), (:/\:)(..), (:||:)(..),+                             zipWithFL, mapFL_FL, mapFL, concatFL,                              (+>+), reverseRL, unsafeCoerceP )+import Darcs.Witnesses.Sealed ( Sealed2(..) )  -newtype Tag = TG Integer deriving ( Num, Show, Eq, Ord, Enum )+-- | 'TG' @mp i@ acts as a temporary identifier to help us keep track of patches+--   during the selection process.  These are useful for finding patches that+--   may have moved around during patch selection (being pushed forwards or+--   backwards as dependencies arise).+--+--   The identifier is implemented as a tuple @TG mp i@. The @i@ is just some+--   arbitrary label, expected to be unique within the patches being+--   scrutinised.  The @mp@ is motivated by patch splitting; it+--   provides a convenient way to generate a new identifier from the patch+--   being split.  For example, if we split a patch identified as @TG Nothing+--   5@, the resulting sub-patches could be identified as @TG (TG Nothing 5)+--   1@, @TG (TG Nothing 5) 2@, etc.+data Tag = TG (Maybe Tag) Integer deriving ( Eq, Ord ) data TaggedPatch p C(x y) = TP Tag (p C(x y))+ data PatchChoice p C(x y) = PC (TaggedPatch p C(x y)) Slot newtype PatchChoices p C(x y) = PCs (FL (PatchChoice p) C(x y)) +-- | See module documentation for 'Darcs.Patch.Choices' data Slot = InFirst | InMiddle | InLast +negTag :: Tag -> Tag+negTag (TG k n) = TG k (-n)+ invertTag :: Slot -> Slot invertTag InFirst = InLast invertTag InLast  = InFirst invertTag t = t  tag :: TaggedPatch p C(x y) -> Tag-tag (TP (TG t) _) = TG t+tag (TP tg _) = tg -tp_patch :: TaggedPatch p C(x y) -> p C(x y)-tp_patch (TP _ p) = p+tpPatch :: TaggedPatch p C(x y) -> p C(x y)+tpPatch (TP _ p) = p  liftTP :: (p C(x y) -> p C(a b)) -> (TaggedPatch p C(x y) -> TaggedPatch p C(a b)) liftTP f (TP t p) = TP t (f p) +-- This is dangerous if two patches from different tagged series are compared+-- ideally Tag (and hence TaggedPatch/PatchChoices) would have a witness type+-- to represent the originally tagged sequence.+compareTags :: TaggedPatch p C(a b) -> TaggedPatch p C(c d) -> EqCheck C((a, b) (c, d))+compareTags (TP t1 _) (TP t2 _) = if t1 == t2 then unsafeCoerceP IsEq else NotEq+ instance MyEq p => MyEq (TaggedPatch p) where     unsafeCompare (TP t1 p1) (TP t2 p2) = t1 == t2 && unsafeCompare p1 p2  instance Invert p => Invert (TaggedPatch p) where     invert = liftTP invert-    identity = TP (-1) identity+    identity = TP (TG Nothing (-1)) identity  instance Commute p => Commute (TaggedPatch p) where     commute (TP t1 p1 :> TP t2 p2) = do p2' :> p1' <- commute (p1 :> p2)                                         return (TP t2 p2' :> TP t1 p1')-    list_touched_files (TP _ p) = list_touched_files p+    listTouchedFiles (TP _ p) = listTouchedFiles p+    hunkMatches f (TP _ p) = hunkMatches f p     merge (TP t1 p1 :\/: TP t2 p2) = case merge (p1 :\/: p2) of                                      p2' :/\: p1' -> TP t2 p2' :/\: TP t1 p1' -patch_choices :: Patchy p => FL p C(x y) -> PatchChoices p C(x y)-patch_choices = fst . patch_choices_tps+patchChoices :: Patchy p => FL p C(x y) -> PatchChoices p C(x y)+patchChoices = fst . patchChoicesTps -patch_choices_tps :: Patchy p => FL p C(x y) -> (PatchChoices p C(x y), FL (TaggedPatch p) C(x y))-patch_choices_tps ps = let tps = zipWithFL TP [1..] ps-                       in (PCs $ zipWithFL (flip PC) (repeat InMiddle) tps, tps)+-- |Tag a sequence of patches as subpatches of an existing tag. This is intended for+-- use when substituting a patch for an equivalent patch or patches.+patchChoicesTpsSub :: Patchy p+                      => Maybe Tag -> FL p C(x y)+                      -> (PatchChoices p C(x y), FL (TaggedPatch p) C(x y))+patchChoicesTpsSub tg ps = let tps = zipWithFL TP (map (TG tg) [1..]) ps+                              in (PCs $ zipWithFL (flip PC) (repeat InMiddle) tps, tps) -make_everything_later :: Patchy p => PatchChoices p C(x y) -> PatchChoices p C(x y)+-- |Tag a sequence of patches.+patchChoicesTps :: Patchy p => FL p C(x y) -> (PatchChoices p C(x y), FL (TaggedPatch p) C(x y))+patchChoicesTps = patchChoicesTpsSub Nothing  instance MyEq p => MyEq (PatchChoice p) where     unsafeCompare (PC tp1 _) (PC tp2 _) = unsafeCompare tp1 tp2@@ -122,26 +155,41 @@     merge (PC t1 x1 :\/: PC t2 x2)         = case merge (t1 :\/: t2) of           t2' :/\: t1' -> PC t2' x2 :/\: PC t1' x1-    list_touched_files (PC t _) = list_touched_files t+    listTouchedFiles (PC t _) = listTouchedFiles t+    hunkMatches f (PC t _) = hunkMatches f t  invertSeq :: (Invert p, Invert q) => (p :> q) C(x y) -> (q :> p) C(y x) invertSeq (x :> y) = (invert y :> invert x) -separate_first_from_middle_last :: Patchy p => PatchChoices p C(x z)+separateFirstFromMiddleLast :: Patchy p => PatchChoices p C(x z)                                 -> (FL (TaggedPatch p) :> FL (TaggedPatch p)) C(x z)-separate_first_from_middle_last (PCs e) = pull_only_firsts e+separateFirstFromMiddleLast (PCs e) = pull_only_firsts e -separate_first_middle_from_last :: Patchy p => PatchChoices p C(x z)+separateFirstMiddleFromLast :: Patchy p => PatchChoices p C(x z)                                 -> (FL (TaggedPatch p) :> FL (TaggedPatch p)) C(x z)-separate_first_middle_from_last (PCs e) = pull_firsts_middles e+separateFirstMiddleFromLast (PCs e) = pull_firsts_middles e -get_choices :: Patchy p => PatchChoices p C(x y)+getChoices :: Patchy p => PatchChoices p C(x y)             -> (FL (TaggedPatch p) :> FL (TaggedPatch p) :> FL (TaggedPatch p)) C(x y)-get_choices (PCs e) = case pull_firsts e of+getChoices (PCs e) = case pull_firsts e of                       f :> ml -> case pull_firsts (invert ml) of                                  l :> m -> f :> mapFL_FL pc2tp (invert m) :> invert l   where pc2tp (PC tp _) = tp +{-+This unsafePerformIO hack was reported by Igloo as being necessary for+constant space performance when working with a very large set of changes+(e.g. from an initial import) where the second element of the returned tuple+is expected to be small, and will only be accessed after the entire first+element has been forced.+On a quick scan on 20080729 it seemed like only revert/unrevert actually+make use of both elements of the tuple.+We should (a) add a test case that checks on constant space usage and+(b) clean up this interface and code, perhaps by replacing the FL :> FL+with a custom structure that forces traversal of the first element to+get at the second (but then how would we commute/pattern-match? messy...)+-}+ pull_firsts_middles :: Patchy p => FL (PatchChoice p) C(x z) -> (FL (TaggedPatch p) :> FL (TaggedPatch p)) C(x z) pull_firsts_middles easyPC =     let r = unsafePerformIO@@ -214,21 +262,23 @@     Just (TP t2 p2 :> e') ->         case commute (p:>p2) of         Just (p2':>p') -> Just (TP t2 p2' :> (PC (TP t p') InMiddle:>:e'))-        Nothing -> Just (tp :> PC (TP (-t2) p2) InFirst:>:e')+        Nothing -> Just (tp :> PC (TP (negTag t2) p2) InFirst:>:e')     Nothing -> Nothing -patch_slot :: forall p C(a b x y). TaggedPatch p C(a b) -> PatchChoices p C(x y) -> Slot-patch_slot tp (PCs e) = ipf e+patchSlot :: forall p C(a b x y). TaggedPatch p C(a b) -> PatchChoices p C(x y) -> Slot+patchSlot tp (PCs e) = ipf e   where ipf :: FL (PatchChoice p) C(u v) -> Slot         ipf (PC a mb:>:e') | tag a == tag tp = mb                            | otherwise = ipf e'         -- actually, the following should be impossible, but this is a reasonable answer         ipf NilFL = InLast -set_simplys :: [Tag] -> Bool -> FL (PatchChoice p) C(x y) -> FL (PatchChoice p) C(x y)-set_simplys ts b e = mapFL_FL ch e+-- | 'setSimplys' @ts s ps@ assigns all patches in @ps@ with a tag in @ts@ to slot @s@+--   (and any other patch to slot 'InMiddle')+setSimplys :: [Tag] -> Slot -> FL (PatchChoice p) C(x y) -> FL (PatchChoice p) C(x y)+setSimplys ts s e = mapFL_FL ch e     where ch (PC tp@(TP t _) _)-           | t `elem` ts = PC tp (if b then InFirst else InLast)+           | t `elem` ts = PC tp s            | otherwise   = PC tp InMiddle  @@ -238,55 +288,69 @@  | otherwise = m2ids m e m2ids _ NilFL = [] -force_matching_first :: Patchy p => (FORALL(x y) TaggedPatch p C(x y) -> Bool)+forceMatchingFirst :: Patchy p => (FORALL(x y) TaggedPatch p C(x y) -> Bool)                      -> PatchChoices p C(a b) -> PatchChoices p C(a b)-force_matching_first m (PCs e) =+forceMatchingFirst m (PCs e) =     let thd (PC (TP t _) _) = t         xs = m2ids m e-        not_needed = case pull_firsts $ set_simplys xs True e of+        not_needed = case pull_firsts $ setSimplys xs InFirst e of                      _ :> rest -> mapFL thd rest         ch pc@(PC tp@(TP t _) _)          | t `elem` not_needed = pc          | otherwise = PC tp InFirst     in PCs $ mapFL_FL ch e -force_firsts :: Patchy p => [Tag] -> PatchChoices p C(x y) -> PatchChoices p C(x y)-force_firsts ps pc = force_matching_first ((`elem` ps) . tag) pc+forceFirsts :: Patchy p => [Tag] -> PatchChoices p C(x y) -> PatchChoices p C(x y)+forceFirsts ps pc = forceMatchingFirst ((`elem` ps) . tag) pc -force_first :: Patchy p => Tag -> PatchChoices p C(x y) -> PatchChoices p C(x y)-force_first p pc = force_matching_first ((== p) . tag) pc+forceFirst :: Patchy p => Tag -> PatchChoices p C(x y) -> PatchChoices p C(x y)+forceFirst p pc = forceMatchingFirst ((== p) . tag) pc -select_all_middles :: Patchy p => Bool -> PatchChoices p C(x y) -> PatchChoices p C(x y)-select_all_middles b (PCs e) = PCs (mapFL_FL f e)+selectAllMiddles :: Patchy p => Bool -> PatchChoices p C(x y) -> PatchChoices p C(x y)+selectAllMiddles b (PCs e) = PCs (mapFL_FL f e)     where f (PC tp InMiddle) = PC tp (if b then InLast else InFirst)           f pc = pc  reverse_pc :: Patchy p => PatchChoices p C(x y) -> PatchChoices p C(y x) reverse_pc (PCs e) = PCs $ invert e -force_matching_last :: Patchy p => (FORALL(x y) TaggedPatch p C(x y) -> Bool)+forceMatchingLast :: Patchy p => (FORALL(x y) TaggedPatch p C(x y) -> Bool)                     -> PatchChoices p C(a b) -> PatchChoices p C(a b)-force_matching_last m (PCs e) =+forceMatchingLast m (PCs e) =     let thd (PC (TP t _) _) = t         xs = m2ids m e-        not_needed = case pull_lasts $ set_simplys xs False e of+        not_needed = case pull_lasts $ setSimplys xs InLast e of                      rest :> _ -> mapFL thd rest         ch pc@(PC tp@(TP t _) _)          | t `elem` not_needed = pc          | otherwise = PC tp InLast     in PCs $ mapFL_FL ch e -force_last :: Patchy p => Tag -> PatchChoices p C(x y) -> PatchChoices p C(x y)-force_last p pc = reverse_pc $ force_first p $ reverse_pc pc+forceLast :: Patchy p => Tag -> PatchChoices p C(x y) -> PatchChoices p C(x y)+forceLast p pc = reverse_pc $ forceFirst p $ reverse_pc pc -force_lasts :: Patchy p => [Tag] -> PatchChoices p C(x y) -> PatchChoices p C(x y)-force_lasts ps pc = reverse_pc $ force_firsts ps $ reverse_pc pc+forceLasts :: Patchy p => [Tag] -> PatchChoices p C(x y) -> PatchChoices p C(x y)+forceLasts ps pc = reverse_pc $ forceFirsts ps $ reverse_pc pc -make_uncertain :: Patchy p => Tag -> PatchChoices p C(x y) -> PatchChoices p C(x y)-make_uncertain t (PCs e) = PCs $ mapFL_FL ch e+makeUncertain :: Patchy p => Tag -> PatchChoices p C(x y) -> PatchChoices p C(x y)+makeUncertain t (PCs e) = PCs $ mapFL_FL ch e     where ch pc@(PC x _) = if t == tag x then PC x InMiddle else pc -make_everything_later (PCs e) = PCs $ mapFL_FL ch e+makeEverythingLater :: Patchy p => PatchChoices p C(x y) -> PatchChoices p C(x y)+makeEverythingLater (PCs e) = PCs $ mapFL_FL ch e     where ch (PC tp InMiddle) = PC tp InLast           ch (PC tp InFirst)  = PC tp InMiddle           ch x = x++-- | 'substitute' @(a :||: bs)@ @pcs@ replaces @a@ with @bs@ in @pcs@ preserving the choice+--   associated with @a@+substitute :: forall p C(x y)+            . Patchy p+           => Sealed2 (TaggedPatch p :||: FL (TaggedPatch p))+           -> PatchChoices p C(x y)+           -> PatchChoices p C(x y)+substitute (Sealed2 (tp :||: new_tps)) (PCs pcs) = PCs (concatFL (mapFL_FL translate pcs))+   where translate :: PatchChoice p C(a b) -> FL (PatchChoice p) C(a b)+         translate (PC tp' c)+             | IsEq <- compareTags tp tp' = mapFL_FL (flip PC c) new_tps+             | otherwise = PC tp' c :>: NilFL
src/Darcs/Patch/Commute.lhs view
@@ -24,9 +24,9 @@ #include "gadts.h"  module Darcs.Patch.Commute ( fromPrims,-                             modernize_patch,+                             modernizePatch, #ifndef GADT_WITNESSES-                             merge, elegant_merge,+                             merge, elegantMerge,                              merger, unravel, #endif                              public_unravel, mangle_unravelled,@@ -40,23 +40,23 @@  import Darcs.Patch.FileName ( FileName, fn2fp, fp2fn ) import Darcs.Patch.Info ( invert_name, idpatchinfo )-import Darcs.Patch.Patchy ( Commute(..), Invert(..) )+import Darcs.Patch.Patchy ( Commute(..), Invert(..), toFwdCommute, toRevCommute ) import Darcs.Patch.Core ( Patch(..), Named(..), #ifndef GADT_WITNESSES                           flattenFL,-                          is_merger,+                          isMerger, #endif                           merger_undo,                           join_patchesFL ) import Darcs.Patch.Prim ( Prim(..), FromPrims(..),                           Conflict(..), Effect(..),-                          is_filepatch, sort_coalesceFL,+                          is_filepatch, sortCoalesceFL, #ifndef GADT_WITNESSES                           FilePatchType(..), DirPatchType(..), #else                           FilePatchType(Hunk), #endif-                          is_hunk, modernizePrim )+                          primIsHunk, modernizePrim ) import qualified Data.ByteString.Char8 as BC (pack, last) import qualified Data.ByteString       as B (null, ByteString) import Data.Maybe ( isJust )@@ -67,12 +67,12 @@ import Darcs.Patch.Patchy ( invertRL ) import Darcs.Patch.Show ( showPatch_ ) import Data.List ( nubBy )-import Darcs.Sealed ( unsafeUnseal )+import Darcs.Witnesses.Sealed ( unsafeUnseal ) #endif import Darcs.Utils ( nubsort ) #include "impossible.h"-import Darcs.Sealed ( Sealed(..), mapSeal )-import Darcs.Ordered ( mapFL, mapFL_FL, unsafeCoerceP,+import Darcs.Witnesses.Sealed ( Sealed(..), mapSeal )+import Darcs.Witnesses.Ordered ( mapFL, mapFL_FL, unsafeCoerceP,                              FL(..), RL(..),                              (:/\:)(..), (:<)(..), (:\/:)(..), (:>)(..), #ifndef GADT_WITNESSES@@ -196,17 +196,18 @@     merge (NamedP n1 d1 p1 :\/: NamedP n2 d2 p2)         = case merge (p1 :\/: p2) of           (p2' :/\: p1') -> NamedP n2 d2 p2' :/\: NamedP n1 d1 p1'-    list_touched_files (NamedP _ _ p) = list_touched_files p+    listTouchedFiles (NamedP _ _ p) = listTouchedFiles p+    hunkMatches f (NamedP _ _ p) = hunkMatches f p  instance Conflict p => Conflict (Named p) where-    list_conflicted_files (NamedP _ _ p) = list_conflicted_files p-    resolve_conflicts (NamedP _ _ p) = resolve_conflicts p+    listConflictedFiles (NamedP _ _ p) = listConflictedFiles p+    resolveConflicts (NamedP _ _ p) = resolveConflicts p  everything_else_commute :: MaybeCommute -> CommuteFunction everything_else_commute c x = eec x     where     eec :: CommuteFunction-    eec (PP px :< PP py) = toPerhaps $ do y' :< x' <- commutex (px :< py)+    eec (PP px :< PP py) = toPerhaps $ do x' :> y' <- commute (py :> px)                                           return (PP y' :< PP x')     eec (ComP NilFL :< p1) = Succeeded (unsafeCoerceP p1 :< (ComP NilFL))     eec (p2 :< ComP NilFL) = Succeeded (ComP NilFL :< unsafeCoerceP p2)@@ -260,30 +261,36 @@     merge (y :\/: z) = #ifndef GADT_WITNESSES         case actual_merge (y:\/:z) of-        y' -> case commutex (y' :< z) of+        y' -> case commute (z :> y') of                          Nothing -> bugDoc $ text "merge_patches bug"                                     $$ showPatch_ y                                    $$ showPatch_ z                                    $$ showPatch_ y'-                         Just (z' :< _) -> z' :/\: y'+                         Just (_ :> z') -> z' :/\: y' #else-        case elegant_merge (y:\/:z) of+        case elegantMerge (y:\/:z) of         Just (z' :/\: y') -> z' :/\: y'         Nothing -> undefined #endif-    commutex x = toMaybe $ msum [speedy_commute x,+    commute x = toMaybe $ msum+                  [toFwdCommute speedy_commute x, #ifndef GADT_WITNESSES-                                 clever_commute merger_commute x,+                   toFwdCommute (clever_commute merger_commute) x, #endif-                                 everything_else_commute commutex x-                        ]+                   toFwdCommute (everything_else_commute (toRevCommute commute)) x+                  ]     -- Recurse on everything, these are potentially spoofed patches-    list_touched_files (ComP ps) = nubsort $ concat $ mapFL list_touched_files ps-    list_touched_files (Merger _ _ p1 p2) = nubsort $ list_touched_files p1-                                            ++ list_touched_files p2-    list_touched_files c@(Regrem _ _ _ _) = list_touched_files $ invert c-    list_touched_files (PP p) = list_touched_files p+    listTouchedFiles (ComP ps) = nubsort $ concat $ mapFL listTouchedFiles ps+    listTouchedFiles (Merger _ _ p1 p2) = nubsort $ listTouchedFiles p1+                                            ++ listTouchedFiles p2+    listTouchedFiles c@(Regrem _ _ _ _) = listTouchedFiles $ invert c+    listTouchedFiles (PP p) = listTouchedFiles p +    hunkMatches f (ComP ps) = or $ mapFL (hunkMatches f) ps+    hunkMatches f (Merger _ _ p1 p2) = hunkMatches f p1 || hunkMatches f p2+    hunkMatches f c@(Regrem _ _ _ _) = hunkMatches f $ invert c+    hunkMatches f (PP p) = hunkMatches f p+ commute_no_merger :: MaybeCommute commute_no_merger x = #ifndef GADT_WITNESSES@@ -306,19 +313,19 @@ #ifndef GADT_WITNESSES commute_recursive_merger :: (Patch :< Patch) -> Perhaps (Patch :< Patch) commute_recursive_merger (p@(Merger _ _ p1 p2) :< pA) = toPerhaps $-  do (pA' :< _) <- commutex (undo :< pA)-     commutex (invert undo :< pA')-     (pAmid :< _) <- commutex (invert p1 :< pA)-     (pAx :< p1') <- commutex (p1 :< pAmid)+  do (_ :> pA') <- commute (pA :> undo)+     commute (pA' :> invert undo)+     (_ :> pAmid) <- commute (pA :> invert p1)+     (p1' :> pAx) <- commute (pAmid :> p1)      assert (pAx `unsafeCompare` pA)-     (_ :<p2') <- commutex (p2 :< pAmid)-     (_ :< p2o) <- commutex (p2' :< invert pAmid)+     (p2' :> _) <- commute (pAmid :> p2)+     (p2o :> _) <- commute (invert pAmid :> p2')      assert (p2o `unsafeCompare` p2)      let p' = if unsafeCompare p1' p1 && unsafeCompare p2' p2               then p               else merger "0.0" p1' p2'          undo' = merger_undo p'-     (_ :< pAo) <- commutex (pA' :< undo')+     (pAo :> _) <- commute (undo' :> pA')      assert (pAo `unsafeCompare` pA)      return (pA' :< p')     where undo = merger_undo p@@ -327,19 +334,19 @@ other_commute_recursive_merger :: (Patch :< Patch) -> Perhaps (Patch :< Patch) other_commute_recursive_merger (pA':< p_old@(Merger _ _ p1' p2')) =   toPerhaps $-  do (_ :< pA) <- commutex (pA' :< merger_undo p_old)-     (p1 :< pAmid) <- commutex (pA :< p1')-     (pAmido :< _) <- commutex (invert p1 :< pA)+  do (pA :> _) <- commute (merger_undo p_old :> pA')+     (pAmid :> p1) <- commute (p1' :> pA)+     (_ :> pAmido) <- commute (pA :> invert p1)      assert (pAmido `unsafeCompare` pAmid)-     (_ :< p2) <- commutex (p2' :< invert pAmid)-     (_ :< p2o') <- commutex (p2 :< pAmid)+     (p2 :> _) <- commute (invert pAmid :> p2')+     (p2o' :> _) <- commute (pAmid :> p2)      assert (p2o' `unsafeCompare` p2')      let p = if p1 `unsafeCompare` p1' && p2 `unsafeCompare` p2'              then p_old              else merger "0.0" p1 p2          undo = merger_undo p      assert (not $ pA `unsafeCompare` p1) -- special case here...-     (pAo' :< _) <- commutex (undo :<pA)+     (_ :> pAo') <- commute (pA :> undo)      assert (pAo' `unsafeCompare` pA')      return (p :< pA) other_commute_recursive_merger _ = Unknown@@ -411,16 +418,14 @@  \begin{code} -elegant_merge :: (Patch :\/: Patch) C(x y)+elegantMerge :: (Patch :\/: Patch) C(x y)               -> Maybe ((Patch :/\: Patch) C(x y))-elegant_merge (p1 :\/: p2) =-  case commutex (p1 :< invert p2) of-  Just (ip2':<p1') -> case commutex (p1' :< p2) of-                      Nothing -> Nothing -- should be a redundant check-                      Just (_:<p1o) -> if unsafeCompare p1o p1-                                       then Just (invert ip2' :/\: p1')-                                       else Nothing-  Nothing -> Nothing+elegantMerge (p1 :\/: p2) = do+  p1' :> ip2' <- commute (invert p2 :> p1)+  p1o :> _    <- commute (p2 :> p1')+  if unsafeCompare p1o p1 -- should be a redundant check+    then return $ invert ip2' :/\: p1'+    else Nothing  \end{code} @@ -455,7 +460,7 @@                               join_patchesFL $ merge_patches_after_patch p1s p2 actual_merge (p1 :\/: ComP p2s) = seq p1 $ merge_patch_after_patches p1 p2s -actual_merge (p1 :\/: p2) = case elegant_merge (p1:\/:p2) of+actual_merge (p1 :\/: p2) = case elegantMerge (p1:\/:p2) of                             Just (_ :/\: p1') -> p1'                             Nothing -> merger "0.0" p2 p1 @@ -466,8 +471,8 @@  merge_patches_after_patch :: FL Patch -> Patch -> FL Patch merge_patches_after_patch p2s p =-    case commutex (merge_patch_after_patches p p2s :< join_patchesFL p2s) of-    Just (ComP p2s':< _) -> p2s'+    case commute (join_patchesFL p2s :> merge_patch_after_patches p p2s) of+    Just (_ :> ComP p2s') -> p2s'     _ -> impossible #endif \end{code}@@ -602,8 +607,8 @@  put_before :: Patch -> FL Patch -> Maybe (FL Patch) put_before p1 (p2:>:p2s) =-    do p2':<p1' <- commutex (invert p1:<p2)-       commutex (p1:<p2')+    do p1' :> p2' <- commute (p2 :> invert p1)+       commute (p2' :> p1)        (p2' :>:) `fmap` put_before p1' p2s put_before _ NilFL = Just NilFL #endif@@ -636,7 +641,7 @@   commute_no_conflicts (x:>y) = do x' :< y' <- commute_no_merger (y :< x)                                    return (y':>x') #ifndef GADT_WITNESSES-  resolve_conflicts patch = rcs NilFL $ reverseFL $ flattenFL patch+  resolveConflicts patch = rcs NilFL $ reverseFL $ flattenFL patch     where rcs :: FL Patch C(w y) -> RL Patch C(x y) -> [[Sealed (FL Prim C(w))]]           rcs _ NilRL = []           rcs passedby (p@(Merger _ _ _ _):<:ps) =@@ -649,7 +654,7 @@           rcs passedby (p:<:ps) = seq passedby $                                   rcs (p :>: passedby) ps #else-  resolve_conflicts = bug "haven't defined resolve_conflicts with type witnesses."+  resolveConflicts = bug "haven't defined resolveConflicts with type witnesses." #endif  public_unravel :: Patch C(x y) -> [Sealed (FL Prim C(y))]@@ -662,7 +667,7 @@ #ifndef GADT_WITNESSES unravel :: Patch -> [FL Prim] unravel p = nubBy unsafeCompare $-            map (sort_coalesceFL . concatFL . mapFL_FL effect) $+            map (sortCoalesceFL . concatFL . mapFL_FL effect) $             get_supers $ map reverseRL $ new_ur p $ unwind p  get_supers :: [FL Patch] -> [FL Patch]@@ -695,7 +700,7 @@           unwindings = true_unwind fake_p           p = Merger identity unwindings p1 p2           undoit =-              case (is_merger p1, is_merger p2) of+              case (isMerger p1, isMerger p2) of               (True ,True ) -> join_patchesFL $ invertRL $ tailRL $ unwind p                                where tailRL (_:<:t) = t                                      tailRL _ = impossible@@ -721,8 +726,8 @@ only_hunks pss = fn2fp f /= "" && all oh pss     where f = get_a_filename pss           oh :: Sealed (FL Prim C(x)) -> Bool-          oh (Sealed (p:>:ps)) = is_hunk p &&-                                 [fn2fp f] == list_touched_files p &&+          oh (Sealed (p:>:ps)) = primIsHunk p &&+                                 [fn2fp f] == listTouchedFiles p &&                                  oh (Sealed ps)           oh (Sealed NilFL) = True @@ -785,17 +790,17 @@                    else ""  instance Effect Patch where-    effect p@(Merger _ _ _ _) = sort_coalesceFL $ effect $ merger_undo p+    effect p@(Merger _ _ _ _) = sortCoalesceFL $ effect $ merger_undo p     effect p@(Regrem _ _ _ _) = invert $ effect $ invert p     effect (ComP ps) = concatFL $ mapFL_FL effect ps     effect (PP p) = effect p     isHunk p = do PP p' <- return p                   isHunk p' -modernize_patch :: Patch C(x y) -> Patch C(x y)-modernize_patch p@(Merger _ _ _ _) = fromPrims $ effect p-modernize_patch p@(Regrem _ _ _ _) = fromPrims $ effect p-modernize_patch (ComP ps) = ComP $ filtermv $ mapFL_FL modernize_patch ps+modernizePatch :: Patch C(x y) -> Patch C(x y)+modernizePatch p@(Merger _ _ _ _) = fromPrims $ effect p+modernizePatch p@(Regrem _ _ _ _) = fromPrims $ effect p+modernizePatch (ComP ps) = ComP $ filtermv $ mapFL_FL modernizePatch ps     where filtermv :: FL Patch C(x y) -> FL Patch C(x y) #ifndef GADT_WITNESSES           filtermv (PP (Move _ b):>:xs) | hasadd xs = filtermv xs@@ -809,7 +814,7 @@           filtermv (x:>:xs) = x :>: filtermv xs           filtermv NilFL = NilFL -modernize_patch (PP p) = fromPrims $ modernizePrim p+modernizePatch (PP p) = fromPrims $ modernizePrim p  instance FromPrims Patch where     fromPrims (p :>: NilFL) = PP p@@ -828,7 +833,7 @@               $$ vcat (mapRL showPatch_ $ unwind p)  new_ur op ps =-    case filter (is_merger.headRL) $ head_permutationsRL ps of+    case filter (isMerger.headRL) $ head_permutationsRL ps of     [] -> [ps]     (ps':_) -> new_ur op ps' 
src/Darcs/Patch/Core.lhs view
@@ -28,10 +28,10 @@ module Darcs.Patch.Core        ( Patch(..), Named(..),          join_patchesFL, concatFL, flattenFL,-         nullP, is_null_patch, infopatch,+         nullP, isNullPatch, infopatch,          n_fn,          adddeps, namepatch, anonymous,-         merger_undo, is_merger,+         merger_undo, isMerger,          getdeps,          patch2patchinfo, patchname, patchcontents,        )@@ -40,7 +40,7 @@ import Prelude hiding ( pi ) import Darcs.Patch.Info ( PatchInfo, patchinfo, make_filename ) import Darcs.Patch.Patchy ( Patchy )-import Darcs.Ordered+import Darcs.Witnesses.Ordered import Darcs.Patch.Prim ( Prim(..), FromPrim(..), Effect(effect, effectRL), n_fn ) #include "impossible.h" @@ -61,26 +61,34 @@ instance FromPrim Patch where     fromPrim = PP +-- | The @Named@ type adds a patch info about a patch, that is a name. data Named p C(x y) where-    NamedP :: !PatchInfo -> ![PatchInfo] -> !(p C(x y)) -> Named p C(x y)+    NamedP :: !PatchInfo+           -> ![PatchInfo]+           -> !(p C(x y))+           -> Named p C(x y)+-- ^ @NamedP info deps p@ represents patch @p@ with name+-- @info@. @deps@ is a list of dependencies added at the named patch+-- level, compared with the unnamed level (ie, dependencies added with+-- @darcs record --ask-deps@).  instance Effect p => Effect (Named p) where     effect (NamedP _ _ p) = effect p     effectRL (NamedP _ _ p) = effectRL p -is_null_patch :: Patch C(x y) -> Bool-is_null_patch (ComP ps) = and $ mapFL is_null_patch ps-is_null_patch _ = False+isNullPatch :: Patch C(x y) -> Bool+isNullPatch (ComP ps) = and $ mapFL isNullPatch ps+isNullPatch _ = False  nullP :: Patch C(x y) -> EqCheck C(x y) nullP (ComP NilFL) = IsEq nullP (ComP (x:>:xs)) | IsEq <- nullP x = nullP (ComP xs) nullP _ = NotEq -is_merger :: Patch C(a b) -> Bool-is_merger (Merger _ _ _ _) = True-is_merger (Regrem _ _ _ _) = True-is_merger _ = False+isMerger :: Patch C(a b) -> Bool+isMerger (Merger _ _ _ _) = True+isMerger (Regrem _ _ _ _) = True+isMerger _ = False  merger_undo :: Patch C(x y) -> Patch C(x y) merger_undo (Merger undo _ _ _) = undo
src/Darcs/Patch/Depends.hs view
@@ -33,10 +33,10 @@ import Control.Monad ( liftM2 ) import Control.Monad.Error ( Error(..) ) -import Darcs.Patch ( RepoPatch, Named, getdeps, commutex,+import Darcs.Patch ( RepoPatch, Named, getdeps, commute,                      commuteFL,                      patch2patchinfo, merge )-import Darcs.Ordered ( (:\/:)(..), (:<)(..), (:/\:)(..), (:>)(..),+import Darcs.Witnesses.Ordered ( (:\/:)(..), (:<)(..), (:/\:)(..), (:>)(..),                              RL(..), FL(..),                              (+<+),                              reverseFL, mapFL_FL, mapFL, concatReverseFL,@@ -49,15 +49,15 @@ import Darcs.Hopefully ( PatchInfoAnd, piap, info, n2pia,                          hopefully, conscientiously, hopefullyM ) import Darcs.ProgressPatches ( progressRL )-import Darcs.Sealed (Sealed(..), FlippedSeal(..), Sealed2(..)-                    , flipSeal, seal, unseal )+import Darcs.Witnesses.Sealed (Sealed(..), FlippedSeal(..), Sealed2(..)+                    , flipSeal, seal, unseal, mapFlipped ) import Printer ( errorDoc, renderString, ($$), text ) #include "impossible.h"  get_common_and_uncommon :: RepoPatch p => (PatchSet p C(x),PatchSet p C(y)) ->-                           ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))+                           ([PatchInfo],(RL (PatchInfoAnd p) :\/: RL (PatchInfoAnd p)) C(x y)) get_common_and_uncommon_or_missing :: RepoPatch p => (PatchSet p C(x),PatchSet p C(y)) ->-                                      Either PatchInfo ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))+                                      Either PatchInfo ([PatchInfo],(RL (PatchInfoAnd p) :\/: RL (PatchInfoAnd p)) C(x y))  get_common_and_uncommon =      either missingPatchError id . get_common_and_uncommon_err@@ -66,7 +66,7 @@     either (\(MissingPatch x _) -> Left x) Right . get_common_and_uncommon_err  get_common_and_uncommon_err :: RepoPatch p => (PatchSet p C(x),PatchSet p C(y)) ->-                               Either MissingPatch ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))+                               Either MissingPatch ([PatchInfo],(RL (PatchInfoAnd p) :\/: RL (PatchInfoAnd p)) C(x y)) get_common_and_uncommon_err (ps1,ps2) = gcau (optimize_patchset ps1) ps2  {-|@@ -184,15 +184,15 @@ -}  gcau :: forall p C(x y). RepoPatch p => PatchSet p C(x) -> PatchSet p C(y)-     -> Either MissingPatch ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))-gcau NilRL ps2 = return ([], NilRL:<:NilRL :\/: concatRL ps2 :<: NilRL)-gcau ps1 NilRL = return ([], concatRL ps1 :<: NilRL :\/: NilRL:<:NilRL)+     -> Either MissingPatch ([PatchInfo],(RL (PatchInfoAnd p) :\/: RL (PatchInfoAnd p)) C(x y))+gcau NilRL ps2 = return ([], NilRL :\/: concatRL ps2)+gcau ps1 NilRL = return ([], concatRL ps1 :\/: NilRL) gcau (NilRL:<:ps1) ps2 = gcau ps1 ps2 gcau ps1 (NilRL:<:ps2) = gcau ps1 ps2 gcau ((pi1:<:NilRL):<:_) ((pi2:<:NilRL):<:_)  | info pi1 == info pi2  , IsEq <- sloppyIdentity pi1- , IsEq <- sloppyIdentity pi2 = return ([info pi1], NilRL:<:NilRL :\/: unsafeCoerceP (NilRL:<:NilRL))+ , IsEq <- sloppyIdentity pi2 = return ([info pi1], NilRL :\/: unsafeCoerceP NilRL) gcau (orig_ps1:<:orig_ps1s) (orig_ps2:<:orig_ps2s)  = f (lengthRL orig_ps1) (unseal info $ lastRL orig_ps1) (orig_ps1:>:NilFL) orig_ps1s      (lengthRL orig_ps2) (unseal info $ lastRL orig_ps2) (orig_ps2:>:NilFL) orig_ps2s@@ -200,7 +200,7 @@                          lx = last $ concatReverseFL psx   -}           f :: Int -> PatchInfo -> FL (RL (PatchInfoAnd p)) C(r x) -> PatchSet p C(r)             -> Int -> PatchInfo -> FL (RL (PatchInfoAnd p)) C(u y) -> PatchSet p C(u)-            -> Either MissingPatch ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))+            -> Either MissingPatch ([PatchInfo],(RL (PatchInfoAnd p) :\/: RL (PatchInfoAnd p)) C(x y))           f _n1 l1 ps1 _ps1s _n2 l2 ps2 _ps2s            | l1 == l2 = gcau_simple (unsafeCoerceP (concatReverseFL ps1)) (unsafeCoerceP (concatReverseFL ps2))           f n1 l1 ps1 ps1s n2 l2 ps2 ps2s@@ -242,12 +242,12 @@ -- | Filters the common elements from @ps1@ and @ps2@ and returns the simplified sequences. gcau_simple :: RepoPatch p => RL (PatchInfoAnd p) C(x y) -- ^ @ps1@             -> RL (PatchInfoAnd p) C(u v) -- ^ @ps2@-            -> Either MissingPatch ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(y v))+            -> Either MissingPatch ([PatchInfo],(RL (PatchInfoAnd p) :\/: RL (PatchInfoAnd p)) C(y v)) gcau_simple ps1 ps2 = do  FlippedSeal ex1 <- get_extra common ps1  FlippedSeal ex2 <- get_extra common ps2  let ps1' = filter (`elem` common) $ ps1_info- return (ps1', (unsafeCoerceP ex1 :<: NilRL) :\/: ex2 :<: NilRL)+ return (ps1', (unsafeCoerceP ex1 :\/: ex2))   where common   = ps1_info `intersect` mapRL info ps2         ps1_info = mapRL info ps1 @@ -258,7 +258,33 @@     noMsg = bug "MissingPatch doesn't define noMsg."  -- | Returns a sub-sequence from @patches@, where all the elements of @common@ have--- been removed by commuting them out.+--   been removed by commuting them back into the early part of the history.+--+--  An informal illustration of this process as it traverses a mixed list of patches+--  where C and x denote common patches and extra patches accordingly.  Variants of+--  patches obtained through commutation are indicated by letters following the+--  patch name.+--+--  > in: x6 < x5 < C4 < x3 < C2 < x1  skip:           extra:+--  > in:      x5 < C4 < x3 < C2 < x1  skip:           extra:                  x6+--  > in:           C4 < x3 < C2 < x1  skip:           extra:             x5 > x6+--  > in:                x3 < C2 < x1  skip: C4        extra:             x5 > x6+--  > in:                     C2 < x1  skip: C4b       extra:       x3b > x5 > x6+--  > in:                          x1  skip: C2  > C4b extra:       x3b > x5 > x6+--  > in:                              skip: C2b > C4c extra: x1b > x3b > x5 > x6+--+--  This function is undefined if for any reason we fail to commute an extra+--  patch past one of the common ones.  Such a failure would indicate that the+--  common patch depends on the extra one, contradicting the claim that the+--  \"common\" patch is shared with another repository lacking the extra patches.+--  Unfortunately, such cases have crept up in practice.  Some notable cases can+--  be found on the bugtracker as:+--+--   * issue27   - different patches with identical patch info; mistaken identity.+--                 Note how @common@ consists only of a list of 'PatchInfo' which+--                 we trust to uniquely identify such patches.+--+--   * issue1014 - duplicate patches get_extra :: RepoPatch p => [PatchInfo] -- ^ @common@           -> RL (PatchInfoAnd p) C(u x) -- ^ @patches@           -> Either MissingPatch (FlippedSeal (RL (PatchInfoAnd p)) C(y))@@ -313,19 +339,14 @@ get_extra_old common pps =     either missingPatchError id (get_extra common pps) -get_patches_beyond_tag :: RepoPatch p => PatchInfo -> PatchSet p C(x) -> FlippedSeal (RL (RL (PatchInfoAnd p))) C(x)-get_patches_beyond_tag t ((hp:<:NilRL):<:_) | info hp == t = flipSeal $ NilRL :<: NilRL+get_patches_beyond_tag :: RepoPatch p => PatchInfo -> PatchSet p C(x) -> FlippedSeal (RL (PatchInfoAnd p)) C(x)+get_patches_beyond_tag t ((hp:<:NilRL):<:_) | info hp == t = flipSeal NilRL get_patches_beyond_tag t patchset@((hp:<:ps):<:pps) =     if info hp == t     then if get_tags_right patchset == [info hp]-         then flipSeal $ NilRL :<: NilRL -- special case to avoid looking at redundant patches-         else case get_extra_old [t] (concatRL patchset) of-              FlippedSeal x -> flipSeal $ x :<: NilRL-    else hp `prepend` get_patches_beyond_tag t (ps:<:pps)- where- prepend :: (PatchInfoAnd p) C(x y) -> FlippedSeal (RL (RL (PatchInfoAnd p))) C(x) -> FlippedSeal (RL (RL (PatchInfoAnd p))) C(y)- prepend pp (FlippedSeal NilRL)     = flipSeal $ (pp:<:NilRL) :<: NilRL- prepend pp (FlippedSeal (p:<:ps')) = flipSeal $ (pp:<:p)     :<: ps'+         then flipSeal NilRL -- special case to avoid looking at redundant patches+         else get_extra_old [t] (concatRL patchset)+    else mapFlipped (hp:<:) $ get_patches_beyond_tag t (ps:<:pps) get_patches_beyond_tag t (NilRL:<:pps) = get_patches_beyond_tag t pps get_patches_beyond_tag t NilRL = bug $ "tag\n" ++                                  renderString (human_friendly t) ++@@ -367,9 +388,9 @@                      -> FL (PatchInfoAnd p) C(w z)           commute_by NilFL _ = unsafeCoerceP NilFL           commute_by (hpa:>:xs') p =-              case commutex (hopefully hpa :< p) of+              case commute (p :> hopefully hpa) of                 Nothing -> bug "Failure commuting patches in commute_by called by gpit!"-                Just (p':<a') -> (info hpa `piap` a') :>: commute_by xs' p'+                Just (a' :> p') -> (info hpa `piap` a') :>: commute_by xs' p'  get_patches_in_tag t _ = errorDoc $ text "Couldn't read tag"                                  $$ human_friendly t@@ -481,13 +502,12 @@   f common a b = g_s $ gcau_simple a b     where       g_s :: Either MissingPatch-                    ([PatchInfo],(RL (RL (PatchInfoAnd p)) :\/: RL (RL (PatchInfoAnd p))) C(x y))+                    ([PatchInfo],(RL (PatchInfoAnd p) :\/: RL (PatchInfoAnd p)) C(x y))           -> SealedPatchSet p       g_s (Left e) = missingPatchError e-      g_s (Right (_, (a' :<: NilRL) :\/: (b' :<: NilRL))) =+      g_s (Right (_, a' :\/: b')) =           case (merge_sets (a' :\/: b')) of           Sealed a'b' -> seal $ (a'b' +<+ b) :<: common-      g_s _ = impossible  merge_sets :: RepoPatch p => (RL (PatchInfoAnd p) :\/: RL (PatchInfoAnd p)) C(x y) -> Sealed (RL (PatchInfoAnd p) C(y)) merge_sets (l :\/: r) =
src/Darcs/Patch/FileName.hs view
@@ -21,7 +21,7 @@                               fp2fn, fn2fp,                               fn2ps, ps2fn,                               niceps2fn, fn2niceps,-                              break_on_dir, norm_path, own_name, super_name,+                              break_on_dir, norm_path, own_name, superName,                               movedirfilename,                               encode_white, decode_white,                               (///),@@ -30,9 +30,9 @@  import System.IO import Data.Char ( isSpace, chr, ord )-import qualified UTF8 ( encode )+import qualified Codec.Binary.UTF8.String as UTF8 ( encode )+import Codec.Binary.UTF8.Generic ( toString ) import Data.Word ( Word8( ) )-import ByteStringUtils ( unpackPSfromUTF8 ) import qualified Data.ByteString.Char8 as BC (unpack, pack) import qualified Data.ByteString       as B  (ByteString, pack) @@ -66,7 +66,7 @@  {-# INLINE ps2fn #-} ps2fn :: B.ByteString -> FileName-ps2fn ps = FN $ decode_white $ unpackPSfromUTF8 ps+ps2fn ps = FN $ decode_white $ toString ps  -- | 'encode_white' translates whitespace in filenames to a darcs-specific --   format (backslash followed by numerical representation according to 'ord').@@ -98,8 +98,8 @@ own_name :: FileName -> FileName own_name (FN f) = case breakLast '/' f of Nothing -> FN f                                           Just (_,f') -> FN f'-super_name :: FileName -> FileName-super_name fn = case norm_path fn of+superName :: FileName -> FileName+superName fn = case norm_path fn of                 FN f -> case breakLast '/' f of                         Nothing -> FN "."                         Just (d,_) -> FN d
src/Darcs/Patch/Info.hs view
@@ -32,10 +32,11 @@ import qualified Data.ByteString       as B  (length, splitAt, null, drop                                              ,isPrefixOf, tail, concat, ByteString ) import qualified Data.ByteString.Char8 as BC (index, head, unpack, pack, break)+import Data.List( isPrefixOf )  import Printer ( renderString, Doc, packedString,                  empty, ($$), (<>), (<+>), vcat, text, blueText, prefix )-import OldDate ( readUTCDate, showIsoDateTime )+import Darcs.Patch.OldDate ( readUTCDate, showIsoDateTime ) import System.Time ( CalendarTime(ctTZ), calendarTimeToString, toClockTime,                      toCalendarTime ) import System.IO.Unsafe ( unsafePerformIO )@@ -72,7 +73,8 @@ add_junk pinf =     do x <- randomRIO (0,2^(128 ::Integer) :: Integer)        when (_pi_log pinf /= ignore_junk (_pi_log pinf)) $-            do yorn <- promptYorn "Lines beginning with 'Ignore-this: ' will be ignored.\nProceed? "+            do putStrLn "Lines beginning with 'Ignore-this: ' will be ignored."+               yorn <- promptYorn "Proceed? "                when (yorn == 'n') $ fail "User cancelled because of Ignore-this."        return $ pinf { _pi_log = BC.pack (head ignored++showHex x ""):                                  _pi_log pinf }@@ -118,7 +120,7 @@ pi_author = BC.unpack . _pi_author  is_tag :: PatchInfo -> Bool-is_tag pinfo = take 4 (just_name pinfo) == "TAG "+is_tag pinfo = "TAG " `isPrefixOf` just_name pinfo   -- | Note: we ignore timezone information in the date string,
src/Darcs/Patch/Match.lhs view
@@ -35,13 +35,14 @@ import System.IO.Unsafe ( unsafePerformIO )  import Darcs.Hopefully ( PatchInfoAnd, hopefully, info )-import Darcs.Patch ( Patch, Patchy, list_touched_files, patchcontents )+import Darcs.Patch ( Patch, Patchy, hunkMatches, listTouchedFiles, patchcontents ) import Darcs.Patch.Info ( just_name, just_author, make_filename,                           pi_date )-import Darcs.Sealed ( Sealed2(..), seal2 )+import Darcs.Witnesses.Sealed ( Sealed2(..), seal2 ) import DateMatcher ( parseDateMatcher )  import Darcs.Patch.MatchData ( PatchMatch(..), patch_match )+import qualified Data.ByteString.Char8 as BC  -- | A type for predicates over patches which do not care about -- contexts@@ -78,7 +79,7 @@ trivial = const True \end{code} -\paragraph{Match}+\subsection{Match}  Currently \verb!--match! accepts six primitive match types, although there are plans to expand it to match more patterns.  Also, note that the@@ -304,6 +305,9 @@  , ("author", "check a regular expression against the author name"             , ["\"David Roundy\"", "droundy", "droundy@darcs.net"]             , authormatch )+ , ("hunk", "check a regular expression against the contents of a hunk patch"+            , ["foo = 2", "^instance .* Foo where$"]+            , hunkmatch )  , ("hash",  "match the darcs hash for a patch"           ,  ["20040403105958-53a90-c719567e92c3b0ab9eddd5290b705712b8b918ef"]           ,  hashmatch )@@ -327,7 +331,7 @@          <|> between spaces spaces (many $ noneOf " ()")          <?> "string" -mymatch, exactmatch, authormatch, hashmatch, datematch, touchmatch :: Patchy p => String -> MatchFun p+mymatch, exactmatch, authormatch, hunkmatch, hashmatch, datematch, touchmatch :: Patchy p => String -> MatchFun p  mymatch r (Sealed2 hp) = isJust $ matchRegex (mkRegex r) $ just_name (info hp) @@ -335,12 +339,17 @@  authormatch a (Sealed2 hp) = isJust $ matchRegex (mkRegex a) $ just_author (info hp) ++hunkmatch r (Sealed2 hp) = let patch = patchcontents $ hopefully hp+                               regexMatcher = isJust . (matchRegex (mkRegex r) . BC.unpack)+                           in hunkMatches regexMatcher patch+ hashmatch h (Sealed2 hp) = let rh = make_filename (info hp) in                                   (rh == h) || (rh == h++".gz")  datematch d (Sealed2 hp) = let dm = unsafePerformIO $ parseDateMatcher d                                   in dm $ pi_date (info hp) -touchmatch r (Sealed2 hp) = let files = list_touched_files $ patchcontents $ hopefully hp+touchmatch r (Sealed2 hp) = let files = listTouchedFiles $ patchcontents $ hopefully hp                             in or $ map (isJust . matchRegex (mkRegex r)) files \end{code}
src/Darcs/Patch/Non.hs view
@@ -34,15 +34,15 @@ import Data.List ( delete ) import Control.Monad ( liftM ) import Darcs.Patch.Prim ( Prim, FromPrim(..), ToFromPrim(..), Effect(..),-                          showPrim, FileNameFormat(..), sort_coalesceFL )+                          showPrim, FileNameFormat(..), sortCoalesceFL ) import Darcs.Patch.Patchy import Darcs.Patch.ReadMonads ( ParserM, lex_char )-import Darcs.Ordered+import Darcs.Witnesses.Ordered import Darcs.Patch.Read ( readPrim ) import Darcs.Patch.Viewing () import Darcs.Patch.Permutations ( removeFL, commuteWhatWeCanFL )-import Darcs.Show-import Darcs.Sealed ( Sealed(Sealed) )+import Darcs.Witnesses.Show+import Darcs.Witnesses.Sealed ( Sealed(Sealed) ) import Printer ( Doc, empty, vcat, hiddenPrefix, blueText, redText, ($$) )  --import Darcs.ColorPrinter ( traceDoc )@@ -62,7 +62,7 @@     where rns = peekfor "}}" (return []) $                 do Just (Sealed ps) <- readPatch' False                    lex_char ':'-                   Just (Sealed p) <- readPrim NewFormat False+                   Just (Sealed p) <- readPrim NewFormat                    (Non ps p :) `liftM` rns  readNon :: (ReadPatch p, ParserM m) => m (Maybe (Non p C(x)))@@ -90,10 +90,28 @@ class Nonable p where     non :: p C(x y) -> Non p C(x) +-- | 'addP' @x cy@ tries to commute @x@ past @cy@ and always returns some+-- variant @cy'@.  -- commutation suceeds, the variant is just+-- straightforwardly the commuted versian.  If commutation fails, the variant+-- consists of @x@ prepended to the context of @cy@. addP :: (Patchy p, ToFromPrim p) => p C(x y) -> Non p C(y) -> Non p C(x) addP p n | Just n' <- p >* n = n' addP p (Non c x) = Non (p:>:c) x +-- | 'addPs' @xs cy@ commutes as many patches of @xs@ past @cy@ as+--   possible, stopping at the first patch that fails to commute.+--   Note the fact @xs@ is a 'RL'+--+--   Suppose we have+--+--   > x1 x2 x3 [c1 c2 y]+--+--   and that in our example @c1@ fails to commute past @x1@, this+--   function would commute down to+--+--   > x1 [c1'' c2'' y''] x2' x3'+--+--   and return @[x1 c1'' c2'' y'']@ addPs :: (Patchy p, ToFromPrim p) => RL p C(x y) -> Non p C(y) -> Non p C(x) addPs NilRL n = n addPs (p:<:ps) n = addPs ps $ addP p n@@ -112,7 +130,7 @@ remNonHelper [] x = NilFL :> x remNonHelper ns (c:>:cs)     | non c `elem` ns = case remNonHelper (map (addP $ invert c) $ delete (non c) ns) cs of-                        a :> z -> sort_coalesceFL (effect c+>+a) :> z+                        a :> z -> sortCoalesceFL (effect c+>+a) :> z     | otherwise = case commuteWhatWeCanFL (c :> cs) of                   b :> c' :> d ->                       case remNonHelper ns b of
+ src/Darcs/Patch/OldDate.hs view
@@ -0,0 +1,350 @@+-- Copyright (C) 2003 Peter Simons+-- Copyright (C) 2003,2008 David Roundy+--+-- This program is free software; you can redistribute it and/or modify+-- it under the terms of the GNU General Public License as published by+-- the Free Software Foundation; either version 2, or (at your option)+-- any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++-- This module is intended to provide backwards-compatibility in the parsing+-- of darcs patches.  In other words: don't change it, new features don't get+-- added here.  The only user should be Darcs.Patch.Info.++module Darcs.Patch.OldDate ( readUTCDate, showIsoDateTime ) where++import Text.ParserCombinators.Parsec+import System.Time+import Data.Char ( toUpper, isDigit )+import Control.Monad ( liftM, liftM2 )+import qualified Data.ByteString.Char8 as B+import Data.Maybe ( fromMaybe )++-- | Read/interpret a date string, assuming UTC if timezone+--   is not specified in the string+readUTCDate :: String -> CalendarTime+readUTCDate = readDate 0++readDate :: Int -> String -> CalendarTime+readDate tz d =+             case parseDate tz d of+             Left e -> error e+             Right ct -> ct++parseDate :: Int -> String -> Either String CalendarTime+parseDate tz d =+              if length d >= 14 && B.all isDigit bd+              then Right $+                   CalendarTime (readI $ B.take 4 bd)+                                (toEnum $ (+ (-1)) $ readI $ B.take 2 $ B.drop 4 bd)+                                (readI $ B.take 2 $ B.drop 6 bd) -- Day+                                (readI $ B.take 2 $ B.drop 8 bd) -- Hour+                                (readI $ B.take 2 $ B.drop 10 bd) -- Minute+                                (readI $ B.take 2 $ B.drop 12 bd) -- Second+                                0 Sunday 0 -- Picosecond, weekday and day of year unknown+                                "GMT" 0 False+              else let dt = do { x <- date_time tz; eof; return x }+                   in case parse dt "" d of+                      Left e -> Left $ "bad date: "++d++" - "++show e+                      Right ct -> Right ct+  where bd = B.pack (take 14 d)+        readI s = fst $ fromMaybe (error "parseDate: invalid date") (B.readInt s)++showIsoDateTime :: CalendarTime -> String+showIsoDateTime ct = concat [ show $ ctYear ct+                            , twoDigit . show . (+1) . fromEnum $ ctMonth ct+                            , twoDigit . show $ ctDay ct+                            , twoDigit . show $ ctHour ct+                            , twoDigit . show $ ctMin ct+                            , twoDigit . show $ ctSec ct+                            ]+    where twoDigit []          = undefined+          twoDigit x@(_:[])    = '0' : x+          twoDigit x@(_:_:[])  = x+          twoDigit _           = undefined++----- Parser Combinators ---------------------------------------------++-- |Case-insensitive variant of Parsec's 'char' function.++caseChar        :: Char -> GenParser Char a Char+caseChar c       = satisfy (\x -> toUpper x == toUpper c)++-- |Case-insensitive variant of Parsec's 'string' function.++caseString      :: String -> GenParser Char a ()+caseString cs    = mapM_ caseChar cs <?> cs++-- |Match a parser at least @n@ times.++manyN           :: Int -> GenParser a b c -> GenParser a b [c]+manyN n p+    | n <= 0     = return []+    | otherwise  = liftM2 (++) (count n p) (many p)++-- |Match a parser at least @n@ times, but no more than @m@ times.++manyNtoM        :: Int -> Int -> GenParser a b c -> GenParser a b [c]+manyNtoM n m p+    | n < 0      = return []+    | n > m      = return []+    | n == m     = count n p+    | n == 0     = foldr (<|>) (return []) (map (\x -> try $ count x p) (reverse [1..m]))+    | otherwise  = liftM2 (++) (count n p) (manyNtoM 0 (m-n) p)+++----- Date/Time Parser -----------------------------------------------++date_time :: Int -> CharParser a CalendarTime+date_time tz =+            choice [try $ cvs_date_time tz,+                    try $ iso8601_date_time tz,+                    old_date_time]++cvs_date_time :: Int -> CharParser a CalendarTime+cvs_date_time tz =+                do y <- year+                   char '/'+                   mon <- month_num +                   char '/'+                   d <- day+                   my_spaces+                   h <- hour+                   char ':'+                   m <- minute+                   char ':'+                   s <- second+                   z <- option tz $ my_spaces >> zone+                   return (CalendarTime y mon d h m s 0 Monday 0 "" z False)++old_date_time   :: CharParser a CalendarTime+old_date_time    = do wd <- day_name+                      my_spaces+                      mon <- month_name+                      my_spaces+                      d <- day+                      my_spaces+                      h <- hour+                      char ':'+                      m <- minute+                      char ':'+                      s <- second+                      my_spaces+                      z <- zone+                      my_spaces+                      y <- year+                      return (CalendarTime y mon d h m s 0 wd 0 "" z False)++{- FIXME: In case you ever want to use this outside of darcs, you should note +   that this implementation of ISO 8601 is not complete.  ++   reluctant to implement (ambiguous!): +     * years > 9999  +     * truncated representations with implied century (89 for 1989) +   unimplemented: +     * repeated durations (not relevant)+     * lowest order component fractions in intervals+     * negative dates (BC)                    +   unverified or too relaxed:+     * the difference between 24h and 0h+     * allows stuff like 2005-1212; either you use the hyphen all the way +       (2005-12-12) or you don't use it at all (20051212), but you don't use+       it halfway, likewise with time +     * No bounds checking whatsoever on intervals! +       (next action: read iso doc to see if bounds-checking required?) -}+iso8601_date_time   :: Int -> CharParser a CalendarTime+iso8601_date_time localTz = try $ +  do d <- iso8601_date+     t <- option id $ try $ do optional $ oneOf " T" +                               iso8601_time  +     return $ t $ d { ctTZ = localTz }++iso8601_date :: CharParser a CalendarTime+iso8601_date = +  do d <- calendar_date <|> week_date <|> ordinal_date+     return $ foldr ($) nullCalendar d+  where +    calendar_date = -- yyyy-mm-dd+      try $ do d <- optchain year_ [ (dash, month_), (dash, day_) ]+               -- allow other variants to be parsed correctly +               notFollowedBy (digit <|> char 'W')+               return d+    week_date = --yyyy-Www-dd +      try $ do yfn <- year_+               optional dash+               char 'W'+               -- offset human 'week 1' -> computer 'week 0'+               w'  <- (\x -> x-1) `liftM` two_digits+               wd  <- option 1 $ do { optional dash; n_digits 1 }+               let y = yfn nullCalendar+                   firstDay = ctWDay y+               -- things that make this complicated+               -- 1. iso8601 weeks start from Monday; Haskell weeks start from Sunday+               -- 2. the first week is the one that contains at least Thursday+               --    if the year starts after Thursday, then some days of the year+               --    will have already passed before the first week+               let afterThursday = firstDay == Sunday || firstDay > Thursday+                   w  = if afterThursday then w'+1 else w'+                   diff c = c { ctDay = (7 * w) + wd - (fromEnum firstDay) }+               return [(toUTCTime.toClockTime.diff.yfn)]+    ordinal_date = -- yyyy-ddd+      try $ optchain year_ [ (dash, yearDay_) ]+    --+    year_  = try $ do y <- four_digits <?> "year (0000-9999)"+                      return $ \c -> c { ctYear = y }+    month_ = try $ do m <- two_digits <?> "month (1 to 12)"+                      -- we (artificially) use ctPicosec to indicate+                      -- whether the month has been specified.+                      return $ \c -> c { ctMonth = intToMonth m, ctPicosec = 0 }+    day_   = try $ do d <- two_digits <?> "day in month (1 to 31)"+                      return $ \c -> c { ctDay = d }+    yearDay_ = try $ do d <- n_digits 3 <?> "day in year (1 to 366)"+                        return $ \c -> c { ctYDay = d }+    dash = char '-'++-- we return a function which sets the time on another calendar+iso8601_time :: CharParser a (CalendarTime -> CalendarTime)+iso8601_time = try $+  do ts <- optchain hour_ [ (colon     , min_)+                          , (colon     , sec_)+                          , (oneOf ",.", pico_) ] +     z  <- option id $ choice [ zulu , offset ]+     return $ foldr (.) id (z:ts)+  where +    hour_ = do h <- two_digits+               return $ \c -> c { ctHour = h }+    min_  = do m <- two_digits+               return $ \c -> c { ctMin = m }+    sec_  = do s <- two_digits+               return $ \c -> c { ctSec = s }+    pico_ = do digs <- many digit+               let picoExp = 12+                   digsExp = length digs+               let frac | null digs = 0+                        | digsExp > picoExp = read $ take picoExp digs+                        | otherwise = 10 ^ (picoExp - digsExp) * (read digs)+               return $ \c -> c { ctPicosec = frac }+    zulu   = do { char 'Z'; return (\c -> c { ctTZ = 0 }) }+    offset = do sign <- choice [ do { char '+' >> return   1  }+                               , do { char '-' >> return (-1) } ]+                h <- two_digits+                m <- option 0 $ do { optional colon; two_digits }+                return $ \c -> c { ctTZ = sign * 60 * ((h*60)+m) }+    colon = char ':'++optchain :: CharParser a b -> [(CharParser a c, CharParser a b)] -> CharParser a [b]+optchain p next = try $ +  do r1 <- p+     r2 <- case next of +           [] -> return []+           ((sep,p2):next2) -> option [] $ do { optional sep; optchain p2 next2 }+     return (r1:r2)++n_digits :: Int -> CharParser a Int +n_digits n = read `liftM` count n digit++two_digits, four_digits :: CharParser a Int+two_digits = n_digits 2+four_digits = n_digits 4++my_spaces :: CharParser a String+my_spaces = manyN 1 $ char ' '++day_name        :: CharParser a Day+day_name         = choice+                       [ caseString "Mon"       >> return Monday+                       , try (caseString "Tue") >> return Tuesday+                       , caseString "Wed"       >> return Wednesday+                       , caseString "Thu"       >> return Thursday+                       , caseString "Fri"       >> return Friday+                       , try (caseString "Sat") >> return Saturday+                       , caseString "Sun"       >> return Sunday+                       ]++year            :: CharParser a Int+year             = four_digits++month_num       :: CharParser a Month+month_num = do mn <- manyNtoM 1 2 digit +               return $ intToMonth $ (read mn :: Int)++intToMonth :: Int -> Month+intToMonth 1 = January+intToMonth 2 = February+intToMonth 3 = March+intToMonth 4 = April+intToMonth 5 = May+intToMonth 6 = June+intToMonth 7 = July+intToMonth 8 = August+intToMonth 9 = September+intToMonth 10 = October+intToMonth 11 = November+intToMonth 12 = December+intToMonth _  = error "invalid month!"++month_name      :: CharParser a Month+month_name       = choice+                       [ try (caseString "Jan") >> return January+                       , caseString "Feb"       >> return February+                       , try (caseString "Mar") >> return March+                       , try (caseString "Apr") >> return April+                       , caseString "May"       >> return May+                       , try (caseString "Jun") >> return June+                       , caseString "Jul"       >> return July+                       , caseString "Aug"       >> return August+                       , caseString "Sep"       >> return September+                       , caseString "Oct"       >> return October+                       , caseString "Nov"       >> return November+                       , caseString "Dec"       >> return December+                       ]++day             :: CharParser a Int+day              = do d <- manyNtoM 1 2 digit+                      return (read d :: Int)++hour            :: CharParser a Int+hour             = two_digits++minute          :: CharParser a Int+minute           = two_digits++second          :: CharParser a Int+second           = two_digits++zone            :: CharParser a Int+zone             = choice+                       [ do { char '+'; h <- hour; m <- minute; return (((h*60)+m)*60) }+                       , do { char '-'; h <- hour; m <- minute; return (-((h*60)+m)*60) }+                       , mkZone "UTC"  0+                       , mkZone "UT"  0+                       , mkZone "GMT" 0+                       , mkZone "EST" (-5)+                       , mkZone "EDT" (-4)+                       , mkZone "CST" (-6)+                       , mkZone "CDT" (-5)+                       , mkZone "MST" (-7)+                       , mkZone "MDT" (-6)+                       , mkZone "PST" (-8)+                       , mkZone "PDT" (-7)+                       , mkZone "CEST" 2+                       , mkZone "EEST" 3+                         -- if we don't understand it, just give a GMT answer...+                       , do { manyTill (oneOf $ ['a'..'z']++['A'..'Z']++[' '])+                                       (lookAhead space_digit);+                              return 0 }+                       ]+     where mkZone n o  = try $ do { caseString n; return (o*60*60) }+           space_digit = try $ do { char ' '; oneOf ['0'..'9'] }++nullCalendar :: CalendarTime +nullCalendar = CalendarTime 0 January 0 0 0 0 1 Sunday 0 "" 0 False
src/Darcs/Patch/Patchy.hs view
@@ -25,7 +25,7 @@                             Apply, apply, applyAndTryToFix, applyAndTryToFixFL,                             mapMaybeSnd,                             Commute(..), commuteFL, commuteRL, commuteRLFL,-                            mergeFL,+                            mergeFL, toFwdCommute, toRevCommute,                             ShowPatch(..),                             ReadPatch, readPatch', bracketedFL, peekfor,                             Invert(..), invertFL, invertRL ) where@@ -35,10 +35,10 @@ import Data.Word ( Word8 ) import Data.List ( nub ) -import Darcs.SlurpDirectory ( Slurpy )-import Darcs.Sealed ( Sealed(..), Sealed2(..), seal2 )+import Storage.Hashed.Monad( TreeIO )+import Darcs.Witnesses.Sealed ( Sealed(..), Sealed2(..), seal2 ) import Darcs.Patch.ReadMonads ( ParserM, lex_eof, peek_input, my_lex, work, alter_input )-import Darcs.Ordered+import Darcs.Witnesses.Ordered import Printer ( Doc, (<>), text ) import Darcs.Lock ( writeDocBinFile, gzWriteDocFile ) import Darcs.IO ( WriteableDirectory )@@ -69,22 +69,35 @@ mapMaybeSnd f (Just (a,b)) = Just (a,f b) mapMaybeSnd _ Nothing = Nothing +-- | Things that can commute. class Commute p where     commute :: (p :> p) C(x y) -> Maybe ((p :> p) C(x y))-    commutex :: (p :< p) C(x y) -> Maybe ((p :< p) C(x y))-    commute (x :> y) = do x' :< y' <- commutex (y :< x)-                          return (y' :> x')-    commutex (x :< y) = do x' :> y' <- commute (y :> x)-                           return (y' :< x')     merge :: (p :\/: p) C(x y) -> (p :/\: p) C(x y)-    list_touched_files :: p C(x y) -> [FilePath]+    listTouchedFiles :: p C(x y) -> [FilePath]+    hunkMatches :: (BC.ByteString -> Bool) -> p C(x y) -> Bool +-- | Swaps the ordered pair type so that commute can be+-- called directly.+toFwdCommute :: (Commute p, Commute q, Monad m)+             => ((p :< q) C(x y) -> m ((q :< p) C(x y)))+             -> (q :> p) C(x y) -> m ((p :> q) C(x y))+toFwdCommute c (x :> y) = do x' :< y' <- c (y :< x)+                             return (y' :> x')++-- | Swaps the ordered pair type from the order expected+-- by commute to the reverse order.+toRevCommute :: (Commute p, Commute q, Monad m)+             => ((p :> q) C(x y) -> m ((q :> p) C(x y)))+             -> (q :< p) C(x y) -> m ((p :< q) C(x y))+toRevCommute c (x :< y) = do x' :> y' <- c (y :> x)+                             return (y' :< x')+ class Commute p => ShowPatch p where     showPatch :: p C(x y) -> Doc     showNicely :: p C(x y) -> Doc     showNicely = showPatch-    showContextPatch :: Slurpy -> p C(x y) -> Doc-    showContextPatch _ p = showPatch p+    showContextPatch :: p C(x y) -> TreeIO Doc+    showContextPatch p = return $ showPatch p     description :: p C(x y) -> Doc     description = showPatch     summary :: p C(x y) -> Doc@@ -131,7 +144,8 @@     merge ((x:>:xs) :\/: ys) = fromJust $ do ys' :/\: x' <- return $ mergeFL (x :\/: ys)                                              xs' :/\: ys'' <- return $ merge (ys' :\/: xs)                                              return (ys'' :/\: (x' :>: xs'))-    list_touched_files xs = nub $ concat $ mapFL list_touched_files xs+    listTouchedFiles xs = nub $ concat $ mapFL listTouchedFiles xs+    hunkMatches f = or . mapFL (hunkMatches f)  mergeFL :: Commute p => (p :\/: FL p) C(x y) -> (FL p :/\: p) C(x y) mergeFL (p :\/: NilFL) = NilFL :/\: p@@ -216,7 +230,8 @@                             return (reverseFL fys' :> xs')     merge (x :\/: y) = case merge (reverseRL x :\/: reverseRL y) of                        (ry' :/\: rx') -> reverseFL ry' :/\: reverseFL rx'-    list_touched_files = list_touched_files . reverseRL+    listTouchedFiles = listTouchedFiles . reverseRL+    hunkMatches f = hunkMatches f . reverseRL instance ReadPatch p => ReadPatch (RL p) where     readPatch' want_eof = do Just (Sealed fl) <- readPatch' want_eof                              return $ Just $ Sealed $ reverseFL fl
src/Darcs/Patch/Permutations.hs view
@@ -1,4 +1,5 @@ -- Copyright (C) 2002-2003 David Roundy+-- Copyright (C) 2009 Ganesh Sittampalam -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by@@ -27,11 +28,14 @@                                   partitionFL, partitionRL,                                   head_permutationsFL, head_permutationsRL,                                   headPermutationsFL,-                                  remove_subsequenceFL, remove_subsequenceRL ) where+                                  remove_subsequenceFL, remove_subsequenceRL,+                                  partitionConflictingFL,+                                  CommuteFn, selfCommuter, commuterIdRL,+                                ) where  import Data.Maybe ( catMaybes ) import Darcs.Patch.Patchy ( Commute, commute, commuteFL, commuteRL, Invert(..), invertFL, invertRL )-import Darcs.Ordered+import Darcs.Witnesses.Ordered #include "impossible.h"  -- |split an 'FL' into "left" and "right" lists according to a predicate, using commutation as necessary.@@ -230,3 +234,37 @@     sloppyIdentity NilRL = IsEq     sloppyIdentity (x:<:xs) | IsEq <- sloppyIdentity x = sloppyIdentity xs     sloppyIdentity _ = NotEq++-- |CommuteFn is the basis of a general framework for building up commutation+-- operations between different patch types in a generic manner. Unfortunately+-- type classes are not well suited to the problem because of the multiple possible+-- routes by which the commuter for (FL p1, FL p2) can be built out of the+-- commuter for (p1, p2) - and more complicated problems when we start building+-- multiple constructors on top of each other. The type class resolution machinery+-- really can't cope with selecting some route, because it doesn't know that all+-- possible routes should be equivalent.+type CommuteFn p1 p2 = FORALL(x y) (p1 :> p2) C(x y) -> Maybe ((p2 :> p1) C(x y))++-- |Build a commuter between a patch and itself using the operation from the type class.+selfCommuter :: Commute p => CommuteFn p p+selfCommuter = commute++commuterIdRL :: CommuteFn p1 p2 -> CommuteFn p1 (RL p2)+commuterIdRL _ (x :> NilRL) = return (NilRL :> x)+commuterIdRL commuter (x :> (y :<: ys))+  = do ys' :> x' <- commuterIdRL commuter (x :> ys)+       y' :> x'' <- commuter (x' :> y)+       return ((y' :<: ys') :> x'')++-- |Partition a list into the patches that commute with the given patch and those that don't (including dependencies)+partitionConflictingFL :: (Commute p1, Invert p1) => CommuteFn p1 p2 -> FL p1 C(x y) -> p2 C(x z) -> (FL p1 :> FL p1) C(x y)+partitionConflictingFL _ NilFL _ = (NilFL :> NilFL)+partitionConflictingFL commuter (x :>: xs) y =+   case commuter (invert x :> y) of+     Nothing -> case commuteWhatWeCanFL (x :> xs) of+                 xs_ok :> x' :> xs_deps ->+                   case partitionConflictingFL commuter xs_ok y of+                     xs_clean :> xs_conflicts -> xs_clean :> (xs_conflicts +>+ (x' :>: xs_deps))+     Just (y' :> _) ->+       case partitionConflictingFL commuter xs y' of+          xs_clean :> xs_conflicts -> (x :>: xs_clean) :> xs_conflicts
src/Darcs/Patch/Prim.lhs view
@@ -26,15 +26,15 @@        ( Prim(..), IsConflictedPrim(IsC), ConflictState(..), showPrim,          DirPatchType(..), FilePatchType(..),          CommuteFunction, Perhaps(..),-         null_patch, nullP, is_null_patch,+         null_patch, nullP, isNullPatch,          is_identity,          formatFileName, FileNameFormat(..),          adddir, addfile, binary, changepref,          hunk, move, rmdir, rmfile, tokreplace,-         is_addfile, is_hunk, is_binary, is_setpref,-         is_similar, is_adddir, is_filepatch,-         canonize, try_to_shrink, modernizePrim,-         subcommutes, sort_coalesceFL, join,+         primIsAddfile, primIsHunk, primIsBinary, primIsSetpref,+         isSimilar, primIsAdddir, is_filepatch,+         canonize, tryToShrink, modernizePrim,+         subcommutes, sortCoalesceFL, join, canonizeFL,          try_tok_internal,          try_shrinking_inverse,          n_fn,@@ -56,14 +56,14 @@  import Darcs.Patch.FileName ( FileName, fn2ps, fn2fp, fp2fn, norm_path,                               movedirfilename, encode_white )-import Darcs.Ordered-import Darcs.Sealed ( Sealed, unseal )-import Darcs.Patch.Patchy ( Invert(..), Commute(..) )+import Darcs.Witnesses.Ordered+import Darcs.Witnesses.Sealed ( Sealed, unseal )+import Darcs.Patch.Patchy ( Invert(..), Commute(..), toFwdCommute, toRevCommute ) import Darcs.Patch.Permutations () -- for Invert instance of FL-import Darcs.Show+import Darcs.Witnesses.Show import Darcs.Utils ( nubsort ) import Lcs ( getChanges )-import RegChars ( regChars )+import Darcs.Patch.RegChars ( regChars ) import Printer ( Doc, vcat, packedString, Color(Cyan,Magenta), lineColor,                  text, userchunk, invisibleText, invisiblePS, blueText,                  ($$), (<+>), (<>), prefix, userchunkPS,@@ -97,11 +97,11 @@ null_patch :: Prim C(x x) null_patch = Identity -is_null_patch :: Prim C(x y) -> Bool-is_null_patch (FP _ (Binary x y)) = B.null x && B.null y-is_null_patch (FP _ (Hunk _ [] [])) = True-is_null_patch Identity = True-is_null_patch _ = False+isNullPatch :: Prim C(x y) -> Bool+isNullPatch (FP _ (Binary x y)) = B.null x && B.null y+isNullPatch (FP _ (Hunk _ [] [])) = True+isNullPatch Identity = True+isNullPatch _ = False  nullP :: Prim C(x y) -> EqCheck C(x y) nullP = sloppyIdentity@@ -119,30 +119,30 @@ -- | Tells you if two patches are in the same category, human-wise. -- Currently just returns true if they are filepatches on the same -- file.-is_similar :: Prim C(x y) -> Prim C(a b) -> Bool-is_similar (FP f _) (FP f' _) = f == f'-is_similar (DP f _) (DP f' _) = f == f'-is_similar _ _ = False+isSimilar :: Prim C(x y) -> Prim C(a b) -> Bool+isSimilar (FP f _) (FP f' _) = f == f'+isSimilar (DP f _) (DP f' _) = f == f'+isSimilar _ _ = False -is_addfile :: Prim C(x y) -> Bool-is_addfile (FP _ AddFile) = True-is_addfile _ = False+primIsAddfile :: Prim C(x y) -> Bool+primIsAddfile (FP _ AddFile) = True+primIsAddfile _ = False -is_adddir :: Prim C(x y) -> Bool-is_adddir (DP _ AddDir) = True-is_adddir _ = False+primIsAdddir :: Prim C(x y) -> Bool+primIsAdddir (DP _ AddDir) = True+primIsAdddir _ = False -is_hunk :: Prim C(x y) -> Bool-is_hunk (FP _ (Hunk _ _ _)) = True-is_hunk _ = False+primIsHunk :: Prim C(x y) -> Bool+primIsHunk (FP _ (Hunk _ _ _)) = True+primIsHunk _ = False -is_binary :: Prim C(x y) -> Bool-is_binary (FP _ (Binary _ _)) = True-is_binary _ = False+primIsBinary :: Prim C(x y) -> Bool+primIsBinary (FP _ (Binary _ _)) = True+primIsBinary _ = False -is_setpref :: Prim C(x y) -> Bool-is_setpref (ChangePref _ _ _) = True-is_setpref _ = False+primIsSetpref :: Prim C(x y) -> Bool+primIsSetpref (ChangePref _ _ _) = True+primIsSetpref _ = False  addfile :: FilePath -> Prim C(x y) rmfile :: FilePath -> Prim C(x y)@@ -406,19 +406,19 @@     toPerhaps $ cs (patches :< patch) >>= sc     where cs :: ((FL Prim) :< Prim) C(x y) -> Maybe ((Prim :< (FL Prim)) C(x y))           cs (NilFL :< p1) = return (p1 :< NilFL)-          cs (p:>:ps :< p1) = do p1' :< p' <- commutex (p :< p1)+          cs (p:>:ps :< p1) = do p' :> p1' <- commute (p1 :> p)                                  p1'' :< ps' <- cs (ps :< p1')                                  return (p1'' :< p':>:ps')           sc :: (Prim :< (FL Prim)) C(x y) -> Maybe ((Prim :< Prim) C(x y))-          sc (p1 :< ps) = scFL $ p1 :< (sort_coalesceFL ps)+          sc (p1 :< ps) = scFL $ p1 :< (sortCoalesceFL ps)             where scFL :: (Prim :< (FL Prim)) C(x y)                        -> Maybe ((Prim :< Prim) C(x y))                   scFL (p1' :< (p :>: NilFL)) = return (p1' :< p)                   scFL (p1' :< ps') = return (p1' :< Split ps') commute_split _ = Unknown -try_to_shrink :: FL Prim C(x y) -> FL Prim C(x y)-try_to_shrink = mapPrimFL try_harder_to_shrink+tryToShrink :: FL Prim C(x y) -> FL Prim C(x y)+tryToShrink = mapPrimFL try_harder_to_shrink  mapPrimFL :: (FORALL(x y) FL Prim C(x y) -> FL Prim C(x y))              -> FL Prim C(w z) -> FL Prim C(w z)@@ -462,7 +462,7 @@  try_to_shrink2 :: FL Prim C(x y) -> FL Prim C(x y) try_to_shrink2 psold =-    let ps = sort_coalesceFL psold+    let ps = sortCoalesceFL psold         ps_shrunk = shrink_a_bit ps                     in     if lengthFL ps_shrunk < lengthFL ps@@ -492,17 +492,33 @@ try_one sofar p (p1:>:ps) =     case coalesce (p1 :< p) of     Just p' -> Just (reverseRL sofar +>+ p':>:NilFL +>+ ps)-    Nothing -> case commutex (p1 :< p) of+    Nothing -> case commute (p :> p1) of                Nothing -> Nothing-               Just (p' :< p1') -> try_one (p1':<:sofar) p' ps+               Just (p1' :> p') -> try_one (p1':<:sofar) p' ps --- | 'sort_coalesceFL' @ps@ coalesces as many patches in @ps@ as+-- | 'canonizeFL' @ps@ puts a sequence of primitive patches into+-- canonical form. Even if the patches are just hunk patches,+-- this is not necessarily the same set of results as you would get+-- if you applied the sequence to a specific tree and recalculated+-- a diff.+--+-- Note that this process does not preserve the commutation behaviour+-- of the patches and is therefore not appropriate for use when+-- working with already recorded patches (unless doing amend-record+-- or the like).+canonizeFL :: FL Prim C(x y) -> FL Prim C(x y)+-- Running canonize twice is apparently necessary to fix issue525;+-- would be nice to understand why.+canonizeFL = concatFL . mapFL_FL canonize . sortCoalesceFL .+             concatFL . mapFL_FL canonize++-- | 'sortCoalesceFL' @ps@ coalesces as many patches in @ps@ as --   possible, sorting the results according to the scheme defined --   in 'comparePrim'-sort_coalesceFL :: FL Prim C(x y) -> FL Prim C(x y)-sort_coalesceFL = mapPrimFL sort_coalesceFL2+sortCoalesceFL :: FL Prim C(x y) -> FL Prim C(x y)+sortCoalesceFL = mapPrimFL sort_coalesceFL2 --- | The heart of "sort_coalesceFL"+-- | The heart of "sortCoalesceFL" sort_coalesceFL2 :: FL Prim C(x y) -> FL Prim C(x y) sort_coalesceFL2 NilFL = NilFL sort_coalesceFL2 (x:>:xs) | IsEq <- nullP x = sort_coalesceFL2 xs@@ -535,8 +551,8 @@       Just new' | IsEq <- nullP new' -> Right ps'                 | otherwise -> Right $ either id id $ push_coalesce_patch new' ps'       Nothing -> if comparePrim new p == LT then Left (new:>:ps)-                            else case commutex (p :< new) of-                                 Just (new' :< p') ->+                            else case commute (new :> p) of+                                 Just (p' :> new') ->                                      case push_coalesce_patch new' ps' of                                      Right r -> Right $ either id id $                                                 push_coalesce_patch p' r@@ -628,20 +644,29 @@  instance Commute Prim where     merge (y :\/: z) =-        case elegant_merge (y:\/:z) of+        case elegantMerge (y:\/:z) of         Just (z' :/\: y') -> z' :/\: y'         Nothing -> error "Commute Prim merge"-    commutex x = toMaybe $ msum [speedy_commute x,-                                 everything_else_commute x-                                ]+    commute x = toMaybe $ msum [toFwdCommute speedy_commute x,+                                toFwdCommute everything_else_commute x+                               ]     -- Recurse on everything, these are potentially spoofed patches-    list_touched_files (Move f1 f2) = map fn2fp [f1, f2]-    list_touched_files (Split ps) = nubsort $ concat $ mapFL list_touched_files ps-    list_touched_files (FP f _) = [fn2fp f]-    list_touched_files (DP d _) = [fn2fp d]-    list_touched_files (ChangePref _ _ _) = []-    list_touched_files Identity = []+    listTouchedFiles (Move f1 f2) = map fn2fp [f1, f2]+    listTouchedFiles (Split ps) = nubsort $ concat $ mapFL listTouchedFiles ps+    listTouchedFiles (FP f _) = [fn2fp f]+    listTouchedFiles (DP d _) = [fn2fp d]+    listTouchedFiles (ChangePref _ _ _) = []+    listTouchedFiles Identity = [] +    hunkMatches f (FP _ (Hunk _ remove add)) = anyMatches remove || anyMatches add+        where anyMatches = foldr ((||) . f) False+    hunkMatches _ (FP _ _) = False+    hunkMatches f (Split ps) = or $ mapFL (hunkMatches f) ps+    hunkMatches _ (DP _ _) = False+    hunkMatches _ (ChangePref _ _ _) = False+    hunkMatches _ Identity = False+    hunkMatches _ (Move _ _) = False+ is_filepatch :: Prim C(x y) -> Maybe FileName is_filepatch (FP f _) = Just f is_filepatch _ = Nothing@@ -690,12 +715,12 @@     [("speedy_commute", speedy_commute),      ("commute_filedir", clever_commute commute_filedir),      ("commute_filepatches", clever_commute commute_filepatches),-     ("commutex", toPerhaps . commutex)+     ("commutex", toPerhaps . toRevCommute commute)     ] -elegant_merge :: (Prim :\/: Prim) C(x y)+elegantMerge :: (Prim :\/: Prim) C(x y)               -> Maybe ((Prim :/\: Prim) C(x y))-elegant_merge (p1 :\/: p2) =+elegantMerge (p1 :\/: p2) =     do p1':>ip2' <- commute (invert p2 :> p1)        -- The following should be a redundant check        p1o:>_ <- commute (p2 :> p1')@@ -711,7 +736,7 @@ old and new version of a file. \begin{code} canonize :: Prim C(x y) -> FL Prim C(x y)-canonize (Split ps) = sort_coalesceFL ps+canonize (Split ps) = sortCoalesceFL ps canonize p | IsEq <- is_identity p = NilFL canonize (FP f (Hunk line old new)) = canonizeHunk f line old new canonize p = p :>: NilFL@@ -998,11 +1023,11 @@     joinPatches = concatRL . reverseFL  class (Invert p, Commute p, Effect p) => Conflict p where-    list_conflicted_files :: p C(x y) -> [FilePath]-    list_conflicted_files p =-        nubsort $ concatMap (unseal list_touched_files) $ concat $ resolve_conflicts p-    resolve_conflicts :: p C(x y) -> [[Sealed (FL Prim C(y))]]-    resolve_conflicts _ = []+    listConflictedFiles :: p C(x y) -> [FilePath]+    listConflictedFiles p =+        nubsort $ concatMap (unseal listTouchedFiles) $ concat $ resolveConflicts p+    resolveConflicts :: p C(x y) -> [[Sealed (FL Prim C(y))]]+    resolveConflicts _ = []     -- | If 'commute_no_conflicts' @x :> y@ succeeds, we know that that @x@ commutes     --   past @y@ without any conflicts.   This function is useful for patch types     --   for which 'commute' is defined to always succeed; so we need some way to@@ -1045,14 +1070,14 @@            IsEq <- return $ ix'' =\/= invert x'            return (y':>x')     conflictedEffect :: p C(x y) -> [IsConflictedPrim]-    conflictedEffect x = case list_conflicted_files x of+    conflictedEffect x = case listConflictedFiles x of                          [] -> mapFL (IsC Okay) $ effect x                          _ -> mapFL (IsC Conflicted) $ effect x  instance Conflict p => Conflict (FL p) where-    list_conflicted_files = nubsort . concat . mapFL list_conflicted_files-    resolve_conflicts NilFL = []-    resolve_conflicts x = resolve_conflicts $ reverseFL x+    listConflictedFiles = nubsort . concat . mapFL listConflictedFiles+    resolveConflicts NilFL = []+    resolveConflicts x = resolveConflicts $ reverseFL x     commute_no_conflicts (NilFL :> x) = Just (x :> NilFL)     commute_no_conflicts (x :> NilFL) = Just (NilFL :> x)     commute_no_conflicts (xs :> ys) = do ys' :> rxs' <- commute_no_conflictsRLFL (reverseFL xs :> ys)@@ -1060,13 +1085,13 @@     conflictedEffect = concat . mapFL conflictedEffect  instance Conflict p => Conflict (RL p) where-    list_conflicted_files = nubsort . concat . mapRL list_conflicted_files-    resolve_conflicts x = rcs x NilFL+    listConflictedFiles = nubsort . concat . mapRL listConflictedFiles+    resolveConflicts x = rcs x NilFL         where rcs :: RL p C(x y) -> FL p C(y w) -> [[Sealed (FL Prim C(w))]]               rcs NilRL _ = []-              rcs (p:<:ps) passedby | (_:_) <- resolve_conflicts p =+              rcs (p:<:ps) passedby | (_:_) <- resolveConflicts p =                   case commute_no_conflictsFL (p:>passedby) of-                    Just (_:> p') -> resolve_conflicts p' ++ rcs ps (p:>:passedby)+                    Just (_:> p') -> resolveConflicts p' ++ rcs ps (p:>:passedby)                     Nothing -> rcs ps (p:>:passedby)               rcs (p:<:ps) passedby = seq passedby $ rcs ps (p:>:passedby)     commute_no_conflicts (NilRL :> x) = Just (x :> NilRL)@@ -1096,7 +1121,7 @@              | otherwise = p :>: NilFL     effectRL p | IsEq <- sloppyIdentity p = NilRL                | otherwise = p :<: NilRL-    isHunk p = if is_hunk p then Just p else Nothing+    isHunk p = if primIsHunk p then Just p else Nothing  instance Conflict Prim 
src/Darcs/Patch/Properties.lhs view
@@ -42,13 +42,13 @@                                 join_inverses, join_commute ) where  import Control.Monad ( msum, mplus )-import Darcs.Show ( Show2(..) )+import Darcs.Witnesses.Show ( Show2(..) ) import Darcs.Patch.Patchy import Darcs.Patch.Prim import Darcs.Patch () import Darcs.Patch.Read ( readPatch )-import Darcs.Ordered-import Darcs.Sealed ( Sealed(Sealed) )+import Darcs.Witnesses.Ordered+import Darcs.Witnesses.Sealed ( Sealed(Sealed) ) import Printer ( Doc, renderPS, redText, greenText, ($$) ) --import Darcs.ColorPrinter ( traceDoc ) \end{code}
src/Darcs/Patch/Read.hs view
@@ -44,8 +44,8 @@                                parse_strictly, peek_input, lex_string, lex_eof, my_lex) #include "impossible.h" import Darcs.Patch.Patchy ( ReadPatch, readPatch', bracketedFL )-import Darcs.Ordered ( FL(..) )-import Darcs.Sealed ( Sealed(..), seal, mapSeal )+import Darcs.Witnesses.Ordered ( FL(..) )+import Darcs.Witnesses.Sealed ( Sealed(..), seal, mapSeal )  readPatch :: ReadPatch p => B.ByteString -> Maybe (Sealed (p C(x )), B.ByteString) readPatch ps = case parse_strictly (readPatch' False) ps of@@ -60,10 +60,10 @@           _ -> return Nothing  instance ReadPatch Prim where- readPatch' w = readPrim OldFormat w+ readPatch' _ = readPrim OldFormat -readPrim :: ParserM m => FileNameFormat -> Bool -> m (Maybe (Sealed (Prim C(x ))))-readPrim x _+readPrim :: ParserM m => FileNameFormat -> m (Maybe (Sealed (Prim C(x ))))+readPrim x    = do s <- peek_input         case liftM (BC.unpack . fst) $ my_lex s of           Just "{}" ->         do work my_lex@@ -95,7 +95,7 @@  read_patches :: ParserM m => FileNameFormat -> String -> Bool -> m (Sealed (FL Prim C(x ))) read_patches x str want_eof- = do mp <- readPrim x False+ = do mp <- readPrim x       case mp of           Nothing -> do unit <- lex_string str                         case unit of
src/Darcs/Patch/Real.hs view
@@ -33,7 +33,7 @@                           IsConflictedPrim(..), ConflictState(..) ) import Darcs.Patch.Read ( readPrim ) import Darcs.Patch.Patchy-import Darcs.Ordered+import Darcs.Witnesses.Ordered --import Darcs.Patch.Read () --import Darcs.Patch.Viewing () --import Darcs.Patch.Apply ()@@ -45,11 +45,11 @@ import Darcs.Patch.Permutations ( commuteWhatWeCanFL, commuteWhatWeCanRL,                                   genCommuteWhatWeCanRL,                                   removeRL, removeFL, remove_subsequenceFL )-import qualified Data.ByteString.Char8 as BC ( unpack )-import Darcs.Patch.ReadMonads (work, peek_input, my_lex )+import qualified Data.ByteString.Char8 as BC ( ByteString, unpack )+import Darcs.Patch.ReadMonads ( work, peek_input, my_lex ) import Darcs.Utils ( nubsort )-import Darcs.Sealed ( FlippedSeal(..), Sealed(Sealed), mapSeal )-import Darcs.Show+import Darcs.Witnesses.Sealed ( FlippedSeal(..), Sealed(Sealed), mapSeal )+import Darcs.Witnesses.Show import Printer ( Doc, renderString, blueText, redText, (<+>), ($$) ) import Darcs.ColorPrinter ( errorDoc, assertDoc ) --import Printer ( greenText )@@ -291,7 +291,7 @@     conflictedEffect (Conflictor _ _ (Non _ x)) = [IsC Conflicted x]     conflictedEffect (InvConflictor _ _ _) = impossible     conflictedEffect (Normal x) = [IsC Okay x]-    resolve_conflicts (Conflictor ix xx x) = [mangle_unravelled unravelled : unravelled]+    resolveConflicts (Conflictor ix xx x) = [mangle_unravelled unravelled : unravelled]             where unravelled = nub $ filter isn $ map (`merge_with` (x:ix++nonxx)) (x:ix++nonxx)                   nonxx = nonxx_ (nonxx_aux ix xx)                   nonxx_aux :: [Non RealPatch C(x)] -> FL Prim C(x y) -> RL RealPatch C(x y)@@ -303,7 +303,7 @@                   isn :: Sealed (FL p C(x)) -> Bool                   isn (Sealed NilFL) = False                   isn _ = True-    resolve_conflicts _ = []+    resolveConflicts _ = []      -- cA     commute_no_conflicts (Duplicate x :> Duplicate y) = Just (Duplicate y :> Duplicate x)@@ -406,8 +406,11 @@     where nix = Normal $ invert x  nonTouches :: Non RealPatch C(x) -> [FilePath]-nonTouches (Non c x) = list_touched_files (c +>+ fromPrim x :>: NilFL)+nonTouches (Non c x) = listTouchedFiles (c +>+ fromPrim x :>: NilFL) +nonHunkMatches :: (BC.ByteString -> Bool) -> Non RealPatch C(x) -> Bool+nonHunkMatches f (Non c x) = hunkMatches f c || hunkMatches f x+ toNons :: (Conflict p, Patchy p, ToFromPrim p, Nonable p) => FL p C(x y) -> [Non p C(x)] toNons xs = map lastNon $ initsFL xs     where lastNon :: (Conflict p, Patchy p, Nonable p) => Sealed ((p :> FL p) C(x)) -> Non p C(x)@@ -592,14 +595,20 @@             Nothing -> impossible pullInContext fromNons --    merge _ = error "haven't finished fixing merge" -    list_touched_files (Duplicate p) = nonTouches p-    list_touched_files (Etacilpud p) = nonTouches p-    list_touched_files (Normal p) = list_touched_files p-    list_touched_files (Conflictor x c p) =-        nubsort $ concatMap nonTouches x ++ list_touched_files c ++ nonTouches p-    list_touched_files (InvConflictor x c p) =-        nubsort $ concatMap nonTouches x ++ list_touched_files c ++ nonTouches p+    listTouchedFiles (Duplicate p) = nonTouches p+    listTouchedFiles (Etacilpud p) = nonTouches p+    listTouchedFiles (Normal p) = listTouchedFiles p+    listTouchedFiles (Conflictor x c p) =+        nubsort $ concatMap nonTouches x ++ listTouchedFiles c ++ nonTouches p+    listTouchedFiles (InvConflictor x c p) =+        nubsort $ concatMap nonTouches x ++ listTouchedFiles c ++ nonTouches p +    hunkMatches f (Duplicate p) = nonHunkMatches f p+    hunkMatches f (Etacilpud p) = nonHunkMatches f p+    hunkMatches f (Normal p) = hunkMatches f p+    hunkMatches f (Conflictor x c p) = or [or $ map (nonHunkMatches f) x, hunkMatches f c, nonHunkMatches f p]+    hunkMatches f (InvConflictor x c p) = or [or $ map (nonHunkMatches f) x, hunkMatches f c, nonHunkMatches f p]+ {- all_conflicts_withFL :: FL Prim C(x y) -> [Non RealPatch C(x)]                      -> ([Non RealPatch C(x)], [Non RealPatch C(x)])@@ -714,11 +723,11 @@         showPatch cs $$         blueText "]" $$         showNon p-    showContextPatch s (Normal p) = showContextPatch s p-    showContextPatch _ c = showPatch c+    showContextPatch (Normal p) = showContextPatch p+    showContextPatch c = return $ showPatch c  instance ReadPatch RealPatch where- readPatch' want_eof =+ readPatch' _ =      do s <- peek_input         case fmap (BC.unpack . fst) $ my_lex s of           Just "duplicate" ->@@ -744,7 +753,7 @@                  Just (Sealed ps) <- bracketedFL (fromIntegral $ fromEnum '[') (fromIntegral $ fromEnum ']')                  Just p <- readNon                  return $ Just $ Sealed $ InvConflictor i ps p-          _ -> do mp <- readPrim NewFormat want_eof+          _ -> do mp <- readPrim NewFormat                   case mp of                     Just p -> return $ Just $ Normal `mapSeal` p                     Nothing -> return Nothing
+ src/Darcs/Patch/RegChars.hs view
@@ -0,0 +1,75 @@+-- Copyright (C) 2003 David Roundy+--+-- This program is free software; you can redistribute it and/or modify+-- it under the terms of the GNU General Public License as published by+-- the Free Software Foundation; either version 2, or (at your option)+-- any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.+++module Darcs.Patch.RegChars ( regChars,+                ) where++(&&&) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)+(&&&) a b c = a c && b c++(|||) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)+(|||) a b c = a c || b c++{-# INLINE regChars #-}++-- | 'regChars' returns a filter function that tells if a char is a member+-- of the regChar expression or not. The regChar expression is basically a+-- set of chars, but it can contain ranges with use of the '-' (dash), and+-- it can also be specified as a complement set by prefixing with '^'+-- (caret). The dash and caret, as well as the backslash, can all be+-- escaped with a backslash to suppress their special meaning.+-- +-- NOTE: The '.' (dot) is allowed to be escaped. It has no special meaning+-- if it is not escaped, but the default 'filename_toks' in+-- Darcs.Commands.Replace uses an escaped dot (WHY?).++regChars :: String -> (Char -> Bool)+regChars ('^':cs) = not . normalRegChars (unescapeChars cs)+regChars ('\\':'^':cs) = normalRegChars $ unescapeChars $ '^':cs+regChars cs = normalRegChars $ unescapeChars cs++{-# INLINE unescapeChars #-}++-- | 'unescapeChars' unescapes whitespace, which is escaped in the replace+-- patch file format. It will also unescape escaped carets, which is useful+-- for escaping a leading caret that should not invert the regChars. All+-- other escapes are left for the unescaping in 'normalRegChars'.++unescapeChars :: String -> String+unescapeChars ('\\':'n':cs) = '\n' : unescapeChars cs+unescapeChars ('\\':'t':cs) = '\t' : unescapeChars cs+unescapeChars ('\\':'^':cs) = '^' : unescapeChars cs+unescapeChars (c:cs) = c : unescapeChars cs+unescapeChars [] = []++{-# INLINE normalRegChars #-}++-- | 'normalRegChars' assembles the filter function. It handles special+-- chars, and also unescaping of escaped special chars. If a non-special+-- char is still escaped by now we get a failure.++normalRegChars :: String -> (Char -> Bool)+normalRegChars ('\\':'.':cs) = (=='.') ||| normalRegChars cs+normalRegChars ('\\':'-':cs) = (=='-') ||| normalRegChars cs+normalRegChars ('\\':'\\':cs) = (=='\\') ||| normalRegChars cs+normalRegChars ('\\':c:_) = error $ "'\\"++[c]++"' not supported."+normalRegChars (c1:'-':c2:cs) = ((>= c1) &&& (<= c2)) ||| normalRegChars cs+normalRegChars (c:cs) = (== c) ||| normalRegChars cs+normalRegChars [] = \_ -> False++
src/Darcs/Patch/Set.hs view
@@ -23,8 +23,8 @@ module Darcs.Patch.Set ( PatchSet, SealedPatchSet ) where  import Darcs.Hopefully ( PatchInfoAnd )-import Darcs.Ordered ( RL )-import Darcs.Sealed ( Sealed )+import Darcs.Witnesses.Ordered ( RL )+import Darcs.Witnesses.Sealed ( Sealed )  -- | A PatchSet is in reverse order, plus has information about which -- tags are clean, meaning all patches applied prior to them are in
src/Darcs/Patch/Show.lhs view
@@ -31,7 +31,7 @@ import Darcs.Patch.Core ( Patch(..) ) import Darcs.Patch.Prim ( showPrim, FileNameFormat(..) ) import Darcs.Patch.Info ( PatchInfo, showPatchInfo )-import Darcs.Ordered ( FL(NilFL), mapFL )+import Darcs.Witnesses.Ordered ( FL(NilFL), mapFL ) #include "gadts.h" \end{code} 
+ src/Darcs/Patch/Split.hs view
@@ -0,0 +1,147 @@+{-# LANGUAGE CPP, RankNTypes, GADTs #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+-- Copyright (C) 2009 Ganesh Sittampalam+--+-- Permission is hereby granted, free of charge, to any person+-- obtaining a copy of this software and associated documentation+-- files (the "Software"), to deal in the Software without+-- restriction, including without limitation the rights to use, copy,+-- modify, merge, publish, distribute, sublicense, and/or sell copies+-- of the Software, and to permit persons to whom the Software is+-- furnished to do so, subject to the following conditions:+--+-- The above copyright notice and this permission notice shall be+-- included in all copies or substantial portions of the Software.+--+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+-- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+-- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+-- SOFTWARE.++module Darcs.Patch.Split ( Splitter(..), rawSplitter, noSplitter, primSplitter ) where++import Data.List ( intersperse )++import Darcs.Witnesses.Ordered+import Darcs.Witnesses.Sealed++import Darcs.Patch.Patchy ( ReadPatch(..), ShowPatch(..), Invert(..) )+import Darcs.Patch.Prim ( Prim(..), FilePatchType(..), canonize, canonizeFL )+import Darcs.Patch.ReadMonads ( parse_strictly )+import Darcs.Patch.Read ()+import Darcs.Patch.Viewing ()++import Printer ( renderPS )++import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC++#include "gadts.h"++-- |A splitter is something that can take a patch and (possibly) render it+-- as text in some format of its own choosing.+-- This text can then be presented to the user for editing, and the result+-- given to the splitter for parsing.+-- If the parse succeeds, the result is a list of patches that could replace+-- the original patch in any context.+-- Typically this list will contain the changed version of the patch, along+-- with fixup pieces to ensure that the overall effect of the list is the same+-- as the original patch.+-- The individual elements of the list can then be offered separately to the+-- user, allowing them to accept some and reject others.+--+-- There's no immediate application for a splitter for anything other than+-- Prim (you shouldn't go editing named patches, you'll break them!)+-- However you might want to compose splitters for FilePatchType to make+-- splitters for Prim etc, and the generality doesn't cost anything.+data Splitter p+  = Splitter {+              applySplitter :: FORALL(x y) p C(x y)+                              -> Maybe (B.ByteString,+                                        B.ByteString -> Maybe (FL p C(x y)))+              -- canonization is needed to undo the effects of splitting+              -- Typically, the list returned by applySplitter will not+              -- be in the simplest possible form (since the user will have+              -- deliberately added extra stuff). Once the user has selected+              -- the pieces they want, we need to make sure that we eliminate+              -- any remaining redundancy in the selected pieces, otherwise+              -- we might record (or whatever) a rather strange looking patch.+              -- This hook allows the splitter to provide an appropriate+              -- function for doing this.+             ,canonizeSplit :: FORALL(x y) FL p C(x y) -> FL p C(x y)+             }++{- Some facts that probably ought to be true about splitters: should make some QC+properties++applySplitter p = Just (bs, f) ==> f bs == Just (p :>: NilFL)++applySplitter p = Just (bs, f) ; f bs' = Just ps ==> canonizeSplit ps = p :>: NilFL++-}++-- Does not canonize as there is no generic operation to do this.+withEditedHead :: Invert p => p C(x y) -> p C(x z) -> FL p C(x y)+withEditedHead p res = res :>: invert res :>: p :>: NilFL++-- |This generic splitter just lets the user edit the printed representation of the patch+-- Should not be used expect for testing and experimentation.+rawSplitter :: (ShowPatch p, ReadPatch p, Invert p) => Splitter p+rawSplitter = Splitter {+                  applySplitter =+                     \p -> Just (renderPS . showPatch $ p,+                                 \str -> case parse_strictly (readPatch' False) str of+                                          Just (Just (Sealed res), _) -> Just (withEditedHead p res)+                                          _ -> Nothing+                                )+                 ,canonizeSplit = id+                }++-- |Never splits. In other code we normally pass around Maybe Splitter instead of using this+-- as the default, because it saves clients that don't care about splitting from having to+-- import this module just to get noSplitter.+noSplitter :: Splitter p+noSplitter = Splitter { applySplitter = const Nothing, canonizeSplit = id }+++doPrimSplit :: Prim C(x y) -> Maybe (B.ByteString, B.ByteString -> Maybe (FL Prim C(x y)))+doPrimSplit (FP fn (Hunk n before after))+ = Just (B.concat $ intersperse (BC.pack "\n") $ concat+           [ helptext+           , [mkSep " BEFORE (reference) =========================="]+           , before+           , [mkSep "=== AFTER (edit) ============================="]+           , after+           , [mkSep "=== (edit above) ============================="]+           ],+         \bs -> do let ls = BC.split '\n' bs+                   (_, ls2) <- breakSep ls        -- before+                   (before', ls3) <- breakSep ls2 -- after 1+                   (after', _) <- breakSep ls3    -- after 2+                   return (hunk before before' +>+ hunk before' after' +>+ hunk after' after))+    where sep = BC.pack "=========================="+          helptext = map BC.pack [ "Interactive hunk edit:"+                                 , " - Edit the section marked 'AFTER'"+                                 , " - Arbitrary editing is supported"+                                 , " - This will only affect the patch, not your working copy"+                                 , " - Hints:"+                                 , "   - To split added text, delete the part you want to postpone"+                                 , "   - To split removed text, copy back the part you want to retain"+                                 , ""+                                 ]+          hunk b a = canonize (FP fn (Hunk n b a))+          mkSep s = BC.append sep (BC.pack s)+          breakSep xs = case break (sep `BC.isPrefixOf`) xs of+                           (_, []) -> Nothing+                           (ys, _:zs) -> Just (ys, zs)+doPrimSplit _ = Nothing++-- |Split a primitive hunk patch up+-- by allowing the user to edit both the before and after lines, then insert fixup patches+-- to clean up the mess.+primSplitter :: Splitter Prim+primSplitter = Splitter { applySplitter = doPrimSplit, canonizeSplit = canonizeFL }
src/Darcs/Patch/TouchesFiles.hs view
@@ -24,67 +24,69 @@                       select_touching,                       deselect_not_touching, select_not_touching,                     ) where-import Data.List ( sort )+import Data.List ( sort, isSuffixOf )  import Darcs.Patch.Choices ( PatchChoices, Tag, TaggedPatch,-                             patch_choices, tag, get_choices,-                      force_firsts, force_lasts, tp_patch,+                             patchChoices, tag, getChoices,+                      forceFirsts, forceLasts, tpPatch,                     )-import Darcs.Patch ( Patchy, apply_to_filepaths, list_touched_files )-import Darcs.Ordered ( FL(..), (:>)(..), mapFL_FL, (+>+) )-import Darcs.Sealed ( Sealed, seal )+import Darcs.Patch ( Patchy, applyToFilepaths, listTouchedFiles )+import Darcs.Witnesses.Ordered ( FL(..), (:>)(..), mapFL_FL, (+>+) )+import Darcs.Witnesses.Sealed ( Sealed, seal )  select_touching :: Patchy p => [FilePath] -> PatchChoices p C(x y) -> PatchChoices p C(x y) select_touching [] pc = pc-select_touching files pc = force_firsts xs pc+select_touching files pc = forceFirsts xs pc     where ct :: Patchy p => [FilePath] -> FL (TaggedPatch p) C(x y) -> [Tag]           ct _ NilFL = []-          ct fs (tp:>:tps) = case look_touch fs (tp_patch tp) of+          ct fs (tp:>:tps) = case look_touch fs (tpPatch tp) of                              (True, fs') -> tag tp:ct fs' tps                              (False, fs') -> ct fs' tps-          xs = case get_choices pc of+          xs = case getChoices pc of                _ :> mc :> lc -> ct (map fix files) (mc +>+ lc)  deselect_not_touching :: Patchy p => [FilePath] -> PatchChoices p C(x y) -> PatchChoices p C(x y) deselect_not_touching [] pc = pc-deselect_not_touching files pc = force_lasts xs pc+deselect_not_touching files pc = forceLasts xs pc     where ct :: Patchy p => [FilePath] -> FL (TaggedPatch p) C(x y) -> [Tag]           ct _ NilFL = []-          ct fs (tp:>:tps) = case look_touch fs (tp_patch tp) of+          ct fs (tp:>:tps) = case look_touch fs (tpPatch tp) of                              (True, fs') -> ct fs' tps                              (False, fs') -> tag tp:ct fs' tps-          xs = case get_choices pc of+          xs = case getChoices pc of                fc :> mc :> _ -> ct (map fix files) (fc +>+ mc)  select_not_touching :: Patchy p => [FilePath] -> PatchChoices p C(x y) -> PatchChoices p C(x y) select_not_touching [] pc = pc-select_not_touching files pc = force_firsts xs pc+select_not_touching files pc = forceFirsts xs pc     where ct :: Patchy p => [FilePath] -> FL (TaggedPatch p) C(x y) -> [Tag]           ct _ NilFL = []-          ct fs (tp:>:tps) = case look_touch fs (tp_patch tp) of+          ct fs (tp:>:tps) = case look_touch fs (tpPatch tp) of                              (True, fs') -> ct fs' tps                              (False, fs') -> tag tp:ct fs' tps-          xs = case get_choices pc of+          xs = case getChoices pc of                fc :> mc :> _ -> ct (map fix files) (fc +>+ mc)  fix :: FilePath -> FilePath-fix f | take 1 (reverse f) == "/" = fix $ reverse $ drop 1 $ reverse f+fix f | "/" `isSuffixOf` f = fix $ init f fix "" = "." fix "." = "." fix f = "./" ++ f  choose_touching :: Patchy p => [FilePath] -> FL p C(x y) -> Sealed (FL p C(x)) choose_touching [] p = seal p-choose_touching files p = case get_choices $ select_touching files $ patch_choices p of-                          fc :> _ :> _ -> seal $ mapFL_FL tp_patch fc+choose_touching files p = case getChoices $ select_touching files $ patchChoices p of+                          fc :> _ :> _ -> seal $ mapFL_FL tpPatch fc  look_touch :: Patchy p => [FilePath] -> p C(x y) -> (Bool, [FilePath])-look_touch fs p = (any (\tf -> any (affects tf) fs) (list_touched_files p)+look_touch fs p = (any (\tf -> any (affects tf) fs) (listTouchedFiles p)                    || fs' /= fs, fs')-    where affects touched f | touched == f = True-          affects t f = case splitAt (length f) t of-                        (t', '/':_) -> t' == f-                        _ -> case splitAt (length t) f of-                             (f', '/':_) -> f' == t-                             _ -> False-          fs' = sort $ apply_to_filepaths p fs+    where affects :: FilePath -> FilePath -> Bool+          affects touched f =  touched == f+                            || touched `isSubPathOf` f+                            || f `isSubPathOf` touched+          isSubPathOf :: FilePath -> FilePath -> Bool+          isSubPathOf sub path = case splitAt (length sub) path of+                                 (path', '/':_) -> path' == sub+                                 _ -> False+          fs' = sort $ applyToFilepaths p fs
src/Darcs/Patch/Viewing.hs view
@@ -18,17 +18,19 @@ {-# OPTIONS_GHC -cpp -fno-warn-orphans #-} {-# LANGUAGE CPP #-} -module Darcs.Patch.Viewing ( xml_summary, summarize )+module Darcs.Patch.Viewing ( xmlSummary, plainSummary )              where -import Prelude hiding ( pi )-import Control.Monad ( liftM )-import Data.List ( sort )+import Prelude hiding ( pi, readFile )+import Control.Monad.State.Strict ( gets )+import Control.Monad.Trans ( liftIO ) -import Darcs.SlurpDirectory ( Slurpy, get_slurp, get_filecontents )+import Storage.Hashed.Monad( TreeIO, fileExists, readFile, tree, virtualTreeIO )+import Storage.Hashed.AnchoredPath( floatPath ) import ByteStringUtils (linesPS )-import qualified Data.ByteString as B (null)-import Darcs.Patch.FileName ( FileName, fp2fn, fn2fp )+import qualified Data.ByteString as BS (null, concat)+import qualified Data.ByteString.Lazy as BL (toChunks)+import Darcs.Patch.FileName ( FileName, fn2fp ) import Printer ( Doc, empty, vcat,                  text, blueText, Color(Cyan,Magenta), lineColor,                  minus, plus, ($$), (<+>), (<>),@@ -37,69 +39,76 @@                ) import Darcs.Patch.Core ( Patch(..), Named(..),                           patchcontents )-import Darcs.Patch.Prim ( Prim(..), is_hunk, isHunk, formatFileName, showPrim, FileNameFormat(..), Conflict(..),+import Darcs.Patch.Prim ( Prim(..), primIsHunk, isHunk, formatFileName, showPrim, FileNameFormat(..), Conflict(..),                           Effect, IsConflictedPrim(IsC), ConflictState(..),                           DirPatchType(..), FilePatchType(..) ) import Darcs.Patch.Patchy ( Patchy, Apply, ShowPatch(..), identity ) import Darcs.Patch.Show ( showPatch_, showNamedPrefix ) import Darcs.Patch.Info ( showPatchInfo, human_friendly )-import Darcs.Patch.Apply ( apply_to_slurpy )+import Darcs.Patch.Apply ( applyToTree ) #include "impossible.h" #include "gadts.h"-import Darcs.Ordered ( RL(..), FL(..),+import Darcs.Witnesses.Ordered ( RL(..), FL(..),                              mapFL, mapFL_FL, reverseRL )  instance ShowPatch Prim where     showPatch = showPrim OldFormat-    showContextPatch s p@(FP _ (Hunk _ _ _)) = showContextHunk s (PP p)-    showContextPatch s (Split ps) =-        blueText "(" $$ showContextSeries s (mapFL_FL PP ps)-                     <> blueText ")"-    showContextPatch _ p = showPatch p-    summary = gen_summary False . (:[]) . IsC Okay+    showContextPatch p@(FP _ (Hunk _ _ _)) = showContextHunk (PP p)+    showContextPatch (Split ps) =+        do x <- showContextSeries (mapFL_FL PP ps)+           return $ blueText "(" $$ x <> blueText ")"+    showContextPatch p = return $ showPatch p+    summary = vcat . map summChunkToLine . genSummary . (:[]) . IsC Okay     thing _ = "change" -summarize :: (Conflict e, Effect e) => e C(x y) -> Doc-summarize = gen_summary False . conflictedEffect+plainSummary :: (Conflict e, Effect e) => e C(x y) -> Doc+plainSummary = vcat . map summChunkToLine . genSummary . conflictedEffect  instance ShowPatch Patch where     showPatch = showPatch_-    showContextPatch s (PP x) | is_hunk x = showContextHunk s (PP x)-    showContextPatch _ (ComP NilFL) = blueText "{" $$ blueText "}"-    showContextPatch s (ComP ps) = blueText "{" $$ showContextSeries s ps-                                   $$ blueText "}"-    showContextPatch _ p = showPatch p-    summary = summarize+    showContextPatch (PP x) | primIsHunk x = showContextHunk (PP x)+    showContextPatch (ComP NilFL) = return $ blueText "{" $$ blueText "}"+    showContextPatch (ComP ps) =+        do x <- showContextSeries ps+           return $ blueText "{" $$ x $$ blueText "}"+    showContextPatch p = return $ showPatch p+    summary = plainSummary     thing _ = "change" -showContextSeries :: (Apply p, ShowPatch p, Effect p) => Slurpy -> FL p C(x y) -> Doc-showContextSeries slur patches = scs slur identity patches-    where scs :: (Apply p, ShowPatch p, Effect p) => Slurpy -> Prim C(w x) -> FL p C(x y) -> Doc-          scs s pold (p:>:ps) =-              case isHunk p of-              Nothing -> showContextPatch s p $$ scs s' identity ps+showContextSeries :: (Apply p, ShowPatch p, Effect p) => FL p C(x y) -> TreeIO Doc+showContextSeries patches = scs identity patches+    where scs :: (Apply p, ShowPatch p, Effect p) => Prim C(w x) -> FL p C(x y) -> TreeIO Doc+          scs pold (p:>:ps) = do+            s' <- gets tree >>= liftIO . applyToTree p+            case isHunk p of+              Nothing -> do a <- showContextPatch p+                            b <- liftIO $ virtualTreeIO (scs identity ps) s'+                            return $ a $$ fst b               Just hp ->                   case ps of-                  NilFL -> coolContextHunk s pold hp identity+                  NilFL -> coolContextHunk pold hp identity                   (p2:>:_) ->                       case isHunk p2 of-                      Nothing -> coolContextHunk s pold hp identity $$ scs s' hp ps-                      Just hp2 -> coolContextHunk s pold hp hp2 $$-                                  scs s' hp ps-              where s' =-                        fromJust $ apply_to_slurpy p s-          scs _ _ NilFL = empty+                      Nothing -> do a <- coolContextHunk pold hp identity+                                    b <- liftIO $ virtualTreeIO (scs hp ps) s'+                                    return $ a $$ fst b+                      Just hp2 -> do a <- coolContextHunk pold hp hp2+                                     b <- liftIO $ virtualTreeIO (scs hp ps) s'+                                     return $ a $$ fst b+          scs _ NilFL = return empty -showContextHunk :: (Apply p, ShowPatch p, Effect p) => Slurpy -> p C(x y) -> Doc-showContextHunk s p = case isHunk p of-                        Just h -> coolContextHunk s identity h identity-                        Nothing -> showPatch p+showContextHunk :: (Apply p, ShowPatch p, Effect p) => p C(x y) -> TreeIO Doc+showContextHunk p = case isHunk p of+                      Just h -> coolContextHunk identity h identity+                      Nothing -> return $ showPatch p -coolContextHunk :: Slurpy -> Prim C(a b) -> Prim C(b c)-                -> Prim C(c d) -> Doc-coolContextHunk s prev p@(FP f (Hunk l o n)) next =-    case (linesPS . get_filecontents) `liftM` get_slurp f s of-    Nothing -> showPatch p -- This is a weird error...+coolContextHunk :: Prim C(a b) -> Prim C(b c) -> Prim C(c d) -> TreeIO Doc+coolContextHunk prev p@(FP f (Hunk l o n)) next = do+  let path = floatPath $ fn2fp f+  have <- fileExists path+  content <- if have then Just `fmap` readFile path else return Nothing+  case (linesPS . BS.concat . BL.toChunks) `fmap` content of -- sigh+    Nothing -> return $ showPatch p -- This is a weird error...     Just ls ->         let numpre = case prev of                      (FP f' (Hunk lprev _ nprev))@@ -116,19 +125,19 @@                               lnext - (l+length n)                       _ -> 3             cleanedls = case reverse ls of-                        (x:xs) | B.null x -> reverse xs+                        (x:xs) | BS.null x -> reverse xs                         _ -> ls             post = take numpost $ drop (max 0 $ l+length o-1) cleanedls-            in blueText "hunk" <+> formatFileName OldFormat f <+> text (show l)+            in return $ blueText "hunk" <+> formatFileName OldFormat f <+> text (show l)             $$ prefix " " (vcat $ map userchunkPS pre)             $$ lineColor Magenta (prefix "-" (vcat $ map userchunkPS o))             $$ lineColor Cyan    (prefix "+" (vcat $ map userchunkPS n))             $$ prefix " " (vcat $ map userchunkPS post)-coolContextHunk _ _ _ _ = impossible+coolContextHunk _ _ _ = impossible -xml_summary :: (Effect p, Patchy p, Conflict p) => Named p C(x y) -> Doc-xml_summary p = text "<summary>"-             $$ gen_summary True (conflictedEffect $ patchcontents p)+xmlSummary :: (Effect p, Patchy p, Conflict p) => Named p C(x y) -> Doc+xmlSummary p = text "<summary>"+             $$ (vcat . map summChunkToXML . genSummary . conflictedEffect . patchcontents $ p)              $$ text "</summary>"  -- Yuck duplicated code below...@@ -143,165 +152,124 @@   | otherwise = z : (strReplace x y zs) -- end yuck duplicated code. -gen_summary :: Bool -> [IsConflictedPrim] -> Doc-gen_summary use_xml p-    = vcat themoves-   $$ vcat themods-    where themods = map summ $ combine $ sort $ concatMap s2 p-          s2 :: IsConflictedPrim -> [(FileName, Int, Int, Int, Bool, ConflictState)]-          s2 (IsC c x) = map (append56 c) $ s x-          s :: Prim C(x y) -> [(FileName, Int, Int, Int, Bool)]-          s (FP f (Hunk _ o n)) = [(f, length o, length n, 0, False)]-          s (FP f (Binary _ _)) = [(f, 0, 0, 0, False)]-          s (FP f AddFile) = [(f, -1, 0, 0, False)]-          s (FP f RmFile) = [(f, 0, -1, 0, False)]-          s (FP f (TokReplace _ _ _)) = [(f, 0, 0, 1, False)]-          s (DP d AddDir) = [(d, -1, 0, 0, True)]-          s (DP d RmDir) = [(d, 0, -1, 0, True)]+-- | High-level representation of a piece of patch summary+data SummChunk = SummChunk SummDetail ConflictState+   deriving (Ord, Eq)++data SummDetail = SummAddDir FileName+                | SummRmDir  FileName+                | SummFile SummOp FileName Int Int Int+                | SummMv   FileName FileName+                | SummNone+  deriving (Ord, Eq)++data SummOp = SummAdd | SummRm | SummMod deriving (Ord, Eq)++genSummary :: [IsConflictedPrim] -> [SummChunk]+genSummary p+    = combine $ concatMap s2 p+    where s2 :: IsConflictedPrim -> [SummChunk]+          s2 (IsC c x) = map (\d -> SummChunk d c) $ s x+          s :: Prim C(x y) -> [SummDetail]+          s (FP f (Hunk _ o n)) = [SummFile SummMod f (length o) (length n) 0]+          s (FP f (Binary _ _)) = [SummFile SummMod f 0 0 0]+          s (FP f AddFile) = [SummFile SummAdd f 0 0 0]+          s (FP f RmFile) = [SummFile SummRm f 0 0 0]+          s (FP f (TokReplace _ _ _)) = [SummFile SummMod f 0 0 1]+          s (DP d AddDir) = [SummAddDir d]+          s (DP d RmDir) = [SummRmDir d]           s (Split xs) = concat $ mapFL s xs-          s (Move _ _) = [(fp2fn "", 0, 0, 0, False)]-          s (ChangePref _ _ _) = [(fp2fn "", 0, 0, 0, False)]-          s Identity = [(fp2fn "", 0, 0, 0, False)]-          append56 f (a,b,c,d,e) = (a,b,c,d,e,f)-          (-1) .+ _ = -1-          _ .+ (-1) = -1-          a .+ b = a + b-          combine ((f,a,b,r,isd,c):(f',a',b',r',_,c'):ss)-              -- Don't combine AddFile and RmFile: (maybe an old revision of) darcs-              -- allows a single patch to add and remove the same file, see issue 185-              | f == f' && (a /= -1 || b' /= -1) && (a' /= -1 || b /= -1) =-                  combine ((f,a.+a',b.+b',r+r',isd,combineConflitStates c c'):ss)-          combine ((f,a,b,r,isd,c):ss) = (f,a,b,r,isd,c) : combine ss+          s (Move f1 f2) = [SummMv f1 f2]+          s (ChangePref _ _ _) = [SummNone]+          s Identity = [SummNone]+          combine (x1@(SummChunk d1 c1) : x2@(SummChunk d2 c2) : ss)+              = case combineDetail d1 d2 of+                  Nothing -> x1 : combine (x2:ss)+                  Just d3 -> combine $ SummChunk d3 (combineConflitStates c1 c2) : ss+          combine (x:ss) = x  : combine ss           combine [] = []+          --+          combineDetail (SummFile o1 f1 r1 a1 x1) (SummFile o2 f2 r2 a2 x2) | f1 == f2 =+            do o3 <- combineOp o1 o2+               return $ SummFile o3 f1 (r1 + r2) (a1 + a2) (x1 + x2)+          combineDetail _ _ = Nothing+          --           combineConflitStates Conflicted _ = Conflicted           combineConflitStates _ Conflicted = Conflicted           combineConflitStates Duplicated _ = Duplicated           combineConflitStates _ Duplicated = Duplicated           combineConflitStates Okay Okay = Okay+          -- Don't combine AddFile and RmFile: (maybe an old revision of) darcs+          -- allows a single patch to add and remove the same file, see issue 185+          combineOp SummAdd SummRm  = Nothing+          combineOp SummRm  SummAdd = Nothing+          combineOp SummAdd _ = Just SummAdd+          combineOp _ SummAdd = Just SummAdd+          combineOp SummRm  _ = Just SummRm+          combineOp _ SummRm  = Just SummRm+          combineOp SummMod SummMod = Just SummMod -          summ (f,_,-1,_,False,Okay)-              = if use_xml then text "<remove_file>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</remove_file>"-                           else text "R" <+> text (fn2fp f)-          summ (f,_,-1,_,False,Conflicted)-              = if use_xml then text "<remove_file conflict='true'>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</remove_file>"-                           else text "R!" <+> text (fn2fp f)-          summ (f,_,-1,_,False,Duplicated)-              = if use_xml then text "<remove_file duplicate='true'>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</remove_file>"-                           else text "R" <+> text (fn2fp f) <+> text "(duplicate)"-          summ (f,-1,_,_,False,Okay)-              = if use_xml then text "<add_file>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</add_file>"-                           else text "A" <+> text (fn2fp f)-          summ (f,-1,_,_,False,Conflicted)-              = if use_xml then text "<add_file conflict='true'>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</add_file>"-                           else text "A!" <+> text (fn2fp f)-          summ (f,-1,_,_,False,Duplicated)-              = if use_xml then text "<add_file duplicate='true'>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</add_file>"-                           else text "A" <+> text (fn2fp f) <+> text "(duplicate)"-          summ (f,0,0,0,False,Okay) | f == fp2fn "" = empty-          summ (f,0,0,0,False,Conflicted) | f == fp2fn ""-              = if use_xml then empty -- don't know what to do here...-                           else text "!" <+> text (fn2fp f)-          summ (f,0,0,0,False,Duplicated) | f == fp2fn ""-              = if use_xml then empty -- don't know what to do here...-                           else text (fn2fp f) <+> text "(duplicate)"-          summ (f,a,b,r,False,Okay)-              = if use_xml then text "<modify_file>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                                    <> xrm a <> xad b <> xrp r-                             $$ text "</modify_file>"-                           else text "M" <+> text (fn2fp f)-                                         <+> rm a <+> ad b <+> rp r-          summ (f,a,b,r,False,Conflicted)-              = if use_xml then text "<modify_file conflict='true'>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                                    <> xrm a <> xad b <> xrp r-                             $$ text "</modify_file>"-                           else text "M!" <+> text (fn2fp f)-                                    <+> rm a <+> ad b <+> rp r-          summ (f,a,b,r,False,Duplicated)-              = if use_xml then text "<modify_file duplicate='true'>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                                    <> xrm a <> xad b <> xrp r-                             $$ text "</modify_file>"-                           else text "M" <+> text (fn2fp f)-                                    <+> rm a <+> ad b <+> rp r <+> text "(duplicate)"-          summ (f,_,-1,_,True,Okay)-              = if use_xml then text "<remove_directory>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</remove_directory>"-                           else text "R" <+> text (fn2fp f) <> text "/"-          summ (f,_,-1,_,True,Conflicted)-              = if use_xml then text "<remove_directory conflict='true'>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</remove_directory>"-                           else text "R!" <+> text (fn2fp f) <> text "/"-          summ (f,_,-1,_,True,Duplicated)-              = if use_xml then text "<remove_directory duplicate='true'>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</remove_directory>"-                           else text "R" <+> text (fn2fp f) <> text "/ (duplicate)"-          summ (f,-1,_,_,True,Okay)-              = if use_xml then text "<add_directory>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</add_directory>"-                           else text "A" <+> text (fn2fp f) <> text "/"-          summ (f,-1,_,_,True,Conflicted)-              = if use_xml then text "<add_directory conflict='true'>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</add_directory>"-                           else text "A!" <+> text (fn2fp f) <> text "/"-          summ (f,-1,_,_,True,Duplicated)-              = if use_xml then text "<add_directory duplicate='true'>"-                             $$ escapeXML (drop_dotslash $ fn2fp f)-                             $$ text "</add_directory>"-                           else text "A!" <+> text (fn2fp f) <> text "/ (duplicate)"-          summ _ = empty-          ad 0 = empty-          ad a = plus <> text (show a)-          xad 0 = empty-          xad a = text "<added_lines num='" <> text (show a) <> text "'/>"-          rm 0 = empty-          rm a = minus <> text (show a)-          xrm 0 = empty-          xrm a = text "<removed_lines num='" <> text (show a) <> text "'/>"-          rp 0 = empty-          rp a = text "r" <> text (show a)-          xrp 0 = empty-          xrp a = text "<replaced_tokens num='" <> text (show a) <> text "'/>"-          drop_dotslash ('.':'/':str) = drop_dotslash str-          drop_dotslash str = str-          themoves :: [Doc]-          themoves = map showmoves p-          showmoves :: IsConflictedPrim -> Doc-          showmoves (IsC _ (Move a b))-              = if use_xml-                then text "<move from=\""-                  <> escapeXML (drop_dotslash $ fn2fp a) <> text "\" to=\""-                  <> escapeXML (drop_dotslash $ fn2fp b) <> text"\"/>"-                else text " "    <> text (fn2fp a)-                  <> text " -> " <> text (fn2fp b)-          showmoves _ = empty+summChunkToXML :: SummChunk -> Doc+summChunkToXML (SummChunk detail c) =+ case detail of+   SummRmDir f  -> xconf c "remove_directory" (xfn f)+   SummAddDir f -> xconf c "add_directory"    (xfn f)+   SummFile SummRm  f _ _ _ -> xconf c "remove_file" (xfn f)+   SummFile SummAdd f _ _ _ -> xconf c "add_file"    (xfn f)+   SummFile SummMod f r a x -> xconf c "modify_file" $ xfn f <> xrm r <> xad a <> xrp x+   SummMv f1 f2  -> text "<move from=\"" <> xfn f1+                      <> text "\" to=\"" <> xfn f2 <> text"\"/>"+   SummNone      -> empty+ where+   xconf Okay t x       = text ('<':t++">") $$ x $$ text ("</"++t++">")+   xconf Conflicted t x = text ('<':t++" conflict='true'>") $$ x $$ text ("</"++t++">")+   xconf Duplicated t x = text ('<':t++" duplicate='true'>") $$ x $$ text ("</"++t++">")+   xfn = escapeXML . dropDotSlash .fn2fp+   --+   xad 0 = empty+   xad a = text "<added_lines num='" <> text (show a) <> text "'/>"+   xrm 0 = empty+   xrm a = text "<removed_lines num='" <> text (show a) <> text "'/>"+   xrp 0 = empty+   xrp a = text "<replaced_tokens num='" <> text (show a) <> text "'/>" +summChunkToLine :: SummChunk -> Doc+summChunkToLine (SummChunk detail c) =+  case detail of+   SummRmDir f   -> lconf c "R" $ text (fn2fp f) <> text "/"+   SummAddDir f  -> lconf c "A" $ text (fn2fp f) <> text "/"+   SummFile SummRm  f _ _ _ -> lconf c "R" $ text (fn2fp f)+   SummFile SummAdd f _ _ _ -> lconf c "A" $ text (fn2fp f)+   SummFile SummMod f r a x -> lconf c "M" $ text (fn2fp f) <+> rm r <+> ad a <+> rp x+   SummMv f1 f2 -> text " "    <> text (fn2fp f1)+                <> text " -> " <> text (fn2fp f2)+   SummNone -> case c of+               Okay -> empty+               _    -> lconf c ""  empty+  where+   lconf Okay       t x = text t <+> x+   lconf Conflicted t x = text (t ++ "!") <+> x+   lconf Duplicated t x = text t <+> x <+> text "duplicate"+   --+   ad 0 = empty+   ad a = plus <> text (show a)+   rm 0 = empty+   rm a = minus <> text (show a)+   rp 0 = empty+   rp a = text "r" <> text (show a)++dropDotSlash :: FilePath -> FilePath+dropDotSlash ('.':'/':str) = dropDotSlash str+dropDotSlash str = str+ instance (Conflict p, ShowPatch p) => ShowPatch (Named p) where     showPatch (NamedP n [] p) = showPatchInfo n <> showPatch p     showPatch (NamedP n d p) = showNamedPrefix n d <+> showPatch p-    showContextPatch s (NamedP n [] p) = showPatchInfo n <> showContextPatch s p-    showContextPatch s (NamedP n d p) = showNamedPrefix n d <+> showContextPatch s p+    showContextPatch (NamedP n [] p) = showContextPatch p >>= return . (showPatchInfo n <>)+    showContextPatch (NamedP n d p) = showContextPatch p >>= return . (showNamedPrefix n d <+>)     description (NamedP n _ _) = human_friendly n     summary p = description p $$ text "" $$-                prefix "    " (summarize p) -- this isn't summary because summary does the+                prefix "    " (plainSummary p) -- this isn't summary because summary does the                                             -- wrong thing with (Named (FL p)) so that it can                                             -- get the summary of a sequence of named patches                                             -- right.@@ -323,7 +291,7 @@  instance (Conflict p, Apply p, ShowPatch p) => ShowPatch (RL p) where     showPatch = showPatch . reverseRL-    showContextPatch s = showContextPatch s . reverseRL+    showContextPatch = showContextPatch . reverseRL     description = description . reverseRL     summary = summary . reverseRL     thing = thing . reverseRL
src/Darcs/Population.hs view
@@ -37,10 +37,10 @@ import Darcs.Patch.FileName ( fn2fp, fp2fn, fn2ps, norm_path ) import Darcs.Patch ( RepoPatch, applyToPop, patchcontents, patchChanges,                      Effect, effect )-import Darcs.Ordered ( FL(..), RL(..), reverseRL, concatRL, mapRL )+import Darcs.Witnesses.Ordered ( FL(..), RL(..), reverseRL, concatRL, mapRL ) import Darcs.Patch.Info ( PatchInfo, idpatchinfo, to_xml ) import Darcs.Patch.Set ( PatchSet )-import Darcs.Sealed ( Sealed(..), seal, unseal )+import Darcs.Witnesses.Sealed ( Sealed(..), seal, unseal ) import Darcs.Repository ( withRepositoryDirectory, ($-), read_repo ) import Darcs.Repository.Pristine ( identifyPristine, getPristinePop ) import Darcs.PopulationData ( Population(..), PopTree(..), Info(..), DirMark(..),
src/Darcs/PopulationData.hs view
@@ -103,7 +103,7 @@           then do            fnames <- getDirectoryContents dirname            sl <- withCurrentDirectory dirname-                 (sequence $ map getPopFrom_helper $ filter not_hidden fnames)+                 (mapM getPopFrom_helper $ filter not_hidden fnames)            let i = Info {nameI = n,                          modifiedByI = pinfo,                          modifiedHowI = DullDir,
src/Darcs/PrintPatch.hs view
@@ -24,7 +24,8 @@                           printPatchPager, printFriendly ) where  import Darcs.Patch ( Patchy, showContextPatch, showPatch )-import Darcs.SlurpDirectory ( Slurpy )+import Storage.Hashed.Tree( Tree )+import Storage.Hashed.Monad( virtualTreeIO ) import Darcs.Arguments ( DarcsFlag, showFriendly ) import Printer ( putDocLnWith ) import Darcs.ColorPrinter ( fancyPrinters )@@ -46,5 +47,5 @@  -- | 'contextualPrintPatch' prints a patch, together with its context, -- on standard output.-contextualPrintPatch :: Patchy p => Slurpy -> p C(x y) -> IO ()-contextualPrintPatch s p = putDocLnWith fancyPrinters $ showContextPatch s p+contextualPrintPatch :: Patchy p => Tree IO -> p C(x y) -> IO ()+contextualPrintPatch s p = virtualTreeIO (showContextPatch p) s >>= putDocLnWith fancyPrinters . fst
src/Darcs/ProgressPatches.hs view
@@ -1,9 +1,9 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP, GADTs #-}  #include "gadts.h" module Darcs.ProgressPatches (progressRL, progressFL, progressRLShowTags) where-import Darcs.Ordered ( FL(..), RL(..), lengthRL, lengthFL )+import Darcs.Witnesses.Ordered ( FL(..), RL(..), lengthRL, lengthFL ) import Darcs.Hopefully (PatchInfoAnd,info) import System.IO.Unsafe ( unsafePerformIO ) import Progress (minlist, beginTedious,
src/Darcs/RemoteApply.hs view
@@ -20,7 +20,7 @@                         then apply_via_url opts repodir bundle                         else apply_via_local opts repodir bundle         Just un -> if is_ssh repodir-                   then apply_via_ssh_and_sudo repodir un bundle+                   then apply_via_ssh_and_sudo opts repodir un bundle                    else apply_via_sudo un repodir bundle  apply_as :: [DarcsFlag] -> Maybe String@@ -29,10 +29,12 @@ apply_as [] = Nothing apply_via_sudo :: String -> String -> Doc -> IO ExitCode apply_via_sudo user repo bundle =-    pipeDoc "sudo" ["-u",user,"darcs","apply","--all","--repodir",repo] bundle+    darcs_program >>= \darcs ->+    pipeDoc "sudo" ["-u",user,darcs,"apply","--all","--repodir",repo] bundle apply_via_local :: [DarcsFlag] -> String -> Doc -> IO ExitCode apply_via_local opts repo bundle =-    pipeDoc "darcs" ("apply":"--all":"--repodir":repo:applyopts opts) bundle+    darcs_program >>= \darcs ->+    pipeDoc darcs ("apply":"--all":"--repodir":repo:applyopts opts) bundle  apply_via_url :: [DarcsFlag] -> String -> Doc -> IO ExitCode apply_via_url opts repo bundle =@@ -45,13 +47,14 @@  apply_via_ssh :: [DarcsFlag] -> String -> Doc -> IO ExitCode apply_via_ssh opts repo bundle =-    pipeDocSSH addr ["darcs apply --all "++unwords (applyopts opts)++" --repodir '"++path++"'"] bundle+    pipeDocSSH addr [remoteDarcsCmd opts++" apply --all "++unwords (applyopts opts)+++                     " --repodir '"++path++"'"] bundle         where (addr,':':path) = break (==':') repo -apply_via_ssh_and_sudo :: String -> String -> Doc -> IO ExitCode-apply_via_ssh_and_sudo repo username bundle =-    pipeDocSSH addr ["sudo -u "++username++-                         " darcs apply --all --repodir '"++path++"'"] bundle+apply_via_ssh_and_sudo :: [DarcsFlag] -> String -> String -> Doc -> IO ExitCode+apply_via_ssh_and_sudo opts repo username bundle =+    pipeDocSSH addr ["sudo -u "++username++" "++remoteDarcsCmd opts+++                     " apply --all --repodir '"++path++"'"] bundle         where (addr,':':path) = break (==':') repo  applyopts :: [DarcsFlag] -> [String]
src/Darcs/Repository.hs view
@@ -21,56 +21,47 @@  #include "gadts.h" -module Darcs.Repository ( Repository, ($-), maybeIdentifyRepository,-                          identifyRepositoryFor,-                          withRepoLock, withRepoReadLock,-                          withRepository, withRepositoryDirectory, withGutsOf,-                          makePatchLazy, writePatchSet,-                    findRepository, amInRepository, amNotInRepository,-                    slurp_pending, replacePristineFromSlurpy,-                    slurp_recorded, slurp_recorded_and_unrecorded,-                    withRecorded,-                    get_unrecorded, get_unrecorded_unsorted, get_unrecorded_no_look_for_adds,-                    get_unrecorded_in_files, get_unrecorded_in_files_unsorted,-                    read_repo, sync_repo,-                    prefsUrl,-                    add_to_pending,-                    tentativelyAddPatch, tentativelyRemovePatches, tentativelyAddToPending,-                    tentativelyReplacePatches,-                    tentativelyMergePatches, considerMergeToWorking,-                    revertRepositoryChanges, finalizeRepositoryChanges,-                          createRepository, copyRepository, copy_oldrepo_patches,-                    patchSetToRepository,-                    unrevertUrl,-                    applyToWorking, patchSetToPatches,-                    createPristineDirectoryTree, createPartialsPristineDirectoryTree,-                    optimizeInventory, cleanRepository,-                    checkPristineAgainstSlurpy, getMarkedupFile,-                    PatchSet, SealedPatchSet, PatchInfoAnd,-                    setScriptsExecutable,-                    checkUnrelatedRepos,-                    testTentative, testRecorded-                  ) where+module Darcs.Repository+    ( Repository, ($-), maybeIdentifyRepository, identifyRepositoryFor+    , withRepoLock, withRepoReadLock, withRepository, withRepositoryDirectory+    , withGutsOf, makePatchLazy, writePatchSet, findRepository, amInRepository+    , amNotInRepository, slurp_pending, replacePristine, slurp_recorded+    , slurp_recorded_and_unrecorded, withRecorded, read_repo, prefsUrl+    , add_to_pending, tentativelyAddPatch, tentativelyRemovePatches+    , tentativelyAddToPending, tentativelyReplacePatches+    , tentativelyMergePatches, considerMergeToWorking, revertRepositoryChanges+    , finalizeRepositoryChanges, createRepository, copyRepository+    , copy_oldrepo_patches, patchSetToRepository, unrevertUrl, applyToWorking+    , patchSetToPatches, createPristineDirectoryTree+    , createPartialsPristineDirectoryTree, optimizeInventory, cleanRepository+    , getMarkedupFile, PatchSet, SealedPatchSet, PatchInfoAnd+    , setScriptsExecutable, checkUnrelatedRepos, testTentative, testRecorded+    -- * Recorded and unrecorded and pending.+    , readRecorded, readUnrecorded, unrecordedChanges, readPending, pendingChanges+    , readRecordedAndPending+    -- * Index.+    , readIndex, invalidateIndex+    ) where  import System.Exit ( ExitCode(..), exitWith ) +import Darcs.Repository.State( readRecorded, readUnrecorded, unrecordedChanges+                             , readPending, pendingChanges, readIndex, invalidateIndex+                             , readRecordedAndPending )+ import Darcs.Repository.Internal-    (Repository(..), RepoType(..), ($-), pristineFromWorking,+    (Repository(..), RepoType(..), ($-),      maybeIdentifyRepository, identifyRepositoryFor,      findRepository, amInRepository, amNotInRepository,      makePatchLazy,-     slurp_pending, replacePristineFromSlurpy,+     slurp_pending,      slurp_recorded, slurp_recorded_and_unrecorded,      withRecorded,-     get_unrecorded, get_unrecorded_unsorted, get_unrecorded_no_look_for_adds,-     get_unrecorded_in_files, get_unrecorded_in_files_unsorted,-     read_repo, sync_repo,-     prefsUrl, checkPristineAgainstSlurpy,-     add_to_pending,+     read_repo,+     prefsUrl,      withRepoLock, withRepoReadLock, withRepository, withRepositoryDirectory, withGutsOf,      tentativelyAddPatch, tentativelyRemovePatches, tentativelyAddToPending,      tentativelyReplacePatches,-     tentativelyMergePatches, considerMergeToWorking,      revertRepositoryChanges, finalizeRepositoryChanges,      unrevertUrl,      applyToWorking, patchSetToPatches,@@ -78,14 +69,16 @@      optimizeInventory, cleanRepository,      getMarkedupFile,      setScriptsExecutable,-     testTentative, testRecorded+     testTentative, testRecorded,+     make_new_pending     )+import Darcs.Repository.Merge( tentativelyMergePatches, considerMergeToWorking ) import Darcs.Repository.Cache ( unionCaches, fetchFileUsingCache, HashedDir(..) ) import Darcs.Patch.Set ( PatchSet, SealedPatchSet )  import Control.Monad ( unless, when ) import Data.Either(Either(..))-import System.Directory ( createDirectory )+import System.Directory ( createDirectory, renameDirectory ) import System.IO.Error ( isAlreadyExistsError )  import qualified Darcs.Repository.DarcsRepo as DarcsRepo@@ -94,30 +87,40 @@ import Darcs.Hopefully ( PatchInfoAnd, info, extractHash ) import Darcs.Repository.Checkpoint ( identify_checkpoint, write_checkpoint_patch, get_checkpoint ) import Darcs.Repository.ApplyPatches ( apply_patches )-import Darcs.Repository.HashedRepo ( apply_to_tentative_pristine )-import Darcs.Patch ( RepoPatch, Named, Patch, patch2patchinfo, apply )-import Darcs.Ordered ( RL(..), bunchFL, mapFL, mapRL, mapRL_RL, concatFL, reverseRL,-                       concatRL, lengthRL, isShorterThanRL )+import Darcs.Repository.HashedRepo ( apply_to_tentative_pristine, pris2inv )+import Darcs.Repository.InternalTypes ( Pristine(..) )+import Darcs.Patch ( RepoPatch, Named, Prim, Patch, patch2patchinfo, apply )+import Darcs.Witnesses.Ordered ( FL(..), RL(..), bunchFL, mapFL, mapRL, mapRL_RL, concatFL+                     , reverseRL ,concatRL, lengthRL, isShorterThanRL, (+>+) ) import Darcs.Patch.Info ( PatchInfo ) import Darcs.Repository.Format ( RepoProperty ( HashedInventory ),-                                 create_repo_format, format_has, writeRepoFormat )-import Darcs.Repository.Prefs ( write_default_prefs )-import Darcs.Repository.Pristine ( createPristine, flagsToPristine )+                                 createRepoFormat, formatHas, writeRepoFormat )+import Darcs.Repository.Prefs ( writeDefaultPrefs )+import Darcs.Repository.Pristine ( createPristine, flagsToPristine, createPristineFromWorking ) import Darcs.Patch.Depends ( get_patches_beyond_tag )-import Darcs.SlurpDirectory ( empty_slurpy ) import Darcs.Utils ( withCurrentDirectory, catchall, promptYorn, prettyError ) import Darcs.External ( copyFileOrUrl, Cachable(..) ) import Progress ( debugMessage, tediousSize,                         beginTedious, endTedious, progress ) import Darcs.ProgressPatches (progressRLShowTags, progressFL)-import Darcs.Lock ( writeBinFile )-import Darcs.Sealed ( Sealed(..), FlippedSeal(..), flipSeal, mapFlipped )+import Darcs.Lock ( writeBinFile, writeDocBinFile, rm_recursive )+import Darcs.Witnesses.Sealed ( Sealed(..), FlippedSeal(..), flipSeal, mapFlipped ) -import Darcs.Flags ( DarcsFlag( Quiet, Partial, Lazy, Ephemeral,-                                AllowUnrelatedRepos-                              ),-                     compression )+import Darcs.Flags ( DarcsFlag( Quiet, Partial, Lazy, Ephemeral, Complete,+                                AllowUnrelatedRepos, NoUpdateWorking )+                   , compression ) import Darcs.Global ( darcsdir )++import Storage.Hashed.Tree( Tree, emptyTree )+import Storage.Hashed.Hash( encodeBase16 )+import Storage.Hashed.Darcs( writeDarcsHashed )+import Storage.Hashed( writePlainTree )+import ByteStringUtils( gzReadFilePS )++import System.FilePath( (</>) )++import qualified Data.ByteString.Char8 as BS+ #include "impossible.h"  createRepository :: [DarcsFlag] -> IO ()@@ -126,19 +129,19 @@       (\e-> if isAlreadyExistsError e             then fail "Tree has already been initialized!"             else fail $ "Error creating directory `"++darcsdir++"'.")-  let rf = create_repo_format opts+  let rf = createRepoFormat opts   createPristine $ flagsToPristine opts rf   createDirectory $ darcsdir ++ "/patches"   createDirectory $ darcsdir ++ "/prefs"-  write_default_prefs+  writeDefaultPrefs   writeRepoFormat rf (darcsdir++"/format")-  if format_has HashedInventory rf+  if formatHas HashedInventory rf       then writeBinFile (darcsdir++"/hashed_inventory") ""       else DarcsRepo.write_inventory "." ((NilRL:<:NilRL) :: PatchSet Patch C(())) -- YUCK!  copyRepository :: RepoPatch p => Repository p C(r u t) -> IO () copyRepository fromrepository@(Repo _ opts rf _)-    | Partial `elem` opts && not (format_has HashedInventory rf) =+    | Partial `elem` opts && not (formatHas HashedInventory rf) =         do isPartial <- copyPartialRepository fromrepository            unless (isPartial == IsPartial) $ copyFullRepository fromrepository     | otherwise = copyFullRepository fromrepository@@ -156,11 +159,11 @@       copyHashedHashed = HashedRepo.copy_repo newrepo opts fromdir       copyAnythingToOld r = withCurrentDirectory todir $ read_repo r >>=                             DarcsRepo.write_inventory_and_patches opts-      repoSort rfx | format_has HashedInventory rfx = Hashed+      repoSort rfx | formatHas HashedInventory rfx = Hashed                    | otherwise = Old   case repoSort rf2 of     Hashed ->-        if format_has HashedInventory rf+        if formatHas HashedInventory rf         then copyHashedHashed         else withCurrentDirectory todir $              do HashedRepo.revert_tentative_changes@@ -207,7 +210,7 @@            local_patches <- read_repo torepository            let pi_ch = patch2patchinfo ch            FlippedSeal ps <- return $ get_patches_beyond_tag pi_ch local_patches-           let needed_patches = reverseRL $ concatRL ps+           let needed_patches = reverseRL ps            apply opts ch `catch`                              \e -> fail ("Bad checkpoint!\n" ++ prettyError e)            apply_patches opts needed_patches@@ -223,15 +226,15 @@                      `catchall` return ()   debugMessage "Grabbing lock in new repository..."   withRepoLock opts $- \torepository@(Repo _ _ rfto (DarcsRepository _ c)) ->-      if format_has HashedInventory rffrom && format_has HashedInventory rfto+      if formatHas HashedInventory rffrom && formatHas HashedInventory rfto       then do debugMessage "Writing working directory contents..."               createPristineDirectoryTree torepository "."               fetch_patches_if_necessary opts torepository               when (Partial `elem` opts) $ putStrLn $                        "--partial: hashed or darcs-2 repository detected, using --lazy instead"-      else if format_has HashedInventory rfto+      else if formatHas HashedInventory rfto            then do local_patches <- read_repo torepository-                   replacePristineFromSlurpy torepository empty_slurpy+                   replacePristine torepository emptyTree                    let patchesToApply = progressFL "Applying patch" $ concatFL $ reverseRL $                                         mapRL_RL reverseRL local_patches                    sequence_ $ mapFL (apply_to_tentative_pristine c opts) $ bunchFL 100 patchesToApply@@ -252,7 +255,7 @@             Right r -> r             Left e  -> bug ("Current directory not repository in writePatchSet: " ++ e)     debugMessage "Writing inventory"-    if format_has HashedInventory rf2+    if formatHas HashedInventory rf2        then do HashedRepo.write_tentative_inventory c (compression opts) patchset                HashedRepo.finalize_tentative_changes repo (compression opts)        else DarcsRepo.write_inventory_and_patches opts patchset@@ -266,7 +269,7 @@ patchSetToRepository :: RepoPatch p => Repository p C(r1 u1 r1) -> PatchSet p C(x)                      -> [DarcsFlag] -> IO (Repository p C(r u t)) patchSetToRepository (Repo fromrepo _ rf _) patchset opts = do-    when (format_has HashedInventory rf) $ -- set up sources and all that+    when (formatHas HashedInventory rf) $ -- set up sources and all that        do writeFile "_darcs/tentative_pristine" "" -- this is hokey           repox <- writePatchSet patchset opts           HashedRepo.copy_repo repox opts fromrepo@@ -276,7 +279,7 @@     pristineFromWorking repo     return repo -checkUnrelatedRepos :: [DarcsFlag] -> [PatchInfo] -> PatchSet p C(x) -> PatchSet p C(x) -> IO ()+checkUnrelatedRepos :: [DarcsFlag] -> [PatchInfo] -> PatchSet p C(x) -> PatchSet p C(y) -> IO () checkUnrelatedRepos opts common us them     | AllowUnrelatedRepos `elem` opts || not (null common)        || concatRL us `isShorterThanRL` 5 || concatRL them `isShorterThanRL` 5@@ -292,7 +295,8 @@ fetch_patches_if_necessary :: RepoPatch p => [DarcsFlag] -> Repository p C(r u t) -> IO () fetch_patches_if_necessary opts torepository@(Repo _ _ _ (DarcsRepository _ c)) =      unless (Partial `elem` opts || Lazy `elem` opts || Ephemeral `elem` opts) $-             do putInfo "Copying patches, to get lazy repository hit ctrl-C..."+             do unless (Complete `elem` opts) $+                       putInfo "Copying patches, to get lazy repository hit ctrl-C..."                 r <- read_repo torepository                 let peekaboo :: PatchInfoAnd p C(x y) -> IO ()                     peekaboo x = case extractHash x of@@ -300,3 +304,37 @@                                  Right h -> fetchFileUsingCache c HashedPatchesDir h >> return ()                 sequence_ $ mapRL peekaboo $ progressRLShowTags "Copying patches" $ concatRL r   where putInfo = when (not $ Quiet `elem` opts) . putStrLn++add_to_pending :: RepoPatch p => Repository p C(r u t) -> FL Prim C(u y) -> IO ()+add_to_pending (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return ()+add_to_pending repo@(Repo _ opts _ _) p =+    do pend <- unrecordedChanges opts repo []+       invalidateIndex repo+       make_new_pending repo (pend +>+ p)++-- | Replace the existing pristine with a new one (loaded up in a Tree object).+replacePristine :: Repository p C(r u t) -> Tree IO -> IO ()+replacePristine (Repo r _opts _rf (DarcsRepository pris _c)) tree =+    withCurrentDirectory r $ replace pris+    where replace HashedPristine =+              do let t = "_darcs" </> "hashed_inventory"+                 i <- gzReadFilePS t+                 root <- writeDarcsHashed tree $ "_darcs" </> "pristine.hashed"+                 writeDocBinFile t $ pris2inv (BS.unpack $ encodeBase16 root) i+          replace (PlainPristine n) =+              do rm_recursive nold `catchall` return ()+                 writePlainTree tree ntmp+                 renameDirectory n nold+                 renameDirectory ntmp n+                 return ()+          replace (NoPristine _) = return ()+          nold = darcsdir </> "pristine-old"+          ntmp = darcsdir </> "pristine-tmp"++pristineFromWorking :: RepoPatch p => Repository p C(r u t) -> IO ()+pristineFromWorking repo@(Repo dir _ rf _)+    | formatHas HashedInventory rf =+        withCurrentDirectory dir $ readUnrecorded repo >>= replacePristine repo+pristineFromWorking (Repo dir _ _ (DarcsRepository p _)) =+  withCurrentDirectory dir $ createPristineFromWorking p+
src/Darcs/Repository/ApplyPatches.hs view
@@ -25,7 +25,7 @@ import Darcs.Patch ( Patchy, apply ) import Darcs.Hopefully ( PatchInfoAnd, hopefully, info ) import Darcs.Patch.Info ( human_friendly )-import Darcs.Ordered ( FL(..), lengthFL, mapFL )+import Darcs.Witnesses.Ordered ( FL(..), lengthFL, mapFL ) import Darcs.Flags ( DarcsFlag ) import Darcs.Utils ( putDocLnError ) import Progress ( beginTedious, endTedious, tediousSize, finishedOneIO )
src/Darcs/Repository/Cache.hs view
@@ -9,7 +9,7 @@                    HashedDir(..), hashedDir,                    unionCaches, cleanCaches, cleanCachesWithHint,                    fetchFileUsingCache, speculateFileUsingCache, writeFileUsingCache,-                   findFileMtimeUsingCache, setFileMtimeUsingCache, peekInCache,+                   peekInCache,                    repo2cache,                    writable, isthisrepo, hashedFilePath, allHashedDirs                  ) where@@ -18,9 +18,7 @@ import Data.List ( nub ) import Data.Maybe ( listToMaybe ) import System.Directory ( removeFile, doesFileExist, getDirectoryContents )-import System.Posix ( setFileTimes )-import System.Posix.Files ( linkCount, modificationTime, getSymbolicLinkStatus )-import System.Posix.Types ( EpochTime )+import System.Posix.Files ( linkCount, getSymbolicLinkStatus ) import System.IO ( hPutStrLn, stderr )  import Crypt.SHA256 ( sha256sum )@@ -39,7 +37,6 @@ import Darcs.Global ( darcsdir ) import Darcs.Lock ( writeAtomicFilePS, gzWriteAtomicFilePS ) import Progress ( progressList, debugMessage, debugFail )-import Darcs.SlurpDirectory ( undefined_time ) import Darcs.URL ( is_file ) import Darcs.Utils ( withCurrentDirectory, catchall ) @@ -97,21 +94,6 @@               | length h == 75 = B.length s == read (take 10 h) && sha256sum s == drop 11 h               | otherwise = False --findFileMtimeUsingCache :: Cache -> HashedDir -> String -> IO EpochTime-findFileMtimeUsingCache (Ca cache) subdir f = mt cache-    where mt [] = return undefined_time-          mt (Cache Repo Writable r:_) = (modificationTime `fmap`-                                          getSymbolicLinkStatus (r++"/"++darcsdir++"/"++(hashedDir subdir)++"/"++f))-                                         `catchall` return undefined_time-          mt (_:cs) = mt cs--setFileMtimeUsingCache :: Cache -> HashedDir -> String -> EpochTime -> IO ()-setFileMtimeUsingCache (Ca cache) subdir f t = st cache-    where st [] = return ()-          st (Cache Repo Writable r:_) = setFileTimes (r++"/"++darcsdir++"/"++(hashedDir subdir)++"/"++f) t t-                                         `catchall` return ()-          st (_:cs) = st cs  fetchFileUsingCache :: Cache -> HashedDir -> String -> IO (String, B.ByteString) fetchFileUsingCache = fetchFileUsingCachePrivate Anywhere
src/Darcs/Repository/Checkpoint.hs view
@@ -22,45 +22,31 @@  module Darcs.Repository.Checkpoint ( get_checkpoint, get_checkpoint_by_default,                                      identify_checkpoint,-                                     write_checkpoint, write_recorded_checkpoint,                                      write_checkpoint_patch,                                    ) where -import System.Directory ( setCurrentDirectory, createDirectoryIfMissing )-import Workaround ( getCurrentDirectory )+import System.Directory ( createDirectoryIfMissing ) import System.IO.Unsafe ( unsafeInterleaveIO ) import Data.Maybe ( listToMaybe, catMaybes )-import Darcs.Hopefully ( PatchInfoAnd, hopefully, info )+import Darcs.Hopefully ( PatchInfoAnd, info ) import qualified Data.ByteString as B ( null, empty, ByteString ) -import Darcs.Lock ( withTempDir, writeDocBinFile )-import Darcs.SlurpDirectory ( Slurpy, empty_slurpy, mmap_slurp, )-import Darcs.Patch ( RepoPatch, Patch, Named, Prim, invertRL, patch2patchinfo,-                     apply_to_slurpy, patchcontents,-                     effect, fromPrims,-                     is_setpref, infopatch,-                     readPatch,-                     gzWritePatch-                   )-import Darcs.Ordered ( RL(..), FL(..), EqCheck(IsEq,NotEq),-                             (+>+), filterFL, unsafeCoerceP,-                             mapRL, mapFL_FL, mapRL_RL, reverseRL, concatRL, concatFL )-import Darcs.Repository.Internal ( Repository(..), read_repo, slurp_recorded, withRecorded )-import Darcs.Repository.ApplyPatches ( apply_patches )+import Darcs.Lock ( writeDocBinFile )+import Darcs.SlurpDirectory ( Slurpy, empty_slurpy )+import Darcs.Patch ( RepoPatch, Patch, Named, patch2patchinfo,+                     applyToSlurpy, readPatch, gzWritePatch )+import Darcs.Witnesses.Ordered ( RL(..), FL(..), mapRL, reverseRL )+import Darcs.Repository.Internal ( Repository(..), read_repo ) import Darcs.Patch.Info ( PatchInfo, make_filename, readPatchInfo,                           showPatchInfo                         )-import Darcs.Diff ( unsafeDiff ) import Darcs.External ( gzFetchFilePS, fetchFilePS, Cachable(..) )-import Darcs.Flags ( DarcsFlag(LookForAdds, Partial, Complete ) )-import Darcs.Patch.Depends ( get_patches_beyond_tag, get_patches_in_tag )-import Darcs.Repository.Prefs ( filetype_function )+import Darcs.Flags ( DarcsFlag( Partial, Complete ) ) import Darcs.Utils ( catchall ) import Darcs.RepoPath ( ioAbsoluteOrRemote, toPath ) import Darcs.Global ( darcsdir ) import Printer ( Doc, ($$), empty )-#include "impossible.h"-import Darcs.Sealed ( Sealed(Sealed), FlippedSeal(..), Sealed2(Sealed2), seal, seal2 )+import Darcs.Witnesses.Sealed ( Sealed(Sealed), Sealed2(Sealed2), seal, seal2 ) import Control.Monad ( liftM )  read_patch_ids :: B.ByteString -> [PatchInfo]@@ -83,7 +69,7 @@                     (r++"/"++darcsdir++"/checkpoints/"++make_filename pinfo) Cachable                 case fst `fmap` (readPatch pstr :: Maybe (Sealed (Named Patch C(x)), B.ByteString)) of                   Nothing -> return Nothing-                  Just (Sealed p) -> return $ apply_to_slurpy p empty_slurpy+                  Just (Sealed p) -> return $ applyToSlurpy p empty_slurpy  get_checkpoint :: RepoPatch p => Repository p C(r u t) -> IO (Maybe (Sealed (Named p C(x)))) get_checkpoint repository@(Repo _ opts _ _) = if Partial `elem` opts@@ -126,36 +112,6 @@ format_inv (pinfo:ps) = showPatchInfo pinfo                      $$ format_inv ps -write_recorded_checkpoint :: RepoPatch p => Repository p C(r u t) -> PatchInfo -> IO ()-write_recorded_checkpoint r@(Repo _ _ _ _) pinfo = do-    Sealed ps <- (seal . mapFL_FL hopefully.reverseRL.concatRL) `liftM` read_repo r-    ftf <- filetype_function-    s <- slurp_recorded r-    write_checkpoint_patch $ infopatch pinfo-        (fromPrims $ changepps ps +>+ unsafeDiff [LookForAdds] ftf empty_slurpy s :: Patch C(() y))-    where changeps = filterFL is_setprefFL .-                     effect . patchcontents-          changepps = concatFL . mapFL_FL changeps--is_setprefFL :: Prim C(x y) -> EqCheck C(x y)-is_setprefFL p | is_setpref p = NotEq-               | otherwise = unsafeCoerceP IsEq--write_checkpoint :: RepoPatch p => Repository p C(r u t) -> PatchInfo -> IO ()-write_checkpoint repo@(Repo _ _ _ _) pinfo = do-    repodir <- getCurrentDirectory-    Sealed pit <- get_patches_in_tag pinfo `liftM` read_repo repo-    let ps = (reverseRL.mapRL_RL hopefully.concatRL) pit-    ftf <- filetype_function-    with_tag repo pinfo $ do-      s <- mmap_slurp "."-      setCurrentDirectory repodir-      write_checkpoint_patch $ infopatch pinfo $-          (fromPrims $ changepps ps +>+ unsafeDiff [LookForAdds] ftf empty_slurpy s :: Patch C(() y))-    where changeps = filterFL is_setprefFL .-                     effect . patchcontents-          changepps = concatFL . mapFL_FL changeps- write_checkpoint_patch :: RepoPatch p => Named p C(x y) -> IO () write_checkpoint_patch p =  do createDirectoryIfMissing False (darcsdir++"/checkpoints")@@ -163,12 +119,3 @@     cpi <- (map fst) `fmap` read_checkpoints "."     writeDocBinFile (darcsdir++"/checkpoints/inventory")         $ format_inv $ reverse $ patch2patchinfo p:cpi--with_tag :: RepoPatch p  => Repository p C(r u t) -> PatchInfo -> (IO ()) -> IO ()-with_tag r pinfo job = do-    ps <- read_repo r-    case get_patches_beyond_tag pinfo ps of-        FlippedSeal (extras :<: NilRL) -> withRecorded r (withTempDir "checkpoint") $ \_ -> do-                                            apply_patches [] $ invertRL extras-                                            job-        _ -> bug "with_tag"
src/Darcs/Repository/DarcsRepo.lhs view
@@ -61,7 +61,7 @@  import System.Directory ( doesDirectoryExist, createDirectoryIfMissing ) import Workaround ( renameFile )-import Darcs.Utils ( clarify_errors )+import Darcs.Utils ( clarifyErrors ) import Progress ( debugMessage, beginTedious, endTedious, finishedOneIO ) import Darcs.RepoPath ( ioAbsoluteOrRemote, toPath ) import System.IO ( hPutStrLn, stderr )@@ -80,10 +80,10 @@ import Darcs.Patch ( RepoPatch, Effect, Prim, Named, Patch, invert,                      effect,                      patch2patchinfo,-                     apply_to_slurpy,+                     applyToSlurpy,                      readPatch,                      writePatch, gzWritePatch, showPatch )-import Darcs.Ordered ( FL(..), RL(..), (:<)(..),+import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:<)(..),                              reverseFL, mapFL, unsafeCoerceP,                              reverseRL, concatRL, mapRL, mapRL_RL ) import Darcs.Patch.Info ( PatchInfo, make_filename, readPatchInfo,@@ -100,7 +100,7 @@ import Darcs.Utils ( catchall ) import Darcs.ProgressPatches ( progressFL ) import Printer ( text, (<>), Doc, ($$), empty )-import Darcs.Sealed ( Sealed(Sealed), seal, unseal )+import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal, unseal ) \end{code}  There is a very special patch which may be stored in \verb!patches! which@@ -221,7 +221,7 @@                                    Nothing -> seal $ NilFL  repairable :: IO a -> IO a-repairable x = x `clarify_errors` unlines+repairable x = x `clarifyErrors` unlines                ["Your repository is now in an inconsistent state.",                 "This must be fixed by running darcs repair."] @@ -315,7 +315,7 @@                     (r++"/"++darcsdir++"/checkpoints/"++make_filename pinfo) Cachable                 case fst `liftM` readPatch_ pstr of                   Nothing -> return Nothing-                  Just (Sealed p) -> return $ apply_to_slurpy p empty_slurpy+                  Just (Sealed p) -> return $ applyToSlurpy p empty_slurpy             readPatch_ :: B.ByteString -> Maybe (Sealed (Named Patch C(x)), B.ByteString)             readPatch_ = readPatch 
src/Darcs/Repository/Format.hs view
@@ -6,9 +6,9 @@ {-# LANGUAGE CPP #-}  module Darcs.Repository.Format ( RepoFormat(..), RepoProperty(..), identifyRepoFormat,-                    create_repo_format, writeRepoFormat,-                    write_problem, read_problem, readfrom_and_writeto_problem,-                    format_has, format_has_together,+                    createRepoFormat, writeRepoFormat,+                    writeProblem, readProblem, readfromAndWritetoProblem,+                    formatHas, formatHasTogether,                   ) where  import Data.List ( sort )@@ -56,9 +56,9 @@           then do finishedOneIO k "inventory"                   have_inventory <- doesRemoteFileExist (repo++"/"++darcsdir++"/inventory")                   case have_inventory of-                    Right _ -> return $ Right default_repo_format+                    Right _ -> return $ Right defaultRepoFormat                     Left e -> return $ Left $ "Not a repository: "++repo++" ("++e++")"-          else return $ Right $ parse_repo_format dff+          else return $ Right $ parseRepoFormat dff     endTedious k     return rf     where drfe x = fetchFilePS x Cachable >> return True@@ -70,16 +70,16 @@ writeRepoFormat (RF rf) loc = writeBinFile loc $ unlines $                               map (BC.unpack . BU.intercalate (BC.singleton '|')) rf -parse_repo_format :: B.ByteString -> RepoFormat-parse_repo_format ps =+parseRepoFormat :: B.ByteString -> RepoFormat+parseRepoFormat ps =     RF $ map (BC.split '|') $ filter (not . B.null) $ linesPS ps  -- | The repo format we assume if we do not find a format file.-default_repo_format :: RepoFormat-default_repo_format = RF [[rp2ps Darcs1_0]]+defaultRepoFormat :: RepoFormat+defaultRepoFormat = RF [[rp2ps Darcs1_0]] -create_repo_format :: [DarcsFlag] -> RepoFormat-create_repo_format fs = RF ([map rp2ps flags2inv] ++ maybe2)+createRepoFormat :: [DarcsFlag] -> RepoFormat+createRepoFormat fs = RF ([map rp2ps flags2inv] ++ maybe2)     where flags2inv | UseFormat2 `elem` fs = [HashedInventory]                     | UseHashedInventory `elem` fs = [HashedInventory]                     | UseOldFashionedInventory `elem` fs = [Darcs1_0]@@ -90,47 +90,47 @@                    then []                    else [[rp2ps Darcs2]] --- | @write_problem from@ tells if we can write to a repo in format @form@.+-- | @writeProblem from@ tells if we can write to a repo in format @form@. -- it returns @Nothing@ if there's no problem writing to such a repository.-write_problem :: RepoFormat -> Maybe String-write_problem rf | isJust $ read_problem rf = read_problem rf-write_problem (RF ks) = unlines `fmap` justsOrNothing (map wp ks)-    where wp x | all is_known x = Nothing+writeProblem :: RepoFormat -> Maybe String+writeProblem rf | isJust $ readProblem rf = readProblem rf+writeProblem (RF ks) = unlines `fmap` justsOrNothing (map wp ks)+    where wp x | all isKnown x = Nothing           wp [] = impossible           wp x = Just $ unwords $ "Can't write repository format: " :-                 map BC.unpack (filter (not . is_known) x)+                 map BC.unpack (filter (not . isKnown) x)  --- | @write_problem from@ tells if we can read and write to a repo in+-- | @writeProblem from@ tells if we can read and write to a repo in -- format @form@.  it returns @Nothing@ if there's no problem reading -- and writing to such a repository.-readfrom_and_writeto_problem :: RepoFormat -> RepoFormat -> Maybe String-readfrom_and_writeto_problem inrf outrf-    | format_has Darcs2 inrf /= format_has Darcs2 outrf+readfromAndWritetoProblem :: RepoFormat -> RepoFormat -> Maybe String+readfromAndWritetoProblem inrf outrf+    | formatHas Darcs2 inrf /= formatHas Darcs2 outrf         = Just "Cannot mix darcs-2 repositories with older formats" -    | otherwise = msum [read_problem inrf, write_problem outrf]+    | otherwise = msum [readProblem inrf, writeProblem outrf]  --- | @read_problem from@ tells if we can write to a repo in format @form@.+-- | @readProblem from@ tells if we can write to a repo in format @form@. -- it returns @Nothing@ if there's no problem reading from such a repository.-read_problem :: RepoFormat -> Maybe String-read_problem rf | format_has Darcs1_0 rf && format_has Darcs2 rf+readProblem :: RepoFormat -> Maybe String+readProblem rf | formatHas Darcs1_0 rf && formatHas Darcs2 rf                     = Just "Invalid repositoryformat:  format 2 is incompatible with format 1"-read_problem (RF ks) = unlines `fmap` justsOrNothing (map rp ks)-    where rp x | any is_known x = Nothing+readProblem (RF ks) = unlines `fmap` justsOrNothing (map rp ks)+    where rp x | any isKnown x = Nothing           rp [] = impossible           rp x = Just $ unwords $                  "Can't understand repository format:" : map BC.unpack x   -- | Does this version of darcs know how to handle this property?-is_known :: B.ByteString -> Bool-is_known p = p `elem` map rp2ps known_properties+isKnown :: B.ByteString -> Bool+isKnown p = p `elem` map rp2ps knownProperties  -- | This is the list of properties which this version of darcs knows -- how to handle.-known_properties :: [RepoProperty]-known_properties = [Darcs1_0, Darcs2, HashedInventory]+knownProperties :: [RepoProperty]+knownProperties = [Darcs1_0, Darcs2, HashedInventory]  justsOrNothing :: [Maybe x] -> Maybe [x] justsOrNothing mxs =@@ -138,11 +138,11 @@    [] -> Nothing    xs -> Just xs -format_has :: RepoProperty -> RepoFormat -> Bool-format_has f (RF ks) = rp2ps f `elem` concat ks+formatHas :: RepoProperty -> RepoFormat -> Bool+formatHas f (RF ks) = rp2ps f `elem` concat ks -format_has_together :: [RepoProperty] -> RepoFormat -> Bool-format_has_together fs (RF ks) = fht (sort $ map rp2ps fs) ks+formatHasTogether :: [RepoProperty] -> RepoFormat -> Bool+formatHasTogether fs (RF ks) = fht (sort $ map rp2ps fs) ks     where fht _ [] = False           fht x (y:ys) | x == sort y = True                        | otherwise = fht x ys
src/Darcs/Repository/HashedIO.hs view
@@ -20,25 +20,24 @@ #include "gadts.h"  module Darcs.Repository.HashedIO ( HashedIO, applyHashed,-                                   copyHashed, syncHashedPristine, copyPartialsHashed, listHashedContents,+                                   copyHashed, copyPartialsHashed, listHashedContents,                                    slurpHashedPristine, writeHashedPristine,                                    clean_hashdir ) where  import Darcs.Global ( darcsdir )-import Data.List ( (\\) )+import qualified Data.Set as Set import qualified Data.Map as Map import System.Directory ( getDirectoryContents, createDirectoryIfMissing )-import System.Posix.Types ( EpochTime ) import Control.Monad.State ( StateT, runStateT, modify, get, put, gets, lift ) import Control.Monad ( when )+import Control.Applicative ( (<$>) ) import Data.Maybe ( isJust ) import System.IO.Unsafe ( unsafeInterleaveIO )  import Darcs.SlurpDirectory.Internal ( Slurpy(..), SlurpyContents(..), map_to_slurpies, slurpies_to_map )-import Darcs.SlurpDirectory ( withSlurpy, undefined_time, undefined_size )+import Darcs.SlurpDirectory ( withSlurpy, undefined_size ) import Darcs.Repository.Cache ( Cache, fetchFileUsingCache, writeFileUsingCache,                                 peekInCache, speculateFileUsingCache,-                                findFileMtimeUsingCache, setFileMtimeUsingCache,                                 okayHash, cleanCachesWithHint, HashedDir(..), hashedDir ) import Darcs.Patch ( Patchy, apply ) import Darcs.RepoPath ( FilePathLike, toFilePath )@@ -48,7 +47,7 @@ import Darcs.Utils ( withCurrentDirectory ) import Progress ( debugMessage, beginTedious, endTedious, tediousSize, finishedOneIO, progress ) import Darcs.Patch.FileName ( FileName, norm_path, fp2fn, fn2fp, fn2niceps, niceps2fn,-                              break_on_dir, own_name, super_name )+                              break_on_dir, own_name, superName )  import ByteStringUtils ( linesPS, unlinesPS ) import qualified Data.ByteString       as B  (ByteString, length, empty)@@ -111,7 +110,7 @@                                                        Just h -> inh h $ mInCurrentDirectory fn'' j         where fn' = norm_path fn     mGetDirectoryContents = map (\ (_,f,_) -> f) `fmap` readroot-    mReadFilePS fn = mInCurrentDirectory (super_name fn) $ do+    mReadFilePS fn = mInCurrentDirectory (superName fn) $ do                                           c <- readroot                                           case geta F (own_name fn) c of                                             Nothing -> fail $ " file don't exist... "++ fn2fp fn@@ -170,11 +169,11 @@         where fn' = norm_path fn  makeThing :: FileName -> (ObjType,String) -> HashedIO RW p ()-makeThing fn (o,h) = mWithCurrentDirectory (super_name $ norm_path fn) $+makeThing fn (o,h) = mWithCurrentDirectory (superName $ norm_path fn) $                      seta o (own_name $ norm_path fn) h `fmap` readroot >>= writeroot  rmThing :: FileName -> HashedIO RW p ()-rmThing fn = mWithCurrentDirectory (super_name $ norm_path fn) $+rmThing fn = mWithCurrentDirectory (superName $ norm_path fn) $              do c <- readroot                 let c' = filter (\(_,x,_)->x/= own_name (norm_path fn)) c                 if length c' == length c - 1@@ -191,10 +190,6 @@ readTediousHash k h = do lift $ finishedOneIO k h                          readhash h -gethashmtime :: String -> HashedIO r p EpochTime-gethashmtime h = do HashDir _ c _ _ <- get-                    lift $ unsafeInterleaveIO $ findFileMtimeUsingCache c HashedPristineDir h- withh :: String -> HashedIO RW p a -> HashedIO RW p (String,a) withh h j = do hd <- get                put $ hd { rootHash = h }@@ -286,10 +281,9 @@          lift $ beginTedious k          safeInterleave $ (Slurpy rootdir . SlurpDir (Just hroot) . slurpies_to_map) `fmap` mapM sl c     where sl (F,n,h) = do ps <- safeInterleave $ readTediousHash k h-                          t <- gethashmtime h                           let len = if length h == 75 then read (take 10 h)                                                       else undefined_size-                          return $ Slurpy n $ SlurpFile (Just h, t, len) ps+                          return $ Slurpy n $ SlurpFile (Just h, 0, len) ps           sl (D,n,h) = inh h $ do c <- readroot                                   lift $ tediousSize k (length c)                                   lift $ finishedOneIO k h@@ -327,33 +321,6 @@                                                return (F, f, h)           k = "Writing pristine" -grab :: FileName -> Slurpy -> Maybe Slurpy-grab _ (Slurpy _ (SlurpFile _ _)) = Nothing-grab fn (Slurpy _ (SlurpDir _ ss)) = fmap (Slurpy fn) $ Map.lookup fn ss---- | Update timestamps on pristine files to match those in the working directory--- (which is passed to this function in form of a Slurpy). It needed for the--- mtime-based unsafeDiff optimisation to work efficiently.-syncHashedPristine :: Cache -> Slurpy -> String -> IO ()-syncHashedPristine c s r = do runStateT sh $ HashDir { permissions=RW, cache=c,-                                                       compress=compression [], rootHash=r }-                              return ()-    where sh = do cc <- readroot-                  lift $ tediousSize k (length cc)-                  mapM_ sh' cc-          sh' (D,n,h) = case progress k $ grab n s of-                        Just s' -> lift $ syncHashedPristine c s' h-                        Nothing -> return ()-          sh' (F,n,h) = case progress k $ grab n s of-                        Just (Slurpy _ (SlurpFile (_,t',l) x)) ->-                            do t <- lift $ findFileMtimeUsingCache c HashedPristineDir h-                               when (t' /= undefined_time && t' /= t) $-                                    do ps <- readhash h-                                       when (B.length ps == fromIntegral l && ps == x) $-                                            lift $ setFileMtimeUsingCache c HashedPristineDir h t'-                        _ -> return ()-          k = "Synchronizing pristine"- copyHashed :: String -> Cache -> Compression -> String -> IO () copyHashed k c compr z = do runStateT cph $ HashDir { permissions = RO, cache = c,                                                       compress = compr, rootHash = z }@@ -409,9 +376,11 @@    do -- we'll remove obsolete bits of "dir"       debugMessage $ "Cleaning out " ++ (hashedDir dir_) ++ "..."       let hashdir = darcsdir ++ "/" ++ (hashedDir dir_) ++ "/"-      hs <- concat `fmap` (mapM (listHashedContents "cleaning up..." c) hashroots)-      fs <- filter okayHash `fmap` getDirectoryContents hashdir-      mapM_ (removeFileMayNotExist . (hashdir++)) (fs \\ hs)+      hs <- set . concat <$> mapM (listHashedContents "cleaning up..." c) hashroots+      fs <- set . filter okayHash <$> getDirectoryContents hashdir+      mapM_ (removeFileMayNotExist . (hashdir++)) (unset $ fs `Set.difference` hs)       -- and also clean out any global caches.       debugMessage "Cleaning out any global caches..."-      cleanCachesWithHint c dir_ (fs \\ hs)+      cleanCachesWithHint c dir_ (unset $ fs `Set.difference` hs)+   where set = Set.fromList . map BC.pack+         unset = map BC.unpack . Set.toList
src/Darcs/Repository/HashedRepo.hs view
@@ -20,14 +20,13 @@ #include "gadts.h"  module Darcs.Repository.HashedRepo ( revert_tentative_changes, finalize_tentative_changes,-                                     slurp_pristine, sync_repo, clean_pristine,-                                     copy_pristine, copy_partials_pristine, pristine_from_working,+                                     slurp_pristine, clean_pristine,+                                     copy_pristine, copy_partials_pristine,                                      apply_to_tentative_pristine,-                                     replacePristineFromSlurpy,                                      add_to_tentative_inventory, remove_from_tentative_inventory,                                      read_repo, read_tentative_repo, write_and_read_patch,                                      write_tentative_inventory, copy_repo, slurp_all_but_darcs,-                                     readHashedPristineRoot+                                     readHashedPristineRoot, pris2inv                                    ) where  import System.Directory ( doesFileExist, createDirectoryIfMissing )@@ -45,8 +44,8 @@                                 unionCaches, repo2cache, okayHash, takeHash,                                 HashedDir(..), hashedDir ) import Darcs.Repository.HashedIO ( applyHashed, slurpHashedPristine,-                                   copyHashed, syncHashedPristine, copyPartialsHashed,-                                   writeHashedPristine, clean_hashdir )+                                   copyHashed, copyPartialsHashed,+                                   clean_hashdir ) import Darcs.Repository.InternalTypes ( Repository(..), extractCache ) import Darcs.Hopefully ( PatchInfoAnd, patchInfoAndPatch, n2pia, info,                          extractHash, createHashed )@@ -54,11 +53,11 @@ import Darcs.Patch ( RepoPatch, Patchy, Named, showPatch, patch2patchinfo, readPatch ) import Darcs.Patch.Depends ( commute_to_end, slightly_optimize_patchset ) import Darcs.Patch.Info ( PatchInfo, showPatchInfo, human_friendly, readPatchInfo )-import Darcs.Ordered ( unsafeCoerceP, (:<)(..) )+import Darcs.Witnesses.Ordered ( unsafeCoerceP, (:<)(..) ) import Darcs.Patch.FileName ( fp2fn )  import ByteStringUtils ( gzReadFilePS, dropSpace )-import qualified Data.ByteString as B (null, length, readFile, empty+import qualified Data.ByteString as B (null, length, empty                                       ,tail, take, drop, ByteString) import qualified Data.ByteString.Char8 as BC (unpack, dropWhile, break, pack) @@ -69,9 +68,9 @@ import Darcs.Utils ( withCurrentDirectory ) import Progress ( beginTedious, tediousSize, endTedious, debugMessage, finishedOneIO ) #include "impossible.h"-import Darcs.Ordered ( FL(..), RL(..),+import Darcs.Witnesses.Ordered ( FL(..), RL(..),                              mapRL, mapFL, lengthRL )-import Darcs.Sealed ( Sealed(..), seal, unseal )+import Darcs.Witnesses.Sealed ( Sealed(..), seal, unseal ) import Darcs.Global ( darcsdir )  revert_tentative_changes :: IO ()@@ -338,18 +337,6 @@                                     h | h == sha1PS B.empty -> return empty_slurpy                                       | otherwise -> slurpHashedPristine c compr h -pristine_from_working :: Cache -> Compression -> IO ()-pristine_from_working c compr = do-  s <- slurp_all_but_darcs "."-  replacePristineFromSlurpy c compr s--replacePristineFromSlurpy :: Cache -> Compression -> Slurpy -> IO ()-replacePristineFromSlurpy c compr s = do -  h <- writeHashedPristine c compr s-  let t = darcsdir++"/hashed_inventory"-  i <- gzReadFilePS t-  writeDocBinFile t $ pris2inv h i- copy_pristine :: Cache -> Compression -> String -> String -> IO () copy_pristine c compr d iname = do     i <- fetchFilePS (d++"/"++iname) Uncachable@@ -358,13 +345,6 @@     beginTedious k     copyHashed k c compr $ inv2pris i     endTedious k--sync_repo :: Cache -> IO ()-sync_repo c = do i <- B.readFile $ darcsdir++"/hashed_inventory"-                 s <- slurp_all_but_darcs "."-                 beginTedious "Synchronizing pristine"-                 syncHashedPristine c s $ inv2pris i-                   copy_partials_pristine :: FilePathLike fp =>                           Cache -> Compression -> String -> String -> [fp] -> IO ()
src/Darcs/Repository/Internal.hs view
@@ -24,131 +24,122 @@ module Darcs.Repository.Internal ( Repository(..), RepoType(..), RIO(unsafeUnRIO), ($-),                     maybeIdentifyRepository, identifyDarcs1Repository, identifyRepositoryFor,                     findRepository, amInRepository, amNotInRepository,-                    slurp_pending, pristineFromWorking, revertRepositoryChanges,+                    slurp_pending, revertRepositoryChanges,                     slurp_recorded, slurp_recorded_and_unrecorded,-                    read_pending, announce_merge_conflicts, setTentativePending,+                    announce_merge_conflicts, setTentativePending,                     check_unrecorded_conflicts,                     withRecorded,-                    checkPristineAgainstSlurpy,-                    get_unrecorded, get_unrecorded_unsorted, get_unrecorded_no_look_for_adds,-                    get_unrecorded_in_files, get_unrecorded_in_files_unsorted,-                    read_repo, sync_repo,+                    read_repo,                     prefsUrl, makePatchLazy,-                    add_to_pending,                     withRepoLock, withRepoReadLock,                     withRepository, withRepositoryDirectory, withGutsOf,                     tentativelyAddPatch, tentativelyRemovePatches, tentativelyAddToPending,+                    tentativelyAddPatch_,                     tentativelyReplacePatches,-                    tentativelyMergePatches, considerMergeToWorking,                     finalizeRepositoryChanges,                     unrevertUrl,                     applyToWorking, patchSetToPatches,                     createPristineDirectoryTree, createPartialsPristineDirectoryTree,-                    replacePristineFromSlurpy,                     optimizeInventory, cleanRepository,                     getMarkedupFile,                     PatchSet, SealedPatchSet,                     setScriptsExecutable,                     getRepository, rIO,-                    testTentative, testRecorded+                    testTentative, testRecorded,+                    UpdatePristine(..), MakeChanges(..), applyToTentativePristine,+                    make_new_pending                   ) where  import Printer ( putDocLn, (<+>), text, ($$) )  import Data.Maybe ( isJust, isNothing )-import Darcs.Repository.Prefs ( get_prefval )-import Darcs.Resolution ( standard_resolution, external_resolution )+import Darcs.Repository.Prefs ( getPrefval )+import Darcs.Repository.State ( readRecorded )+import Darcs.Repository.LowLevel ( read_pending, pendingName, readPrims, read_pendingfile ) import System.Exit ( ExitCode(..), exitWith ) import System.Cmd ( system )-import Darcs.External ( backupByCopying, clonePartialsTree )+import Darcs.External ( clonePartialsTree ) import Darcs.IO ( runTolerantly, runSilently ) import Darcs.Repository.Pristine ( identifyPristine, nopristine,-                                   easyCreatePristineDirectoryTree, slurpPristine, syncPristine,-                                   easyCreatePartialsPristineDirectoryTree,-                                   createPristineFromWorking )-import qualified Darcs.Repository.Pristine as Pristine ( replacePristineFromSlurpy )-                                                         +                                   easyCreatePristineDirectoryTree, slurpPristine,+                                   easyCreatePartialsPristineDirectoryTree )+ import Data.List ( (\\) ) import Darcs.SignalHandler ( withSignalsBlocked ) import Darcs.Repository.Format ( RepoFormat, RepoProperty( Darcs2, HashedInventory ),-                                 identifyRepoFormat, format_has,-                                 write_problem, read_problem, readfrom_and_writeto_problem )+                                 identifyRepoFormat, formatHas,+                                 writeProblem, readProblem, readfromAndWritetoProblem ) import System.Directory ( doesDirectoryExist, setCurrentDirectory, removeFile,                           createDirectoryIfMissing ) import Control.Monad ( liftM, when, unless ) import Workaround ( getCurrentDirectory, renameFile, setExecutable )  import ByteStringUtils ( gzReadFilePS )-import qualified Data.ByteString as B (ByteString, empty, readFile, isPrefixOf)+import qualified Data.ByteString as B ( empty, readFile, isPrefixOf ) import qualified Data.ByteString.Char8 as BC (pack) -import Darcs.Patch ( Patch, RealPatch, Effect, is_hunk, is_binary, description,+import Darcs.Patch ( Patch, RealPatch, Effect, primIsHunk, primIsBinary, description, -                     try_to_shrink, commuteFL, commute, apply_to_filepaths )+                     tryToShrink, commuteFL, commute ) import Darcs.Patch.Prim ( try_shrinking_inverse, Conflict ) import Darcs.Patch.Bundle ( scan_bundle, make_bundle )-import Darcs.Patch.FileName ( FileName, fn2fp )-import Darcs.Patch.TouchesFiles ( choose_touching )-import Darcs.SlurpDirectory ( Slurpy, slurp_unboring, mmap_slurp, co_slurp,-                              slurp_has, list_slurpy_files )+import Darcs.SlurpDirectory ( Slurpy, mmap_slurp, co_slurp, list_slurpy_files ) import Darcs.Hopefully ( PatchInfoAnd, info, n2pia,                          hopefully, hopefullyM ) import Darcs.Repository.ApplyPatches ( apply_patches ) import qualified Darcs.Repository.HashedRepo as HashedRepo                             ( revert_tentative_changes, finalize_tentative_changes,-                              remove_from_tentative_inventory, sync_repo,+                              remove_from_tentative_inventory,                               copy_pristine, copy_partials_pristine, slurp_pristine,-                              apply_to_tentative_pristine, pristine_from_working,+                              apply_to_tentative_pristine,                               write_tentative_inventory, write_and_read_patch,                               add_to_tentative_inventory,                               read_repo, read_tentative_repo, clean_pristine,-                              replacePristineFromSlurpy,                               slurp_all_but_darcs ) import qualified Darcs.Repository.DarcsRepo as DarcsRepo-import Darcs.Flags ( DarcsFlag(AnyOrder, Boring, LookForAdds, Verbose, Quiet,+import Darcs.Flags ( DarcsFlag(Verbose, Quiet,                                MarkConflicts, AllowConflicts, NoUpdateWorking,                                WorkRepoUrl, WorkRepoDir, UMask, Test, LeaveTestDir,-                               SetScriptsExecutable, DryRun, IgnoreTimes,-                               Summary, NoSummary),+                               SetScriptsExecutable, DryRun ),                      want_external_merge, compression )-import Darcs.Ordered ( FL(..), RL(..), EqCheck(..), unsafeCoerceP,+import Darcs.Witnesses.Ordered ( FL(..), RL(..), EqCheck(..), unsafeCoerceP,                              (:\/:)(..), (:/\:)(..), (:>)(..),-                             (+>+), lengthFL, nullFL,+                             (+>+), lengthFL,                              allFL, filterFL,                              reverseRL, reverseFL, concatRL, mapFL,                              mapFL_FL, concatFL ) import Darcs.Patch ( RepoPatch, Patchy, Prim, merge,-                     joinPatches, sort_coalesceFL,-                     list_conflicted_files, list_touched_files,-                     Named, patchcontents, anonymous,+                     joinPatches,+                     listConflictedFiles, listTouchedFiles,+                     Named, patchcontents,                      commuteRL, fromPrims,                      patch2patchinfo, readPatch,                      writePatch, effect, invert,-                     is_addfile, is_adddir,-                     is_setpref,-                     apply, apply_to_slurpy,-                     empty_markedup_file, MarkedUpFile+                     primIsAddfile, primIsAdddir,+                     primIsSetpref,+                     apply, applyToSlurpy,+                     emptyMarkedupFile, MarkedUpFile                    ) import Darcs.Patch.Patchy ( Invert(..) ) import Darcs.Patch.Permutations ( commuteWhatWeCanFL, removeFL ) import Darcs.Patch.Info ( PatchInfo ) import Darcs.Patch.Set ( PatchSet, SealedPatchSet )-import Darcs.Patch.Apply ( markup_file, LineMark(None) )+import Darcs.Patch.Apply ( markupFile, LineMark(None) ) import Darcs.Patch.Depends ( get_common_and_uncommon, deep_optimize_patchset )-import Darcs.Diff ( unsafeDiffAtPaths, unsafeDiff ) import Darcs.RepoPath ( FilePathLike, AbsolutePath, toFilePath,                         ioAbsoluteOrRemote, toPath ) import Darcs.Utils ( promptYorn, catchall, withCurrentDirectory, withUMask, nubsort ) import Progress ( debugMessage ) import Darcs.ProgressPatches (progressFL) import Darcs.URL ( is_file )-import Darcs.Repository.Prefs ( darcsdir_filter, boring_file_filter, filetype_function,-                                getCaches )+import Darcs.Repository.Prefs ( getCaches ) import Darcs.Lock ( withLock, writeDocBinFile, withDelayedDir, removeFileMayNotExist,                     withTempDir, withPermDir )-import Darcs.Sealed ( Sealed(Sealed), seal, FlippedSeal(FlippedSeal), flipSeal )+import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal, FlippedSeal(FlippedSeal), flipSeal ) import Darcs.Repository.InternalTypes( Repository(..), RepoType(..) ) import Darcs.Global ( darcsdir )+import System.Mem( performGC )+ #include "impossible.h"  -- | Repository IO monad.  This monad-like datatype is responsible for@@ -206,7 +197,7 @@        case rf_or_e of          Left err -> return $ Left err          Right rf ->-             case read_problem rf of+             case readProblem rf of              Just err -> return $ Left err              Nothing -> if darcs then do pris <- identifyPristine                                          cs <- getCaches opts here@@ -217,7 +208,7 @@     rf_or_e <- identifyRepoFormat url     case rf_or_e of       Left e -> return $ Left e-      Right rf -> case read_problem rf of+      Right rf -> case readProblem rf of                   Just err -> return $ Left err                   Nothing ->  do cs <- getCaches opts url                                  return $ Right $ Repo url opts rf (DarcsRepository nopristine cs)@@ -233,7 +224,7 @@ identifyRepositoryFor (Repo _ opts rf _) url =     do Repo absurl _ rf_ t <- identifyDarcs1Repository opts url        let t' = case t of DarcsRepository x c -> DarcsRepository x c-       case readfrom_and_writeto_problem rf_ rf of+       case readfromAndWritetoProblem rf_ rf of          Just e -> fail $ "Incompatibility with repository " ++ url ++ ":\n" ++ e          Nothing -> return $ Repo absurl opts rf_ t' @@ -275,8 +266,12 @@                   else do setCurrentDirectory startpwd                           return onFail +-- The performGC in this function is a workaround for a library/GHC bug,+-- http://hackage.haskell.org/trac/ghc/ticket/2924 -- (doesn't seem to be a+-- problem on fast machines, but virtual ones trip this from time to time) amNotInRepository :: [DarcsFlag] -> IO (Either String ()) amNotInRepository (WorkRepoDir d:_) = do createDirectoryIfMissing False d+                                            `catchall` (performGC >> createDirectoryIfMissing False d)                                          -- note that the above could always fail                                          setCurrentDirectory d                                          amNotInRepository []@@ -300,7 +295,7 @@ slurp_pending repo@(Repo _ _ _ rt) = do   cur <- slurp_recorded repo   Sealed pend <- read_pending repo-  case apply_to_slurpy pend cur of+  case applyToSlurpy pend cur of     Just pendcur -> return pendcur     Nothing -> do putStrLn "Yikes, pending has conflicts.  Renaming file as_darcs/patches/pending_buggy"                   renameFile (pendingName rt) (pendingName rt++"_buggy")@@ -308,7 +303,7 @@  slurp_recorded :: RepoPatch p => Repository p C(r u t) -> IO Slurpy slurp_recorded (Repo dir opts rf (DarcsRepository _ c))-    | format_has HashedInventory rf =+    | formatHas HashedInventory rf =         HashedRepo.slurp_pristine c (compression opts) dir $ darcsdir++"/hashed_inventory" slurp_recorded repository@(Repo dir _ _ (DarcsRepository p _)) = do     mc <- withCurrentDirectory dir $ slurpPristine p@@ -323,34 +318,11 @@   cur <- slurp_recorded repo   Sealed pend <- read_pending repo   withCurrentDirectory r $-      case apply_to_slurpy pend cur of+      case applyToSlurpy pend cur of       Nothing -> fail "Yikes, pending has conflicts!"       Just pendslurp -> do unrec <- co_slurp pendslurp "."                            return (cur, unrec) -pendingName :: RepoType p -> String-pendingName (DarcsRepository _ _) = darcsdir++"/patches/pending"--read_pending :: RepoPatch p => Repository p C(r u t) -> IO (Sealed (FL Prim C(r)))-read_pending (Repo r _ _ tp) =-    withCurrentDirectory r (read_pendingfile (pendingName tp))--add_to_pending :: RepoPatch p => Repository p C(r u t) -> FL Prim C(u y) -> IO ()-add_to_pending (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return ()-add_to_pending repo p =-    do pend <- get_unrecorded repo-       make_new_pending repo (pend +>+ p)--readPrims :: B.ByteString -> Sealed (FL Prim C(x))-readPrims s = case readPatch s :: Maybe (Sealed (Patch C(x )), B.ByteString) of-              Nothing -> Sealed NilFL-              Just (Sealed p,_) -> Sealed (effect p)--read_pendingfile :: String -> IO (Sealed (FL Prim C(x)))-read_pendingfile name = do-  pend <- gzReadFilePS name `catchall` return B.empty-  return $ readPrims pend- make_new_pending :: forall p C(r u t y). RepoPatch p => Repository p C(r u t) -> FL Prim C(r y) -> IO () make_new_pending (Repo _ opts _ _) _ | NoUpdateWorking `elem` opts = return () make_new_pending repo@(Repo r _ _ tp) origp =@@ -361,7 +333,7 @@        writeSealedPatch newname $ seal $ fromPrims $ sfp        cur <- slurp_recorded repo        Sealed p <- read_pendingfile newname-       when (isNothing $ apply_to_slurpy p cur) $ do+       when (isNothing $ applyToSlurpy p cur) $ do          let buggyname = pendingName tp ++ "_buggy"          renameFile newname buggyname          bugDoc $ text "There was an attempt to write an invalid pending!"@@ -376,113 +348,45 @@ sift_for_pending :: FL Prim C(x y) -> Sealed (FL Prim C(x)) sift_for_pending simple_ps =  let oldps = maybe simple_ps id $ try_shrinking_inverse $ crude_sift simple_ps- in if allFL (\p -> is_addfile p || is_adddir p) $ oldps+ in if allFL (\p -> primIsAddfile p || primIsAdddir p) $ oldps     then seal oldps     else fromJust $ do       Sealed x <- return $ sfp NilFL $ reverseFL oldps-      return (case try_to_shrink x of+      return (case tryToShrink x of               ps | lengthFL ps < lengthFL oldps -> sift_for_pending ps                  | otherwise -> seal ps)       where sfp :: FL Prim C(a b) -> RL Prim C(c a) -> Sealed (FL Prim C(c))             sfp sofar NilRL = seal sofar             sfp sofar (p:<:ps)-                | is_hunk p || is_binary p+                | primIsHunk p || primIsBinary p                     = case commuteFL (p :> sofar) of                       Right (sofar' :> _) -> sfp sofar' ps                       Left _ -> sfp (p:>:sofar) ps             sfp sofar (p:<:ps) = sfp (p:>:sofar) ps -get_unrecorded_no_look_for_adds :: RepoPatch p => Repository p C(r u t) -> [FileName] -> IO (FL Prim C(r y))-get_unrecorded_no_look_for_adds r paths = get_unrecorded_private (filter (/= LookForAdds)) r paths --get_unrecorded_unsorted :: RepoPatch p => Repository p C(r u t) -> IO (FL Prim C(r u))-get_unrecorded_unsorted r = get_unrecorded_in_files_unsorted r []--get_unrecorded :: RepoPatch p => Repository p C(r u t) -> IO (FL Prim C(r u))-get_unrecorded r = get_unrecorded_private id r []---- | Gets the unrecorded changes in the given paths in the current repository,---   without sorting them for presentation to the user-get_unrecorded_in_files_unsorted :: RepoPatch p => Repository p C(r u t) -> [FileName] -> IO (FL Prim C(r u))-get_unrecorded_in_files_unsorted = get_unrecorded_private (AnyOrder:)---- | Gets the unrecorded changes in the given paths in the current repository.-get_unrecorded_in_files :: RepoPatch p => Repository p C(r u t) -> [FileName] -> IO (FL Prim C(r u))-get_unrecorded_in_files = get_unrecorded_private id ---- | The /unrecorded/ includes the pending and the working directory changes.---   The third argument is a list of paths: if this list is [], it will diff---   the whole repo, but if there are elements in it, the function will return---   only changes to files under those paths. The paths must be fixed paths ---   starting with ".", but need not yet be unique.-get_unrecorded_private :: RepoPatch p => ([DarcsFlag]->[DarcsFlag]) -> Repository p C(r u t) -> [FileName] -> IO (FL Prim C(r y))-get_unrecorded_private _ (Repo _ opts _ _) _-    | NoUpdateWorking `elem` opts = return $ unsafeCoerceP NilFL-get_unrecorded_private modopts repository@(Repo r oldopts _ _) files =-  withCurrentDirectory r (do-    debugMessage "Looking for unrecorded changes..."-    cur <- slurp_pending repository-    work <- if LookForAdds `elem` opts-            then do nboring <- if Boring `elem` opts-                               then return $ darcsdir_filter-                               else boring_file_filter-                    slurp_unboring (myfilt cur nboring) "."-            else co_slurp cur "."-    ftf <- filetype_function-    Sealed pend <- read_pending repository-    let changed_files = apply_to_filepaths pend filesFP-        pre_changed_files = apply_to_filepaths (invert pend) filesFP-    Sealed relevantPend <- return $ if null files-                                      then seal pend-                                      else choose_touching pre_changed_files pend-    debugMessage "diffing dir..."-    let diffs = if null files-                  then unsafeDiff opts ftf cur work-                  else unsafeDiffAtPaths (ignoreTimes, lookForAdds, summary) ftf cur work changed_files-        dif = if AnyOrder `elem` opts-                  then relevantPend +>+ diffs-                  else sort_coalesceFL $ relevantPend +>+ diffs-    seq dif $ debugMessage "Found unrecorded changes."-    return dif)-    where myfilt s nboring f = slurp_has f s || nboring [f] /= []-          opts = modopts oldopts-          -- NoSummary/Summary both present gives False-          -- Just Summary gives True-          -- Just NoSummary gives False-          -- Neither gives False-          summary = Summary `elem` opts && NoSummary `notElem` opts-          lookForAdds = LookForAdds `elem` opts-          ignoreTimes = IgnoreTimes `elem` opts-          filesFP = map fn2fp files- -- @todo: we should not have to open the result of HashedRepo and -- seal it.  Instead, update this function to work with type witnesses -- by fixing DarcsRepo to match HashedRepo in the handling of -- Repository state. read_repo :: RepoPatch p => Repository p C(r u t) -> IO (PatchSet p C(r)) read_repo repo@(Repo r opts rf _)-    | format_has HashedInventory rf = do ps <- HashedRepo.read_repo repo r+    | formatHas HashedInventory rf =  do ps <- HashedRepo.read_repo repo r                                          return ps     | otherwise = do Sealed ps <- DarcsRepo.read_repo opts r                      return $ unsafeCoerceP ps  readTentativeRepo :: RepoPatch p => Repository p C(r u t) -> IO (PatchSet p C(t)) readTentativeRepo repo@(Repo r opts rf _)-    | format_has HashedInventory rf = do ps <- HashedRepo.read_tentative_repo repo r+    | formatHas HashedInventory rf = do  ps <- HashedRepo.read_tentative_repo repo r                                          return ps     | otherwise = do Sealed ps <- DarcsRepo.read_tentative_repo opts r                      return $ unsafeCoerceP ps  makePatchLazy :: RepoPatch p => Repository p C(r u t) -> PatchInfoAnd p C(x y) -> IO (PatchInfoAnd p C(x y)) makePatchLazy (Repo r opts rf (DarcsRepository _ c)) p-    | format_has HashedInventory rf = withCurrentDirectory r $ HashedRepo.write_and_read_patch c (compression opts) p+    | formatHas HashedInventory rf = withCurrentDirectory r $ HashedRepo.write_and_read_patch c (compression opts) p     | otherwise = withCurrentDirectory r $ DarcsRepo.write_and_read_patch opts p -sync_repo :: Repository p C(r u t) -> IO ()-sync_repo (Repo r _ rf (DarcsRepository _ c))-    | format_has HashedInventory rf = withCurrentDirectory r $ HashedRepo.sync_repo c-sync_repo (Repo r _ _ (DarcsRepository p _)) = withCurrentDirectory r $ syncPristine p- prefsUrl :: Repository p C(r u t) -> String prefsUrl (Repo r _ _ (DarcsRepository _ _)) = r ++ "/"++darcsdir++"/prefs" @@ -524,91 +428,26 @@           fromPrims_ = fromPrims  is_simple :: Prim C(x y) -> Bool-is_simple x = is_hunk x || is_binary x || is_setpref x+is_simple x = primIsHunk x || primIsBinary x || primIsSetpref x  crude_sift :: FL Prim C(x y) -> FL Prim C(x y) crude_sift xs = if allFL is_simple xs then filterFL ishunkbinary xs else xs     where ishunkbinary :: Prim C(x y) -> EqCheck C(x y)-          ishunkbinary x | is_hunk x || is_binary x = unsafeCoerceP IsEq+          ishunkbinary x | primIsHunk x || primIsBinary x = unsafeCoerceP IsEq                          | otherwise = NotEq  data HashedVsOld a = HvsO { old, hashed :: a }  decideHashedOrNormal :: Monad m => RepoFormat -> HashedVsOld (m a) -> m a decideHashedOrNormal rf (HvsO { hashed = h, old = o })-    | format_has HashedInventory rf = h+    | formatHas HashedInventory rf = h     | otherwise = o --tentativelyMergePatches :: RepoPatch p-                        => Repository p C(r u t) -> String -> [DarcsFlag]-                        -> FL (PatchInfoAnd p) C(x r) -> FL (PatchInfoAnd p) C(x y)-                        -> IO (Sealed (FL Prim C(u)))-tentativelyMergePatches = tentativelyMergePatches_ MakeChanges--considerMergeToWorking :: RepoPatch p-                       => Repository p C(r u t) -> String -> [DarcsFlag]-                       -> FL (PatchInfoAnd p) C(x r) -> FL (PatchInfoAnd p) C(x y)-                       -> IO (Sealed (FL Prim C(u)))-considerMergeToWorking = tentativelyMergePatches_ DontMakeChanges- data MakeChanges = MakeChanges | DontMakeChanges deriving ( Eq ) -tentativelyMergePatches_ :: forall p C(r u t y x). RepoPatch p-                         => MakeChanges-                         -> Repository p C(r u t) -> String -> [DarcsFlag]-                         -> FL (PatchInfoAnd p) C(x r) -> FL (PatchInfoAnd p) C(x y)-                         -> IO (Sealed (FL Prim C(u)))-tentativelyMergePatches_ mc r cmd opts usi themi =-  do let us = mapFL_FL hopefully usi-         them = mapFL_FL hopefully themi-     _ :/\: pc <- return $ merge (progressFL "Merging them" them :\/: progressFL "Merging us" us)-     pend <- get_unrecorded_unsorted r -- we don't care if it looks pretty...-     anonpend <- anonymous (fromPrims pend)-     pend' :/\: pw <- return $ merge (pc :\/: anonpend :>: NilFL)-     let pwprim = joinPatches $ progressFL "Examining patches for conflicts" $ mapFL_FL patchcontents pw-     Sealed standard_resolved_pw <- return $ standard_resolution pwprim-     debugMessage "Checking for conflicts..."-     mapM_ backupByCopying $ list_touched_files standard_resolved_pw-     debugMessage "Announcing conflicts..."-     have_conflicts <- announce_merge_conflicts cmd opts standard_resolved_pw-     debugMessage "Checking for unrecorded conflicts..."-     have_unrecorded_conflicts <- check_unrecorded_conflicts opts pc-     debugMessage "Reading working directory..."-     (_, working) <- slurp_recorded_and_unrecorded r-     debugMessage "Working out conflicts in actual working directory..."-     Sealed pw_resolution <--          case (want_external_merge opts, have_conflicts || have_unrecorded_conflicts) of-          (Nothing,_) -> return $ if AllowConflicts `elem` opts-                                  then seal NilFL-                                  else seal standard_resolved_pw-          (_,False) -> return $ seal standard_resolved_pw-          (Just c, True) -> external_resolution working c-                                                    (effect us +>+ pend)-                                                    (effect them) pwprim-     debugMessage "Applying patches to the local directories..."-     when (mc == MakeChanges) $-          do let doChanges :: FL (PatchInfoAnd p) C(x r) -> IO ()-                 doChanges NilFL = applyps r themi-                 doChanges _     = applyps r (mapFL_FL n2pia pc)-             doChanges usi-             setTentativePending r (effect pend' +>+ pw_resolution)-     return $ seal (effect pwprim +>+ pw_resolution)-  where mapAdd :: Repository p C(i l m) -> FL (PatchInfoAnd p) C(i j) -> [IO ()]-        mapAdd _ NilFL = []-        mapAdd r'@(Repo dir df rf dr) (a:>:as) =-               -- we construct a new Repository object on the recursive case so that the-               -- recordedstate of the repository can match the fact that we just wrote a patch-               tentativelyAddPatch_ DontUpdatePristine r' opts a : mapAdd (Repo dir df rf dr) as-        applyps :: Repository p C(i l m) -> FL (PatchInfoAnd p) C(i j) -> IO ()-        applyps repo ps = do debugMessage "Adding patches to inventory..."-                             sequence_ $ mapAdd repo ps-                             debugMessage "Applying patches to pristine..."-                             applyToTentativePristine repo ps- announce_merge_conflicts :: String -> [DarcsFlag] -> FL Prim C(x y) -> IO Bool announce_merge_conflicts cmd opts resolved_pw =-    case nubsort $ list_touched_files $ resolved_pw of+    case nubsort $ listTouchedFiles $ resolved_pw of     [] -> return False     cfs -> if MarkConflicts `elem` opts || AllowConflicts `elem` opts               || want_external_merge opts /= Nothing@@ -636,11 +475,11 @@                        pend ->                            case merge (fromPrims_ pend :\/: fromPrims_ (concatFL $ mapFL_FL effect pc)) of                            _ :/\: pend' ->-                               case list_conflicted_files pend' of+                               case listConflictedFiles pend' of                                [] -> return False-                               fs -> do yorn <- promptYorn-                                                ("You have conflicting local changes to:\n"-                                                 ++ unwords fs++"\nProceed?")+                               fs -> do putStrLn ("You have conflicting local changes to:\n"+                                                 ++ unwords fs)+                                        yorn <- promptYorn "Proceed?"                                         when (yorn /= 'y') $                                              do putStrLn "Cancelled."                                                 exitWith ExitSuccess@@ -736,7 +575,7 @@                                        prepend repository $ effect ps       remove_from_unrevert_context repository ps       debugMessage "Removing changes from tentative inventory..."-      if format_has HashedInventory rf+      if formatHas HashedInventory rf         then do HashedRepo.remove_from_tentative_inventory repository (compression opts) ps                 when (up == UpdatePristine) $                      HashedRepo.apply_to_tentative_pristine c opts $@@ -773,7 +612,7 @@ finalizeRepositoryChanges (Repo _ opts _ _)     | DryRun `elem` opts = bug "finalizeRepositoryChanges called when --dry-run specified" finalizeRepositoryChanges repository@(Repo dir opts rf _)-    | format_has HashedInventory rf =+    | formatHas HashedInventory rf =         withCurrentDirectory dir $ do debugMessage "Considering whether to test..."                                       testTentative repository                                       debugMessage "Finalizing changes..."@@ -802,7 +641,7 @@     when (Test `elem` opts) $ withCurrentDirectory dir $     do let putInfo = if not $ Quiet `elem` opts then putStrLn else const (return ())        debugMessage "About to run test if it exists."-       testline <- get_prefval "test"+       testline <- getPrefval "test"        case testline of          Nothing -> return ()          Just testcode ->@@ -837,7 +676,7 @@ getUMask (_:l) = getUMask l  withGutsOf :: Repository p C(r u t) -> IO () -> IO ()-withGutsOf (Repo _ _ rf _) | format_has HashedInventory rf = id+withGutsOf (Repo _ _ rf _) | formatHas HashedInventory rf = id                            | otherwise = withSignalsBlocked  withRepository :: [DarcsFlag] -> (forall p C(r u). RepoPatch p => Repository p C(r u r) -> IO a) -> IO a@@ -848,7 +687,7 @@ withRepositoryDirectory opts1 url job =     do Repo dir opts rf rt <- identifyDarcs1Repository opts1 url        let rt' = case rt of DarcsRepository t c -> DarcsRepository t c-       if format_has Darcs2 rf+       if formatHas Darcs2 rf          then do debugMessage $ "Identified darcs-2 repo: " ++ dir                  job1_ (Repo dir opts rf rt')          else do debugMessage $ "Identified darcs-1 repo: " ++ dir@@ -868,7 +707,7 @@ withRepoLock :: [DarcsFlag] -> (forall p C(r u). RepoPatch p => Repository p C(r u r) -> IO a) -> IO a withRepoLock opts job =     withRepository opts $- \repository@(Repo _ _ rf _) ->-    do case write_problem rf of+    do case writeProblem rf of          Nothing -> return ()          Just err -> fail err        let name = "./"++darcsdir++"/lock"@@ -882,13 +721,13 @@ withRepoReadLock :: [DarcsFlag] -> (forall p C(r u). RepoPatch p => Repository p C(r u r) -> IO a) -> IO a withRepoReadLock opts job =     withRepository opts $- \repository@(Repo _ _ rf _) ->-    do case write_problem rf of+    do case writeProblem rf of          Nothing -> return ()          Just err -> fail err        let name = "./"++darcsdir++"/lock"            wu = case (getUMask opts) of Nothing -> id                                         Just u -> withUMask u-       wu $ if format_has HashedInventory rf || DryRun `elem` opts+       wu $ if formatHas HashedInventory rf || DryRun `elem` opts             then job repository             else withLock name (revertRepositoryChanges repository >> job repository) @@ -898,7 +737,8 @@   Sealed bundle <- unrevert_patch_bundle `catchall` (return $ seal (NilRL:<:NilRL))   remove_from_unrevert_context_ bundle   where unrevert_impossible unrevert_loc =-            do yorn <- promptYorn "This operation will make unrevert impossible!\nProceed?"+            do putStrLn "This operation will make unrevert impossible!"+               yorn <- promptYorn "Proceed?"                case yorn of                  'n' -> fail "Cancelled."                  'y' -> removeFile unrevert_loc `catchall` return ()@@ -916,15 +756,14 @@             debugMessage "Adjusting the context of the unrevert changes..."             ref <- readTentativeRepo repository             case get_common_and_uncommon (bundle, ref) of-                 (common,(h_us:<:NilRL):<:NilRL :\/: NilRL:<:NilRL) ->+                 (common,(h_us:<:NilRL) :\/: NilRL) ->                     case commuteRL (reverseFL ps :> hopefully h_us) of                     Nothing -> unrevert_impossible unrevert_loc                     Just (us' :> _) -> do-                        s <- slurp_recorded repository-                        writeDocBinFile unrevert_loc $-                             make_bundle [] s-                             (common \\ pis) (us':>:NilFL)-                 (common,(x:<:NilRL):<:NilRL:\/:_)+                        s <- readRecorded repository+                        bundle' <- make_bundle [] s (common \\ pis) (us' :>: NilFL)+                        writeDocBinFile unrevert_loc bundle'+                 (common,(x:<:NilRL):\/:_)                         | isr && any (`elem` common) pis -> unrevert_impossible unrevert_loc                         | isr -> return ()                         where isr = isJust $ hopefullyM x@@ -957,14 +796,9 @@     HvsO { hashed = HashedRepo.clean_pristine repository,            old = return () } -replacePristineFromSlurpy :: Repository p C(r u t) -> Slurpy -> IO ()-replacePristineFromSlurpy (Repo r opts rf (DarcsRepository pris c)) s-    | format_has HashedInventory rf = withCurrentDirectory r $ HashedRepo.replacePristineFromSlurpy c (compression opts) s-    | otherwise = withCurrentDirectory r $ Pristine.replacePristineFromSlurpy s pris- createPristineDirectoryTree :: RepoPatch p => Repository p C(r u t) -> FilePath -> IO () createPristineDirectoryTree repo@(Repo r opts rf (DarcsRepository pris c)) reldir-    | format_has HashedInventory rf =+    | formatHas HashedInventory rf =         do createDirectoryIfMissing True reldir            withCurrentDirectory reldir $ HashedRepo.copy_pristine c (compression opts) r (darcsdir++"/hashed_inventory")     | otherwise =@@ -977,7 +811,7 @@ -- fp below really should be FileName createPartialsPristineDirectoryTree :: (FilePathLike fp, RepoPatch p) => Repository p C(r u t) -> [fp] -> FilePath -> IO () createPartialsPristineDirectoryTree (Repo r opts rf (DarcsRepository _ c)) prefs dir-    | format_has HashedInventory rf =+    | formatHas HashedInventory rf =         do createDirectoryIfMissing True dir            withCurrentDirectory dir $                HashedRepo.copy_partials_pristine c (compression opts) r (darcsdir++"/hashed_inventory") prefs@@ -987,34 +821,17 @@       unless done $ withRecorded r (withTempDir "recorded") $ \_ -> do           clonePartialsTree "." dir (map toFilePath prefs) -pristineFromWorking :: RepoPatch p => Repository p C(r u t) -> IO ()-pristineFromWorking (Repo dir opts rf (DarcsRepository _ c))-    | format_has HashedInventory rf =-        withCurrentDirectory dir $ HashedRepo.pristine_from_working c (compression opts)-pristineFromWorking (Repo dir _ _ (DarcsRepository p _)) =-  withCurrentDirectory dir $ createPristineFromWorking p- withRecorded :: RepoPatch p => Repository p C(r u t)              -> ((AbsolutePath -> IO a) -> IO a) -> (AbsolutePath -> IO a) -> IO a withRecorded repository mk_dir f     = mk_dir $ \d -> do createPristineDirectoryTree repository (toFilePath d)                         f d -checkPristineAgainstSlurpy :: RepoPatch p => Repository p C(r u t) -> Slurpy -> IO Bool-checkPristineAgainstSlurpy repository@(Repo _ opts _ _) s2 =-    do s1 <- slurp_recorded repository-       ftf <- filetype_function-       -- The @$!@ is necessary because some code called from this function uses-       -- unsafeInterleaveIO around functions that throw exceptions. If one used-       -- @$@ instead of @$!@ here, those exceptions might not be caught by code-       -- that runs this function inside a @catch@.-       return $! nullFL $ unsafeDiff (LookForAdds:IgnoreTimes:opts) ftf s1 s2- withTentative :: forall p a C(r u t). RepoPatch p =>                  Repository p C(r u t) -> ((AbsolutePath -> IO a) -> IO a)               -> (AbsolutePath -> IO a) -> IO a withTentative (Repo dir opts rf (DarcsRepository _ c)) mk_dir f-    | format_has HashedInventory rf =+    | formatHas HashedInventory rf =         mk_dir $ \d -> do HashedRepo.copy_pristine c (compression opts) dir (darcsdir++"/tentative_pristine")                           f d withTentative repository@(Repo dir opts _ _) mk_dir f =@@ -1032,7 +849,7 @@ getMarkedupFile repository pinfo f = do   Sealed (FlippedSeal patches) <- (seal . dropWhileFL ((/= pinfo) . info)                                   . reverseRL . concatRL) `liftM` read_repo repository-  return $ snd $ do_mark_all patches (f, empty_markedup_file)+  return $ snd $ do_mark_all patches (f, emptyMarkedupFile)   where dropWhileFL :: (FORALL(x y) a C(x y) -> Bool) -> FL a C(r v) -> FlippedSeal (FL a) C(v)         dropWhileFL _ NilFL       = flipSeal NilFL         dropWhileFL p xs@(x:>:xs')@@ -1042,7 +859,7 @@             -> (FilePath, MarkedUpFile) -> (FilePath, MarkedUpFile) do_mark_all (hp:>:pps) (f, mk) =     case hopefullyM hp of-    Just p -> do_mark_all pps $ markup_file (info hp) (patchcontents p) (f, mk)+    Just p -> do_mark_all pps $ markupFile (info hp) (patchcontents p) (f, mk)     Nothing -> (f, [(BC.pack "Error reading a patch!",None)]) do_mark_all NilFL (f, mk) = (f, mk) 
+ src/Darcs/Repository/LowLevel.hs view
@@ -0,0 +1,51 @@+-- Copyright (C) 2002-2004,2007-2008 David Roundy+-- Copyright (C) 2005 Juliusz Chroboczek+--+-- This program is free software; you can redistribute it and/or modify+-- it under the terms of the GNU General Public License as published by+-- the Free Software Foundation; either version 2, or (at your option)+-- any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+{-# LANGUAGE CPP #-}++#include "gadts.h"++module Darcs.Repository.LowLevel ( read_pending, read_pendingfile, pendingName, readPrims ) where++import Darcs.Repository.InternalTypes ( RepoType(..), Repository(..) )+import Darcs.Patch ( readPatch, Prim, Patch, RepoPatch, effect )+import Darcs.Global ( darcsdir )+import Darcs.Witnesses.Sealed ( Sealed(Sealed) )+import Darcs.Witnesses.Ordered ( FL(..) )+import Darcs.Utils ( catchall, withCurrentDirectory )+import ByteStringUtils ( gzReadFilePS )+import qualified Data.ByteString as BS ( ByteString, empty )++pendingName :: RepoType p -> String+pendingName (DarcsRepository _ _) = darcsdir++"/patches/pending"++read_pending :: RepoPatch p => Repository p C(r u t) -> IO (Sealed (FL Prim C(r)))+read_pending (Repo r _ _ tp) =+    withCurrentDirectory r (read_pendingfile (pendingName tp))++read_pendingfile :: String -> IO (Sealed (FL Prim C(x)))+read_pendingfile name = do+  pend <- gzReadFilePS name `catchall` return BS.empty+  return $ readPrims pend++readPrims :: BS.ByteString -> Sealed (FL Prim C(x))+readPrims s = case readPatch s :: Maybe (Sealed (Patch C(x )), BS.ByteString) of+              Nothing -> Sealed NilFL+              Just (Sealed p,_) -> Sealed (effect p)+
+ src/Darcs/Repository/Merge.hs view
@@ -0,0 +1,113 @@+-- Copyright (C) 2002-2004,2007-2008 David Roundy+-- Copyright (C) 2005 Juliusz Chroboczek+-- Copyright (C) 2009 Petr Rockai+--+-- This program is free software; you can redistribute it and/or modify+-- it under the terms of the GNU General Public License as published by+-- the Free Software Foundation; either version 2, or (at your option)+-- any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++#include "gadts.h"++module Darcs.Repository.Merge where++import Darcs.Resolution ( standard_resolution, external_resolution )+import Darcs.External ( backupByCopying )+import Control.Monad ( when )++import Darcs.Patch ( Effect )+import Darcs.Hopefully ( PatchInfoAnd, n2pia, hopefully )+import Darcs.Flags+    ( DarcsFlag( AllowConflicts ), want_external_merge )+import Darcs.Witnesses.Ordered+    ( FL(..), (:\/:)(..), (:/\:)(..), (+>+), mapFL_FL )+import Darcs.Patch+    ( RepoPatch, Prim, merge, joinPatches, listTouchedFiles+    , patchcontents, anonymous, fromPrims, effect )+import Progress( debugMessage )+import Darcs.ProgressPatches( progressFL )+import Darcs.Witnesses.Sealed( Sealed(Sealed), seal )+import Darcs.Repository.InternalTypes( Repository(..) )++import Darcs.Repository.State( unrecordedChanges, readUnrecorded )++import Darcs.Repository.Internal+    ( announce_merge_conflicts, check_unrecorded_conflicts+    , MakeChanges(..), setTentativePending+    , tentativelyAddPatch_, applyToTentativePristine, UpdatePristine(..) )++tentativelyMergePatches_ :: forall p C(r u t y x). RepoPatch p+                         => MakeChanges+                         -> Repository p C(r u t) -> String -> [DarcsFlag]+                         -> FL (PatchInfoAnd p) C(x r) -> FL (PatchInfoAnd p) C(x y)+                         -> IO (Sealed (FL Prim C(u)))+tentativelyMergePatches_ mc r cmd opts usi themi =+  do let us = mapFL_FL hopefully usi+         them = mapFL_FL hopefully themi+     _ :/\: pc <- return $ merge (progressFL "Merging them" them :\/: progressFL "Merging us" us)+     pend <- unrecordedChanges opts r []+     anonpend <- anonymous (fromPrims pend)+     pend' :/\: pw <- return $ merge (pc :\/: anonpend :>: NilFL)+     let pwprim = joinPatches $ progressFL "Examining patches for conflicts" $ mapFL_FL patchcontents pw+     Sealed standard_resolved_pw <- return $ standard_resolution pwprim+     debugMessage "Checking for conflicts..."+     mapM_ backupByCopying $ listTouchedFiles standard_resolved_pw+     debugMessage "Announcing conflicts..."+     have_conflicts <- announce_merge_conflicts cmd opts standard_resolved_pw+     debugMessage "Checking for unrecorded conflicts..."+     have_unrecorded_conflicts <- check_unrecorded_conflicts opts pc+     debugMessage "Reading working directory..."+     working <- readUnrecorded r+     debugMessage "Working out conflicts in actual working directory..."+     Sealed pw_resolution <-+          case (want_external_merge opts, have_conflicts || have_unrecorded_conflicts) of+          (Nothing,_) -> return $ if AllowConflicts `elem` opts+                                  then seal NilFL+                                  else seal standard_resolved_pw+          (_,False) -> return $ seal standard_resolved_pw+          (Just c, True) -> external_resolution working c+                                                    (effect us +>+ pend)+                                                    (effect them) pwprim+     debugMessage "Applying patches to the local directories..."+     when (mc == MakeChanges) $+          do let doChanges :: FL (PatchInfoAnd p) C(x r) -> IO ()+                 doChanges NilFL = applyps r themi+                 doChanges _     = applyps r (mapFL_FL n2pia pc)+             doChanges usi+             setTentativePending r (effect pend' +>+ pw_resolution)+     return $ seal (effect pwprim +>+ pw_resolution)+  where mapAdd :: Repository p C(i l m) -> FL (PatchInfoAnd p) C(i j) -> [IO ()]+        mapAdd _ NilFL = []+        mapAdd r'@(Repo dir df rf dr) (a:>:as) =+               -- we construct a new Repository object on the recursive case so that the+               -- recordedstate of the repository can match the fact that we just wrote a patch+               tentativelyAddPatch_ DontUpdatePristine r' opts a : mapAdd (Repo dir df rf dr) as+        applyps :: Repository p C(i l m) -> FL (PatchInfoAnd p) C(i j) -> IO ()+        applyps repo ps = do debugMessage "Adding patches to inventory..."+                             sequence_ $ mapAdd repo ps+                             debugMessage "Applying patches to pristine..."+                             applyToTentativePristine repo ps++tentativelyMergePatches :: RepoPatch p+                        => Repository p C(r u t) -> String -> [DarcsFlag]+                        -> FL (PatchInfoAnd p) C(x r) -> FL (PatchInfoAnd p) C(x y)+                        -> IO (Sealed (FL Prim C(u)))+tentativelyMergePatches = tentativelyMergePatches_ MakeChanges+++considerMergeToWorking :: RepoPatch p+                       => Repository p C(r u t) -> String -> [DarcsFlag]+                       -> FL (PatchInfoAnd p) C(x r) -> FL (PatchInfoAnd p) C(x y)+                       -> IO (Sealed (FL Prim C(u)))+considerMergeToWorking = tentativelyMergePatches_ DontMakeChanges+
src/Darcs/Repository/Prefs.lhs view
@@ -22,16 +22,16 @@  #include "gadts.h" -module Darcs.Repository.Prefs ( add_to_preflist, get_preflist, set_preflist,-                   get_global, environmentHelpHome,-                   defaultrepo, set_defaultrepo,-                   get_prefval, set_prefval, change_prefval,-                   def_prefval,-                   write_default_prefs,-                   boring_regexps, boring_file_filter, darcsdir_filter,-                   FileType(..), filetype_function,+module Darcs.Repository.Prefs ( addToPreflist, getPreflist, setPreflist,+                   getGlobal, environmentHelpHome,+                   defaultrepo, setDefaultrepo,+                   getPrefval, setPrefval, changePrefval,+                   defPrefval,+                   writeDefaultPrefs,+                   boringRegexps, boringFileFilter, darcsdirFilter,+                   FileType(..), filetypeFunction,                    getCaches,-                   binaries_file_help+                   binariesFileHelp                  ) where  import System.IO.Error ( isDoesNotExistError )@@ -71,10 +71,10 @@ \input{Darcs/ArgumentDefaults.lhs}  \begin{code}-write_default_prefs :: IO ()-write_default_prefs = do set_preflist "boring" default_boring-                         set_preflist "binaries" default_binaries-                         set_preflist "motd" []+writeDefaultPrefs :: IO ()+writeDefaultPrefs =   do setPreflist "boring" defaultBoring+                         setPreflist "binaries" defaultBinaries+                         setPreflist "motd" [] \end{code}  \paragraph{repos}@@ -124,7 +124,7 @@ as \verb!manual/index.html!) matches any of the boring regular expressions is considered boring.  The boring file is used to filter the files provided to darcs add, to allow you to use a-simple \verb-darcs add newdir newdir/*-+simple \verb-darcs add newdir newdir/-\verb-*- % cabal haddock barfs on adjacent / * without accidentally adding a bunch of object files.  It is also used when the \verb!--look-for-adds! flag is given to whatsnew or record.@@ -132,9 +132,9 @@ boring, even if it matches the boring file filter.  \begin{code}-{-# NOINLINE default_boring #-}-default_boring :: [String]-default_boring = ["# Boring file regexps:",+{-# NOINLINE defaultBoring #-}+defaultBoring :: [String]+defaultBoring = ["# Boring file regexps:",                   "",                   "### compiler and interpreter intermediate files",                   "# haskell (ghc) interfaces",@@ -229,20 +229,20 @@                   "# mac os finder",                   "(^|/)\\.DS_Store$" ] -darcsdir_filter :: [FilePath] -> [FilePath]-darcsdir_filter = filter (not.is_darcsdir)-is_darcsdir :: FilePath -> Bool-is_darcsdir ('.':'/':f) = is_darcsdir f-is_darcsdir "." = True-is_darcsdir "" = True-is_darcsdir ".." = True-is_darcsdir "../" = True-is_darcsdir fp = darcsdir `isPrefixOf` fp+darcsdirFilter :: [FilePath] -> [FilePath]+darcsdirFilter = filter (not.isDarcsdir)+isDarcsdir :: FilePath -> Bool+isDarcsdir ('.':'/':f) = isDarcsdir f+isDarcsdir "." = True+isDarcsdir "" = True+isDarcsdir ".." = True+isDarcsdir "../" = True+isDarcsdir fp = darcsdir `isPrefixOf` fp  -- | The path of the global preference directory; @~/.darcs@ on Unix, -- and @%APPDATA%/darcs@ on Windows.-global_prefs_dir :: IO (Maybe FilePath)-global_prefs_dir = do+globalPrefsDir :: IO (Maybe FilePath)+globalPrefsDir = do   env <- getEnvironment   case lookup "DARCS_TESTING_PREFS_DIR" env of     Just d -> return (Just d)@@ -255,26 +255,26 @@  "%APPDATA%/darcs (on Windows).  This is also the default location of",  "the cache."]) -get_global :: String -> IO [String]-get_global f = do-  dir <- global_prefs_dir+getGlobal :: String -> IO [String]+getGlobal f = do+  dir <- globalPrefsDir   case dir of-    (Just d) -> get_preffile $ d </> f+    (Just d) -> getPreffile $ d </> f     Nothing -> return [] -global_cache_dir :: IO (Maybe FilePath)-global_cache_dir = slash_cache `fmap` global_prefs_dir+globalCacheDir :: IO (Maybe FilePath)+globalCacheDir = slash_cache `fmap` globalPrefsDir   where slash_cache = fmap (</> "cache") -boring_regexps :: IO [Regex]-boring_regexps = do-    borefile <- def_prefval "boringfile" (darcsdir ++ "/prefs/boring")-    bores <- get_lines borefile `catchall` return []-    gbs <- get_global "boring"+boringRegexps :: IO [Regex]+boringRegexps = do+    borefile <- defPrefval "boringfile" (darcsdir ++ "/prefs/boring")+    bores <- getPrefLines borefile `catchall` return []+    gbs <- getGlobal "boring"     return $ map mkRegex $ bores ++ gbs -boring_file_filter :: IO ([FilePath] -> [FilePath])-boring_file_filter = boring_regexps >>= return . actual_boring_file_filter+boringFileFilter :: IO ([FilePath] -> [FilePath])+boringFileFilter = boringRegexps >>= return . actualBoringFileFilter  noncomments :: [String] -> [String] noncomments ss = filter is_ok ss@@ -282,8 +282,8 @@                        is_ok ('#':_) = False                        is_ok _ = True -get_lines :: ReadableDirectory m => FilePath -> m [String]-get_lines f = (notconflicts . noncomments . map stripCr . lines)+getPrefLines :: ReadableDirectory m => FilePath -> m [String]+getPrefLines f = (notconflicts . noncomments . map stripCr . lines)               `fmap` mReadBinFile (fp2fn f)     where notconflicts = filter nc           startswith [] _ = True@@ -296,9 +296,9 @@  -- | From a list of paths, filter out any that are within @_darcs@ or -- match a boring regexp.-actual_boring_file_filter :: [Regex] -> [FilePath] -> [FilePath]-actual_boring_file_filter regexps files = filter (not . boring . normalize) files-    where boring file = is_darcsdir file ||+actualBoringFileFilter :: [Regex] -> [FilePath] -> [FilePath]+actualBoringFileFilter regexps files = filter (not . boring . normalize) files+    where boring file = isDarcsdir file ||                         any (\regexp -> isJust $ matchRegex regexp file) regexps  normalize :: FilePath -> FilePath@@ -326,23 +326,23 @@ data FileType = BinaryFile | TextFile                 deriving (Eq) -{-# NOINLINE default_binaries #-}+{-# NOINLINE defaultBinaries #-} -- | The lines that will be inserted into @_darcs/prefs/binaries@ when -- @darcs init@ is run.  Hence, a list of comments, blank lines and -- regular expressions (ERE dialect). -- -- Note that while this matches .gz and .GZ, it will not match .gZ, -- i.e. it is not truly case insensitive.-default_binaries :: [String]-default_binaries = help +++defaultBinaries :: [String]+defaultBinaries = help ++                    ["\\.(" ++ e ++ "|" ++ map toUpper e ++ ")$" | e <- extensions ]     where extensions = ["a","bmp","bz2","doc","elc","exe","gif","gz","iso",                         "jar","jpe?g","mng","mpe?g","p[nbgp]m","pdf","png",                         "pyc","so","tar","tgz","tiff?","z","zip"]-          help = map ("# "++) binaries_file_help+          help = map ("# "++) binariesFileHelp -binaries_file_help :: [String]-binaries_file_help =+binariesFileHelp :: [String]+binariesFileHelp =   ["This file contains a list of extended regular expressions, one per",    "line.  A file path matching any of these expressions is assumed to",    "contain binary data (not text).  The entries in ~/.darcs/binaries (if",@@ -351,12 +351,12 @@    "Blank lines, and lines beginning with an octothorpe (#) are ignored.",    "See regex(7) for a description of extended regular expressions."] -filetype_function :: IO (FilePath -> FileType)-filetype_function = do-    binsfile <- def_prefval "binariesfile" (darcsdir ++ "/prefs/binaries")-    bins <- get_lines binsfile `catch`+filetypeFunction :: IO (FilePath -> FileType)+filetypeFunction = do+    binsfile <- defPrefval "binariesfile" (darcsdir ++ "/prefs/binaries")+    bins <- getPrefLines binsfile `catch`              (\e-> if isDoesNotExistError e then return [] else ioError e)-    gbs <- get_global "binaries"+    gbs <- getGlobal "binaries"     regexes <- return (map (\r -> mkRegex r) (bins ++ gbs))     let isbin f = or $ map (\r -> isJust $ matchRegex r f) regexes         ftf f = if isbin $ normalize f then BinaryFile else TextFile@@ -375,60 +375,60 @@ withPrefsDirectory j = do prefs <- prefsDirectory `mplus` return "x"                           when (prefs /= "x") $ j prefs -add_to_preflist :: WriteableDirectory m => String -> String -> m ()-add_to_preflist p s = withPrefsDirectory $ \prefs -> do+addToPreflist :: WriteableDirectory m => String -> String -> m ()+addToPreflist p s = withPrefsDirectory $ \prefs -> do   hasprefs <- mDoesDirectoryExist $ fp2fn prefs   unless hasprefs $ mCreateDirectory $ fp2fn prefs-  pl <- get_preflist p+  pl <- getPreflist p   mWriteBinFile (fp2fn $ prefs ++ p) $ unlines $ union [s] pl -get_preflist :: ReadableDirectory m => String -> m [String]-get_preflist p = do prefs <- prefsDirectory `mplus` return "x"-                    if (prefs /= "x") then get_preffile $ prefs ++ p+getPreflist :: ReadableDirectory m => String -> m [String]+getPreflist p =  do prefs <- prefsDirectory `mplus` return "x"+                    if (prefs /= "x") then getPreffile $ prefs ++ p                                       else return [] -get_preffile :: ReadableDirectory m => FilePath -> m [String]-get_preffile f = do+getPreffile :: ReadableDirectory m => FilePath -> m [String]+getPreffile f = do   hasprefs <- mDoesFileExist (fp2fn f)   if hasprefs-    then get_lines f+    then getPrefLines f     else return [] -set_preflist :: WriteableDirectory m => String -> [String] -> m ()-set_preflist p ls = withPrefsDirectory $ \prefs -> do+setPreflist :: WriteableDirectory m => String -> [String] -> m ()+setPreflist p ls = withPrefsDirectory $ \prefs -> do   haspref <- mDoesDirectoryExist $ fp2fn prefs   if haspref      then mWriteBinFile (fp2fn $ prefs ++ p) (unlines ls)      else return () -def_prefval :: String -> String -> IO String-def_prefval p d = do-  pv <- get_prefval p+defPrefval :: String -> String -> IO String+defPrefval p d = do+  pv <- getPrefval p   case pv of Nothing -> return d              Just v -> return v -get_prefval :: ReadableDirectory m => String -> m (Maybe String)-get_prefval p =-    do pl <- get_preflist "prefs"+getPrefval :: ReadableDirectory m => String -> m (Maybe String)+getPrefval p =+    do pl <- getPreflist "prefs"        case map snd $ filter ((==p).fst) $ map (break (==' ')) pl of            [val] -> case words val of                [] -> return Nothing                _ -> return $ Just $ tail val            _ -> return Nothing -set_prefval :: WriteableDirectory m => String -> String -> m ()-set_prefval p v = do pl <- get_preflist "prefs"-                     set_preflist "prefs" $+setPrefval :: WriteableDirectory m => String -> String -> m ()+setPrefval p v =  do pl <- getPreflist "prefs"+                     setPreflist "prefs" $                        filter ((/=p).fst.(break (==' '))) pl ++ [p++" "++v] -change_prefval :: WriteableDirectory m => String -> String -> String -> m ()-change_prefval p f t =-    do pl <- get_preflist "prefs"-       ov <- get_prefval p+changePrefval :: WriteableDirectory m => String -> String -> String -> m ()+changePrefval p f t =+    do pl <- getPreflist "prefs"+       ov <- getPrefval p        newval <- case ov of                  Nothing -> return t                  Just old -> if old == f then return t else return old-       set_preflist "prefs" $+       setPreflist "prefs" $                     filter ((/=p).fst.(break(==' '))) pl ++ [p++" "++newval]  defaultrepo :: [DarcsFlag] -> AbsolutePath -> [String] -> IO [String]@@ -437,22 +437,22 @@                 | otherwise = do absr <- ioAbsolute r                                  return $ toFilePath absr      case [r | RemoteRepo r <- opts] of-       [] -> do defrepo <- get_preflist "defaultrepo"+       [] -> do defrepo <- getPreflist "defaultrepo"                 case defrepo of                   [r] -> (:[]) `fmap` fixR r                   _ -> return []        rs -> mapM fixR rs defaultrepo _ _ r = return r -set_defaultrepo :: String -> [DarcsFlag] -> IO ()-set_defaultrepo r opts = do doit <- if (NoSetDefault `notElem` opts && DryRun `notElem` opts && r_is_not_tmp)+setDefaultrepo :: String -> [DarcsFlag] -> IO ()+setDefaultrepo r opts =  do doit <- if (NoSetDefault `notElem` opts && DryRun `notElem` opts && r_is_not_tmp)                                     then return True                                     else do olddef <--                                                get_preflist "defaultrepo"+                                                getPreflist "defaultrepo"                                             return (olddef == [])                             when doit-                                (set_preflist "defaultrepo" [r])-                            add_to_preflist "repos" r+                                (setPreflist "defaultrepo" [r])+                            addToPreflist "repos" r                          `catchall` return () -- we don't care if this fails!  where   r_is_not_tmp = not $ r `elem` [x | RemoteRepo x <- opts]@@ -503,16 +503,16 @@ \begin{code} getCaches :: [DarcsFlag] -> String -> IO Cache getCaches opts repodir =-    do here <- parsehs `fmap` get_preffile (darcsdir ++ "/prefs/sources")+    do here <- parsehs `fmap` getPreffile (darcsdir ++ "/prefs/sources")        there <- (parsehs . lines . BC.unpack) `fmap`                 (gzFetchFilePS (repodir ++ "/" ++ darcsdir ++ "/prefs/sources") Cachable                  `catchall` return B.empty)-       globalcachedir <- global_cache_dir+       globalcachedir <- globalCacheDir        let globalcache = case (nocache,globalcachedir) of                            (True,_) -> []                            (_,Just d) -> [Cache Directory Writable d]                            _ -> []-       globalsources <- parsehs `fmap` get_global "sources"+       globalsources <- parsehs `fmap` getGlobal "sources"        thisdir <- getCurrentDirectory        let thisrepo = if Ephemeral `elem` opts                       then [Cache Repo NotWritable $ toFilePath thisdir]
src/Darcs/Repository/Pristine.hs view
@@ -25,7 +25,6 @@                  createPristine, removePristine, identifyPristine,                  slurpPristine,                  applyPristine, createPristineFromWorking,-                 syncPristine, replacePristineFromSlurpy,                  getPristinePop,                  pristineDirectory, pristineToFlagString,                  easyCreatePristineDirectoryTree,@@ -34,17 +33,14 @@  import Data.Maybe ( isJust ) import Control.Monad ( when, liftM )-import System.Directory ( createDirectory, doesDirectoryExist, doesFileExist,-                   renameDirectory, removeFile )+import System.Directory ( createDirectory, doesDirectoryExist, doesFileExist, removeFile ) import Darcs.Lock ( rm_recursive, writeBinFile )-import Darcs.Diff ( sync ) import Workaround ( getCurrentDirectory )-import Darcs.SlurpDirectory ( Slurpy,  mmap_slurp, co_slurp, writeSlurpy )-import Darcs.Utils ( catchall )+import Darcs.SlurpDirectory ( Slurpy,  mmap_slurp )  import Darcs.PopulationData ( Population, getPopFrom ) import Darcs.Flags ( DarcsFlag( PristinePlain, PristineNone ) )-import Darcs.Repository.Format ( RepoFormat, format_has,+import Darcs.Repository.Format ( RepoFormat, formatHas,                                  RepoProperty(HashedInventory) ) import Darcs.IO ( WriteableDirectory(mWithCurrentDirectory) ) import Darcs.Patch ( Patchy, apply )@@ -97,7 +93,7 @@                      n2 = darcsdir++"/current" ++ ext  flagsToPristine :: [DarcsFlag] -> RepoFormat -> Pristine-flagsToPristine _ rf | format_has HashedInventory rf = HashedPristine+flagsToPristine _ rf | formatHas HashedInventory rf = HashedPristine flagsToPristine (PristineNone : _) _ = NoPristine (darcsdir++"/" ++ pristineName ++ ".none") flagsToPristine (PristinePlain : _) _ = PlainPristine (darcsdir++"/" ++ pristineName) flagsToPristine (_ : t) rf = flagsToPristine t rf@@ -143,28 +139,6 @@ createPristineFromWorking (NoPristine _) = return () createPristineFromWorking (PlainPristine n) = cloneTreeExcept [darcsdir] "." n createPristineFromWorking HashedPristine =-    bug "HashedPristine is not implemented yet."--syncPristine :: Pristine -> IO ()-syncPristine (NoPristine _) = return ()-syncPristine (PlainPristine n) =-    do ocur <- mmap_slurp n-       owork <- co_slurp ocur "."-       sync n ocur owork-syncPristine HashedPristine = return () -- FIXME this should be implemented!--replacePristineFromSlurpy :: Slurpy -> Pristine -> IO ()-replacePristineFromSlurpy _ (NoPristine _) = return ()-replacePristineFromSlurpy s (PlainPristine n) =-    do rm_recursive nold-           `catchall` return ()-       writeSlurpy s ntmp-       renameDirectory n nold-       renameDirectory ntmp n-       return ()-           where nold = darcsdir ++ "/" ++ pristineName ++ "-old"-                 ntmp = darcsdir ++ "/" ++ pristineName ++ "-tmp"-replacePristineFromSlurpy _ HashedPristine =     bug "HashedPristine is not implemented yet."  getPristinePop :: PatchInfo -> Pristine -> IO (Maybe Population)
src/Darcs/Repository/Repair.hs view
@@ -1,63 +1,59 @@ {-# OPTIONS_GHC -cpp #-} {-# LANGUAGE CPP #-} -module Darcs.Repository.Repair ( replayRepository,-                                 RepositoryConsistency(..) )+module Darcs.Repository.Repair ( replayRepository, checkIndex+                               , RepositoryConsistency(..) )        where         import Control.Monad ( when, unless )+import Control.Monad.Trans ( liftIO )+import Control.Applicative( (<$>) ) import Control.Exception ( finally ) import Data.Maybe ( catMaybes )-import Data.List ( sort )+import Data.List ( sort, (\\) ) import System.Directory ( createDirectoryIfMissing ) -import Darcs.SlurpDirectory ( empty_slurpy, withSlurpy, Slurpy, SlurpMonad, syncSlurpy ) import Darcs.Lock( rm_recursive ) import Darcs.Hopefully ( PatchInfoAnd, info ) -import Darcs.Ordered ( FL(..), RL(..), lengthFL, reverseFL, reverseRL, concatRL,+import Darcs.Witnesses.Ordered ( FL(..), RL(..), lengthFL, reverseFL, reverseRL, concatRL,                      mapRL )-import Darcs.Patch.Depends ( get_patches_beyond_tag ) import Darcs.Patch.Patchy ( applyAndTryToFix ) import Darcs.Patch.Info ( PatchInfo( .. ), human_friendly ) import Darcs.Patch.Set ( PatchSet )-import Darcs.Patch ( RepoPatch, patch2patchinfo )+import Darcs.Patch ( RepoPatch )  import Darcs.Repository.Format ( identifyRepoFormat, -                                 RepoProperty ( HashedInventory ), format_has )-import Darcs.Repository.Cache ( Cache, HashedDir( HashedPristineDir ) )-import Darcs.Repository.HashedIO ( slurpHashedPristine, writeHashedPristine,-                                   clean_hashdir )+                                 RepoProperty ( HashedInventory ), formatHas )+import Darcs.Repository.Cache ( HashedDir( HashedPristineDir ) )+import Darcs.Repository.HashedIO ( clean_hashdir ) import Darcs.Repository.HashedRepo ( readHashedPristineRoot )-import Darcs.Repository.Checkpoint ( get_checkpoint_by_default ) import Darcs.Repository.InternalTypes ( extractCache )-import Darcs.Repository ( Repository, read_repo,-                          checkPristineAgainstSlurpy,-                          makePatchLazy )+import Darcs.Repository.Prefs ( filetypeFunction )+import Darcs.Repository ( Repository, read_repo, makePatchLazy+                        , readRecorded, readIndex, readRecordedAndPending ) -import Darcs.Sealed ( Sealed(..), unsafeUnflippedseal ) import Progress ( debugMessage, beginTedious, endTedious, tediousSize, finishedOneIO ) import Darcs.Utils ( catchall ) import Darcs.Global ( darcsdir )-import Darcs.Flags ( compression ) import Printer ( Doc, putDocLn, text ) import Darcs.Arguments ( DarcsFlag( Verbose, Quiet ) )-#include "impossible.h" -run_slurpy :: Slurpy -> SlurpMonad a -> IO (Slurpy, a)-run_slurpy s f =-    case withSlurpy s f of-      Left err -> fail err-      Right x -> return x+import Darcs.Diff( treeDiff )+import Storage.Hashed.Monad( TreeIO )+import Storage.Hashed.Darcs( hashedTreeIO )+import Storage.Hashed.Tree( Tree, emptyTree )+import Storage.Hashed.AnchoredPath( anchorPath )+import Storage.Hashed.Hash( Hash(NoHash), encodeBase16 )+import Storage.Hashed.Tree( list, restrict, expand, itemHash, zipTrees )+import Storage.Hashed.Darcs( darcsUpdateHashes )+import Storage.Hashed.Index( updateIndex )+import Storage.Hashed( readPlainTree ) -update_slurpy :: Repository p -> Cache -> [DarcsFlag] -> Slurpy -> IO Slurpy-update_slurpy r c opts s = do-  current <- readHashedPristineRoot r-  h <- writeHashedPristine c (compression opts) s-  s' <- slurpHashedPristine c (compression opts) h-  clean_hashdir c HashedPristineDir $ catMaybes [Just h, current]-  return s'+import qualified Data.ByteString.Char8 as BS +#include "impossible.h"+ replaceInFL :: FL (PatchInfoAnd a)             -> [(PatchInfo, PatchInfoAnd a)]             -> FL (PatchInfoAnd a)@@ -67,33 +63,33 @@     | info o == o' = c:>:replaceInFL orig ch_rest     | otherwise = o:>:replaceInFL orig ch -applyAndFix :: RepoPatch p => Cache -> [DarcsFlag] -> Slurpy -> Repository p -> FL (PatchInfoAnd p) -> IO (FL (PatchInfoAnd p), Slurpy, Bool)-applyAndFix _ _ s _ NilFL = return (NilFL, s, True)-applyAndFix c opts s_ r psin =-    do beginTedious k-       tediousSize k $ lengthFL psin-       (repaired, slurpy, ok) <- aaf s_ psin-       endTedious k-       orig <- (reverseRL . concatRL) `fmap` read_repo r-       return (replaceInFL orig repaired, slurpy, ok)+applyAndFix :: forall p. RepoPatch p => Repository p -> FL (PatchInfoAnd p) -> TreeIO (FL (PatchInfoAnd p), Bool)+applyAndFix _ NilFL = return (NilFL, True)+applyAndFix r psin =+    do liftIO $ beginTedious k+       liftIO $ tediousSize k $ lengthFL psin+       (repaired, ok) <- aaf psin+       liftIO $ endTedious k+       orig <- liftIO $ (reverseRL . concatRL) `fmap` read_repo r+       return (replaceInFL orig repaired, ok)     where k = "Replaying patch"-          aaf s NilFL = return ([], s, True)-          aaf s (p:>:ps) = do-            (s', mp') <- run_slurpy s $ applyAndTryToFix p+          aaf :: FL (PatchInfoAnd p) -> TreeIO ([(PatchInfo, PatchInfoAnd p)], Bool)+          aaf NilFL = return ([], True)+          aaf (p:>:ps) = do+            mp' <- applyAndTryToFix p             let !infp = info p -- assure that 'p' can be garbage collected.-            finishedOneIO k $ show $ human_friendly $ infp-            s'' <- syncSlurpy (update_slurpy r c opts) s'-            (ps', s''', restok) <- aaf s'' ps+            liftIO $ finishedOneIO k $ show $ human_friendly $ infp+            (ps', restok) <- aaf ps             case mp' of-              Nothing -> return (ps', s''', restok)-              Just (e,pp) -> do putStrLn e-                                p' <- makePatchLazy r pp-                                return ((infp, p'):ps', s''', False)+              Nothing -> return (ps', restok)+              Just (e,pp) -> do liftIO $ putStrLn e+                                p' <- liftIO $ makePatchLazy r pp+                                return ((infp, p'):ps', False)  data RepositoryConsistency p =     RepositoryConsistent-  | BrokenPristine Slurpy-  | BrokenPatches Slurpy (PatchSet p)+  | BrokenPristine (Tree IO)+  | BrokenPatches (Tree IO) (PatchSet p)  check_uniqueness :: RepoPatch p => (Doc -> IO ()) -> (Doc -> IO ()) -> Repository p -> IO () check_uniqueness putVerbose putInfo repository =@@ -116,35 +112,32 @@   let putVerbose s = when (Verbose `elem` opts) $ putDocLn s       putInfo s = when (not $ Quiet `elem` opts) $ putDocLn s   check_uniqueness putVerbose putInfo repo-  maybe_chk <- get_checkpoint_by_default repo-  let c = extractCache repo   createDirectoryIfMissing False $ darcsdir ++ "/pristine.hashed"-  rooth <- writeHashedPristine c (compression opts) empty_slurpy-  s <- slurpHashedPristine c (compression opts) rooth+  putVerbose $ text "Reading recorded state..."+  pris <- readRecorded repo `catch` \_ -> return emptyTree   putVerbose $ text "Applying patches..."   patches <- read_repo repo-  (s', newpatches, patches_ok) <- case maybe_chk of-    Just (Sealed chk) ->-        do let chtg = patch2patchinfo chk-           putVerbose $ text "I am repairing from a checkpoint."-           (s'', _) <- run_slurpy s $ applyAndTryToFix chk-           (_, s_, ok) <- applyAndFix c opts s'' repo-                      (reverseRL $ concatRL $ unsafeUnflippedseal $ get_patches_beyond_tag chtg patches)-           return (s_, patches, ok)-    Nothing -> do debugMessage "Fixing any broken patches..."-                  let psin = reverseRL $ concatRL patches-                  (ps, s_, ok) <- applyAndFix c opts s repo psin-                  debugMessage "Done fixing broken patches..."-                  return (s_, (reverseFL ps :<: NilRL), ok)+  debugMessage "Fixing any broken patches..."+  let psin = reverseRL $ concatRL patches+      repair = applyAndFix repo psin+  ((ps, patches_ok), newpris) <- hashedTreeIO repair emptyTree "_darcs/pristine.hashed"+  debugMessage "Done fixing broken patches..."+  let newpatches = reverseFL ps :<: NilRL+   debugMessage "Checking pristine against slurpy"-  is_same <- checkPristineAgainstSlurpy repo s' `catchall` return False+  ftf <- filetypeFunction+  is_same <- do diff <- treeDiff ftf pris newpris+                return $ case diff of+                           NilFL -> True+                           _ -> False+              `catchall` return False   -- TODO is the latter condition needed? Does a broken patch imply pristine   -- difference? Why, or why not?   return (if is_same && patches_ok      then RepositoryConsistent      else if patches_ok-            then BrokenPristine s'-            else BrokenPatches s' newpatches)+            then BrokenPristine newpris+            else BrokenPatches newpris newpatches)  cleanupRepositoryReplay :: Repository p -> IO () cleanupRepositoryReplay r = do@@ -152,9 +145,9 @@   rf_or_e <- identifyRepoFormat "."   rf <- case rf_or_e of Left e -> fail e                         Right x -> return x-  unless (format_has HashedInventory rf) $+  unless (formatHas HashedInventory rf) $          rm_recursive $ darcsdir ++ "/pristine.hashed" -  when (format_has HashedInventory rf) $ do+  when (formatHas HashedInventory rf) $ do        current <- readHashedPristineRoot r        clean_hashdir c HashedPristineDir $ catMaybes [current] @@ -163,3 +156,33 @@     where run = do             st <- replayRepository' r opt             f st++checkIndex :: (RepoPatch p) => Repository p -> Bool -> IO Bool+checkIndex repo quiet = do+  index <- updateIndex =<< readIndex repo+  pristine <- expand =<< readRecordedAndPending repo+  working <- expand =<< restrict pristine <$> readPlainTree "."+  working_hashed <- darcsUpdateHashes working+  let index_paths = [ p | (p, _) <- list index ]+      working_paths = [ p | (p, _) <- list working ]+      index_extra = index_paths \\ working_paths+      working_extra = working_paths \\ index_paths+      gethashes p (Just i1) (Just i2) = (p, itemHash i1, itemHash i2)+      gethashes p (Just i1) Nothing   = (p, itemHash i1, NoHash)+      gethashes p   Nothing (Just i2) = (p,      NoHash, itemHash i2)+      gethashes p   Nothing Nothing   = error $ "Bad case at " ++ show p+      mismatches = [ miss | miss@(_, h1, h2) <- zipTrees gethashes index working_hashed, h1 /= h2 ]++      format paths = unlines $ (map $ (("  " ++) . anchorPath "")) paths+      mismatches_disp = unlines [ anchorPath "" p +++                                    "\n    index: " ++ BS.unpack (encodeBase16 h1) +++                                    "\n  working: " ++ BS.unpack (encodeBase16 h2)+                                  | (p, h1, h2) <- mismatches ]+  unless (quiet || null index_extra) $+         putStrLn $ "Extra items in index!\n" ++ format index_extra+  unless (quiet || null working_extra) $+         putStrLn $ "Missing items in index!\n" ++ format working_extra+  unless (quiet || null mismatches) $+         putStrLn $ "Hash mismatch(es)!\n" ++ mismatches_disp+  return $ null index_extra && null working_extra && null mismatches+
+ src/Darcs/Repository/State.hs view
@@ -0,0 +1,244 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -cpp -fglasgow-exts -fno-warn-orphans #-}++-- Copyright (C) 2009 Petr Rockai+--+-- Permission is hereby granted, free of charge, to any person+-- obtaining a copy of this software and associated documentation+-- files (the "Software"), to deal in the Software without+-- restriction, including without limitation the rights to use, copy,+-- modify, merge, publish, distribute, sublicense, and/or sell copies+-- of the Software, and to permit persons to whom the Software is+-- furnished to do so, subject to the following conditions:+--+-- The above copyright notice and this permission notice shall be+-- included in all copies or substantial portions of the Software.+--+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+-- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+-- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+-- SOFTWARE.++module Darcs.Repository.State+    ( restrictSubpaths, restrictBoring+    -- * Diffs.+    , unrecordedChanges, readPending, pendingChanges+    -- * Trees.+    , readRecorded, readUnrecorded, readRecordedAndPending+    -- * Index.+    , readIndex, invalidateIndex ) where++import Prelude hiding ( filter )+import Control.Monad( when )+import Control.Applicative( (<$>) )+import Data.Maybe( isJust )+import Data.List( union )+import Text.Regex( matchRegex )++import System.Directory( removeFile, doesFileExist, doesDirectoryExist, renameFile )+import System.FilePath ( (</>) )+import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as BSC++import Darcs.Patch ( RepoPatch, Prim, invert, applyToTree, applyToFilepaths+                   , sortCoalesceFL )+import Darcs.Patch.TouchesFiles ( choose_touching )+import Darcs.Witnesses.Ordered ( FL(..), (+>+) )+import Darcs.Witnesses.Sealed ( Sealed(Sealed), seal )+import Darcs.Diff ( treeDiff )+import Darcs.Flags ( DarcsFlag( LookForAdds ), willIgnoreTimes )+import Darcs.Utils ( filterPaths )++import Darcs.Repository.InternalTypes ( Repository )+import Darcs.Repository.LowLevel( read_pending )+import Darcs.Repository.Prefs ( filetypeFunction, boringRegexps )++import Darcs.Patch.FileName ( fn2fp )+import Darcs.RepoPath ( SubPath, sp2fn )++import Storage.Hashed.AnchoredPath( AnchoredPath(..), anchorPath, floatPath, Name(..) )+import Storage.Hashed.Tree( Tree, restrict, FilterTree, expand, filter, emptyTree, overlay, find )+import Storage.Hashed.Plain( readPlainTree )+import Storage.Hashed.Darcs( darcsTreeHash, readDarcsHashed, decodeDarcsHash, decodeDarcsSize )+import Storage.Hashed.Hash( Hash( NoHash ) )+import qualified Storage.Hashed.Index as I++#include "gadts.h"++-- | From a repository and a list of SubPath's, construct a filter that can be+-- used on a Tree (recorded or unrecorded state) of this repository. This+-- constructed filter will take pending into account, so the subpaths will be+-- translated correctly relative to pending move patches. As an exception for+-- convenience, if the subpath list is empty, the filter constructed is an+-- identity.+restrictSubpaths :: (RepoPatch p) => Repository p C(r u t) -> [SubPath]+                 -> IO (forall t m. FilterTree t m => t m -> t m)+restrictSubpaths repo subpaths = do+  Sealed pending <- read_pending repo+  let paths = map (fn2fp . sp2fn) subpaths+      paths' = paths `union` applyToFilepaths pending paths+      anchored = map floatPath paths'+      restrictPaths :: FilterTree t m => t m -> t m+      restrictPaths = if null subpaths then id else filter (filterPaths anchored)+  return restrictPaths++-- | Construct a Tree filter that removes any boring files the Tree might have+-- contained. Additionally, you should (in most cases) pass an (expanded) Tree+-- that corresponds to the recorded content of the repository. This is+-- important in the cases when the repository contains files that would be+-- boring otherwise. (If you pass emptyTree instead, such files will simply be+-- discarded by the filter, which is usually not what you want.)+--+-- This function is most useful when you have a plain Tree corresponding to the+-- full working copy of the repository, including untracked+-- files. Cf. whatsnew, record --look-for-adds.  NB. Assumes that our CWD is+-- the repository root.+restrictBoring :: forall t m. Tree m -> IO (FilterTree t m => t m -> t m)+restrictBoring guide = do+  boring <- boringRegexps+  let boring' (AnchoredPath (Name x:_)) | x == BSC.pack "_darcs" = False+      boring' p = not $ any (\rx -> isJust $ matchRegex rx p') boring+          where p' = anchorPath "" p+      restrictTree :: FilterTree t m => t m -> t m+      restrictTree = filter $ \p _ -> case find guide p of+                                        Nothing -> boring' p+                                        _ -> True+  return restrictTree++-- | For a repository and a list of paths (when empty, take everything) compute+-- a (forward) list of prims (i.e. a patch) going from the recorded state of+-- the repository (pristine) to the unrecorded state of the repository (the+-- working copy + pending). When a non-empty list of paths is given, exactly+-- the files that live under any of these paths in either recorded or+-- unrecorded will be included in the resulting patch.+--+-- This also depends on the options given: with LookForAdds, we will include+-- any non-boring files (i.e. also those that do not exist in the "recorded"+-- state) in the working in the "unrecorded" state, and therefore they will+-- show up in the patches as addfiles.+--+-- The IgnoreTimes option disables index usage completely -- for each file, we+-- read both the unrecorded and the recorded copy and run a diff on them. This+-- is very inefficient, although in extremely rare cases, the index could go+-- out of sync (file is modified, index is updated and file is modified again+-- within a single second).+unrecordedChanges :: (RepoPatch p) => [DarcsFlag] -> Repository p C(r u t)+                  -> [SubPath] -> IO (FL Prim C(r y))+unrecordedChanges opts repo paths = do+  (all_current, _) <- readPending repo+  Sealed pending <- pendingChanges repo paths++  relevant <- restrictSubpaths repo paths+  let getIndex = I.updateIndex =<< (relevant <$> readIndex repo)+      current = relevant all_current++  working <- case (LookForAdds `elem` opts, willIgnoreTimes opts) of+               (False, False) -> getIndex+               (False, True) -> do+                 guide <- expand current+                 relevant <$> restrict guide <$> readPlainTree "."+               (True, ignoretimes) -> do+                 index <- getIndex+                 nonboring <- restrictBoring index+                 plain <- relevant <$> nonboring <$> readPlainTree "."+                 return $ if ignoretimes then plain else plain `overlay` index++  ft <- filetypeFunction+  diff <- treeDiff ft current working+  return $ sortCoalesceFL (pending +>+ diff)++-- | Obtains a Tree corresponding to the "recorded" state of the repository:+-- this is the same as the pristine cache, which is the same as the result of+-- applying all the repository's patches to an empty directory.+--+-- Handles the plain and hashed pristine cases. Currently does not handle the+-- no-pristine case, as that requires replaying patches. Cf. 'readDarcsHashed'+-- and 'readPlainTree' in hashed-storage that are used to do the actual 'Tree'+-- construction.+readRecorded :: (RepoPatch p) => Repository p C(r u t) -> IO (Tree IO)+readRecorded _repo = do+  let darcs = "_darcs"+      h_inventory = darcs </> "hashed_inventory"+  hashed <- doesFileExist h_inventory+  if hashed+     then do inv <- BS.readFile h_inventory+             let linesInv = BSC.split '\n' inv+             case linesInv of+               [] -> return emptyTree+               (pris_line:_) -> do+                          let hash = decodeDarcsHash $ BS.drop 9 pris_line+                              size = decodeDarcsSize $ BS.drop 9 pris_line+                          when (hash == NoHash) $ fail $ "Bad pristine root: " ++ show pris_line+                          readDarcsHashed (darcs </> "pristine.hashed") (size, hash)+     else do have_pristine <- doesDirectoryExist $ darcs </> "pristine"+             have_current <- doesDirectoryExist $ darcs </> "current"+             case (have_pristine, have_current) of+               (True, _) -> readPlainTree $ darcs </> "pristine"+               (False, True) -> readPlainTree $ darcs </> "current"+               (_, _) -> fail "No pristine tree is available!"++-- | Obtains a Tree corresponding to the "unrecorded" state of the repository:+-- the working tree plus the "pending" patch.+readUnrecorded :: (RepoPatch p) => Repository p C(r u t) -> IO (Tree IO)+readUnrecorded repo = readIndex repo >>= I.updateIndex++readRecordedAndPending :: (RepoPatch p) => Repository p C(r u t) -> IO (Tree IO)+readRecordedAndPending repo = do+  pristine <- readRecorded repo+  Sealed pending <- pendingChanges repo []+  applyToTree pending pristine++readPending :: (RepoPatch p) => Repository p C(r u t) -> IO (Tree IO, Sealed (FL Prim C(r)))+readPending repo =+  do Sealed pending <- read_pending repo+     pristine <- readRecorded repo+     catch ((\t -> (t, seal pending)) `fmap` applyToTree pending pristine) $ \ err -> do+       putStrLn $ "Yikes, pending has conflicts! " ++ show err+       putStrLn $ "Stashing the buggy pending as _darcs/patches/pending_buggy"+       renameFile "_darcs/patches/pending"+                  "_darcs/patches/pending_buggy"+       return (pristine, seal NilFL)++pendingChanges :: (RepoPatch p) => Repository p C(r u t)+               -> [SubPath] -> IO (Sealed (FL Prim C(r)))+pendingChanges repo paths = do+  Sealed pending <- snd `fmap` readPending repo+  let files = map (fn2fp . sp2fn) paths+      pre_files = applyToFilepaths (invert pending) files+      relevant = case paths of+                   [] -> seal pending+                   _ -> choose_touching pre_files pending+  return relevant++-- | Mark the existing index as invalid. This has to be called whenever the+-- listing of pristine changes and will cause darcs to update the index next+-- time it tries to read it. (NB. This is about files added and removed from+-- pristine: changes to file content in either pristine or working are handled+-- transparently by the index reading code.)+invalidateIndex :: t -> IO ()+invalidateIndex _ = do+  BS.writeFile "_darcs/index_invalid" BS.empty++readIndex :: (RepoPatch p) => Repository p C(r u t) -> IO I.Index+readIndex repo = do+  invalid <- doesFileExist "_darcs/index_invalid"+  exist <- doesFileExist "_darcs/index"+  format_valid <- if exist+                     then I.indexFormatValid "_darcs/index"+                     else return True+  when (exist && not format_valid) $+#if mingw32_HOST_OS+       renameFile "_darcs/index" "_darcs/index.old"+#else+       removeFile "_darcs/index"+#endif+  if (not exist || invalid || not format_valid)+     then do pris <- readRecordedAndPending repo+             idx <- I.updateIndexFrom "_darcs/index" darcsTreeHash pris+             when invalid $ removeFile "_darcs/index_invalid"+             return idx+     else I.readIndex "_darcs/index" darcsTreeHash
src/Darcs/Resolution.lhs view
@@ -32,33 +32,35 @@ import Data.List ( zip4 ) import Control.Monad ( when ) -import Darcs.Patch ( RepoPatch, Prim, joinPatches, resolve_conflicts,+import Darcs.Diff( treeDiff )+import Darcs.Patch ( RepoPatch, Prim, joinPatches, resolveConflicts,                      effect,-                     apply_to_filepaths, patchcontents,-                     invert, list_conflicted_files, commute )+                     applyToFilepaths, patchcontents,+                     invert, listConflictedFiles, commute, applyToTree ) import Darcs.RepoPath ( toFilePath )-import Darcs.Ordered ( FL(..), RL(..), (:>)(..), (+>+),-                             mapFL_FL, reverseRL, lengthFL )+import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (+>+),+                             mapFL_FL, reverseRL )  import CommandLine ( parseCmd ) import Darcs.Hopefully ( hopefully )-import Darcs.Utils ( askUser )-import Darcs.SlurpDirectory ( Slurpy, slurp, write_files )+import Darcs.Utils ( askUser, filterFilePaths ) import Darcs.Patch.Set ( PatchSet )-import Darcs.Diff ( unsafeDiff )-import Darcs.Sealed ( Sealed(..) )-import Darcs.Repository.Prefs ( filetype_function )+import Darcs.Witnesses.Sealed ( seal )+import Darcs.Witnesses.Sealed ( Sealed(..) )+import Darcs.Repository.Prefs ( filetypeFunction ) import Exec ( exec, Redirect(..) ) import Darcs.Lock ( withTempDir ) import Darcs.External ( cloneTree )-import Darcs.Patch.Apply ( apply_to_slurpy ) +import qualified Storage.Hashed.Tree as Tree+import Storage.Hashed ( writePlainTree, readPlainTree )+ --import Darcs.ColorPrinter ( traceDoc ) --import Printer ( greenText, ($$), Doc ) --import Darcs.Patch ( showPatch )  standard_resolution :: RepoPatch p => p C(x y) -> Sealed (FL Prim C(y))-standard_resolution p = merge_list $ map head $ resolve_conflicts p+standard_resolution p = merge_list $ map head $ resolveConflicts p  merge_list :: [Sealed (FL Prim C(x))] -> Sealed (FL Prim C(x)) merge_list patches = doml NilFL patches@@ -156,18 +158,19 @@ Note that the defaults file does not want quotes around the command.  \begin{code}-external_resolution :: RepoPatch p => Slurpy -> String -> FL Prim C(x y) -> FL Prim C(x z)+external_resolution :: RepoPatch p => Tree.Tree IO -> String -> FL Prim C(x y) -> FL Prim C(x z)                     -> p C(y a)                     -> IO (Sealed (FL Prim C(a))) external_resolution s1 c p1 p2 pmerged = do- sa <- apply_to_slurpy (invert p1) s1- sm <- apply_to_slurpy pmerged s1- s2 <- apply_to_slurpy p2 sa- let nms = list_conflicted_files pmerged-     nas = apply_to_filepaths (invert pmerged) nms-     n1s = apply_to_filepaths p1 nas-     n2s = apply_to_filepaths p2 nas+ sa <- applyToTree (invert p1) s1+ sm <- applyToTree pmerged s1+ s2 <- applyToTree p2 sa+ let nms = listConflictedFiles pmerged+     nas = applyToFilepaths (invert pmerged) nms+     n1s = applyToFilepaths p1 nas+     n2s = applyToFilepaths p2 nas      ns = zip4 nas n1s n2s nms+     write_files tree fs = writePlainTree (Tree.filter (filterFilePaths fs) tree) "."   in do    former_dir <- getCurrentDirectory    withTempDir "version1" $ \absd1 -> do@@ -190,13 +193,10 @@              let d2 = toFilePath absd2              write_files s2 n2s              mapM_ (externally_resolve_file c da d1 d2 dm) ns-             sc <- slurp dc-             sfixed <- slurp dm-             ftf <- filetype_function-             case unsafeDiff [] ftf sc sfixed of-               di -> lengthFL di `seq` return (Sealed di)-               -- The `seq` above forces the two slurpies to be read before-               -- we delete their directories.+             sc <- readPlainTree dc+             sfixed <- readPlainTree dm+             ftf <- filetypeFunction+             seal `fmap` treeDiff ftf sc sfixed  externally_resolve_file :: String -> String -> String -> String -> String                         -> (FilePath, FilePath, FilePath, FilePath)@@ -226,9 +226,9 @@                                       Sealed NilFL patchset_conflict_resolutions (xs:<:_)     = --traceDoc (greenText "looking at resolutions" $$-      --         (sh $ resolve_conflicts $ joinPatches $+      --         (sh $ resolveConflicts $ joinPatches $       --              mapFL_FL (patchcontents . hopefully) $ reverseRL xs )) $-      merge_list $ map head $ resolve_conflicts $ joinPatches $+      merge_list $ map head $ resolveConflicts $ joinPatches $       mapFL_FL (patchcontents . hopefully) $ reverseRL xs     --where sh :: [[Sealed (FL Prim)]] -> Doc     --      sh [] = greenText "no more conflicts"
src/Darcs/RunCommand.hs view
@@ -26,30 +26,28 @@  import Darcs.Arguments ( DarcsFlag(..),                          help,-                         option_from_darcsoption,-                         list_options )+                         optionFromDarcsoption,+                         listOptions ) import Darcs.ArgumentDefaults ( get_default_flags ) import Darcs.Commands ( CommandArgs( CommandOnly, SuperCommandOnly, SuperCommandSub ),                         DarcsCommand,-                        command_name,-                        command_command,-                        command_prereq,-                        command_extra_arg_help,-                        command_extra_args,-                        command_argdefaults,-                        command_get_arg_possibilities,-                        command_options, command_alloptions,-                        disambiguate_commands,-                        get_command_help, get_command_mini_help,-                        get_subcommands,-                        extract_commands,-                        super_name,-                        subusage, chomp_newline )-#ifdef HAVE_HASKELL_ZLIB+                        commandName,+                        commandCommand,+                        commandPrereq,+                        commandExtraArgHelp,+                        commandExtraArgs,+                        commandArgdefaults,+                        commandGetArgPossibilities,+                        commandOptions, commandAlloptions,+                        disambiguateCommands,+                        getCommandHelp, getCommandMiniHelp,+                        getSubcommands,+                        extractCommands,+                        superName,+                        subusage, chompNewline ) import Darcs.Commands.GZCRCs ( doCRCWarnings ) import Darcs.Global ( atexit )-#endif-import Darcs.Commands.Help ( command_control_list )+import Darcs.Commands.Help ( commandControlList ) import Darcs.External ( viewDoc ) import Darcs.Global ( setDebugMode, setSshControlMasterDisabled,                       setTimingsMode, setVerboseMode )@@ -58,12 +56,13 @@ import Darcs.RepoPath ( getCurrentDirectory ) import Darcs.Test ( run_posthook, run_prehook ) import Darcs.Utils ( formatPath )+import Data.List ( intersperse ) import Printer ( text ) import URL ( setDebugHTTP, setHTTPPipelining )  run_the_command :: String -> [String] -> IO () run_the_command cmd args =-  either fail rtc $ disambiguate_commands command_control_list cmd args+  either fail rtc $ disambiguateCommands commandControlList cmd args  where   rtc (CommandOnly c, as)       = run_command Nothing c  as   rtc (SuperCommandOnly c,  as) = run_raw_supercommand c as@@ -80,18 +79,18 @@ run_command msuper cmd args = do    cwd <- getCurrentDirectory    let options = opts1 ++ opts2-       (opts1, opts2) = command_options cwd cmd+       (opts1, opts2) = commandOptions cwd cmd    case getOpt Permute-             (option_from_darcsoption cwd list_options++options) args of+             (optionFromDarcsoption cwd listOptions++options) args of     (opts,extra,[])-      | Help `elem` opts -> viewDoc $ text $ get_command_help msuper cmd+      | Help `elem` opts -> viewDoc $ text $ getCommandHelp msuper cmd       | ListOptions `elem` opts  -> do            setProgressMode False-           command_prereq cmd opts-           file_args <- command_get_arg_possibilities cmd+           commandPrereq cmd opts+           file_args <- commandGetArgPossibilities cmd            putStrLn $ get_options_options (opts1++opts2) ++ unlines file_args       | otherwise -> consider_running msuper cmd (addVerboseIfDebug opts) extra-    (_,_,ermsgs) -> do fail $ chomp_newline(unlines ermsgs)+    (_,_,ermsgs) -> do fail $ chompNewline(unlines ermsgs)     where addVerboseIfDebug opts | DebugVerbose `elem` opts = Debug:Verbose:opts                                  | otherwise = opts @@ -99,27 +98,27 @@                  -> [DarcsFlag] -> [String] -> IO () consider_running msuper cmd opts old_extra = do  cwd <- getCurrentDirectory- location <- command_prereq cmd opts+ location <- commandPrereq cmd opts  case location of    Left complaint -> fail $ "Unable to " ++-                     formatPath ("darcs " ++ super_name msuper ++ command_name cmd) +++                     formatPath ("darcs " ++ superName msuper ++ commandName cmd) ++                      " here.\n\n" ++ complaint    Right () -> do     specops <- add_command_defaults cmd opts-    extra <- (command_argdefaults cmd) specops cwd old_extra+    extra <- (commandArgdefaults cmd) specops cwd old_extra     when (Disable `elem` specops) $-      fail $ "Command "++command_name cmd++" disabled with --disable option!"-    if command_extra_args cmd < 0+      fail $ "Command "++commandName cmd++" disabled with --disable option!"+    if commandExtraArgs cmd < 0       then runWithHooks specops extra-      else if length extra > command_extra_args cmd+      else if length extra > commandExtraArgs cmd            then fail $ "Bad argument: `"++unwords extra++"'\n"++-                       get_command_mini_help msuper cmd-           else if length extra < command_extra_args cmd+                       getCommandMiniHelp msuper cmd+           else if length extra < commandExtraArgs cmd                 then fail $ "Missing argument:  " ++                             nth_arg (length extra + 1) ++-                            "\n" ++ get_command_mini_help msuper cmd+                            "\n" ++ getCommandMiniHelp msuper cmd                 else runWithHooks specops extra-       where nth_arg n = nth_of n (command_extra_arg_help cmd)+       where nth_arg n = nth_of n (commandExtraArgHelp cmd)              nth_of 1 (h:_) = h              nth_of n (_:hs) = nth_of (n-1) hs              nth_of _ [] = "UNDOCUMENTED"@@ -135,52 +134,45 @@                when (HTTPPipelining `elem` os) $ setHTTPPipelining True                when (NoHTTPPipelining `elem` os) $ setHTTPPipelining False                unless (SSHControlMaster `elem` os) setSshControlMasterDisabled-#ifdef HAVE_HASKELL_ZLIB                unless (Quiet `elem` os) $ atexit $ doCRCWarnings (Verbose `elem` os)-#endif                -- actually run the command and its hooks                preHookExitCode <- run_prehook os here                if preHookExitCode /= ExitSuccess                   then exitWith preHookExitCode                   else do let fixFlag = FixFilePath here cwd-                          (command_command cmd) (fixFlag : os) ex+                          (commandCommand cmd) (fixFlag : os) ex                           postHookExitCode <- run_posthook os here                           exitWith postHookExitCode  add_command_defaults :: DarcsCommand -> [DarcsFlag] -> IO [DarcsFlag] add_command_defaults cmd already = do-  let (opts1, opts2) = command_alloptions cmd-  defaults <- get_default_flags (command_name cmd) (opts1 ++ opts2) already+  let (opts1, opts2) = commandAlloptions cmd+  defaults <- get_default_flags (commandName cmd) (opts1 ++ opts2) already   return $ already ++ defaults  get_options_options :: [OptDescr DarcsFlag] -> String-get_options_options [] = ""-get_options_options (o:os) =-    get_long_option o ++"\n"++ get_options_options os--get_long_option :: OptDescr DarcsFlag -> String-get_long_option (Option _ [] _ _) = ""-get_long_option (Option a (o:os) b c) = "--"++o++-                 get_long_option (Option a os b c)+get_options_options = concat . intersperse "\n" . concatMap goo+ where+  goo (Option _ os _ _) = map ("--"++) os  run_raw_supercommand :: DarcsCommand -> [String] -> IO () run_raw_supercommand super [] =-    fail $ "Command '"++ command_name super ++"' requires subcommand!\n\n"+    fail $ "Command '"++ commandName super ++"' requires subcommand!\n\n"              ++ subusage super run_raw_supercommand super args = do   cwd <- getCurrentDirectory   case getOpt RequireOrder-             (option_from_darcsoption cwd help++-              option_from_darcsoption cwd list_options) args of+             (optionFromDarcsoption cwd help+++              optionFromDarcsoption cwd listOptions) args of     (opts,_,[])       | Help `elem` opts ->-            viewDoc $ text $ get_command_help Nothing super+            viewDoc $ text $ getCommandHelp Nothing super       | ListOptions `elem` opts -> do             putStrLn "--help"-            mapM_ (putStrLn . command_name) (extract_commands $ get_subcommands super)+            mapM_ (putStrLn . commandName) (extractCommands $ getSubcommands super)       | otherwise ->             if Disable `elem` opts-            then fail $ "Command " ++ (command_name super) +++            then fail $ "Command " ++ (commandName super) ++                       " disabled with --disable option!"             else fail $ "Invalid subcommand!\n\n" ++ subusage super-    (_,_,ermsgs) -> do fail $ chomp_newline(unlines ermsgs)+    (_,_,ermsgs) -> do fail $ chompNewline(unlines ermsgs)
− src/Darcs/Sealed.hs
@@ -1,103 +0,0 @@--- Copyright (C) 2007 David Roundy------ This program is free software; you can redistribute it and/or modify--- it under the terms of the GNU General Public License as published by--- the Free Software Foundation; either version 2, or (at your option)--- any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; see the file COPYING.  If not, write to--- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,--- Boston, MA 02110-1301, USA.--{-# OPTIONS_GHC -cpp -fglasgow-exts #-}-{-# LANGUAGE CPP #-}--- , MagicHash, GADTs #-}--#include "gadts.h"--module Darcs.Sealed ( Sealed(..), seal, unseal, mapSeal,-#ifndef GADT_WITNESSES-                      unsafeUnseal, unsafeUnflippedseal, unsafeUnseal2,-#endif-                      Sealed2(..), seal2, unseal2, mapSeal2,-                      FlippedSeal(..), flipSeal, unsealFlipped, mapFlipped,-                      unsealM, liftSM-                    ) where--import GHC.Base ( unsafeCoerce# )-import Darcs.Show--data Sealed a where-    Sealed :: a C(x ) -> Sealed a--seal :: a C(x ) -> Sealed a-seal = Sealed--data Sealed2 a where-    Sealed2 :: !(a C(x y )) -> Sealed2 a--seal2 :: a C(x y ) -> Sealed2 a-seal2 = Sealed2--data FlippedSeal a C(y) where-    FlippedSeal :: !(a C(x y)) -> FlippedSeal a C(y)--flipSeal :: a C(x y) -> FlippedSeal a C(y)-flipSeal = FlippedSeal--#ifndef GADT_WITNESSES-unsafeUnseal :: Sealed a -> a-unsafeUnseal (Sealed a) = a--unsafeUnflippedseal :: FlippedSeal a -> a-unsafeUnflippedseal (FlippedSeal a) = a--unsafeUnseal2 :: Sealed2 a -> a-unsafeUnseal2 (Sealed2 a) = a-#endif--seriouslyUnsafeUnseal :: Sealed a -> a C(())-seriouslyUnsafeUnseal (Sealed a) = unsafeCoerce# a--unseal :: (FORALL(x) a C(x ) -> b) -> Sealed a -> b-unseal f x = f (seriouslyUnsafeUnseal x)---- laziness property:--- unseal (const True) undefined == True--unsealM :: Monad m => m (Sealed a) -> (FORALL(x) a C(x) -> m b) -> m b-unsealM m1 m2 = do sx <- m1-                   unseal m2 sx--liftSM :: Monad m => (FORALL(x) a C(x) -> b) -> m (Sealed a) -> m b-liftSM f m = do sx <- m-                return (unseal f sx)--mapSeal :: (FORALL(x) a C(x ) -> b C(x )) -> Sealed a -> Sealed b-mapSeal f = unseal (seal . f)--mapFlipped :: (FORALL(x) a C(x y) -> b C(x z)) -> FlippedSeal a C(y) -> FlippedSeal b C(z)-mapFlipped f (FlippedSeal x) = FlippedSeal (f x)--seriouslyUnsafeUnseal2 :: Sealed2 a -> a C(() ())-seriouslyUnsafeUnseal2 (Sealed2 a) = unsafeCoerce# a--unseal2 :: (FORALL(x y) a C(x y ) -> b) -> Sealed2 a -> b-unseal2 f a = f (seriouslyUnsafeUnseal2 a)--mapSeal2 :: (FORALL(x y) a C(x y ) -> b C(x y )) -> Sealed2 a -> Sealed2 b-mapSeal2 f = unseal2 (seal2 . f)--unsealFlipped :: (FORALL(x y) a C(x y) -> b) -> FlippedSeal a C(z) -> b-unsealFlipped f (FlippedSeal a) = f a--instance Show1 a => Show (Sealed a) where-    showsPrec d (Sealed x) = showParen (d > app_prec) $ showString "Sealed " . showsPrec1 (app_prec + 1) x-instance Show2 a => Show (Sealed2 a) where-    showsPrec d (Sealed2 x) = showParen (d > app_prec) $ showString "Sealed2 " . showsPrec2 (app_prec + 1) x
src/Darcs/SelectChanges.hs view
@@ -33,6 +33,7 @@                        with_selected_last_changes_reversed,                        view_changes,                        with_selected_patch_from_repo,+                       filterOutConflicts,                      ) where import System.IO import Data.List ( intersperse )@@ -43,33 +44,38 @@  import English ( Noun(..), englishNum  ) import Darcs.Arguments ( showFriendly )-import Darcs.Hopefully ( PatchInfoAnd, hopefully )-import Darcs.Repository ( Repository, read_repo )+import Darcs.Hopefully ( PatchInfoAnd, hopefully, n2pia )+import Darcs.Repository ( Repository, read_repo, unrecordedChanges ) import Darcs.Patch ( RepoPatch, Patchy, Prim, summary,-                     invert, list_touched_files,-                     commuteFL )+                     invert, listTouchedFiles,+                     commuteFL, fromPrims, anonymous ) import qualified Darcs.Patch ( thing, things )-import Darcs.Ordered ( FL(..), RL(..), (:>)(..),+import Darcs.Patch.Split ( Splitter(..) )+import Darcs.Witnesses.Ordered ( FL(..), RL(..), (:>)(..), (:||:)(..),                        (+>+), lengthFL, lengthRL, concatRL, mapFL_FL,                        spanFL, reverseFL, (+<+), mapFL,                        unsafeCoerceP )-import Darcs.Patch.Choices ( PatchChoices, patch_choices, patch_choices_tps,-                             force_first, force_last, make_uncertain, tag,-                      get_choices,-                      separate_first_middle_from_last,-                      separate_first_from_middle_last,-                      patch_slot,-                      select_all_middles,-                      force_matching_last,-                      force_matching_first, make_everything_later,-                             TaggedPatch, tp_patch, Slot(..),+import Darcs.Patch.Choices ( PatchChoices, patchChoices, patchChoicesTps,+                             patchChoicesTpsSub,+                             forceFirst, forceLast, makeUncertain, tag,+                      getChoices,+                      separateFirstMiddleFromLast,+                      separateFirstFromMiddleLast,+                      patchSlot,+                      selectAllMiddles,+                      forceMatchingLast,+                      forceMatchingFirst, makeEverythingLater,+                             TaggedPatch, tpPatch, Slot(..),+                      substitute,                     )+import Darcs.Patch.Permutations ( partitionConflictingFL, selfCommuter, commuterIdRL ) import Darcs.Patch.TouchesFiles ( deselect_not_touching, select_not_touching ) import Darcs.PrintPatch ( printFriendly, printPatch, printPatchPager )-import Darcs.Match ( have_nonrange_match, match_a_patch, match_a_patchread )-import Darcs.Flags ( DarcsFlag( Summary, DontGrabDeps, Verbose, DontPromptForDependencies), isInteractive )-import Darcs.Sealed ( FlippedSeal(..), flipSeal, seal2, unseal2 )+import Darcs.Match ( haveNonrangeMatch, matchAPatch, matchAPatchread )+import Darcs.Flags ( DarcsFlag( Summary, DontGrabDeps, Verbose, DontPromptForDependencies, SkipConflicts), isInteractive )+import Darcs.Witnesses.Sealed ( FlippedSeal(..), flipSeal, seal2, unseal2, Sealed(..) ) import Darcs.Utils ( askUser, promptCharFancy )+import Darcs.Lock ( editText ) import Printer ( prefix, putDocLn ) #include "impossible.h" @@ -80,6 +86,7 @@ type WithPatches p a C(x y) =         String              -- jobname      -> [DarcsFlag]         -- opts+     -> Maybe (Splitter p)  -- for interactive editing      -> FL p C(x y)         -- patches to select among      -> ((FL p :> FL p) C(x y) -> IO a) -- job      -> IO a                -- result of running job@@ -88,6 +95,7 @@ type WithPatchesToFiles p a C(x y) =         String              -- jobname      -> [DarcsFlag]         -- opts+     -> Maybe (Splitter p)  -- for interactive editing      -> [FilePath]          -- files      -> FL p C(x y)         -- patches to select among      -> ((FL p :> FL p) C(x y) -> IO a) -- job@@ -107,8 +115,8 @@ triv _ _ _ = True  iswanted :: Patchy p => MatchCriterion (PatchInfoAnd p)-iswanted First opts p = match_a_patch opts . hopefully $ p-iswanted LastReversed opts p = match_a_patch opts . hopefully . invert $ p+iswanted First opts p = matchAPatch opts . hopefully $ p+iswanted LastReversed opts p = matchAPatch opts . hopefully . invert $ p iswanted Last _ _ = bug "don't support patch matching with Last in wasp" iswanted FirstReversed _ _ = bug "don't support patch matching with FirstReversed in wasp" @@ -133,34 +141,34 @@  -- | wasc and wasc_ are just shorthand for with_any_selected_changes wasc  :: Patchy p => WhichChanges -> MatchCriterion p -> WithPatches p a C(x y)-wasc mwch crit j o = wasc_ mwch crit j o []+wasc mwch crit j o spl = wasc_ mwch crit j o spl [] wasc_ :: Patchy p => WhichChanges -> MatchCriterion p -> WithPatchesToFiles p a C(x y) wasc_ = with_any_selected_changes  with_any_selected_changes :: Patchy p => WhichChanges -> MatchCriterion p -> WithPatchesToFiles p a C(x y)-with_any_selected_changes Last crit jn opts fs =+with_any_selected_changes Last crit jn opts splitter fs =     with_any_selected_changes_last         (patches_to_consider_last' fs opts crit)-        crit jn opts fs-with_any_selected_changes First crit jn opts fs =+        crit jn opts splitter fs+with_any_selected_changes First crit jn opts splitter fs =     with_any_selected_changes_first        (patches_to_consider_first' fs opts crit)-       crit jn opts fs-with_any_selected_changes FirstReversed crit jn opts fs =+       crit jn opts splitter fs+with_any_selected_changes FirstReversed crit jn opts splitter fs =     with_any_selected_changes_first_reversed        (patches_to_consider_first_reversed' fs opts crit)-       crit jn opts fs-with_any_selected_changes LastReversed crit jn opts fs =+       crit jn opts splitter fs+with_any_selected_changes LastReversed crit jn opts splitter fs =     with_any_selected_changes_last_reversed         (patches_to_consider_last_reversed' fs opts crit)-        crit jn opts fs+        crit jn opts splitter fs   view_changes :: RepoPatch p => [DarcsFlag] -> FL (PatchInfoAnd p) C(x y) -> IO () view_changes opts ps = do   text_view opts Nothing 0 NilRL init_tps init_pc   return ()-    where (init_pc, init_tps) = patch_choices_tps ps+    where (init_pc, init_tps) = patchChoicesTps ps  data KeyPress a = KeyPress { kp     :: Char                            , kpHelp :: String }@@ -183,7 +191,7 @@                               -> (FORALL(a) (FL (PatchInfoAnd p) :> PatchInfoAnd p) C(a r) -> IO ()) -> IO () with_selected_patch_from_repo jn repository opts job = do     p_s <- read_repo repository-    sp <- wspfr jn (match_a_patchread opts)+    sp <- wspfr jn (matchAPatchread opts)                               (concatRL p_s) NilFL     case sp of      Just (FlippedSeal (skipped :> selected)) -> job (skipped :> selected)@@ -228,69 +236,76 @@                   repeat_this   where jn_cap = (toUpper $ head jn) : tail jn +-- After selecting with a splitter, the results may not be canonical+canonizeWith :: Maybe (Splitter p) -> (FL p :> FL p) C(x y) -> (FL p :> FL p) C(x y)+canonizeWith Nothing xy = xy+canonizeWith (Just spl) (x :> y) = canonizeSplit spl x :> canonizeSplit spl y+ with_any_selected_changes_last :: forall p a C(x y). Patchy p                                => (FL p C(x y) -> (FL p :> FL p) C(x y))                                -> MatchCriterion p                                -> WithPatchesToFiles p a C(x y)-with_any_selected_changes_last p2c crit jobname opts _ ps job =+with_any_selected_changes_last p2c crit jobname opts splitter _ ps job =  case p2c ps of  ps_to_consider :> other_ps ->          if not $ isInteractive opts          then job $ ps_to_consider :> other_ps-         else do pc <- tentatively_text_select "" jobname (Noun "patch") Last crit+         else do pc <- tentatively_text_select splitter "" jobname (Noun "patch") Last crit                                               opts ps_len 0 NilRL init_tps init_pc-                 job $ selected_patches_last rejected_ps pc+                 job $ canonizeWith splitter $ selected_patches_last rejected_ps pc          where rejected_ps = ps_to_consider                ps_len = lengthFL init_tps-               (init_pc, init_tps) = patch_choices_tps $ other_ps+               (init_pc, init_tps) = patchChoicesTps $ other_ps  with_any_selected_changes_first :: forall p a C(x y). Patchy p                                 => (FL p C(x y) -> (FL p :> FL p) C(x y))                                 -> MatchCriterion p                                 -> WithPatchesToFiles p a C(x y)-with_any_selected_changes_first p2c crit jobname opts _ ps job =+with_any_selected_changes_first p2c crit jobname opts splitter _ ps job =  case p2c ps of  ps_to_consider :> other_ps ->          if not $ isInteractive opts          then job $ ps_to_consider :> other_ps-         else do pc <- tentatively_text_select "" jobname (Noun "patch") First crit+         else do pc <- tentatively_text_select splitter "" jobname (Noun "patch") First crit                                               opts ps_len 0 NilRL init_tps init_pc-                 job $ selected_patches_first rejected_ps pc+                 job $ canonizeWith splitter $ selected_patches_first rejected_ps pc          where rejected_ps = other_ps                ps_len = lengthFL init_tps-               (init_pc, init_tps) = patch_choices_tps $ ps_to_consider+               (init_pc, init_tps) = patchChoicesTps $ ps_to_consider  with_any_selected_changes_first_reversed :: forall p a C(x y). Patchy p                                 => (FL p C(x y) -> (FL p :> FL p) C(y x))                                 -> MatchCriterion p                                 -> WithPatchesToFiles p a C(x y)-with_any_selected_changes_first_reversed p2c crit jobname opts _ ps job =+with_any_selected_changes_first_reversed p2c crit jobname opts splitter _ ps job =  case p2c ps of  ps_to_consider :> other_ps ->          if not $ isInteractive opts          then job $ invert other_ps :> invert ps_to_consider-         else do pc <- tentatively_text_select "" jobname (Noun "patch") FirstReversed crit+         else do pc <- tentatively_text_select splitter+                                             "" jobname (Noun "patch") FirstReversed crit                                              opts ps_len 0 NilRL init_tps init_pc-                 job $ selected_patches_first_reversed rejected_ps pc+                 job $ canonizeWith splitter $ selected_patches_first_reversed rejected_ps pc          where rejected_ps = ps_to_consider                ps_len = lengthFL init_tps-               (init_pc, init_tps) = patch_choices_tps other_ps+               (init_pc, init_tps) = patchChoicesTps other_ps  with_any_selected_changes_last_reversed :: forall p a C(x y). Patchy p                                 => (FL p C(x y) -> (FL p :> FL p) C(y x))                                 -> MatchCriterion p                                 -> WithPatchesToFiles p a C(x y)-with_any_selected_changes_last_reversed p2c crit jobname opts _ ps job =+with_any_selected_changes_last_reversed p2c crit jobname opts splitter _ ps job =  case p2c ps of  ps_to_consider :> other_ps ->          if not $ isInteractive opts          then job $ invert other_ps :> invert ps_to_consider-         else do pc <- tentatively_text_select "" jobname (Noun "patch") LastReversed crit+         else do pc <- tentatively_text_select splitter+                                             "" jobname (Noun "patch") LastReversed crit                                              opts ps_len 0 NilRL init_tps init_pc-                 job $ selected_patches_last_reversed rejected_ps pc+                 job $ canonizeWith splitter $ selected_patches_last_reversed rejected_ps pc          where rejected_ps = other_ps                ps_len = lengthFL init_tps-               (init_pc, init_tps) = patch_choices_tps ps_to_consider+               (init_pc, init_tps) = patchChoicesTps ps_to_consider   patches_to_consider_first' :: Patchy p@@ -301,16 +316,16 @@                      -> (FL p :> FL p) C(x y) patches_to_consider_first' fs opts crit ps =   let deselect_unwanted pc =-        if have_nonrange_match opts+        if haveNonrangeMatch opts         then if DontGrabDeps `elem` opts-                  then force_matching_last (not.iswanted_) pc-                  else make_everything_later $ force_matching_first iswanted_ pc+                  then forceMatchingLast (not.iswanted_) pc+                  else makeEverythingLater $ forceMatchingFirst iswanted_ pc         else pc-      iswanted_ = crit First opts . tp_patch-  in if null fs && not (have_nonrange_match opts)+      iswanted_ = crit First opts . tpPatch+  in if null fs && not (haveNonrangeMatch opts)      then ps :> NilFL-     else tp_patches $ separate_first_middle_from_last $ deselect_not_touching fs-                     $ deselect_unwanted $ patch_choices ps+     else tp_patches $ separateFirstMiddleFromLast $ deselect_not_touching fs+                     $ deselect_unwanted $ patchChoices ps  patches_to_consider_last' :: Patchy p                      => [FilePath]  -- ^ files@@ -320,15 +335,15 @@                      -> (FL p :> FL p) C(x y) patches_to_consider_last' fs opts crit ps =   let deselect_unwanted pc =-        if have_nonrange_match opts+        if haveNonrangeMatch opts         then if DontGrabDeps `elem` opts-                  then force_matching_last (not.iswanted_) pc-                  else make_everything_later $ force_matching_first iswanted_ pc+                  then forceMatchingLast (not.iswanted_) pc+                  else makeEverythingLater $ forceMatchingFirst iswanted_ pc         else pc-      iswanted_ = crit Last opts . tp_patch-  in if null fs && not (have_nonrange_match opts)+      iswanted_ = crit Last opts . tpPatch+  in if null fs && not (haveNonrangeMatch opts)      then NilFL :> ps-     else case get_choices $ select_not_touching fs $ deselect_unwanted $ patch_choices ps of+     else case getChoices $ select_not_touching fs $ deselect_unwanted $ patchChoices ps of            fc :> mc :> lc -> tp_patches $ fc :> mc +>+ lc  patches_to_consider_first_reversed' :: Patchy p@@ -339,15 +354,15 @@                      -> (FL p :> FL p) C(y x) patches_to_consider_first_reversed' fs opts crit ps =   let deselect_unwanted pc =-        if have_nonrange_match opts+        if haveNonrangeMatch opts         then if DontGrabDeps `elem` opts-                  then force_matching_last (not.iswanted_) pc-                  else make_everything_later $ force_matching_first iswanted_ pc+                  then forceMatchingLast (not.iswanted_) pc+                  else makeEverythingLater $ forceMatchingFirst iswanted_ pc         else pc-      iswanted_ = crit FirstReversed opts . tp_patch-  in if null fs && not (have_nonrange_match opts)+      iswanted_ = crit FirstReversed opts . tpPatch+  in if null fs && not (haveNonrangeMatch opts)      then NilFL :> (invert ps)-     else case get_choices $ select_not_touching fs $ deselect_unwanted $ patch_choices $ invert ps of+     else case getChoices $ select_not_touching fs $ deselect_unwanted $ patchChoices $ invert ps of            fc :> mc :> lc -> tp_patches $ fc :> mc +>+ lc  patches_to_consider_last_reversed' :: Patchy p@@ -358,55 +373,55 @@                      -> (FL p :> FL p) C(y x) patches_to_consider_last_reversed' fs opts crit ps =   let deselect_unwanted pc =-        if have_nonrange_match opts+        if haveNonrangeMatch opts         then if DontGrabDeps `elem` opts-             then force_matching_last (not.iswanted_) pc-             else make_everything_later $ force_matching_first iswanted_ pc+             then forceMatchingLast (not.iswanted_) pc+             else makeEverythingLater $ forceMatchingFirst iswanted_ pc         else pc-      iswanted_ = crit LastReversed opts . tp_patch+      iswanted_ = crit LastReversed opts . tpPatch   in-    if null fs && not (have_nonrange_match opts)+    if null fs && not (haveNonrangeMatch opts)     then (invert ps) :> NilFL-    else tp_patches $ separate_first_middle_from_last $ deselect_not_touching fs-                     $ deselect_unwanted $ patch_choices $ invert ps+    else tp_patches $ separateFirstMiddleFromLast $ deselect_not_touching fs+                     $ deselect_unwanted $ patchChoices $ invert ps  -- | Returns the results of a patch selection user interaction selected_patches_last :: Patchy p => FL p C(x y) -> PatchChoices p C(y z)                       -> (FL p :> FL p) C(x z) selected_patches_last other_ps pc =-  case get_choices pc of-   fc :> mc :> lc -> other_ps +>+ mapFL_FL tp_patch (fc +>+ mc) :> mapFL_FL tp_patch lc+  case getChoices pc of+   fc :> mc :> lc -> other_ps +>+ mapFL_FL tpPatch (fc +>+ mc) :> mapFL_FL tpPatch lc  selected_patches_first :: Patchy p => FL p C(y z) -> PatchChoices p C(x y)                        -> (FL p :> FL p) C(x z) selected_patches_first other_ps pc =-  case separate_first_from_middle_last pc of-  xs :> ys -> mapFL_FL tp_patch xs :> mapFL_FL tp_patch ys +>+ other_ps+  case separateFirstFromMiddleLast pc of+  xs :> ys -> mapFL_FL tpPatch xs :> mapFL_FL tpPatch ys +>+ other_ps  selected_patches_last_reversed :: Patchy p => FL p C(y x) -> PatchChoices p C(z y)                                -> (FL p :> FL p) C(x z) selected_patches_last_reversed other_ps pc =-  case separate_first_from_middle_last pc of-  xs :> ys -> invert (mapFL_FL tp_patch ys +>+ other_ps) :> invert (mapFL_FL tp_patch xs)+  case separateFirstFromMiddleLast pc of+  xs :> ys -> invert (mapFL_FL tpPatch ys +>+ other_ps) :> invert (mapFL_FL tpPatch xs)  selected_patches_first_reversed :: Patchy p => FL p C(z y) -> PatchChoices p C(y x)                                 -> (FL p :> FL p) C(x z) selected_patches_first_reversed other_ps pc =-  case get_choices pc of-  fc :> mc :> lc -> invert (mapFL_FL tp_patch lc) :> invert (other_ps +>+ mapFL_FL tp_patch (fc +>+ mc))+  case getChoices pc of+  fc :> mc :> lc -> invert (mapFL_FL tpPatch lc) :> invert (other_ps +>+ mapFL_FL tpPatch (fc +>+ mc)) -text_select :: forall p C(x y z). Patchy p => String -> WhichChanges+text_select :: forall p C(x y z). Patchy p => Maybe (Splitter p) -> String -> WhichChanges             ->  MatchCriterion p -> [DarcsFlag] -> Int -> Int             -> RL (TaggedPatch p) C(x y) -> FL (TaggedPatch p) C(y z) -> PatchChoices p C(x z)             -> IO ((PatchChoices p) C(x z)) -text_select _ _ _ _ _ _ _ NilFL pc = return pc-text_select jn whichch crit opts n_max n+text_select _ _ _ _ _ _ _ _ NilFL pc = return pc+text_select splitter jn whichch crit opts n_max n             tps_done tps_todo@(tp:>:tps_todo') pc = do       (printFriendly opts) `unseal2` viewp       repeat_this -- prompt the user     where-        do_next_action ja je = tentatively_text_select ja jn je whichch crit opts+        do_next_action ja je = tentatively_text_select splitter ja jn je whichch crit opts                                           n_max                                           (n+1) (tp:<:tps_done) tps_todo'         do_next = do_next_action "" (Noun "patch")@@ -414,6 +429,7 @@         helper = undefined         thing  = Darcs.Patch.thing (helper pc)         things = Darcs.Patch.things (helper pc)+        split = splitter >>= flip applySplitter (tpPatch tp)         options_basic =            [ KeyPress 'y' (jn++" this "++thing)            , KeyPress 'n' ("don't "++jn++" it")@@ -434,7 +450,12 @@         options_nav =            [ KeyPress 'j' ("skip to next "++thing)            , KeyPress 'k' ("back up to previous "++thing) ]+        options_split+           | Just _ <- split+                 = [ KeyPress 'e' ("interactively edit this "++thing) ]+           | otherwise = []         options = [options_basic]+                  ++ [options_split]                   ++ (if is_single_file_patch then [options_file] else [])                   ++ [options_view ++                       if Summary `elem` opts then [] else options_summary]@@ -448,18 +469,28 @@           case yorn of             'y' -> do_next $ force_yes (tag tp) pc             'n' -> do_next $ force_no (tag tp) pc-            'w' -> do_next $ make_uncertain (tag tp) pc+            'w' -> do_next $ makeUncertain (tag tp) pc+            'e' | Just (text, parse) <- split+                -> do newText <- editText "darcs-patch-edit" text+                      case parse newText of+                        Nothing -> repeat_this+                        Just ps -> do let tps_new = snd $ patchChoicesTpsSub (Just (tag tp)) ps+                                      text_select splitter+                                                  jn whichch crit opts (n_max + lengthFL tps_new - 1) n+                                                  tps_done (tps_new+>+tps_todo')+                                                  (substitute (seal2 (tp :||: tps_new)) pc)+             's' -> do_next_action "Skipped"  (Noun "change") $ skip_file             'f' -> do_next_action "Included" (Noun "change") $ do_file             'v' -> printPatch `unseal2` viewp >> repeat_this             'p' -> printPatchPager `unseal2` viewp >> repeat_this-            'l' -> do let selected = case get_choices pc of+            'l' -> do let selected = case getChoices pc of                                           (first_chs:>_:>last_chs) ->                                              if whichch == Last || whichch == FirstReversed                                                 then map_patches last_chs                                                 else map_patches first_chs                           map_patches = mapFL (\a ->-                                           (showFriendly opts) `unseal2` (seal2 $ tp_patch a))+                                           (showFriendly opts) `unseal2` (seal2 $ tpPatch a))                       putStrLn $ "---- Already selected "++things++" ----"                       mapM_ putDocLn $ selected                       putStrLn $ "---- end of already selected "++things++" ----"@@ -469,38 +500,38 @@                       repeat_this             'd' -> return pc             'a' -> do ask_confirmation-                      return $ select_all_middles (whichch == Last || whichch == FirstReversed) pc+                      return $ selectAllMiddles (whichch == Last || whichch == FirstReversed) pc             'q' -> do putStrLn $ jn_cap++" cancelled."                       exitWith $ ExitSuccess             'j' -> case tps_todo' of                        NilFL -> -- May as well work out the length now we have all                                 -- the patches in memory-                                text_select jn whichch crit opts+                                text_select splitter jn whichch crit opts                                     n_max n tps_done tps_todo pc-                       _ -> text_select jn whichch crit opts+                       _ -> text_select splitter jn whichch crit opts                                 n_max (n+1) (tp:<:tps_done) tps_todo' pc             'k' -> case tps_done of                         NilRL -> repeat_this                         (tp':<:tps_done') ->-                           text_select jn whichch crit opts+                           text_select splitter jn whichch crit opts                                n_max (n-1) tps_done' (tp':>:tps_todo) pc-            'c' -> text_select jn whichch crit opts+            'c' -> text_select splitter jn whichch crit opts                                         n_max n tps_done tps_todo pc             _   -> do putStrLn $ helpFor jn options                       repeat_this-        force_yes = if whichch == Last || whichch == FirstReversed then force_last else force_first-        force_no  = if whichch == Last || whichch == FirstReversed then force_first else force_last+        force_yes = if whichch == Last || whichch == FirstReversed then forceLast else forceFirst+        force_no  = if whichch == Last || whichch == FirstReversed then forceFirst else forceLast         patches_to_skip = (tag tp:) $ catMaybes-                        $ mapFL (\tp' -> if list_touched_files tp' == touched_files+                        $ mapFL (\tp' -> if listTouchedFiles tp' == touched_files                                          then Just (tag tp')                                          else Nothing) tps_todo'         skip_file = foldr force_no pc patches_to_skip         do_file = foldr force_yes pc patches_to_skip-        the_default = get_default (whichch == Last || whichch == FirstReversed) $ patch_slot tp pc+        the_default = get_default (whichch == Last || whichch == FirstReversed) $ patchSlot tp pc         jn_cap = (toUpper $ head jn) : tail jn-        touched_files = list_touched_files $ tp_patch tp+        touched_files = listTouchedFiles $ tpPatch tp         is_single_file_patch = length touched_files == 1-        viewp = if whichch == LastReversed || whichch == FirstReversed then seal2 $ invert (tp_patch tp) else seal2 $ tp_patch tp+        viewp = if whichch == LastReversed || whichch == FirstReversed then seal2 $ invert (tpPatch tp) else seal2 $ tpPatch tp         ask_confirmation =             if jn `elem` ["unpull", "unrecord", "obliterate"]             then do yorn <- askUser $ "Really " ++ jn ++ " all undecided patches? "@@ -512,10 +543,10 @@ text_view :: forall p C(x y u r s). Patchy p => [DarcsFlag] -> Maybe Int -> Int             -> RL (TaggedPatch p) C(x y) -> FL (TaggedPatch p) C(y u) -> PatchChoices p C(r s)             -> IO ((PatchChoices p) C(r s))-text_view _ _ _ _ NilFL _ = return $ patch_choices $ unsafeCoerceP NilFL --return pc+text_view _ _ _ _ NilFL _ = return $ patchChoices $ unsafeCoerceP NilFL --return pc text_view opts n_max n             tps_done tps_todo@(tp:>:tps_todo') pc = do-      printFriendly opts (tp_patch tp)+      printFriendly opts (tpPatch tp)       putStr "\n"       repeat_this -- prompt the user     where@@ -556,11 +587,11 @@         repeat_this = do           yorn <- promptCharFancy prompt (keysFor options) (Just 'n') "?h"           case yorn of-            'y' -> printPatch (tp_patch tp) >> next_patch+            'y' -> printPatch (tpPatch tp) >> next_patch             'n' -> next_patch-            'v' -> printPatch (tp_patch tp) >> repeat_this-            'p' -> printPatchPager (tp_patch tp) >> repeat_this-            'x' -> do putDocLn $ prefix "    " $ summary (tp_patch tp)+            'v' -> printPatch (tpPatch tp) >> repeat_this+            'p' -> printPatchPager (tpPatch tp) >> repeat_this+            'x' -> do putDocLn $ prefix "    " $ summary (tpPatch tp)                       repeat_this             'q' -> exitWith ExitSuccess             'k' -> prev_patch@@ -571,25 +602,25 @@                       repeat_this         count_n_max | isJust n_max = n_max                     | otherwise    = Just $ lengthFL tps_todo + lengthRL tps_done-tentatively_text_select :: Patchy p => String -> String -> Noun -> WhichChanges+tentatively_text_select :: Patchy p => Maybe (Splitter p) -> String -> String -> Noun -> WhichChanges                         -> MatchCriterion p -> [DarcsFlag]                         -> Int -> Int -> RL (TaggedPatch p) C(x y) -> FL (TaggedPatch p) C(y z)                         -> PatchChoices p C(x z)                         -> IO ((PatchChoices p) C(x z))-tentatively_text_select _ _ _ _ _ _ _ _ _ NilFL pc = return pc-tentatively_text_select jobaction jobname jobelement whichch crit+tentatively_text_select _ _ _ _ _ _ _ _ _ _ NilFL pc = return pc+tentatively_text_select splitter jobaction jobname jobelement whichch crit                         opts n_max n ps_done ps_todo pc =-  case spanFL (\p -> decided $ patch_slot p pc) ps_todo of+  case spanFL (\p -> decided $ patchSlot p pc) ps_todo of   skipped :> unskipped -> do    when (numSkipped > 0) show_skipped    let (boringThenInteresting) =                           if DontPromptForDependencies `elem` opts-                          then spanFL (not.(crit whichch opts).tp_patch) unskipped+                          then spanFL (not.(crit whichch opts).tpPatch) unskipped                           else NilFL :> unskipped    case boringThenInteresting of      boring :> interesting -> do      let numNotConsidered = lengthFL boring + numSkipped-     text_select jobname whichch crit opts n_max (n + numNotConsidered)+     text_select splitter jobname whichch crit opts n_max (n + numNotConsidered)                  (reverseFL boring +<+ reverseFL skipped +<+ ps_done) interesting pc    where    numSkipped  = lengthFL skipped@@ -601,7 +632,7 @@       _action_ = if (length jobaction) == 0 then "Skipped" else jobaction       _elem_ = englishNum numSkipped jobelement       showskippedpatch :: Patchy p => FL (TaggedPatch p) C(y t) -> IO ()-      showskippedpatch (tp:>:tps) = (putDocLn $ prefix "    " $ summary (tp_patch tp)) >> showskippedpatch tps+      showskippedpatch (tp:>:tps) = (putDocLn $ prefix "    " $ summary (tpPatch tp)) >> showskippedpatch tps       showskippedpatch NilFL = return ()  decided :: Slot -> Bool@@ -617,4 +648,26 @@  tp_patches :: (FL (TaggedPatch p) :> FL (TaggedPatch p)) C(x y)            -> (FL p :> FL p) C(x y)-tp_patches (x:>y) = mapFL_FL tp_patch x :> mapFL_FL tp_patch y+tp_patches (x:>y) = mapFL_FL tpPatch x :> mapFL_FL tpPatch y++-- |Optionally remove any patches (+dependencies) from a sequence that+-- conflict with the recorded or unrecorded changes in a repo+filterOutConflicts :: RepoPatch p+                   => [DarcsFlag]                                    -- ^Command-line options. Only 'SkipConflicts' is+                                                                     -- significant; filtering will happen iff it is present+                   -> RL (PatchInfoAnd p) C(x r)                     -- ^Recorded patches from repository, starting from+                                                                     -- same context as the patches to filter+                   -> Repository p C(r u t)                          -- ^Repository itself, used for grabbing unrecorded changes+                   -> FL (PatchInfoAnd p) C(x z)                     -- ^Patches to filter+                   -> IO (Bool, Sealed (FL (PatchInfoAnd p) C(x)))   -- ^(True iff any patches were removed, possibly filtered patches)+filterOutConflicts opts us repository them+  | SkipConflicts `elem` opts+     = do let commuter = commuterIdRL selfCommuter+          unrec <- fmap n2pia . (anonymous . fromPrims) =<< unrecordedChanges [] repository []+          them' :> rest <- return $ partitionConflictingFL commuter them (unrec :<: us)+          return (check rest, Sealed them')+  | otherwise+     = return (False, Sealed them)+  where check :: FL p C(a b) -> Bool+        check NilFL = False+        check _ = True
− src/Darcs/Show.hs
@@ -1,25 +0,0 @@-{-# OPTIONS_GHC -cpp -fglasgow-exts #-}-{-# LANGUAGE CPP #-}--module Darcs.Show(Show1(..), Show2(..), showOp2, app_prec) where--#include "gadts.h"--class Show1 a where-    show1 :: a C(x) -> String-    show1 x = showsPrec1 0 x ""-    showsPrec1 :: Int -> a C(x) -> ShowS-    showsPrec1 _ x s = show1 x ++ s--class Show2 a where-    show2 :: a C(x y) -> String-    show2 x = showsPrec2 0 x ""-    showsPrec2 :: Int -> a C(x y) -> ShowS-    showsPrec2 _ x s = show2 x ++ s--showOp2 :: (Show2 a, Show2 b) => Int -> String -> Int -> a C(w x) -> b C(y z) -> String -> String-showOp2 prec opstr d x y = showParen (d > prec) $ showsPrec2 (prec + 1) x .-                          showString opstr . showsPrec2 (prec + 1) y--app_prec :: Int-app_prec = 10
src/Darcs/SlurpDirectory.hs view
@@ -21,7 +21,6 @@   FileContents,   undefined_time, undefined_size,   doesFileReallyExist, doesDirectoryReallyExist, isFileReallySymlink,-  wait_a_moment,   is_dir, is_file,   get_slurp, slurp_name,   slurp_has, slurp_has_anycase, slurp_hasfile, slurp_hasdir,
src/Darcs/SlurpDirectory/Internal.hs view
@@ -30,7 +30,7 @@                         slurp_removefile, slurp_removedir,                         slurp_remove,                         slurp_modfile, slurp_hasfile, slurp_hasdir,-                        slurp_has_anycase, wait_a_moment, undefined_time,+                        slurp_has_anycase, undefined_time,                         undefined_size,                         slurp_has, list_slurpy, list_slurpy_files,                         get_path_list,@@ -56,7 +56,6 @@           fileSize,           isRegularFile, isDirectory, isSymbolicLink         )-import System.Posix ( sleep ) import Data.Maybe ( catMaybes, isJust, maybeToList ) import Data.Map (Map) import qualified Data.Map as Map@@ -69,7 +68,7 @@ import qualified Data.ByteString as B  import Darcs.Patch.FileName ( FileName, fn2fp, fp2fn, norm_path, break_on_dir,-                              own_name, super_name )+                              own_name, superName ) #if mingw32_HOST_OS import Data.Int ( Int64 ) #else@@ -183,7 +182,7 @@ write_file s fn = case withSlurpy s $ smReadFilePS fn of                      Left err -> fail err                      Right (_, c) -> do-                       ensureDirectories (super_name fn)+                       ensureDirectories (superName fn)                        mWriteFilePS fn c                         try_write_file :: Slurpy -> FilePath -> IO ()@@ -199,7 +198,7 @@           isPar <- mDoesDirectoryExist d           if isPar              then return ()-            else ensureDirectories (super_name d) >> (mCreateDirectory d)+            else ensureDirectories (superName d) >> (mCreateDirectory d)  write_files ::  Slurpy -> [FilePath] -> IO () write_files s fps = mapM_ (try_write_file s) fps@@ -256,7 +255,7 @@  insertSlurpy :: FileName -> Slurpy -> SlurpMonad () insertSlurpy f news = mksm $ \s ->-                      if slurp_hasfile f s || slurp_hasdir f s || not (slurp_hasdir (super_name f) s)+                      if slurp_hasfile f s || slurp_hasdir f s || not (slurp_hasdir (superName f) s)                       then Left $ "Error creating file "++fn2fp f                       else Right (addslurp f news s, ()) @@ -341,13 +340,6 @@ undef_time_size :: (Maybe String, EpochTime, FileOffset) undef_time_size = (Nothing, undefined_time, undefined_size) -wait_a_moment :: IO ()-wait_a_moment = do { sleep 1; return () }-    -- HACKERY: In ghc 6.1, sleep has the type signature IO Int; it-    -- returns an integer just like sleep(3) does. To stay compatible-    -- with older versions, though, we just ignore sleep's return-    -- value. Hackery, like I said.- isFileReallySymlink :: FilePath -> IO Bool isFileReallySymlink f = do fs <- getSymbolicLinkStatus f                            return (isSymbolicLink fs)@@ -536,7 +528,7 @@  slurp_move :: FileName -> FileName -> Slurpy -> Maybe Slurpy slurp_move f f' s =-    if not (slurp_has (fn2fp f') s) && slurp_hasdir (super_name f') s+    if not (slurp_has (fn2fp f') s) && slurp_hasdir (superName f') s     then case get_slurp f s of          Nothing -> Nothing          Just sf ->@@ -549,7 +541,7 @@  addslurp :: FileName -> Slurpy -> Slurpy -> Slurpy addslurp fname s s' =-    case get_slurp_context (super_name fname) s' of+    case get_slurp_context (superName fname) s' of         Just (ctx, Slurpy d (SlurpDir _ c)) -> ctx (Slurpy d (SlurpDir Nothing (uncurry Map.insert (slurpy_to_pair s) c)))         _ -> s' @@ -567,7 +559,7 @@  slurp_adddir :: FileName -> Slurpy -> Maybe Slurpy slurp_adddir f s =-  if slurp_hasfile f s || slurp_hasdir f s || not (slurp_hasdir (super_name f) s)+  if slurp_hasfile f s || slurp_hasdir f s || not (slurp_hasdir (superName f) s)   then Nothing   else Just $ addslurp f (Slurpy (own_name f) (SlurpDir Nothing Map.empty)) s 
src/Darcs/Test.lhs view
@@ -27,8 +27,8 @@  import Darcs.Arguments ( DarcsFlag( Quiet,                                     AskPosthook, AskPrehook ),-                        get_posthook_cmd, get_prehook_cmd )-import Darcs.Repository.Prefs ( get_prefval )+                        getPosthookCmd, getPrehookCmd )+import Darcs.Repository.Prefs ( getPrefval ) import Darcs.Utils ( askUser ) import System.IO ( hPutStrLn, stderr ) \end{code}@@ -61,7 +61,7 @@ get_test opts =  let putInfo s = when (not $ Quiet `elem` opts) $ putStr s  in do- testline <- get_prefval "test"+ testline <- getPrefval "test"  return $    case testline of    Nothing -> return ExitSuccess@@ -78,13 +78,14 @@                                withCurrentDirectory repodir $ run_hook opts "Posthook" ph  get_posthook :: [DarcsFlag] -> IO (Maybe String)-get_posthook opts = case get_posthook_cmd opts of+get_posthook opts = case getPosthookCmd opts of                     Nothing -> return Nothing                     Just command ->                        if AskPosthook `elem` opts-                       then do yorn <- askUser ("\nThe following command is set to execute.\n"+++                       then do putStr ("\nThe following command is set to execute.\n"++                                                 "Execute the following command now (yes or no)?\n"++                                                 command++"\n")+                               yorn <- askUser ""                                case yorn of ('y':_) -> return $ Just command                                             _ -> do putStrLn "Posthook cancelled..."                                                     return Nothing@@ -95,13 +96,14 @@                               withCurrentDirectory repodir $ run_hook opts "Prehook" ph  get_prehook :: [DarcsFlag] -> IO (Maybe String)-get_prehook opts = case get_prehook_cmd opts of+get_prehook opts = case getPrehookCmd opts of                    Nothing -> return Nothing                    Just command ->                        if AskPrehook `elem` opts-                       then do yorn <- askUser ("\nThe following command is set to execute.\n"+++                       then do putStr ("\nThe following command is set to execute.\n"++                                                 "Execute the following command now (yes or no)?\n"++                                                 command++"\n")+                               yorn <- askUser ""                                case yorn of ('y':_) -> return $ Just command                                             _ -> do putStrLn "Prehook cancelled..."                                                     return Nothing
+ src/Darcs/Test/Patch/Check.hs view
@@ -0,0 +1,333 @@+-- Copyright (C) 2002-2003 David Roundy+--+-- This program is free software; you can redistribute it and/or modify+-- it under the terms of the GNU General Public License as published by+-- the Free Software Foundation; either version 2, or (at your option)+-- any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++module Darcs.Test.Patch.Check ( PatchCheck(), do_check, file_exists, dir_exists,+                                remove_file, remove_dir, create_file, create_dir,+                                insert_line, delete_line, is_valid, do_verbose_check,+                                file_empty,+                                check_move, modify_file, FileContents(..)+                              ) where++import System.IO.Unsafe ( unsafePerformIO )+import qualified Data.ByteString as B (ByteString)+import Data.List ( isPrefixOf, inits )+import Control.Monad.State ( State, evalState, runState )+import Control.Monad.State.Class ( get, put, modify )+-- use Map, not IntMap, because Map has mapKeys and IntMap hasn't+import Data.Map ( Map )+import qualified Data.Map as M ( mapKeys, delete, insert, empty, lookup, null )+import System.FilePath ( joinPath, splitDirectories )++-- | File contents are represented by a map from line numbers to line contents.+--   If for a certain line number, the line contents are Nothing, that means+--   that we are sure that that line exists, but we don't know its contents.+--   We must also store the greatest line number that is known to exist in a+--   file, to be able to exclude the possibility of it being empty without+--   knowing its contents.+data FileContents = FC { fc_lines   :: Map Int B.ByteString+                       , fc_maxline :: Int+                       } deriving (Eq, Show)+data Prop = FileEx String | DirEx String | NotEx String+          | FileLines String FileContents+            deriving (Eq)+-- | A @KnownState@ is a simulated repository state. The repository is either+-- inconsistent, or it has two lists of properties: one list with properties+-- that hold for this repo, and one with properties that do not hold for this+-- repo. These two lists may not have any common elements: if they had, the+-- repository would be inconsistent.+data KnownState = P [Prop] [Prop]+                | Inconsistent+                  deriving (Show)+instance  Show Prop  where+    show (FileEx f) = "FileEx "++f+    show (DirEx d)  = "DirEx "++d+    show (NotEx f) = "NotEx"++f+    show (FileLines f l)  = "FileLines "++f++": "++show l++-- | PatchCheck is a state monad with a simulated repository state+type PatchCheck = State KnownState++-- | The @FileContents@ structure for an empty file+empty_filecontents :: FileContents+empty_filecontents = FC M.empty 0++-- | Returns a given value if the repository state is inconsistent, and performs+--   a given action otherwise.+handle_inconsistent :: a            -- ^ The value to return if the state is inconsistent+                   -> PatchCheck a -- ^ The action to perform otherwise+                   -> PatchCheck a+handle_inconsistent v a = do state <- get+                             case state of+                               Inconsistent -> return v+                               _            -> a++do_check :: PatchCheck a -> a+do_check p = evalState p (P [] [])++-- | Run a check, and print the final repository state+do_verbose_check :: PatchCheck a -> a+do_verbose_check p =+    case runState p (P [] []) of+    (b, pc) -> unsafePerformIO $ do putStrLn $ show pc+                                    return b++-- | Returns true if the current repository state is not inconsistent+is_valid :: PatchCheck Bool+is_valid = handle_inconsistent False (return True)++has :: Prop -> [Prop] -> Bool+has _ [] = False+has k (k':ks) = k == k' || has k ks++modify_file :: String+            -> (Maybe FileContents -> Maybe FileContents)+            -> PatchCheck Bool+modify_file f change = do+    file_exists f+    c <- file_contents f+    case change c of+      Nothing -> assert_not $ FileEx f -- shorthand for "FAIL"+      Just c' -> do set_contents f c'+                    is_valid++insert_line :: String -> Int -> B.ByteString -> PatchCheck Bool+insert_line f n l = do+    c <- file_contents f+    case c of+      Nothing -> assert_not $ FileEx f -- in this case, the repo is inconsistent+      Just c' -> do+        let lines'   = M.mapKeys (\k -> if k >= n then k+1 else k) (fc_lines c')+            lines''  = M.insert n l lines'+            maxline' = max n (fc_maxline c')+        set_contents f (FC lines'' maxline')+        return True++-- deletes a line from a hunk patch (third argument) in the given file (first+-- argument) at the given line number (second argument)+delete_line :: String -> Int -> B.ByteString -> PatchCheck Bool+delete_line f n l = do+    c <- file_contents f+    case c of+      Nothing -> assert_not $ FileEx f+      Just c' ->+        let flines  = fc_lines c'+            flines' = M.mapKeys (\k -> if k > n then k-1 else k)+                                (M.delete n flines)+            maxlinenum' | n <= fc_maxline c'  = fc_maxline c' - 1+                        | otherwise           = n - 1+            c'' = FC flines' maxlinenum'+            do_delete = do+              set_contents f c''+              is_valid+        in case M.lookup n flines of+          Nothing -> do_delete+          Just l' -> if l == l'+                       then do_delete+                       else assert_not $ FileEx f++set_contents :: String -> FileContents -> PatchCheck ()+set_contents f c = handle_inconsistent () $ do+    P ks nots <- get+    let ks' = FileLines f c : filter (not . is_file_lines_for f) ks+    put (P ks' nots)+  where is_file_lines_for file prop = case prop of +                                        FileLines f' _ -> file == f'+                                        _              -> False++-- | Get (as much as we know about) the contents of a file in the current state.+--   Returns Nothing if the state is inconsistent.+file_contents :: String -> PatchCheck (Maybe FileContents)+file_contents f = handle_inconsistent Nothing $ do+      P ks _ <- get+      return (fic ks)+    where fic (FileLines f' c:_) | f == f' = Just c+          fic (_:ks) = fic ks+          fic [] = Just empty_filecontents++-- | Checks if a file is empty+file_empty :: String          -- ^ Name of the file to check+           -> PatchCheck Bool+file_empty f = do+  c <- file_contents f+  let empty = case c of+               Just c' -> fc_maxline c' == 0 && M.null (fc_lines c')+               Nothing -> True+  if empty+     then do set_contents f empty_filecontents+             is_valid+     -- Crude way to make it inconsistent and return false:+     else assert_not $ FileEx f+  return empty++movedirfilename :: String -> String -> String -> String+movedirfilename d d' f+  | (d ++ "/") `isPrefixOf` f = d' ++ drop (length d) f+  | f == d = d'+  | otherwise = f++-- | Replaces a filename by another in all paths. Returns True if the repository+--   is consistent, False if it is not.+do_swap :: String -> String -> PatchCheck Bool+do_swap f f' = handle_inconsistent False $ do+    modify (\(P ks nots) -> P (map sw ks) (map sw nots))+    return True+  where sw (FileEx a) | f  `is_soe` a = FileEx $ movedirfilename f f' a+                      | f' `is_soe` a = FileEx $ movedirfilename f' f a+        sw (DirEx a) | f  `is_soe` a = DirEx $ movedirfilename f f' a+                     | f' `is_soe` a = DirEx $ movedirfilename f' f a+        sw (FileLines a c) | f  `is_soe` a = FileLines (movedirfilename f f' a) c+                           | f' `is_soe` a = FileLines (movedirfilename f' f a) c+        sw (NotEx a) | f `is_soe` a = NotEx $ movedirfilename f f' a+                     | f' `is_soe` a = NotEx $ movedirfilename f' f a+        sw p = p+        is_soe d1 d2 = -- is_superdir_or_equal+            d1 == d2 || (d1 ++ "/") `isPrefixOf` d2++-- | Assert a property about the repository. If the property is already present+-- in the repo state, nothing changes, and the function returns True. If it is+-- not present yet, it is added to the repo state, and the function is True. If+-- the property is already in the list of properties that do not hold for the+-- repo, the state becomes inconsistent, and the function returns false.+assert :: Prop -> PatchCheck Bool+assert p = handle_inconsistent False $ do+    P ks nots <- get+    if has p nots+      then do+        put Inconsistent+        return False+      else if has p ks+             then return True+             else do+               put (P (p:ks) nots)+               return True++-- | Like @assert@, but negatively: state that some property must not hold for+--   the current repo.+assert_not :: Prop -> PatchCheck Bool+assert_not p = handle_inconsistent False $ do+    P ks nots <- get+    if has p ks+      then do+        put Inconsistent+        return False+      else if has p nots+             then return True+             else do+               put (P ks (p:nots))+               return True++-- | Remove a property from the list of properties that do not hold for this+-- repo (if it's there), and add it to the list of properties that hold.+-- Returns False if the repo is inconsistent, True otherwise.+change_to_true :: Prop -> PatchCheck Bool+change_to_true p = handle_inconsistent False $ do+    modify (\(P ks nots) -> P (p:ks) (filter (p /=) nots))+    return True++-- | Remove a property from the list of properties that hold for this repo (if+-- it's in there), and add it to the list of properties that do not hold.+-- Returns False if the repo is inconsistent, True otherwise.+change_to_false :: Prop -> PatchCheck Bool+change_to_false p = handle_inconsistent False $ do+    modify (\(P ks nots) -> P (filter (p /=) ks) (p:nots))+    return True++assert_file_exists :: String -> PatchCheck Bool+assert_file_exists f = do assert_not $ NotEx f+                          assert_not $ DirEx f+                          assert $ FileEx f+assert_dir_exists :: String -> PatchCheck Bool+assert_dir_exists d = do assert_not $ NotEx d+                         assert_not $ FileEx d+                         assert $ DirEx d+assert_exists :: String -> PatchCheck Bool+assert_exists f = assert_not $ NotEx f++assert_no_such :: String -> PatchCheck Bool+assert_no_such f = do assert_not $ FileEx f+                      assert_not $ DirEx f+                      assert $ NotEx f++create_file :: String -> PatchCheck Bool+create_file fn = do+  superdirs_exist fn+  assert_no_such fn+  change_to_true (FileEx fn)+  change_to_false (NotEx fn)++create_dir :: String -> PatchCheck Bool+create_dir fn = do+  substuff_dont_exist fn+  superdirs_exist fn+  assert_no_such fn+  change_to_true (DirEx fn)+  change_to_false (NotEx fn)++remove_file :: String -> PatchCheck Bool+remove_file fn = do+  superdirs_exist fn+  assert_file_exists fn+  file_empty fn+  change_to_false (FileEx fn)+  change_to_true (NotEx fn)++remove_dir :: String -> PatchCheck Bool+remove_dir fn = do+  substuff_dont_exist fn+  superdirs_exist fn+  assert_dir_exists fn+  change_to_false (DirEx fn)+  change_to_true (NotEx fn)++check_move :: String -> String -> PatchCheck Bool+check_move f f' = do+  superdirs_exist f+  superdirs_exist f'+  assert_exists f+  assert_no_such f'+  do_swap f f'++substuff_dont_exist :: String -> PatchCheck Bool+substuff_dont_exist d = handle_inconsistent False $ do+    P ks _ <- get+    if all noss ks+      then return True+      else do+        put Inconsistent+        return False+  where noss (FileEx f) = not (is_within_dir f)+        noss (DirEx f) = not (is_within_dir f)+        noss _ = True+        is_within_dir f = (d ++ "/") `isPrefixOf` f++-- the init and tail calls dump the final init (which is just the path itself+-- again), the first init (which is empty), and the initial "." from+-- splitDirectories+superdirs_exist :: String -> PatchCheck Bool+superdirs_exist fn = and `fmap` mapM assert_dir_exists superdirs+  where superdirs =  map (("./"++) . joinPath) +                         (init (tail (inits (tail (splitDirectories fn)))))++file_exists :: String -> PatchCheck Bool+file_exists fn = do+  superdirs_exist fn+  assert_file_exists fn++dir_exists :: String -> PatchCheck Bool+dir_exists fn = do+  superdirs_exist fn+  assert_dir_exists fn
src/Darcs/TheCommands.hs view
@@ -16,26 +16,22 @@ -- Boston, MA 02110-1301, USA.  {-# LANGUAGE CPP #-}-module Darcs.TheCommands ( command_control_list ) where+module Darcs.TheCommands ( commandControlList ) where +import Prelude hiding ( log ) import Darcs.Commands.Add ( add ) import Darcs.Commands.AmendRecord ( amendrecord ) import Darcs.Commands.Annotate ( annotate ) import Darcs.Commands.Apply ( apply )-import Darcs.Commands.Changes ( changes )+import Darcs.Commands.Changes ( changes, log ) import Darcs.Commands.Check ( check ) import Darcs.Commands.Convert ( convert ) import Darcs.Commands.Diff import Darcs.Commands.Dist ( dist ) import Darcs.Commands.Get ( get, clone )-#ifdef HAVE_HASKELL_ZLIB import Darcs.Commands.GZCRCs ( gzcrcs )-#else--- import just to check it compiles-import Darcs.Commands.GZCRCs ()-#endif import Darcs.Commands.Init ( initialize )-import Darcs.Commands.Show ( show_command, list, query )+import Darcs.Commands.Show ( showCommand, list, query ) import Darcs.Commands.MarkConflicts ( markconflicts, resolve ) import Darcs.Commands.Move ( move, mv ) import Darcs.Commands.Optimize ( optimize )@@ -52,56 +48,54 @@ import Darcs.Commands.SetPref ( setpref ) import Darcs.Commands.Tag ( tag ) import Darcs.Commands.TrackDown ( trackdown )-import Darcs.Commands.TransferMode ( transfer_mode )+import Darcs.Commands.TransferMode ( transferMode ) import Darcs.Commands.Unrecord ( unrecord, unpull, obliterate ) import Darcs.Commands.Unrevert ( unrevert ) import Darcs.Commands.WhatsNew ( whatsnew )-import Darcs.Commands ( CommandControl(Command_data,Hidden_command,Group_name) )+import Darcs.Commands ( CommandControl(CommandData,HiddenCommand,GroupName) )  -- | The commands that darcs knows about (e.g. whatsnew, record), --   organized into thematic groups.  Note that hidden commands --   are also listed here.-command_control_list :: [CommandControl]-command_control_list = [Group_name "Changing and querying the working copy:",-                Command_data add,-                Command_data remove, Hidden_command unadd, Hidden_command rm,-                Command_data move, Hidden_command mv,-                Command_data replace,-                Command_data revert,-                Command_data unrevert,-                Command_data whatsnew,-                Group_name "Copying changes between the working copy and the repository:",-                Command_data record, Hidden_command commit,-                Command_data unrecord,-                Command_data amendrecord,-                Command_data markconflicts, Hidden_command resolve,-                Group_name "Direct modification of the repository:",-                Command_data tag,-                Command_data setpref,-                Group_name "Querying the repository:",-                Command_data diff_command,-                Command_data changes,-                Command_data annotate,-                Command_data dist,-                Command_data trackdown,-                Command_data show_command, Hidden_command list, Hidden_command query,-                Hidden_command transfer_mode,-                Group_name "Copying patches between repositories with working copy update:",-                Command_data pull,-                Command_data obliterate, Hidden_command unpull,-                Command_data rollback,-                Command_data push,-                Command_data send,-                Command_data apply,-                Command_data get, Hidden_command clone,-                Command_data put,-                Group_name "Administrating repositories:",-                Command_data initialize,-                Command_data optimize,-                Command_data check,-                Command_data repair,-                Command_data convert-#ifdef HAVE_HASKELL_ZLIB-                ,Hidden_command gzcrcs-#endif+commandControlList :: [CommandControl]+commandControlList = [GroupName "Changing and querying the working copy:",+                CommandData add,+                CommandData remove, HiddenCommand unadd, HiddenCommand rm,+                CommandData move, HiddenCommand mv,+                CommandData replace,+                CommandData revert,+                CommandData unrevert,+                CommandData whatsnew,+                GroupName "Copying changes between the working copy and the repository:",+                CommandData record, HiddenCommand commit,+                CommandData unrecord,+                CommandData amendrecord,+                CommandData markconflicts, HiddenCommand resolve,+                GroupName "Direct modification of the repository:",+                CommandData tag,+                CommandData setpref,+                GroupName "Querying the repository:",+                CommandData diffCommand,+                CommandData changes, HiddenCommand log,+                CommandData annotate,+                CommandData dist,+                CommandData trackdown,+                CommandData showCommand, HiddenCommand list, HiddenCommand query,+                HiddenCommand transferMode,+                GroupName "Copying patches between repositories with working copy update:",+                CommandData pull,+                CommandData obliterate, HiddenCommand unpull,+                CommandData rollback,+                CommandData push,+                CommandData send,+                CommandData apply,+                CommandData get, HiddenCommand clone,+                CommandData put,+                GroupName "Administrating repositories:",+                CommandData initialize,+                CommandData optimize,+                CommandData check,+                CommandData repair,+                CommandData convert+                ,HiddenCommand gzcrcs                ]
src/Darcs/Utils.hs view
@@ -3,16 +3,20 @@ {-# LANGUAGE CPP, ForeignFunctionInterface #-}  module Darcs.Utils ( catchall, ortryrunning, nubsort, breakCommand,-                     clarify_errors, prettyException, prettyError,+                     clarifyErrors, prettyException, prettyError,                     putStrLnError, putDocLnError,                     withCurrentDirectory,                     withUMask, askUser, stripCr,                     showHexLen, add_to_error_loc,                     maybeGetEnv, firstNotBlank, firstJustM, firstJustIO,                     isUnsupportedOperationError, isHardwareFaultError,-                    get_viewer, edit_file, promptYorn, promptCharFancy,+                    get_viewer, edit_file, run_editor,+                    promptYorn, promptCharFancy,                     environmentHelpEditor, environmentHelpPager,-                    formatPath ) where+                    formatPath+                    -- * Tree filtering.+                   , filterFilePaths, filterPaths+                   ) where  import Prelude hiding ( catch ) import Control.Exception ( bracket, bracket_, catch, Exception(IOException), try )@@ -39,6 +43,8 @@  import Progress ( withoutProgress ) +import Storage.Hashed.AnchoredPath( AnchoredPath, isPrefix, floatPath )+ import System.Console.Haskeline ( runInputT, defaultSettings, getInputLine,                                   getInputChar, outputStrLn ) import System.Console.Haskeline.Encoding ( encode )@@ -91,8 +97,8 @@ firstJustIO = firstJustM . map (\o -> o `catchall` return Nothing)  -clarify_errors :: IO a -> String -> IO a-clarify_errors a e = a `catch` (\x -> fail $ unlines [prettyException x,e])+clarifyErrors :: IO a -> String -> IO a+clarifyErrors a e = a `catch` (\x -> fail $ unlines [prettyException x,e])  prettyException :: Control.Exception.Exception -> String prettyException (IOException e) | isUserError e = ioeGetErrorString e@@ -184,15 +190,8 @@  edit_file :: FilePathLike p => p -> IO ExitCode edit_file ff = do-  ed <- get_editor   old_content <- file_content-  ec <- exec_interactive ed f-             `ortryrunning` exec_interactive "emacs" f-             `ortryrunning` exec_interactive "emacs -nw" f-             `ortryrunning` exec_interactive "nano" f-#ifdef WIN32-             `ortryrunning` exec_interactive "edit" f-#endif+  ec <- run_editor f   new_content <- file_content   when (new_content == old_content) $ do     yorn <- promptYorn "File content did not change. Continue anyway?"@@ -206,6 +205,17 @@                                 return $ Just content                         else return Nothing +run_editor :: FilePath -> IO ExitCode+run_editor f = do+  ed <- get_editor+  exec_interactive ed f+       `ortryrunning` exec_interactive "emacs" f+       `ortryrunning` exec_interactive "emacs -nw" f+       `ortryrunning` exec_interactive "nano" f+#ifdef WIN32+       `ortryrunning` exec_interactive "edit" f+#endif+ get_editor :: IO String get_editor = getEnv "DARCS_EDITOR" `catchall`              getEnv "DARCSEDITOR" `catchall`@@ -256,3 +266,16 @@  setDefault s = case md of Nothing -> s                            Just d  -> map (setUpper d) s  setUpper d c = if d == c then toUpper c else c++-- | Construct a filter from a list of AnchoredPaths, that will accept any path+-- that is either a parent or a child of any of the listed paths, and discard+-- everything else.+filterPaths :: [AnchoredPath] -> AnchoredPath -> t -> Bool+filterPaths files =+    \p _ -> any (\x -> x `isPrefix` p || p `isPrefix` x) files++-- | Same as 'filterPath', but for ordinary 'FilePath's (as opposed to+-- AnchoredPath).+filterFilePaths :: [FilePath] -> AnchoredPath -> t -> Bool+filterFilePaths = filterPaths . map floatPath+
+ src/Darcs/Witnesses/Ordered.hs view
@@ -0,0 +1,277 @@+-- Copyright (C) 2007 David Roundy+--+-- This program is free software; you can redistribute it and/or modify+-- it under the terms of the GNU General Public License as published by+-- the Free Software Foundation; either version 2, or (at your option)+-- any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+{-# LANGUAGE CPP #-}+-- , MagicHash, TypeOperators, GADTs #-}++#include "gadts.h"++module Darcs.Witnesses.Ordered ( EqCheck(..), isEq, (:>)(..), (:<)(..), (:\/:)(..), (:/\:)(..), (:||:)(..),+                             FL(..), RL(..),Proof(..),+#ifndef GADT_WITNESSES+                             unsafeUnFL, unsafeFL, unsafeRL, unsafeUnRL,+#endif+                             lengthFL, mapFL, mapFL_FL, spanFL, foldlFL, allFL,+                             splitAtFL, bunchFL, foldlRL,+                             lengthRL, isShorterThanRL, mapRL, mapRL_RL, zipWithFL,+                             unsafeMap_l2f, filterE, filterFL,+                             reverseFL, reverseRL, (+>+), (+<+),+                             nullFL, concatFL, concatRL, concatReverseFL, headRL,+                             MyEq, unsafeCompare, (=\/=), (=/\=),+                             consRLSealed, nullRL,+                             unsafeCoerceP, unsafeCoerceP2+                           ) where++#include "impossible.h"+import GHC.Base (unsafeCoerce#)+import Darcs.Witnesses.Show+import Darcs.Witnesses.Sealed ( FlippedSeal(..), flipSeal )++data EqCheck C(a b) where+    IsEq :: EqCheck C(a a)+    NotEq :: EqCheck C(a b)++instance Eq (EqCheck C(a b)) where+    IsEq == IsEq = True+    NotEq == NotEq = True+    _ == _ = False++isEq :: EqCheck C(a b) -> Bool+isEq IsEq = True+isEq NotEq = False++instance Show (EqCheck C(a b)) where+    show IsEq = "IsEq"+    show NotEq = "NotEq"++data Proof a C(x y) where+    Proof :: a -> Proof a C(x x)++data (a1 :> a2) C(x y) = FORALL(z) (a1 C(x z)) :> (a2 C(z y))+infixr 1 :>+data (a1 :< a2) C(x y) = FORALL(z) (a1 C(z y)) :< (a2 C(x z))+infix 1 :<+infix 1 :/\:, :\/:, :||:+data (a1 :\/: a2) C(x y) = FORALL(z) (a1 C(z x)) :\/: (a2 C(z y))+data (a1 :/\: a2) C(x y) = FORALL(z) (a1 C(x z)) :/\: (a2 C(y z))+data (a1 :||: a2) C(x y) = (a1 C(x y)) :||: (a2 C(x y))+class MyEq p where+    -- Minimal definition defines any one of unsafeCompare, =\/= and =/\=.+    unsafeCompare :: p C(a b) -> p C(c d) -> Bool+    unsafeCompare a b = IsEq == (a =/\= unsafeCoerceP b)+    (=\/=) :: p C(a b) -> p C(a c) -> EqCheck C(b c)+    a =\/= b | unsafeCompare a b = unsafeCoerceP IsEq+             | otherwise = NotEq+    (=/\=) :: p C(a c) -> p C(b c) -> EqCheck C(a b)+    a =/\= b | IsEq == (a =\/= unsafeCoerceP b) = unsafeCoerceP IsEq+             | otherwise = NotEq++infix 4 =\/=, =/\=++unsafeCoerceP :: a C(x y) -> a C(b c)+unsafeCoerceP = unsafeCoerce#++unsafeCoerceP2 :: t C(w x y z) -> t C(a b c d)+unsafeCoerceP2 = unsafeCoerce#++instance (Show2 a, Show2 b) => Show ( (a :> b) C(x y) ) where+    showsPrec d (x :> y) = showOp2 1 ":>" d x y++instance (Show2 a, Show2 b) => Show2 (a :> b) where+    showsPrec2 = showsPrec++instance (Show2 a, Show2 b) => Show ( (a :\/: b) C(x y) ) where+    showsPrec d (x :\/: y) = showOp2 9 ":\\/:" d x y++instance (Show2 a, Show2 b) => Show2 (a :\/: b) where+    showsPrec2 = showsPrec++infixr 5 :>:, :<:, +>+, +<+++-- forward list+data FL a C(x z) where+    (:>:) :: a C(x y) -> FL a C(y z) -> FL a C(x z)+    NilFL :: FL a C(x x)++instance Show2 a => Show (FL a C(x z)) where+   showsPrec _ NilFL = showString "NilFL"+   showsPrec d (x :>: xs) = showParen (d > prec) $ showsPrec2 (prec + 1) x .+                            showString " :>: " . showsPrec (prec + 1) xs+       where prec = 5++instance Show2 a => Show2 (FL a) where+   showsPrec2 = showsPrec++-- reverse list+data RL a C(x z) where+    (:<:) :: a C(y z) -> RL a C(x y) -> RL a C(x z)+    NilRL :: RL a C(x x)++nullFL :: FL a C(x z) -> Bool+nullFL NilFL = True+nullFL _ = False++nullRL :: RL a C(x z) -> Bool+nullRL NilRL = True+nullRL _ = False++filterFL :: (FORALL(x y) p C(x y) -> EqCheck C(x y)) -> FL p C(w z) -> FL p C(w z)+filterFL _ NilFL = NilFL+filterFL f (x:>:xs) | IsEq <- f x = filterFL f xs+                    | otherwise = x :>: filterFL f xs++filterE :: (a -> EqCheck C(x y)) -> [a] -> [Proof a C(x y)]+filterE _ [] = []+filterE p (x:xs)+    | IsEq <- p x = Proof x : filterE p xs+    | otherwise   = filterE p xs++(+>+) :: FL a C(x y) -> FL a C(y z) -> FL a C(x z)+NilFL +>+ ys = ys+(x:>:xs) +>+ ys = x :>: xs +>+ ys++(+<+) :: RL a C(y z) -> RL a C(x y) -> RL a C(x z)+NilRL +<+ ys = ys+(x:<:xs) +<+ ys = x :<: xs +<+ ys++reverseFL :: FL a C(x z) -> RL a C(x z)+reverseFL xs = r NilRL xs+  where r :: RL a C(l m) -> FL a C(m o) -> RL a C(l o)+        r ls NilFL = ls+        r ls (a:>:as) = r (a:<:ls) as++reverseRL :: RL a C(x z) -> FL a C(x z)+reverseRL xs = r NilFL xs -- r (xs :> NilFL)+  where r :: FL a C(m o) -> RL a C(l m) -> FL a C(l o)+        r ls NilRL = ls+        r ls (a:<:as) = r (a:>:ls) as++concatFL :: FL (FL a) C(x z) -> FL a C(x z)+concatFL NilFL = NilFL+concatFL (a:>:as) = a +>+ concatFL as++concatRL :: RL (RL a) C(x z) -> RL a C(x z)+concatRL NilRL = NilRL+concatRL (a:<:as) = a +<+ concatRL as++spanFL :: (FORALL(w y) a C(w y) -> Bool) -> FL a C(x z) -> (FL a :> FL a) C(x z)+spanFL f (x:>:xs) | f x = case spanFL f xs of+                            ys :> zs -> (x:>:ys) :> zs+spanFL _ xs = NilFL :> xs++splitAtFL :: Int -> FL a C(x z) -> (FL a :> FL a) C(x z)+splitAtFL 0 xs = NilFL :> xs+splitAtFL _ NilFL = NilFL :> NilFL+splitAtFL n (x:>:xs) = case splitAtFL (n-1) xs of+                       (xs':>xs'') -> (x:>:xs' :> xs'')++-- 'bunchFL n' groups patches into batches of n, except that it always puts+-- the first patch in its own group, this being a recognition that the+-- first patch is often *very* large.++bunchFL :: Int -> FL a C(x y) -> FL (FL a) C(x y)+bunchFL _ NilFL = NilFL+bunchFL n (x:>:xs) = (x :>: NilFL) :>: bFL xs+    where bFL :: FL a C(x y) -> FL (FL a) C(x y)+          bFL NilFL = NilFL+          bFL bs = case splitAtFL n bs of+                   a :> b -> a :>: bFL b+++allFL :: (FORALL(x y) a C(x y) -> Bool) -> FL a C(w z) -> Bool+allFL f xs = and $ mapFL f xs++foldlFL :: (FORALL(w y) a -> b C(w y) -> a) -> a -> FL b C(x z) -> a+foldlFL _ x NilFL = x+foldlFL f x (y:>:ys) = foldlFL f (f x y) ys++foldlRL :: (FORALL(w y) a -> b C(w y) -> a) -> a -> RL b C(x z) -> a+foldlRL _ x NilRL = x+foldlRL f x (y:<:ys) = foldlRL f (f x y) ys++mapFL_FL :: (FORALL(w y) a C(w y) -> b C(w y)) -> FL a C(x z) -> FL b C(x z)+mapFL_FL _ NilFL = NilFL+mapFL_FL f (a:>:as) = f a :>: mapFL_FL f as++zipWithFL :: (FORALL(x y) a -> p C(x y) -> q C(x y))+          -> [a] -> FL p C(w z) -> FL q C(w z)+zipWithFL f (x:xs) (y :>: ys) = f x y :>: zipWithFL f xs ys+zipWithFL _ _ NilFL = NilFL+zipWithFL _ [] (_:>:_) = bug "zipWithFL called with too short a list"++mapRL_RL :: (FORALL(w y) a C(w y) -> b C(w y)) -> RL a C(x z) -> RL b C(x z)+mapRL_RL _ NilRL = NilRL+mapRL_RL f (a:<:as) = f a :<: mapRL_RL f as++mapFL :: (FORALL(w z) a C(w z) -> b) -> FL a C(x y) -> [b]+mapFL _ NilFL = []+mapFL f (a :>: b) = f a : mapFL f b++mapRL :: (FORALL(w z) a C(w z) -> b) -> RL a C(x y) -> [b]+mapRL _ NilRL = []+mapRL f (a :<: b) = f a : mapRL f b++unsafeMap_l2f :: (FORALL(w z) a -> b C(w z)) -> [a] -> FL b C(x y)+unsafeMap_l2f _ [] = unsafeCoerceP NilFL+unsafeMap_l2f f (x:xs) = f x :>: unsafeMap_l2f f xs++lengthFL :: FL a C(x z) -> Int+lengthFL xs = l xs 0+  where l :: FL a C(x z) -> Int -> Int+        l NilFL n = n+        l (_:>:as) n = l as $! n+1++lengthRL :: RL a C(x z) -> Int+lengthRL xs = l xs 0+  where l :: RL a C(x z) -> Int -> Int+        l NilRL n = n+        l (_:<:as) n = l as $! n+1++isShorterThanRL :: RL a C(x y) -> Int -> Bool+isShorterThanRL _ n | n <= 0 = False+isShorterThanRL NilRL _ = True+isShorterThanRL (_:<:xs) n = isShorterThanRL xs (n-1)++concatReverseFL :: FL (RL a) C(x y) -> RL a C(x y)+concatReverseFL = concatRL . reverseFL++headRL :: RL a C(x y) -> FlippedSeal a C(y)+headRL (x:<:_) = flipSeal x+headRL _ = impossible++consRLSealed :: a C(y z) -> FlippedSeal (RL a) C(y) -> FlippedSeal (RL a) C(z)+consRLSealed a (FlippedSeal as) = flipSeal $ a :<: as++#ifndef GADT_WITNESSES+-- These are useful for interfacing with modules which do not yet use type witnesses+unsafeUnFL :: FL a -> [a]+unsafeUnFL NilFL = []+unsafeUnFL (a:>:as) = a : unsafeUnFL as++unsafeUnRL :: RL a -> [a]+unsafeUnRL NilRL = []+unsafeUnRL (a:<:as) = a : unsafeUnRL as++unsafeFL :: [a] -> FL a+unsafeFL [] = NilFL+unsafeFL (a:as) = a :>: unsafeFL as++unsafeRL :: [a] -> RL a+unsafeRL [] = NilRL+unsafeRL (a:as) = a :<: unsafeRL as+#endif
+ src/Darcs/Witnesses/Sealed.hs view
@@ -0,0 +1,103 @@+-- Copyright (C) 2007 David Roundy+--+-- This program is free software; you can redistribute it and/or modify+-- it under the terms of the GNU General Public License as published by+-- the Free Software Foundation; either version 2, or (at your option)+-- any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; see the file COPYING.  If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+{-# LANGUAGE CPP #-}+-- , MagicHash, GADTs #-}++#include "gadts.h"++module Darcs.Witnesses.Sealed ( Sealed(..), seal, unseal, mapSeal,+#ifndef GADT_WITNESSES+                      unsafeUnseal, unsafeUnflippedseal, unsafeUnseal2,+#endif+                      Sealed2(..), seal2, unseal2, mapSeal2,+                      FlippedSeal(..), flipSeal, unsealFlipped, mapFlipped,+                      unsealM, liftSM+                    ) where++import GHC.Base ( unsafeCoerce# )+import Darcs.Witnesses.Show++data Sealed a where+    Sealed :: a C(x ) -> Sealed a++seal :: a C(x ) -> Sealed a+seal = Sealed++data Sealed2 a where+    Sealed2 :: !(a C(x y )) -> Sealed2 a++seal2 :: a C(x y ) -> Sealed2 a+seal2 = Sealed2++data FlippedSeal a C(y) where+    FlippedSeal :: !(a C(x y)) -> FlippedSeal a C(y)++flipSeal :: a C(x y) -> FlippedSeal a C(y)+flipSeal = FlippedSeal++#ifndef GADT_WITNESSES+unsafeUnseal :: Sealed a -> a+unsafeUnseal (Sealed a) = a++unsafeUnflippedseal :: FlippedSeal a -> a+unsafeUnflippedseal (FlippedSeal a) = a++unsafeUnseal2 :: Sealed2 a -> a+unsafeUnseal2 (Sealed2 a) = a+#endif++seriouslyUnsafeUnseal :: Sealed a -> a C(())+seriouslyUnsafeUnseal (Sealed a) = unsafeCoerce# a++unseal :: (FORALL(x) a C(x ) -> b) -> Sealed a -> b+unseal f x = f (seriouslyUnsafeUnseal x)++-- laziness property:+-- unseal (const True) undefined == True++unsealM :: Monad m => m (Sealed a) -> (FORALL(x) a C(x) -> m b) -> m b+unsealM m1 m2 = do sx <- m1+                   unseal m2 sx++liftSM :: Monad m => (FORALL(x) a C(x) -> b) -> m (Sealed a) -> m b+liftSM f m = do sx <- m+                return (unseal f sx)++mapSeal :: (FORALL(x) a C(x ) -> b C(x )) -> Sealed a -> Sealed b+mapSeal f = unseal (seal . f)++mapFlipped :: (FORALL(x) a C(x y) -> b C(x z)) -> FlippedSeal a C(y) -> FlippedSeal b C(z)+mapFlipped f (FlippedSeal x) = FlippedSeal (f x)++seriouslyUnsafeUnseal2 :: Sealed2 a -> a C(() ())+seriouslyUnsafeUnseal2 (Sealed2 a) = unsafeCoerce# a++unseal2 :: (FORALL(x y) a C(x y ) -> b) -> Sealed2 a -> b+unseal2 f a = f (seriouslyUnsafeUnseal2 a)++mapSeal2 :: (FORALL(x y) a C(x y ) -> b C(x y )) -> Sealed2 a -> Sealed2 b+mapSeal2 f = unseal2 (seal2 . f)++unsealFlipped :: (FORALL(x y) a C(x y) -> b) -> FlippedSeal a C(z) -> b+unsealFlipped f (FlippedSeal a) = f a++instance Show1 a => Show (Sealed a) where+    showsPrec d (Sealed x) = showParen (d > app_prec) $ showString "Sealed " . showsPrec1 (app_prec + 1) x+instance Show2 a => Show (Sealed2 a) where+    showsPrec d (Sealed2 x) = showParen (d > app_prec) $ showString "Sealed2 " . showsPrec2 (app_prec + 1) x
+ src/Darcs/Witnesses/Show.hs view
@@ -0,0 +1,25 @@+{-# OPTIONS_GHC -cpp -fglasgow-exts #-}+{-# LANGUAGE CPP #-}++module Darcs.Witnesses.Show(Show1(..), Show2(..), showOp2, app_prec) where++#include "gadts.h"++class Show1 a where+    show1 :: a C(x) -> String+    show1 x = showsPrec1 0 x ""+    showsPrec1 :: Int -> a C(x) -> ShowS+    showsPrec1 _ x s = show1 x ++ s++class Show2 a where+    show2 :: a C(x y) -> String+    show2 x = showsPrec2 0 x ""+    showsPrec2 :: Int -> a C(x y) -> ShowS+    showsPrec2 _ x s = show2 x ++ s++showOp2 :: (Show2 a, Show2 b) => Int -> String -> Int -> a C(w x) -> b C(y z) -> String -> String+showOp2 prec opstr d x y = showParen (d > prec) $ showsPrec2 (prec + 1) x .+                          showString opstr . showsPrec2 (prec + 1) y++app_prec :: Int+app_prec = 10
src/Exec.hs view
@@ -32,7 +32,7 @@ import Control.Exception ( bracket ) import System.Posix.Env ( setEnv, getEnv, unsetEnv ) import System.Posix.IO ( queryFdOption, setFdOption, FdOption(..), stdInput )-import System.IO	( stdin )+import System.IO ( stdin ) #else import Control.Exception ( catchJust, Exception(IOException) ) import Data.List ( isInfixOf )@@ -40,9 +40,9 @@  import System.Exit ( ExitCode (..) ) import System.Cmd ( system )-import System.IO	( IOMode(..), openBinaryFile, stdout )+import System.IO ( IOMode(..), openBinaryFile, stdout ) import System.Process   ( runProcess, terminateProcess, waitForProcess )-import GHC.Handle	( hDuplicate )+import GHC.Handle ( hDuplicate )         -- urgh.  hDuplicate isn't available from a standard place. import Control.Exception ( bracketOnError ) 
− src/OldDate.hs
@@ -1,350 +0,0 @@--- Copyright (C) 2003 Peter Simons--- Copyright (C) 2003,2008 David Roundy------ This program is free software; you can redistribute it and/or modify--- it under the terms of the GNU General Public License as published by--- the Free Software Foundation; either version 2, or (at your option)--- any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; see the file COPYING.  If not, write to--- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,--- Boston, MA 02110-1301, USA.---- This module is intended to provide backwards-compatibility in the parsing--- of darcs patches.  In other words: don't change it, new features don't get--- added here.  The only user should be Darcs.Patch.Info.--module OldDate ( readUTCDate, showIsoDateTime ) where--import Text.ParserCombinators.Parsec-import System.Time-import Data.Char ( toUpper, isDigit )-import Control.Monad ( liftM, liftM2 )-import qualified Data.ByteString.Char8 as B-import Data.Maybe ( fromMaybe )---- | Read/interpret a date string, assuming UTC if timezone---   is not specified in the string-readUTCDate :: String -> CalendarTime-readUTCDate = readDate 0--readDate :: Int -> String -> CalendarTime-readDate tz d =-             case parseDate tz d of-             Left e -> error e-             Right ct -> ct--parseDate :: Int -> String -> Either String CalendarTime-parseDate tz d =-              if length d >= 14 && B.all isDigit bd-              then Right $-                   CalendarTime (readI $ B.take 4 bd)-                                (toEnum $ (+ (-1)) $ readI $ B.take 2 $ B.drop 4 bd)-                                (readI $ B.take 2 $ B.drop 6 bd) -- Day-                                (readI $ B.take 2 $ B.drop 8 bd) -- Hour-                                (readI $ B.take 2 $ B.drop 10 bd) -- Minute-                                (readI $ B.take 2 $ B.drop 12 bd) -- Second-                                0 Sunday 0 -- Picosecond, weekday and day of year unknown-                                "GMT" 0 False-              else let dt = do { x <- date_time tz; eof; return x }-                   in case parse dt "" d of-                      Left e -> Left $ "bad date: "++d++" - "++show e-                      Right ct -> Right ct-  where bd = B.pack (take 14 d)-        readI s = fst $ fromMaybe (error "parseDate: invalid date") (B.readInt s)--showIsoDateTime :: CalendarTime -> String-showIsoDateTime ct = concat [ show $ ctYear ct-                            , twoDigit . show . (+1) . fromEnum $ ctMonth ct-                            , twoDigit . show $ ctDay ct-                            , twoDigit . show $ ctHour ct-                            , twoDigit . show $ ctMin ct-                            , twoDigit . show $ ctSec ct-                            ]-    where twoDigit []          = undefined-          twoDigit x@(_:[])    = '0' : x-          twoDigit x@(_:_:[])  = x-          twoDigit _           = undefined------- Parser Combinators ------------------------------------------------- |Case-insensitive variant of Parsec's 'char' function.--caseChar        :: Char -> GenParser Char a Char-caseChar c       = satisfy (\x -> toUpper x == toUpper c)---- |Case-insensitive variant of Parsec's 'string' function.--caseString      :: String -> GenParser Char a ()-caseString cs    = mapM_ caseChar cs <?> cs---- |Match a parser at least @n@ times.--manyN           :: Int -> GenParser a b c -> GenParser a b [c]-manyN n p-    | n <= 0     = return []-    | otherwise  = liftM2 (++) (count n p) (many p)---- |Match a parser at least @n@ times, but no more than @m@ times.--manyNtoM        :: Int -> Int -> GenParser a b c -> GenParser a b [c]-manyNtoM n m p-    | n < 0      = return []-    | n > m      = return []-    | n == m     = count n p-    | n == 0     = foldr (<|>) (return []) (map (\x -> try $ count x p) (reverse [1..m]))-    | otherwise  = liftM2 (++) (count n p) (manyNtoM 0 (m-n) p)-------- Date/Time Parser -------------------------------------------------date_time :: Int -> CharParser a CalendarTime-date_time tz =-            choice [try $ cvs_date_time tz,-                    try $ iso8601_date_time tz,-                    old_date_time]--cvs_date_time :: Int -> CharParser a CalendarTime-cvs_date_time tz =-                do y <- year-                   char '/'-                   mon <- month_num -                   char '/'-                   d <- day-                   my_spaces-                   h <- hour-                   char ':'-                   m <- minute-                   char ':'-                   s <- second-                   z <- option tz $ my_spaces >> zone-                   return (CalendarTime y mon d h m s 0 Monday 0 "" z False)--old_date_time   :: CharParser a CalendarTime-old_date_time    = do wd <- day_name-                      my_spaces-                      mon <- month_name-                      my_spaces-                      d <- day-                      my_spaces-                      h <- hour-                      char ':'-                      m <- minute-                      char ':'-                      s <- second-                      my_spaces-                      z <- zone-                      my_spaces-                      y <- year-                      return (CalendarTime y mon d h m s 0 wd 0 "" z False)--{- FIXME: In case you ever want to use this outside of darcs, you should note -   that this implementation of ISO 8601 is not complete.  --   reluctant to implement (ambiguous!): -     * years > 9999  -     * truncated representations with implied century (89 for 1989) -   unimplemented: -     * repeated durations (not relevant)-     * lowest order component fractions in intervals-     * negative dates (BC)                    -   unverified or too relaxed:-     * the difference between 24h and 0h-     * allows stuff like 2005-1212; either you use the hyphen all the way -       (2005-12-12) or you don't use it at all (20051212), but you don't use-       it halfway, likewise with time -     * No bounds checking whatsoever on intervals! -       (next action: read iso doc to see if bounds-checking required?) -}-iso8601_date_time   :: Int -> CharParser a CalendarTime-iso8601_date_time localTz = try $ -  do d <- iso8601_date-     t <- option id $ try $ do optional $ oneOf " T" -                               iso8601_time  -     return $ t $ d { ctTZ = localTz }--iso8601_date :: CharParser a CalendarTime-iso8601_date = -  do d <- calendar_date <|> week_date <|> ordinal_date-     return $ foldr ($) nullCalendar d-  where -    calendar_date = -- yyyy-mm-dd-      try $ do d <- optchain year_ [ (dash, month_), (dash, day_) ]-               -- allow other variants to be parsed correctly -               notFollowedBy (digit <|> char 'W')-               return d-    week_date = --yyyy-Www-dd -      try $ do yfn <- year_-               optional dash-               char 'W'-               -- offset human 'week 1' -> computer 'week 0'-               w'  <- (\x -> x-1) `liftM` two_digits-               wd  <- option 1 $ do { optional dash; n_digits 1 }-               let y = yfn nullCalendar-                   firstDay = ctWDay y-               -- things that make this complicated-               -- 1. iso8601 weeks start from Monday; Haskell weeks start from Sunday-               -- 2. the first week is the one that contains at least Thursday-               --    if the year starts after Thursday, then some days of the year-               --    will have already passed before the first week-               let afterThursday = firstDay == Sunday || firstDay > Thursday-                   w  = if afterThursday then w'+1 else w'-                   diff c = c { ctDay = (7 * w) + wd - (fromEnum firstDay) }-               return [(toUTCTime.toClockTime.diff.yfn)]-    ordinal_date = -- yyyy-ddd-      try $ optchain year_ [ (dash, yearDay_) ]-    ---    year_  = try $ do y <- four_digits <?> "year (0000-9999)"-                      return $ \c -> c { ctYear = y }-    month_ = try $ do m <- two_digits <?> "month (1 to 12)"-                      -- we (artificially) use ctPicosec to indicate-                      -- whether the month has been specified.-                      return $ \c -> c { ctMonth = intToMonth m, ctPicosec = 0 }-    day_   = try $ do d <- two_digits <?> "day in month (1 to 31)"-                      return $ \c -> c { ctDay = d }-    yearDay_ = try $ do d <- n_digits 3 <?> "day in year (1 to 366)"-                        return $ \c -> c { ctYDay = d }-    dash = char '-'---- we return a function which sets the time on another calendar-iso8601_time :: CharParser a (CalendarTime -> CalendarTime)-iso8601_time = try $-  do ts <- optchain hour_ [ (colon     , min_)-                          , (colon     , sec_)-                          , (oneOf ",.", pico_) ] -     z  <- option id $ choice [ zulu , offset ]-     return $ foldr (.) id (z:ts)-  where -    hour_ = do h <- two_digits-               return $ \c -> c { ctHour = h }-    min_  = do m <- two_digits-               return $ \c -> c { ctMin = m }-    sec_  = do s <- two_digits-               return $ \c -> c { ctSec = s }-    pico_ = do digs <- many digit-               let picoExp = 12-                   digsExp = length digs-               let frac | null digs = 0-                        | digsExp > picoExp = read $ take picoExp digs-                        | otherwise = 10 ^ (picoExp - digsExp) * (read digs)-               return $ \c -> c { ctPicosec = frac }-    zulu   = do { char 'Z'; return (\c -> c { ctTZ = 0 }) }-    offset = do sign <- choice [ do { char '+' >> return   1  }-                               , do { char '-' >> return (-1) } ]-                h <- two_digits-                m <- option 0 $ do { optional colon; two_digits }-                return $ \c -> c { ctTZ = sign * 60 * ((h*60)+m) }-    colon = char ':'--optchain :: CharParser a b -> [(CharParser a c, CharParser a b)] -> CharParser a [b]-optchain p next = try $ -  do r1 <- p-     r2 <- case next of -           [] -> return []-           ((sep,p2):next2) -> option [] $ do { optional sep; optchain p2 next2 }-     return (r1:r2)--n_digits :: Int -> CharParser a Int -n_digits n = read `liftM` count n digit--two_digits, four_digits :: CharParser a Int-two_digits = n_digits 2-four_digits = n_digits 4--my_spaces :: CharParser a String-my_spaces = manyN 1 $ char ' '--day_name        :: CharParser a Day-day_name         = choice-                       [ caseString "Mon"       >> return Monday-                       , try (caseString "Tue") >> return Tuesday-                       , caseString "Wed"       >> return Wednesday-                       , caseString "Thu"       >> return Thursday-                       , caseString "Fri"       >> return Friday-                       , try (caseString "Sat") >> return Saturday-                       , caseString "Sun"       >> return Sunday-                       ]--year            :: CharParser a Int-year             = four_digits--month_num       :: CharParser a Month-month_num = do mn <- manyNtoM 1 2 digit -               return $ intToMonth $ (read mn :: Int)--intToMonth :: Int -> Month-intToMonth 1 = January-intToMonth 2 = February-intToMonth 3 = March-intToMonth 4 = April-intToMonth 5 = May-intToMonth 6 = June-intToMonth 7 = July-intToMonth 8 = August-intToMonth 9 = September-intToMonth 10 = October-intToMonth 11 = November-intToMonth 12 = December-intToMonth _  = error "invalid month!"--month_name      :: CharParser a Month-month_name       = choice-                       [ try (caseString "Jan") >> return January-                       , caseString "Feb"       >> return February-                       , try (caseString "Mar") >> return March-                       , try (caseString "Apr") >> return April-                       , caseString "May"       >> return May-                       , try (caseString "Jun") >> return June-                       , caseString "Jul"       >> return July-                       , caseString "Aug"       >> return August-                       , caseString "Sep"       >> return September-                       , caseString "Oct"       >> return October-                       , caseString "Nov"       >> return November-                       , caseString "Dec"       >> return December-                       ]--day             :: CharParser a Int-day              = do d <- manyNtoM 1 2 digit-                      return (read d :: Int)--hour            :: CharParser a Int-hour             = two_digits--minute          :: CharParser a Int-minute           = two_digits--second          :: CharParser a Int-second           = two_digits--zone            :: CharParser a Int-zone             = choice-                       [ do { char '+'; h <- hour; m <- minute; return (((h*60)+m)*60) }-                       , do { char '-'; h <- hour; m <- minute; return (-((h*60)+m)*60) }-                       , mkZone "UTC"  0-                       , mkZone "UT"  0-                       , mkZone "GMT" 0-                       , mkZone "EST" (-5)-                       , mkZone "EDT" (-4)-                       , mkZone "CST" (-6)-                       , mkZone "CDT" (-5)-                       , mkZone "MST" (-7)-                       , mkZone "MDT" (-6)-                       , mkZone "PST" (-8)-                       , mkZone "PDT" (-7)-                       , mkZone "CEST" 2-                       , mkZone "EEST" 3-                         -- if we don't understand it, just give a GMT answer...-                       , do { manyTill (oneOf $ ['a'..'z']++['A'..'Z']++[' '])-                                       (lookAhead space_digit);-                              return 0 }-                       ]-     where mkZone n o  = try $ do { caseString n; return (o*60*60) }-           space_digit = try $ do { char ' '; oneOf ['0'..'9'] }--nullCalendar :: CalendarTime -nullCalendar = CalendarTime 0 January 0 0 0 0 1 Sunday 0 "" 0 False
src/Preproc.hs view
@@ -13,23 +13,24 @@ --     LaTeX text.  In particular, \\darcsCommand{foo} is replaced by --     LaTeX markup describing the command @foo@. module Preproc ( preproc_main ) where+import qualified Ratified( readFile ) import System.FilePath ( (</>) ) import System.Environment ( getArgs ) import System.Exit ( exitWith, ExitCode(..) ) import Text.Regex ( matchRegex, mkRegex ) import Darcs.Commands ( DarcsCommand(SuperCommand,-                        command_sub_commands, command_name,-                        command_extra_arg_help, command_basic_options,-                        command_advanced_options, command_help,-                        command_description),-                        extract_commands )-import Darcs.Arguments ( options_latex )-import Darcs.Commands.Help ( command_control_list, environmentHelp )+                        commandSubCommands, commandName,+                        commandExtraArgHelp, commandBasicOptions,+                        commandAdvancedOptions, commandHelp,+                        commandDescription),+                        extractCommands )+import Darcs.Arguments ( optionsLatex )+import Darcs.Commands.Help ( commandControlList, environmentHelp ) import English ( andClauses )-import ThisVersion ( darcs_version )+import Version ( version )  the_commands :: [DarcsCommand]-the_commands = extract_commands command_control_list+the_commands = extractCommands commandControlList  -- | The entry point for this program.  The path to the TeX master -- file is supplied as the first argument.  Bootstrapping into@@ -79,17 +80,17 @@              else return $ "\\end{Verbatim}" : rest preproc ("\\darcsVersion":ss) = do   rest <- preproc ss-  return $ darcs_version:rest+  return $ version:rest preproc (s:ss) = do   rest <- preproc ss   let rx = mkRegex "^\\\\(input|darcs(Command|Env))\\{(.+)\\}$"   case matchRegex rx s of     Just ["input", _, path] ->-        do cs <- readFile $ "src" </> path -- ratify readFile: not part of darcs executable+        do cs <- Ratified.readFile $ "src" </> path -- not part of normal darcs operation            this <- preproc $ lines cs            return $ this ++ rest     Just ["darcsCommand", _, command] ->-        return $ commandHelp command : rest+        return $ latexCommandHelp command : rest     Just ["darcsEnv", _, variable] ->         return $ envHelp variable : rest     -- The base case for the whole preproc function.  Nothing to@@ -97,18 +98,18 @@     -- the result unmodified.     _ -> return $ s : rest -commandHelp :: String -> String-commandHelp command = section ++ "{darcs " ++ command ++ "}\n" +++latexCommandHelp :: String -> String+latexCommandHelp command = section ++ "{darcs " ++ command ++ "}\n" ++                       "\\label{" ++ command ++ "}\n" ++                       gh ++ get_options command ++ gd     where       section = if ' ' `elem` command then "\\subsubsection" else "\\subsection"       -- | Given a Darcs command name as a string, return that command's (multi-line) help string.       gh :: String-      gh =  escape_latex_specials $ command_property command_help the_commands command+      gh =  escape_latex_specials $ command_property commandHelp the_commands command       -- | Given a Darcs command name as a string, return that command's (one-line) description string.       gd :: String-      gd = command_property command_description the_commands command+      gd = command_property commandDescription the_commands command  get_options :: String -> String get_options comm = get_com_options $ get_c names the_commands@@ -120,10 +121,10 @@     [] -> [get name commands]     _ -> case get name commands of          c@SuperCommand { } ->-             c:(get_c ns $ extract_commands $ command_sub_commands c)+             c:(get_c ns $ extractCommands $ commandSubCommands c)          _ ->              error $ "Not a supercommand: " ++ name-    where get n (c:cs) | command_name c == n = c+    where get n (c:cs) | commandName c == n = c                        | otherwise = get n cs           get n [] = error $ "No such command:  "++n get_c [] _ = error "no command specified"@@ -131,12 +132,12 @@ get_com_options :: [DarcsCommand] -> String get_com_options c =     "\\par\\verb!Usage: darcs " ++ cmd ++ " [OPTION]... " ++-    args ++ "!\n\n" ++ "Options:\n\n" ++ options_latex opts1 ++-    (if null opts2 then "" else "\n\n" ++ "Advanced options:\n\n" ++ options_latex opts2)-    where cmd = unwords $ map command_name c-          args = unwords $ command_extra_arg_help $ last c-          opts1 = command_basic_options $ last c-          opts2 = command_advanced_options $ last c+    args ++ "!\n\n" ++ "Options:\n\n" ++ optionsLatex opts1 +++    (if null opts2 then "" else "\n\n" ++ "Advanced options:\n\n" ++ optionsLatex opts2)+    where cmd = unwords $ map commandName c+          args = unwords $ commandExtraArgHelp $ last c+          opts1 = commandBasicOptions $ last c+          opts2 = commandAdvancedOptions $ last c  command_property :: (DarcsCommand -> String) -> [DarcsCommand] -> String                  -> String
src/Progress.hs view
@@ -46,11 +46,12 @@  printProgress :: String -> ProgressData -> IO () printProgress k (ProgressData {sofar=s, total=Just t, latest=Just l}) =-    myput (k++" "++show s++"/"++show t++" : "++l) (k++" "++show s++"/"++show t)+    myput output output+        where output = (k++" "++show s++" done, "++show (t - s)++" queued. "++l) printProgress k (ProgressData {latest=Just l}) =     myput (k++" "++l) k printProgress k (ProgressData {sofar=s, total=Just t}) | t >= s =-    myput (k++" "++show s++"/"++show t) (k++" "++show s)+    myput (k++" "++show s++" done, "++show (t - s)++" queued") (k++" "++show s) printProgress k (ProgressData {sofar=s}) =     myput (k++" "++show s) k 
+ src/Ratified.hs view
@@ -0,0 +1,2 @@+module Ratified( readFile, hGetContents ) where+import System.IO( hGetContents )
− src/RegChars.hs
@@ -1,75 +0,0 @@--- Copyright (C) 2003 David Roundy------ This program is free software; you can redistribute it and/or modify--- it under the terms of the GNU General Public License as published by--- the Free Software Foundation; either version 2, or (at your option)--- any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; see the file COPYING.  If not, write to--- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,--- Boston, MA 02110-1301, USA.---module RegChars ( regChars,-                ) where--(&&&) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)-(&&&) a b c = a c && b c--(|||) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)-(|||) a b c = a c || b c--{-# INLINE regChars #-}---- | 'regChars' returns a filter function that tells if a char is a member--- of the regChar expression or not. The regChar expression is basically a--- set of chars, but it can contain ranges with use of the '-' (dash), and--- it can also be specified as a complement set by prefixing with '^'--- (caret). The dash and caret, as well as the backslash, can all be--- escaped with a backslash to suppress their special meaning.--- --- NOTE: The '.' (dot) is allowed to be escaped. It has no special meaning--- if it is not escaped, but the default 'filename_toks' in--- Darcs.Commands.Replace uses an escaped dot (WHY?).--regChars :: String -> (Char -> Bool)-regChars ('^':cs) = not . normalRegChars (unescapeChars cs)-regChars ('\\':'^':cs) = normalRegChars $ unescapeChars $ '^':cs-regChars cs = normalRegChars $ unescapeChars cs--{-# INLINE unescapeChars #-}---- | 'unescapeChars' unescapes whitespace, which is escaped in the replace--- patch file format. It will also unescape escaped carets, which is useful--- for escaping a leading caret that should not invert the regChars. All--- other escapes are left for the unescaping in 'normalRegChars'.--unescapeChars :: String -> String-unescapeChars ('\\':'n':cs) = '\n' : unescapeChars cs-unescapeChars ('\\':'t':cs) = '\t' : unescapeChars cs-unescapeChars ('\\':'^':cs) = '^' : unescapeChars cs-unescapeChars (c:cs) = c : unescapeChars cs-unescapeChars [] = []--{-# INLINE normalRegChars #-}---- | 'normalRegChars' assembles the filter function. It handles special--- chars, and also unescaping of escaped special chars. If a non-special--- char is still escaped by now we get a failure.--normalRegChars :: String -> (Char -> Bool)-normalRegChars ('\\':'.':cs) = (=='.') ||| normalRegChars cs-normalRegChars ('\\':'-':cs) = (=='-') ||| normalRegChars cs-normalRegChars ('\\':'\\':cs) = (=='\\') ||| normalRegChars cs-normalRegChars ('\\':c:_) = error $ "'\\"++[c]++"' not supported."-normalRegChars (c1:'-':c2:cs) = ((>= c1) &&& (<= c2)) ||| normalRegChars cs-normalRegChars (c:cs) = (== c) ||| normalRegChars cs-normalRegChars [] = \_ -> False--
src/Ssh.hs view
@@ -5,6 +5,7 @@            ) where  import Prelude hiding ( lookup, catch )+import qualified Ratified( hGetContents )  import System.Exit ( ExitCode(..) ) import System.Environment ( getEnv )@@ -15,7 +16,7 @@ import Data.Bits ( (.&.) ) import System.Random ( randomIO ) #endif-import System.IO ( Handle, hPutStr, hPutStrLn, hGetLine, hGetContents, hClose, hFlush )+import System.IO ( Handle, hPutStr, hPutStrLn, hGetLine, hClose, hFlush ) import System.IO.Unsafe ( unsafePerformIO ) import System.Directory ( doesFileExist, createDirectoryIfMissing ) import Control.Monad ( when )@@ -42,18 +43,19 @@  data Connection = C { inp :: !Handle, out :: !Handle, err :: !Handle, deb :: String -> IO () } -withSSHConnection :: String -> (Connection -> IO a) -> IO a -> IO a-withSSHConnection x withconnection withoutconnection =+withSSHConnection :: String -> String -> (Connection -> IO a) -> IO a -> IO a+withSSHConnection rdarcs repoid withconnection withoutconnection =     withoutProgress $     do cs <- readIORef sshConnections-       let uhost = takeWhile (/= ':') x-           url = cleanrepourl x+       let uhost = takeWhile (/= ':') repoid+           url = cleanrepourl repoid        case lookup url (cs :: Map String (Maybe Connection)) of          Just Nothing -> withoutconnection          Just (Just c) -> withconnection c          Nothing ->            do mc <- do (ssh,sshargs_) <- getSSHOnly SSH-                       let sshargs = sshargs_ ++ [uhost,"darcs","transfer-mode","--repodir",cleanrepodir x]+                       let sshargs = sshargs_ ++ [uhost,rdarcs,+                                                  "transfer-mode","--repodir",cleanrepodir repoid]                        debugMessage $ "ssh "++unwords sshargs                        (i,o,e,_) <- runInteractiveProcess ssh sshargs Nothing Nothing                        l <- hGetLine o@@ -67,7 +69,7 @@                     `catchNonSignal`                             \e -> do debugMessage $ "Failed to start ssh connection:\n    "++                                                     prettyException e-                                     severSSHConnection x+                                     severSSHConnection repoid                                      debugMessage $ unlines $                                          [ "NOTE: the server may be running a version of darcs prior to 2.0.0."                                          , ""@@ -98,10 +100,10 @@                    clean "" = bug $ "Buggy path in grabSSH: "++x                    file = clean dir                    failwith e = do severSSHConnection x-                                   eee <- hGetContents (err c) -- ratify hGetContents: it's okay-                                                               -- here because we're only grabbing-                                                               -- stderr, and we're also about to-                                                               -- throw the contents.+                                   -- hGetContents is ok here because we're+                                   -- only grabbing stderr, and we're also+                                   -- about to throw the contents.+                                   eee <- Ratified.hGetContents (err c)                                    debugFail $ e ++ " grabbing ssh file "++x++"\n"++eee                deb c $ "get "++file                hPutStrLn (inp c) $ "get " ++ file@@ -123,8 +125,8 @@ sshStdErrMode = withDebugMode $ \amdebugging ->                 return $ if amdebugging then AsIs else Null -copySSH :: String -> FilePath -> IO ()-copySSH uRaw f = withSSHConnection uRaw (\c -> grabSSH uRaw c >>= B.writeFile f) $+copySSH :: String -> String -> FilePath -> IO ()+copySSH rdarcs uRaw f = withSSHConnection rdarcs uRaw (\c -> grabSSH uRaw c >>= B.writeFile f) $               do let u = escape_dollar uRaw                  stderr_behavior <- sshStdErrMode                  r <- runSSH SCP u [] [u,f] (AsIs,AsIs,stderr_behavior)@@ -136,11 +138,11 @@            where tr '$' = "\\$"                  tr c = [c] -copySSHs :: String -> [String] -> FilePath -> IO ()-copySSHs u ns d =-  withSSHConnection u (\c -> withCurrentDirectory d $-                             mapM_ (\n -> grabSSH (u++"/"++n) c >>= B.writeFile n) $-                             progressList "Copying via ssh" ns) $+copySSHs :: String -> String -> [String] -> FilePath -> IO ()+copySSHs rdarcs u ns d =+  withSSHConnection rdarcs u (\c -> withCurrentDirectory d $+                                mapM_ (\n -> grabSSH (u++"/"++n) c >>= B.writeFile n) $+                                progressList "Copying via ssh" ns) $   do let path = drop 1 $ dropWhile (/= ':') u          host = takeWhile (/= ':') u          cd = "cd "++path++"\n"
− src/ThisVersion.hs
@@ -1,13 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS -cpp #-}--module ThisVersion ( darcs_version ) where--#ifndef PACKAGE_VERSION-#define PACKAGE_VERSION "0"-#define PACKAGE_VERSION_STATE "no version info"-#endif--{-# NOINLINE darcs_version #-}-darcs_version :: String-darcs_version = PACKAGE_VERSION ++ " (" ++ PACKAGE_VERSION_STATE ++ ")"
− src/UTF8.lhs
@@ -1,173 +0,0 @@-Copyright (c) 2002, members of the Haskell Internationalisation Working-Group All rights reserved.--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are met:--* Redistributions of source code must retain the above copyright notice,-   this list of conditions and the following disclaimer.-* Redistributions in binary form must reproduce the above copyright notice,-   this list of conditions and the following disclaimer in the-   documentation and/or other materials provided with the distribution.-* Neither the name of the Haskell Internationalisation Working Group nor-   the names of its contributors may be used to endorse or promote products-   derived from this software without specific prior written permission.--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE-POSSIBILITY OF SUCH DAMAGE.--This module provides lazy stream encoding/decoding facilities for UTF-8,-the Unicode Transformation Format with 8-bit words.--2002-09-02  Sven Moritz Hallberg <pesco@gmx.de>---> {-# OPTIONS_GHC -cpp #-}-> module UTF8->   ( encode ) where---SUNSET: we should remove this module after the 2009-07 release-of darcs and just use Codec.Binary.UTF8.String instead--#ifdef HAVE_UTF8STRING-> import qualified Codec.Binary.UTF8.String (encode)-> import Data.Word (Word8)-#else-> import Data.Char (ord)-> import Data.Word (Word8, Word16, Word32)-> import Data.Bits (Bits, shiftR, (.&.), (.|.))-#endif----///- UTF-8 in General -///--Adapted from the Unicode standard, version 3.2,-Table 3.1 "UTF-8 Bit Distribution" (excluded are UTF-16 encodings):--  Scalar                    1st Byte  2nd Byte  3rd Byte  4th Byte-          000000000xxxxxxx  0xxxxxxx-          00000yyyyyxxxxxx  110yyyyy  10xxxxxx-          zzzzyyyyyyxxxxxx  1110zzzz  10yyyyyy  10xxxxxx-  000uuuzzzzzzyyyyyyxxxxxx  11110uuu  10zzzzzz  10yyyyyy  10xxxxxx--Also from the Unicode standard, version 3.2,-Table 3.1B "Legal UTF-8 Byte Sequences":--  Code Points         1st Byte  2nd Byte  3rd Byte  4th Byte-    U+0000..U+007F    00..7F-    U+0080..U+07FF    C2..DF    80..BF-    U+0800..U+0FFF    E0        A0..BF    80..BF-    U+1000..U+CFFF    E1..EC    80..BF    80..BF-    U+D000..U+D7FF    ED        80..9F    80..BF-    U+D800..U+DFFF    ill-formed-    U+E000..U+FFFF    EE..EF    80..BF    80..BF-   U+10000..U+3FFFF   F0        90..BF    80..BF    80..BF-   U+40000..U+FFFFF   F1..F3    80..BF    80..BF    80..BF-  U+100000..U+10FFFF  F4        80..8F    80..BF    80..BF----///- Encoding Functions -///--Must the encoder ensure that no illegal byte sequences are output or-can we trust the Haskell system to supply only legal values?-For now I include error case for the surrogate values U+D800..U+DFFF and-out-of-range scalars.--The function is pretty much a transscript of table 3.1B with error checks.-It dispatches the actual encoding to functions specific to the number of-required bytes.--#ifndef HAVE_UTF8STRING-> encodeOne :: Char -> [Word8]-> encodeOne c->-- The report guarantees in (6.1.2) that this won't happen:->--   | n < 0       = error "encodeUTF8: ord returned a negative value"->     | n < 0x0080  = encodeOne_onebyte n8->     | n < 0x0800  = encodeOne_twobyte n16->     | n < 0xD800  = encodeOne_threebyte n16->     | n < 0xE000  = error "encodeUTF8: ord returned a surrogate value"->     | n < 0x10000       = encodeOne_threebyte n16->-- Haskell 98 only talks about 16 bit characters, but ghc handles 20.1.->     | n < 0x10FFFF      = encodeOne_fourbyte n32->     | otherwise  = error "encodeUTF8: ord returned a value above 0x10FFFF"->     where->     n = ord c            :: Int->     n8 = fromIntegral n  :: Word8->     n16 = fromIntegral n :: Word16->     n32 = fromIntegral n :: Word32-#endif---With the above, a stream decoder is trivial:---> encode :: [Char] -> [Word8]-#ifdef HAVE_UTF8STRING-> encode = Codec.Binary.UTF8.String.encode-#else-> encode = concatMap encodeOne-#endif---Now follow the individual encoders for certain numbers of bytes...-          _-         / |  __  ___  __ __-        / ^| //  /__/ // //-       /.==| \\ //_  // //-It's  //  || // \_/_//_//_  and it's here to stay!--#ifndef HAVE_UTF8STRING-> encodeOne_onebyte :: Word8 -> [Word8]-> encodeOne_onebyte cp = [cp]-#endif---00000yyyyyxxxxxx -> 110yyyyy 10xxxxxx--#ifndef HAVE_UTF8STRING-> encodeOne_twobyte :: Word16 -> [Word8]-> encodeOne_twobyte cp = [(0xC0.|.ys), (0x80.|.xs)]->     where->     xs, ys :: Word8->     ys = fromIntegral (shiftR cp 6)->     xs = (fromIntegral cp) .&. 0x3F-#endif---zzzzyyyyyyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx--#ifndef HAVE_UTF8STRING-> encodeOne_threebyte :: Word16 -> [Word8]-> encodeOne_threebyte cp = [(0xE0.|.zs), (0x80.|.ys), (0x80.|.xs)]->     where->     xs, ys, zs :: Word8->     xs = (fromIntegral cp) .&. 0x3F->     ys = (fromIntegral (shiftR cp 6)) .&. 0x3F->     zs = fromIntegral (shiftR cp 12)-#endif---000uuuzzzzzzyyyyyyxxxxxx -> 11110uuu 10zzzzzz 10yyyyyy 10xxxxxx--#ifndef HAVE_UTF8STRING-> encodeOne_fourbyte :: Word32 -> [Word8]-> encodeOne_fourbyte cp = [0xF0.|.us, 0x80.|.zs, 0x80.|.ys, 0x80.|.xs]->     where->     xs, ys, zs, us :: Word8->     xs = (fromIntegral cp) .&. 0x3F->     ys = (fromIntegral (shiftR cp 6)) .&. 0x3F->     zs = (fromIntegral (shiftR cp 12)) .&. 0x3F->     us = fromIntegral (shiftR cp 18)-#endif
src/atomic_create.h view
@@ -12,14 +12,6 @@ int renamefile(const char *from, const char *to); #endif -int open_read(const char *fname);-int open_write(const char *fname);-int smart_wait(int pid);--int execvp_no_vtalarm(const char *file, char *const argv[]);--int is_symlink(const char *file);- int stdout_is_a_pipe();  int maybe_relink(const char *src, const char *dst, int careful);
− src/c_compat.c
@@ -1,88 +0,0 @@--#include <sys/types.h>-#include <sys/stat.h>-#include <fcntl.h>-#include <string.h>-#include <stdio.h>-#include <stdlib.h>--#include <unistd.h>-#include <errno.h>-#include <sys/time.h>-#include <time.h>--#ifdef _WIN32-#include <windows.h>-#include <io.h>-#endif--#ifndef _WIN32--int open_read(const char *fname) {-  return open(fname, O_RDONLY);-}--int open_write(const char *fname) {-  return open(fname, O_WRONLY | O_TRUNC | O_CREAT,-              S_IWUSR | S_IRUSR | S_IROTH | S_IRGRP);-}--int get_errno() {-  return errno;-}--#include <sys/wait.h>-#include <signal.h>-#if  HAVE_SIGINFO_H-#include <siginfo.h>-#endif--/* This waits and then returns the exit status of the process that was-   waited for. */-int smart_wait(int pid) {-  int stat;-  pid_t rc;--  do {-      rc = waitpid(pid, &stat, 0);-  } while(rc < 0 && errno == EINTR);--  if(rc < 0) {-    perror("waitpid");-    return -138;-  } else if (WIFEXITED(stat)) {-    return WEXITSTATUS(stat);-  } else if (WIFSIGNALED(stat)) {-    /* Fixme: psignal isn't portable (not in POSIX).  */-    psignal(WTERMSIG(stat), "Error in subprocess");-    return - WTERMSIG(stat);-  } else {-    return -137;-  }-}--#include <unistd.h>-#include <sys/time.h>-#include <errno.h>-#include <stdio.h>--int execvp_no_vtalarm(const char *file, char *const argv[]) {-  /* Reset the itimers in the child, so it doesn't get plagued-   * by SIGVTALRM interrupts.-   */-  struct timeval tv_null = { 0, 0 };-  struct itimerval itv;-  itv.it_interval = tv_null;-  itv.it_value = tv_null;-  setitimer(ITIMER_REAL, &itv, NULL);-  setitimer(ITIMER_VIRTUAL, &itv, NULL);-  setitimer(ITIMER_PROF, &itv, NULL);-  execvp(file, argv);-  perror("Error in execvp");-  return errno;-}--#include <sys/types.h>-#include <sys/stat.h>-#endif-
− src/compat.h
@@ -1,12 +0,0 @@--#include <sys/stat.h>-#include <string.h>-#include <stdlib.h>--int open_read(const char *fname);-int open_write(const char *fname);-int smart_wait(int pid);-int get_errno();--int execvp_no_vtalarm(const char *file, char *const argv[]);-
src/darcs.hs view
@@ -28,10 +28,9 @@  import Darcs.RunCommand ( run_the_command ) import Darcs.Flags ( DarcsFlag(Verbose) )-import Darcs.Commands.Help ( help_cmd, list_available_commands, print_version )-import ThisVersion ( darcs_version )+import Darcs.Commands.Help ( helpCmd, listAvailableCommands, printVersion ) import Darcs.SignalHandler ( withSignalsHandled )-import Context ( context )+import Version ( version, context ) import Darcs.Global ( with_atexit ) import Preproc( preproc_main ) import Exec ( ExecException(..) )@@ -55,14 +54,14 @@   argv <- getArgs   case argv of     -- User called "darcs" without arguments.-    []                  -> print_version >> help_cmd [] []+    []                  -> printVersion >> helpCmd [] []     -- User called "darcs --foo" for some special foo.-    ["-h"]              -> help_cmd [] []-    ["--help"]          -> help_cmd [] []-    ["--overview"]      -> help_cmd [Verbose] []-    ["--commands"]      -> list_available_commands-    ["-v"]              -> putStrLn darcs_version-    ["--version"]       -> putStrLn darcs_version+    ["-h"]              -> helpCmd [] []+    ["--help"]          -> helpCmd [] []+    ["--overview"]      -> helpCmd [Verbose] []+    ["--commands"]      -> listAvailableCommands+    ["-v"]              -> putStrLn version+    ["--version"]       -> putStrLn version     ["--exact-version"] -> do               putStrLn $ "darcs compiled on "++__DATE__++", at "++__TIME__               putStrLn context
+ src/darcs.tex view
@@ -0,0 +1,674 @@+%  Copyright (C) 2002-2003 David Roundy+%+%  This program is free software; you can redistribute it and/or modify+%  it under the terms of the GNU General Public License as published by+%  the Free Software Foundation; either version 2, or (at your option)+%  any later version.+%+%  This program is distributed in the hope that it will be useful,+%  but WITHOUT ANY WARRANTY; without even the implied warranty of+%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+%  GNU General Public License for more details.+%+%  You should have received a copy of the GNU General Public License+%  along with this program; see the file COPYING.  If not, write to+%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+%  Boston, MA 02110-1301, USA.++\documentclass{book}+%\usepackage{color}++\usepackage{verbatim}+\usepackage{html}+\usepackage{fancyvrb}+\newenvironment{code}{\comment}{\endcomment}+% \newenvironment{code}{\color{blue}\verbatim}{\endverbatim}++\begin{document}+++% Definition of title page:+\title{Darcs User Manual}+\date{+\darcsVersion+} % icky newline before closing brace is to appease preproc.hs.+\author{David Roundy}++\maketitle++\tableofcontents++\chapter{Introduction}++%% FIXME: DVCS is no longer distinctive; it is the norm.++Darcs is a revision control system, along the lines of CVS or arch.  That+means that it keeps track of various revisions and branches of your+project, allows for changes to propagate from one branch to another.  Darcs+is intended to be an ``advanced'' revision control system.  Darcs has two+particularly distinctive features which differ from other revision control+systems: 1) each copy of the source is a fully functional branch, and 2)+underlying darcs is a consistent and powerful theory of patches.++%% FIXME: don't talk about CVS and arch as if they are our+%% contemporaries, it makes us sound as dated as they are.  Our key+%% competitors are git, hg, bzr and svn.++\paragraph{Every source tree a branch}+The primary simplifying notion of darcs is that \emph{every} copy of your+source code is a full repository. This is dramatically different from CVS,+in which the normal usage is for there to be one central repository from+which source code will be checked out. It is closer to the notion of arch,+since the `normal' use of arch is for each developer to create his own+repository. However, darcs makes it even easier, since simply checking out+the code is all it takes to create a new repository. This has several+advantages, since you can harness the full power of darcs in any scratch+copy of your code, without committing your possibly destabilizing changes to+a central repository.++%% FIXME: unbound personal pronoun (me).  Use third person, passive voice.++\paragraph{Theory of patches}+The development of a simplified theory of patches is what originally+motivated me to create darcs. This patch formalism means that darcs patches+have a set of properties, which make possible manipulations that couldn't be+done in other revision control systems. First, every patch is invertible.+Secondly, sequential patches (i.e.\ patches that are created in sequence, one+after the other) can be reordered, although this reordering can fail, which+means the second patch is dependent on the first. Thirdly, patches which are+in parallel (i.e.\ both patches were created by modifying identical trees)+can be merged, and the result of a set of merges is independent of the order+in which the merges are performed. This last property is critical to darcs'+philosophy, as it means that a particular version of a source tree is fully+defined by the list of patches that are in it, i.e.\ there is no issue+regarding the order in which merges are performed. For a more thorough+discussion of darcs' theory of patches, see Appendix~\ref{Patch}.++%% FIXME: clarify - the theory is advanced, the UI is simple.++\paragraph{A simple advanced tool}+Besides being ``advanced'' as discussed above, darcs is actually also quite+simple. Versioning tools can be seen as three layers. At the foundation is+the ability to manipulate changes. On top of that must be placed some kind+of database system to keep track of the changes. Finally, at the very top is+some sort of distribution system for getting changes from one place to+another.++Really, only the first of these three layers is of particular interest to+me, so the other two are done as simply as possible.  At the database+layer, darcs just has an ordered list of patches along with the patches+themselves, each stored as an individual file.  Darcs' distribution system+is strongly inspired by that of arch.  Like arch, darcs uses a dumb server,+typically apache or just a local or network file system when pulling+patches.  darcs has built-in support for using \verb!ssh! to write to a remote file+system. A darcs executable is called on the remote system to apply the patches.+Arbitrary other transport protocols are supported, through an environment+variable describing a command that will run darcs on the remote system.+See the documentation for DARCS\_APPLY\_FOO in Chapter~\ref{configuring}+for details.++The recommended method is to send patches through gpg-signed email+messages, which has the advantage of being mostly asynchronous.++\paragraph{Keeping track of changes rather than versions}++In the last paragraph, I explained revision control systems in terms of+three layers.  One can also look at them as having two distinct uses.  One+is to provide a history of previous versions.  The other is to keep track+of changes that are made to the repository, and to allow these changes to+be merged and moved from one repository to another.  These two uses are+distinct, and almost orthogonal, in the sense that a tool can support one+of the two uses optimally while providing no support for the other.  Darcs+is not intended to maintain a history of versions, although it is possible+to kludge together such a revision history, either by making each new patch+depend on all previous patches, or by tagging regularly.  In a sense, this+is what the tag feature is for, but the intention is that tagging will be+used only to mark particularly notable versions (e.g.\ released versions, or+perhaps versions that pass a time consuming test suite).++Other revision control systems are centered upon the job of keeping track+of a history of versions, with the ability to merge changes being added as+it was seen that this would be desirable.  But the fundamental object+remained the versions themselves.++In such a system, a patch (I am using patch here to mean an encapsulated+set of changes) is uniquely determined by two trees.  Merging changes that+are in two trees consists of finding a common parent tree, computing the+diffs of each tree with their parent, and then cleverly combining those two+diffs and applying the combined diff to the parent tree, possibly at some+point in the process allowing human intervention, to allow for fixing up+problems in the merge such as conflicts.++In the world of darcs, the source tree is \emph{not} the fundamental+object, but rather the patch is the fundamental object.  Rather than a+patch being defined in terms of the difference between two trees, a tree is+defined as the result of applying a given set of patches to an empty tree.+Moreover, these patches may be reordered (unless there are dependencies+between the patches involved) without changing the tree.  As a result,+there is no need to find a common parent when performing a merge.  Or, if+you like, their common parent is defined by the set of common patches, and+may not correspond to any version in the version history.++One useful consequence of darcs' patch-oriented philosophy is that since a+patch need not be uniquely defined by a pair of trees (old and new), we can+have several ways of representing the same change, which differ only in how+they commute and what the result of merging them is.  Of course, creating+such a patch will require some sort of user input.  This is a Good Thing,+since the user \emph{creating} the patch should be the one forced to think+about what he really wants to change, rather than the users merging the+patch.  An example of this is the token replace patch (See+Section~\ref{token_replace}).  This feature makes it possible to create a+patch, for example, which changes every instance of the variable+``stupidly\_named\_var'' to ``better\_var\_name'', while leaving+``other\_stupidly\_named\_var'' untouched.  When this patch is merged with+any other patch involving the ``stupidly\_named\_var'', that instance will+also be modified to ``better\_var\_name''.  This is in contrast to a more+conventional merging method which would not only fail to change new+instances of the variable, but would also involve conflicts when merging+with any patch that modifies lines containing the variable.  By more using+additional information about the programmer's intent, darcs is thus able to+make the process of changing a variable name the trivial task that it+really is, which is really just a trivial search and replace, modulo+tokenizing the code appropriately.++The patch formalism discussed in Appendix~\ref{Patch} is what makes darcs'+approach possible.  In order for a tree to consist of a set of patches,+there must be a deterministic merge of any set of patches, regardless of the+order in which they must be merged.  This requires that one be able to+reorder patches.  While I don't know that the patches are required to be+invertible as well, my implementation certainly requires invertibility.  In+particular, invertibility is required to make use of+Theorem~\ref{merge_thm}, which is used extensively in the manipulation of+merges.++\input{features.tex}++\chapter{Getting started}++This chapter will lead you through an example use of darcs, which hopefully+will allow you to get started using darcs with your project.++\section{Creating your repository}++Creating your repository in the first place just involves telling darcs to+create the special directory (called {\tt \_darcs}) in your project tree,+which will hold the revision information.  This is done by simply calling+from the root directory of your project:+\begin{verbatim}+$ cd my_project/+$ darcs initialize+\end{verbatim}+This creates the \verb|_darcs| directory and populates it with whatever+files and directories are needed to describe an empty project.  You now+need to tell darcs what files and directories in your project should be+under revision control.  You do this using the command \verb|darcs add|%+\footnote{Note that darcs does not do wildcard expansion, instead relying+on the command shell.  The Windows port of darcs has a limited form of+expansion provided by the C runtime}:+\begin{verbatim}+$ darcs add *.c Makefile.am configure.ac+\end{verbatim}+When you have added all your files (or at least, think you have), you will+want to record your changes.  ``Recording'' always includes adding a note+as to why the change was made, or what it does.  In this case, we'll just+note that this is the initial version.+\begin{verbatim}+$ darcs record --all+What is the patch name? Initial revision.+\end{verbatim}+Note that since we didn't specify a patch name on the command line we were+prompted for one.  If the environment variable `EMAIL' isn't set, you will+also be prompted for your email address.  Each patch that is recorded is+given a unique identifier consisting of the patch name, its creator's email+address, and the date when it was created.++\section{Making changes}++Now that we have created our repository, make a change to one or more of+your files.  After making the modification run:+\begin{verbatim}+$ darcs whatsnew+\end{verbatim}+This should show you the modifications that you just made, in the darcs+patch format.  If you prefer to see your changes in a different format,+read Section~\ref{whatsnew}, which describes the whatsnew command in+detail.++Let's say you have now made a change to your project.  The next thing to do+is to record a patch.  Recording a patch consists of grouping together a+set of related changes, and giving them a name.  It also tags the patch+with the date it was recorded and your email address.++To record a patch simply type:+\begin{verbatim}+$ darcs record+\end{verbatim}+darcs will then prompt you with all the changes that you have made that+have not yet been recorded, asking you which ones you want to include in+the new patch.  Finally, darcs will ask you for a name for the patch.++You can now rerun whatsnew, and see that indeed the changes you have+recorded are no longer marked as new.++\section{Making your repository visible to others}+How do you let the world know about these wonderful changes?  Obviously,+they must be able to see your repository.  Currently the easiest way to do+this is typically by http using any web server.  The recommended way to do+this (using apache in a UNIX environment) is to create a directory called+{\tt /var/www/repos}, and then put a symlink to your repository there:+\begin{verbatim}+$ cd /var/www/repos+$ ln -s /home/username/myproject .+\end{verbatim}++\section{Getting changes made to another repository}+Ok, so I can now browse your repository using my web browser\ldots\ so+what? How do I get your changes into \emph{my} repository, where they can+do some good? It couldn't be easier.  I just \verb|cd| into my repository,+and there type:+\begin{verbatim}+$ darcs pull http://your.server.org/repos/yourproject+\end{verbatim}+Darcs will check to see if you have recorded any changes that aren't in my+current repository.  If so, it'll prompt me for each one, to see which ones+I want to add to my repository.  Note that you may see a different series+of prompts depending on your answers, since sometimes one patch depends on+another, so if you answer yes to the first one, you won't be prompted for+the second if the first depends on it.++Of course, maybe I don't even have a copy of your repository.  In that case+I'd want to do a+\begin{verbatim}+$ darcs get http://your.server.org/repos/yourproject+\end{verbatim}+which gets the whole repository.++I could instead create an empty repository and fetch all of your patches+with pull.  Get is just a more efficient way to clone a whole repository.++Get, pull and push also work over ssh.  Ssh-paths are of the same form+accepted by scp, namely \verb|[username@]host:/path/to/repository|.++\section{Moving patches from one repository to another}++Darcs is flexible as to how you move patches from one repository to another.+This section will introduce all the ways you can get patches from one place+to another, starting with the simplest and moving to the most complicated.++\subsection{All pulls}++The simplest method is the ``all-pull'' method.  This involves making each+repository readable (by http, ftp, nfs-mounted disk, whatever), and you+run \verb|darcs pull| in the repository you want to move the patch to.  This is nice,+as it doesn't require you to give write access to anyone else, and is+reasonably simple.++\subsection{Send and apply manually}++Sometimes you have a machine on which it is not convenient to set up a web+server, perhaps because it's behind a firewall or perhaps for security+reasons, or because it is often turned off.  In this case you can use+\verb|darcs send|+from that computer to generate a patch bundle destined for another+repository.  You can either let darcs email the patch for you, or save it+as a file and transfer it by hand.  Then in the destination repository you+(or the owner of that repository) run \verb|darcs apply| to apply the patches contained+in the bundle.  This is also quite a simple method since, like the all-pull+method, it doesn't require that you give anyone write access to your+repository.  But it's less convenient, since you have to keep track of the+patch bundle (in the email, or whatever).++If you use the send and apply method with email, you'll probably want to+create a \verb!_darcs/prefs/email! file containing your email address.+This way anyone who sends to your repository will automatically send the+patch bundle to your email address.++If you receive many patches by email, you probably will benefit by running+darcs apply directly from your mail program.  I have in my \verb!.muttrc!+the following:+\begin{verbatim}+auto_view text/x-patch text/x-darcs-patch+macro pager A "<pipe-entry>darcs apply --verbose --mark-conflicts \+        --reply droundy@abridgegame.org --repodir ~/darcs"+\end{verbatim}+which allows me to view a sent patch, and then apply the patch directly from \verb!mutt!, sending a+confirmation email to the person who sent me the patch. The autoview line relies on on the following+lines, or something like them, being present in one's \verb!.mailcap!:+\begin{verbatim}+text/x-patch;                           cat; copiousoutput+text/x-darcs-patch;                     cat; copiousoutput+\end{verbatim}++\subsection{Push}++If you use ssh (and preferably also ssh-agent, so you won't have to keep+retyping your password), you can use the push method to transfer changes+(using the scp protocol for communication).  This method is again not very+complicated, since you presumably already have the ssh permissions set up.+Push can also be used when the target repository is local, in which case+ssh isn't needed.  On the other hand, in this situation you could as easily+run a pull, so there isn't much benefit.++Note that you can use push to administer a multiple-user repository.  You+just need to create a user for the repository (or repositories), and give+everyone with write access ssh access, perhaps using+\verb!.ssh/authorized_keys!.  Then they run+\begin{verbatim}+$ darcs push repouser@repo.server:repo/directory+\end{verbatim}++\subsection{Push ---apply-as}++Now we get more subtle.  If you like the idea in the previous paragraph+about creating a repository user to own a repository which is writable by+a number of users, you have one other option.++Push \verb!--apply-as! can run on either a local repository or one accessed+with ssh, but uses \verb!sudo! to run a darcs apply command (having created+a patch bundle as in send) as another user.  You can add the following line+in your \verb|sudoers| file to allow the users to apply their patches to a+centralized repository:+{\small+\begin{verbatim}+ALL   ALL = (repo-user) NOPASSWD: /usr/bin/darcs apply --all --repodir /repo/path*+\end{verbatim}+}+This method is ideal for a centralized repository when all the users have+accounts on the same computer, if you don't want your users to be able to+run arbitrary commands as repo-user.++\subsection{Sending signed patches by email}++Most of the previous methods are a bit clumsy if you don't want to give+each person with write access to a repository an account on your server.  Darcs+send can be configured to send a cryptographically signed patch by email.+You can then set up your mail system to have darcs verify that patches were+signed by an authorized user and apply them when a patch is received by+email.  The results of the apply can be returned to the user by email.+Unsigned patches (or patches signed by unauthorized users) will be+forwarded to the repository owner (or whoever you configure them to be+forwarded to\ldots).++This method is especially nice when combined with the \verb!--test! option+of darcs apply, since it allows you to run the test suite (assuming you+have one) and reject patches that fail---and it's all done on the server,+so you can happily go on working on your development machine without+slowdown while the server runs the tests.++Setting up darcs to run automatically in response to email is by far the+most complicated way to get patches from one repository to another\ldots\ so it'll+take a few sections to explain how to go about it.++\paragraph{Security considerations}++When you set up darcs to run apply on signed patches, you should assume+that a user with write access can write to any file or directory that is+writable by the user under which the apply process runs.  Unless you+specify the \verb!--no-test! flag to darcs apply (and this is \emph{not}+the default), you are also allowing anyone with write access to that+repository to run arbitrary code on your machine (since they can run a test+suite---which they can modify however they like).  This is quite a+potential security hole.++For these reasons, if you don't implicitly trust your users, it is+recommended that you create a user for each repository to limit the damage+an attacker can do with access to your repository.  When considering who to+trust, keep in mind that a security breach on any developer's machine could+give an attacker access to their private key and passphrase, and thus to+your repository.++\paragraph{Installing necessary programs}++You also must install the following programs: gnupg, a mailer configured to+receive mail (e.g.\ exim, sendmail or postfix), and a web server (usually+apache).++\paragraph{Granting access to a repository}++You create your gpg key by running (as your normal user):+\begin{verbatim}+$ gpg --gen-key+\end{verbatim}+You will be prompted for your name and email address, among other options.+%%To add your public key to the allowed keys keyring.+Of course, you can+skip this step if you already have a gpg key you wish to use.++You now need to export the public key so we can tell the patcher about it.+You can do this with the following command (again as your normal user):+\begin{verbatim}+$ gpg --export "email@address" > /tmp/exported_key+\end{verbatim}+And now we can add your key to the \verb!allowed_keys!:+\begin{verbatim}+(as root)> gpg --keyring /var/lib/darcs/repos/myproject/allowed_keys \+               --no-default-keyring --import /tmp/exported_key+\end{verbatim}+You can repeat this process any number of times to authorize multiple users+to send patches to the repository.++You should now be able to send a patch to the repository by running as your+normal user, in a working copy of the repository:+\begin{verbatim}+$ darcs send --sign http://your.computer/repos/myproject+\end{verbatim}+You may want to add ``send sign'' to the file \verb!_darcs/prefs/defaults!+so that you won't need to type \verb!--sign! every time you want to+send\ldots++If your gpg key is protected by a passphrase, then executing \verb!send!+with the \verb!--sign! option might give you the following error:+\begin{verbatim}+darcs failed:  Error running external program 'gpg'+\end{verbatim}+The most likely cause of this error is that you have a misconfigured+gpg that tries to automatically use a non-existent gpg-agent+program. GnuPG will still work without gpg-agent when you try to sign+or encrypt your data with a passphrase protected key. However, it will+exit with an error code 2 (\verb!ENOENT!) causing \verb!darcs! to+fail. To fix this, you will need to edit your \verb!~/.gnupg/gpg.conf!+file and comment out or remove the line that says:+\begin{verbatim}+use-agent+\end{verbatim}+If after commenting out or removing the \verb!use-agent! line in your+gpg configuration file you still get the same error, then you probably+have a modified GnuPG with use-agent as a hard-coded option. In that+case, you should change \verb!use-agent! to \verb!no-use-agent! to+disable it explicitly.++\paragraph{Setting up a sendable repository using procmail}+If you don't have root access on your machine, or perhaps simply don't want+to bother creating a separate user, you can set up a darcs repository using+procmail to filter your mail.  I will assume that you already use procmail+to filter your email.  If not, you will need to read up on it, or perhaps+should use a different method for routing the email to darcs.++To begin with, you must configure your repository so that a darcs send to+your repository will know where to send the email.  Do this by creating a+file in \verb!/path/to/your/repo/_darcs/prefs! called \verb!email!+containing your email address.  As a trick (to be explained below), we will+create the email address with ``darcs repo'' as your name, in an email+address of the form ``David Roundy $<$droundy@abridgegame.org$>$.''+\begin{verbatim}+$ echo 'my darcs repo <user@host.com>' \+      > /path/to/your/repo/_darcs/prefs/email+\end{verbatim}++The next step is to set up a gnupg keyring containing the public keys of+people authorized to send to your repository.  Here I'll give a second way of+going about this (see above for the first).  This time I'll assume you+want to give me write access to your repository.  You can do this by:+\begin{verbatim}+gpg --no-default-keyring \+    --keyring /path/to/the/allowed_keys --recv-keys D3D5BCEC+\end{verbatim}+This works because ``D3D5BCEC'' is the ID of my gpg key, and I have+uploaded my key to the gpg keyservers.  Actually, this also requires that+you have configured gpg to access a valid keyserver.  You can, of course,+repeat this command for all keys you want to allow access to.++Finally, we add a few lines to your \verb!.procmailrc!:+\begin{verbatim}+:0+* ^TOmy darcs repo+|(umask 022; darcs apply --reply user@host.com \+    --repodir /path/to/your/repo --verify /path/to/the/allowed_keys)+\end{verbatim}+The purpose for the ``my darcs repo'' trick is partially to make it easier+to recognize patches sent to the repository, but is even more crucial to+avoid nasty bounce loops by making the \verb!--reply! option have an email+address that won't go back to the repository.  This means that unsigned+patches that are sent to your repository will be forwarded to your ordinary+email.++Like most mail-processing programs, Procmail by default sets a tight umask.+However, this will prevent the repository from remaining world-readable;+thus, the ``umask 022'' is required to relax the umask.+(Alternatively, you could set Procmail's global \verb!UMASK! variable+to a more suitable value.)++\paragraph{Checking if your e-mail patch was applied}++After sending a patch with \verb!darcs send!, you may not receive any feedback,+even if the patch is applied. You can confirm whether or not your patch was applied+to the remote repository by pointing \verb!darcs changes! at a remote repository:+\begin{verbatim}+darcs changes --last=10 --repo=http://darcs.net/+\end{verbatim}++That shows you the last 10 changes in the remote repository. You can adjust the options given+to \verb!changes! if a more advanced query is needed.++\input{configuring_darcs.tex}++\input{best_practices.tex}++\input{formats.tex}++\chapter{Darcs commands}++\input{Darcs/Commands.lhs}++\section{Options apart from darcs commands}+\begin{options}+--help+\end{options}+Calling darcs with just \verb|--help| as an argument gives a brief+summary of what commands are available.+\begin{options}+--version, --exact-version+\end{options}+Calling darcs with the flag \verb|--version| tells you the version of+darcs you are using.  Calling darcs with the flag \verb|--exact-version|+gives the precise version of darcs, even if that version doesn't correspond+to a released version number.  This is helpful with bug reports, especially+when running with a ``latest'' version of darcs.+\begin{options}+--commands+\end{options}+Similarly calling darcs with only \verb|--commands| gives a simple list+of available commands.  This latter arrangement is primarily intended for+the use of command-line autocompletion facilities, as are available in+bash.++\section{Getting help}++\input{Darcs/Commands/Help.lhs}++\section{Creating repositories}++\input{Darcs/Commands/Init.lhs}++\input{Darcs/Commands/Get.lhs}++\input{Darcs/Commands/Put.lhs}++\section{Modifying the contents of a repository}++\input{Darcs/Commands/Add.lhs}++\input{Darcs/Commands/Remove.lhs}++\input{Darcs/Commands/Move.lhs}++\input{Darcs/Commands/Replace.lhs}++\section{Working with changes}++\input{Darcs/Commands/Record.lhs}++\input{Darcs/Commands/Pull.lhs}++\input{Darcs/Commands/Push.lhs}++\input{Darcs/Commands/Send.lhs}++\input{Darcs/Commands/Apply.lhs}++\section{Seeing what you've done}++\input{Darcs/Commands/WhatsNew.lhs}++\input{Darcs/Commands/Changes.lhs}++\input{Darcs/Commands/Show.lhs}++\section{More advanced commands}++\input{Darcs/Commands/Tag.lhs}++\input{Darcs/Commands/SetPref.lhs}++\input{Darcs/Commands/Check.lhs}++\input{Darcs/Commands/Optimize.lhs}++\section{Undoing, redoing and running in circles}++\input{Darcs/Commands/AmendRecord.lhs}++\input{Darcs/Commands/Rollback.lhs}++\input{Darcs/Commands/Unrecord.lhs}++\input{Darcs/Commands/Revert.lhs}++\input{Darcs/Commands/Unrevert.lhs}++\section{Advanced examination of the repository}++\input{Darcs/Commands/Diff.lhs}++\input{Darcs/Commands/Annotate.lhs}++% Includes the show commands.+\input{Darcs/Commands/Show.lhs}++\section{Rarely needed and obscure commands}++\input{Darcs/Commands/Convert.lhs}++\input{Darcs/Commands/MarkConflicts.lhs}++\input{Darcs/Commands/Dist.lhs}++\input{Darcs/Commands/TrackDown.lhs}++\input{Darcs/Commands/Repair.lhs}++\appendix++\input{switching.tex}++\input{building_darcs.tex}++\input{Darcs/Patch.lhs}++\input{Darcs/Repository/DarcsRepo.lhs}++\input{gpl.tex}++\end{document}++
+ src/formats.tex view
@@ -0,0 +1,69 @@+\chapter{Repository Formats}++Darcs 2 supports three repository formats:++\begin{itemize}+\item The current format, called `darcs-2'.  It has the most features.+\item The original format, called `darcs-1' or `old-fashioned inventory'.+  It is the only format supported by Darcs releases prior to 2.0.+  Patches cannot be shared between darcs-2 and darcs-1 repositories.+\item An intermediary format, called `hashed'.  It provides some of+  the features of darcs-2, while retaining the ability to exchange+  patches with darcs-1.  Patches cannot be shared between darcs-2 and+  hashed repositories.+\end{itemize}++Note that references to the hashed format refer to hashed darcs-1+repositories.  All darcs-2 repositories are also hashed, and `darcs+show repo' in a darcs-2 repository will report the format as `hashed,+darcs-2'.++The hashed (and darcs-2) format improves on the darcs-1 format in the+following ways:++\begin{itemize}+\item Improved atomicity of operations.  This improves the safety and+  efficiency of those operations.+\item File names in the `pristine' copy of the working tree are+  hashed.  This greatly reduces the chance of a program accidentally+  treating files in \_darcs/pristine as part of the working tree.++  For example, in darcs-1 running \verb|find -name "*.gif" -delete|+  instead of \verb|find -name _darcs -prune -o -name "*.gif" -delete|+  would result in GIF files in pristine files being deleted.++\item Support for `lazy' repositories.  This causes patches to be+  copied from the parent repository on demand, rather than during the+  initial `darcs get'.  For repositories that only operate on recent+  patches (such as feature branches), this reduces the repository's+  size, and the time and bandwidth taken to create it.++  Lazy repositories are first-class repositories, and all operations+  are supported as long as the parent repository remains accessible.+  This isn't the case for the `partial' feature of the darcs-1 format.++\item Support for caches that are shared by all repositories.  When+  operating on many similar repositories, the patches and pristine+  files they have in common are hard links to the cache.  This greatly+  reduces storage requirements, and the time and bandwidth needed to+  make similar repositories.+\end{itemize}++The darcs-2 format improves on the hashed format in the following+ways:++\begin{itemize}+\item The `exponential merge' problem is \emph{far} less likely to+  occur (it can still be produced in deliberately pathological cases).+\item Identical primitive changes no longer conflict.  For example, if+  two patches both attempt to add a directory `tests', these patches+  will not conflict.+\end{itemize}++% The following reference is particularly important because init+% explains *when* to use each format, which I don't want to+% copy-and-paste here because then the two copies will get out of+% sync.++See also `darcs initialize' (\ref{initialize}), `darcs convert'+(\ref{convert}) and `darcs get' (\ref{get}).
src/fpstring.c view
@@ -26,132 +26,12 @@ #include <sys/mman.h> #endif -/* A locale-independent isspace(3) so patches are interpreted the same- * everywhere. */-// #define ISSPACE(c) \-//     ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')--// int first_white(const char *s, int len)-// {-//     const char *start;-//     const char *end;-// -//     for (start = s, end = s + len; s < end && !ISSPACE(*s); s++);-// -//     return s - start;-// }--// int first_nonwhite(const char *s, int len)-// {-//     const char *start;-//     const char *end;-// -//     for (start = s, end = s + len; s < end && ISSPACE(*s); s++);-// -//     return s - start;-// }- int has_funky_char(const char *s, int len) {   // We check first for the more likely \0 so we can break out of   // memchr that much sooner.   return !!(memchr(s, 0, len) || memchr(s, 26, len)); -}--// ForeignPtr debugging stuff...--static int num_alloced = 0;--void debug_free(void *p) {-  num_alloced--;-  fprintf(stderr, "Freeing %p (%d left)\n", p, num_alloced);-}--void debug_alloc(void *p, const char *name) {-  num_alloced++;-  fprintf(stderr, "Allocating %p named %s (%d left)\n",-          p, name, num_alloced);-}--/* Specification: RFC 2279 */--int utf8_to_ints(HsInt *pwc, const unsigned char *s, int n) {-  /* returns number of unicode chars in the output.  The output array is-     assumed to have the same number of elements as the input array, which-     is n. */--  HsInt *pwc_original = pwc;-  while (n > 0) {-    unsigned char c = s[0];--    if (c < 0x80) {-      *pwc++ = c;-      n--;-      s++;-    } else if (c < 0xc2) {-      return -1;-    } else if (c < 0xe0) {-      if (n < 2) return -1;-      if (!((s[1] ^ 0x80) < 0x40)) return -1;-      *pwc++ = ((unsigned) (c & 0x1f) << 6)-        | (unsigned) (s[1] ^ 0x80);-      n -= 2;-      s += 2;-    } else if (c < 0xf0) {-      if (n < 3) return -1;-      if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40-            && (c >= 0xe1 || s[1] >= 0xa0)))-        return -1;-      *pwc++ = ((unsigned) (c & 0x0f) << 12)-        | ((unsigned) (s[1] ^ 0x80) << 6)-        | (unsigned) (s[2] ^ 0x80);-      n -= 3;-      s += 3;-    } else if (c < 0xf8 && sizeof(unsigned)*8 >= 32) {-      if (n < 4) return -1;-      if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40-            && (s[3] ^ 0x80) < 0x40-            && (c >= 0xf1 || s[1] >= 0x90)))-        return -1;-      *pwc++ = ((unsigned) (c & 0x07) << 18)-        | ((unsigned) (s[1] ^ 0x80) << 12)-        | ((unsigned) (s[2] ^ 0x80) << 6)-        | (unsigned) (s[3] ^ 0x80);-      n -= 4;-      s += 4;-    } else if (c < 0xfc && sizeof(unsigned)*8 >= 32) {-      if (n < 5) return -1;-      if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40-            && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40-            && (c >= 0xf9 || s[1] >= 0x88)))-        return -1;-      *pwc++ = ((unsigned) (c & 0x03) << 24)-        | ((unsigned) (s[1] ^ 0x80) << 18)-        | ((unsigned) (s[2] ^ 0x80) << 12)-        | ((unsigned) (s[3] ^ 0x80) << 6)-        | (unsigned) (s[4] ^ 0x80);-      n -= 5;-      s += 5;-    } else if (c < 0xfe && sizeof(unsigned)*8 >= 32) {-      if (n < 6) return -1;-      if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40-            && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40-            && (s[5] ^ 0x80) < 0x40-            && (c >= 0xfd || s[1] >= 0x84)))-        return -1;-      *pwc++ = ((unsigned) (c & 0x01) << 30)-        | ((unsigned) (s[1] ^ 0x80) << 24)-        | ((unsigned) (s[2] ^ 0x80) << 18)-        | ((unsigned) (s[3] ^ 0x80) << 12)-        | ((unsigned) (s[4] ^ 0x80) << 6)-        | (unsigned) (s[5] ^ 0x80);-      n -= 6;-      s += 6;-    } else-      return -1;-  }-  return pwc - pwc_original; }  /* Conversion to and from hex */
src/fpstring.h view
@@ -1,15 +1,7 @@ #include <HsFFI.h> #include <sys/types.h> -int wfindps_helper(char c, const char *s, int len);-void debug_free(void *p);-void debug_alloc(void *p, const char *name);--// int first_white(const char *s, int len);-// int first_nonwhite(const char *s, int len); int has_funky_char(const char *s, int len);--int utf8_to_ints(HsInt *pwc, const unsigned char *s, int n);  void conv_to_hex(unsigned char *dest, unsigned char *from, int num_chars); void conv_from_hex(unsigned char *dest, unsigned char *from, int num_chars);
src/unit.lhs view
@@ -48,23 +48,24 @@  import System.IO.Unsafe ( unsafePerformIO ) import ByteStringUtils hiding ( intercalate )+import Codec.Binary.UTF8.Generic ( toString ) import qualified Data.ByteString.Char8 as BC ( unpack, pack )-import qualified Data.ByteString as B ( empty, concat, length, unpack, foldr,-                                        cons, ByteString, null, filter, head )-import Data.Char ( isPrint )+import qualified Data.ByteString as B ( concat, empty ) import Darcs.Patch-import Darcs.Patch.Test-import Darcs.Patch.Unit ( patch_unit_tests )+import Darcs.Test.Patch.Test+import Darcs.Test.Patch.Unit ( patch_unit_tests )+import Darcs.Test.Email ( email_parsing, email_header_no_long_lines,+                          email_header_ascii_chars, email_header_lines_start,+                          email_header_no_empty_lines ) import Lcs ( shiftBoundaries ) import Test.QuickCheck-import Printer ( renderPS, text )+import Printer ( renderPS ) import Darcs.Patch.Commute import Data.Array.Base import Data.Array.Unboxed import Control.Monad.ST-import Darcs.Ordered-import Darcs.Sealed ( Sealed(Sealed), unsafeUnseal )-import Darcs.Email ( make_email, read_email, formatHeader )+import Darcs.Witnesses.Ordered+import Darcs.Witnesses.Sealed ( Sealed(Sealed), unsafeUnseal ) import Test.HUnit ( assertBool, assertFailure ) import Test.Framework.Providers.QuickCheck2 ( testProperty ) import Test.Framework.Providers.HUnit ( testCase )@@ -99,27 +100,22 @@ tests :: [Test] tests = patch_unit_tests ++         [testBool "Checking that UTF-8 packing and unpacking preserves 'hello world'"-                  (unpackPSfromUTF8 (BC.pack "hello world") == "hello world"),+                  (toString (BC.pack "hello world") == "hello world"),          testBool "Checking that hex packing and unpacking preserves 'hello world'"                   (BC.unpack (fromHex2PS $ fromPS2Hex $ BC.pack "hello world")                        == "hello world"),-         testProperty "Checking that email can be parsed"-          (\s ->-            unlines ("":s++["", ""]) ==-              BC.unpack (read_email (renderPS-                    $ make_email "reponame" [] (Just (text "contents\n"))-                                 (text $ unlines s) (Just "filename")))),-         testProperty "Checking email header line length" email_header_no_long_lines,-         testProperty "Checking email for illegal characters" email_header_ascii_chars,-         testProperty "Checking for spaces at start of folded email header lines" email_header_lines_start,-         testProperty "Checking that there are no empty lines in email headers" email_header_no_empty_lines,+         email_parsing,+         email_header_no_long_lines,+         email_header_ascii_chars,+         email_header_lines_start,+         email_header_no_empty_lines,          testProperty "Checking that B.concat works" prop_concatPS,          testProperty "Checking that hex conversion works" prop_hex_conversion,          testProperty "Checking that show and read work right" prop_read_show,          testStringList "Checking known commutes" commute_tests,          testStringList "Checking known merges" merge_tests,          testStringList "Checking known canons" canonization_tests]-        ++ check_subcommutes subcommutes_inverse "patch and inverse both commutex"+        ++ check_subcommutes subcommutes_inverse "patch and inverse both commute"         ++ check_subcommutes subcommutes_nontrivial_inverse "nontrivial commutes are correct"         ++ check_subcommutes subcommutes_failure "inverses fail"         ++@@ -147,18 +143,18 @@          --runQuickCheckTest returnval prop_unravel_seq_merge          testProperty "Checking inverse of inverse" prop_inverse_composition,          testProperty "Checking the order of commutes" prop_commute_either_order,-         testProperty "Checking commutex either way" prop_commute_either_way,-         testProperty "Checking the double commutex" prop_commute_twice,-         testProperty "Checking that merges commutex and are well behaved" prop_merge_is_commutable_and_correct,+         testProperty "Checking commute either way" prop_commute_either_way,+         testProperty "Checking the double commute" prop_commute_twice,+         testProperty "Checking that merges commute and are well behaved" prop_merge_is_commutable_and_correct,          testProperty "Checking that merges can be swapped" prop_merge_is_swapable,          testProperty "Checking again that merges can be swapped (I'm paranoid) " prop_merge_is_swapable,          testStringList "Checking that the patch validation works" test_check,-         testStringList "Checking commutex/recommute" commute_recommute_tests,+         testStringList "Checking commute/recommute" commute_recommute_tests,          testStringList "Checking merge properties" generic_merge_tests,          testStringList "Testing the lcs code" show_lcs_tests,          testStringList "Checking primitive patch IO functions" primitive_show_read_tests,          testStringList "Checking IO functions" show_read_tests,-         testStringList "Checking primitive commutex/recommute" primitive_commute_recommute_tests+         testStringList "Checking primitive commute/recommute" primitive_commute_recommute_tests         ] \end{code} @@ -183,54 +179,6 @@     = (thetest p1 p2)++(pair_unit_tester thetest ps) \end{code} -\chapter{Email format tests}--These tests check whether the emails generated by darcs meet a few criteria.-We check for line length and non-ASCII characters. We apparently do not have to-check for CR-LF newlines because that's handled by sendmail.--\begin{code}---- Check that formatHeader never creates lines longer  than 78 characters--- (excluding the carriage return and line feed)-email_header_no_long_lines :: String -> String -> Bool-email_header_no_long_lines field value =-    not $ any (>78) $ map B.length $ bs_lines $ formatHeader cleanField value-  where cleanField = clean_field_string field--bs_lines :: B.ByteString -> [B.ByteString]-bs_lines = finalizeFold . B.foldr splitAtLines (B.empty, [])-  where splitAtLines 10 (thisLine, prevLines) = (B.empty, thisLine:prevLines)-        splitAtLines c  (thisLine, prevLines) = (B.cons c thisLine, prevLines)-        finalizeFold (lastLine, otherLines) = lastLine : otherLines---- Check that an email header does not contain non-ASCII characters--- formatHeader doesn't escape field names, there is no such thing as non-ascii--- field names afaik-email_header_ascii_chars :: String -> String -> Bool-email_header_ascii_chars field value-    = not (any (>127) (B.unpack (formatHeader cleanField value)))-  where cleanField = clean_field_string field---- Check that header the second and later lines of a header start with a space-email_header_lines_start :: String -> String -> Bool-email_header_lines_start field value =-    all (\l -> B.null l || B.head l == 32) (tail headerLines)-  where headerLines = bs_lines (formatHeader cleanField value)-        cleanField  = clean_field_string field---- Checks that there are no lines in email headers with only whitespace-email_header_no_empty_lines :: String -> String -> Bool-email_header_no_empty_lines field value =-    all (not . B.null . B.filter (not . (`elem` [10, 32, 9]))) headerLines-  where headerLines = bs_lines (formatHeader cleanField value)-        cleanField  = clean_field_string field--clean_field_string :: String -> String-clean_field_string = filter (\c -> isPrint c && c < '\x80' && c /= ':')--\end{code}- \chapter{LCS}  Here are a few quick tests of the shiftBoundaries function.@@ -307,10 +255,10 @@ canonization_tests = concatMap check_known_canon known_canons check_known_canon :: (Patch, Patch) -> [String] check_known_canon (p1,p2) =-    if (fromPrims $ concatFL $ mapFL_FL canonize $ sort_coalesceFL $ effect p1) == p2+    if (fromPrims $ concatFL $ mapFL_FL canonize $ sortCoalesceFL $ effect p1) == p2     then []     else ["Canonization failed:\n"++show p1++"canonized is\n"-          ++show (fromPrims $ concatFL $ mapFL_FL canonize $ sort_coalesceFL $ effect p1 :: Patch)+          ++show (fromPrims $ concatFL $ mapFL_FL canonize $ sortCoalesceFL $ effect p1 :: Patch)           ++"which is not\n"++show p2] known_canons :: [(Patch,Patch)] known_canons =@@ -383,7 +331,7 @@ Here we test to see if commuting patch A and patch B and then commuting the result gives us patch A and patch B again.  The set of patches (A,B) is chosen from the set of all pairs of test patches by selecting those which-commutex with one another.+commute with one another.  \begin{code} commute_recommute_tests :: [String]@@ -391,7 +339,7 @@   case take 200 [(p2:<p1)|                  p1<-test_patches,                  p2<-filter (\p->checkseq [p1,p]) test_patches,-                 commutex (p2:<p1) /= Nothing] of+                 commute (p1:>p2) /= Nothing] of   commute_pairs -> pair_unit_tester t_commute_recommute commute_pairs   where checkseq ps = check_a_patch $ join_patches ps primitive_commute_recommute_tests :: [String]@@ -400,15 +348,15 @@     [(p1:<p2)|      p1<-primitive_test_patches,      p2<-primitive_test_patches,-     commutex (p1:<p2) /= Nothing,+     commute (p2:>p1) /= Nothing,      check_a_patch $ join_patches [p2,p1]] t_commute_recommute   :: TwoPatchUnitTest t_commute_recommute p1 p2 =-    if (commutex (p1:<p2) >>= commutex) == Just (p1:<p2)+    if (commute (p2:>p1) >>= commute) == Just (p2:>p1)        then []-       else ["Failed to recommute:\n"++(show p1)++(show p2)++-            "we saw it as:\n"++show (commutex (p1:<p2))++-             "\nAnd recommute was:\n"++show (commutex (p1:<p2) >>= commutex)+       else ["Failed to recommute:\n"++(show p2)++(show p1)+++            "we saw it as:\n"++show (commute (p2:>p1))+++             "\nAnd recommute was:\n"++show (commute (p2:>p1) >>= commute)              ++ "\n"] \end{code} @@ -422,8 +370,8 @@     concatMap check_cant_commute known_cant_commute check_known_commute :: (Patch:< Patch, Patch:< Patch) -> [String] check_known_commute (p1:<p2,p2':<p1') =-   case commutex (p1:<p2) of-   Just (p2a:<p1a) ->+   case commute (p2:>p1) of+   Just (p1a:>p2a) ->        if (p2a:< p1a) == (p2':< p1')        then []        else ["Commute gave wrong value!\n"++show p1++"\n"++show p2@@ -431,8 +379,8 @@              ++"but is\n"++show p2a++"\n"++show p1a]    Nothing -> ["Commute failed!\n"++show p1++"\n"++show p2]    ++-   case commutex (p2':<p1') of-   Just (p1a:<p2a) ->+   case commute (p1':>p2') of+   Just (p2a:>p1a) ->        if (p1a:< p2a) == (p1:< p2)        then []        else ["Commute gave wrong value!\n"++show p2a++"\n"++show p1a@@ -491,10 +439,10 @@  check_cant_commute :: (Patch:< Patch) -> [String] check_cant_commute (p1:<p2) =-    case commutex (p1:<p2) of+    case commute (p2:>p1) of     Nothing -> []     _ -> [show p1 ++ "\n\n" ++ show p2 ++-          "\nArgh, these guys shouldn't commutex!\n"]+          "\nArgh, these guys shouldn't commute!\n"] known_cant_commute :: [(Patch:< Patch)] known_cant_commute = [                       (testhunk 2 ["o"] ["n"]:<@@ -644,8 +592,8 @@     _ :/\: p2' ->         case merge (p1:\/:p2) of         _ :/\: p1' ->-            case commutex (p2':<p1) of-            Just (p1'b:<_) ->+            case commute (p1:>p2') of+            Just (_:>p1'b) ->                 if p1'b /= p1'                 then ["Merge swapping problem with...\np1 "++                       show p1++"merged with\np2 "++@@ -657,7 +605,7 @@             Nothing -> ["Merge commuting problem with...\np1 "++                         show p1++"merged with\np2 "++                         show p2++"gives\np2' "++-                        show p2'++"which doesn't commutex with p1.\n"+                        show p2'++"which doesn't commute with p1.\n"                        ] \end{code} @@ -731,15 +679,15 @@     take 50 [join_patches [p1,p2]|              p1<-primitive_test_patches,              p2<-filter (\p->checkseq [p1,p]) primitive_test_patches,-             commutex (p2:<p1) == Nothing]+             commute (p1:>p2) == Nothing]     where checkseq ps = check_a_patch $ join_patches ps  test_patches_composite =     take 100 [join_patches [p1,p2]|               p1<-primitive_test_patches,               p2<-filter (\p->checkseq [p1,p]) primitive_test_patches,-              commutex (p2:<p1) /= Nothing,-              commutex (p2:<p1) /= Just (p1:<p2)]+              commute (p1:>p2) /= Nothing,+              commute (p1:>p2) /= Just (p2:>p1)]     where checkseq ps = check_a_patch $ join_patches ps  test_patches_two_composite_hunks =@@ -773,7 +721,7 @@          ++take 10 test_patches_two_composite_hunks          ++take 2 test_patches_composite_four_hunks,      check_a_patch $ join_patches [invert p1, p2],-     commutex (p1:<p2) /= Just (p2:<p1)+     commute (p2:>p1) /= Just (p1:>p2)     ]  test_patches =  primitive_test_patches ++
src/win32/System/Posix.hs view
@@ -3,35 +3,31 @@  module System.Posix where -import Foreign.Ptr ( Ptr, castPtr, plusPtr )-import Foreign.Storable ( peek, poke, sizeOf )+import Foreign.Ptr ( Ptr )+import Foreign.Storable ( peek ) import Foreign.C.Types ( CInt, CUInt, CULong, CTime ) import Foreign.C.String ( CString, withCString )-import Foreign.Marshal.Alloc ( allocaBytes )+import Foreign.Marshal.Array ( withArray )+import Foreign.Marshal.Alloc ( alloca )  import System.Posix.Types ( EpochTime ) import System.IO ( Handle ) --foreign import ccall "sys/utime.h _utime" c_utime :: CString -> Ptr a -> IO CInt+foreign import ccall "sys/utime.h _utime" c_utime :: CString -> Ptr CTime -> IO CInt  setFileTimes :: FilePath -> EpochTime -> EpochTime -> IO () setFileTimes path atime mtime = path `withCString` \s -> do-  allocaBytes 8 $ \p -> do-    poke (castPtr p :: Ptr CTime) (atime)-    poke (castPtr (plusPtr p 4) :: Ptr CTime) (mtime)-    c_utime s p-    return ()+  withArray [atime,mtime] $ \p -> do c_utime s p+                                     return ()   foreign import ccall "time" c_ctime :: Ptr CTime -> IO CInt  epochTime :: IO EpochTime epochTime = do-    allocaBytes (sizeOf (undefined :: CTime)) $ \p -> do-      c_ctime p-      t <- peek p :: IO CTime-      return t+  alloca $ \p -> do c_ctime p+                    t <- peek p :: IO CTime+                    return t  foreign import stdcall "winbase.h SleepEx" c_SleepEx :: CULong -> CUInt -> IO CInt 
src/witnesses.hs view
@@ -1,3 +1,6 @@+import Version+-- import Preproc -- imports Darcs.Commands.Help+-- import Darcs.ArgumentDefaults -- imports Darcs.Commands.Help import Darcs.Patch.Real import Darcs.Patch.Properties import Darcs.Patch.Bundle@@ -6,16 +9,46 @@ import Darcs.Patch.Match import Darcs.Repository.HashedRepo import Darcs.Resolution-import Darcs.Patch.Check+import Darcs.Test.Patch.Check import Darcs.Repository.Pristine import Darcs.Repository.DarcsRepo import Darcs.Repository.Internal-import Darcs.Commands.Unrevert-import Darcs.Commands.WhatsNew-import Darcs.Commands.Show-import Darcs.Commands.Unrecord+-- import Darcs.Commands.Add+import Darcs.Commands.Annotate+-- import Darcs.Commands.AmendRecord -- depends on Darcs.Commands.Record+import Darcs.Commands.Apply+-- import Darcs.Commands.Changes -- does lots of nasty filtering of patch lists+-- import Darcs.Commands.Check+-- import Darcs.Commands.Convert+import Darcs.Commands.Diff import Darcs.Commands.Dist-import Darcs.Commands.TransferMode+-- import Darcs.Commands.Get import Darcs.Commands.GZCRCs+-- import Darcs.Commands.Help -- depends on Darcs.TheCommands+import Darcs.Commands.Init+-- import Darcs.Commands.MarkConflicts+-- import Darcs.Commands.Move+-- import Darcs.Commands.Optimize+import Darcs.Commands.Pull+import Darcs.Commands.Push+-- import Darcs.Commands.Put+-- import Darcs.Commands.Record+-- import Darcs.Commands.Remove -- depends on Darcs.Commands.Add+-- import Darcs.Commands.Repair+-- import Darcs.Commands.Replace+-- import Darcs.Commands.Revert+-- import Darcs.Commands.Rollback -- depends on Darcs.Commands.Rollback+import Darcs.Commands.Send+import Darcs.Commands.SetPref+import Darcs.Commands.Show+-- import Darcs.Commands.Tag -- depends on Darcs.Commands.Tag+import Darcs.Commands.TrackDown+import Darcs.Commands.TransferMode+import Darcs.Commands.Unrevert+import Darcs.Commands.Unrecord+import Darcs.Commands.WhatsNew++-- import Darcs.RunCommand -- imports Darcs.Commands.Help+-- import Darcs.TheCommands -- pulls in all other commands  main = return ()
tests/EXAMPLE.sh view
@@ -28,11 +28,16 @@ rm -rf R S                      # Another script may have left a mess. darcs init      --repo R        # Create our test repos. darcs init      --repo S-mkdir R/d/ R/e/                 # Change the working tree.-echo 'Example content.' >R/d/f-darcs record    --repo R -lam 'Add d/f and e.'-darcs mv        --repo R d/f e/-darcs record    --repo R -am 'Move d/f to e/f.'-darcs push      --repo R S -a   # Try to push patches between repos.-darcs push      --repo S R-rm -rf R/ S/                    # Clean up after ourselves.++cd R+mkdir d e                       # Change the working tree.+echo 'Example content.' > d/f+darcs record -lam 'Add d/f and e.'+darcs mv d/f e/+darcs record -am 'Move d/f to e/f.'+darcs push ../S -a	        # Try to push patches between repos.+cd ..++cd S+darcs push ../R -a+cd ..
tests/check.sh view
@@ -27,9 +27,16 @@ . lib                           # Load some portability helpers. rm -rf R                        # Another script may have left a mess. darcs init      --repo R-darcs setpref   --repo R test true-darcs record    --repo R -am 'true test'+darcs setpref   --repo R test 'grep hello f'+not darcs record    --repo R -am 'true test'+darcs record    --repo R -am 'true test' --no-test+ touch R/f-darcs record    --repo R -lam 'added foo'-darcs check     --repo R --test+darcs record    --repo R -lam 'added foo' --no-test+darcs tag       --repo R -m 'got f?'++echo hello > R/f+darcs record    --repo R -lam 'hellofoo'+darcs chec      --repo R --test+ rm -rf R                        # Clean up after ourselves.
tests/checkpoint.sh view
@@ -2,6 +2,9 @@  # A test for unrecording checkpoint tags, inspired by issue517 +exit 200 # checkpoint creation is not supported by current darcs+         # we would need a testdata tarball for this test+ set -ev  darcs --version
tests/diff.sh view
@@ -10,8 +10,8 @@ darcs add afile.txt darcs record --author me --all --no-test --patch-name init darcs diff-darcs diff -p . --store > diffinmem-darcs diff -p . > diffondisk+darcs diff -p . --store-in-mem > diffinmem+darcs diff -p . --no-store-in-mem > diffondisk diff diffinmem diffondisk cd .. 
+ tests/dist-v.sh view
@@ -0,0 +1,18 @@+#!/usr/bin/env bash+set -ev++# tests for "darcs dist"++not () { "$@" && exit 1 || :; }++rm -rf temp1+mkdir temp1+cd temp1+darcs init+# needs fixed on FreeBSD+darcs dist -v 2> log+not grep error log+cd ..++rm -rf temp1+
+ tests/emailformat.sh view
@@ -0,0 +1,43 @@+#!/usr/bin/env bash++. ../tests/lib++set -ev+switch_to_latin9_locale+rm -rf temp1+rm -rf temp2+mkdir temp1+mkdir temp2+cd temp1++seventysevenaddy="<aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@bbbbbbbbbb.cccccccccc.abrasoft.com>"++darcs init++echo "Have you seen the smørrebrød of René Çavésant?" > non_ascii_file+darcs add non_ascii_file+darcs record -am "non-ascii file add" -A test++cd ../temp2+darcs init+cd ../temp1++# long email adress: check that email adresses of <= 77 chars don't get split up+darcs send --from="Kjålt Überström $seventysevenaddy" \+           --subject "Un patch pour le répositoire" \+           --to="Un garçon français <garcon@francais.fr>" \+           --sendmail-command='tee mail_as_file %<' \+           -a ../temp2++cat mail_as_file+# The long mail address should be in there as a whole+grep $seventysevenaddy mail_as_file++# Check that there are no non-ASCII characters in the mail+ghc -e 'getContents >>= return . not . any (> Data.Char.chr 127)' < mail_as_file | grep '^True$'+++cd ..+rm -rf temp1+rm -rf temp2+
+ tests/external-resolution.sh view
@@ -0,0 +1,31 @@+#!/usr/bin/env bash+. lib++rm -rf temp1 temp2++mkdir temp1+cd temp1+darcs init+echo "Conflict, Base ." > child_of_conflict+darcs add child_of_conflict+darcs record -am 'Conflict Base'+cd ..+darcs get temp1 temp2++# Add and record differing lines to both repos+cd temp1+echo "Conflict, Part 1." > child_of_conflict+darcs record -A author -am 'Conflict Part 1'+cd ..+cd temp2+echo "Conflict, Part 2." > child_of_conflict+darcs record -A author -am 'Conflict Part 2'+cd ..++cd temp1+echo | darcs pull -a ../temp2 --external-merge 'cp %2 %o'+cd ..++diff -u temp1/child_of_conflict temp2/child_of_conflict++rm -rf temp1 temp2
+ tests/failed-amend-should-not-break-repo.sh view
@@ -0,0 +1,58 @@+#!/usr/bin/env bash+## Test for keeping the repository in consitent state in case+## of a test failure on amend-record. The bug was almost introduced+## when trying to fix issue 1406.+##+## Copyright (C) 2009 Kamil Dworakowski+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib+set -ev+rm -rf R+mkdir R+cd R+darcs init+# first patch: new file A+touch A+darcs add A+darcs record -a -m 'A'+# second patch: mv A to B+darcs mv A B+echo y | darcs record -a -m 'move'+# third patch: modify B+echo "content" > B+echo y | darcs record -a -m 'add content'++# amending 'move' results in commuting 'move' patch+# to the end for removal. The commute changes the "add content"+# patch to modify A instead of B. But the amend is interrupted+# because of test failure. Check the consitency after the operation.+darcs setpref test false+echo yy | not darcs amend -p move+darcs check++# Note: Amend-record in case of test failure is broken as described in issue1406,+# though when trying to fix it I almost managed to break darcs even more.+# This test is to guard against such regressions in the future.++cd ..+rm -rf R
+ tests/failing-add_permissions.sh view
@@ -0,0 +1,36 @@+#!/usr/bin/env bash+## Darcs should refuse to add an unreadable file, because unreadable+## files aren't recordable.+##+## Copyright (C) 2005  Mark Stosberg+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib++abort_windows                   # does not work on Windows.+rm -rf temp1                    # Another script may have left a mess.+darcs initialize --repodir temp1+touch temp1/unreadable+chmod a-r temp1/unreadable      # Make the file unreadable.+not darcs add --repodir temp1 no_perms.txt 2>temp1/log+fgrep -i 'permission denied' temp1/log+rm -rf temp1
+ tests/failing-issue1013_either_dependency.sh view
@@ -0,0 +1,53 @@+#!/usr/bin/env bash+set -ev+export DARCS_EMAIL=test+rm -rf tmp_d1 tmp_d2 tmp_d+# Preparations:+# Set up two repos, each with a patch (d1 and d2 respectively) with both+# an individual change and a change that is identical in both repos,+# and thus auto-merge, i.e., they don't conflict in darcs2.  Pull them+# together and record a patch (problem) on top of the auto-merged change,+# so that it depends on EITHER of two patches.++mkdir tmp_d1; cd tmp_d1+darcs init --darcs-2+echo a > a+echo b > b+echo c > c+darcs rec -alm init+echo a-independent > a+echo c-common > c+darcs rec -am d1+cd ..+darcs get --to-patch init tmp_d1 tmp_d2+cd tmp_d2+echo b-independent > b+echo c-common > c+darcs rec -am d2+darcs pull -a ../tmp_d1+# no conflicts -- c-common is identical+echo c-problem > c+darcs rec -am problem+cd ..++# I want to pull the 'problem' patch, but expect darcs to get confused+# because it doesn't know how to select one of the two dependent patches.++darcs get --to-patch init tmp_d2 tmp_d+cd tmp_d+echo n/n/y |tr / \\012 |darcs pull ../tmp_d2+darcs cha++# This is weird, we got d2 though we said No.  I would have expected+# darcs to skip the 'problem' patch in this case.++# Try to pull d1 and unpull d2.++darcs pull -a ../tmp_d1+exit 1 # darcs hangs here (2.0.2+77)!+echo n/y/d |tr / \\012 |darcs obl -p d2++# The obliterate fails with: patches to commute_to_end does not commutex (1)++cd ..+rm -rf tmp_d1 tmp_d2 tmp_d
+ tests/failing-issue1014_identical_patches.sh view
@@ -0,0 +1,60 @@+#!/usr/bin/env bash+set -ev++# Set up a base repo. Our experiment will start from this point+mkdir base+cd base+darcs init --darcs-2+printf "Line1\nLine2\nLine3\n" > foo+darcs rec -alm Base+cd ..++# Now we want to record patch A, which will turn "Line2" into "Hello"+darcs get base a+cd a+printf "Line1\nHello\nLine3\n" > foo+darcs rec --ignore-times -am A+cd ..++# Make B the same as A+darcs get base b+cd b+printf "Line1\nHello\nLine3\n" > foo+darcs rec --ignore-times -am B+cd ..++# Now we make a patch C that depends on A+darcs get a ac+cd ac+printf "Line1\nWorld\nLine3\n" > foo+darcs rec --ignore-times -am C+cd ..++# Merge A and B+darcs get a ab+cd ab+darcs pull -a ../b+darcs revert -a+cd ..++# And merge in C too+darcs get ab abc+cd abc+darcs pull -a ../ac+darcs revert -a+cd ..++# Now we can pull just B and C into base+darcs get base bc+cd bc+darcs pull ../abc -ap 'B|C'+cd ..++# Now we have base, B and C in a repository.  At this point we're correct.++# Let's try merging AC with BC now, here we discover a bug.++darcs get ac abc2+cd abc2+darcs pull -a ../bc+
+ tests/failing-issue1190_unmarked_hunk_replace_conflict.sh view
@@ -0,0 +1,43 @@+#!/usr/bin/env bash+## Test for issue1190 - conflicts between HUNK and REPLACE are not+## marked by --mark-conflicts.+##+## Copyright (C) 2009  Trent W. Buck+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib++rm -rf d e                      # Another script may have left a mess.+darcs init    --repo d/+printf %s\\n foo bar baz >d/f+darcs record  --repo d/ -lam f1+darcs get d/ e/+darcs replace --repo e/ --force bar baz f+darcs record  --repo e/ -lam replacement+printf %s\\n foo bar quux >d/f  # replace baz with quux+darcs record  --repo d/ -am f2++## There ought to be a conflict here, and there is.+darcs pull    --repo e/ d/ -a --mark-conflicts+## The file ought to now have conflict markers in it.+grep 'v v v' e/f+rm -rf d/ e/                    # Clean up after ourselves.
+ tests/failing-issue1196_whatsnew_falsely_lists_all_changes.sh view
@@ -0,0 +1,21 @@+#!/usr/bin/env bash+set -ev++not () { "$@" && exit 1 || :; }++rm -rf temp1+mkdir temp1+cd temp1++darcs init+touch aargh+darcs add aargh+echo utrecht > aargh++darcs wh foo foo/../foo/. > out+cat out+not grep utrecht out++cd ..+rm -rf temp1+
+ tests/failing-issue1266_init_inside_a_repo.sh view
@@ -0,0 +1,33 @@+#!/usr/bin/env bash+## Test for issue1266 - attempting to initialize a repository inside+## another repository should cause a warning, because while perfectly+## legitimate, it is likely to be accidental.+##+## Copyright (C) 2009  Trent W. Buck+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib++rm -rf temp1 out                # Another script may have left a mess.+darcs init --repodir temp1+darcs init --repodir temp1/temp2 2>&1 | tee out+grep -i WARNING out             # A warning should be printed.
+ tests/failing-issue1317_list-options_subdir.sh view
@@ -0,0 +1,39 @@+#!/bin/sh++# Test for issue1317 - darcs mv --list-options returns results from root, and+# not from the current directory++# Copyright 2009 Marco Túlio Gontijo e Silva <marcot@riseup.net>++# Permission is hereby granted, free of charge, to any person obtaining a copy+# of this software and associated documentation files (the "Software"), to deal+# in the Software without restriction, including without limitation the rights+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+# copies of the Software, and to permit persons to whom the Software is+# furnished to do so, subject to the following conditions:++# The above copyright notice and this permission notice shall be included in+# all copies or substantial portions of the Software.++# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+# THE SOFTWARE.++. ../tests/lib+rm -rf R+mkdir R+cd R+darcs init+touch abcd+mkdir foo+darcs add foo+cd foo+touch abcc+mkdir bar+darcs mv --list-options | grep -x abcc+cd ../..+rm -rf R
+ tests/failing-issue1325_pending_minimisation.sh view
@@ -0,0 +1,55 @@+#!/usr/bin/env bash+## Test for issue1325 - hunk patches interfere with pending patch+## minimisation+##+## Copyright (C) 2009 Marco Túlio Gontijo e Silva, Eric Kow+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R S                      # Another script may have left a mess.+darcs init   --repo=R+darcs init   --repo=S++# this is expected to pass regardless of issue1325+# and is here to provide contrast+cd R+touch file+darcs add file+darcs record -am ' file'+mkdir b+darcs add b+darcs mv  file b+rm -r b+darcs whatsnew | not grep adddir+cd ..++# this is/was the failing part of issue1325+cd S+echo file > file                # we need a hunk to make this interesting+darcs add file+darcs record -am ' file'+mkdir b+darcs add b+darcs mv  file b+rm -r b+darcs whatsnew | not grep adddir+cd ..
+ tests/failing-issue1327.sh view
@@ -0,0 +1,27 @@+#!/usr/bin/env bash+set -ev++# See issue1327.+# results in the error:+# patches to commute_to_end does not commutex (1) at src/Darcs/Patch/Depends.hs:452+++rm -rf temp1 temp2+mkdir temp1+cd temp1+darcs init+echo fileA version 1 > fileA+echo fileB version 1 > fileB+darcs add fileA fileB+darcs record --author foo@bar --ignore-times --all -m "Add fileA and fileB"+echo fileA version 2 > fileA+darcs record --author foo@bar --ignore-times --all -m "Modify fileA"+cd ..+darcs get temp1 temp2+cd temp2+darcs obliterate -p "Modify fileA" --all+darcs unrecord -p "Add fileA and fileB" --all+darcs record --author foo@bar --ignore-times --all fileA -m "Add just fileA"+cd ../temp1+darcs pull --all ../temp2+echo y | darcs obliterate --dont-prompt-for-dependencies -p "Add fileA and fileB"
+ tests/failing-issue1332_add_r_boring.sh view
@@ -0,0 +1,45 @@+#!/usr/bin/env bash+## Test for issue1332 - add -r ignores --boring+##+## Copyright (C) 2009 Eric Kow+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R                        # Another script may have left a mess.+darcs init      --repo R        # Create our test repos.++cd R+mkdir d+touch core f+# this is already known to work+darcs add --boring core f+darcs whatsnew > log+grep 'addfile ./f' log+grep 'addfile ./core' log+rm _darcs/patches/pending+# this fails for issue1332+darcs add -r --boring .+darcs whatsnew > log+grep 'addfile ./f' log+grep 'addfile ./core' log+rm _darcs/patches/pending+cd ..
+ tests/failing-issue1337_darcs_changes_false_positives.sh view
@@ -0,0 +1,37 @@+#!/usr/bin/env bash+## Test for issue1337 - darcs changes shows unrelated patches+## Asking "darcs changes" about an unrecorded file d/f will list the+## patch that creates the parent directory d/ (instead of no patches).+##+## Copyright (C) 2009  Trent W. Buck+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib++rm -rf temp1+darcs init --repodir temp1+cd temp1+mkdir d+darcs record -lam d d+# We use --match 'touch d/f' instead of simply d/f because the latter+# prints "Changes to d/f:\n" before the count.+test 0 -eq "$(darcs changes --count --match 'touch d/f')"
+ tests/failing-issue1396_changepref-conflict.sh view
@@ -0,0 +1,32 @@+#!/usr/bin/env bash+set -ev++. ../tests/lib++rm -rf temp1 temp1a temp1b++mkdir temp1+cd temp1+darcs init+darcs setpref test 'echo nothing'+darcs record -am 'null pref'+cd ..++darcs get temp1 temp1a+cd temp1a+darcs setpref test 'echo a'+darcs record -am 'pref a'+cd ..++darcs get temp1 temp1b+cd temp1b+darcs setpref test 'echo b'+darcs record -am 'pref b'+cd ..++cd temp1+darcs pull -a ../temp1a --dont-allow-conflicts+not darcs pull -a ../temp1b --dont-allow-conflicts+cd ..++rm -rf temp1 temp1a temp1b
+ tests/failing-issue1401_bug_in_get_extra.sh view
@@ -0,0 +1,44 @@+#!/usr/bin/env bash+## Test for issue1401 - when two repos share a HUNK patch, but that+## patch's ADDFILE dependency is met by different patches in each+## repo, it becomes impossible to pull between the two repos.+##+## Copyright (C) 2009  Trent W. Buck+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib++## This bug only affects darcs-2 repositories.+fgrep darcs-2 ~/.darcs/defaults &>/dev/null || exit 0++rm -rf d e                      # Another script may have left a mess.+darcs initialize --repodir d/+darcs initialize --repodir e/+touch d/f d/g e/f+darcs record     --repodir d/ -lam 'Add f and g'+darcs record     --repodir e/ -lam 'Add f'+echo >d/f+darcs record     --repodir d/ -am 'Change f'+darcs pull       --repodir e/ -a d/+darcs obliterate --repodir e/ -ap 'Add f and g'+darcs pull       --repodir e/ -a d/+rm -rf d/ e/                    # Clean up after ourselves.
+ tests/failing-issue1406.sh view
@@ -0,0 +1,85 @@+#!/usr/bin/env bash+## Test for issue1406 - failed test on amend unrecords the+##                      original patch+##+## Copyright (C) 2009 Adam Vogt, Kamil Dworakowski+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R S                      # Another script may have left a mess.+darcs init      --repo R        # Create our test repos.+darcs init      --repo S+mkdir R/d/ R/e/                 # Change the working tree.+echo 'Example content.' >R/d/f+darcs record    --repo R -lam 'Add d/f and e.'+darcs mv        --repo R d/f e/+darcs record    --repo R -am 'Move d/f to e/f.'+darcs push      --repo R S -a   # Try to push patches between repos.+darcs push      --repo S R+rm -rf R/ S/                    # Clean up after ourselves.+#!/bin/sh+set -ev++. ../tests/lib++rm -rf temp1+darcs init --repodir temp1++cd temp1++echo "test exit 1" > _darcs/prefs/prefs+echo "a" > a+darcs record --look-for-adds --no-test --all --patch-name=p1+echo "b" >> a+echo "y" | not darcs amend-record --all --patch=p1++# There should be one patch in the repo+test 1 -eq `darcs changes --count` || exit 1++# Another check: there should be nothing new after a is restored+echo "a" > a+not darcs whatsnew -l++cd ..+rm -rf test1++# the following section of the test does not create a new repo,+# it oprates on an existing old-fashioned repo; no need to run it 3 times+if grep 'old-fashioned' .darcs/defaults; then++    # check that we do the operations on checkpoints tentatively+    rm -rf old-with-checkpoint+    tar zxf ../tests/repos/old-with-checkpoint.tgz++    echo "test exit 1" > old-with-checkpoint/_darcs/prefs/prefs++    # this amend will fail+    echo 'y' | not darcs amend --repo old-with-checkpoint -m 'no longer a checkpoint :P' -p "checkpoint here"++    # check that the patch has not been removed from+    # the checkpoints inventory+    grep "checkpoint here" old-with-checkpoint/_darcs/checkpoints/inventory+    #NOTE: checking the file is a rather white box way of testing it, but+    #      I could not think of any other way at the time, please improve++    rm -rf old-with-checkpint+fi
+ tests/failing-issue1442_encoding_round-trip.sh view
@@ -0,0 +1,50 @@+#!/usr/bin/env bash+## -*- coding: utf-8 -*-+## Test for issue1442 - if we disable Darcs escaping and don't change+## our encoding, the bytes in a filename should be the same bytes that+## "darcs changes -v" prints to the right of "addfile" and "hunk".+##+## Copyright (C) 2009  Trent W. Buck+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib++rm -rf R                        # Another script may have left a mess.++## Use the first UTF-8 locale we can find.+export LC_ALL=$(locale -a | egrep 'utf8|UTF-8' | head -1)+export DARCS_DONT_ESCAPE_ANYTHING=True++## If LC_ALL is the empty string, this system doesn't support UTF-8.+if test -z "$LC_ALL"+then exit 1+fi++darcs init      --repo R+echo '首頁 = א₀' >R/'首頁 = א₀'+darcs record    --repo R -lam '首頁 = א₀' '首頁 = א₀'+darcs changes   --repo R -v '首頁 = א₀' >R/log+#cat R/log                      # Show the humans what the output was.+grep -c '首頁 = א₀' R/log >R/count+echo 5 >R/expected-count+cmp R/count R/expected-count    # Both count files should contain "5\n".+rm -rf R                        # Clean up after ourselves.
+ tests/failing-issue1461_case_folding.sh view
@@ -0,0 +1,83 @@+#!/usr/bin/env bash+## Test for issue1461 - patches to files whose names only differ by+## case can be wrongly applied to the same file in the working directory.+##+## Copyright (C) 2009 Eric Kow+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf lower upper joint        # Another script may have left a mess.+mkdir lower upper++cd lower+darcs init+cat > a << EOF+1+2+3+EOF+darcs add a+darcs record -am 'lower init a'+cd ..++cd upper+darcs init+cat > A << EOF+1+2+3+EOF+darcs add A+darcs record -am 'upper init A'+cd ..++darcs get lower joint+cd joint+darcs pull -a ../upper+cd ..++cd lower+cat > a << EOF+one lower+2+3+EOF+darcs record -am 'lower modify'+cd ..++cd upper+cat > A << EOF+1+2+three upper+EOF+darcs record -am 'upper modify'+cd ..++cd joint+darcs pull ../lower -a+darcs pull ../upper -a+grep one a && not grep three a+grep three A && not grep one A+cd ..+# clean up after ourselves+rm -rf lower upper joint
+ tests/failing-issue1473_annotate_repodir.sh view
@@ -0,0 +1,21 @@+#!/usr/bin/env bash+set -ev++. ../tests/lib+rm -rf temp+mkdir temp+cd temp+darcs init+mkdir a b+touch a/a b/b+darcs add --rec .+darcs record -a -m ab -A test+darcs annotate a/a+# annotate --repodir=something '.' should work+cd ..+darcs annotate --repodir temp '.'+cd temp++cd ..+rm -rf temp+
+ tests/failing-issue1609_ot_convergence.sh view
@@ -0,0 +1,104 @@+#!/usr/bin/env bash+## Test for issue1609 - standard test for the TP2 property+## in the Operational Transformation literature.+##+## According to Wikipedia:+## For every three concurrent operations op1,op2 and op3 defined on the same+## document state, the transformation function T satisfies CP2/TP2 property+## if and only if:+## T(op_3, op_1 \circ T(op_2,op_1)) = T(op_3, op_2 \circ T(op_1,op_2)).+##+## Copyright (C) 2009 Eric Kow <kowey@darcs.net>+## Copyright (C) 2009 Pascal Molli <momo54@gmail.com>+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf S1  S2  S3               # Another script may have left a mess.+darcs init      --repo S1       # Create our test repos.++cd S1+cat > f << END+1+2+3+4+5+END+darcs add f+darcs record -am init+cd ..++darcs get S1 S2+darcs get S1 S3++cd S1+cat > f << END+1+2+X+3+4+5+END+darcs record -am 'insert X before line 3'+cd ..++cd S2+cat > f << END+1+2+4+5+END+darcs record -am 'delete line 3'+cd ..++cd S3+cat > f << END+1+2+3+Y+4+5+END+darcs record -am 'insert Y after line 3'+cd ..++darcs pull --allow-conflicts -a --repo S1 S2+darcs pull --allow-conflicts -a --repo S2 S1++darcs pull --allow-conflicts -a --repo S1 S3+darcs pull --allow-conflicts -a --repo S2 S3++darcs pull --allow-conflicts -a --repo S3 S1++# TP2 is just fine for conflict resolution itself...+diff S1/f S2/f # no difference+diff S2/f S3/f # no difference++# But what about the conflict marking?+darcs mark-conflicts --repo S1+darcs mark-conflicts --repo S2+darcs mark-conflicts --repo S3+diff S1/f S2/f # no difference+diff S2/f S3/f # no difference
+ tests/failing-issue1610_get_extra.sh view
@@ -0,0 +1,90 @@+#!/usr/bin/env bash+## Test for issue1610 - another bug in get_extra problem+## This is an offshoot of the issue1609 test+##+## Copyright (C) 2009 Eric Kow <kowey@darcs.net>+## Copyright (C) 2009 Pascal Molli <momo54@gmail.com>+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.++# this test is not relevant for darcs 2 repositories+(not grep darcs-2 $HOME/.darcs/defaults) || exit 200++rm -rf S1  S2  S3               # Another script may have left a mess.+darcs init      --repo S1       # Create our test repos.++cd S1+cat > f << END+1+2+3+4+5+END+darcs add f+darcs record -am init+cd ..++darcs get S1 S2+darcs get S1 S3++cd S1+cat > f << END+1+2+X+3+4+5+END+darcs record -am 'insert X before line 3'+cd ..++cd S2+cat > f << END+1+2+4+5+END+darcs record -am 'delete line 3'+cd ..++cd S3+cat > f << END+1+2+3+Y+4+5+END+darcs record -am 'insert Y after line 3'+cd ..++# please compare this with the issue1609 test+darcs pull -a --repo S1 S2+darcs pull -a --repo S1 S3++darcs pull -a --repo S2 S1+darcs pull -a --repo S2 S3
+ tests/failing-issue1632_changes_nonexisting.sh view
@@ -0,0 +1,40 @@+#!/usr/bin/env bash+## Test for issue1632 - 'darcs changes d/f' should not list any changes,+## where d is part of the repo and f is a non-existent file.+##+## Copyright (C) 2009   Ben Franksen+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R                        # Another script may have left a mess.+darcs init      --repo R        # Create our test repos.++cd R+mkdir d+darcs record -lam 'added directory d'+# darcs should not list any changes here:+darcs changes non-existent-file > log+not grep 'added directory d' log+# ...and neither here:+darcs changes d/non-existent-file > log+not grep 'added directory d' log+cd ..
+ tests/failing-issue1645-ignore-symlinks.sh view
@@ -0,0 +1,35 @@+#!/usr/bin/env bash+## Test for issue1645 - whatsnew -l should not consider symlinks to be+## "real" files in the working tree.+##+## Copyright (C) 2009  Trent W. Buck+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R f                      # Another script may have left a mess.+darcs init      --repo R        # Create our test repos.++cd R+echo 'Example content.' > ../f  # a file outside the repo+ln -s ../f                      # a symlink to same inside the repo+darcs whatsnew -l >log+fgrep 'No changes!' log         # Darcs shouldn't report any changes.
@@ -0,0 +1,77 @@+#!/usr/bin/env bash+## Test for issue1702 - an optimize --relink does not relink the files+## in ~/.darcs/cache.+##+## Copyright (C) 2009  Trent W. Buck+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R S                      # Another script may have left a mess.+darcs init      --repo R        # Create our test repos.++## Create a patch.+echo 'Example content.' > R/f+darcs record -lam 'Add f.' --repodir R++## Get a hard link into the cache.+darcs get R S++## Are hard links available?+x=(R/_darcs/patches/*-*)+x=${x#R/_darcs/patches/}+if [[ ! R/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]]+then+    echo This test requires filesystem support for hard links.+    echo This test requires the hashed (or darcs-2) repo format.+    exit 200+fi++## IMPORTANT!  In bash [[ ]] is neither a builtin nor a command; it is+## a keyword.  This means it can fail without tripping ./lib's set -e.+## This is why all invocations below have the form [[ ... ]] || false.++## Confirm that all three are hard linked.+ls -lids {~/.darcs/cache,[RS]/_darcs}/patches/$x # debugging+[[ R/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false+[[ S/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false+[[ R/_darcs/patches/$x -ef S/_darcs/patches/$x ]] || false++## Break all hard links.+rm -rf S+cp -r R S+rm -rf R+cp -r S R++## Confirm that there are no hard links.+ls -lids {~/.darcs/cache,[RS]/_darcs}/patches/$x # debugging+[[ ! R/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false+[[ ! S/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false+[[ ! R/_darcs/patches/$x -ef S/_darcs/patches/$x ]] || false++## Optimize *should* hard-link all three together.+darcs optimize --relink --repodir R --sibling S++## Confirm that all three are hard linked.+ls -lids {~/.darcs/cache,[RS]/_darcs}/patches/$x # debugging+[[ R/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false+[[ S/_darcs/patches/$x -ef ~/.darcs/cache/patches/$x ]] || false+[[ R/_darcs/patches/$x -ef S/_darcs/patches/$x ]] || false
+ tests/failing-issue390_whatsnew.sh view
@@ -0,0 +1,33 @@+#!/usr/bin/env bash++# For issue390: darcs whatsnew somefile" lstats every file in the working copy and pristine/ directory++set -ev++if ! test -x "$(which strace)"+then echo skipping test since strace was not found+     exit+fi++rm -rf temp+mkdir temp+cd temp+darcs init+date > file1+date > file2+darcs add file*+darcs record -am "test"++strace darcs whatsnew file1 &> out+# we should be accessing file1+grep file1 out+# but shouldn't be accessing file2+if grep file2 out+then+    echo A whatsnew for file1 should not involve a 'stat' call to file2+    exit 1+else+    echo Yay.  We pass.+fi++rm -rf temp
+ tests/failing-issue68_broken_pipe.sh view
@@ -0,0 +1,27 @@+#!/usr/bin/env bash++# For issue68, 'don't report "resource vanished" when stdout pipe is broken.'++set -ev++rm -rf temp1 # Another script may have left a mess.++darcs init --repodir temp1++cd temp1++date > f+darcs add f+darcs rec -am firstp+for (( i=0 ; i < 500; i=i+1 )); do+  echo $i >> f;+  darcs rec -am p$i+done++darcs changes 2> err | head++touch correcterr++diff correcterr err++cd ..
+ tests/failing-issue944_partial_inventory.sh view
@@ -0,0 +1,46 @@+#!/usr/bin/env bash++set -ev++test $DARCS || DARCS=$PWD/../darcs+ACTUAL_DARCS=`which $DARCS`+DARCSPATH=`dirname $ACTUAL_DARCS`+PATH="$DARCSPATH:$PATH"+export PATH++# create base repository+rm -rf temp1+mkdir temp1+cd temp1+darcs init++echo first > a+darcs add a+darcs record -am first+darcs tag --checkpoint 'Tag 1'++echo second > b+darcs add b+darcs record -am second+darcs tag --checkpoint 'Tag 2'++echo third > c+darcs add c+darcs record -am third+darcs tag --checkpoint 'Tag 3'++# create a partial copy of the base repository and modify it+cd ..+rm -rf temp2+darcs get --partial temp1 temp2+cd temp2++# instead of the following three commands one could also use darcs optimize+echo mistake > a+darcs record -am mistake+darcs unrecord -ap mistake++# now check the repository+darcs check+# => darcs: failed to read patch: ...+
+ tests/failing-merging_newlines.sh view
@@ -0,0 +1,47 @@+#!/usr/bin/env bash+set -ev++# Note that this is fixed, the lines marked # BUG HERE+# should be moved back into merging_newlines.sh++# trick: requiring something to fail+not () { "$@" && exit 1 || :; }++rm -rf temp1 temp2++# set up the repository+mkdir temp1+cd temp1+darcs init+cd ..++cd temp1+echo "apply allow-conflicts" > _darcs/prefs/defaults+# note: to make this pass, change echo to echo -n+# is that right?+echo "from temp1" > one.txt+darcs add one.txt+darcs record -A bar -am "add one.txt"+echo >> one.txt+darcs wh -u+cd ..++darcs get temp1 temp2+cd temp2+# reality check+darcs show files | grep one.txt+echo "in tmp2" >> one.txt+darcs whatsnew -s | grep M+darcs record -A bar -am "add extra line"+darcs annotate -p . -u+darcs push -av > log+cat log+not grep -i conflicts log+# BUG HERE+# after a conflict, darcs resolve should report a conflict+darcs mark-conflicts > log 2>&1+cat log+not grep -i 'no conflicts' log+cd ..++rm -rf temp1 temp2
+ tests/failing-newlines.sh view
@@ -0,0 +1,28 @@+#!/usr/bin/env bash+set -ev++rm -rf temp1 temp2++# set up the repository+mkdir temp1+cd temp1+darcs init+cd ..++cd temp1+echo -n "from temp1" > one.txt+darcs add one.txt+darcs record -A bar -am "add one.txt"+echo >> one.txt+cd ..++darcs get temp1 temp2+cd temp2+echo "in tmp2" >> one.txt+darcs record -A bar -am "add extra line"+lines_added=`darcs changes -v --last=1 | grep '\+' | wc -l`+echo $lines_added+test $lines_added -eq 1+cd ..++rm -rf temp1 temp2
+ tests/failing-nice-resolutions.sh view
@@ -0,0 +1,52 @@+#!/bin/sh++set -ev++mkdir temp1+cd temp1+darcs init++echo a > foo+darcs add foo+darcs record -am addfoo++cd ..+darcs get temp1 temp2++cd temp2+echo B > foo+darcs record -am B++cd ../temp1+echo b > foo+darcs record -am b+echo c > foo+darcs record -am c+cd ../temp2+darcs pull -a++cat foo++grep b foo && exit 1+grep a foo && exit 1+grep B foo+grep c foo++echo C > foo+darcs record -am C++cd ../temp1+echo d > foo+darcs record -am d++cd ../temp2+darcs pull -a++cat foo++grep b foo && exit 1+grep a foo && exit 1+grep B foo && exit 1+grep c foo && exit 1+grep C foo+grep d foo
+ tests/failing-record-scaling.sh view
@@ -0,0 +1,37 @@+#!/usr/bin/env bash+## Test for issueN - darcs record shouldn't access old inventories!+##+## Copyright (C) 2008  David Roundy+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+which strace || exit 200        # This test requires strace(1).++rm -rf R                        # Another script may have left a mess.+darcs init      --repo R        # Create our test repo.+touch R/a-unique-filename+strace -eopen -oR/trace \+  darcs record  --repo R -lam 'A unique commit message.'+grep a-unique-filename R/trace+grep _darcs/hashed_inventory R/trace+not grep _darcs/inventories/ R/trace+rm -rf R                        # Clean up after ourselves.
tests/haskell_policy.sh view
@@ -1,59 +1,41 @@ #!/usr/bin/env bash+## This is a pseudo-test that runs tweaked hlint on the source code.+##+## Copyright (C) 2009 Petr Rockai+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE. -RESULT=tmpfile-ROOT=..-ERRORSTATUS=0+. lib -# lookfor ( $1=what, $2=reason, $3=source module exception )-lookfor () {-    rm -f "$RESULT"-    darcs query manifest --repodir="$ROOT" | grep '\.l\?hs$' | while read f; do-        grep -Hnwe "$1" "$ROOT/$f" | grep -v "$3\.$1" | \-        grep -v ":[0-9]\+:import " | grep -Fv "ratify $1: " >> "$RESULT"-    done-    if [ -s "$RESULT" ]; then-        echo "Found the following unratified uses of $1:"-        # ugly sed expresion to fix relative paths; think pretty cat-        sed -e 's/[^:]*\/\.\///' "$RESULT"-        echo "$2"-        echo "Comment 'ratify $1: <why>' on the same line to allow it"-        echo-        ERRORSTATUS=1-    fi-    rm -f "$RESULT"+explain() {+    echo >&2+    echo "## It seems that hlint has found errors. This usually means that you" >&2+    echo "## have used a forbidden function. See contrib/darcs-errors.hlint for" >&2+    echo "## explanation. Please also disregard any possible parse errors." >&2 } -# On 2009-02-12 Petr Rockai explained this on darcs-users:-# The problem with Prelude readFile is that it's based on hGetContents, which-# is lazy by definition. This also means that unless you force consumption of-# the produced list, it will keep an fd open for the file, possibly-# indefinitely.  This is called a fd leak. Other than being annoying and if done-# often, leading to fd exhaustion and failure to open any new files (which is-# usually fatal), it also prevents the file to be unlinked (deleted) on win32.-#-# On the other hand, *strict* bytestring version of readFile will read the whole-# file into a contiguous buffer, *close the fd* and return. This is perfectly-# safe with regards to fd leaks. Btw., this is *not* the case with lazy-# bytestring variant of readFile, so that one is unsafe.-lookfor readFile \-        "Prelude.readFile doesn't ensure the file is closed before it is deleted!\nConsider import Data.ByteString.Char8 as B (readFile), B.readFile instead." \-        B # importing readFile from Data.ByteString as B, is allowed--lookfor hGetContents \-        "hGetContents doesn't ensure the file is closed before it is deleted!"+trap explain ERR -# look for tabs in haskell source-rm -f "$RESULT"-darcs query manifest --repodir="$ROOT" | grep '\.l\?hs$' | while read f; do-    grep -FHnwe "	" "$ROOT/$f" >> "$RESULT"-done-if [ -s "$RESULT" ]; then-    echo "Found the following lines with unwanted tabs:"-    # ugly sed expresion to fix relative paths; think pretty cat-    sed -e 's/[^:]*\/\.\///' "$RESULT"-    echo-    ERRORSTATUS=1-fi-rm -f "$RESULT"+hlint >& /dev/null || exit 200 # skip if there's no hlint -exit "$ERRORSTATUS"+wd="`pwd`"+cd ..+hlint --hint=contrib/darcs-errors.hlint src
tests/issue1139-diff-last.sh view
@@ -14,7 +14,7 @@ echo newtext > foo darcs record -am 'modify foo' -darcs diff --store --last=1 > out1+darcs diff --store-in-mem --last=1 > out1 cat out1 grep text out1 grep foo out1
+ tests/issue1224_convert-darcs2-repository.sh view
@@ -0,0 +1,43 @@+#!/usr/bin/env bash+## Test for issue1224 - Attempting to darcs convert a repository+## which is already in darcs-2 format leads to inconsistent result+##+## Copyright (C) 2009 Tomas Caithaml+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++# this test is not relevant for other than darcs 2 repositories+grep darcs-2 $HOME/.darcs/defaults || exit 200++. ../tests/lib++rm -rf R +darcs init --repo R++echo File contents > R/file.txt+darcs add R/file.txt --repodir R+darcs record --patch-name=add_file.txt --author=me --no-test -a --repodir R++# This should fail with repository already in darcs-2 format.+echo "I understand the consequences of my action" > ack+not darcs convert temp/repo-2 temp/repo-2-converted < ack++rm -rf R
+ tests/issue1300_record_delete-file.sh view
@@ -0,0 +1,50 @@+#!/usr/bin/env bash+## Test for issue1300 - record --delete-file should only delete+## after a successful record+##+## Copyright (C) 2009 Eric Kow+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R                        # Another script may have left a mess.+darcs init      --repo R        # Create our test repos.+cd R+touch f+darcs add f+# no test+touch log+echo 'no test' > f+darcs record -am f --logfile log --delete-logfile+test ! -e log+# passing test+touch log+darcs setpref test 'exit 0'+echo 'test pass' > f+darcs record -am f --test --logfile log --delete-logfile+test ! -e log+# failing test+touch log+darcs setpref test 'exit 1'+echo 'test fail' > f+not darcs record -am g --test --logfile log --delete-logfile+test -e log # should *not* be deleted+cd ..
+ tests/issue1392_authorspelling.sh view
@@ -0,0 +1,43 @@+#!/usr/bin/env bash+## Test for issue1392 - .authorspelling processing.+##+## Copyright (C) 2009 Tomas Caithaml+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R                       # Another script may have left a mess.+darcs init      --repo R        # Create our test repos.+cd R++echo 'Bad\, Jr. <a@a.net>, Foo' > .authorspellings+echo 'Example content.' > f+darcs record -lam 'Add f.' -A 'Foo'+darcs show authors | grep -q 'Bad, Jr\. <a@a.net>' ++echo 'Bad\, Jr. <a@a.net>,  ^Foo\, Jr\..*$' > .authorspellings+echo 'Ex. cont.' > f+darcs record -lam 'Change f.' -A 'Foo, Jr. <a@b.net>'+darcs show authors | tee output.txt | grep -q 'Bad, Jr\. <a@a.net>'++cd ..++#--rm -rf R
+ tests/issue142_record-log.sh view
@@ -0,0 +1,34 @@+#!/usr/bin/env bash+## Test for issue142 - darcs record --logfile foo should not+## let you record a patch even when 'foo' is a missing file+##+## Copyright (C) 2009 Eric Kow+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R                        # Another script may have left a mess.+darcs init      --repo R        # Create our test repos.+cd R+touch f g+touch log+darcs     record -alm f --logfile log     f+not darcs record -alm g --logfile missing g
tests/issue1465_ortryrunning.sh view
@@ -32,11 +32,12 @@ # Set the editor to a program that just fails (VISUAL), make Darcs use # it (--edit), and then make sure when it brokenly launches a fallback # editor, that editor will exit because stdin isn't a tty (/dev/null).-not env -u TERM VISUAL=false </dev/null &>R/log \+not env -u TERM DARCS_EDITOR=false VISUAL=false </dev/null &>R/log \ darcs record    --repo R -lam 'Initial commit.' --edit  # If Darcs did the right thing, the output won't make any mention of # the fallback editors.-not egrep -i 'not found|vi|emacs|nano|edit' R/log+# We skip ^\+ since the commandline is logged and matches "edit".+egrep -v '^\+' R/log | not egrep -i 'not found|vi|emacs|nano|edit'  rm -rf R/                       # Clean up after ourselves.
+ tests/issue1472_read_too_much.sh view
@@ -0,0 +1,37 @@+#!/usr/bin/env bash+## Test for issue1472 - running "darcs record ./foo" shouldn't even+## TRY to read ./bar.+##+## Copyright (C) 2009  Trent W. Buck+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R                        # Another script may have left a mess.+darcs init      --repo R        # Create our test repo.+mkdir R/d/                      # Change the working tree.+echo 'Example content.' >R/f+echo 'Similar content.' >R/d/f+chmod 0 R/f                     # Make R/f unreadable, so that+                                # attempting to read it will result in+                                # an error.+darcs record    --repo R -lam 'Only changes to R/d/.' d+rm -rf R/                       # Clean up after ourselves.
+ tests/issue1488_whatsnew-l.sh view
@@ -0,0 +1,34 @@+#!/usr/bin/env bash+## Test for issue1488 - whatsnew in non-added directory crashes on fromJust+##+## Copyright (C) 2009  Marnix Klooster <marnix.klooster@gmail.com>+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R++mkdir -p R/Foo/Bar		# 2 directory levels needed+cd R+darcs init+cd Foo/Bar+# and now the real problem causer:+darcs whatsnew -l .		# a "fromJust error" in Whatsnew.lhs
+ tests/issue1584_optimize_upgrade.sh view
@@ -0,0 +1,38 @@+#!/usr/bin/env bash+## Test for issue1584 - darcs optimize --upgrade+##+## Copyright (C) 2009 Eric Kow <kowey@darcs.net>+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R                        # Another script may have left a mess.+darcs init      --repo R --old-fashioned # Create our test repos.+mkdir R/d/ R/e/                 # Change the working tree.+echo 'Example content.' >R/d/f+darcs record    --repo R -lam 'Add d/f and e.'+darcs mv        --repo R d/f e/  # Unrecorded change+darcs whatsnew  --repo R | grep 'move ./d/f'+darcs optimize  --repo R --upgrade+darcs check     --repo R+grep hashed R/_darcs/format+not grep darcs-2 R/_darcs/format+darcs whatsnew  --repo R | grep 'move ./d/f'
+ tests/issue1618-amend-preserve-logfile.sh view
@@ -0,0 +1,44 @@+#!/usr/bin/env bash+## Test for issue1618 - amend should preserve the logfile+##                      in case of failure+##+## Copyright (C) 2009 Kamil Dworakowski+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++set -ev+. ../tests/lib+rm -rf R; mkdir R; cd R++darcs init+darcs setpref test false+darcs record  -am foo --no-test+export DARCS_EDITOR="echo 'new log' > "+echo y | not darcs amend -p foo --edit-long-comment 2> out++# the msg has the format: "Logfile left in filenamehere."+LOGFILE=`grep "Logfile left in" out | sed "s/Logfile left in //" | sed s/.$//`++echo $LOGFILE+test -e "$LOGFILE"+grep 'new log' $LOGFILE++rm out; cd ..; rm -rf R/
+ tests/issue1620-record-lies-about-leaving-logfile.sh view
@@ -0,0 +1,42 @@+#!/usr/bin/env bash+## Test for issue1620 - record does not really leave logfile+##                      after a failure+##+## Copyright (C) 2009 Kamil Dworakowski+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++set -ev+. ../tests/lib+rm -rf R; mkdir R; cd R+export DARCS_EDITOR="echo 'a log' > "+darcs init+darcs setpref test false+echo yy | not darcs record -m foo -a --edit-long-comment 2> out++# the msg has the format: "Logfile left in filenamehere."+LOGFILE=`grep "Logfile left in" out | sed "s/Logfile left in //" | sed s/.$//`+test -e "$LOGFILE"+grep 'a log' $LOGFILE++rm out+cd ..+rm -rf R/
+ tests/issue1636-match-hunk.sh view
@@ -0,0 +1,56 @@+#!/usr/bin/env bash+## Test for issue1636 - primitive match type: hunk+##+## Copyright (C) Kamil Dworakowski+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R+darcs init      --repo R        # Create our test repos.++cd R+echo 'first line' > f+darcs record -lam 'one'+echo 'second line' >> f+darcs record -am 'two'++darcs changes --match 'hunk first' > log+grep one log+not grep two log++darcs changes --match 'hunk line' > log+grep one log+grep two log++darcs changes --match 'hunk one' > log+not grep one log++# test searching for lines in the remove part of the hunk+echo 'first line' > f++darcs record -am 'three'+darcs changes --match 'hunk second' > log++grep three log+grep two log+not grep first log+
+ tests/issue27.sh view
@@ -0,0 +1,43 @@+#!/bin/sh++set -ev++rm -rf temp1 temp2+mkdir temp1 temp2+cd temp1+darcs init+echo first > a+darcs add a+darcs record --pipe --all --patch-name=first <<EOF+Thu Sep 18 22:37:06 MSD 2008+author+EOF++echo first > b+darcs add b+darcs record --pipe --all --patch-name=first <<EOF+Thu Sep 18 22:37:06 MSD 2008+author+EOF++cd ../temp2+darcs init+darcs pull --all --dont-allow-conflicts ../temp1+echo second >> a+darcs record --pipe --all --patch-name=second <<EOF+Thu Sep 18 22:37:07 MSD 2008+author+EOF++cd ../temp1+echo second >> b+darcs record --pipe --all --patch-name=second <<EOF+Thu Sep 18 22:37:07 MSD 2008+author+EOF++darcs pull --all --dont-allow-conflicts ../temp2+test `darcs changes --count` = "4"+cd ..++rm -rf temp1 temp2
+ tests/issue942_push_apply_prehook.sh view
@@ -0,0 +1,42 @@+#!/usr/bin/env bash+## Test for issue942 - remote apply prehook not invoked on darcs push+## We also test for posthooks along the way even though that's not part+## of the issue.+##+## Copyright (C) 2009 Eric Kow <kowey@darcs.net>+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R S                      # Another script may have left a mess.+darcs init      --repo R        # Create our test repos.+echo 'apply prehook touch g' >R/_darcs/prefs/defaults+echo 'apply posthook touch h' >>R/_darcs/prefs/defaults+darcs get R S+cd S+touch f+darcs add f+darcs record -lam 'Add f'+test ! -e ../R/g+test ! -e ../R/h+darcs push -a+test -e ../R/g+test -e ../R/h
tests/lib view
@@ -1,5 +1,5 @@ # This is a -*- sh -*- library.-set -ev+set -vex  ## I would use the builtin !, but that has the wrong semantics. not () { "$@" && exit 1 || :; }@@ -8,11 +8,30 @@ abort_windows () { if echo $OS | grep -i windows; then   echo This test does not work on Windows-  exit 0+  exit 200 fi }  pwd() {     ghc --make "$TESTS_WD/hspwd.hs"     "$TESTS_WD/hspwd"+}++# switch locale to latin9 if supported if there's a locale command, skip test+# otherwise+switch_to_latin9_locale () {+    if ! which locale ; then+        echo "no locale command"+        exit 200 # skip test+    fi++    latin9_locale=`locale -a | grep @euro | head -n 1`+    if [ -z "$latin9_locale" ]; then+            echo "no latin9 locale found"+            exit 200 # skip, we can't switch away from UTF-8+    fi++    echo "Using locale $latin9_locale"+    export LC_ALL=$latin9_locale+    echo "character encoding is now `locale charmap`" }
+ tests/nfs-failure.sh view
@@ -0,0 +1,35 @@+#!/bin/sh++set -ev++rm -rf temp1 temp2+mkdir temp1+cd temp1+darcs init+echo first > a+darcs add a+darcs record --pipe --all --patch-name=first <<EOF+Thu Sep 18 22:37:06 MSD 2008+author+EOF++echo first > b+darcs add b+darcs record --pipe --all --patch-name=first <<EOF+Thu Sep 18 22:37:06 MSD 2008+author+EOF++# it seems that somehow the following occasionally fails on an nfs+# filesystem when darcs is compiled with ghc 6.6.++darcs get . ../temp2++# it fails with something like:++# darcs: ./_darcs/patches/20080918223706-f64cd-6b512400a8108808b7ba7057f0eac2adf473b3ae.gz: copyFile: resource busy (file is locked)+++cd ..++rm -rf temp1 temp2
tests/partial.sh view
@@ -1,5 +1,8 @@ #!/usr/bin/env bash +exit 200 # checkpoint creation is not supported by current darcs+         # we would need a testdata tarball for this test+ # A partial get of a repo shall have the same _darcs/pristine as the original  set -ev
tests/pending_has_conflicts.sh view
@@ -22,8 +22,7 @@ write_buggy_pending  echo now watch the fireworks as all sorts of things fail-not darcs whatsnew &> out-cat out+not darcs whatsnew 2>&1 | tee out grep 'pending has conflicts' out  echo pending should now be fixed but there are no changes@@ -31,8 +30,7 @@  write_buggy_pending -darcs revert -a &> out-cat out+darcs revert -a 2>&1 | tee out grep 'pending has conflicts' out  echo pending should now be emptied@@ -40,22 +38,19 @@  write_buggy_pending -darcs record -a -m foo &> out-cat out+darcs record -a -m foo 2>&1 | tee out grep 'pending has conflicts' out  darcs record -a -m foo  darcs changes -v -darcs repair &> out-cat out+darcs repair 2>&1 | tee out grep 'The repository is already consistent' out  write_buggy_pending -darcs repair &> out-cat out+darcs repair 2>&1 | tee out grep 'The repository is already consistent' out  cd ..
+ tests/pull_conflicts.sh view
@@ -0,0 +1,57 @@+#!/usr/bin/env bash+## Test that pull --skip-conflicts filters the conflicts+## appropriately.+##+## Copyright (C) 2009 Ganesh Sittampalam+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R S                      # Another script may have left a mess.++mkdir R+cd R+darcs init+echo 'foo' > foo+echo 'bar' > bar+darcs rec -lam 'Add foo and bar'+cd ..++darcs get R S++cd R+echo 'foo2' > foo+darcs rec -lam 'Change foo (2)'+echo 'bar2' > bar+darcs rec -lam 'Change bar (2)'+cd ..++cd S+echo 'foo3' > foo+darcs rec -lam 'Change foo (3)'+darcs pull --skip-conflicts -a ../R+test `darcs changes --count` -eq 3+cd ..++cd S+darcs pull -a ../R+test `darcs changes --count` -eq 4+cd ..
tests/push-formerly-pl.sh view
@@ -4,6 +4,14 @@  . lib +slash() {+if echo $OS | grep -q -i windows; then+    echo -n \\+else+    echo -n /+fi+}+ DIR="`pwd`"  rm -rf temp1 temp2@@ -40,7 +48,7 @@ # Before trying to pull from self, defaultrepo does not exist test ! -e _darcs/prefs/defaultrepo # return special message when you try to push to yourself-not darcs push -a "$DIR/temp1" 2> log+not darcs push -a "$DIR`slash`temp1" 2> log grep -i "cannot push from repository to itself" log # and don't update the default repo to be the current dir test ! -e _darcs/prefs/defaultrepo
+ tests/push_conflicts.sh view
@@ -0,0 +1,59 @@+#!/usr/bin/env bash+## Test that apply --skip-conflicts filters the conflicts+## appropriately.+##+## Copyright (C) 2009 Ganesh Sittampalam+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R S                      # Another script may have left a mess.++mkdir R+cd R+darcs init+echo 'foo' > foo+echo 'bar' > bar+darcs rec -lam 'Add foo and bar'+cd ..++darcs get R S++cd R+echo 'foo2' > foo+darcs rec -lam 'Change foo (2)'+echo 'bar2' > bar+darcs rec -lam 'Change bar (2)'+cd ..++cd S+echo 'foo3' > foo+darcs rec -lam 'Change foo (3)'+cd ..++cd R+darcs send -a ../S -o ../S/applyme.dpatch+cd ..++cd S+darcs apply --skip-conflicts applyme.dpatch+test `darcs changes --count` -eq 3+cd ..
+ tests/remove.sh view
@@ -0,0 +1,50 @@+#!/usr/bin/env bash+##+## Copyright (C) 2009  Roman Plasil+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. ../tests/lib                  # Load some portability helpers.+rm -rf R S                      # Another script may have left a mess.+darcs init      --repo R        # Create our test repos.++cd R+mkdir d e                       # Change the working tree.+mkdir d/f d/f/g+echo 'Example content.' > d/f/1.txt+echo 'Example content.' > d/f/g/2.txt+echo 'Example content.' > e/3.txt++darcs add -r .+darcs wh -s > before.lst+grep -i d before.lst +grep -i e before.lst+grep -i d/f before.lst++darcs remove -r d+darcs wh -s > after.lst+not grep -i d after.lst +not grep -i d/f after.lst+not grep -i d/f/g after.lst+not grep -i d/f/g/2.txt after.lst+not grep -i d/f/1.txt after.lst++cd ..
tests/repair-corrupt.sh view
@@ -15,6 +15,7 @@  hashed=false test -e _darcs/hashed_inventory && hashed=true+cp -R _darcs _clean_darcs  # produce a corrupt patch echo 'rmfile foo' > _darcs/patches/pending@@ -22,6 +23,11 @@ darcs rec -a -m 'remove foo'  not darcs check # unapplicable patch!+cp -R _darcs/ _backup_darcs+darcs repair # repairs the patch+darcs check+rm -rf _darcs+mv _backup_darcs _darcs # get the bad patch back  # stash away contents of _darcs cp -R _darcs/ _backup_darcs@@ -30,15 +36,18 @@ darcs rec -a -m 'here'  # corrupt pristine content-$hashed && inv=`grep ^pristine _darcs/hashed_inventory`-cp _backup_darcs/patches/* _darcs/patches/-cp _backup_darcs/*inventory* _darcs/-$hashed && {-    cp _darcs/hashed_inventory hashed.tmp-    sed -e "s,^pristine:.*$,$inv," < hashed.tmp > _darcs/hashed_inventory-    rm hashed.tmp+corrupt_pristine() {+    $hashed && inv=`grep ^pristine _darcs/hashed_inventory`+    cp _backup_darcs/patches/* _darcs/patches/+    cp _backup_darcs/*inventory* _darcs/+    if $hashed; then+        cp _darcs/hashed_inventory hashed.tmp+        sed -e "s,^pristine:.*$,$inv," < hashed.tmp > _darcs/hashed_inventory+        rm hashed.tmp+    fi } +corrupt_pristine not darcs check # just a little paranoia  darcs repair # repair succeeds@@ -49,5 +58,11 @@ echo foo > foobar1 diff foobar foobar1 +rm -rf _backup_darcs+mv _clean_darcs _backup_darcs+corrupt_pristine # without the unapplicable patch+not darcs check+darcs repair+darcs check+ cd ..-rm -rf bad
+ tests/repos/old-with-checkpoint.tgz view

binary file changed (absent → 3053 bytes)

tests/show_contents.sh view
@@ -1,5 +1,5 @@ #!/usr/bin/env bash-set -ev+. lib  rm -rf temp1 mkdir temp1@@ -21,6 +21,8 @@ darcs show contents foo -p third | grep third darcs show contents foo --match="author author1" first | grep first darcs show contents foo --tag t1 | grep second+not darcs show contents foo --match "hash bla" 2>&1 | tee out+grep "Couldn't match pattern" out cd ..  rm -rf temp1
+ tests/tentative_revert.sh view
@@ -0,0 +1,46 @@+#!/usr/bin/env bash+## Test for clearing tentative state after a failed transaction+##+## Copyright (C) 2009  Kamil Dworakowski+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++set -ev+. ../tests/lib+rm -rf R+darcs init      --repo R+touch R/foo+darcs record    --repo R -lam 'foo'+touch R/bar+darcs record    --repo R -lam 'bar'+echo "this change should stay uncommitted" >> R/foo+darcs setpref   --repo R test false+echo 'y' | not darcs amend --repo R -am 'change everything' R/foo+darcs setpref   --repo R test true++# if tentative state was not cleared, the previous changes+# from failed transaction would piggy back on the next+echo "xx" >> R/bar+echo 'y' | darcs amend     --repo R -am 'bar2' R/bar++# should have uncommitted changes+darcs wh      --repo R > changes+grep "this change should stay uncommitted" changes
+ tests/trailing-newlines.sh view
@@ -0,0 +1,50 @@+#!/usr/bin/env bash+. lib++rm -rf temp && mkdir temp+cd temp+darcs init+echo -n > no_newline+echo -n > newline++darcs rec -lam "empty"++echo -n foo > no_newline+echo foo > newline++wc -l no_newline | grep 0+wc -l newline | grep 1++darcs wh > diff1+darcs rec -am "add bits"+darcs revert -a | grep "no changes"++echo -n > no_newline+echo -n > newline++darcs wh > diff2+darcs rec -lam "bar"++darcs revert -a | grep "no changes"+darcs check++cat > diff1.expected <<EOF+hunk ./newline 1++foo+hunk ./no_newline 1+-++foo+EOF++cat > diff2.expected <<EOF+hunk ./newline 1+-foo+hunk ./no_newline 1+-foo+++EOF++diff -u diff1.expected diff1+diff -u diff2.expected diff2++cd .. && rm -rf temp
tests/unrecord.sh view
@@ -2,6 +2,9 @@  set -ev +exit 200 # checkpoint creation is not supported by current darcs+         # we would need a testdata tarball for this test+ # Check that checkpoints are removed when tags are unrecorded  rm -rf temp1