All Downloads are FREE. Search and download functionalities are using the official Maven repository.

asset.pipeline.fs.ClasspathAssetResolver.groovy Maven / Gradle / Ivy

Go to download

JVM Asset Pipeline library for serving static web assets, bundling, minifying, and extensibility for transpiling.

The newest version!
package asset.pipeline.fs

import asset.pipeline.AssetFile
import asset.pipeline.AssetHelper
import asset.pipeline.GenericAssetFile
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j

/**
* Implementation of the {@link AssetResolver} interface for resolving files on the classpath.
* It is important to note that recursive scanning does not function unless an assets.list file is supplied
*
* @author David Estes
*/
@Slf4j
public class ClasspathAssetResolver extends AbstractAssetResolver {
    static String NATIVE_FILE_SEPARATOR = File.separator
    static String DIRECTIVE_FILE_SEPARATOR = '/'

    ClassLoader classLoader
    String prefixPath
    String assetListPath
    Collection assetList = []

    ClasspathAssetResolver(String name, String basePath, String assetListPath=null, ClassLoader classLoader = Thread.currentThread().contextClassLoader) {
        super(name)

        this.classLoader = classLoader
        this.prefixPath = basePath
        this.assetListPath = assetListPath
        loadAssetList()
    }


    private loadAssetList() {
        if (!assetListPath) {
            return
        }
        def resources = classLoader.getResources(assetListPath)
        resources.each { URL res ->
            assetList += res?.text?.tokenize("\n") ?: []
        }
    }

    AssetFile getAsset(String relativePath, String contentType = null, String extension = null, AssetFile baseFile = null) {
        if (!relativePath) {
            return null
        }
        def normalizedPath = AssetHelper.normalizePath(relativePath.replace(NATIVE_FILE_SEPARATOR, DIRECTIVE_FILE_SEPARATOR))
        if(!normalizedPath) {
            return null
        }
        def specs

        if (contentType) {
            specs = AssetHelper.getPossibleFileSpecs(contentType)
        } else {
            if (!extension) {
                extension = AssetHelper.extensionFromURI(relativePath)
            }
            specs = AssetHelper.assetFileClasses().findAll { it.extensions.contains(extension) }
        }

        AssetFile assetFile = resolveAsset(specs, prefixPath, normalizedPath, baseFile, extension)

        return assetFile
    }

    protected Closure createInputStreamClosure(URL file) {
        if (file) {
            return { -> new BufferedInputStream(file.openStream(), 512) }
        }
        return null
    }

    String relativePathToResolver(URL file, String scanDirectoryPath) {

        if (!file) {
            return null
        }
        def filePath = file.path
        if (filePath.contains(scanDirectoryPath)) {
            def i = filePath.indexOf(scanDirectoryPath)
            return filePath.substring(i + scanDirectoryPath.size() + 1)
        } else {
            throw new RuntimeException("File was not sourced from the same ScanDirectory ${filePath}")
        }
    }

    @CompileStatic
    URL getRelativeFile(String relativePath, String name) {
        if (name.startsWith('/')) {
            name = name.substring(1)
        }

        URL file = classLoader.getResource("$relativePath/$name")
        if (file?.getProtocol()?.equals("file")) {
            if(new File(file.getPath()).isDirectory()) {
                return null
            }
        } else if(file?.getPath()?.endsWith("/")) {
            return null
        }
        return file
    }

    @Override
    @CompileStatic
    protected String getFileName(URL url) {
        String path = url.path
        String name = path
        if (path.lastIndexOf('/'))
            name = path.substring(path.lastIndexOf('/'))
        return name
    }

    @CompileStatic
    List getAssets(String basePath, String contentType = null, String extension = null, Boolean recursive = true, AssetFile relativeFile = null, AssetFile baseFile = null) {
        def specs
        if (contentType) {
            specs = AssetHelper.getPossibleFileSpecs(contentType)
        }
        if (!assetList) {
            return []
        }

        def extensions = []
        if (extension) {
            extensions << extension
        } else if (specs) {
            for (spec in specs) {
                if(spec.extensions) {
                    extensions.addAll(spec.extensions)
                }
            }
        }

        String translatedBasePath = basePath
        if (!basePath.startsWith('/') && relativeFile != null) {
            List pathArgs = relativeFile.parentPath ? relativeFile.parentPath.split(DIRECTIVE_FILE_SEPARATOR).toList() : new ArrayList()
            //(path should be relative not canonical)
            String[] basePathArgs = basePath.split(DIRECTIVE_FILE_SEPARATOR)
            List parentPathArgs = pathArgs ? pathArgs[0..(pathArgs.size() - 1)] as List : [] as List
            parentPathArgs.addAll(basePathArgs.toList() as List)
            translatedBasePath = (parentPathArgs).join(DIRECTIVE_FILE_SEPARATOR)
            translatedBasePath = AssetHelper.normalizePath(translatedBasePath)
            translatedBasePath = translatedBasePath ? (translatedBasePath + "/") : null
        }

        List tree = []
        for (String filePath in assetList) {
            if (!translatedBasePath || filePath.startsWith(translatedBasePath)) {
                String[] mimeType = AssetHelper.assetMimeTypeForURI(filePath).toArray(new String[0])
                def url = classLoader.getResource("$prefixPath/$filePath")
                if (url && mimeType && contentType in mimeType) {
                    tree << assetForFile(url, contentType, baseFile, prefixPath)
                }

            }
        }
        return tree
    }

    /**
     * Uses file globbing to scan for files that need precompiled
     */
    public Collection scanForFiles(List excludePatterns, List includePatterns) {
        def fileList = []
        List excludedPatternList = excludePatterns ? excludePatterns : new ArrayList()
        List includedPatternList = includePatterns ? includePatterns : new ArrayList()

        for (String relativePath in assetList) {
            def entry = classLoader.getResource("$prefixPath/$relativePath")

            if (entry && !isFileMatchingPatterns(relativePath, excludedPatternList) || isFileMatchingPatterns(relativePath, includedPatternList)) {

                def assetFileClass = AssetHelper.assetForFileName(relativePath)
                if (assetFileClass) {
                    fileList << assetFileClass.newInstance(inputStreamSource: createInputStreamClosure(entry), path: relativePath, sourceResolver: this)
                } else {
                    fileList << new GenericAssetFile(inputStreamSource: createInputStreamClosure(entry), path: relativePath)
                }
            }
        }
        return fileList.unique { AssetFile a, AssetFile b -> a.path <=> b.path }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy