{-# LANGUAGE TemplateHaskell #-} module Development.Duplo.Files where import Control.Lens hiding (Action) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Maybe (MaybeT (..)) import Development.Duplo.Component (appId) import qualified Development.Duplo.Component as CM import Development.Shake (Action, liftIO, readFile') import System.FilePath.Posix (joinPath, makeRelative, splitDirectories) type FileName = String type FileContent = String type ComponentId = String data File = File { _filePath :: FilePath , _fileDir :: FilePath , _fileName :: FileName , _componentId :: ComponentId , _fileContent :: String -- Is this part of the root project? , _isRoot :: Bool } deriving (Show) pseudoFile :: File pseudoFile = File { _filePath = "" , _fileDir = "" , _fileName = "" , _componentId = "" , _fileContent = "" , _isRoot = False } makeLenses ''File readFile :: FilePath -> FilePath -> MaybeT Action File readFile cwd path = do let (fDir, fName) = parseFilePath path fContent <- lift $ readFile' path appInfo <- liftIO CM.readManifest let appId' = appId appInfo let cId = parseComponentId cwd appId' fDir let isRoot' = cId == appId' return $ File path fDir fName cId fContent isRoot' parseFilePath :: FilePath -> (FilePath, FileName) parseFilePath path = (fDir, fName) where segments = splitDirectories path segLength = length segments dirLength = segLength - 1 fDir = joinPath $ take dirLength segments fName = segments !! dirLength -- | Given a default component ID (usually the ID of the project on which -- duplo is run) and the file path, deduce the component ID of a particular -- file parseComponentId :: FilePath -> ComponentId -> FilePath -> ComponentId parseComponentId cwd defaultId path = let relPath = makeRelative cwd path segments = splitDirectories relPath in case segments of ("components" : aId : _) -> aId _ -> defaultId