PfeBrowserCerts.hs

module PfeBrowserCerts where
import Prelude hiding (putStr,putStrLn,print,readFile,ioError,catch,readIO)
import AllFudgets as Fud hiding (getModificationTime)
import FudDraw
import Maybe(isJust,listToMaybe,mapMaybe)
import MUtils
import AbstractIO
import FileUtils(readFileNow)
import DirUtils(latestModTime)
import List((\\))

import PfePlumbing
import PfeBrowserMonad
import PPU(pp{-,ppi,ppu,withPPEnv,($$),(<>),(<+>),PPHsMode-})
import PFE0
import PFE_Certs
import CertCmd
import CertServers(certFiles,lookupServer)
import PfePropCmds(tassertionSignature)
import CertAttrs(label)
import DrawLex(cstatusIcon,certIcon)
import QualNames(getQualified)
import TypedIds
import HsIdent(HsIdentI(..))
import TiNames(topName)

evidenceGfx: this function computes the table that is shown in the Evidence window. Every existing certificate, certificate annotation and assertion will be mentioned in one of the table entries.

evidenceGfx m dir (bad,icons) certs asserts =
    htableD hdrs (concatMap certD certs++concatMap missingD missing)
  where
    hdrs = ["Icon","Name","Sequent (or other info)"]
    missing = [a|(a,_)<-asserts,pp a `notElem` concs]
    concs = mapMaybe (lookup "conc" @@ fst.snd) certs

    missingD a = [g bad,createCertD "" s,"?" |- HsCon a]
      where s = pp a

    certD (cert,(optattrs,status)) =
      case optattrs of
	Nothing -> [g bad,certNameD cert,
		    g "certificate does not exist (not created yet?)"]
	Just attrs ->
	  case (`lookup` icons) =<< lookup "type" attrs of
	    Just cicons ->
		[certIconD cert icon,certNameD cert, hyp |- a]
	      where
		icon = cstatusIcon cicons status
	    _ -> [g bad,certNameD cert,g "bad cert/unknown cert type"]
	  where
	    conc = fromMaybe "-" (lookup "conc" attrs)
	    hyp = fromMaybe "" (lookup "hyp" attrs)
	    --sequent = conc++" -| "++hyp
	    a = HsCon (topName Nothing m conc Assertion)

    certIconD cert icon = labelD (CertLbl cert) (g icon)

    hyp |- conc = hboxcD [g hyp,g "|-", assertionD conc]

    assertionD a = labelD (DefLbl a) (ulinkD (g (pp a)))

getAssertionInfo: compute the extra info that is shown when the user clicks on an assertion name.

getAssertionInfo (n,Assertion) =
  do allcs <- certs # getStBr
     cicons <- icons # getStBr
     let a = pp (getQualified n)
	 certs = [c|c@(_,(Just attrs,_))<-allcs,lookup "conc" attrs==Just a]
	 newc = head ((a:[a++show n|n<-[1..]])\\map fst allcs)
	 cis = [(cert,certIcon cicons cert)|cert<-certs]
     return [hboxcD' 10 (g "Certificates:":
			 (if null certs
			 then [g "none."]
			 else map certNameIconD cis)
			 ++[createCertD newc a])]
getAssertionInfo _ = return []


visibleStatusChange: calling showCertInfo or showQCertInfo can cause the status of a certificate to be updated. This function returns true when the status of a certificate in the current module changed, in which case certificate icons should be redrawn and the internal state should be updated.

