Skip to content

Instantly share code, notes, and snippets.

@joliss
Last active March 1, 2017 20:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joliss/e46516c5e019d5c431546c41506c881f to your computer and use it in GitHub Desktop.
Save joliss/e46516c5e019d5c431546c41506c881f to your computer and use it in GitHub Desktop.
// module: fso, for in-memory file system objects
// FSObject is the raw object that will be part of the
// internal Broccoli plugin API. Need better name?
// (Git terminology: File = blob, Directory = tree,
// FSObject = object.)
class FSObject { }
class File extends FSObject {
executable: bool
revision: int // mtime and size go into this; like a hash in a Merkle tree but fast
contentLocation: string // absolute path on disk
}
class Directory extends FSObject {
revision: int // max of all child revision
entries: Map<string, FSObject> // string is a single path segment, e.g. "src"
}
// want this in a shared node module
fso.read(path) -> FSObject
fso.write(path, fsObject)
fso.update(path, oldFsObject, newFsObject)
// in broccoli-plugin subclasses:
// easy to implement:
this.fs.statSync(this.in[0], 'src/foo.js')
// With facade. Harder to implement but cuter:
this.in[0].statSync('src/foo.js')
// Want to be able to pass things forward:
this.out.copy(someFsObject, 'foo/bar') // can be file or directory
// someFileObject.contentLocation could point anywhere. Are we OK not really
// knowing where it came from?
this.out.symlinkSync('ourCacheDir/bar.js', 'foo/bar.js')
// creates a new File object with { contentLocation: 'ourCacheDir/bar.js' }
this.out.writeSync('foo/bar.js', 'some text')
// We actually write to outputPath/foo/bar.js, and do
// this.out.get('foo').set('bar.js', new File(contentLocation: '.../foo/bar.js'))
// On every build, we start with a new empty this.out
// Is this.cache an FSObject cache?
this.cache.writeSync('dir1/foo.js', '// foo')
this.cache.copy(someFsObjectFromThisDotIn, 'dir2/foo')
// dir2/foo might become stale, but the answer is perhaps simply
// "don't do this" -- make sure you don't keep stale objects around
// or you'll get FileNotFound errors because contentLocation goes invalid
// Cache invalidation pattern:
oldCache = this.cache.get('current')
this.cache.mkdir('new')
newCache = this.cache.get('new')
// Iterate over input, copy stuff from oldCache to newCache.
// At the end, overwrite current with new:
this.cache.move('new', 'current')
// Can get stuff that FSTree consumes:
this.in[0].getEntries()
// To start implementing:
// broccoli-plugin can start implementing some facade like this and just
// always read and write from disk for compat.
// Gives us incremental outputPath updating, but no savings on reading.
// Once we're happy, we turn the underlying FSObject into an official
// Broccoli API:
// Let's not sniff like this:
this.inputNodes[0].out // brittle!
this.inputNodes[0].__broccoliGetInfo__ // still brittle!
// Then add feature flag: fsobject
// Broccoli core:
// calls fso.read/fso.write as needed
// broccoli-plugin:
// can request physical files or FSObjects from Broccoli core
// call fso.read/fso.write only to deal with old Builder versions (compat)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment