Source: apc-static/task/worker/link_theme_files.js

/**
 * Link theme image files.
 * @function task.worker.linkThemeImageFiles.
 * @param {object} config - Task configuration.
 * @param {string} config.srcDir - Source files directory.
 * @param {string} config.destDir - Destination directory.
 * @param {string} config.settingFile - Setting file name.
 * @param {string} config.themeName - Theme name. ('a', 'b' or 'c'...)
 * @param {function} callback - Callback when done.
 * @author Taka Okunishi
 */
var path = require('path'),
    util = require('util'),
    fs = require('fs'),
    format = util.format,
    debug = require('./_debug'),
    lib = require('../../lib'),
    file = lib.file,
    string = lib.string,
    camelize = string.camelize,
    relativeSymlink = file.relativeSymlink;

exports = module.exports = function (config, callback) {
    var srcDir = path.resolve(config.srcDir),
        destDir = path.resolve(config.destDir),
        settingFile = path.resolve(config.settingFile),
        setting = require(settingFile);
    fs.readdir(srcDir, function (err, dirnames) {
        if (err) {
            callback(err);
            return;
        }
        var async = require('async');
        async.series(
            dirnames
                .map(function (dirname) {
                    return {
                        dirname: path.resolve(srcDir, dirname),
                        themeName: exports._getThemeName(setting, dirname)
                    };
                })
                .filter(function (data) {
                    return fs.statSync(data.dirname).isDirectory();
                })
                .filter(function (data) {
                    return !!data.themeName;
                })
                .map(function (data) {
                    return function (callback) {
                        var srcSubDir = data.dirname,
                            themeName = data.themeName;
                        if (!themeName.match(/^theme\-/)) {
                            themeName = ['theme', themeName].join('-');
                        }
                        exports._findThemeFileFromDir(srcSubDir, themeName, function (err, srcNames) {
                            if (err) {
                                callback(err);
                                return;
                            }
                            exports._linkThemeFiles(srcSubDir, destDir, srcNames, themeName, function () {
                                callback(err);
                            });
                        });
                    }
                }),
            function (err) {
                callback(err);
            }
        )
    });
};

exports._findThemeFileFromDir = function (dirname, themeName, callback) {
    fs.readdir(dirname, function (err, filenames) {
        if (err) {
            callback(err);
            return;
        }
        var srcNames = filenames.filter(function (filename) {
            return !!filename.match(themeName);
        });
        if (!srcNames.length) {
            var errMsg = format('Image for theme %s is not found in %s.',
                themeName, dirname);
            callback(null, []);
//            callback(new Error(errMsg));
            return;
        }
        callback(null, srcNames);
    });
};

exports._getThemeName = function (setting, dirname) {
    var minimatch = require('minimatch');
    return setting[camelize(dirname)] ||
        Object.keys(setting).filter(function (key) {
            return minimatch(dirname, key);
        }).map(function (key) {
                return setting[key];
            }).shift();
};

exports._linkThemeFiles = function (srcDir, destDir, srcNames, themeName, callback) {
    require('async').parallel(
        srcNames.map(function (srcName) {
            return function (callback) {
                var destName = srcName.replace(themeName, '')
                    .replace(/\-\./g, '.')
                    .replace(/\-\-/g, '-');
                var src = path.resolve(srcDir, srcName),
                    dest = path.resolve(destDir, destName);
                relativeSymlink(src, dest, function (err) {
                    if (!err) {
                        debug.didCreateLink(dest, src);
                    }
                    callback(err);
                });
            }
        }),
        function (err) {
            callback(err);
        }
    );
};