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