diff --git a/assetman.js b/assetman.js index 63b5776..d07e465 100644 --- a/assetman.js +++ b/assetman.js @@ -14,41 +14,14 @@ var path = require('path'), fs = require('fs'), util = require('util'), exec = require('child_process').exec, - mkdirp = require('mkdirp'), minimatch = require('minimatch'), - Glob = require("glob").Glob, + glob = require('glob'), + ninja = require('ninja-build-gen')(), checkHelp, showHelp, help, parse; -var currentDir = process.cwd(), - previousDir, assetConfig, - configPath; - -// Search for Asset Config file starting with working directory and working -// up the hierarchy -// curr and prev will be the same when root is reached -while (currentDir != previousDir) { - configPath = path.join(currentDir, 'assets.json'); - if (fs.existsSync(configPath)) { - assetConfig = require(configPath); - - // resolve paths - assetConfig.boar_repo = path.resolve(currentDir, assetConfig.boar_repo); - assetConfig.target_dir = path.resolve(currentDir, assetConfig.target_dir); - break; - } - - previousDir = currentDir; - currentDir = path.join(currentDir, '..'); -} - -if (!assetConfig) { - console.error('ERROR: Could not find assets.json file'); - process.exit(1); -} - // check argv for -h or --help checkHelp = function(argv) { var len = argv.length, @@ -116,180 +89,83 @@ parse = function(settings, argv) { } }; -var convert, - convertAll, - convertRecent, - convertOne, - getConverter, - filterConverters; - -// convert one file with the provided converter -convert = function(input, converter) { - var filename, - indir, outdir, - absInput, absFilename, - re, i, ext; - - // replace extension - // output = input.replace(re, converter.ext); - filename = input.slice(0, input.lastIndexOf(path.extname(input))); - - indir = assetConfig.boar_repo; - outdir = assetConfig.target_dir; - - absInput = path.join(indir, input); - absFilename = path.join(outdir, filename); - // make directories if they don't exist - mkdirp(path.dirname(absFilename), function(err) { - if (err) { - throw err; - } - - // var commands = con - // If a string, turn into array: [string] - var commands = ([]).concat(converter.commands); - - commands.forEach(function(command) { - // Populate convert command - command = command.replace('%i', absInput).replace('%n', absFilename); - - exec(command, - function(error, stdout, stderr) { - if (error) throw err; - console.info('Processed: ' + input); - }); - }); - }); -}; - -// Get converter from asset config and check input file against filters -getConverter = function(file, converters) { - var len = converters.length, - i, converter; - - for (i = 0; i < len; ++i) { - converter = converters[i]; +var getConfig = function(srcPath) { + var configPath = path.join(srcPath, 'assets.json'); - if (minimatch(file, converter.pattern)) { - return converter; - } + if (fs.existsSync(configPath)) { + return require(configPath); + } else { + console.error('ERROR: The source directory "' + srcPath + '" does not appear to contain assets.json.'); + process.exit(1); } - - return null; }; -// Get converters with the right tags -filterConverters = function(filters) { - // filters may be 'arguments' which isn't a proper array - filters = Array.prototype.slice.call(filters); +var generate = function(srcPath) { + srcPath = srcPath || ''; + srcPath = path.resolve(process.cwd(), srcPath); - var converters; - if (filters.length !== 0) { - converters = assetConfig.converters.filter(function(converter) { - return !converter.tag || filters.indexOf(converter.tag) !== -1; - }); - } else { - converters = assetConfig.converters; - } + var buildPath = process.cwd(), + assetConfig = getConfig(srcPath); - return converters; -}; + var srcRelPath = path.relative(buildPath, srcPath); -// Converts all files in the boar repo -convertAll = function() { - var indir = assetConfig.boar_repo, - converters = filterConverters(arguments); + var compareEchoPath = path.join(__dirname, 'compare_echo.js'), + command = 'node ' + compareEchoPath + ' "$glob" $out ' + srcRelPath; + ninja.rule('compare_echo') + .restat(true) + .description('Update file list') + .run(command); - var glob, cache = null; - converters.forEach(function(converter) { - glob = new Glob(converter.pattern, { cache: cache, cwd: indir }); - cache = glob.cache; + ninja.rule('rebuild') + .generator(true) + .description('Generate build.ninja') + .run('assetman.cmd ' + srcRelPath); - glob.on("match", function(file) { - convert(file, converter); - }) - }); -}; + for (var rule in assetConfig.rules) { + ninja.rule(rule).run(assetConfig.rules[rule]); + } -// Converts all files that were recently modified in the boar repo -convertRecent = function() { - var infoPath = path.join(assetConfig.boar_repo, '.boar/info'), - converters = filterConverters(arguments); + var patterns = []; + var assets = []; + for (var pattern in assetConfig.files) { + patterns.push(pattern); + var files = glob.sync(pattern, {cwd: srcPath}); - fs.readFile(infoPath, function(err, boarJSON) { - if (err) { - console.error("ERROR: " + assetConfig.boar_repo + " is not a boar repo"); - process.exit(1); - } + var len = files.length, i; + for (i = 0; i < len; ++i) { + var target = path.relative(buildPath, path.join(srcPath, files[i])); + var inRelPath = files[i]; + var relDir = path.dirname(inRelPath); - var boarInfo = JSON.parse(boarJSON), - revision = boarInfo.session_id, - repoPath = boarInfo.repo_path, - boarLog = util.format('boar --repo=%s log -vr %d', repoPath, revision); + var filename = path.basename(inRelPath, path.extname(inRelPath)); - // run boar log - exec(boarLog, function(error, stdout, stderr) { - if (error || stderr) { - console.error("ERROR: Error executing boar log: " + (error || stderr)); - process.exit(1); - } + var outPatterns = assetConfig.files[pattern]; + for (var outPattern in outPatterns) { + var rule = outPatterns[outPattern]; + var outName = outPattern.replace(/\$filename/, filename); + var outRelPath = path.join(relDir, outName); - // Scan for new or modified files - // A new file - // M modified file - var modified = stdout.match(/^[AM]\s*(.+)/m), - len = modified.length, - i, file, - converter; - - // convert each modified/new file - for (i = 1; i < len; i++) { - file = modified[i]; - converter = getConverter(file, converters); - if (converter) { - convert(file, converter); - } else { - console.log("WARN: No converter for: " + file); - } + ninja.edge(outRelPath).from(target).using(rule); + assets.push(outRelPath); } - }); - }); -}; - -// converts all files that meets provided pattern -convertOne = function(pattern) { - if (!pattern) { - console.error("ERROR: Pattern must be supplied to convert command."); - process.exit(1); + } } - var indir = assetConfig.boar_repo; + var globs = patterns.join(' '); + ninja.edge('.dirty'); + ninja.edge('.files').from('.dirty').using('compare_echo').assign('glob', globs); - var glob = new Glob(pattern, { cwd: indir }); + var assetConfigPath = path.join(srcRelPath, 'assets.json'); + ninja.edge('build.ninja').from(['.files', assetConfigPath]).using('rebuild'); - glob.on('match', function(file) { - var converter = getConverter(file, assetConfig.converters); + ninja.edge('assets').from(assets); + ninja.byDefault('assets'); - if (converter) { - convert(file, converter); - } else { - console.warn("WARN: No converter for: " + file); - } - }); + ninja.save('build.ninja'); }; var commandSettings = { - commands: { - all: { - action: convertAll - }, - recent: { - action: convertRecent - }, - convert: { - action: convertOne - } - } + action: generate }; var argv = process.argv.slice(2); diff --git a/compare_echo.js b/compare_echo.js new file mode 100644 index 0000000..db0b500 --- /dev/null +++ b/compare_echo.js @@ -0,0 +1,19 @@ +var glob = require('glob'), + fs = require('fs'), + args = process.argv.slice(2), + cwd = args[2] || process.cwd(); + +// construct search patterns +var patterns = args[0].split(' '), + pattern = patterns.length > 1 ? '{' + patterns.join(',') + '}' : patterns[0]; + +// collect files that match pattern +var files = glob.sync(pattern, {cwd: cwd}).join('\n'); + +// update file list in output if they don't match +var outpath = args[1]; +fs.readFile(outpath, {encoding: 'utf8'}, function(_, oldfiles) { + if (oldfiles !== files) { + fs.writeFileSync(outpath, files); + } +}); diff --git a/example-assets.json b/example-assets.json index 0d44a44..6ffaf18 100644 --- a/example-assets.json +++ b/example-assets.json @@ -1,11 +1,6 @@ { - "boar_repo": "RawAssets", - "target_dir": "Assets", - "converters" : [ - { - "pattern": "**/*.psd", - "tag": "images", - "commands": "convert \"%i[0]\" \"%n.png\"" - } - ] + "**/*.psd": { + "$filename.png": "convert \"$in[0]\" -resize 50% \"$out\"", + "$filename@2x.png": "convert \"$in[0]\" \"$out\"" + } } diff --git a/package.json b/package.json index 5cfd53a..3128a1b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "assetman", "description": "Boar-to-DVCS asset manager", - "version": "0.4.1", + "version": "1.0.0", "homepage": "https://github.com/miningold/assetman", "author": { "name": "Tylor Reynolds", @@ -30,7 +30,7 @@ "dependencies": { "glob": "~3.2.6", "minimatch": "~0.2.12", - "mkdirp": "~0.3.5" + "ninja-build-gen": "~0.1.1" }, "preferGlobal": "true", "bin": {