@@ -2,7 +2,7 @@ import { h, Component } from 'preact'; | |||||
import WBTable from 'wb-table'; | import WBTable from 'wb-table'; | ||||
import WBBreadcrumbs from 'wb-breadcrumbs'; | import WBBreadcrumbs from 'wb-breadcrumbs'; | ||||
import { WBManifestReader } from 'wb-collection-manifest'; | import { WBManifestReader } from 'wb-collection-manifest'; | ||||
// import WBManifestReader from 'wb-manifest-reader'; | |||||
//import WBManifestReader from 'wb-manifest-reader'; | |||||
import WBPagination from 'wb-pagination'; | import WBPagination from 'wb-pagination'; | ||||
import makeArvadosRequest from 'make-arvados-request'; | import makeArvadosRequest from 'make-arvados-request'; | ||||
import wbDownloadFile from 'wb-download-file'; | import wbDownloadFile from 'wb-download-file'; | ||||
@@ -43,7 +43,7 @@ class WBManifestReader { | |||||
dir[fileName] = [[], 0]; | dir[fileName] = [[], 0]; | ||||
if (!(dir[fileName] instanceof Array)) | if (!(dir[fileName] instanceof Array)) | ||||
throw Error('Conflict trying to create a file - a directory with the same name already exists: ' + fileName); | throw Error('Conflict trying to create a file - a directory with the same name already exists: ' + fileName); | ||||
this.appendReferences(dir[fileName], locators, position, size); | |||||
//this.appendReferences(dir[fileName], locators, position, size); | |||||
} | } | ||||
appendReferences(file, locators, position, size) { | appendReferences(file, locators, position, size) { | ||||
@@ -18,16 +18,28 @@ function mkpath(parent, path) { | |||||
return dir; | return dir; | ||||
} | } | ||||
function appendFile(dir, name, sidx, seg) { | |||||
if (name in dir && (!(dir[name] instanceof Array))) | |||||
throw Error('Directory with the same name already exists'); | |||||
if (!(name in dir)) | |||||
dir[name] = []; | |||||
const f = dir[name]; | |||||
f.push([ sidx, seg[0], seg[1] ]); | |||||
function makeFile(dir, name) { | |||||
if (name in dir) { | |||||
if (!(dir[name] instanceof Array)) | |||||
throw Error('Directory with the same name already exists'); | |||||
return dir[name]; | |||||
} | |||||
const f = [[], 0]; | |||||
dir[name] = f; | |||||
return f; | return f; | ||||
} | } | ||||
function appendFile(f, sidx, seg) { | |||||
f[0].push([ sidx, seg[0], seg[1] ]); | |||||
//f[1] += seg[1]; | |||||
return f; | |||||
} | |||||
function unescapeName(name) { | |||||
return name.replace(/(\\\\|\\[0-9]{3})/g, | |||||
(_, $1) => ($1 === '\\\\' ? '\\' : String.fromCharCode(parseInt($1.substr(1), 8)))); | |||||
} | |||||
function process(streams) { | function process(streams) { | ||||
const rootDir = {}; | const rootDir = {}; | ||||
@@ -55,19 +67,22 @@ function parse(manifestText) { | |||||
const streams = []; | const streams = []; | ||||
let locators = []; | let locators = []; | ||||
let segments = []; | |||||
let streamName; | let streamName; | ||||
let accum = ''; | let accum = ''; | ||||
let tokenStart = 0; | let tokenStart = 0; | ||||
let lastFile = null; | |||||
let lastPath = null; | |||||
const rootDir = {}; | |||||
for (let i = 0; i < manifestText.length; i++) { | for (let i = 0; i < manifestText.length; i++) { | ||||
const c = manifestText[i]; | const c = manifestText[i]; | ||||
if (mode === M_STREAM_NAME) { | if (mode === M_STREAM_NAME) { | ||||
if (c === ' ') { | if (c === ' ') { | ||||
mode = M_LOCATORS; | mode = M_LOCATORS; | ||||
streamName = accum; | |||||
streamName = unescapeName(accum); | |||||
accum = ''; | accum = ''; | ||||
tokenStart = i + 1; | tokenStart = i + 1; | ||||
} else { | } else { | ||||
@@ -97,14 +112,26 @@ function parse(manifestText) { | |||||
} else if (mode === M_FILE_SEGMENTS) { | } else if (mode === M_FILE_SEGMENTS) { | ||||
if (c === ' ' || c === '\n') { | if (c === ' ' || c === '\n') { | ||||
let seg = accum.split(':'); | let seg = accum.split(':'); | ||||
seg = [Number(seg[0]), Number(seg[1]), seg[2]]; | |||||
segments.push(seg); | |||||
seg = [Number(seg[0]), Number(seg[1]), seg.slice(2).join(':')]; | |||||
const path = streamName + '/' + unescapeName(seg[2]); | |||||
let f; | |||||
if (path !== lastPath) { | |||||
let dirName = path.split('/'); | |||||
const fileName = dirName[dirName.length - 1]; | |||||
dirName = dirName.slice(0, dirName.length - 1); | |||||
const dir = mkpath(rootDir, dirName); | |||||
f = makeFile(dir, fileName); | |||||
lastPath = path; | |||||
lastFile = f; | |||||
} else { | |||||
f = lastFile; | |||||
} | |||||
appendFile(f, streams.length, seg); | |||||
accum = ''; | accum = ''; | ||||
tokenStart = i + 1; | tokenStart = i + 1; | ||||
if (c === '\n') { | if (c === '\n') { | ||||
streams.push([streamName, locators, segments]); | |||||
streams.push([ streamName, locators ]); | |||||
locators = []; | locators = []; | ||||
segments = []; | |||||
mode = M_STREAM_NAME; | mode = M_STREAM_NAME; | ||||
} | } | ||||
} else { | } else { | ||||
@@ -114,13 +141,40 @@ function parse(manifestText) { | |||||
} | } | ||||
} | } | ||||
return streams; | |||||
return { rootDir, streams }; | |||||
} | |||||
function findDir(parent, path) { | |||||
if (typeof(path) === 'string') | |||||
path = path.split('/'); | |||||
if (path[0] !== '.') | |||||
throw Error('Path must start with a dot (.)'); | |||||
let dir = parent; | |||||
for (let i = 1; i < path.length; i++) { | |||||
if (!(path[i] in dir)) | |||||
throw Error('Directory not found'); | |||||
dir = dir[path[i]]; | |||||
} | |||||
return dir; | |||||
} | } | ||||
class WBManifestReader { | class WBManifestReader { | ||||
constructor(manifestText) { | constructor(manifestText) { | ||||
this.streams = parse(manifestText); | |||||
this.rootDir = process(this.streams); | |||||
const {rootDir, streams} = parse(manifestText); | |||||
this.rootDir = rootDir; | |||||
this.streams = streams; | |||||
//this.rootDir = process(this.streams); | |||||
} | |||||
listDirectory(path) { | |||||
let dir = findDir(this.rootDir, path); | |||||
let keys = Object.keys(dir); | |||||
keys.sort(); | |||||
let subdirs = keys.filter(k => !(dir[k] instanceof Array)); | |||||
let files = keys.filter(k => (dir[k] instanceof Array)); | |||||
let res = subdirs.map(k => [ 'd', k, null ]); | |||||
res = res.concat(files.map(k => [ 'f', k, dir[k][1] ])); | |||||
return res; | |||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,181 @@ | |||||
function mkdir(parent, name) { | |||||
if (name in parent && (parent[name] instanceof Array)) | |||||
throw Error('File with the same name already exists'); | |||||
if (name in parent) | |||||
return parent[name]; | |||||
const dir = {}; | |||||
parent[name] = dir; | |||||
return dir; | |||||
} | |||||
function mkpath(parent, path) { | |||||
if (typeof(path) === 'string') | |||||
path = path.split('/'); | |||||
let dir = parent; | |||||
for (let i = 1; i < path.length; i++) { | |||||
dir = mkdir(dir, path[i]); | |||||
} | |||||
return dir; | |||||
} | |||||
function makeFile(dir, name) { | |||||
if (name in dir) { | |||||
if (!(dir[name] instanceof Array)) | |||||
throw Error('Directory with the same name already exists'); | |||||
return dir[name]; | |||||
} | |||||
const f = [[], 0]; | |||||
dir[name] = f; | |||||
return f; | |||||
} | |||||
function appendFile(f, sidx, seg) { | |||||
f[0].push([ sidx, seg[0], seg[1] ]); | |||||
//f[1] += seg[1]; | |||||
return f; | |||||
} | |||||
function unescapeName(name) { | |||||
return name.replace(/(\\\\|\\[0-9]{3})/g, | |||||
(_, $1) => ($1 === '\\\\' ? '\\' : String.fromCharCode(parseInt($1.substr(1), 8)))); | |||||
} | |||||
function process(streams) { | |||||
const rootDir = {}; | |||||
streams.map((s, sidx) => { | |||||
const [ streamName, locators, segments ] = s; | |||||
const streamDir = mkpath(rootDir, streamName); | |||||
segments.map((seg, segidx) => { | |||||
let name = seg[2].split('/'); | |||||
const dir = (name.length === 1 ? streamDir : | |||||
mkpath(streamDir, ['.'].concat(name.slice(0, name.length - 1)))); | |||||
name = name[name.length - 1]; | |||||
appendFile(dir, name, sidx, seg); | |||||
}); | |||||
}); | |||||
return rootDir; | |||||
} | |||||
function parse(manifestText) { | |||||
const M_STREAM_NAME = 0; | |||||
const M_LOCATORS = 1; | |||||
const M_FILE_SEGMENTS = 2; | |||||
let mode = M_STREAM_NAME; | |||||
const streams = []; | |||||
let locators = []; | |||||
let streamName; | |||||
let accum = ''; | |||||
let tokenStart = 0; | |||||
let lastFile = null; | |||||
let lastPath = null; | |||||
const rootDir = {}; | |||||
for (let i = 0; i < manifestText.length; i++) { | |||||
const c = manifestText[i]; | |||||
if (mode === M_STREAM_NAME) { | |||||
if (c === ' ') { | |||||
mode = M_LOCATORS; | |||||
streamName = unescapeName(accum); | |||||
accum = ''; | |||||
tokenStart = i + 1; | |||||
} else { | |||||
accum += c; | |||||
} | |||||
} else if (mode === M_LOCATORS) { | |||||
if (c === ':') { | |||||
mode = M_FILE_SEGMENTS; | |||||
accum = ''; | |||||
i = tokenStart - 1; | |||||
let pos = 0; | |||||
locators = locators.map(loc => { | |||||
const r = loc.concat([ pos, pos + loc[1] ]); | |||||
pos += loc[1]; | |||||
return r; | |||||
}); | |||||
} else if (c === ' ') { | |||||
const sz = Number(accum.split('+')[1]); | |||||
locators.push([accum, sz]); | |||||
accum = ''; | |||||
tokenStart = i + 1; | |||||
} else { | |||||
accum += c; | |||||
} | |||||
} else if (mode === M_FILE_SEGMENTS) { | |||||
if (c === ' ' || c === '\n') { | |||||
let seg = accum.split(':'); | |||||
seg = [Number(seg[0]), Number(seg[1]), seg.slice(2).join(':')]; | |||||
const path = streamName + '/' + unescapeName(seg[2]); | |||||
let f; | |||||
if (path !== lastPath) { | |||||
let dirName = path.split('/'); | |||||
const fileName = dirName[dirName.length - 1]; | |||||
dirName = dirName.slice(0, dirName.length - 1); | |||||
const dir = mkpath(rootDir, dirName); | |||||
f = makeFile(dir, fileName); | |||||
lastPath = path; | |||||
lastFile = f; | |||||
} else { | |||||
f = lastFile; | |||||
} | |||||
appendFile(f, streams.length, seg); | |||||
accum = ''; | |||||
tokenStart = i + 1; | |||||
if (c === '\n') { | |||||
streams.push([ streamName, locators ]); | |||||
locators = []; | |||||
mode = M_STREAM_NAME; | |||||
} | |||||
} else { | |||||
accum += c; | |||||
} | |||||
} | |||||
} | |||||
return { rootDir, streams }; | |||||
} | |||||
function findDir(parent, path) { | |||||
if (typeof(path) === 'string') | |||||
path = path.split('/'); | |||||
if (path[0] !== '.') | |||||
throw Error('Path must start with a dot (.)'); | |||||
let dir = parent; | |||||
for (let i = 1; i < path.length; i++) { | |||||
if (!(path[i] in dir)) | |||||
throw Error('Directory not found'); | |||||
dir = dir[path[i]]; | |||||
} | |||||
return dir; | |||||
} | |||||
class WBManifestReader { | |||||
constructor(manifestText) { | |||||
const {rootDir, streams} = parse(manifestText); | |||||
this.rootDir = rootDir; | |||||
this.streams = streams; | |||||
//this.rootDir = process(this.streams); | |||||
} | |||||
listDirectory(path) { | |||||
let dir = findDir(this.rootDir, path); | |||||
let keys = Object.keys(dir); | |||||
keys.sort(); | |||||
let subdirs = keys.filter(k => !(dir[k] instanceof Array)); | |||||
let files = keys.filter(k => (dir[k] instanceof Array)); | |||||
let res = subdirs.map(k => [ 'd', k, null ]); | |||||
res = res.concat(files.map(k => [ 'f', k, dir[k][1] ])); | |||||
return res; | |||||
} | |||||
} | |||||
export default WBManifestReader; |