{-# LANGUAGE CPP #-}moduleDistribution.Simple.UUAGC.UUAGC(uuagcUserHook,uuagcUserHook',uuagc,uuagcLibUserHook,uuagcFromString)whereimportDistribution.Simple.BuildPaths(autogenModulesDir)importDebug.TraceimportDistribution.SimpleimportDistribution.Simple.PreProcessimportDistribution.Simple.LocalBuildInfoimportDistribution.Simple.UtilsimportDistribution.Simple.SetupimportDistribution.PackageDescriptionhiding(Flag)importDistribution.Simple.UUAGC.AbsSyn(AGFileOption(..),AGFileOptions,AGOptionsClass(..),lookupFileOptions,fileClasses)importDistribution.Simple.UUAGC.ParserimportOptionshiding(verbose)importDistribution.VerbosityimportSystem.Process(CreateProcess(..),createProcess,CmdSpec(..),StdStream(..),runProcess,waitForProcess,shell)importSystem.Directory(getModificationTime,doesFileExist,removeFile)importSystem.FilePath(pathSeparators,(</>),takeFileName,normalise,joinPath,dropFileName,addExtension,dropExtension,splitDirectories)importSystem.Exit(ExitCode(..))importSystem.IO(openFile,IOMode(..),hFileSize,hSetFileSize,hClose,hGetContents,hFlush,Handle(..),stderr,hPutStr,hPutStrLn)importSystem.Exit(exitFailure)importControl.Exception(throwIO)importControl.Monad(liftM,when,guard,forM_,forM)importControl.Arrow((&&&),second)importData.Maybe(maybeToList)importData.Either(partitionEithers)importData.List(nub){-# DEPRECATED uuagcUserHook, uuagcUserHook', uuagc "Use uuagcLibUserHook instead" #-}-- | 'uuagc' returns the name of the uuagc compileruuagcn="uuagc"-- | 'defUUAGCOptions' returns the default names of the uuagc optionsdefUUAGCOptions::StringdefUUAGCOptions="uuagc_options"-- | File used to store de classes defined in the cabal file.agClassesFile::StringagClassesFile="ag_file_options"-- | The prefix used for the cabal file optionswagModule::StringagModule="x-agmodule"-- | The prefix used for the cabal file options used for defining classesagClass::StringagClass="x-agclass"-- | Deprecated userhookuuagcUserHook::UserHooksuuagcUserHook=uuagcUserHook'uuagcn-- | Deprecated userhookuuagcUserHook'::String->UserHooksuuagcUserHook'uuagcPath=uuagcLibUserHook(uuagcFromStringuuagcPath)-- | Create uuagc function using shell (old method)uuagcFromString::String->[String]->FilePath->IO(ExitCode,[FilePath])uuagcFromStringuuagcPathargsfile=doletargline=uuagcPath++concatMap(' ':)(args++[file])(_,JustppOutput,JustppError,ph)<-createProcess(shellargline){std_in=Inherit,std_out=CreatePipe,std_err=CreatePipe}ec<-waitForProcessphcaseecofExitSuccess->dofls<-processContentppOutputreturn(ExitSuccess,fls)(ExitFailureexc)->dohPutStrLnstderr(uuagcPath++": "++showexc)putErrorInfoppOutputputErrorInfoppErrorreturn(ExitFailureexc,[])-- | Main hook, argument should be uuagc functionuuagcLibUserHook::([String]->FilePath->IO(ExitCode,[FilePath]))->UserHooksuuagcLibUserHookuuagc=hookswherehooks=simpleUserHooks{hookedPreProcessors=("ag",ag):("lag",ag):knownSuffixHandlers,buildHook=uuagcBuildHookuuagc,sDistHook=uuagcSDistHookuuagc}ag=uuagc'uuagcoriginalPreBuild=preBuildsimpleUserHooksoriginalBuildHook=buildHooksimpleUserHooksoriginalSDistHook=sDistHooksimpleUserHooksprocessContent::Handle->IO[String]processContent=liftMwords.hGetContentsputErrorInfo::Handle->IO()putErrorInfoh=hGetContentsh>>=hPutStrstderraddSearch::String->[String]->[String]addSearchspfl=letsf=[headpathSeparators]path=ifsp==""then'.':sfelsesp++sfin[normalise(joinPath[sp,f])|f<-fl]throwFailure::IO()throwFailure=throwIO$ExitFailure1-- The tmp build directory really depends on the type of project.-- In the case executables it uses the name of the generated file for-- the output directory.withBuildTmpDir::PackageDescription->LocalBuildInfo->(FilePath->IO())->IO()withBuildTmpDirpkgDescrlbif=do#if MIN_VERSION_Cabal(1,8,0)withLibpkgDescr$\_->f$buildDirlbi#elsewithLibpkgDescr()$\_->f$buildDirlbi#endifwithExepkgDescr$\theExe->f$buildDirlbi</>exeNametheExe</>exeNametheExe++"-tmp"-- | 'updateAGFile' search into the uuagc options file for a list of all-- AG Files and theirs file dependencies in order to see if the latters-- are more updated that the formers, and if this is the case to-- update the AG FileupdateAGFile::([String]->FilePath->IO(ExitCode,[FilePath]))->FilePath->PackageDescription->LocalBuildInfo->(FilePath,String)->IO()updateAGFileuuagcclassesPathpkgDescrlbi(f,sp)=dofileOpts<-readFileOptionsclassesPathletopts=caselookupffileOptsofNothing->noOptionsJustx->x(ec,fls)<-uuagc(optionsToString$opts{genFileDeps=True,searchPath=sp:(searchPathopts)})fcaseecofExitSuccess->doletflsC=addSearchspflswhen((not.null)flsC)$doflsmt<-mapMgetModificationTimeflsCletmaxModified=maximumflsmtremoveTmpFilefbuildTmp=do-- For src/a/b/c.ag and build, this creates ["build/src/a/b/c.hs","build/a/b/c.hs","build/b/c.hs","build/c.hs"]-- Problem is we don't know what prefix of the filename is src directory and what part is in the classname-- There must be a better solution for this...letfiles=map(buildTmp</>).scanr1(</>).splitDirectories.(`addExtension`"hs").dropExtension$fforM_files$\f->doexists<-doesFileExistfwhenexists$dofmt<-getModificationTimefwhen(maxModified>fmt)$removeFilefwithBuildTmpDirpkgDescrlbi$removeTmpFilef(ExitFailureexc)->dohPutStrLnstderr(showexc)throwFailuregetAGFileOptions::[(String,String)]->IOAGFileOptionsgetAGFileOptionsextra=dousesOptionsFile<-doesFileExistdefUUAGCOptionsifusesOptionsFilethendor<-parserAG'defUUAGCOptionscaserofLefte->printe>>exitFailureRighta->returnaelsemapM(parseOptionAG.snd)$filter((==agModule).fst)extragetAGClasses::[(String,String)]->IO[AGOptionsClass]getAGClasses=mapM(parseClassAG.snd).filter((==agClass).fst)writeFileOptions::FilePath->[(String,Options)]->IO()writeFileOptionsclassesPathopts=dohClasses<-openFileclassesPathWriteModehPutStrhClasses$show[(s,optionsToStringopt)|(s,opt)<-opts]hFlushhClasseshClosehClassesreadFileOptions::FilePath->IO[(String,Options)]readFileOptionsclassesPath=dohClasses<-openFileclassesPathReadModesClasses<-hGetContentshClassesclasses<-readIOsClasses::IO[(String,[String])]hClosehClassesreturn$[(s,opt)|(s,str)<-classes,let(opt,_,_)=getOptionsstr]getOptionsFromClass::[(String,Options)]->AGFileOption->([String],Options)getOptionsFromClassclassesfOpt=second(foldlcombineOptions(optsfOpt)).partitionEithers$dofClass<-fileClassesfOptcasefClass`lookup`classesofJustx->return$RightxNothing->return$Left$"Warning: The class "++showfClass++" is not defined."uuagcSDistHook::([String]->FilePath->IO(ExitCode,[FilePath]))->PackageDescription->MaybeLocalBuildInfo->UserHooks->SDistFlags->IO()uuagcSDistHookuuagcpdmbLbiuhdf=do{-
case mbLbi of
Nothing -> warn normal "sdist: the local buildinfo was not present. Skipping AG initialization. Dist may fail."
Just lbi -> let classesPath = buildDir lbi </> agClassesFile
in commonHook uuagc classesPath pd lbi (sDistVerbosity df)
originalSDistHook pd mbLbi uh df
-}originalSDistHookpdmbLbi(uh{hookedPreProcessors=("ag",nouuagc):("lag",nouuagc):knownSuffixHandlers})df-- bypass preprocessorsuuagcBuildHook::([String]->FilePath->IO(ExitCode,[FilePath]))->PackageDescription->LocalBuildInfo->UserHooks->BuildFlags->IO()uuagcBuildHookuuagcpdlbiuhbf=doletclassesPath=buildDirlbi</>agClassesFilecommonHookuuagcclassesPathpdlbi(buildVerbositybf)originalBuildHookpdlbiuhbfcommonHook::([String]->FilePath->IO(ExitCode,[FilePath]))->FilePath->PackageDescription->LocalBuildInfo->FlagVerbosity->IO()commonHookuuagcclassesPathpdlbifl=doletverbosity=fromFlagOrDefaultnormalflwhen(verbosity>=verbose)$putStrLn("commonHook: Assuming AG classesPath: "++classesPath)createDirectoryIfMissingVerboseverbosityTrue(buildDirlbi)letlib=librarypdexes=executablespdbis=maplibBuildInfo(maybeToListlib)++mapbuildInfoexesclasses<-map(className&&&opts')`fmap`(getAGClasses.customFieldsPD$pd)options<-getAGFileOptions(bis>>=customFieldsBI)fileOptions<-forMoptions(\opt->let(notFound,opts)=getOptionsFromClassclasses$optindowhen(verbosity>=verbose)$putStrLn("options for "++filenameopt++": "++unwords(optionsToStringopts))forM_notFound(hPutStrLnstderr)>>return(normalise.filename$opt,opts))writeFileOptionsclassesPathfileOptionsletagflSP=map(id&&&dropFileName)$nub$getAGFileListoptionsmapM_(updateAGFileuuagcclassesPathpdlbi)agflSPgetAGFileList::AGFileOptions->[FilePath]getAGFileList=map(normalise.filename)uuagc::BuildInfo->LocalBuildInfo->PreProcessoruuagc=uuagc'(uuagcFromStringuuagcn)uuagc'::([String]->FilePath->IO(ExitCode,[FilePath]))->BuildInfo->LocalBuildInfo->PreProcessoruuagc'uuagcbuildlbi=PreProcessor{platformIndependent=True,runPreProcessor=mkSimplePreProcessor$\inFileoutFileverbosity->doinfoverbosity$concat[inFile," has been preprocessed into ",outFile]print$"processing: "++inFile++" generating: "++outFile-- opts <- getAGFileOptions $ customFieldsBI buildletclassesPath=buildDirlbi</>agClassesFilewhen(verbosity>=verbose)$putStrLn("uuagc-preprocessor: Assuming AG classesPath: "++classesPath)fileOpts<-readFileOptionsclassesPathletopts=caselookupinFilefileOptsofNothing->noOptionsJustx->xsearch=dropFileNameinFileoptions=opts{searchPath=search:(searchPathopts),outputFiles=outFile:(outputFilesopts)}(eCode,_)<-uuagc(optionsToStringoptions)inFilecaseeCodeofExitSuccess->return()ExitFailure_->throwFailure}nouuagc::BuildInfo->LocalBuildInfo->PreProcessornouuagcbuildlbi=PreProcessor{platformIndependent=True,runPreProcessor=mkSimplePreProcessor$\inFileoutFileverbosity->doinfoverbosity("skipping: "++outFile)}