• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright (c) 2009, 2021 Mountainminds GmbH & Co. KG and Contributors
3  * This program and the accompanying materials are made available under
4  * the terms of the Eclipse Public License 2.0 which is available at
5  * http://www.eclipse.org/legal/epl-2.0
6  *
7  * SPDX-License-Identifier: EPL-2.0
8  *
9  * Contributors:
10  *    Marc R. Hoffmann - initial API and implementation
11  *
12  *******************************************************************************/
13 package org.jacoco.report.internal;
14 
15 import java.io.IOException;
16 import java.io.OutputStream;
17 import java.util.HashMap;
18 import java.util.Map;
19 
20 import org.jacoco.report.IMultiReportOutput;
21 
22 /**
23  * Logical representation of a folder in the output structure. This utility
24  * ensures valid and unique file names and helps to create relative links.
25  */
26 public class ReportOutputFolder {
27 
28 	private final IMultiReportOutput output;
29 
30 	private final ReportOutputFolder parent;
31 
32 	private final String path;
33 
34 	/** Cached sub-folder instances to guarantee stable normalization */
35 	private final Map<String, ReportOutputFolder> subFolders = new HashMap<String, ReportOutputFolder>();
36 
37 	private final NormalizedFileNames fileNames;
38 
39 	/**
40 	 * Creates a new root folder for the given output.
41 	 *
42 	 * @param output
43 	 *            output for generated files
44 	 */
ReportOutputFolder(final IMultiReportOutput output)45 	public ReportOutputFolder(final IMultiReportOutput output) {
46 		this(output, null, "");
47 	}
48 
49 	/**
50 	 * Creates a new root folder for the given output.
51 	 *
52 	 * @param output
53 	 *            output for generated files
54 	 */
ReportOutputFolder(final IMultiReportOutput output, final ReportOutputFolder parent, final String path)55 	private ReportOutputFolder(final IMultiReportOutput output,
56 			final ReportOutputFolder parent, final String path) {
57 		this.output = output;
58 		this.parent = parent;
59 		this.path = path;
60 		fileNames = new NormalizedFileNames();
61 	}
62 
63 	/**
64 	 * Creates a sub-folder with the given name.
65 	 *
66 	 * @param name
67 	 *            name of the sub-folder
68 	 * @return handle for output into the sub-folder
69 	 */
subFolder(final String name)70 	public ReportOutputFolder subFolder(final String name) {
71 		final String normalizedName = normalize(name);
72 		ReportOutputFolder folder = subFolders.get(normalizedName);
73 		if (folder != null) {
74 			return folder;
75 		}
76 		folder = new ReportOutputFolder(output, this,
77 				path + normalizedName + "/");
78 		subFolders.put(normalizedName, folder);
79 		return folder;
80 	}
81 
82 	/**
83 	 * Creates a new file in this folder with the given local name.
84 	 *
85 	 * @param name
86 	 *            name of the sub-folder
87 	 * @return handle for output into the sub-folder
88 	 * @throws IOException
89 	 *             if the file creation fails
90 	 */
createFile(final String name)91 	public OutputStream createFile(final String name) throws IOException {
92 		return output.createFile(path + normalize(name));
93 	}
94 
95 	/**
96 	 * Returns a link relative to a given base to a resource within this folder.
97 	 *
98 	 * @param base
99 	 *            base to create the relative link from
100 	 * @param name
101 	 *            name of the file or folder in this folder
102 	 * @return relative link
103 	 * @throws IllegalArgumentException
104 	 *             if this folder and the base do not have the same root
105 	 */
getLink(final ReportOutputFolder base, final String name)106 	public String getLink(final ReportOutputFolder base, final String name) {
107 		if (base.isAncestorOf(this)) {
108 			return this.path.substring(base.path.length()) + normalize(name);
109 		}
110 		if (base.parent == null) {
111 			throw new IllegalArgumentException("Folders with different roots.");
112 		}
113 		return "../" + this.getLink(base.parent, name);
114 	}
115 
isAncestorOf(final ReportOutputFolder folder)116 	private boolean isAncestorOf(final ReportOutputFolder folder) {
117 		if (this == folder) {
118 			return true;
119 		}
120 		return folder.parent == null ? false : isAncestorOf(folder.parent);
121 	}
122 
normalize(final String name)123 	private String normalize(final String name) {
124 		return fileNames.getFileName(name);
125 	}
126 
127 }
128