diff options
Diffstat (limited to 'compiler/src')
-rw-r--r-- | compiler/src/Compiler.hs | 131 | ||||
-rw-r--r-- | compiler/src/Config.hs | 60 | ||||
-rw-r--r-- | compiler/src/Files.hs | 183 | ||||
-rw-r--r-- | compiler/src/Input.hs | 126 | ||||
-rw-r--r-- | compiler/src/Processors.hs | 201 | ||||
-rw-r--r-- | compiler/src/Resource.hs | 198 |
6 files changed, 899 insertions, 0 deletions
diff --git a/compiler/src/Compiler.hs b/compiler/src/Compiler.hs new file mode 100644 index 0000000..a347433 --- /dev/null +++ b/compiler/src/Compiler.hs | |||
@@ -0,0 +1,131 @@ | |||
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 | |||
19 | module Compiler | ||
20 | ( compileGallery | ||
21 | ) where | ||
22 | |||
23 | |||
24 | import Control.Monad (liftM2) | ||
25 | import Data.List (any) | ||
26 | import System.FilePath ((</>)) | ||
27 | import qualified System.FilePath.Glob as Glob | ||
28 | |||
29 | import Data.Aeson (ToJSON) | ||
30 | import qualified Data.Aeson as JSON | ||
31 | |||
32 | import Config | ||
33 | import Input (readInputTree) | ||
34 | import Resource (buildGalleryTree, galleryCleanupResourceDir) | ||
35 | import Files | ||
36 | ( FileName | ||
37 | , FSNode(..) | ||
38 | , readDirectory | ||
39 | , isHidden | ||
40 | , nodeName | ||
41 | , filterDir | ||
42 | , ensureParentDir ) | ||
43 | import Processors | ||
44 | ( itemFileProcessor, thumbnailFileProcessor | ||
45 | , skipCached, withCached ) | ||
46 | |||
47 | |||
48 | galleryConf :: String | ||
49 | galleryConf = "gallery.yaml" | ||
50 | |||
51 | indexFile :: String | ||
52 | indexFile = "index.json" | ||
53 | |||
54 | viewerMainFile :: String | ||
55 | viewerMainFile = "index.html" | ||
56 | |||
57 | viewerConfFile :: String | ||
58 | viewerConfFile = "viewer.json" | ||
59 | |||
60 | itemsDir :: String | ||
61 | itemsDir = "items" | ||
62 | |||
63 | thumbnailsDir :: String | ||
64 | thumbnailsDir = "thumbnails" | ||
65 | |||
66 | |||
67 | writeJSON :: ToJSON a => FileName -> a -> IO () | ||
68 | writeJSON outputPath object = | ||
69 | do | ||
70 | putStrLn $ "Generating:\t" ++ outputPath | ||
71 | ensureParentDir JSON.encodeFile outputPath object | ||
72 | |||
73 | |||
74 | galleryDirFilter :: ([Glob.Pattern], [Glob.Pattern]) -> FSNode -> Bool | ||
75 | galleryDirFilter (inclusionPatterns, exclusionPatterns) = | ||
76 | (not . isHidden) | ||
77 | &&& (matchName True $ anyPattern inclusionPatterns) | ||
78 | &&& (not . isConfigFile) | ||
79 | &&& (not . containsOutputGallery) | ||
80 | &&& (not . (matchName False $ anyPattern exclusionPatterns)) | ||
81 | |||
82 | where | ||
83 | (&&&) = liftM2 (&&) | ||
84 | (|||) = liftM2 (||) | ||
85 | |||
86 | matchName :: Bool -> (FileName -> Bool) -> FSNode -> Bool | ||
87 | matchName matchDir _ Dir{} = matchDir | ||
88 | matchName _ cond file@File{} = maybe False cond $ nodeName file | ||
89 | |||
90 | anyPattern :: [Glob.Pattern] -> FileName -> Bool | ||
91 | anyPattern patterns filename = any (flip Glob.match filename) patterns | ||
92 | |||
93 | isConfigFile = matchName False (== galleryConf) | ||
94 | isGalleryIndex = matchName False (== indexFile) | ||
95 | isViewerIndex = matchName False (== viewerMainFile) | ||
96 | containsOutputGallery File{} = False | ||
97 | containsOutputGallery Dir{items} = any (isGalleryIndex ||| isViewerIndex) items | ||
98 | |||
99 | |||
100 | compileGallery :: FilePath -> FilePath -> Bool -> IO () | ||
101 | compileGallery inputDirPath outputDirPath rebuildAll = | ||
102 | do | ||
103 | fullConfig <- readConfig inputGalleryConf | ||
104 | let config = compiler fullConfig | ||
105 | |||
106 | inputDir <- readDirectory inputDirPath | ||
107 | let inclusionPatterns = map Glob.compile $ includeFiles config | ||
108 | let exclusionPatterns = map Glob.compile $ excludeFiles config | ||
109 | let sourceFilter = galleryDirFilter (inclusionPatterns, exclusionPatterns) | ||
110 | let sourceTree = filterDir sourceFilter inputDir | ||
111 | inputTree <- readInputTree sourceTree | ||
112 | |||
113 | let cache = if rebuildAll then skipCached else withCached | ||
114 | let itemProc = itemProcessor (pictureMaxResolution config) cache | ||
115 | let thumbnailProc = thumbnailProcessor (thumbnailMaxResolution config) cache | ||
116 | let galleryBuilder = buildGalleryTree itemProc thumbnailProc (tagsFromDirectories config) | ||
117 | resources <- galleryBuilder (galleryName config) inputTree | ||
118 | |||
119 | galleryCleanupResourceDir resources outputDirPath | ||
120 | writeJSON outputIndex resources | ||
121 | writeJSON outputViewerConf $ viewer fullConfig | ||
122 | |||
123 | where | ||
124 | inputGalleryConf = inputDirPath </> galleryConf | ||
125 | outputIndex = outputDirPath </> indexFile | ||
126 | outputViewerConf = outputDirPath </> viewerConfFile | ||
127 | |||
128 | itemProcessor maxRes cache = | ||
129 | itemFileProcessor maxRes cache inputDirPath outputDirPath itemsDir | ||
130 | thumbnailProcessor thumbRes cache = | ||
131 | thumbnailFileProcessor thumbRes cache inputDirPath outputDirPath thumbnailsDir | ||
diff --git a/compiler/src/Config.hs b/compiler/src/Config.hs new file mode 100644 index 0000000..53333a5 --- /dev/null +++ b/compiler/src/Config.hs | |||
@@ -0,0 +1,60 @@ | |||
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 | |||
19 | module Config | ||
20 | ( GalleryConfig(..) | ||
21 | , CompilerConfig(..) | ||
22 | , readConfig | ||
23 | ) where | ||
24 | |||
25 | |||
26 | import GHC.Generics (Generic) | ||
27 | import Data.Aeson (FromJSON, withObject, (.:?), (.!=)) | ||
28 | import qualified Data.Aeson as JSON | ||
29 | |||
30 | import Files (FileName) | ||
31 | import Input (decodeYamlFile) | ||
32 | import Resource (Resolution(..)) | ||
33 | |||
34 | |||
35 | data CompilerConfig = CompilerConfig | ||
36 | { galleryName :: String | ||
37 | , includeFiles :: [String] | ||
38 | , excludeFiles :: [String] | ||
39 | , tagsFromDirectories :: Int | ||
40 | , thumbnailMaxResolution :: Resolution | ||
41 | , pictureMaxResolution :: Maybe Resolution | ||
42 | } deriving (Generic, Show) | ||
43 | |||
44 | instance FromJSON CompilerConfig where | ||
45 | parseJSON = withObject "CompilerConfig" $ \v -> CompilerConfig | ||
46 | <$> v .:? "galleryName" .!= "Gallery" | ||
47 | <*> v .:? "includeFiles" .!= ["*"] | ||
48 | <*> v .:? "excludeFiles" .!= [] | ||
49 | <*> v .:? "tagsFromDirectories" .!= 0 | ||
50 | <*> v .:? "thumbnailMaxResolution" .!= (Resolution 400 400) | ||
51 | <*> v .:? "pictureMaxResolution" | ||
52 | |||
53 | |||
54 | data GalleryConfig = GalleryConfig | ||
55 | { compiler :: CompilerConfig | ||
56 | , viewer :: JSON.Object | ||
57 | } deriving (Generic, FromJSON, Show) | ||
58 | |||
59 | readConfig :: FileName -> IO GalleryConfig | ||
60 | readConfig = decodeYamlFile | ||
diff --git a/compiler/src/Files.hs b/compiler/src/Files.hs new file mode 100644 index 0000000..41fc5a8 --- /dev/null +++ b/compiler/src/Files.hs | |||
@@ -0,0 +1,183 @@ | |||
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 | |||
19 | module Files | ||
20 | ( FileName, LocalPath, WebPath, Path(..) | ||
21 | , (</>), (</), (/>), (<.>) | ||
22 | , fileName, subPaths, pathLength | ||
23 | , localPath, webPath | ||
24 | , FSNode(..), AnchoredFSNode(..) | ||
25 | , nodeName, isHidden, flattenDir, filterDir | ||
26 | , readDirectory, copyTo | ||
27 | , ensureParentDir, remove, isOutdated | ||
28 | ) where | ||
29 | |||
30 | |||
31 | import Control.Monad (mapM) | ||
32 | import Data.Bool (bool) | ||
33 | import Data.List (isPrefixOf, length, subsequences) | ||
34 | import Data.Function ((&)) | ||
35 | import Data.Text (pack) | ||
36 | import Data.Aeson (ToJSON) | ||
37 | import qualified Data.Aeson as JSON | ||
38 | |||
39 | import System.Directory | ||
40 | ( doesDirectoryExist | ||