001
014
015 package com.liferay.portal.tools;
016
017 import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
018 import com.liferay.portal.kernel.io.unsync.UnsyncPrintWriter;
019 import com.liferay.portal.kernel.util.FastDateFormatFactoryUtil;
020 import com.liferay.portal.kernel.util.FileUtil;
021 import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
022 import com.liferay.portal.kernel.util.StringPool;
023 import com.liferay.portal.kernel.util.StringUtil;
024 import com.liferay.portal.kernel.util.SystemProperties;
025 import com.liferay.portal.kernel.util.UnsyncPrintWriterPool;
026 import com.liferay.portal.kernel.util.Validator;
027 import com.liferay.portal.model.ModelHintsConstants;
028 import com.liferay.portal.scripting.ruby.RubyExecutor;
029 import com.liferay.portal.servlet.filters.minifier.MinifierFilter;
030 import com.liferay.portal.util.FastDateFormatFactoryImpl;
031 import com.liferay.portal.util.FileImpl;
032 import com.liferay.portal.util.PortalImpl;
033 import com.liferay.portal.util.PortalUtil;
034
035 import java.io.File;
036
037 import java.util.ArrayList;
038 import java.util.HashMap;
039 import java.util.List;
040 import java.util.Map;
041
042 import org.apache.tools.ant.DirectoryScanner;
043
044
047 public class SassToCssBuilder {
048
049 public static File getCacheFile(String fileName) {
050 fileName = StringUtil.replace(
051 fileName, StringPool.BACK_SLASH, StringPool.SLASH);
052
053 int pos = fileName.lastIndexOf(StringPool.SLASH);
054
055 String cacheFileName =
056 fileName.substring(0, pos + 1) + ".sass-cache/" +
057 fileName.substring(pos + 1);
058
059 return new File(cacheFileName);
060 }
061
062 public static void main(String[] args) {
063 Map<String, String> arguments = ArgumentsUtil.parseArguments(args);
064
065 List<String> dirNames = new ArrayList<String>();
066
067 String dirName = arguments.get("sass.dir");
068
069 if (Validator.isNotNull(dirName)) {
070 dirNames.add(dirName);
071 }
072 else {
073 for (int i = 0;; i++ ) {
074 dirName = arguments.get("sass.dir." + i);
075
076 if (Validator.isNotNull(dirName)) {
077 dirNames.add(dirName);
078 }
079 else {
080 break;
081 }
082 }
083 }
084
085 try {
086 new SassToCssBuilder(dirNames);
087 }
088 catch (Exception e) {
089 e.printStackTrace();
090 }
091 }
092
093 public static String parseStaticTokens(String content) {
094 return StringUtil.replace(
095 content,
096 new String[] {
097 "@model_hints_constants_text_display_height@",
098 "@model_hints_constants_text_display_width@",
099 "@model_hints_constants_textarea_display_height@",
100 "@model_hints_constants_textarea_display_width@"
101 },
102 new String[] {
103 ModelHintsConstants.TEXT_DISPLAY_HEIGHT,
104 ModelHintsConstants.TEXT_DISPLAY_WIDTH,
105 ModelHintsConstants.TEXTAREA_DISPLAY_HEIGHT,
106 ModelHintsConstants.TEXTAREA_DISPLAY_WIDTH
107 });
108 }
109
110 public SassToCssBuilder(List<String> dirNames) throws Exception {
111 Class<?> clazz = getClass();
112
113 ClassLoader classLoader = clazz.getClassLoader();
114
115 _initUtil(classLoader);
116
117 _rubyScript = StringUtil.read(
118 classLoader,
119 "com/liferay/portal/servlet/filters/dynamiccss/main.rb");
120
121 _tempDir = SystemProperties.get(SystemProperties.TMP_DIR);
122
123 for (String dirName : dirNames) {
124
125
126
127
128 _rubyExecutor = new RubyExecutor();
129
130 _parseSassDirectory(dirName);
131 }
132 }
133
134 private String _getContent(File file) throws Exception {
135 String content = FileUtil.read(file);
136
137 content = MinifierFilter.aggregateCss(file.getParent(), content);
138
139 return parseStaticTokens(content);
140 }
141
142 private String _getCssThemePath(String fileName) {
143 int pos = fileName.lastIndexOf("/css/");
144
145 return fileName.substring(0, pos + 4);
146 }
147
148 private void _initUtil(ClassLoader classLoader) {
149 FastDateFormatFactoryUtil fastDateFormatFactoryUtil =
150 new FastDateFormatFactoryUtil();
151
152 fastDateFormatFactoryUtil.setFastDateFormatFactory(
153 new FastDateFormatFactoryImpl());
154
155 FileUtil fileUtil = new FileUtil();
156
157 fileUtil.setFile(new FileImpl());
158
159 PortalClassLoaderUtil.setClassLoader(classLoader);
160
161 PortalUtil portalUtil = new PortalUtil();
162
163 portalUtil.setPortal(new PortalImpl());
164 }
165
166 private void _parseSassDirectory(String dirName) throws Exception {
167 DirectoryScanner directoryScanner = new DirectoryScanner();
168
169 directoryScanner.setBasedir(dirName);
170 directoryScanner.setExcludes(
171 new String[] {
172 "**\\_diffs\\**", "**\\.sass-cache*\\**",
173 "**\\.sass_cache_*\\**", "**\\_sass_cache_*\\**",
174 "**\\_styled\\**", "**\\_unstyled\\**"
175 });
176 directoryScanner.setIncludes(new String[] {"**\\*.css"});
177
178 directoryScanner.scan();
179
180 String[] fileNames = directoryScanner.getIncludedFiles();
181
182 for (String fileName : fileNames) {
183 fileName = StringUtil.replace(
184 dirName + StringPool.SLASH + fileName, StringPool.BACK_SLASH,
185 StringPool.SLASH);
186
187 try {
188 long start = System.currentTimeMillis();
189
190 if (_parseSassFile(fileName)) {
191 long end = System.currentTimeMillis();
192
193 System.out.println(
194 "Parsed " + fileName + " in " + (end - start) + " ms");
195 }
196 }
197 catch (Exception e) {
198 System.out.println("Unable to parse " + fileName);
199
200 e.printStackTrace();
201 }
202 }
203 }
204
205 private boolean _parseSassFile(String fileName) throws Exception {
206 File file = new File(fileName);
207 File cacheFile = getCacheFile(fileName);
208
209 if (file.lastModified() == cacheFile.lastModified()) {
210 return false;
211 }
212
213 Map<String, Object> inputObjects = new HashMap<String, Object>();
214
215 inputObjects.put("content", _getContent(file));
216 inputObjects.put("cssRealPath", fileName);
217 inputObjects.put("cssThemePath", _getCssThemePath(fileName));
218 inputObjects.put("sassCachePath", _tempDir);
219
220 UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
221 new UnsyncByteArrayOutputStream();
222
223 UnsyncPrintWriter unsyncPrintWriter = UnsyncPrintWriterPool.borrow(
224 unsyncByteArrayOutputStream);
225
226 inputObjects.put("out", unsyncPrintWriter);
227
228 _rubyExecutor.eval(null, inputObjects, null, _rubyScript);
229
230 unsyncPrintWriter.flush();
231
232 String parsedContent = unsyncByteArrayOutputStream.toString();
233
234 FileUtil.write(cacheFile, parsedContent);
235
236 cacheFile.setLastModified(file.lastModified());
237
238 return true;
239 }
240
241 private RubyExecutor _rubyExecutor;
242 private String _rubyScript;
243 private String _tempDir;
244
245 }