mirror of
				https://github.com/flynx/pWiki.git
				synced 2025-10-31 11:00:08 +00:00 
			
		
		
		
	added file backup versioning...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									1c6cceb61b
								
							
						
					
					
						commit
						62a6d3de07
					
				
							
								
								
									
										203
									
								
								pwiki2.js
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								pwiki2.js
									
									
									
									
									
								
							| @ -487,11 +487,15 @@ module.BaseStore = { | |||||||
| 	// NOTE: deleting and updating only applies to explicit matching 
 | 	// NOTE: deleting and updating only applies to explicit matching 
 | ||||||
| 	// 		paths -- no page acquisition is performed...
 | 	// 		paths -- no page acquisition is performed...
 | ||||||
| 	// NOTE: edit methods are local-only...
 | 	// NOTE: edit methods are local-only...
 | ||||||
| 	//
 | 	// NOTE: if .__update__ and .__delete__ are set to null/false this 
 | ||||||
|  | 	// 		will quietly go into read-only mode...
 | ||||||
| 	// XXX do we copy the data here or modify it????
 | 	// XXX do we copy the data here or modify it????
 | ||||||
| 	__update__: async function(key, data, mode='update'){ | 	__update__: async function(key, data, mode='update'){ | ||||||
| 		this.data[key] = data }, | 		this.data[key] = data }, | ||||||
| 	update: async function(path, data, mode='update'){ | 	update: async function(path, data, mode='update'){ | ||||||
|  | 		// read-only...
 | ||||||
|  | 		if(this.__update__ == null){ | ||||||
|  | 			return this } | ||||||
| 		var exists = await this.exists(path)  | 		var exists = await this.exists(path)  | ||||||
| 		path = exists | 		path = exists | ||||||
| 			|| module.path.normalize(path, 'string') | 			|| module.path.normalize(path, 'string') | ||||||
| @ -516,6 +520,9 @@ module.BaseStore = { | |||||||
| 	__delete__: async function(path){ | 	__delete__: async function(path){ | ||||||
| 		delete this.data[path] }, | 		delete this.data[path] }, | ||||||
| 	delete: async function(path){ | 	delete: async function(path){ | ||||||
|  | 		// read-only...
 | ||||||
|  | 		if(this.__delete__ == null){ | ||||||
|  | 			return this } | ||||||
| 		path = await this.exists(path) | 		path = await this.exists(path) | ||||||
| 		path | 		path | ||||||
| 			&& await this.__delete__(path) | 			&& await this.__delete__(path) | ||||||
| @ -824,90 +831,6 @@ async function(base, sub, options){ | |||||||
| 	return target ? | 	return target ? | ||||||
| 		fs.promises.readFile(target, {encoding: 'utf-8'}) | 		fs.promises.readFile(target, {encoding: 'utf-8'}) | ||||||
| 		: undefined } | 		: undefined } | ||||||
| // NOTE: backing up ** will include nested backups...
 |  | ||||||
| // XXX add versioning...
 |  | ||||||
| var backup = |  | ||||||
| module.backup = |  | ||||||
| async function(base, sub, options){ |  | ||||||
| 	var {index, backup, verbose, recursive, cleanBackup} = |  | ||||||
| 		Object.assign({},  |  | ||||||
| 			FILESTORE_OPTIONS,  |  | ||||||
| 			options ?? {}) |  | ||||||
| 	recursive = recursive ?? false |  | ||||||
| 
 |  | ||||||
| 	var _backup = backup |  | ||||||
| 	backup =  |  | ||||||
| 		module.path.join( |  | ||||||
| 			base, |  | ||||||
| 			module.path.relative(sub, backup)) |  | ||||||
| 
 |  | ||||||
| 	// ** or * -- backup each file in path...
 |  | ||||||
| 	if(/[\\\/]*\*\*?$/.test(sub)){ |  | ||||||
| 		if(cleanBackup  |  | ||||||
| 				&& fs.existsSync(backup)){ |  | ||||||
| 			verbose |  | ||||||
| 				&& console.log('backup(..): cleaning:', backup) |  | ||||||
| 			await fs.promises.rm(backup, {recursive: true}) } |  | ||||||
| 		if(sub.endsWith('**')){ |  | ||||||
| 			options = { |  | ||||||
| 				...(options ?? {}),  |  | ||||||
| 				recursive: true, |  | ||||||
| 			} } |  | ||||||
| 		sub = sub.replace(/[\\\/]*\*\*?$/, '') |  | ||||||
| 		// XXX should we ignore only the first element (current) or the sub-path???
 |  | ||||||
| 		var b = module.path.split(_backup) |  | ||||||
| 			.filter(function(p){  |  | ||||||
| 				return p != '' }) |  | ||||||
| 			.shift() |  | ||||||
| 		return fs.promises.readdir(base +'/'+ sub) |  | ||||||
| 			.iter() |  | ||||||
| 			// skip backups...
 |  | ||||||
| 			.filter(function(file){ |  | ||||||
| 				return !file.includes(b) }) |  | ||||||
| 			.map(async function(file){ |  | ||||||
| 				return await module.backup(base, sub +'/'+ file, options) }) |  | ||||||
| 			// keep only the paths we backed up...
 |  | ||||||
| 			.filter(function(e){  |  | ||||||
| 				return !!e })  |  | ||||||
| 
 |  | ||||||
| 	// backup single page...
 |  | ||||||
| 	} else { |  | ||||||
| 		var target = module.path.join(base, sub)  |  | ||||||
| 		var full = _backup[0] == '/' |  | ||||||
| 
 |  | ||||||
| 		// nothing to backup...
 |  | ||||||
| 		if(!fs.existsSync(target)){ |  | ||||||
| 			verbose |  | ||||||
| 				&& console.log('backup(..): target does not exist:', target) |  | ||||||
| 			return } |  | ||||||
| 
 |  | ||||||
| 		if(!recursive){ |  | ||||||
| 			var stat = await fs.promises.stat(target) |  | ||||||
| 			if(stat.isDirectory()){ |  | ||||||
| 				sub += '/'+index  |  | ||||||
| 				target += '/'+index |  | ||||||
| 				// nothing to backup...
 |  | ||||||
| 				if(!fs.existsSync(target)){ |  | ||||||
| 					verbose |  | ||||||
| 						&& console.log('backup(..): nothing to backup:', target) |  | ||||||
| 					return } } } |  | ||||||
| 
 |  | ||||||
| 		var to = full ? |  | ||||||
| 			backup +'/'+ sub |  | ||||||
| 			: backup +'/'+ module.path.basename(sub) |  | ||||||
| 		var todir = module.path.dirname(to) |  | ||||||
| 
 |  | ||||||
| 		verbose |  | ||||||
| 			&& console.log('backup(..):', sub, '->', to) |  | ||||||
| 		await fs.promises.mkdir(todir, {recursive: true})  |  | ||||||
| 		await fs.promises.cp(target, to, {force: true, recursive}) |  | ||||||
| 		return to } } |  | ||||||
| // XXX
 |  | ||||||
| var restore = |  | ||||||
| module.restore = |  | ||||||
| async function(base, sub, options){ |  | ||||||
| 	// XXX
 |  | ||||||
| } |  | ||||||
| var mkdir =  | var mkdir =  | ||||||
| module.mkdir = | module.mkdir = | ||||||
| async function(base, sub, options){ | async function(base, sub, options){ | ||||||
| @ -1063,7 +986,117 @@ async function(base, options){ | |||||||
| 						continue } | 						continue } | ||||||
| 				} } }) } | 				} } }) } | ||||||
| 
 | 
 | ||||||
