|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- /*
- * Copyright 2000-2018 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
- package com.vaadin.sass.linker;
-
- import java.io.ByteArrayInputStream;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
-
- import org.w3c.css.sac.CSSException;
-
- import com.google.gwt.core.ext.LinkerContext;
- import com.google.gwt.core.ext.TreeLogger;
- import com.google.gwt.core.ext.UnableToCompleteException;
- import com.google.gwt.core.ext.linker.AbstractLinker;
- import com.google.gwt.core.ext.linker.ArtifactSet;
- import com.google.gwt.core.ext.linker.EmittedArtifact;
- import com.google.gwt.core.ext.linker.LinkerOrder;
- import com.google.gwt.core.ext.linker.LinkerOrder.Order;
- import com.google.gwt.core.ext.linker.Shardable;
- import com.vaadin.sass.internal.ScssStylesheet;
-
- /**
- * Pre-linker that checks for the existence of SASS files in public folders,
- * compiles them to CSS files with the SassCompiler from Vaadin and adds the CSS
- * back into the artifact.
- *
- */
- @LinkerOrder(Order.PRE)
- @Shardable
- public class SassLinker extends AbstractLinker {
-
- @Override
- public String getDescription() {
- return "Compiling SCSS files in public folders to standard CSS";
- }
-
- @Override
- public ArtifactSet link(TreeLogger logger, LinkerContext context,
- ArtifactSet artifacts, boolean onePermutation)
- throws UnableToCompleteException {
-
- if (!onePermutation) {
- // The artifact to return
- ArtifactSet toReturn = new ArtifactSet(artifacts);
-
- // The temporary scss files provided from the artefacts
- List<FileInfo> scssFiles = new ArrayList<FileInfo>();
-
- // The public files are provided as inputstream, but the compiler
- // needs real files, as they can contain references to other
- // files. They will be stored here, with their relative paths intact
- String tempFolderName = new Date().getTime() + File.separator;
- File tempFolder = createTempDir(tempFolderName);
-
- // Can't search here specifically for public resources, as the type
- // is different during compilation. This means we have to loop
- // through all the artifacts
- for (EmittedArtifact resource : artifacts
- .find(EmittedArtifact.class)) {
-
- // Create the temporary files.
- String partialPath = resource.getPartialPath();
- if (partialPath.endsWith(".scss")) {
- // In my opinion, the SCSS file does not need to be
- // output to the web content folder, as they can't
- // be used there
- toReturn.remove(resource);
-
- String fileName = partialPath;
- File path = tempFolder;
-
- int separatorIndex = fileName.lastIndexOf(File.separator);
- if (-1 != separatorIndex) {
- fileName = fileName.substring(separatorIndex + 1);
-
- String filePath = partialPath.substring(0,
- separatorIndex);
- path = createTempDir(tempFolderName + filePath);
- }
-
- File tempfile = new File(path, fileName);
- try {
- boolean fileCreated = tempfile.createNewFile();
- if (fileCreated) {
-
- // write the received inputstream to the temp file
- writeFromInputStream(resource.getContents(logger),
- tempfile);
-
- // Store the file info for the compilation
- scssFiles.add(new FileInfo(tempfile, partialPath));
- } else {
- logger.log(TreeLogger.WARN,
- "Duplicate file " + tempfile.getPath());
- }
- } catch (IOException e) {
- logger.log(TreeLogger.ERROR,
- "Could not write temporary file " + fileName,
- e);
- }
- }
- }
-
- // Compile the files and store them in the artifact
- logger.log(TreeLogger.INFO,
- "Processing " + scssFiles.size() + " Sass file(s)");
- for (FileInfo fileInfo : scssFiles) {
- logger.log(TreeLogger.INFO, " " + fileInfo.originalScssPath
- + " -> " + fileInfo.getOriginalCssPath());
-
- try {
- ScssStylesheet scss = ScssStylesheet
- .get(fileInfo.getAbsolutePath());
- if (!fileInfo.isMixin()) {
- scss.compile();
- InputStream is = new ByteArrayInputStream(
- scss.printState().getBytes());
-
- toReturn.add(this.emitInputStream(logger, is,
- fileInfo.getOriginalCssPath()));
- }
-
- fileInfo.getFile().delete();
- } catch (CSSException e) {
- logger.log(TreeLogger.ERROR, "SCSS compilation failed for "
- + fileInfo.getOriginalCssPath(), e);
- } catch (IOException e) {
- logger.log(TreeLogger.ERROR, "Could not write CSS file for "
- + fileInfo.getOriginalCssPath(), e);
- } catch (Exception e) {
- logger.log(TreeLogger.ERROR, "SCSS compilation failed for "
- + fileInfo.getOriginalCssPath(), e);
- }
- }
-
- return toReturn;
- }
-
- return artifacts;
- }
-
- /**
- * Writes the contents of an InputStream out to a file.
- *
- * @param contents
- * @param tempfile
- * @throws IOException
- */
- private void writeFromInputStream(InputStream contents, File tempfile)
- throws IOException {
- // write the inputStream to a FileOutputStream
- OutputStream out = new FileOutputStream(tempfile);
-
- int read = 0;
- byte[] bytes = new byte[1024];
-
- while ((read = contents.read(bytes)) != -1) {
- out.write(bytes, 0, read);
- }
-
- contents.close();
- out.flush();
- out.close();
- }
-
- /**
- * Create folder in temporary space on disk.
- *
- * @param partialPath
- * @return
- */
- private File createTempDir(String partialPath) {
- String baseTempPath = System.getProperty("java.io.tmpdir");
-
- File tempDir = new File(baseTempPath + File.separator + partialPath);
- if (!tempDir.exists()) {
- tempDir.mkdirs();
- }
-
- tempDir.deleteOnExit();
- return tempDir;
- }
-
- /**
- * Temporal storage for file info from Artifact.
- */
- private class FileInfo {
- private String originalScssPath;
- private File file;
-
- public FileInfo(File file, String originalScssPath) {
- this.file = file;
- this.originalScssPath = originalScssPath;
- }
-
- public boolean isMixin() {
- return file.getName().startsWith("_");
- }
-
- public String getAbsolutePath() {
- return file.getAbsolutePath();
- }
-
- public String getOriginalCssPath() {
- return originalScssPath.substring(0, originalScssPath.length() - 5)
- + ".css";
- }
-
- public File getFile() {
- return file;
- }
- }
- }
|