001package org.jszip.sass;
002
003import org.codehaus.plexus.util.IOUtil;
004import org.jszip.pseudo.io.PseudoFile;
005import org.jszip.pseudo.io.PseudoFileInputStream;
006import org.jszip.pseudo.io.PseudoFileSystem;
007import org.mozilla.javascript.Context;
008
009import java.io.IOException;
010import java.io.InputStream;
011import java.util.Date;
012
013/**
014 * @author stephenc
015 * @since 31/01/2013 12:01
016 */
017public class PseudoFileSystemImporter {
018
019    private final PseudoFileSystem fs;
020    private final String encoding;
021
022    public PseudoFileSystemImporter(PseudoFileSystem fs, String encoding) {
023        this.fs = fs;
024        this.encoding = encoding;
025    }
026
027    /**
028     * Find a Sass file, if it exists.
029     * <p/>
030     * This is the primary entry point of the Importer.
031     * It corresponds directly to an `@import` statement in Sass.
032     * It should do three basic things:
033     * <p/>
034     * * Determine if the URI is in this importer's format.
035     * If not, return nil.
036     * * Determine if the file indicated by the URI actually exists and is readable.
037     * If not, return nil.
038     * * Read the file and place the contents in a {Sass::Engine}.
039     * Return that engine.
040     * <p/>
041     * If this importer's format allows for file extensions,
042     * it should treat them the same way as the default {Filesystem} importer.
043     * If the URI explicitly has a `.sass` or `.scss` filename,
044     * the importer should look for that exact file
045     * and import it as the syntax indicated.
046     * If it doesn't exist, the importer should return nil.
047     * <p/>
048     * If the URI doesn't have either of these extensions,
049     * the importer should look for files with the extensions.
050     * If no such files exist, it should return nil.
051     * <p/>
052     * The {Sass::Engine} to be returned should be passed `options`,
053     * with a few modifications. `:syntax` should be set appropriately,
054     * `:filename` should be set to `uri`,
055     * and `:importer` should be set to this importer.
056     *
057     * @param uri [String] The URI to import.
058     * @return the contents of the uri.
059     */
060    public String find(String uri) throws IOException {
061        Context.enter();
062        try {
063            fs.installInContext();
064            final PseudoFile file = fs.getPseudoFile(uri);
065            if (file.isFile()) {
066                InputStream is = null;
067                try {
068                    is = new PseudoFileInputStream(file);
069                    return IOUtil.toString(is, encoding);
070                } finally {
071                    IOUtil.close(is);
072                }
073            }
074            return null;
075        } finally {
076            fs.removeFromContext();
077            Context.exit();
078        }
079    }
080
081    /**
082     * Returns the time the given Sass file was last modified.
083     * <p/>
084     * If the given file has been deleted or the time can't be accessed
085     * for some other reason, this should return nil.
086     *
087     * @param uri [String] The URI of the file to check.
088     *            Comes from a `:filename` option set on an engine returned by this importer.
089     * @return [Time, nil]
090     */
091    public Date mtime(String uri) {
092        Context.enter();
093        try {
094            fs.installInContext();
095            final PseudoFile file = fs.getPseudoFile(uri);
096            if (file.isFile()) {
097                return new Date(file.lastModified());
098            }
099            return null;
100        } finally {
101            fs.removeFromContext();
102            Context.exit();
103        }
104    }
105
106}