CurryInfo: cpm-3.3.0 / CPM.Repository.Update

classes:

              
documentation:
------------------------------------------------------------------------------
--- This module implements operations to update and change the
--- package repository, i.e., the index of all packages known
--- to the package manager.
------------------------------------------------------------------------------
name:
CPM.Repository.Update
operations:
addPackageToRepository updateRepository
sourcecode:
module CPM.Repository.Update
  ( addPackageToRepository, updateRepository
  )
 where

import System.Directory
import System.FilePath
import Data.List         ( isSuffixOf )
import Control.Monad

import CPM.Config             ( Config, packageInstallDir, packageIndexURLs
                              , repositoryDir )
import CPM.ErrorLogger
import CPM.Executables        ( getCurlCmd )
import CPM.Package
import CPM.Package.Helpers    ( cleanPackage )
import CPM.FileUtil           ( copyDirectory, quote, recreateDirectory
                              , removeDirectoryComplete, whenFileExists )
import CPM.Repository
import CPM.Repository.CacheDB ( tryInstallRepositoryDB )
import CPM.Repository.Select  ( addPackageToRepositoryCache
                              , updatePackageInRepositoryCache )

------------------------------------------------------------------------------
--- Updates the package index from the central Git repository.
--- If the second argument is `True`, also the global package cache
--- is cleaned in order to support downloading the newest versions.
--- If the third argument is `True`, the global package index is recreated
--- by downloading it from the central repository.
--- If the fourth argument is `True`, the package database is created
--- by reading the CSV file `REPOSITORY_CACHE.csv` downloaded from
--- the tar files URL, otherwise by reading all package specifications.
--- If the fifth argument is `True`, also a CSV file containing the
--- database entries is written.
updateRepository :: Config -> Bool -> Bool -> Bool -> Bool -> ErrorLogger ()
updateRepository cfg cleancache download usecache writecsv = do
  let repodir    = repositoryDir cfg
      repodirbak = repodir ++ ".BAK"
  logDebug $ "Recreating package index: '" ++ repodir ++ "'"
  if download
    then do
      liftIOEL $ do removeDirectoryComplete repodirbak
                    renameDirectory repodir repodirbak -- save old repo
                    recreateDirectory repodir
      c <- inDirectoryEL repodir (tryDownload (packageIndexURLs cfg))
      if c == 0
        then finishUpdate >> liftIOEL (removeDirectoryComplete repodirbak)
        else do logDebug "Keeping old package index"
                liftIOEL $ do removeDirectoryComplete repodir
                              renameDirectory repodirbak repodir
                fail $ "Failed to update package index, return code " ++ show c
    else tryInstallRepositoryDB cfg usecache writecsv
  when cleancache $ do
    logDebug $ "Deleting global package cache: '" ++
               packageInstallDir cfg ++ "'"
    liftIOEL $ removeDirectoryComplete $ packageInstallDir cfg
 where
  tryDownload []         = return 1
  tryDownload (url:urls) = do c <- downloadCommand url
                              if c == 0 then return 0
                                        else tryDownload urls

  downloadCommand piurl
    | ".git" `isSuffixOf` piurl
    = let qcmd q = unwords ["git clone", q, quote piurl, "."]
      in execQuietCmd (qcmd "-q") (qcmd "")
    | ".tar" `isSuffixOf` piurl
    = do let tarfile = "INDEX.tar"
         curlcmd <- getCurlCmd
         c1 <- showExecCmd $ unwords [curlcmd, "-o", tarfile, quote piurl]
         c2 <- showExecCmd $ unwords ["tar", "-xf", tarfile]
         liftIOEL $ whenFileExists tarfile $ removeFile tarfile
         return (c1 + c2)
    | ".tar.gz" `isSuffixOf` piurl
    = do let tarfile = "INDEX.tar.gz"
         curlcmd <- getCurlCmd
         c1 <- showExecCmd $ unwords [curlcmd, "-o", tarfile, quote piurl]
         c2 <- showExecCmd $ unwords ["tar", "-xzf", tarfile]
         liftIOEL $ whenFileExists tarfile $ removeFile tarfile
         return (c1 + c2)
    | otherwise
    = do logError $ "Unknown kind of package index URL: " ++ piurl
         return 1

  finishUpdate = do
    setLastUpdate cfg
    cleanRepositoryCache cfg
    logInfo "Successfully downloaded repository index"
    tryInstallRepositoryDB cfg usecache writecsv

--- Sets the date of the last update by touching README.md.
setLastUpdate :: Config -> ErrorLogger ()
setLastUpdate cfg = do
  showExecCmd $ unwords ["touch", repositoryDir cfg </> "README.md"]
  return ()

------------------------------------------------------------------------------
--- Adds a package stored in the given directory to the repository index.
--- If the argument `force` is true, overwrite an already existing package.
--- If the argument `cpdir` is true, copy also the complete directory
--- into the local package installation store.
addPackageToRepository :: Config -> String -> Bool -> Bool -> ErrorLogger ()
addPackageToRepository cfg pkgdir force cpdir = do
  dirExists <- liftIOEL $ doesDirectoryExist pkgdir
  if dirExists
    then do pkgSpec <- loadPackageSpec pkgdir
            copyPackage pkgSpec
            logInfo $ "Package in directory '" ++ pkgdir ++
                          "' installed into local repository"
    else logCritical $ "Directory '" ++ pkgdir ++ "' does not exist."
 where
  copyPackage pkg = do
    let pkgIndexDir      = name pkg </> showVersion (version pkg)
        pkgRepositoryDir = repositoryDir cfg </> pkgIndexDir
        pkgInstallDir    = packageInstallDir cfg </> packageId pkg
    exrepodir <- liftIOEL $ doesDirectoryExist pkgRepositoryDir
    when (exrepodir && not force) $ error $
      "Package repository directory '" ++
      pkgRepositoryDir ++ "' already exists!\n"
    expkgdir <- liftIOEL $ doesDirectoryExist pkgInstallDir
    when expkgdir $
      if force then liftIOEL $ removeDirectoryComplete pkgInstallDir
               else error $ "Package installation directory '" ++
                            pkgInstallDir ++ "' already exists!\n"
    logInfo $ "Create directory: " ++ pkgRepositoryDir
    liftIOEL $ do
      createDirectoryIfMissing True pkgRepositoryDir
      copyFile (pkgdir </> packageSpecFile)
               (pkgRepositoryDir </> packageSpecFile)
    when cpdir $ do
      liftIOEL $ copyDirectory pkgdir pkgInstallDir
      inDirectoryEL pkgInstallDir $ cleanPackage cfg Debug
    if exrepodir then updatePackageInRepositoryCache cfg pkg
                 else addPackageToRepositoryCache    cfg pkg

------------------------------------------------------------------------------
types:

              
unsafe:
unsafe due to modules Data.Global System.IO.Unsafe