statusChange cert =
  do m <- modname # getStBr
     newstatus <- fmap fst # certStatus m cert
     oldstatus <- ((fmap fst . snd) # ) . lookup cert . certs # getStBr
     return $ Just newstatus/=oldstatus

showCertInfo: computes the certificate information displayed when the user clicks on a certificate icon. This includes checking whether the certificate is valid, invalid or outofdate.

showCertInfo cert =
  do m <- modname # getStBr
     showQCertInfo (QCertName m cert)

showQCertInfo qcert =
    maybe idle inProgress . listToMaybe . certInProgress =<< getStBr
  where
    idle = showQCertInfo' qcert
    inProgress cmd =
      case cmdCert cmd of
        Just qcert' -> inProgress' cmd qcert'
	_ -> idle
    inProgress' cmd qcert' =
      if qcert'==qcert
      then popupCertInfo qcert $
	     spacedD centerS $
	     vboxD [g $ "Certificate server command in progress:",
		    g (shellCmd cmd)]
      else idle

showQCertInfo' qcert =
    do certinfo <- getCertDescription qcert
       pfePut (toRefs (linesD (briefTxt certinfo)))
       popupCertInfo qcert (fullGfx certinfo)
  where
    briefTxt (Left (msg,actionD)) = [g msg,actionD]
    briefTxt (Right (fields,_)) = map (g.join) (take 3 fields)
      where join (x,y) = x++": "++y

    fullGfx (Left (msg,actionD)) = vboxD [Fud.g msg,actionD]
    fullGfx (Right (fields,actionD)) =
	vboxD [htableD ["Field","Value"] flatfields,actionD]
      where flatfields = concatMap (\(x,y)->[g x,g y]) fields

    getCertDescription (QCertName m cert) =
      withWaitCursor $ 
      do let msg =g ("Checking status of certificate "++cert)
         putInfoWindow (CertInfo,msg)
	 pfePut (toRefs msg)
         dir <- checkProject
	 servers <- certServers # getStBr
	 (revalidate,status,info) <- certUpdStatus dir m =<< certInfo m cert
	 --let status = "Unknown"
	 optlogfile <- do let logfile = certDiagnosticsPath m cert dir
			  r <- try (readFileNow logfile)
			  return $ case r of
			             Right txt@(_:_) -> Just txt
			             _ -> Nothing

         return (certDescription (m,revalidate,optlogfile,status,servers) info)

    certDescription _ (cert,(Nothing,_)) =
        Left (cert++": certificate does not exist (not created yet?)", actionD)
      where
        actionD = createCertD cert ""

    certDescription (m,revalidate,optlogfile,status',servers)
                    (cert,(Just attrs,status)) =
      Right ([("Certificate",(cert++" :: "++ctype)),
              ("Current Status",status')]
--	     ++ cfield "Certifies" "conc"
--	     ++ cfield "Depends on" "hyp"
	     ++ showStatus status
	     ++ concat [cfield (label attrs) name|(name,attrs)<-cattrs]
	     ++ cfield "Created by" "who"
	     ++ sfield "About this certificate type" "description",
	     actionD)
      where
	showStatus Nothing = cfield "Date" "date"
	showStatus (Just (valid,when)) =
          [("Marked "++(if valid then "" else "in")++"valid on",show when)]

        ctype = fromMaybe "missing!!" (lookup "type" attrs)
	optserver = lookupServer servers ctype
	sattrs = maybe [] serverAttrs optserver
	cattrs = maybe [] certAttrs optserver
        cfield = field attrs
	sfield = field sattrs
        field attrs hdr name = maybe [] ((:[]).((,) hdr)) (lookup name attrs)

        actionD = hboxD' 20 (revalD++editD++logfileD++removeD)
          where
	    revalD  = if revalidate then [cmdD reval "Validate"] else []
	    removeD = [cmdD rm "Remove"]
	    logfileD = maybe [] logfile optlogfile
	      where
                logfile txt= [cmdD' (CertShowText txt) "View diagnostic output"]
	    editD =
	      if isJust optserver
	      then [cmdD' (CertEdit (ctype,(cert,attrs))) "Edit"]
	      else []

            cmdD  = cmdD' . CertCmd
            cmdD' cmd lbl = labelD cmd (ulinkD (g lbl))

            reval = ValidateCert mcert
	    rm    = RemoveCert mcert
	    mcert = QCertName m cert

    --showType = pfePut . toRefs @@ getType

revalidateAll =
    withWaitCursor $
    do dir <- checkProject
       m <- modname # getStBr
       mapM_ (certUpdStatus dir m @@ certInfo m . fst) . certs =<< getStBr

certUpdStatus dir m info@(cert,(a@(Just attrs),Just (valid,when))) =
    ifM auxchange (revalidate "auxiliary file changed/missing") $
    ifM srcchange
	(if valid
	 then certStatusFromSig
	 else revalidate "was invalid, some source file has been changed") $
    return (not valid,if valid then "Valid" else "Invalid",info)
  where
    auxchange = let auxfiles = certAuxFiles m cert attrs dir
		in anyChangeSince when auxfiles
    srcchange = do srcfiles <- map fst # getSubGraph (Just [m])
		   anyChangeSince when srcfiles -- not cached??

    revalidate why = return (True,"Needs revalidation ("++why++")",info)

    isUnconditionalCert =
      case (lookup "conc" attrs,lookup "hyp" attrs) of
	(Just conc,Just "..") -> Just conc
	_ -> lookup "test" attrs -- TestCase

    certStatusFromSig =
	maybe unknownStatus uncondCertStatusFromSig isUnconditionalCert

    unknownStatus = return (True,"unknown",info)

    uncondCertStatusFromSig conc =
      do optcertsig <-
	   maybeM (readIO =<< readFile (certDir m cert dir++"/deps"))
	 case optcertsig of
	   Nothing -> return (True,"New, not yet validated",info)
	   Just certsig ->
	     do srcsig <- tassertionSignature ((m,conc),Nothing)
		if certsig==srcsig
		  then do markValid m cert
			  st <- certStatus m cert
			  return (False,"Valid",(cert,(a,st)))
		  else revalidate "source changed"

    -- vaid/invalid status missing:
certUpdStatus _ _ info@(_,(Just _,_)) =
    return (True,"New, not yet validated",info)

    -- attributes missing:
certUpdStatus _ _ info = return (False,"unknown (attributes missing?!)",info)

quickCertsStatus m certs dir =
  do srcdate <- latestModTime . map fst =<< getSubGraph (Just [m])
     mapM (quickCertStatus m srcdate dir) certs

quickCertStatus m srcdate dir cert =
  do (optattrs,status) <- snd # certInfo m cert
     case (,) # optattrs <# status of
       Nothing -> return Nothing
       Just (attrs,status@(valid,when)) ->
	 if srcdate>when
	 then return Nothing
	 else ifM (anyChangeSince when (certAuxFiles m cert attrs dir))
		  (return Nothing)
		  (return (Just status))

--allCertFiles m cert dir = (++) # certAuxFiles m cert dir <# certSrcFiles m
certAuxFiles m cert attrs dir = certAttrsPath m cert dir:certFiles attrs
--certSrcFiles m = map fst # getSubGraph [m]

createCertD cert concl = labelD (CreateCert (cert,concl))
			        (ulinkD (g "Create a new certificate!"))

certNameD cert = labelD (CertLbl cert) (ulinkD (g cert))

certNameIconD ((c,_),icon) = labelD (CertLbl c) (hboxD [ulinkD (g c),g icon])

htableD hdrs cells = tableD' 0 (length hdrs) (map b hdrs++map f cells)
  where
    b x = stackD [fgD "grey" (g $ filler False False 5),padD 3 (g x)]
    f x = stackD [fgD "grey" (g frame),padD 3 x]
    --f x = padD 3 x

linesD = fontD defaultFont . vboxlD' 0 -- . map g

anyChangeSince when paths =
   ifM (allM doesFileExist paths)
       ((when<) # latestModTime paths)
       (return True) -- a file has been deleted

Plain-text version of PfeBrowserCerts.hs | Valid HTML?