big leaps in git engine

This commit is contained in:
Peter Cottle 2012-08-15 13:05:43 -07:00
parent 21d204df92
commit 2cd620de27
4 changed files with 209 additions and 83 deletions

View file

@ -2,9 +2,69 @@
* Util classes * Util classes
*/ */
function CommandQueue() {
this.commands = [];
this.consumeTimeout = null;
/* this.initialDelay = 400;
var e = sys.addEdge(node1, node2); }
CommandQueue.prototype.add = function(command) {
this.commands.push(command);
this.touchTimer();
};
CommandQueue.prototype.touchTimer = function() {
if (this.consumeTimeout) {
return;
}
this.consumeTimeout = setTimeout(_.bind(function() {
this.next();
}, this), this.initialDelay);
};
CommandQueue.prototype.reset = function() {
this.consumeTimeout = null;
};
CommandQueue.prototype.next = function() {
if (this.commands.length == 0) {
this.reset();
return;
}
// execute the top command by passing it into the engine
var toExecute = this.commands.shift(0);
var callback = _.bind(function() {
this.next();
}, this);
gitEngine.execute(toExecute, callback);
};
/******************
* Planning:
here is the major flow:
someone types in a command ->
make a new command object. if error, give immediate feedback, dont append to queue
if not error ->
append command object to queue
Command Queue ->
consume commands at a certain rate (either instantly if just added, or with an interval
Execute command -> (usually a git engine thing)
Wait for git engine command to finish
when done, execute next command (if more)
so two levels of Async-ness:
command queue slowly consumes commands
GitEngine executes commands, which will have async bits to them (such as popping off commits for a
rebase)
*/ */
function Scheduler(closures, options) { function Scheduler(closures, options) {

View file

@ -1,9 +1,98 @@
// backbone or something uses _.uniqueId, so we make our own here
var uniqueId = (function() {
var n = 0;
return function(prepend) {
return prepend? prepend + n++ : n++;
};
})();
function GitEngine() { function GitEngine() {
this.detachedHead = false; this.rootCommit = null;
this.refs = {};
this.HEAD = null;
this.id_gen = 0;
this.init();
} }
GitEngine.prototype.commit = function() { GitEngine.prototype.init = function() {
// make an initial commit and a master branch
this.rootCommit = new Commit({rootCommit: true});
this.refs[this.rootCommit.get('id')] = this.rootCommit;
var master = this.makeBranch('master', this.rootCommit);
this.HEAD = new Ref({
id: 'HEAD',
target: master
});
this.refs[this.HEAD.get('id')] = this.HEAD;
// commit once to get things going
this.commit();
};
GitEngine.prototype.getDetachedHead = function() {
// detached head is if HEAD points to a commit instead of a branch...
var target = this.HEAD.get('target');
var targetType = target.get('type');
return targetType !== 'branch';
};
GitEngine.prototype.makeBranch = function(id, target) {
var branch = new Branch({
target: target,
id: id
});
this.refs[branch.get('id')] = branch;
return branch;
};
GitEngine.prototype.makeCommit = function(parent) {
var commit = new Commit({
parents: [parent]
});
this.refs[commit.get('id')] = commit;
return commit;
};
GitEngine.prototype.commit = function() {
if (this.getDetachedHead()) {
throw new Error('you are in detached head state!');
}
// commits are always done on head
var targetBranch = this.HEAD.get('target');
var targetCommit = targetBranch.get('target');
var newCommit = this.makeCommit(targetCommit);
targetBranch.set('target', newCommit);
};
GitEngine.prototype.resolveId = function(idOrTarget) {
if (typeof idOrTarget !== 'string') {
return idOrTarget;
}
return this.resolveStringRef(idOrTarget);
};
GitEngine.prototype.resolveStringRef = function(ref) {
var target = this.refs[ref];
if (!target) {
throw new Error('that ref ' + idOrTarget + ' does not exist');
}
return target;
};
GitEngine.prototype.checkout = function(idOrTarget) {
var target = this.resolveId(idOrTarget);
var type = target.get('type');
if (type !== 'branch' && type !== 'commit') {
throw new Error('can only checkout branches and commits!');
}
this.HEAD.set('target', target);
}; };
GitEngine.prototype.execute = function(command, callback) { GitEngine.prototype.execute = function(command, callback) {
@ -30,91 +119,68 @@ GitEngine.prototype.getClosuresForCommand = function(command) {
return closures; return closures;
}; };
var Commit = Backbone.Model.extend({ var Ref = Backbone.Model.extend({
initialize: function() { initialize: function() {
// validation / defaults if (!this.get('target')) {
throw new Error('must be initialized with target');
}
if (!this.get('id')) { if (!this.get('id')) {
this.set('id', _.uniqueId('C')); throw new Error('must be given an id');
}
if (!this.get('parentCommit') && !this.get('rootCommit')) {
throw new Error('needs parent commit');
} }
this.set('type', 'general ref');
},
this.set('node', sys.addNode(this.get('id'))); toString: function() {
return 'a ' + this.get('type') + 'pointing to ' + String(this.get('target'));
if (this.get('rootCommit')) {
// TODO -- fix this node in place
// this.get('node').fixed = true;
// this.get('node').p = {x: 0, y: 0};
} else {
var parentNode = this.get('parentCommit').get('node');
sys.addEdge(parentNode, this.get('node'));
}
} }
}); });
var Branch = Ref.extend({
function CommandQueue() { initialize: function() {
this.commands = []; Ref.prototype.initialize.call(this);
this.consumeTimeout = null; this.set('type', 'branch');
this.initialDelay = 400;
} }
});
CommandQueue.prototype.add = function(command) { var Commit = Backbone.Model.extend({
this.commands.push(command); validateAtInit: function() {
this.touchTimer(); if (!this.get('id')) {
}; this.set('id', uniqueId('C'));
CommandQueue.prototype.touchTimer = function() {
if (this.consumeTimeout) {
return;
} }
this.consumeTimeout = setTimeout(_.bind(function() { this.set('type', 'commit');
this.next();
}, this), this.initialDelay);
};
CommandQueue.prototype.reset = function() { // root commits have no parents
this.consumeTimeout = null; if (this.get('rootCommit')) {
}; this.set('parents', []);
} else {
CommandQueue.prototype.next = function() { if (!this.get('parents') || !this.get('parents').length) {
if (this.commands.length == 0) { throw new Error('needs parents');
this.reset();
return;
} }
}
},
// execute the top command by passing it into the engine addNodeToVisuals: function() {
var toExecute = this.commands.shift(0); // TODO: arbor stuff
var callback = _.bind(function() { // this.set('node', sys.addNode(this.get('id')));
this.next(); },
addEdgeToVisuals: function(parent) {
},
initialize: function() {
this.validateAtInit();
this.addNodeToVisuals();
console.log('MAKING NEW COMMIT', this.get('id'));
_.each(this.get('parents'), function(parent) {
if (parent.get('child')) {
console.warn('overwriting child for ', parent, ' to this', this);
}
parent.set('child', this);
this.addEdgeToVisuals(parent);
}, this); }, this);
gitEngine.execute(toExecute, callback); }
}; });
/******************
* Planning:
here is the major flow:
someone types in a command ->
make a new command object. if error, give immediate feedback, dont append to queue
if not error ->
append command object to queue
Command Queue ->
consume commands at a certain rate (either instantly if just added, or with an interval
Execute command -> (usually a git engine thing)
Wait for git engine command to finish
when done, execute next command (if more)
so two levels of Async-ness:
command queue slowly consumes commands
GitEngine executes commands, which will have async bits to them (such as popping off commits for a
rebase)
*/

View file

@ -58,7 +58,7 @@ Renderer = function(canvas) {
var p = {x:e.pageX-pos.left, y:e.pageY-pos.top}; var p = {x:e.pageX-pos.left, y:e.pageY-pos.top};
selected = nearest = dragged = particleSystem.nearest(p); selected = nearest = dragged = particleSystem.nearest(p);
if (selected.node !== null){ if (selected && selected.node !== null){
dragged.node.tempMass = constants.clickDragMass; dragged.node.tempMass = constants.clickDragMass;
dragged.node.fixed = true; dragged.node.fixed = true;
} }

View file

@ -7,12 +7,12 @@ var graphicsEffects = {};
var gitEngine = null; var gitEngine = null;
$(document).ready(function(){ $(document).ready(function(){
gitEngine = new GitEngine();
ee = new EventEmitter(); ee = new EventEmitter();
sys = arbor.ParticleSystem(4000, 500, 0.5, false, 55, 0.005, 'verlet'); sys = arbor.ParticleSystem(4000, 500, 0.5, false, 55, 0.005, 'verlet');
sys.renderer = Renderer('#viewport'); sys.renderer = Renderer('#viewport');
gitEngine = new GitEngine();
var repulsionBreathe = function(r) { var repulsionBreathe = function(r) {
sys.parameters({repulsion: r}); sys.parameters({repulsion: r});
}; };