content: {-
    Copyright (c) Meta Platforms, Inc. and affiliates.
    All rights reserved.
  
    This source code is licensed under the BSD-style license found in the
    LICENSE file in the root directory of this source tree.
  -}
  
  module Util (withFixtureOptions) where
  
  import Data.List
  import System.Directory
  import System.FilePath
  
  import Thrift.Compiler.Options
  import Thrift.Compiler.OptParse
  import Thrift.Compiler.Plugins.Haskell
  import Thrift.Compiler.Plugins.Linter
  
  withFixtureOptions :: ([SomeOptions] -> IO a) -> IO a
  withFixtureOptions f = do
    dir <- getCurrentDirectory
    compilerDir <- findCompilerDir dir
    let outPath = if inTree
          then "compiler" </> "test" </> "fixtures"
          else                "test" </> "fixtures"
        inTree = takeBaseName compilerDir == "compiler"
        testsCwd = if inTree then takeDirectory compilerDir else compilerDir
        includePathFor fp
          | inTree, "compiler/" `isPrefixOf` fp = "compiler"
          | "tests/" `isPrefixOf` fp = "tests"
          | otherwise = "."
        fixup fp
          | Just rest <- stripPrefix "compiler/" fp = rest
          | Just rest <- stripPrefix "tests/" fp = rest
          | otherwise = fp
  
    withCurrentDirectory testsCwd $ f
      [ TheseOptions (defaultOptions langopts)
           { optsPath = fixup path
           , optsOutPath = outPath </> genDir
           , optsIncludePath = includePathFor path
           , optsRecursive = True
           , optsGenMode = mode
           , optsSingleOutput = singleOut
           }
      | (TheseLangOpts langopts, mode, singleOut, genDir, path) <-
           [ (TheseLangOpts defaultHsOpts, EmitCode, False, "",
              "tests/if/hs_test.thrift")
           , (TheseLangOpts defaultHsOpts{hsoptsExtraHasFields=True},
              EmitCode, False, "",
              "tests/if/service.thrift")
           , (TheseLangOpts defaultHsOpts, EmitCode, False, "",
              "compiler/test/if/a.thrift")
           , (TheseLangOpts NoOpts, EmitJSON WithoutLoc, False, "gen-basic",
              "compiler/test/if/a.thrift")
           , (TheseLangOpts NoOpts, EmitJSON WithoutLoc, True, "gen-single-out",
              "compiler/test/if/a.thrift")
           , (TheseLangOpts NoOpts, EmitJSON WithLoc, False, "gen-basic-loc",
              "compiler/test/if/a.thrift")
           , (TheseLangOpts NoOpts, EmitJSON WithLoc, True, "gen-single-out-loc",
              "compiler/test/if/a.thrift")
           ]
      ]
  
  findCompilerDir :: FilePath -> IO FilePath
  findCompilerDir cwd = lookFor "thrift-compiler.cabal" cwd maxDepth >>= \mdir ->
    case mdir of
      Nothing -> error "findCompilerDir: reached max depth, couldn't find thrift-compiler.cabal"
      Just d  -> return d
  
    where lookFor _ _ (-1) = return Nothing
          lookFor file curDir depth = do
            existsHere <- doesFileExist (curDir </> file)
            if existsHere
              then return (Just curDir)
              else do xs <- listDirectory curDir
                      visitDirsIn xs file curDir depth
          visitDirsIn [] _ _ _ = return Nothing
          visitDirsIn (d:ds) file curDir depth = do
            dirExists <- doesDirectoryExist (curDir </> d)
            if dirExists
              then do mfp <- lookFor file (curDir </> d) (depth-1)
                      case mfp of
                        Nothing -> visitDirsIn ds file curDir depth
                        Just fp -> return (Just fp)
              else visitDirsIn ds file curDir depth
          maxDepth = 2 :: Int
  