started work on fs writer...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2015-12-05 01:19:06 +03:00
parent 4e31790f95
commit 0d47a559ba
4 changed files with 216 additions and 21 deletions

View File

@ -7,16 +7,21 @@
var pathlib = require('path')
var events = require('events')
var fse = require('fs.extra')
var fse = require('fs-extra')
var glob = require('glob')
var Promise = require('promise')
// XXX seems that we need different buids of this for use with node and nw...
// XXX BUG: nw-gyp does not support msvs2015...
//var sharp = require('sharp')
var guaranteeEvents = require('guarantee-events')
define(function(require){ var module = {}
console.log('>>> file')
//var DEBUG = DEBUG != null ? DEBUG : true
var data = require('data')
@ -73,8 +78,8 @@ module.gGlob = function(){
var listIndexes =
module.listIndexes =
function(base){
return gGlob(base +'/**/'+ INDEX_DIR)
function(base, index_dir){
return gGlob(base +'/**/'+ index_dir || INDEX_DIR)
}
@ -93,6 +98,8 @@ function listJSON(path, pattern){
var loadFile = Promise.denodeify(fse.readFile)
var writeFile = Promise.denodeify(fse.writeFile)
var ensureDir = Promise.denodeify(fse.ensureDir)
// XXX handle errors...
@ -174,7 +181,8 @@ function loadJSON(path){
// ...(a) seems more logical...
var loadIndex =
module.loadIndex =
function(path, logger){
function(path, index_dir, logger){
index_dir = index_dir || INDEX_DIR
// XXX should this be interactive (a-la EventEmitter) or as it is now
// return the whole thing as a block (Promise)...
// NOTE: one way to do this is use the logger, it will get
@ -182,7 +190,7 @@ function(path, logger){
return new Promise(function(resolve, reject){
// we've got an index...
// XXX do we need to check if if it's a dir???
if(pathlib.basename(path) == INDEX_DIR){
if(pathlib.basename(path) == index_dir){
logger && logger.emit('path', path)
@ -355,7 +363,7 @@ function(path, logger){
var loaders = []
// XXX handle 'error' event...
listIndexes(path)
listIndexes(path, index_dir)
// XXX handle errors...
.on('error', function(err){
logger && logger.emit('error', err)
@ -369,7 +377,7 @@ function(path, logger){
// dir (the parent dir to the index root)
// we do not need to include the index
// itself in the base path...
var p = path.split(INDEX_DIR)[0]
var p = path.split(index_dir)[0]
res[p] = obj[path]
}))
})
@ -401,8 +409,9 @@ function(path, logger){
// XXX handle errors....
var loadPreviews =
module.loadPreviews =
function(base, previews, absolute_path){
function(base, previews, index_dir, absolute_path){
previews = previews || {}
index_dir = index_dir || INDEX_DIR
return new Promise(function(resolve, reject){
listIndexes(base)
@ -438,7 +447,7 @@ function(base, previews, absolute_path){
// add a preview...
// NOTE: this will overwrite a previews if they are found in
// several locations...
images[gid].preview[res] = INDEX_DIR +'/'+ path.split(INDEX_DIR)[1]
images[gid].preview[res] = index_dir +'/'+ path.split(index_dir)[1]
})
})
.on('end', function(){
@ -518,8 +527,130 @@ module.buildIndex = function(index, base_path){
/*********************************************************************/
// Builder...
// - read list
// - generate previews (use config)
// - build images/data
// .loadURLs(..)
// - write (writer)
/*********************************************************************/
// Writer...
//
// This is just like the loader, done in two stages:
// - format dependent de-construction (symetric to buildIndex(..))
// - generic writer...
//
// NOTE: for now we'll stick to the current format...
// this will take the output of .json()
//
// .data
// .images
// .bookmarked
// .marked
// .tags
// .current
//
// NOTE: this will prepare for version 2.0 file structure...
//
// XXX write tags, marks and bookmarks only if changed...
var prepareIndex =
module.prepareIndex =
function(json, changes){
changes = changes || {}
var res = {
data: json.data,
current: json.data.current,
}
// NOTE: we write the whole set ONLY if an item is true or undefined
// i.e. not false...
if(changes.bookmarked !== false){
res.bookmarked = json.data.tags.bookmark
}
if(changes.selected !== false){
res.marked = json.data.tags.selected
}
if(changes.tags !== false){
res.tags = json.data.tags
}
// clean out some stuff from data...
delete res.data.tags.bookmark
delete res.data.tags.selected
delete res.data.tags
if(changes.images){
var diff = res['images-diff'] = {}
changes.images.forEach(function(gid){
diff[gid] = json.images[gid]
})
} else {
res.images = json.images
}
return res
}
var FILENAME = '${DATE}-${KEYWORD}.${EXT}'
var writeIndex =
module.writeIndex =
function(json, path, filename_tpl, logger){
filename_tpl = filename_tpl || FILENAME
// XXX for some reason this gets the unpatched node.js Date, so we
// get the patched date explicitly...
var date = window.Date.timeStamp()
var files = []
// build the path if it does not exist...
return ensureDir(path)
.catch(function(err){
logger && logger.emit('error', err)
})
.then(function(){
logger && logger.emit('path', path)
// write files...
// NOTE: we are not doing this sequencilly as there will not
// be too many files...
return Promise
.all(Object.keys(json).map(function(keyword){
var file = path +'/'+ (filename_tpl
.replace('${DATE}', date)
.replace('${KEYWORD}', keyword)
.replace('${EXT}', 'json'))
return ensureDir(pathlib.dirname(file))
.then(function(){
files.push(file)
var data = JSON.stringify(json[keyword])
logger && logger.emit('queued', file)
return writeFile(file, data, 'utf8')
.catch(function(err){
logger && logger.emit('error', err)
})
.then(function(){
logger && logger.emit('written', file)
})
})
}))
.then(function(){
logger && logger.emit('done', files)
})
})
}

View File

@ -18,10 +18,11 @@
"dependencies": {
"flickrapi": "^0.3.28",
"fs-walk": "0.0.1",
"fs.extra": "^1.2.1",
"fs-extra": "*",
"glob": "^4.0.6",
"guarantee-events": "^1.0.0",
"promise": "^6.0.1",
"requirejs": "*"
"requirejs": "*",
"sharp": "^0.12.0"
}
}

View File

@ -4,7 +4,6 @@
*
**********************************************************************/
window.nodejs = (typeof(process) === 'object' && process.features.uv)
? {
require: window.require,

View File

@ -2079,13 +2079,6 @@ module.AutoAlignRibbons = ImageGridFeatures.Feature({
})
// XXX add a feature not to align the ribbons and focus the central
// image on next prev ribbon...
// XXX in general need a way to control .nextRibbon(..)/.prevRibbon(..)
// image selection...
// XXX this should also define up/down navigation behavior e.g. what to
// focus on next/prev ribbon...
// XXX should .alignByOrder(..) be a feature-specific action or global
// as it is now???
var AlignRibbonsToImageOrder =
@ -2157,6 +2150,7 @@ module.ManualAlignRibbons = ImageGridFeatures.Feature({
//---------------------------------------------------------------------
// XXX at this point this does not support target lists...
// XXX shift up/down to new ribbon is not too correct...
var ShiftAnimation =
module.ShiftAnimation = ImageGridFeatures.Feature({
title: '',
@ -2166,7 +2160,9 @@ module.ShiftAnimation = ImageGridFeatures.Feature({
depends: ['ui'],
handlers: [
['shiftImageUp.pre shiftImageDown.pre',
//['shiftImageUp.pre shiftImageDown.pre '
// +'travelImageUp.pre travelImageDown.pre',
['shiftImageUp.pre shiftImageDown.pre',
function(target){
// XXX do not do target lists...
if(target != null && target.constructor === Array
@ -3329,10 +3325,16 @@ if(window.nodejs != null){
var FileSystemLoaderActions = actions.Actions({
config: {
'index-dir': '.ImageGrid',
},
// NOTE: when passed no path this will not do anything...
// XXX should this set something like .path???
// ...and how should this be handled when merging indexes or
// viewing multiple/clustered indexes???
// XXX add a symmetric equivalent to .prepareIndexForWrite(..) so as
// to enable features to load their data...
// XXX look inside...
loadIndex: ['File/Load index',
function(path, logger){
@ -3345,7 +3347,7 @@ var FileSystemLoaderActions = actions.Actions({
// XXX get a logger...
logger = logger || this.logger
file.loadIndex(path, logger)
file.loadIndex(path, this.config['index-dir'], logger)
.then(function(res){
// XXX if res is empty load raw...
@ -3593,6 +3595,67 @@ module.FileSystemLoaderUI = ImageGridFeatures.Feature({
//---------------------------------------------------------------------
// fs writer...
var FileSystemWriterActions = actions.Actions({
config: {
// XXX should this include the '.ImageGrid/' section???
'index-filename-template': '${DATE}-${KEYWORD}.${EXT}',
},
// This is here so as other features can participate in index
// preparation...
// There are several stages features can control the output format:
// 1) .json() action
// - use this for global high level serialization format
// - the output of this is .load(..) compatible
// 2) .prepareIndex(..) action
// - use this for file system write preparation
// - this directly affects the index structure
prepareIndexForWrite: ['File/Prepare index for writing',
function(json){
return file.prepareIndex(json || this.json())
}],
// XXX should this get the base uncropped state or the current state???
// XXX get real base path...
saveIndex: ['File/save index',
function(path, logger){
// XXX get real base path...
path = path || this.base_path +'/'+ this.config['index-dir']
file.writeIndex(
this.prepareIndexForWrite(),
path,
this.config['index-filename-template'],
logger || this.logger)
}],
// XXX same as ctrl-shif-s in gen3
exportView: ['File/Export current view',
function(){
}],
// XXX export current state as a full loadable index
// XXX might be interresting to unify this and .exportView(..)
exportCollection: ['File/Export as collection',
function(){
}],
})
var FileSystemWriter =
module.FileSystemWriter = ImageGridFeatures.Feature({
title: '',
doc: '',
tag: 'fs-writer',
// NOTE: this is mostly because of the base path handling...
depends: ['fs-loader'],
actions: FileSystemWriterActions,
isApplicable: function(){
return window.nodejs != null
},
})
//---------------------------------------------------------------------
@ -3623,6 +3686,7 @@ ImageGridFeatures.Feature('viewer-testing', [
'fs-loader',
'fs-loader-ui',
'fs-writer',
'app-control',