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