MergeTask.java
1/*******************************************************************************
2 * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Brock Janiczak - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.ant;
13
14import java.io.BufferedOutputStream;
15import java.io.File;
16import java.io.FileOutputStream;
17import java.io.IOException;
18import java.io.InputStream;
19import java.io.OutputStream;
20import java.util.Iterator;
21
22import org.apache.tools.ant.BuildException;
23import org.apache.tools.ant.Project;
24import org.apache.tools.ant.Task;
25import org.apache.tools.ant.types.Resource;
26import org.apache.tools.ant.types.ResourceCollection;
27import org.apache.tools.ant.types.resources.Union;
28import org.apache.tools.ant.util.FileUtils;
29import org.jacoco.core.data.ExecutionDataReader;
30import org.jacoco.core.data.ExecutionDataStore;
31import org.jacoco.core.data.ExecutionDataWriter;
32import org.jacoco.core.data.SessionInfoStore;
33
34/**
35 * Task for merging a set of execution data store files into a single file
36 *
37 * @author Brock Janiczak
38 * @version 0.4.1.20101007204400
39 */
40public class MergeTask extends Task {
41
42 private File destfile;
43
44 private final Union files = new Union();
45
46 /**
47 * Sets the location of the merged data store
48 *
49 * @param destfile
50 * Destination data store location
51 */
52 public void setDestfile(final File destfile) {
53 this.destfile = destfile;
54 }
55
56 /**
57 * This task accepts any number of execution data resources.
58 *
59 * @param resources
60 * Execution data resources
61 */
62 public void addConfigured(final ResourceCollection resources) {
63 files.add(resources);
64 }
65
66 @Override
67 public void execute() throws BuildException {
68 if (destfile == null) {
69 throw new BuildException("Destination file must be supplied");
70 }
71
72 if (destfile.exists() && (!destfile.canWrite() || !destfile.isFile())) {
73 throw new BuildException("Unable to write to destination file");
74 }
75
76 final SessionInfoStore infoStore = new SessionInfoStore();
77 final ExecutionDataStore dataStore = new ExecutionDataStore();
78
79 loadSourceFiles(infoStore, dataStore);
80
81 OutputStream outputStream = null;
82 try {
83 FileUtils.getFileUtils().createNewFile(destfile, true);
84
85 outputStream = new BufferedOutputStream(new FileOutputStream(
86 destfile));
87 final ExecutionDataWriter dataWriter = new ExecutionDataWriter(
88 outputStream);
89 infoStore.accept(dataWriter);
90 dataStore.accept(dataWriter);
91 } catch (final IOException e) {
92 throw new BuildException(String.format(
93 "Unable to write merged file %s", destfile.getName()), e);
94 } finally {
95 FileUtils.close(outputStream);
96 }
97
98 }
99
100 private void loadSourceFiles(final SessionInfoStore infoStore,
101 final ExecutionDataStore dataStore) {
102 int numFilesMerged = 0;
103
104 final Iterator<?> resourceIterator = files.iterator();
105 while (resourceIterator.hasNext()) {
106 final Resource resource = (Resource) resourceIterator.next();
107
108 if (resource.isDirectory()) {
109 continue;
110 }
111
112 log(String.format("Merging %s", resource.getName()),
113 Project.MSG_DEBUG);
114
115 InputStream resourceStream = null;
116 try {
117 resourceStream = resource.getInputStream();
118 final ExecutionDataReader reader = new ExecutionDataReader(
119 resourceStream);
120 reader.setSessionInfoVisitor(infoStore);
121 reader.setExecutionDataVisitor(dataStore);
122 reader.read();
123
124 numFilesMerged++;
125 } catch (final IOException e) {
126 throw new BuildException(String.format("Unable to read %s",
127 resource.getName()), e);
128 } finally {
129 FileUtils.close(resourceStream);
130 }
131 }
132
133 log(String.format("%d files merged", Integer.valueOf(numFilesMerged)),
134 Project.MSG_INFO);
135 }
136
137}