Source: util/file.js

/*
 * Copyright (c) 2020 Capgemini Group, Commissariat à l'énergie atomique et aux énergies alternatives,
 *                    OW2, Sysgo AG, Technikon, Tree Technology, Universitat Politècnica de València.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

/** A File
 */
class File
{
	/** constructor
	 * 
	 * @param {string} rel_path - path relative to root directory
	 * @param {(string|Buffer)} [content] - content of file
	 * @param {string} [encoding] - text encoding of a text file (implicitely null for raw buffer, undefined if same as global file system text encoding)
	 * @param {string} [type] - type
	 * @param {string} [mime_type] - MIME type
	 * @param {string} [git_working_tree] - URL of git repository
	 * @param {boolean} [git_dirty] - Git dirty flag
	 * @param {boolean} [git_unmerged] - Git unmerged flag
	 */
	constructor(rel_path, content = undefined, encoding = 'utf8', type = '', mime_type = '', git_working_tree = undefined, git_dirty = undefined, git_unmerged = undefined)
	{
		const path = require('path');
		this.rel_path = path.posix.normalize(rel_path);
		if(this.rel_path.startsWith('/')) this.rel_path = this.rel_path.slice(1); // make sure path is really relative (no leading '/')
		this.content = content;
		this.encoding = Buffer.isBuffer(content) ? null : encoding;
		this.type = type;
		this.mime_type = mime_type;
		if(git_working_tree !== undefined) this.git_working_tree = git_working_tree;
		if(git_dirty !== undefined) this.git_dirty = git_dirty;
		if(git_unmerged !== undefined) this.git_unmerged = git_unmerged;
	}
	
	/** Compare content with another file
	 * 
	 * @param {File} other - other file to compare content with
	 * @return {number} sort order (0 means equal)
	 */
	compare_content(other)
	{
		const a = Buffer.isBuffer(this.content) ? this.content : Buffer.from(this.content, this.encoding);
		const b = Buffer.isBuffer(other.content) ? other.content : Buffer.from(other.content, other.encoding);
		return a.compare(b);
	}
	
	/** Get the absolute path of the file (on the host file system)
	 * 
	 * @param {string} root_directory_path - the root directory path on the host file system
	 * @return {string} the absolute path of the file
	 */
	get_abs_path(root_directory_path)
	{
		const path = require('path');
		return path.normalize(path.join(root_directory_path, this.rel_path));
	}
	
	/** Build a File instance from an object, convenient for transportation with a transport protocol, that looks like a file but with an additional property 'format'.
	 * If a property 'format' exists in the object then property 'content' is considered
	 * as a base64 encoded string that is converted to a buffer in the File instance.
	 * 
	 * @param {Object} obj - an object
	 * @return {File} an instance of File
	 */
	static from(obj)
	{
		return new File(
			obj.rel_path,                                                                // rel_path
			(obj.format == 'binary') ? (obj.content ? Buffer.from(obj.content, 'base64') : Buffer.alloc(0)) : obj.content, // content
			obj.encoding,                                                                // encoding
			obj.type,                                                                    // type
			obj.mime_type,                                                               // MIME type
			obj.git_working_tree,                                                        // Git working tree
			obj.git_dirty,                                                               // Git dirty
			obj.git_unmerged                                                             // Git unmerged
		);
	}

	/** Export the file as an object convenient for transportation with a transport protocol.
	 * It has property 'format' which value is 'binary' when the property 'content' of the object is a base64 encoded string, otherwise its value is 'text'.
	 *
	 * @return {Object} an object
	 */
	export()
	{
		let obj =
		{
			rel_path : this.rel_path
		};
		if(this.content !== undefined)
		{
			obj.content = Buffer.isBuffer(this.content) ? this.content.toString('base64') : this.content;
			obj.format = Buffer.isBuffer(this.content) ? 'binary' : 'text';
		}
		if((this.encoding !== undefined) && (this.encoding !== null))
		{
			obj.encoding = this.encoding;
		}
		if(this.type !== undefined)
		{
			obj.type = this.type;
		}
		if(this.mime_type !== undefined)
		{
			obj.mime_type = this.mime_type;
		}
		if(this.git_working_tree !== undefined)
		{
			obj.git_working_tree = this.git_working_tree;
		}
		if(this.git_dirty !== undefined)
		{
			obj.git_dirty = this.git_dirty;
		}
		if(this.git_unmerged !== undefined)
		{
			obj.git_unmerged = this.git_unmerged;
		}
		
		return obj;
	}
	
	/** Build a File instance from an object from the database.
	 * 
	 * @param {Object} obj - an object from database
	 * @return {File} an instance of File
	 */
	static from_database(obj)
	{
		return new File(
			obj.filename,     // rel_path
			(obj.fileFormat == 'binary') ? (obj.filecontent ? Buffer.from(obj.filecontent, 'base64') : Buffer.alloc(0)) : obj.filecontent, // content
			obj.fileEncoding, // encoding
			obj.fileType,     // type
			obj.fileMimeType, // MIME type
			obj.gitWorkingTree,// Git working tree
			obj.gitDirty,      // Git dirty
			obj.gitUnmerged    // Git unmerged
		);
	}
	
	/** Export the file as an object convenient for storing in the database.
	 * It has property 'format' which value is 'binary' when the property 'content' of the object is a base64 encoded string, otherwise its value is 'text'.
	 *
	 * @return {Object} an object
	 */
	database_export()
	{
		let obj =
		{
			filename : this.rel_path
		};
		if(this.content !== undefined)
		{
			obj.filecontent = Buffer.isBuffer(this.content) ? this.content.toString('base64') : this.content;
		}
		if(this.type !== undefined)
		{
			obj.fileType = this.type;
		}
		if(this.mime_type !== undefined)
		{
			obj.fileMimeType = this.mime_type;
		}
		if(this.content !== undefined)
		{
			obj.fileFormat = Buffer.isBuffer(this.content) ? 'binary' : 'text';
		}
		if((this.encoding !== undefined) && (this.encoding !== null))
		{
			obj.fileEncoding = this.encoding;
		}
		if(this.git_working_tree !== undefined)
		{
			obj.gitWorkingTree = this.git_working_tree;
		}
		if(this.git_dirty !== undefined)
		{
			obj.gitDirty = this.git_dirty;
		}
		if(this.git_unmerged !== undefined)
		{
			obj.gitUnmerged = this.git_unmerged;
		}
		
		return obj;
	}
}

module.exports = File;