{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} module Distribution.Types.SourceRepo ( SourceRepo(..), RepoKind(..), RepoType(..), knownRepoTypes, emptySourceRepo, classifyRepoType, classifyRepoKind, ) where import Prelude () import Distribution.Compat.Prelude import Distribution.Utils.Generic (lowercase) import Distribution.Pretty import Distribution.Parsec import qualified Distribution.Compat.CharParsing as P import qualified Text.PrettyPrint as Disp -- ------------------------------------------------------------ -- * Source repos -- ------------------------------------------------------------ -- | Information about the source revision control system for a package. -- -- When specifying a repo it is useful to know the meaning or intention of the -- information as doing so enables automation. There are two obvious common -- purposes: one is to find the repo for the latest development version, the -- other is to find the repo for this specific release. The 'ReopKind' -- specifies which one we mean (or another custom one). -- -- A package can specify one or the other kind or both. Most will specify just -- a head repo but some may want to specify a repo to reconstruct the sources -- for this package release. -- -- The required information is the 'RepoType' which tells us if it's using -- 'Darcs', 'Git' for example. The 'repoLocation' and other details are -- interpreted according to the repo type. -- data SourceRepo = SourceRepo { -- | The kind of repo. This field is required. repoKind :: RepoKind, -- | The type of the source repository system for this repo, eg 'Darcs' or -- 'Git'. This field is required. repoType :: Maybe RepoType, -- | The location of the repository. For most 'RepoType's this is a URL. -- This field is required. repoLocation :: Maybe String, -- | 'CVS' can put multiple \"modules\" on one server and requires a -- module name in addition to the location to identify a particular repo. -- Logically this is part of the location but unfortunately has to be -- specified separately. This field is required for the 'CVS' 'RepoType' and -- should not be given otherwise. repoModule :: Maybe String, -- | The name or identifier of the branch, if any. Many source control -- systems have the notion of multiple branches in a repo that exist in the -- same location. For example 'Git' and 'CVS' use this while systems like -- 'Darcs' use different locations for different branches. This field is -- optional but should be used if necessary to identify the sources, -- especially for the 'RepoThis' repo kind. repoBranch :: Maybe String, -- | The tag identify a particular state of the repository. This should be -- given for the 'RepoThis' repo kind and not for 'RepoHead' kind. -- repoTag :: Maybe String, -- | Some repositories contain multiple projects in different subdirectories -- This field specifies the subdirectory where this packages sources can be -- found, eg the subdirectory containing the @.cabal@ file. It is interpreted -- relative to the root of the repository. This field is optional. If not -- given the default is \".\" ie no subdirectory. repoSubdir :: Maybe FilePath } deriving (Eq, Ord, Generic, Read, Show, Typeable, Data) emptySourceRepo :: RepoKind -> SourceRepo emptySourceRepo kind = SourceRepo { repoKind = kind , repoType = Nothing , repoLocation = Nothing , repoModule = Nothing , repoBranch = Nothing , repoTag = Nothing , repoSubdir = Nothing } instance Binary SourceRepo instance Structured SourceRepo instance NFData SourceRepo where rnf = genericRnf -- | What this repo info is for, what it represents. -- data RepoKind = -- | The repository for the \"head\" or development version of the project. -- This repo is where we should track the latest development activity or -- the usual repo people should get to contribute patches. RepoHead -- | The repository containing the sources for this exact package version -- or release. For this kind of repo a tag should be given to give enough -- information to re-create the exact sources. | RepoThis | RepoKindUnknown String deriving (Eq, Generic, Ord, Read, Show, Typeable, Data) instance Binary RepoKind instance Structured RepoKind instance NFData RepoKind where rnf = genericRnf -- | An enumeration of common source control systems. The fields used in the -- 'SourceRepo' depend on the type of repo. The tools and methods used to -- obtain and track the repo depend on the repo type. -- data RepoType = Darcs | Git | SVN | CVS | Mercurial | GnuArch | Bazaar | Monotone | OtherRepoType String deriving (Eq, Generic, Ord, Read, Show, Typeable, Data) instance Binary RepoType instance Structured RepoType instance NFData RepoType where rnf = genericRnf knownRepoTypes :: [RepoType] knownRepoTypes = [Darcs, Git, SVN, CVS ,Mercurial, GnuArch, Bazaar, Monotone] repoTypeAliases :: RepoType -> [String] repoTypeAliases Bazaar = ["bzr"] repoTypeAliases Mercurial = ["hg"] repoTypeAliases GnuArch = ["arch"] repoTypeAliases _ = [] instance Pretty RepoKind where pretty RepoHead = Disp.text "head" pretty RepoThis = Disp.text "this" pretty (RepoKindUnknown other) = Disp.text other instance Parsec RepoKind where parsec = classifyRepoKind <$> P.munch1 isIdent classifyRepoKind :: String -> RepoKind classifyRepoKind name = case lowercase name of "head" -> RepoHead "this" -> RepoThis _ -> RepoKindUnknown name instance Pretty RepoType where pretty (OtherRepoType other) = Disp.text other pretty other = Disp.text (lowercase (show other)) instance Parsec RepoType where parsec = classifyRepoType <$> P.munch1 isIdent classifyRepoType :: String -> RepoType classifyRepoType s = fromMaybe (OtherRepoType s) $ lookup (lowercase s) repoTypeMap where repoTypeMap = [ (name, repoType') | repoType' <- knownRepoTypes , name <- prettyShow repoType' : repoTypeAliases repoType' ] isIdent :: Char -> Bool isIdent c = isAlphaNum c || c == '_' || c == '-'