packages feed

hsec-sync-0.1.0.0: src/Security/Advisories/Sync.hs

{-# LANGUAGE DerivingStrategies #-}

module Security.Advisories.Sync
  ( Repository (..),
    defaultRepository,
    SyncStatus (..),
    sync,
    RepositoryStatus (..),
    status,
  )
where

import Data.Time (zonedTimeToUTC)
import Security.Advisories.Sync.Atom
import Security.Advisories.Sync.Git

data SyncStatus
  = Created
  | Updated
  | AlreadyUpToDate
  deriving stock (Eq, Show)

sync :: Repository -> IO (Either String SyncStatus)
sync repo = do
  gitStatus <- gitRepositoryStatus repo
  ensured <- ensureGitRepositoryWithRemote repo gitStatus
  let mkGitError = Left . explainGitError
  case ensured of
    Left e -> return $ mkGitError e
    Right s ->
      case s of
        GitRepositoryCreated ->
          return $ Right Created
        GitRepositoryExisting -> do
          repoStatus <- status' repo gitStatus
          if repoStatus == DirectoryOutDated
            then either mkGitError (const $ Right Updated) <$> updateGitRepository repo
            else return $ Right AlreadyUpToDate

data RepositoryStatus
  = DirectoryMissing
  | DirectoryEmpty
  | DirectoryUpToDate
  | DirectoryOutDated
  deriving stock (Eq, Show)

status :: Repository -> IO RepositoryStatus
status repo =
  status' repo =<< gitRepositoryStatus repo

status' :: Repository -> GitRepositoryStatus -> IO RepositoryStatus
status' repo gitStatus = do
  case gitStatus of
    GitDirectoryMissing ->
      return DirectoryMissing
    GitDirectoryEmpty ->
      return DirectoryEmpty
    GitDirectoryInitialized -> do
      gitInfo <- getDirectoryGitInfo $ repositoryRoot repo
      case gitInfo of
        Left _ ->
          return DirectoryOutDated
        Right info -> do
          update <- latestUpdate (repositoryUrl repo) (repositoryBranch repo)
          return $
            if update == Right (zonedTimeToUTC $ lastModificationCommitDate info)
              then DirectoryUpToDate
              else DirectoryOutDated

defaultRepository :: Repository
defaultRepository =
  Repository
    { repositoryUrl = "https://github.com/haskell/security-advisories",
      repositoryRoot = "security-advisories",
      repositoryBranch = "main"
    }