-
Notifications
You must be signed in to change notification settings - Fork 26
Add git-salt lib and git script #242
base: master
Are you sure you want to change the base?
Changes from 6 commits
4f22df1
1172ed1
e988025
e5a18a3
a367dac
2372d80
b7626d7
e12422a
ccc4811
e0e3365
8100c09
59105c7
7fb9780
c484624
3c59045
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -189,7 +189,7 @@ module.exports = function(grunt) { | |
{ | ||
expand: true, | ||
cwd: 'samples/web_shell/scripts/', | ||
src: ['**/*.js', | ||
src: ['**/*.*', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
'**/*.html'], | ||
dest: 'tmp/samples/web_shell/scripts' | ||
}, | ||
|
@@ -313,7 +313,7 @@ module.exports = function(grunt) { | |
options: { | ||
atBegin: true | ||
}, | ||
files: ['lib/**/*.js', 'samples/**/*.js'], | ||
files: ['lib/**/*.js', 'samples/**/*.*'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above. Can't we list all extensions explicitly? |
||
tasks: ['check', 'samples'] | ||
}, | ||
check_test_harness: { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,311 @@ | ||
// Copyright 2015 Google Inc. All rights reserved. | ||
// | ||
// 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. | ||
|
||
var PROXY_SERVER_URL = 'pepper_https://cors-anywhere.herokuapp.com/'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a TODO comment this is temporary |
||
var GIT_NMF_FILE_PATH = 'scripts/resources/git'; | ||
|
||
// The subject field sent with each message to identify it. | ||
var messageId = 1; | ||
|
||
document.currentScript.ready(function(cx) { | ||
var GIT_CMD_USAGE_STRING = 'usage: git [options]'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Additional details? It looks like we support |
||
|
||
/** | ||
* @return {void} | ||
*/ | ||
var gitMain = function(cx) { | ||
cx.ready(); | ||
|
||
/** @type {Array<string>} */ | ||
var list = cx.getArg('_', []); | ||
if (list.length != 3 || cx.getArg('help')) { | ||
cx.stdout.write(GIT_CMD_USAGE_STRING + '\n'); | ||
return cx.closeOk(); | ||
} | ||
|
||
createMessage(cx).then(function(message) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nicer to wrap all this code into a separate function, so that we don't have to hunt for the
|
||
/** @type {GitSalt} */ | ||
var git = new GitSalt(); | ||
|
||
git.loadPlugin('git_salt', GIT_NMF_FILE_PATH).then(function() { | ||
var cb = createMessageCallback(cx, message); | ||
git.postMessage(message, cb); | ||
}).catch(function(e) { | ||
cx.closeError(e); | ||
}); | ||
}); | ||
}; | ||
|
||
gitMain.signature = { | ||
'help|h': '?', | ||
'_': '@' | ||
}; | ||
|
||
var installGit = function(cx) { | ||
var path = new axiom.fs.path.Path('jsfs:/exe'); | ||
var jsDir = cx.jsfs.resolve(path).entry; | ||
jsDir.install({ | ||
'git': gitMain | ||
}); | ||
}; | ||
installGit(cx); | ||
}); | ||
|
||
function genMessageId() { | ||
messageId++; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. indentation? |
||
return messageId.toString(); | ||
} | ||
|
||
function createMessage(cx) { | ||
var message = {}; | ||
var args = {}; | ||
var list = cx.getArg('_', []); | ||
var command = list.shift(); | ||
var path; | ||
|
||
// TODO(grv): Make the check case insensitive. | ||
if (command == 'clone' && list.length == 2) { | ||
message['name'] = 'clone'; | ||
args['url'] = PROXY_SERVER_URL + list.shift(); | ||
|
||
// TODO(grv): resolve path using pwd instead of taking as argument. | ||
path = new axiom.fs.path.Path(list.shift()); | ||
} else { | ||
throw new axiom.core.error.AxiomError.Invalid( | ||
'Invalid arguments to git.', []); | ||
} | ||
|
||
return cx.fileSystemManager.mkdir(path).then(function(dir) { | ||
args['filesystem'] = dir.filesystem; | ||
args['fullPath'] = dir.fullPath; | ||
message['subject'] = genMessageId(); | ||
message.arg = args; | ||
return message; | ||
}); | ||
} | ||
|
||
function createMessageCallback(cx, message) { | ||
var cb = function(result) { | ||
console.log(message['name'] + ' command successful!'); | ||
cx.closeOk(); | ||
}; | ||
return cb; | ||
} | ||
|
||
/** | ||
*@constructor | ||
*/ | ||
var GitSalt = function() { | ||
this.callbacks = new Object(); | ||
}; | ||
|
||
GitSalt.prototype.listenerDiv = null; | ||
|
||
GitSalt.prototype.loadPromise = null; | ||
|
||
GitSalt.prototype.callbacks = {}; | ||
|
||
/** | ||
* Create the Native Client <embed> element as a child of the DOM element | ||
* named "listener". | ||
* | ||
* @param {string} name The name of the example. | ||
* @param {string} path Directory name where .nmf file can be found. | ||
*/ | ||
GitSalt.prototype.createNaClModule = function(name, path) { | ||
return new Promise(function(resolve, reject) { | ||
this.loadPromise = resolve; | ||
var moduleEl = document.createElement('embed'); | ||
moduleEl.setAttribute('width', 0); | ||
moduleEl.setAttribute('height', 0); | ||
moduleEl.setAttribute('path', path); | ||
moduleEl.setAttribute('src', path + '/' + name + '.nmf'); | ||
|
||
moduleEl.setAttribute('type', "application/x-pnacl"); | ||
this.naclModule = moduleEl; | ||
|
||
// The <EMBED> element is wrapped inside a <DIV>, which has both a 'load' | ||
// and a 'message' event listener attached. This wrapping method is used | ||
// instead of attaching the event listeners directly to the <EMBED> element | ||
// to ensure that the listeners are active before the NaCl module 'load' | ||
// event fires. | ||
this.listenerDiv.appendChild(moduleEl); | ||
}.bind(this)); | ||
}; | ||
|
||
GitSalt.prototype.statusText = 'NO-STATUSES'; | ||
|
||
GitSalt.prototype.updateStatus = function(opt_message) { | ||
if (opt_message) { | ||
statusText = opt_message; | ||
} | ||
} | ||
|
||
/** | ||
* Add the default "load" and "message" event listeners to the element with | ||
* id "listener". | ||
* | ||
* The "load" event is sent when the module is successfully loaded. The | ||
* "message" event is sent when the naclModule posts a message using | ||
* PPB_Messaging.PostMessage() (in C) or pp::Instance().PostMessage() (in | ||
* C++). | ||
*/ | ||
GitSalt.prototype.attachDefaultListeners = function() { | ||
this.listenerDiv.addEventListener('load', this.moduleDidLoad.bind(this), true); | ||
this.listenerDiv.addEventListener('message', this.handleMessage.bind(this), true); | ||
this.listenerDiv.addEventListener('error', this.handleError.bind(this), true); | ||
this.listenerDiv.addEventListener('crash', this.handleCrash.bind(this), true); | ||
}; | ||
|
||
/** | ||
* Called when the NaCl module fails to load. | ||
* | ||
* This event listener is registered in createNaClModule above. | ||
*/ | ||
GitSalt.prototype.handleError = function(event) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't we propagate (somehow) the error to cx so we display an error in the wash window? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, We should propagate these to stderr somehow. I will add a todo and add a fix in follow up PR. |
||
this.updateStatus('ERROR [' + this.naclModule.lastError + ']'); | ||
}; | ||
|
||
/** | ||
* Called when the Browser can not communicate with the Module | ||
* | ||
* This event listener is registered in attachDefaultListeners above. | ||
*/ | ||
GitSalt.prototype.handleCrash = function(event) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't we propagate (somehow) the error to cx so we display an error in the wash window? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. |
||
if (this.naclModule.exitStatus == -1) { | ||
this.updateStatus('CRASHED'); | ||
} else { | ||
this.updateStatus('EXITED [' + this.naclModule.exitStatus + ']'); | ||
} | ||
if (typeof window.handleCrash !== 'undefined') { | ||
window.handleCrash(this.naclModule.lastError); | ||
} | ||
}; | ||
|
||
/** | ||
* Called when the NaCl module is loaded. | ||
* | ||
* This event listener is registered in attachDefaultListeners above. | ||
*/ | ||
GitSalt.prototype.moduleDidLoad = function() { | ||
this.updateStatus('RUNNING'); | ||
if (typeof window.moduleDidLoad !== 'undefined') { | ||
window.moduleDidLoad(); | ||
} | ||
if (this.loadPromise != null) { | ||
this.loadPromise(); | ||
this.loadPromise = null; | ||
} | ||
}; | ||
|
||
/** | ||
* Hide the NaCl module's embed element. | ||
* | ||
* We don't want to hide by default; if we do, it is harder to determine that | ||
* a plugin failed to load. Instead, call this function inside the example's | ||
* "moduleDidLoad" function. | ||
* | ||
*/ | ||
GitSalt.prototype.hideModule = function() { | ||
// Setting GitSalt.naclModule.style.display = "None" doesn't work; the | ||
// module will no longer be able to receive postMessages. | ||
this.naclModule.style.height = '0'; | ||
}; | ||
|
||
/** | ||
* Remove the NaCl module from the page. | ||
*/ | ||
GitSalt.prototype.removeModule = function() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see any call to this function, does this mean we leak a git object at each invocation? |
||
this.naclModule.parentNode.removeChild(this.naclModule); | ||
this.naclModule = null; | ||
}; | ||
|
||
/** | ||
* Return true when |s| starts with the string |prefix|. | ||
* | ||
* @param {string} s The string to search. | ||
* @param {string} prefix The prefix to search for in |s|. | ||
*/ | ||
GitSalt.prototype.startsWith = function(s, prefix) { | ||
// indexOf would search the entire string, lastIndexOf(p, 0) only checks at | ||
// the first index. See: http://stackoverflow.com/a/4579228 | ||
return s.lastIndexOf(prefix, 0) === 0; | ||
}; | ||
|
||
GitSalt.prototype.logMessage = function(message) { | ||
console.log(message); | ||
}; | ||
|
||
GitSalt.prototype.defaultMessageTypes = { | ||
'alert': alert, | ||
'log': this.logMessage | ||
}; | ||
|
||
/** | ||
* Called when the NaCl module sends a message to JavaScript (via | ||
* PPB_Messaging.PostMessage()) | ||
* | ||
* This event listener is registered in createNaClModule above. | ||
* | ||
* @param {Event} message_event A message event. message_event.data contains | ||
* the data sent from the NaCl module. | ||
*/ | ||
GitSalt.prototype.handleMessage = function(message_event) { | ||
if (typeof message_event.data === 'string') { | ||
for (var type in this.defaultMessageTypes) { | ||
if (this.defaultMessageTypes.hasOwnProperty(type)) { | ||
if (this.startsWith(message_event.data, type + ':')) { | ||
func = this.defaultMessageTypes[type]; | ||
func(message_event.data.slice(type.length + 1)); | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
|
||
this.handleResponse(message_event); | ||
}; | ||
|
||
GitSalt.prototype.handleResponse = function(response) { | ||
var cb = this.callbacks[response.data.regarding]; | ||
if (cb != null) { | ||
cb(response.data.arg); | ||
this.callbacks[response.data] = null; | ||
} | ||
}; | ||
|
||
/** | ||
* @param {string} name The name of the example. | ||
* @param {string} path Directory name where .nmf file can be found. | ||
*/ | ||
GitSalt.prototype.loadPlugin = function(name, path) { | ||
this.listenerDiv = document.createElement('div'); | ||
|
||
var addons = document.getElementById('addons'); | ||
var gitSaltContainer = document.getElementById('git-salt-container'); | ||
if (!gitSaltContainer) { | ||
gitSaltContainer = document.createElement('div'); | ||
gitSaltContainer.id = 'git-salt-container'; | ||
addons.appendChild(gitSaltContainer); | ||
} | ||
gitSaltContainer.appendChild(this.listenerDiv); | ||
|
||
this.attachDefaultListeners(); | ||
return this.createNaClModule(name, path); | ||
}; | ||
|
||
GitSalt.prototype.postMessage = function(message, cb) { | ||
this.callbacks[message.subject] = cb; | ||
this.naclModule.postMessage(message); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Copyright (c) 2013 The Chromium Authors. All rights reserved. | ||
# Use of this source code is governed by a BSD-style license that can be | ||
# found in the LICENSE file. | ||
|
||
# GNU Makefile based on shared rules provided by the Native Client SDK. | ||
# See README.Makefiles for more details. | ||
|
||
VALID_TOOLCHAINS := pnacl | ||
|
||
NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../../..) | ||
|
||
|
||
include $(NACL_SDK_ROOT)/tools/common.mk | ||
|
||
|
||
TARGET = git_salt | ||
LIBS = git2 ssl ssh2 crypto nacl_io glibc-compat ppapi_cpp ppapi pthread z | ||
|
||
CFLAGS = -Wall | ||
SOURCES = main.cc git_command.cc git_salt.cc | ||
|
||
# Build rules generated by macros from common.mk: | ||
|
||
$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS)))) | ||
|
||
# The PNaCl workflow uses both an unstripped and finalized/stripped binary. | ||
# On NaCl, only produce a stripped binary for Release configs (not Debug). | ||
ifneq (,$(or $(findstring pnacl,$(TOOLCHAIN)),$(findstring Release,$(CONFIG)))) | ||
$(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS))) | ||
$(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped)) | ||
else | ||
$(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS))) | ||
endif | ||
|
||
$(eval $(call NMF_RULE,$(TARGET),)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This task is supposed to be generic, so we should not have this here. Can't we create the 'div' manually if it does not exist (in the code that creates the sub-elements)?