caslet
Version:
A simple content addressable system
195 lines (168 loc) • 5.32 kB
JavaScript
// Generated by CoffeeScript 1.4.0
(function() {
var FSCas, crypto, filelet, fs, funclet, loglet, path, uuid, _;
loglet = require('loglet');
fs = require('fs');
path = require('path');
crypto = require('crypto');
uuid = require('node-uuid');
funclet = require('funclet');
filelet = require('filelet');
_ = require('underscore');
FSCas = (function() {
FSCas.initialize = function(options, cb) {
var cas, defaultOpts;
defaultOpts = {
baseDir: path.join(process.env.HOME, '.caslet')
};
options = _.extend({}, defaultOpts, options);
cas = new this(options);
return cas.initialize(cb);
};
function FSCas(options) {
this.options = options;
this.pathsDir = path.join(this.options.baseDir, 'paths');
this.contentsDir = path.join(this.options.baseDir, 'contents');
this.tempDir = path.join(this.options.baseDir, 'temp');
this.cache = {};
}
FSCas.prototype.initialize = function(cb) {
var _this = this;
return funclet.each([this.pathsDir, this.contentsDir, this.tempDir], function(dirPath, next) {
return filelet.mkdirp(dirPath, next);
})["catch"](cb).done(function() {
return cb(null, _this);
});
};
FSCas.prototype.get = function(option, cb) {
if (option.path) {
return this._getViaPath(option.path, cb);
} else if (option.hash) {
return this._getViaHash(option.hash, cb);
} else {
return cb({
error: 'invalid_argument',
args: [option]
});
}
};
FSCas.prototype._getViaPath = function(pathsPath, cb) {
var _this = this;
if (this.cache.hasOwnProperty(pathsPath)) {
return this._getViaHash(this.cache[pathsPath].hash, cb);
} else {
return funclet.start(function(next) {
var normalized;
normalized = _this._pathsFilePath(pathsPath);
return fs.readFile(normalized, 'utf8', next);
})["catch"](cb).done(function(data) {
var parsed;
parsed = JSON.parse(data);
_this.cache[pathsPath] = parsed;
return _this._getViaHash(parsed.hash, cb);
});
}
};
FSCas.prototype._getViaHash = function(hash, cb) {
var hashPath, stream;
try {
hashPath = this._hashFilePath(hash);
stream = fs.createReadStream(hashPath);
return cb(null, stream);
} catch (e) {
return cb(e);
}
};
FSCas.prototype.store = function(instream, cb) {
var digest, outstream, tempFilePath,
_this = this;
try {
tempFilePath = this._tempFilePath();
digest = crypto.createHash('sha1');
digest.setEncoding('hex');
outstream = fs.createWriteStream(tempFilePath);
instream.once('close', function() {
var hash;
try {
digest.end();
outstream.end();
hash = digest.read();
instream.close();
outstream.close();
return _this._moveTempFile(tempFilePath, hash, cb);
} catch (e) {
return cb(e);
}
});
instream.once('error', cb);
outstream.once('error', cb);
digest.once('error', cb);
instream.pipe(digest);
return instream.pipe(outstream);
} catch (e) {
instream.close();
outstream.close();
return cb(e);
}
};
FSCas.prototype.storeWithPath = function(instream, destPath, cb) {
var hash,
_this = this;
hash = null;
return funclet.start(function(next) {
return _this.store(instream, next);
}).then(function(val, next) {
hash = val;
return _this._storePathMapping(hash, destPath, next);
})["catch"](cb).done(function() {
return cb(null, hash);
});
};
FSCas.prototype._storePathMapping = function(hash, destPath, cb) {
var normalizedPath, result,
_this = this;
normalizedPath = this._pathsFilePath(destPath);
result = {
type: 'fs',
hash: hash
};
return filelet.writeFile(normalizedPath, JSON.stringify(result, null, 2), 'utf8', function(err) {
if (err) {
return cb(err);
} else {
_this.cache[destPath] = result;
return cb(null);
}
});
};
FSCas.prototype._moveTempFile = function(tempFilePath, hash, cb) {
var hashPath;
try {
hashPath = this._hashFilePath(hash);
return filelet.move(tempFilePath, hashPath, function(err) {
if (err) {
return cb(err);
} else {
return cb(null, hash);
}
});
} catch (e) {
return cb(e);
}
};
FSCas.prototype._tempFilePath = function() {
return path.join(this.tempDir, uuid.v4());
};
FSCas.prototype._pathsFilePath = function(filePath) {
return path.join(this.pathsDir, filePath);
};
FSCas.prototype._hashFilePath = function(hash) {
var fileName, parentDir;
parentDir = hash.substring(0, 3);
fileName = hash.substring(3);
return path.join(this.contentsDir, parentDir, fileName);
};
return FSCas;
})();
module.exports = FSCas;
}).call(this);