Skip to content

Commit 3a6151e

Browse files
committed
Allow to set an alternative source directory (for editing)
Always check if a file is existing before returning true for isEditable and non-null for getDoxiaSourcePath()/getDoxiaSourcePath(String) This closes #277
1 parent f976f25 commit 3a6151e

File tree

6 files changed

+335
-120
lines changed

6 files changed

+335
-120
lines changed

doxia-site-renderer/src/main/java/org/apache/maven/doxia/siterenderer/DefaultSiteRenderer.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,11 @@ public Map<String, DocumentRenderer> locateDocumentFiles(SiteRenderingContext si
198198

199199
addModuleFiles(
200200
siteRenderingContext.getRootDirectory(),
201+
siteDirectory,
201202
moduleBasedir,
202203
module,
203204
excludes,
204-
files,
205-
siteDirectory.isEditable(),
206-
siteDirectory.isSkipDuplicates());
205+
files);
207206
}
208207
}
209208
}
@@ -228,32 +227,27 @@ private List<String> filterExtensionIgnoreCase(List<String> fileNames, String ex
228227
* Populates the files map with {@link DocumentRenderer}s per output name in parameter {@code files} for all files in the moduleBasedir matching the module extensions,
229228
* taking care of duplicates if needed.
230229
*
231-
* @param rootDir
230+
* @param siteRootDirectory
231+
* @param siteDirectory
232232
* @param moduleBasedir
233233
* @param module
234234
* @param excludes
235235
* @param files
236-
* @param editable
237-
* @param skipDuplicates
238236
* @throws IOException
239237
* @throws RendererException
240238
*/
241239
private void addModuleFiles(
242-
File rootDir,
240+
File siteRootDirectory,
241+
SiteDirectory siteDirectory,
243242
File moduleBasedir,
244243
ParserModule module,
245244
String excludes,
246-
Map<String, DocumentRenderer> files,
247-
boolean editable,
248-
boolean skipDuplicates)
245+
Map<String, DocumentRenderer> files)
249246
throws IOException, RendererException {
250247
if (!moduleBasedir.exists() || ArrayUtils.isEmpty(module.getExtensions())) {
251248
return;
252249
}
253250

254-
String moduleRelativePath =
255-
PathTool.getRelativeFilePath(rootDir.getAbsolutePath(), moduleBasedir.getAbsolutePath());
256-
257251
List<String> allFiles = FileUtils.getFileNames(moduleBasedir, "**/*", excludes, false);
258252

259253
for (String extension : module.getExtensions()) {
@@ -268,14 +262,20 @@ private void addModuleFiles(
268262

269263
for (String doc : docs) {
270264
DocumentRenderingContext docRenderingContext = new DocumentRenderingContext(
271-
moduleBasedir, moduleRelativePath, doc, module.getParserId(), extension, editable);
265+
moduleBasedir,
266+
doc,
267+
module.getParserId(),
268+
extension,
269+
siteRootDirectory,
270+
siteDirectory.getPath(),
271+
siteDirectory.getEditableSourceDirectories());
272272

273273
// TODO: DOXIA-111: we need a general filter here that knows how to alter the context
274274
if (endsWithIgnoreCase(doc, ".vm")) {
275275
docRenderingContext.setAttribute("velocity", "true");
276276
}
277277

278-
if (!checkForDuplicate(docRenderingContext, files, skipDuplicates)) {
278+
if (!checkForDuplicate(docRenderingContext, files, siteDirectory.isSkipDuplicates())) {
279279
String key = docRenderingContext.getOutputName();
280280
files.put(key, new DoxiaDocumentRenderer(docRenderingContext));
281281
}

doxia-site-renderer/src/main/java/org/apache/maven/doxia/siterenderer/DocumentRenderingContext.java

Lines changed: 163 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
package org.apache.maven.doxia.siterenderer;
2020

2121
import java.io.File;
22+
import java.util.Collection;
23+
import java.util.Collections;
2224
import java.util.HashMap;
2325
import java.util.Map;
26+
import java.util.Objects;
2427

2528
import org.codehaus.plexus.util.PathTool;
2629

@@ -32,26 +35,59 @@
3235
* @since 1.5 (was since 1.1 in o.a.m.d.sink.render)
3336
*/
3437
public class DocumentRenderingContext {
35-
private final File basedir;
3638

37-
private final String basedirRelativePath;
39+
/** absolute path to the source base directory (not null, pseudo value when not a Doxia source), this is parser format specific. Must start with {@link #siteRootDirectory}. */
40+
private final File basedir;
3841

42+
/** {@link #basedir} relative path to the document's source including {@link #extension}. May be {@code null} if not rendered from a Doxia source */
3943
private final String inputPath;
4044

45+
/** same as {@link #inputPath} but with extension replaced with {@code .html}, this is parser format specific */
4146
private final String outputPath;
4247

48+
/** the Doxia module parser id associated to this document, may be null if document not rendered from a Doxia source. */
4349
private final String parserId;
4450

45-
private final String relativePath;
46-
51+
/** the source document filename extension, may be null if document not rendered from a Doxia source. */
4752
private final String extension;
4853

4954
private Map<String, String> attributes;
5055

51-
private final boolean editable;
56+
/**
57+
* The absolute paths of directories which may contain the original editable source.
58+
* If empty document is not editable.
59+
*/
60+
private final Collection<File> sourceDirectories;
5261

62+
/** The project's build directory, may be {@code null} rendered from a Doxia source) */
63+
private final File rootDirectory;
64+
65+
/** The site's root directory (never null), must be within below {@link #rootDirectory}, may be {@code null} rendered from a Doxia source */
66+
private final File siteRootDirectory;
67+
68+
/** optional descriptive text of the plugin which generated the output (usually Maven coordinates). Only set when document is not based on a Doxia source. */
5369
private final String generator;
5470

71+
static File stripSuffixFromPath(File file, String suffix) {
72+
File relevantFile = file;
73+
if (suffix == null || suffix.isEmpty()) {
74+
return relevantFile;
75+
}
76+
File currentSuffixPart = new File(suffix);
77+
// compare elements from end, suffix should be a suffix of file
78+
do {
79+
if (currentSuffixPart.getName().equals(relevantFile.getName())) {
80+
relevantFile = relevantFile.getParentFile();
81+
if (relevantFile == null) {
82+
throw new IllegalArgumentException("Suffix " + suffix + " has more elements than file " + file);
83+
}
84+
} else {
85+
throw new IllegalArgumentException("Suffix " + suffix + " is not a suffix of file " + file);
86+
}
87+
} while ((currentSuffixPart = currentSuffixPart.getParentFile()) != null);
88+
return relevantFile;
89+
}
90+
5591
/**
5692
* <p>
5793
* Constructor for rendering context when document is not rendered from a Doxia markup source.
@@ -64,9 +100,10 @@ public class DocumentRenderingContext {
64100
* @since 1.8
65101
*/
66102
public DocumentRenderingContext(File basedir, String document, String generator) {
67-
this(basedir, null, document, null, null, false, generator);
103+
this(basedir, document, null, null, null, null, Collections.emptySet(), generator);
68104
}
69105

106+
@Deprecated
70107
public DocumentRenderingContext(
71108
File basedir,
72109
String basedirRelativePath,
@@ -77,13 +114,36 @@ public DocumentRenderingContext(
77114
this(basedir, basedirRelativePath, document, parserId, extension, editable, null);
78115
}
79116

117+
/**
118+
* <p>
119+
* Constructor for rendering context when document is a Doxia markup source.
120+
* </p>
121+
* @param basedir
122+
* @param document
123+
* @param parserId
124+
* @param extension
125+
* @param rootDirectory
126+
* @param sourceDirectories
127+
* @since 2.1
128+
*/
129+
public DocumentRenderingContext(
130+
File basedir,
131+
String document,
132+
String parserId,
133+
String extension,
134+
File rootDirectory,
135+
File siteRootDirectory,
136+
Collection<File> sourceDirectories) {
137+
this(basedir, document, parserId, extension, rootDirectory, siteRootDirectory, sourceDirectories, null);
138+
}
139+
80140
/**
81141
* <p>
82142
* Constructor for document rendering context.
83143
* </p>
84144
*
85145
* @param basedir the source base directory (not null, pseudo value when not a Doxia source).
86-
* @param basedirRelativePath the relative path from root (null if not Doxia source)
146+
* @param basedirRelativePath the relative path from project root (null if not Doxia source)
87147
* @param document the source document path.
88148
* @param parserId the Doxia module parser id associated to this document, may be null if document not rendered from
89149
* a Doxia source.
@@ -92,7 +152,9 @@ public DocumentRenderingContext(
92152
* @param editable is the document editable as source, i.e. not generated?
93153
* @param generator the generator (in general a reporting goal: <code>groupId:artifactId:version:goal</code>)
94154
* @since 1.8
155+
* @deprecated Use {@link #DocumentRenderingContext(File, String, String, String, File, Collection, String)} instead.
95156
*/
157+
@Deprecated
96158
public DocumentRenderingContext(
97159
File basedir,
98160
String basedirRelativePath,
@@ -101,6 +163,48 @@ public DocumentRenderingContext(
101163
String extension,
102164
boolean editable,
103165
String generator) {
166+
this(
167+
basedir,
168+
document,
169+
parserId,
170+
extension,
171+
stripSuffixFromPath(basedir, basedirRelativePath),
172+
// assume that site root is the parent of basedir (i.e. module specific source directory is directly
173+
// below site root)
174+
basedir.getParentFile(),
175+
editable ? Collections.singleton(basedir) : Collections.emptySet(),
176+
generator);
177+
}
178+
179+
/**
180+
* <p>
181+
* Constructor for document rendering context.
182+
* </p>
183+
*
184+
* @param basedir the source base directory (not null, pseudo value when not a Doxia source).
185+
* @param basedirRelativePath the relative path from root (null if not Doxia source)
186+
* @param document the source document path.
187+
* @param parserId the Doxia module parser id associated to this document, may be null if document not rendered from
188+
* a Doxia source.
189+
* @param extension the source document filename extension, may be null if document not rendered from
190+
* a Doxia source.
191+
* @param rootDirectory the absolute project's root directory (not null), usually {@code project.basedir}, must be an ancestor of {@code siteRootDirectory}
192+
* @param siteRootDirectory the absolute site's root directory (not null), must start with {@code rootDirectory}, often ends with {@code /src/site}
193+
* @param sourceDirectories the absolute paths of directories which may contain the original editable source.
194+
* @param editable is the document editable as source, i.e. not generated?
195+
* @param generator the generator (in general a reporting goal: <code>groupId:artifactId:version:goal</code>)
196+
* @since 2.1
197+
*/
198+
@SuppressWarnings("checkstyle:parameternumber")
199+
public DocumentRenderingContext(
200+
File basedir,
201+
String document,
202+
String parserId,
203+
String extension,
204+
File rootDirectory,
205+
File siteRootDirectory,
206+
Collection<File> sourceDirectories,
207+
String generator) {
104208
this.basedir = basedir;
105209
this.parserId = parserId;
106210
this.extension = extension;
@@ -110,10 +214,23 @@ public DocumentRenderingContext(
110214
document = document.replace('\\', '/');
111215
this.inputPath = document;
112216

217+
if (rootDirectory == null) {
218+
if (siteRootDirectory != null) {
219+
throw new IllegalArgumentException("Root directory must not be null when site root directory is set");
220+
}
221+
} else {
222+
Objects.requireNonNull(
223+
siteRootDirectory, "Site root directory must not be null when root directory is set");
224+
if (!siteRootDirectory.getPath().startsWith(rootDirectory.getPath())) {
225+
throw new IllegalArgumentException("Site root directory " + siteRootDirectory
226+
+ " must start with root directory " + rootDirectory);
227+
}
228+
}
229+
this.rootDirectory = rootDirectory;
230+
this.siteRootDirectory = siteRootDirectory;
113231
if (extension != null && !extension.isEmpty()) {
114-
this.basedirRelativePath = basedirRelativePath.replace('\\', '/');
115232
// document comes from a Doxia source: see DoxiaDocumentRenderer
116-
this.editable = editable;
233+
this.sourceDirectories = sourceDirectories;
117234

118235
// here we know the parserId and extension, we can play with this to get output name from document:
119236
// - index.xml -> index.html
@@ -126,13 +243,9 @@ public DocumentRenderingContext(
126243
this.outputPath = filePathWithoutExt + ".html";
127244
} else {
128245
// document does not come from a Doxia source but direct Sink API, so no file extension to strip
129-
this.basedirRelativePath = null;
130-
this.editable = false;
246+
this.sourceDirectories = Collections.emptySet();
131247
this.outputPath = document + ".html";
132248
}
133-
134-
this.relativePath = PathTool.getRelativePath(basedir.getPath(), new File(basedir, inputPath).getPath())
135-
.replace('\\', '/');
136249
}
137250

138251
/**
@@ -189,12 +302,13 @@ public String getParserId() {
189302
}
190303

191304
/**
192-
* Get the relative path to site root.
305+
* Get the relative path of the parent folder to site root.
193306
*
194307
* @return the relative path to site root
195308
*/
196309
public String getRelativePath() {
197-
return relativePath;
310+
return PathTool.getRelativePath(basedir.getPath(), new File(basedir, inputPath).getPath())
311+
.replace('\\', '/');
198312
}
199313

200314
/**
@@ -233,7 +347,7 @@ public String getExtension() {
233347
* @since 1.8
234348
*/
235349
public boolean isEditable() {
236-
return editable;
350+
return getDoxiaSourcePath() != null;
237351
}
238352

239353
/**
@@ -257,27 +371,54 @@ public String getGenerator() {
257371
}
258372

259373
/**
260-
* Get the relative path of basedir (when a Doxia source)
374+
* Get the project root relative path of basedir (when a Doxia source). For example {@code src/site/markdown}.
261375
*
262376
* @return the relative path of basedir when a Doxia source, or <code>null</code> if not a Doxia source
263377
* @since 1.8
264378
*/
265379
public String getBasedirRelativePath() {
266-
return basedirRelativePath;
380+
if (!isDoxiaSource()) {
381+
return null;
382+
}
383+
return PathTool.getRelativeFilePath(rootDirectory.getPath(), basedir.getPath());
384+
}
385+
386+
/**
387+
* Get the site root relative path of basedir (when a Doxia source). For example {@code markdown}.
388+
*
389+
* @return the relative path of basedir when a Doxia source, or <code>null</code> if not a Doxia source
390+
*/
391+
private String getBasedirRelativePathAgainstSiteRoot() {
392+
if (!isDoxiaSource()) {
393+
return null;
394+
}
395+
return PathTool.getRelativeFilePath(siteRootDirectory.getPath(), basedir.getPath());
267396
}
268397

269398
/**
270-
* Get the relative path to Doxia source from build root.
399+
* Get the relative path to Doxia source from build root. The file separators in the returned path are {@code /} regardless of the platform..
271400
*
272401
* @return the relative path to Doxia source from build root, or <code>null</code> if not a Doxia source
273402
* @since 1.8
274403
*/
275404
public String getDoxiaSourcePath() {
276-
return isDoxiaSource() ? (basedirRelativePath + '/' + inputPath) : null;
405+
if (!isDoxiaSource()) {
406+
return null;
407+
} else {
408+
for (File sourceDirectory : sourceDirectories) {
409+
File sourceFile = new File(sourceDirectory, getBasedirRelativePathAgainstSiteRoot() + '/' + inputPath);
410+
if (sourceFile.exists()) {
411+
return PathTool.getRelativeFilePath(rootDirectory.getPath(), sourceFile.getPath())
412+
.replace('\\', '/');
413+
}
414+
}
415+
}
416+
return null;
277417
}
278418

279419
/**
280-
* Get url of the Doxia source calculate from given base url.
420+
* Get absolute url of the Doxia source calculate from given base url.
421+
* Used from Skins to render an edit button.
281422
*
282423
* @param base the base url to use
283424
* @return the resulting url

0 commit comments

Comments
 (0)