aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/Input.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/src/Input.hs')
-rw-r--r--compiler/src/Input.hs126
1 files changed, 126 insertions, 0 deletions
diff --git a/compiler/src/Input.hs b/compiler/src/Input.hs
new file mode 100644
index 0000000..cb837e3
--- /dev/null
+++ b/compiler/src/Input.hs
@@ -0,0 +1,126 @@
1-- ldgallery - A static generator which turns a collection of tagged
2-- pictures into a searchable web gallery.
3--
4-- Copyright (C) 2019-2020 Pacien TRAN-GIRARD
5--
6-- This program is free software: you can redistribute it and/or modify
7-- it under the terms of the GNU Affero General Public License as
8-- published by the Free Software Foundation, either version 3 of the
9-- License, or (at your option) any later version.
10--
11-- This program is distributed in the hope that it will be useful,
12-- but WITHOUT ANY WARRANTY; without even the implied warranty of
13-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-- GNU Affero General Public License for more details.
15--
16-- You should have received a copy of the GNU Affero General Public License
17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19module Input
20 ( decodeYamlFile
21 , Sidecar(..)
22 , InputTree(..), readInputTree
23 ) where
24
25
26import GHC.Generics (Generic)
27import Control.Exception (Exception, AssertionFailed(..), throw, throwIO)
28import Control.Monad.IO.Class (MonadIO, liftIO)
29import Data.Function ((&))
30import Data.Maybe (catMaybes)
31import Data.Bool (bool)
32import Data.List (find)
33import Data.Time.Clock (UTCTime)
34import Data.Time.LocalTime (ZonedTime)
35import Data.Yaml (ParseException, decodeFileEither)
36import Data.Aeson (FromJSON)
37import System.FilePath (isExtensionOf, dropExtension)
38import System.Directory (doesFileExist, getModificationTime)
39
40import Files
41
42
43data LoadException = LoadException String ParseException deriving Show
44instance Exception LoadException
45
46decodeYamlFile :: (MonadIO m, FromJSON a) => FileName -> m a
47decodeYamlFile path =
48 liftIO $ Data.Yaml.decodeFileEither path
49 >>= either (throwIO . LoadException path) return
50
51
52-- | Tree representing the input from the input directory.
53data InputTree =
54 InputFile
55 { path :: Path
56 , modTime :: UTCTime
57 , sidecar :: Sidecar }
58 | InputDir
59 { path :: Path
60 , modTime :: UTCTime
61 , dirThumbnailPath :: Maybe Path
62 , items :: [InputTree] }
63 deriving Show
64
65data Sidecar = Sidecar
66 { title :: Maybe String
67 , datetime :: Maybe ZonedTime
68 , description :: Maybe String
69 , tags :: Maybe [String]
70 } deriving (Generic, FromJSON, Show)
71
72emptySidecar :: Sidecar
73emptySidecar = Sidecar
74 { title = Nothing
75 , datetime = Nothing
76 , description = Nothing
77 , tags = Nothing }
78
79sidecarExt :: String
80sidecarExt = "yaml"
81
82readSidecarFile :: FilePath -> IO Sidecar
83readSidecarFile filepath =
84 doesFileExist filepath
85 >>= bool (return Nothing) (decodeYamlFile filepath)
86 >>= return . maybe emptySidecar id
87
88
89readInputTree :: AnchoredFSNode -> IO InputTree
90readInputTree (AnchoredFSNode _ File{}) =
91 throw $ AssertionFailed "Input directory is a file"
92readInputTree (AnchoredFSNode anchor root@Dir{}) = mkDirNode root
93 where
94 mkInputNode :: FSNode -> IO (Maybe InputTree)
95 mkInputNode file@File{path}
96 | (not $ isSidecar file) && (not $ isThumbnail file) =
97 do
98 sidecar <- readSidecarFile $ localPath (anchor /> path <.> sidecarExt)
99 modTime <- getModificationTime $ localPath (anchor /> path)
100 return $ Just $ InputFile path modTime sidecar
101 mkInputNode File{} = return Nothing
102 mkInputNode dir@Dir{} = mkDirNode dir >>= return . Just
103
104 mkDirNode :: FSNode -> IO InputTree
105 mkDirNode File{} = throw $ AssertionFailed "Input directory is a file"
106 mkDirNode Dir{path, items} =
107 do
108 dirItems <- mapM mkInputNode items
109 modTime <- getModificationTime $ localPath (anchor /> path)
110 return $ InputDir path modTime (findThumbnail items) (catMaybes dirItems)
111
112 isSidecar :: FSNode -> Bool
113 isSidecar Dir{} = False
114 isSidecar File{path} =
115 fileName path
116 & (maybe False $ isExtensionOf sidecarExt)
117
118 isThumbnail :: FSNode -> Bool
119 isThumbnail Dir{} = False
120 isThumbnail File{path} =
121 fileName path
122 & fmap dropExtension
123 & (maybe False ("thumbnail" ==))
124
125 findThumbnail :: [FSNode] -> Maybe Path
126 findThumbnail = (fmap Files.path) . (find isThumbnail)