Concatenate CSS files from subdirectories into one single styles.css

Althought this thread is rather old, I used the script to concatenate my CSS files. I recognized that it does not cut out comments nor relative URLs from folders below the root folder work correctly, so I fixed them. As I did not found this tool as an addon within the repository, I will just drop the code here, maybe someone will find it useful :wink:


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ConcatenateCss {
	private static final String SEPARATOR = "----------------------------------------------------------------------";
	private static final Pattern URL_PATTERN = Pattern.compile("url\\(['\"]
?(.*?)['\"]
?\\)");
	private static final Pattern COMMENT_START = Pattern.compile("/\\*");
	private static final Pattern COMMENT_END = Pattern.compile("\\*/");
	private static File cssRootDir;
	private static File cssRootFile;
	private static File cssRootFileAll;
	private static URI cssRootUri;
	private static int fileCount;
	private static int lineCount;

	public static void main(final String[] args) throws IOException {
		if (args.length != 2) {
			System.err.println("Usage: java ConcatenateCss [path to root css file]
 [path to target css file]
");
			return;
		}
		final String fileName = args[0]
;
		cssRootFile = new File(fileName);
		cssRootDir = cssRootFile.getParentFile();
		cssRootFileAll = new File(args[1]
);
		cssRootUri = cssRootDir.toURI();
		System.out.println("CSS root file is: " + cssRootFile);
		System.out.println("Concatenated CSS: " + cssRootFileAll);
		System.out.println("---");
		final StringBuilder cssContent = new StringBuilder();
		cssContent.append("/* CSS CONCATENATED FROM SUBDIRECTORIES */\n");
		concatenate(cssRootFile, cssContent);
		++fileCount;
		final BufferedWriter out = new BufferedWriter(new FileWriter(
				cssRootFileAll));
		out.write(cssContent.toString());
		out.close();
		System.out.println("---");
		System.out.println("Successfully concatenated " + fileCount
				+ " files (" + lineCount + " lines)");
	}

	private static boolean concatenate(final File cssFile,
			final StringBuilder cssContent) throws IOException {
		if (!cssFile.isFile()) {
			System.out.println("Ignored file: " + cssFile
					+ " (missing or not a file)");
			return false;
		}
		cssContent.append("/* " + SEPARATOR + " "
				+ cssFile.getName().toUpperCase() + " */\n");
		++lineCount;
		final DataInputStream in = new DataInputStream(new FileInputStream(
				cssFile));
		final BufferedReader br = new BufferedReader(new InputStreamReader(in));
		String line;
		boolean commentActive = false;
		while ((line = br.readLine()) != null) {
			
			// Remove comments:
			if (!commentActive) {
				Matcher commentStartMatcher = COMMENT_START.matcher(line);
				if (commentStartMatcher.find()) {
					//	Filter for Comments within one line:
					String restLine = line.substring(commentStartMatcher.end(0));
					Matcher commentEndMatcher = COMMENT_END.matcher(restLine);
					if (commentEndMatcher.find()) {
						line = line.substring(0, commentStartMatcher.start(0)) + restLine.substring(commentEndMatcher.end(0));
					} else {
						commentActive = true;
						line = line.substring(0, commentStartMatcher.start(0));
					}
				}
			} else {
				Matcher commentEndMatcher = COMMENT_END.matcher(line);
				if (commentEndMatcher.find()) {
					commentActive = false;
					line = line.substring(commentEndMatcher.end(0));
				} else {
					continue;
				}
			}
			
			if (line == null || line.equals("")) {
				continue;
			}
			if (line.startsWith("@import")) {
				final Matcher urlMatcher = URL_PATTERN.matcher(line);
				if (urlMatcher.find()) {
					final String url = urlMatcher.group(1);
					File importFile = new File(url);
					if (!importFile.isAbsolute()) {
						importFile = new File(cssFile.getParentFile(), url);
					}
					if (!concatenate(importFile, cssContent)) {
						cssContent.append(line).append("\n");
						++lineCount;
					} else {
						++fileCount;
						System.out.println("Concatenated: " + importFile);
					}
				} else {
					cssContent.append(line).append("\n");
					++lineCount;
					System.out
							.println("Warning: Could not find url(...) pattern");
				}
				continue;
			}
			final Matcher urlMatcher = URL_PATTERN.matcher(line);
			if (urlMatcher.find()) {
				final String url = urlMatcher.group(1);
				File imageFile = new File(url);
				if (!imageFile.isAbsolute()) {
					imageFile = new File(cssFile.getParentFile(), url);
					String newUrl = cssRootUri.relativize(imageFile.toURI()).getPath();
					newUrl = newUrl.replaceAll(cssRootUri.getPath(), "");
					line = line.replaceAll(url, newUrl);
				}
			}
			cssContent.append(line).append("\n");
			++lineCount;
		}
		in.close();
		return true;
	}
}

Cheers,

Martin