packages feed

cmdlib-0.2: testrec.hs

{-# LANGUAGE ScopedTypeVariables, EmptyDataDecls, MultiParamTypeClasses,
             DeriveDataTypeable, FlexibleInstances #-}
module Main where
import Prelude hiding ( readFile, all, last )

import Data.Char
import Data.List ( isPrefixOf )
import Data.List.Split ( splitOn )
import System.Console.CmdLib hiding ( Record, disable )
import qualified System.Console.CmdLib as Cmd

data ApplyAs = ApplyAs String | ApplyAsSelf deriving (Typeable, Data, Show, Eq)
data Conflicts = Mark | Allow | Disallow deriving (Typeable, Data, Show, Eq)
data Posthook = Always | Never | Prompt deriving (Typeable, Data, Show, Eq)

newtype AbsolutePath = AbsolutePath FilePath deriving (Eq, Ord, Typeable, Data, Show)
data AbsolutePathOrStd = AP AbsolutePath | APStd deriving (Eq, Ord, Typeable, Data, Show)

data Flag = Flag
  { test :: Bool
  , onlyToFiles :: Bool
  , removeTestDirectory :: Bool

  -- matching several
  , all :: Bool
  , matches :: String
  , patches :: String
  , tags :: String

  -- matching one
  , match :: String
  , patch :: String
  , tag :: String

  -- matching range
  , toMatch :: String
  , fromMatch :: String
  , fromPatch :: String
  , toPatch :: String
  , fromTag :: String
  , toTag :: String

  -- matching numerically
  , last :: Int
  , maxCount :: Int
  , index :: (Int,Int)

  , context :: AbsolutePath

  -- bundle sending/output
  , to :: String
  , cc :: String
  , output :: AbsolutePathOrStd
  , outputAutoName :: Maybe AbsolutePath
  , subject :: String
  , inReplyTo :: String
  , sendmailCmd :: String

  -- recording
  , author :: String
  , name :: String
  , logfile :: AbsolutePath
  , deleteLogfile :: Bool
  , pipe :: Bool

  -- amend
  , keepDate :: Bool

  -- add
  , recursive :: Bool
  , dateTrick :: Bool
  , boring :: Bool
  , caseOk :: Bool
  , reservedOk :: Bool

  -- push/pull/apply
  , setDefault :: Bool
  , applyAs :: ApplyAs
  , conflicts :: Conflicts
  , skipConflicts :: Bool
  , externalMerge :: String
  , setScriptsExecutable :: Bool

  -- repo combinators
  , union :: Bool
  , complement :: Bool
  , intersection :: Bool

  -- output
  , number :: Bool
  , count :: Bool

  -- misc
  , distName :: String
  , trustTimes :: Bool
  , dryRun :: Bool
  , disable :: Bool
  , promptForDependencies :: Bool

  -- hooks
  , runPosthook :: Posthook
  , posthook :: String

  -- network
  , sshCm :: Bool
  , httpPipelining :: Bool
  , remoteDarcs :: String

  -- verbosity & debugging
  , timings :: Bool
  , verbosity :: Int
  , debug :: Bool
  , debugHttp :: Bool

  } deriving (Typeable, Data, Show, Eq)

matchSeveral = matches +% patches +% tags +% all
matchRange = toMatch +% fromMatch +% toPatch +% fromPatch +% toTag +% fromTag
matchOne = match +% patch +% tag
matchNum = maxCount +% last +% index
apply = conflicts +% skipConflicts +% externalMerge +% setScriptsExecutable
posthooks = posthook +% runPosthook
reposet = intersection +% complement +% union

network = sshCm +% httpPipelining +% remoteDarcs

ann cmd f opts = do putStrLn $ "command = " ++ cmd
                    putStrLn $ disp (unwords . drop 1 . words $ show f)
                    putStrLn $ "non-options = " ++ unwords opts
                 where disp ('{':r) = disp r
                       disp ('}':r) = disp r
                       disp (',':' ':r) = '\n':disp r
                       disp (x:xs) = x:disp xs
                       disp [] = []

instance Attributes Flag where
  readFlag _ = readCommon <+< applyas <+< interval
    where applyas "self" = ApplyAsSelf
          applyas x | "user" `isPrefixOf` x = ApplyAs (drop 5 x)
                    | otherwise = error $ "Error decoding --apply-as argument " ++
                                          x ++ ". Expected \"self\" or \"user:STRING\""
          interval :: String -> (Int, Int)
          interval str = case splitOn "-" str of
            [x, y] -> (read x, read y)
            _ -> error $ "Error parsing interval " ++ str

  attributes _ =

    group "Options" [
      name   %> [ short 'm', Help "specify the name of patch", ArgHelp "NAME" ],
      author %> [ short 'A', Help "specify author identity" ],
      test   %> [            Help "run the test script" ],
      all    %> [ short 'a', Help "answer yes to all patches",
                             InvLong ["interactive", "no-all"] ],
      pipe   %> [            Help "ask user interactively for the patch metadata" ] %+ simple
    ] %%

    group "Matching patches" [
      matches    %> [ Help "select patches matching PATTERN", ArgHelp "PATTERN" ],
      patches    %> [ Help "select patches matching REGEXP",  ArgHelp "REGEXP"  ],
      tags       %> [ Help "select tags matching REGEXP",     ArgHelp "REGEXP"  ]
    ] %%

    group "Network options" [
      sshCm          %> Help "use SSH ControlMaster feature",
      remoteDarcs    %> [ Help "name/path of the remote darcs binary"
                        , Default "darcs", ArgHelp "BINARY" ],
      httpPipelining %> [ Help "enable HTTP pipelining", Default True ]
    ] %%

    group "Applying patches" [
      conflicts      %> [ Help "how to treat conflicts", ArgHelp "allow|mark|disallow" ],
      externalMerge  %> [ Help "use external tool to merge conflicts", ArgHelp "COMMAND" ],
      skipConflicts  %> Help "filter out any patches that would create conflicts"
    ] %%

    group "Advanced options" [
      removeTestDirectory %> [ Help "remove the test directory", Default True ],
      trustTimes          %> [ Help "trust the file modification times", Default True
                             , InvLong ["ignore-times", "no-trust-times"] ],
      disable             %> Help "disable this command"
    ] %%

    group "Verbosity control" [
      verbosity %> Help "set verbosity level",
      debug     %> Help "give debug output",
      debugHttp %> Help "give debug output for libcurl (HTTP)",
      timings   %> Help "provide debugging timings information"
    ] %%

    enable <% verbosity +% debug +% disable %% everywhere Cmd.disable
    %% everywhere (Default (-1 :: Int, -1 :: Int))
    %% everywhere (Default $ AbsolutePath "")
    %% everywhere (Default $ APStd)
    %% everywhere (Default $ (Nothing :: Maybe AbsolutePath))
    %% everywhere (Default ApplyAsSelf)
    %% everywhere (Default Mark)
    %% everywhere (Default Never)

data Record = Record deriving Typeable
data Pull = Pull deriving Typeable
data Push = Push deriving Typeable
data Changes = Changes deriving Typeable
data Apply = Apply deriving Typeable
data ShowCmd = ShowCmd deriving Typeable

data ShowRepo deriving Typeable
data ShowContents deriving Typeable

show_subcommands = (cmd :: ShowRepo) %: (cmd :: ShowContents)

instance Command ShowCmd (Cmd.Record Flag) where
  summary      _ = "Show information which is stored by darcs."
  help         _ = "Subcommands:\n" ++ helpCommands show_subcommands
  cmdname      _ = "show" -- override
  supercommand _ = True

  run _ f opts = dispatch [] show_subcommands opts

instance Command Record (Cmd.Record Flag) where
  options _ =  enable <% name +% author +% test +% removeTestDirectory +% all +% pipe
                      +% trustTimes
  summary _ = "Create a patch from unrecorded changes."

  run _ = ann "record"

instance Command Pull (Cmd.Record Flag) where
  options _  =  enable <% matchSeveral +% network +% trustTimes +% apply +% posthooks
                       +% promptForDependencies +% reposet
  summary _  = "Copy and apply patches from another repository to this one."
  synopsis _ = "darcs pull [OPTION]... [REPOSITORY]..."

  run _ = ann "pull"

instance Command Push (Cmd.Record Flag) where
  options _  =  enable <% matchSeveral +% network
  summary _  = "Copy and apply patches from this repository to another one."
  run _ = ann "push"

instance Command Changes (Cmd.Record Flag) where
  options _  =  enable <% matchSeveral +% matchRange +% matchNum
  summary _  = "List patches in the repository."
  run     _  = ann "changes"

instance Command Apply (Cmd.Record Flag) where
  options _  =  enable <% matchSeveral +% matchRange +% matchNum +% apply
  summary _  = "Apply a patch bundle created by `darcs send'."
  run     _  = ann "apply"

instance Command ShowRepo (Cmd.Record Flag) where
  cmdname      _ = "repo"
  summary      _ = "Show repository summary information"
  run _          = ann "show repo"

instance Command ShowContents (Cmd.Record Flag) where
  cmdname      _ = "contents"
  summary      _ = "Outputs a specific version of a file."
  run _          = ann "show contents"

commands = commandGroup "Copying changes between the working copy and the repository"
           Record
        %: commandGroup "Copying patches between repositories with working copy update"
                   (Pull %: Push %: Apply)
        %: commandGroup "Querying the repository"
                   (Changes %: ShowCmd)

main = getArgs >>= dispatch [] commands