|  | //
 | ||||||
|  | // 	backing(<base>[, <options>])
 | ||||||
|  | // 	backing(<base>, '**'[, <options>])
 | ||||||
|  | // 	backing(<base>, '**', Date.timeStamp()[, <options>])
 | ||||||
|  | // 		-> <list>
 | ||||||
|  | //
 | ||||||
|  | // 	backing(<base>, <path>[, <version>][, <options>])
 | ||||||
|  | // 		-> <list>
 | ||||||
|  | //
 | ||||||
|  | // 	backing(<base>, <path>, false[, <options>])
 | ||||||
|  | // 		-> <list>
 | ||||||
|  | //
 | ||||||
|  | // NOTE: backing up ** will include nested backups but will skip the 
 | ||||||
|  | // 		root backup...
 | ||||||
|  | // NOTE: currently this ignores only the first element of the options.backup
 | ||||||
|  | // 		path.
 | ||||||
|  | var backup = | ||||||
|  | module.backup = | ||||||
|  | async function(base, sub='**', version=Date.timeStamp(), options){ | ||||||
|  | 	if(typeof(sub) == 'object'){ | ||||||
|  | 		options = sub | ||||||
|  | 		sub = '**' } | ||||||
|  | 	if(typeof(version) == 'object'){ | ||||||
|  | 		options = version | ||||||
|  | 		version = Date.timeStamp() } | ||||||
|  | 	// options...
 | ||||||
|  | 	var {index, backup, verbose, recursive, cleanBackup} = | ||||||
|  | 		Object.assign({},  | ||||||
|  | 			FILESTORE_OPTIONS,  | ||||||
|  | 			options ?? {}) | ||||||
|  | 	recursive = recursive ?? false | ||||||
| 
 | 
 | ||||||
|  | 	var _backup = backup =  | ||||||
|  | 		version ? | ||||||
|  | 			module.path.join(backup, version) | ||||||
|  | 			: backup | ||||||
|  | 	backup =  | ||||||
|  | 		module.path.join( | ||||||
|  | 			base, | ||||||
|  | 			module.path.relative(sub, backup)) | ||||||
|  | 
 | ||||||
|  | 	// ** or * -- backup each file in path...
 | ||||||
|  | 	if(/[\\\/]*\*\*?$/.test(sub)){ | ||||||
|  | 		if(cleanBackup  | ||||||
|  | 				&& fs.existsSync(backup)){ | ||||||
|  | 			verbose | ||||||
|  | 				&& console.log('backup(..): cleaning:', backup) | ||||||
|  | 			await fs.promises.rm(backup, {recursive: true}) } | ||||||
|  | 		if(sub.endsWith('**')){ | ||||||
|  | 			options = { | ||||||
|  | 				...(options ?? {}),  | ||||||
|  | 				recursive: true, | ||||||
|  | 			} } | ||||||
|  | 		sub = sub.replace(/[\\\/]*\*\*?$/, '') | ||||||
|  | 		// XXX should we ignore only the first element (current) or the sub-path???
 | ||||||
|  | 		var b = module.path.split(_backup) | ||||||
|  | 			.filter(function(p){  | ||||||
|  | 				return p != '' }) | ||||||
|  | 			.shift() | ||||||
|  | 		return fs.promises.readdir(base +'/'+ sub) | ||||||
|  | 			.iter() | ||||||
|  | 			// skip backups...
 | ||||||
|  | 			.filter(function(file){ | ||||||
|  | 				return !file.includes(b) }) | ||||||
|  | 			.map(async function(file){ | ||||||
|  | 				return await module.backup(base, sub +'/'+ file, version, options) }) | ||||||
|  | 			// keep only the paths we backed up...
 | ||||||
|  | 			.filter(function(e){  | ||||||
|  | 				return !!e })  | ||||||
|  | 
 | ||||||
|  | 	// backup single page...
 | ||||||
|  | 	} else { | ||||||
|  | 		var target = module.path.join(base, sub)  | ||||||
|  | 		var full = _backup[0] == '/' | ||||||
|  | 
 | ||||||
|  | 		// nothing to backup...
 | ||||||
|  | 		if(!fs.existsSync(target)){ | ||||||
|  | 			verbose | ||||||
|  | 				&& console.log('backup(..): target does not exist:', target) | ||||||
|  | 			return } | ||||||
|  | 
 | ||||||
|  | 		if(!recursive){ | ||||||
|  | 			var stat = await fs.promises.stat(target) | ||||||
|  | 			if(stat.isDirectory()){ | ||||||
|  | 				sub += '/'+index  | ||||||
|  | 				target += '/'+index | ||||||
|  | 				// nothing to backup...
 | ||||||
|  | 				if(!fs.existsSync(target)){ | ||||||
|  | 					verbose | ||||||
|  | 						&& console.log('backup(..): nothing to backup:', target) | ||||||
|  | 					return } } } | ||||||
|  | 
 | ||||||
|  | 		var to = full ? | ||||||
|  | 			backup +'/'+ sub | ||||||
|  | 			: backup +'/'+ module.path.basename(sub) | ||||||
|  | 		var todir = module.path.dirname(to) | ||||||
|  | 
 | ||||||
|  | 		verbose | ||||||
|  | 			&& console.log('backup(..):', sub, '->', to) | ||||||
|  | 		await fs.promises.mkdir(todir, {recursive: true})  | ||||||
|  | 		await fs.promises.cp(target, to, {force: true, recursive}) | ||||||
|  | 		return to } } | ||||||
|  | // XXX
 | ||||||
|  | var restore = | ||||||
|  | module.restore = | ||||||
|  | async function(base, sub, version, options){ | ||||||
|  | 	// XXX
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // XXX might be a good idea to support ro mode on top level explicitly...
 | ||||||
| // XXX add monitor API + cache + live mode (auto on when lock detected)...
 | // XXX add monitor API + cache + live mode (auto on when lock detected)...
 | ||||||
| var FileStoreRO = | var FileStoreRO = | ||||||
| module.FileStoreRO = { | module.FileStoreRO = { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user