@@ -3,6 +3,7 @@ import { statSync, existsSync, mkdirSync } from 'node:fs'
33import { writeFile } from 'node:fs/promises'
44import { connect } from '@existdb/node-exist'
55import Bottleneck from 'bottleneck'
6+ import { getGlobMatcher } from '../utility/glob.js'
67
78/**
89 * @typedef { import("@existdb/node-exist").NodeExist } NodeExist
@@ -30,15 +31,6 @@ import Bottleneck from 'bottleneck'
3031 * @prop {String[] } exclude filter items
3132 */
3233
33- const stringList = {
34- type : 'string' ,
35- array : true ,
36- coerce : ( values ) =>
37- values . length === 1 && values [ 0 ] . trim ( ) === 'false'
38- ? [ '**' ]
39- : values . reduce ( ( values , value ) => values . concat ( value . split ( ',' ) . map ( ( value ) => value . trim ( ) ) ) , [ ] )
40- }
41-
4234const xmlBooleanOptionValue = new Map ( [
4335 [ 'true' , 'yes' ] ,
4436 [ 'yes' , 'yes' ] ,
@@ -60,7 +52,11 @@ const xmlBooleanSetting = {
6052 return xmlBooleanOptionValue . get ( value )
6153 }
6254}
63- const serializationOptionNames = [ 'insert-final-newline' , 'omit-xml-declaration' , 'expand-xincludes' ]
55+ const serializationOptionNames = [ 'insert-final-newline' , 'omit-xml-declaration' , 'expand-xincludes' , 'method' ]
56+
57+ const htmlSerializationMethod = {
58+ method : 'html'
59+ }
6460
6561const serializationDefaults = {
6662 'expand-xincludes' : 'yes'
@@ -69,15 +65,26 @@ const serializationDefaults = {
6965 // "output.indent": "no",
7066 // "compression": "yes"
7167}
68+ function getHtmlSerializationOptions ( options ) {
69+ const serializationOptions = { ...serializationDefaults }
70+ serializationOptionNames . forEach ( ( o ) => {
71+ if ( o in options ) {
72+ serializationOptions [ o ] = options [ o ]
73+ }
74+ } )
75+ Object . assign ( serializationOptions , htmlSerializationMethod )
76+ // console.log('Serialization options:', serializationOptions)
77+ return serializationOptions
78+ }
7279
7380function getSerializationOptions ( options ) {
74- const serializationOptions = serializationDefaults
81+ const serializationOptions = { ... serializationDefaults }
7582 serializationOptionNames . forEach ( ( o ) => {
7683 if ( o in options ) {
7784 serializationOptions [ o ] = options [ o ]
7885 }
7986 } )
80- // console.log(serializationOptions)
87+ // console.log('Serialization options:', serializationOptions)
8188 return serializationOptions
8289}
8390
@@ -91,12 +98,20 @@ function getSerializationOptions (options) {
9198 */
9299async function downloadResource ( db , options , resource , directory , collection , rename ) {
93100 try {
94- const { verbose } = options
101+ const { verbose, matchesExcludeGlob , matchesIncludeGlob , matchesHtmlGlob } = options
95102 let fileContents
96103 const path = collection ? posix . join ( collection , resource . name ) : resource . name
104+ if ( matchesExcludeGlob ( resource ) || ! matchesIncludeGlob ( resource ) ) {
105+ if ( verbose ) {
106+ console . log ( `- skipping resource ${ path } ` )
107+ }
108+ return true
109+ }
97110
98111 if ( resource . type === 'BinaryResource' ) {
99112 fileContents = await db . documents . readBinary ( path )
113+ } else if ( matchesHtmlGlob ( resource ) ) {
114+ fileContents = await db . documents . read ( path , getHtmlSerializationOptions ( options ) )
100115 } else {
101116 fileContents = await db . documents . read ( path , getSerializationOptions ( options ) )
102117 }
@@ -202,16 +217,16 @@ async function getPathInfo (db, path) {
202217 */
203218async function downloadCollectionOrResource ( db , source , target , options ) {
204219 // read parameters
205- // const start = Date.now()
220+ // const start = Date.now()
206221 const root = resolve ( target )
207222
208223 if ( options . verbose ) {
209- console . error ( 'Downloading: ' , source , 'to' , root )
210- if ( options . include . length > 1 || options . include [ 0 ] !== '**' ) {
211- console . error ( 'Include:\n ' , ... options . include , '\n' )
224+ console . error ( 'Downloading' , source , 'to' , root )
225+ if ( options . include !== '**' ) {
226+ console . error ( 'Include' , options . include )
212227 }
213- if ( options . exclude . length ) {
214- console . error ( 'Exclude:\n ' , ... options . exclude , '\n' )
228+ if ( options . exclude && options . exclude . length ) {
229+ console . error ( 'Exclude' , options . exclude )
215230 }
216231 console . error ( `Downloading up to ${ options . threads } resources at a time` )
217232 if ( options [ 'expand-xincludes' ] === 'false' ) {
@@ -288,15 +303,15 @@ export function builder (yargs) {
288303 yargs
289304 . option ( 'i' , {
290305 alias : 'include' ,
291- describe : 'Include only files matching one or more of include patterns (comma separated) ' ,
306+ describe : 'Include only files matching the include globbing pattern ' ,
292307 default : '**' ,
293- ... stringList
308+ type : 'string'
294309 } )
295310 . option ( 'e' , {
296311 alias : 'exclude' ,
297- describe : 'Exclude any file matching one or more of exclude patterns (comma separated) ' ,
298- default : [ ] ,
299- ... stringList
312+ describe : 'Exclude any file matching the exclude globbing pattern ' ,
313+ default : '' ,
314+ type : 'string'
300315 } )
301316 . option ( 'x' , {
302317 group : 'serialization' ,
@@ -316,6 +331,13 @@ export function builder (yargs) {
316331 describe : 'Force a final newline at the end of an XMLResource (requires eXist >=6.1.0)' ,
317332 ...xmlBooleanSetting
318333 } )
334+ . option ( 'H' , {
335+ group : 'serialization' ,
336+ alias : 'serialize-as-html' ,
337+ describe : 'Serialize resources that match the globbing pattern as HTML' ,
338+ default : '*.html' ,
339+ type : 'string'
340+ } )
319341 . option ( 'v' , {
320342 alias : 'verbose' ,
321343 describe : 'Log every file and resource that was created' ,
@@ -342,7 +364,11 @@ export async function handler (argv) {
342364 return 0
343365 }
344366
345- const { threads, mintime, source } = argv
367+ const { threads, mintime, source, include, exclude, serializeAsHtml } = argv
368+
369+ const matchesIncludeGlob = getGlobMatcher ( include )
370+ const matchesExcludeGlob = getGlobMatcher ( exclude )
371+ const matchesHtmlGlob = getGlobMatcher ( serializeAsHtml )
346372
347373 if ( typeof mintime !== 'number' || mintime < 0 ) {
348374 throw Error ( 'Invalid value for option "mintime"; must be an integer equal or greater than zero.' )
@@ -357,5 +383,5 @@ export async function handler (argv) {
357383 const version = await db . server . version ( )
358384 argv . version = version
359385
360- return await downloadCollectionOrResource ( db , source , target , argv )
386+ return await downloadCollectionOrResource ( db , source , target , { ... argv , matchesIncludeGlob , matchesExcludeGlob , matchesHtmlGlob } )
361387}
0 commit comments