美文网首页English BootCamp英语训练营
Export Merge File Function from

Export Merge File Function from

作者: UULU | 来源:发表于2019-11-10 23:10 被阅读0次

    The NodeGit is Native Node bindings to Git,based on libgit2.

    It's a great library, but not provides all APIs of libgit2.

    I need to export the 3-Way-Merge algorithm from git_merge_file by myself.


    • First of all, clone a depository from my forked project.
    git clone git@github.com:myname/nodegit.git
    cd nodegit
    npm i
    
    1. Edit the configuration file of Customize the generated code using.

    generate/input/descriptor.json

    {
      "types": {
        "merge": {
          "functions": {
            "git_merge_file": {
              // Remove `"ignore": true`, add config
              "args": {
                "out": {
                  "isReturn": true, // As return value
                  "shouldAlloc": true // Auto create
                },
                "opts": {
                  "isOptional": true // Can be null
                }
              },
              "return": {
                "isErrorCode": true
              }
            }
          }
        },
        "merge_file_result": {
          "ignore": false // Can not be ignore
        }
      }
    }
    
    1. Generate detail configuration JSON
    npm run generateJson
    

    output at:

    generate/output/idefs.json

    search "cFunctionName": "git_merge_file",, have got args and returns configuration.

    1. Build nodegit.node
    npm run install
    

    build/Release/nodegit.node

    1. Define a new JS function Merge.file for convert args.

    lib/merge.js

    var _file = Merge.file;
    
    /**
     * Merge two files as they exist in the in-memory data structures, using
     * the given common ancestor as the baseline. (git_merge_file)
     *
     * @param {MergeFileInput} ancestor The contents of the ancestor file
     * @param {MergeFileInput} ours The contents of the file in "our" side
     * @param {MergeFileInput} theirs The contents of the file in "theirs" side
     * @param {MergeFileOptions} [options] The merge file options or `NULL` for defaults
     */
    Merge.file = function(ancestor, ours, theirs, options) {
      ancestor = normalizeOptions(ancestor, NodeGit.MergeFileInput);
      ours = normalizeOptions(ours, NodeGit.MergeFileInput);
      theirs = normalizeOptions(theirs, NodeGit.MergeFileInput);
      options = normalizeOptions(options || {}, NodeGit.MergeFileOptions);
      return _file.call(this, ancestor, ours, theirs, options);
    };
    
    1. Generate JS in dist/ with babel.
    npm run prepublish
    
    1. Create test.

    Create three Markdown files.

    printf "a" > test/base.md
    printf "a\nb" > test/ours.md
    printf "a\nc" > test/theirs.md
    

    Create test JS file.

    test/mergefile.js

    var NodeGit = require('..');
    var path = require('path');
    var fse = require('fs-extra');
    
    const dir = '/mnt/d/workspace/nodegit/test';
    
    async function newMergeFileInput(filePath) {
      const stat = await fse.stat(filePath);
      const content = await fse.readFile(filePath, 'utf-8');
    
      // Wrong: It will case Crash while without normalizeOptions in 'lib/merge.js'
      // const input = {
      //   ptr: content,
      //   size: content.length,
      //   mode: stat.mode,
      //   path: filePath,
      // }
    
      // Correct: Must create object from NodeGit class.
      const input = new NodeGit.MergeFileInput();
      input.ptr = content;
      input.size = stat.size; // UTF8 size! (not content.length)
      input.mode = stat.mode;
      input.path = filePath;
    
      return input;
    }
    
    function getFilePath(fileName) {
      return path.join(dir, fileName);
    }
    
    async function test() {
      // 3 files.
      const base = await newMergeFileInput(getFilePath('base.md'));
      const ours = await newMergeFileInput(getFilePath('ours.md'));
      const theirs = await newMergeFileInput(getFilePath('theirs.md'));
    
      console.log({ base, ours, theirs });
    
      // Call merge file function.
      const res = await NodeGit.Merge.file(base, ours, theirs, {
        version: 0,
        ancestorLabel: 'BASE',
        ourLabel: 'OUR',
        theirLabel: 'THEIR',
        favor: 0,
        flags: 0,
        markerSize: 10,
      });
    
      // Must cut UTF8 Buff with len, or be wrong.
      const ptr = Buffer.from(res.ptr(), 'utf-8').slice(0, res.len()).toString();
    
      // Must call function to get field.
      console.log('res:', {
        automergeable: res.automergeable(),
        path: res.path(),
        mode: res.mode(),
        ptr,
        len: res.len(),
      });
    }
    
    test();
    

    Run.

    node test/mergefile.js
    

    Output.

    {
      base: MergeFileInput {
        mode: 33279,
        path: '/mnt/d/workspace/nodegit/test/base.md',
        size: 1,
        ptr: 'a',
        version: 1
      },
      ours: MergeFileInput {
        mode: 33279,
        path: '/mnt/d/workspace/nodegit/test/ours.md',
        size: 3,
        ptr: 'a\nb',
        version: 1
      },
      theirs: MergeFileInput {
        mode: 33279,
        path: '/mnt/d/workspace/nodegit/test/theirs.md',
        size: 3,
        ptr: 'a\nc',
        version: 1
      }
    }
    res: {
      automergeable: 0,
      path: null,
      mode: 33279,
      ptr: 'a\n<<<<<<<<<< OUR\nb\n==========\nc\n>>>>>>>>>> THEIR\n',
      len: 49
    }
    
    1. Publish

    Change name and version in package.json for publish new version.

    npm login
    npm publish
    

    Install it use yarn.

    yarn add pj-nodegit@latest
    

    IMPORTANT

    If argument object don't create with NodeGit Class and without wrap normalizeOptions. The nodegit.node will be crash.

    node: ../node_modules/nan/nan_object_wrap.h:32: static T* Nan::ObjectWrap::Unwrap(v8::Local<v8::Object>) [with T = GitMergeFileOptions]: Assertion `object->InternalFieldCount() > 0' failed.
    

    Why?

    It lacks embedder fields, by compare with object of correct function. The v8 object InternalFieldCount() only counts the embedder fields actually. What is it? I don't know, may be a special sign of v8 object. No mater how, create object with NodeGit Class will be correct. I found the solution according by function normalizeOptions in file lib/utils/normalize_options.js.

    var NodeGit = require('../../');
    
    function normalizeOptions(options, Ctor) {
      if (!options) {
        return null;
      }
    
      if (options instanceof Ctor) {
        return options;
      }
    
      var instance = new Ctor(); // here.
    
      Object.keys(options).forEach(function(key) {
        if (typeof options[key] !== 'undefined') {
          instance[key] = options[key];
        }
      });
    
      return instance;
    }
    
    NodeGit.Utils.normalizeOptions = normalizeOptions;
    

    相关文章

      网友评论

        本文标题:Export Merge File Function from

        本文链接:https://www.haomeiwen.com/subject/lalzbctx.html