API/api.medcify.app/node_modules/js-git/mixins/create-tree.js
2022-09-26 11:41:44 +05:30

149 lines
3.8 KiB
JavaScript

"use strict";
var modes = require('../lib/modes.js');
module.exports = function (repo) {
repo.createTree = createTree;
function createTree(entries, callback) {
if (!callback) return createTree.bind(null, entries);
callback = singleCall(callback);
if (!Array.isArray(entries)) {
entries = Object.keys(entries).map(function (path) {
var entry = entries[path];
entry.path = path;
return entry;
});
}
// Tree paths that we need loaded
var toLoad = {};
function markTree(path) {
while(true) {
if (toLoad[path]) return;
toLoad[path] = true;
trees[path] = {
add: [],
del: [],
tree: {}
};
if (!path) break;
path = path.substring(0, path.lastIndexOf("/"));
}
}
// Commands to run organized by tree path
var trees = {};
// Counter for parallel I/O operations
var left = 1; // One extra counter to protect again zalgo cache callbacks.
// First pass, stubs out the trees structure, sorts adds from deletes,
// and saves any inline content blobs.
entries.forEach(function (entry) {
var index = entry.path.lastIndexOf("/");
var parentPath = entry.path.substr(0, index);
var name = entry.path.substr(index + 1);
markTree(parentPath);
var tree = trees[parentPath];
var adds = tree.add;
var dels = tree.del;
if (!entry.mode) {
dels.push(name);
return;
}
var add = {
name: name,
mode: entry.mode,
hash: entry.hash
};
adds.push(add);
if (entry.hash) return;
left++;
repo.saveAs("blob", entry.content, function (err, hash) {
if (err) return callback(err);
add.hash = hash;
check();
});
});
// Preload the base trees
if (entries.base) loadTree("", entries.base);
// Check just in case there was no IO to perform
check();
function loadTree(path, hash) {
left++;
delete toLoad[path];
repo.loadAs("tree", hash, function (err, tree) {
if (err) return callback(err);
trees[path].tree = tree;
Object.keys(tree).forEach(function (name) {
var childPath = path ? path + "/" + name : name;
if (toLoad[childPath]) loadTree(childPath, tree[name].hash);
});
check();
});
}
function check() {
if (--left) return;
findLeaves().forEach(processLeaf);
}
function processLeaf(path) {
var entry = trees[path];
delete trees[path];
var tree = entry.tree;
entry.del.forEach(function (name) {
delete tree[name];
});
entry.add.forEach(function (item) {
tree[item.name] = {
mode: item.mode,
hash: item.hash
};
});
left++;
repo.saveAs("tree", tree, function (err, hash, tree) {
if (err) return callback(err);
if (!path) return callback(null, hash, tree);
var index = path.lastIndexOf("/");
var parentPath = path.substring(0, index);
var name = path.substring(index + 1);
trees[parentPath].add.push({
name: name,
mode: modes.tree,
hash: hash
});
if (--left) return;
findLeaves().forEach(processLeaf);
});
}
function findLeaves() {
var paths = Object.keys(trees);
var parents = {};
paths.forEach(function (path) {
if (!path) return;
var parent = path.substring(0, path.lastIndexOf("/"));
parents[parent] = true;
});
return paths.filter(function (path) {
return !parents[path];
});
}
}
};
function singleCall(callback) {
var done = false;
return function () {
if (done) return console.warn("Discarding extra callback");
done = true;
return callback.apply(this, arguments);
};
}