% Copyright (C) 2003-2004 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; if not, write to the Free Software Foundation, % Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. \section{darcs optimize} \begin{code} module Optimize ( optimize ) where import DarcsUtils ( withCurrentDirectory ) import Monad ( when ) import Maybe ( isJust ) import Workaround ( mkRegex, matchRegex ) import DarcsCommands ( DarcsCommand(..), nodefaults ) import DarcsArguments ( DarcsFlag( Compress, NoCompress, Verbose, TagName, CheckPoint ), tagname, verbose, checkpoint, uncompress_nocompress, ) import Repository ( read_repo, write_inventory, write_checkpoint, am_in_repo, ) import PatchInfo ( PatchInfo, just_name, make_filename, human_friendly ) import Zlib ( gzWriteToFile ) import FastPackedString ( gzReadFilePS, hPutPS ) import Lock ( withLock, writeToFile, ) \end{code} \begin{code} optimize_description :: String optimize_description = "Optimize your repository." \end{code} \options{optimize} \haskell{optimize_help} \begin{code} optimize_help :: String optimize_help = "Optimize reorganizes your repository data to make it more efficient to access\n" \end{code} \begin{code} 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 = am_in_repo, command_get_arg_possibilities = return [], command_argdefaults = nodefaults, command_darcsoptions = [checkpoint, uncompress_nocompress, tagname,verbose]} \end{code} \begin{code} optimize_cmd :: [DarcsFlag] -> [String] -> IO () optimize_cmd opts _ = withLock "./_darcs/lock" $ do do_optimize_inventory opts when (CheckPoint `elem` opts) $ do_checkpoint opts when (Compress `elem` opts || NoCompress `elem` opts) $ optimize_compression opts putStr "Done optimizing!\n" is_tag :: PatchInfo -> Bool is_tag pinfo = take 4 (just_name pinfo) == "TAG " \end{code} Optimize will always write out a fresh copy of the inventory that minimizes the amount of inventory that need be downloaded when people pull from the repo. \begin{code} do_optimize_inventory :: [DarcsFlag] -> IO () do_optimize_inventory opts = do ps <- read_repo "." when (Verbose `elem` opts) $ putStr "Writing out a nice copy of the inventory.\n" write_inventory "." ps \end{code} If you use the \verb!--checkpoint! flag optimize creates a checkpoint patch for a tag. You can specify the tag with the \verb!--tag-name! option, or just let darcs choose the most recent tag. \begin{code} do_checkpoint :: [DarcsFlag] -> IO () do_checkpoint opts = do mpi <- get_tag opts case mpi of Nothing -> putStr "There is no tag to checkpoint!\n" Just pinfo -> do putStr $ "Checkpointing tag:\n"++human_friendly pinfo++"\n" write_checkpoint pinfo get_tag :: [DarcsFlag] -> IO (Maybe PatchInfo) get_tag [] = do ps <- read_repo "." case filter (is_tag . fst) $ concat ps of [] -> return Nothing ((pinfo,_):_) -> return $ Just pinfo get_tag (TagName t:_) = do ps <- read_repo "." case filter (match_tag t) $ map fst $ concat ps of (pinfo:_) -> return $ Just pinfo _ -> return Nothing get_tag (_:fs) = get_tag fs \end{code} \begin{code} 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 \end{code} If you give the \verb!compress! flag, optimize will compress all the patches in the repository. Similarly, if you give the \verb!uncompress! or \verb!dont-compress! flag, optimize will decompress all the patches in the repository. You might want to do this on large repositories if you have plenty of disk space but run into memory pressure, since it will allow darcs to open the patch files via mmap. \begin{code} optimize_compression :: [DarcsFlag] -> IO () optimize_compression opts = do r <- read_repo "." withCurrentDirectory "_darcs/patches" (sequence_ $ map (do_compress.make_filename.fst) $ concat r) where wtf = if Compress `elem` opts then gzWriteToFile else writeToFile do_compress f = do contents <- gzReadFilePS f wtf f $ \h -> hPutPS h contents \end{code}