View Javadoc
1   /**************************************************************************
2    *
3    * Copyright (c) 2016-2019 Yawg project contributors.
4    *
5    **************************************************************************/
6   
7   package com.varmateo.yawg.core;
8   
9   import java.io.IOException;
10  import java.io.Reader;
11  import java.nio.charset.StandardCharsets;
12  import java.nio.file.Files;
13  import java.nio.file.InvalidPathException;
14  import java.nio.file.Path;
15  import java.nio.file.Paths;
16  import java.util.Optional;
17  import java.util.regex.PatternSyntaxException;
18  
19  import io.vavr.Function1;
20  import io.vavr.collection.Seq;
21  import io.vavr.collection.Stream;
22  
23  import com.varmateo.yawg.api.YawgException;
24  import com.varmateo.yawg.spi.PageVars;
25  import com.varmateo.yawg.spi.PageVarsBuilder;
26  import com.varmateo.yawg.util.GlobMatcher;
27  import com.varmateo.yawg.util.SimpleMap;
28  import com.varmateo.yawg.util.YamlParser;
29  
30  
31  /**
32   * Reads the baker configuration for one given directory.
33   */
34  /* default */ final class DirBakeOptionsDao {
35  
36  
37      private static final String CONF_FILE_NAME = ".yawg.yml";
38  
39      private static final String PARAM_BAKER_TYPES = "bakerTypes";
40      private static final String PARAM_EXCLUDE = "exclude";
41      private static final String PARAM_EXCLUDE_HERE = "excludeHere";
42      private static final String PARAM_INCLUDE_HERE = "includeHere";
43      private static final String PARAM_TEMPLATE = "template";
44      private static final String PARAM_PAGE_VARS = "pageVars";
45      private static final String PARAM_PAGE_VARS_HERE = "pageVarsHere";
46      private static final String PARAM_TEMPLATES_HERE = "templatesHere";
47      private static final String PARAM_EXTRA_DIRS_HERE = "extraDirsHere";
48  
49  
50      public DirBakeOptionsDao() {
51          // Nothing to do.
52      }
53  
54  
55      /**
56       * Builds the baker configuration for the given directory.
57       *
58       * @param parentConf The configuration from which we will inherit
59       * values.
60       *
61       * @param sourceDir The directory for which we are going to create
62       * the baker conf.
63       *
64       * @return The bake configuration for the given source directory.
65       *
66       * @throws YawgException Thrown if the configuration file could
67       * not be read or had syntax problems.
68       */
69      public DirBakeOptions loadFromDir(final Path sourceDir)
70              throws YawgException {
71  
72          final Path confFile = sourceDir.resolve(CONF_FILE_NAME);
73  
74          return Files.isRegularFile(confFile)
75                  ? loadFromFile(confFile)
76                  : DirBakeOptions.empty();
77      }
78  
79  
80      /**
81       *
82       */
83      public DirBakeOptions loadFromFile(final Path confFile) {
84  
85          final DirBakeOptions result;
86  
87          try {
88              result = doLoadFromFile(confFile);
89          } catch ( IOException e ) {
90              throw DirBakeOptionsDaoException.loadConfigFailure(confFile, e);
91          }
92  
93          return result;
94      }
95  
96  
97      /**
98       *
99       */
100     private DirBakeOptions doLoadFromFile(final Path confFile)
101             throws IOException {
102 
103         final DirBakeOptions result;
104 
105         try ( Reader reader = Files.newBufferedReader(confFile, StandardCharsets.UTF_8) ) {
106             result = read(reader);
107         }
108 
109         return result;
110     }
111 
112 
113     /**
114      *
115      */
116     public DirBakeOptions read(final Reader reader)
117             throws IOException {
118 
119         final SimpleMap confMap = YamlParser.parse(reader);
120         final DirBakeOptions.Builder builder = DirBakeOptions.builder();
121 
122         confMap.getString(PARAM_TEMPLATE)
123                 .ifPresent(builder::templateName);
124 
125         getPatternList(confMap, PARAM_EXCLUDE)
126                 .ifPresent(builder::filesToExclude);
127 
128         getPatternList(confMap, PARAM_EXCLUDE_HERE)
129                 .ifPresent(builder::filesToExcludeHere);
130 
131         getPatternList(confMap, PARAM_INCLUDE_HERE)
132                 .ifPresent(builder::filesToIncludeHere);
133 
134         getBakerTypes(confMap, PARAM_BAKER_TYPES)
135                 .ifPresent(builder::bakerTypes);
136 
137         getPageVars(confMap, PARAM_PAGE_VARS)
138                 .ifPresent(builder::pageVars);
139 
140         getPageVars(confMap, PARAM_PAGE_VARS_HERE)
141                 .ifPresent(builder::pageVarsHere);
142 
143         getTemplatesHere(confMap, PARAM_TEMPLATES_HERE)
144                 .ifPresent(builder::templatesHere);
145 
146         getPathList(confMap, PARAM_EXTRA_DIRS_HERE)
147                 .ifPresent(builder::extraDirsHere);
148 
149         return builder.build();
150     }
151 
152 
153     /**
154      *
155      */
156     private Optional<GlobMatcher> getPatternList(
157             final SimpleMap confMap,
158             final String key)
159             throws YawgException {
160 
161         final Function1<Seq<String>, GlobMatcher> itemsToGlobMatcher = items ->
162                 items
163                 .zipWithIndex()
164                 .foldLeft(
165                         GlobMatcher.builder(),
166                         (xs, x) -> addToGlobBuilder(xs, x._1, x._2, key))
167                 .build();
168 
169         return confMap.getList(key, String.class)
170                 .map(Stream::ofAll)
171                 .map(itemsToGlobMatcher);
172     }
173 
174 
175     private static GlobMatcher.Builder addToGlobBuilder(
176             final GlobMatcher.Builder builder,
177             final String glob,
178             final Integer index,
179             final String key) {
180 
181         try {
182             return builder.addGlobPattern(glob);
183         } catch ( PatternSyntaxException e ) {
184             throw DirBakeOptionsDaoException.invalidGlob(glob, index, key);
185         }
186     }
187 
188 
189     /**
190      *
191      */
192     private Optional<BakerMatcher> getBakerTypes(
193             final SimpleMap map,
194             final String key)
195             throws YawgException {
196 
197         final Optional<BakerMatcher> result;
198         final Optional<SimpleMap> bakerTypesMapOpt = map.getMap(key);
199 
200         if ( bakerTypesMapOpt.isPresent() ) {
201             final SimpleMap bakerTypesMap = bakerTypesMapOpt.get();
202             final BakerMatcher.Builder builder = BakerMatcher.builder();
203 
204             for ( String bakerType : bakerTypesMap.keySet() ) {
205                 getPatternList(bakerTypesMap, bakerType)
206                         .ifPresent(m -> builder.addBakerType(bakerType, m));
207             }
208             result = Optional.of(builder.build());
209         } else {
210             result = Optional.empty();
211         }
212 
213         return result;
214     }
215 
216 
217     /**
218      *
219      */
220     private Optional<PageVars> getPageVars(
221             final SimpleMap confMap,
222             final String key)
223             throws YawgException {
224 
225         return confMap
226                 .getMap(key)
227                 .map(pageVarsMap ->
228                      PageVarsBuilder.create(pageVarsMap.asMap()).build());
229     }
230 
231 
232     /**
233      *
234      */
235     private Optional<TemplateNameMatcher> getTemplatesHere(
236             final SimpleMap map,
237             final String key)
238             throws YawgException {
239 
240         final Optional<TemplateNameMatcher> result;
241         final Optional<SimpleMap> templatesHereMapOpt = map.getMap(key);
242 
243         if ( templatesHereMapOpt.isPresent() ) {
244             final SimpleMap templatesHereMap = templatesHereMapOpt.get();
245             final TemplateNameMatcher.Builder builder = TemplateNameMatcher.builder();
246 
247             for ( String templateName : templatesHereMap.keySet() ) {
248                 final GlobMatcher globMatcher =
249                         getPatternList(templatesHereMap, templateName).get();
250 
251                 builder.addTemplateName(templateName, globMatcher);
252             }
253             result = Optional.of(builder.build());
254         } else {
255             result = Optional.empty();
256         }
257 
258         return result;
259     }
260 
261 
262     /**
263      *
264      */
265     private Optional<Seq<Path>> getPathList(
266             final SimpleMap confMap,
267             final String key)
268             throws YawgException {
269 
270         return confMap
271                 .getList(key, String.class)
272                 .map(Stream::ofAll)
273                 .map(itemSeq ->
274                      itemSeq
275                      .zipWithIndex()
276                      .map(tuple -> buildPath(tuple._1, tuple._2, key)));
277     }
278 
279 
280     private static Path buildPath(
281             final String pathStr,
282             final Integer index,
283             final String key) {
284 
285         try {
286             return Paths.get(pathStr);
287         } catch ( InvalidPathException e ) {
288             throw DirBakeOptionsDaoException.invalidPath(pathStr, index, key);
289         }
290     }
291 
292 
293 }