UNPKG

libvirt-node

Version:

The libvirt virtualization API node.js binding

318 lines (281 loc) 9.33 kB
const fs = require('fs'); const debug = require('debug'); const { impl_emitter, header_emitter, wrapper_emitter, export_emitter } = require('./emitters'); class FileDescriptor { constructor(args, options) { this.args = Object.assign({ ext: '', name: undefined, type: undefined, destination: 'generated', }, args); this.options = Object.assign({ dependencies: [], content: [], opening: '', closing: '', separator: '\n', emitter: undefined, static: args.name === 'libvirt' ? 'static' : '', }, options); this.processed = new Set(); } /** * Returns descriptor as a formatted string */ getAsString() { return ` ${[...new Set(this.options.dependencies)] .join('\n')} ${this.options.opening} ${this.options.content.join(this.options.separator)} ${this.options.closing} `; } /** * addProcessed does any validation required on the metadata * * @param {string} API entry exported name */ addProcessed(name) { debug(`descriptors:${this.args.name}`)(`addProcessed ${name}`); if(this.processed.has(name)) { throw new Error(`${name} has aleady been defined in ${this.arg.type} descriptor ${this.args.name}`); } this.processed.add(name); } /** * Processes parsed function metadata to generate content * * @param {object} function metadata from parser */ process(func) { debug(`descriptors:${this.args.name}`)(`Processing ${func.name}`); this.addProcessed(func.name); // TODO(ramyelkest@gmail.com): addProcessed should not be called from process this.addContent( this.options.emitter.emit(func.name, func) ); } /** * Adds file dependency (at the top of the file) * * @param {string} Dependency as a string * eg. "#include <assert.h>" or "const assert = require('assert');" */ addDependency(str) { this.options.dependencies.push(str); } /** * Adds function content as a string to the file buffer * * @param {string} function content * eg. function header / impl / wrapper (including docs) */ addContent(str) { this.options.content.push(str); } /** * Writes the contents to file */ write() { debug(`descriptors:${this.args.name}`) (`Writing to ${this.args.destination}/${this.args.name}${this.args.ext}`); fs.writeFileSync( `${this.args.destination}/${this.args.name}${this.args.ext}`, this.getAsString() ); } }; class HeaderDescriptor extends FileDescriptor { constructor(args, options) { super ( Object.assign( { ext: '.h', type: 'header' }, args ), Object.assign( { dependencies: [ '#pragma once', '#include <node_api.h>', ], emitter: header_emitter }, options ) ); } } // let hd = new HeaderDescriptor({name: 'domain'}); // hd.addContent('napi_value libvirt_virDomainGetID(napi_env env, napi_callback_info info);') // hd.addContent('napi_value libvirt_virDomainGetOSType(napi_env env, napi_callback_info info);') // console.log(hd.getAsString()); class WrapperDescriptor extends FileDescriptor { constructor(args, options) { super ( Object.assign( { ext: '.js', type: 'wrapper' }, args ), Object.assign( { dependencies: [ `const libvirt_native = require('bindings')('libvirt');`, ], opening: `module.exports = class {`, closing: `}`, separator: '\n\n', emitter: wrapper_emitter }, options ) ); this.addContent(this.options.emitter.emit(`${this.args.name}:constructor`, this.args.name)); } /** * Processes parsed function metadata to generate docs and content * * @param {object} function metadata from parser */ process(func) { debug(`descriptors:${this.args.name}:${this.args.type}`)(`Processing ${func.name}`); this.addProcessed(func.iname); // TODO(ramyelkest@gmail.com): addProcessed should not be called from process super.addDependency( this.options.emitter.emit(func.name+':dependencies', func) ); this.addContent( `${this.options.emitter.emit(func.name+':docs', func)} ${this.options.static} ${this.options.emitter.emit(func.name, func)}` ); } /** * Processes parsed enums metadata to generate docs and content * * @param {string} enums type * @param {array} list of enums metadata from parser for this type */ processEnums(enumsType, enums) { debug(`descriptors:${this.args.name}:${this.args.type}`)(`Processing enum:${enumsType}`); this.addContent(`/** ${enumsType} **/`); enums.forEach(enumDesc => { this.addContent( `${this.options.emitter.emit('enum:'+enumDesc.name+':docs', enumDesc)} ${this.options.static} ${this.options.emitter.emit('enum:'+enumDesc.name, enumDesc)}` ); }); } } // let wd = new WrapperDescriptor({name: 'domain'}); // wd.addContent(` // constructor(conn, domain) { // this.conn = conn; // this.domain = domain // } // `); // wd.addContent(` // /** // * Get the hypervisor ID number for the domain // */ // getID() { // let ret = libvirt_native.virDomainGetID(this.domain); // if (ret == null) throw new Error('virDomainGetID() failed'); // return ret; // } // `); // wd.addContent(` // /** // * Get the type of domain operation system. // */ // getOSType() { // let ret = libvirt_native.virDomainGetOSType(this.domain); // if (ret == null) throw new Error('virDomainGetOSType() failed'); // return ret; // }`); // console.log(wd.getAsString()); class ImplDescriptor extends FileDescriptor { constructor(args, options) { super ( Object.assign( { ext: '.c', type: 'impl' }, args ), Object.assign( { dependencies: [ `#include "${args.name}.h"`, `#include <libvirt/libvirt.h>`, `#include <libvirt/virterror.h>`, // TODO(ramyelkest@gmail.com): is this needed? `#include <assert.h>`, `#include <string.h>`, ], separator: '\n\n', emitter: impl_emitter }, options ) ); } } // let id = new ImplDescriptor({name: 'domain'}); // id.addContent(` // /* The following implementations are generated */ // napi_value libvirt_virDomainGetID(napi_env env, napi_callback_info info) { // napi_status status; // napi_value n_retval; // return n_retval; // }`); // console.log(id.getAsString()); class ExportDescriptor extends FileDescriptor { constructor(args, options) { super ( Object.assign( { ext: '.c', type: 'export', files: undefined }, args ), Object.assign( { dependencies: [ `#include <assert.h>`, ], emitter: export_emitter, opening: `#define DECLARE_NAPI_METHOD(name, func) \\ { name, 0, func, 0, 0, 0, napi_default, 0 } napi_value Init(napi_env env, napi_value exports) { napi_status status; napi_property_descriptor descs[] = {`, closing: ` }; status = napi_define_properties(env, exports, sizeof(descs)/sizeof(descs[0]), descs); assert(status == napi_ok); return exports; } NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)`, separator: '', }, options ) ); args.files.forEach(file => this.addDependency(file)); } addDependency(dependency) { super.addDependency(`#include "${dependency}.h"`); } } module.exports = { WrapperDescriptor, HeaderDescriptor, ImplDescriptor, ExportDescriptor, }