Compare commits
No commits in common. "master" and "alpha" have entirely different histories.
56 changed files with 1824 additions and 4951 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
node_modules
|
||||
repositories
|
||||
database/webide_data_store
|
||||
users.db
|
||||
|
||||
/editor.tar.gz
|
||||
__MACOSX
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 4.8.2
|
||||
- 0.8
|
||||
- 0.6
|
||||
|
|
|
|||
91
README.md
91
README.md
|
|
@ -1,24 +1,17 @@
|
|||
Adafruit webIDE
|
||||
================
|
||||
This is a simple editor designed to help learn the Raspberry Pi and Beaglebone components, and more. This editor is designed solely for use on your secure private network as of now.
|
||||
|
||||
## Note
|
||||
This guidance and repo are deprecated and no longer supported.
|
||||
It is here for historical purposes only
|
||||
******************************************************************************
|
||||
This is a simple editor designed to help learn the Raspberry Pi (including the Raspberry Pi 2) and Beaglebone components, and more. This editor is designed solely for use on your secure private network as of now.
|
||||
|
||||
Debian Installation (Raspberry Pi and BeagleBone Black)
|
||||
============
|
||||
|
||||
The WebIDE installer is currently targeting Debian Stretch (latest Raspbian) installations only.
|
||||
|
||||
On the Raspberry PI or BeagleBone Black (after expanding the file system):
|
||||
|
||||
curl https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/master/scripts/install.sh | sudo sh
|
||||
curl https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/alpha/scripts/install.sh | sudo sh
|
||||
|
||||
Alternatively, you can install using the .deb file:
|
||||
|
||||
curl -O https://adafruit-download.s3.amazonaws.com/adafruitwebide-0.3.12-Linux.deb
|
||||
curl -O http://adafruit-download.s3.amazonaws.com/adafruitwebide-0.3.12-Linux.deb
|
||||
sudo dpkg -i adafruitwebide-0.3.12-Linux.deb
|
||||
sudo apt-get -f install
|
||||
|
||||
|
|
@ -28,24 +21,57 @@ If you don't need these features, feel free to manually install the editor below
|
|||
|
||||
Note: This is also the default installation for any Debian or Ubuntu operating systems
|
||||
|
||||
Manual Installation
|
||||
Angstrom Installation (BeagleBone Black)
|
||||
============
|
||||
|
||||
Follow along in the [installation script][1] and pick and choose
|
||||
the components you'd like to install.
|
||||
On the Beaglebone (as the default root user), execute each line independently:
|
||||
|
||||
echo "nameserver 8.8.8.8" >> /etc/resolv.conf
|
||||
curl -k https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/alpha/scripts/install-angstrom.sh | sh
|
||||
|
||||
Note: The curl -k command is used due to the Beaglebone not having the github SSL certificate in the default installation.
|
||||
|
||||
Note: If you've replaced the default operating system (Angstrom) with Debian or Ubuntu, use the Raspberry Pi installation instructions.
|
||||
|
||||
Manual Installation (without process monitor)
|
||||
============
|
||||
|
||||
On the Raspberry PI:
|
||||
|
||||
sudo apt-get update && sudo apt-get -y install build-essential nodejs nodejs-legacy npm redis-server git
|
||||
git clone git://github.com/adafruit/Adafruit-WebIDE.git
|
||||
cd Adafruit-WebIDE
|
||||
mkdir tmp
|
||||
npm config set tmp tmp
|
||||
npm install
|
||||
editor config/config.js (change port 80 to your port of choice)
|
||||
nodejs server.js
|
||||
|
||||
You can look at the install.sh script if you'd like a process monitor, and to install it
|
||||
as a daemon.
|
||||
|
||||
Uninstallation
|
||||
============
|
||||
|
||||
Debian (Raspberry PI and BeagleBone Black):
|
||||
|
||||
curl https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/master/scripts/uninstall.sh | sudo sh
|
||||
curl https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/alpha/scripts/uninstall.sh | sudo sh
|
||||
|
||||
Or if you installed with the .deb file:
|
||||
|
||||
sudo apt-get remove adafruitwebide
|
||||
|
||||
Angstrom (BeagleBone Black, as default root user):
|
||||
|
||||
curl -k https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/alpha/scripts/uninstall-angstrom.sh | sh
|
||||
|
||||
Manual Uninstallation
|
||||
============
|
||||
|
||||
Follow along in the [uninstallation script][2] and pick and choose
|
||||
the components you'd like to remove.
|
||||
On the Raspberry PI or BeagleBone Black:
|
||||
|
||||
rm -r Adafruit-WebIDE
|
||||
rm ~/.ssh/id_rsa_bitbucket*
|
||||
|
||||
Running the Editor
|
||||
============
|
||||
|
|
@ -54,7 +80,7 @@ Using Firefox or Chrome (and likely any other webkit browser) on any computer in
|
|||
|
||||
Raspberry Pi:
|
||||
|
||||
http://raspberrypi.local:8080
|
||||
http://raspberrypi.local
|
||||
|
||||
BeagleBone:
|
||||
|
||||
|
|
@ -65,17 +91,35 @@ Restart the Editor
|
|||
|
||||
If for any reason you need to restart the editor, you can execute the following commands in order
|
||||
|
||||
sudo systemctl restart adafruit-webide
|
||||
sudo systemctl start adafruit-webide
|
||||
sudo service adafruit-webide.sh stop
|
||||
sudo service adafruit-webide.sh start
|
||||
|
||||
Sudo is required to restart due to the editor running as the 'webide' user.
|
||||
|
||||
Status or Logs for the Editor
|
||||
Advanced Options
|
||||
============
|
||||
|
||||
sudo systemctl status adafruit-webide
|
||||
Offline Mode Installation:
|
||||
|
||||
Logs are in syslog: /var/log/syslog
|
||||
curl https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/alpha/scripts/install.sh | sudo sh -s - --offline
|
||||
|
||||
Note: Offline mode does not setup git in any way other than installing it. You'll want to git config your
|
||||
email and name, and setup your ssh keys.
|
||||
|
||||
GitHub Mode Installation:
|
||||
|
||||
curl https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/alpha/scripts/install.sh | sudo sh -s - --github
|
||||
|
||||
Note: GitHub mode does not automatically create, and post an ssh key to your GitHub account. It requires
|
||||
a bit more manual setup at this time.
|
||||
|
||||
Enable support for Makefiles (execute on the Pi in the terminal, post-installation):
|
||||
|
||||
redis-cli hmset editor:settings enable_make "on"
|
||||
|
||||
Disable:
|
||||
|
||||
redis-cli hmset editor:settings enable_make "off"
|
||||
|
||||
License
|
||||
============
|
||||
|
|
@ -86,6 +130,3 @@ http://www.gnu.org/licenses/agpl-3.0.html
|
|||
SCREENSHOTS
|
||||
===========
|
||||

|
||||
|
||||
[1]: https://github.com/adafruit/Adafruit-WebIDE/blob/master/scripts/install.sh
|
||||
[2]: https://github.com/adafruit/Adafruit-WebIDE/blob/master/scripts/uninstall.sh
|
||||
|
|
|
|||
BIN
bin/node_hf/node
Normal file
BIN
bin/node_hf/node
Normal file
Binary file not shown.
1
bin/node_hf/version.md
Normal file
1
bin/node_hf/version.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
node hardfloat v0.10.29
|
||||
BIN
bin/node_sf/node
Normal file
BIN
bin/node_sf/node
Normal file
Binary file not shown.
1
bin/node_sf/version.md
Normal file
1
bin/node_sf/version.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
node softfloat v0.8.9
|
||||
|
|
@ -2,16 +2,19 @@ Welcome to the Adafruit webIDE.
|
|||
|
||||
We've pre-loaded the Adafruit Python libraries that you may find useful.
|
||||
|
||||
By navigating into those libraries, you can choose to copy them into your
|
||||
project folder, so you can edit, and save them. If you ever need to start
|
||||
over, just delete your copied project folder, and grab the
|
||||
By navigating into those libraries, you can choose to copy them into your
|
||||
project folder, so you can edit, and save them. If you ever need to start
|
||||
over, just delete your copied project folder, and grab the
|
||||
Adafruit libraries again.
|
||||
|
||||
We've also created a folder you can start putting your projects into.
|
||||
We've also created a folder you can start putting your projects into. This
|
||||
is a version-controlled repository stored in your Bitbucket account.
|
||||
Whenever you create projects and files within this folder, they will be
|
||||
versioned and saved at Bitbucket.
|
||||
|
||||
This file was pre-loaded in your projects folder, and is located in the
|
||||
This file was pre-loaded in your projects folder, and is located in the
|
||||
'my-pi-projects' link to the left.
|
||||
|
||||
We have usage information, installation instructions and various
|
||||
other information you may find useful at the Adafruit Learning System:
|
||||
other information you may find useful at the Adafruit Learning System:
|
||||
http://learn.adafruit.com/webide
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@
|
|||
//Change offline in /config.
|
||||
//Change github in /config.
|
||||
exports.editor = {
|
||||
"port": 3000,
|
||||
"version": "0.8.0",
|
||||
"version_url": "https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/master/release/version.txt"
|
||||
"port": 80,
|
||||
"version": "0.3.12",
|
||||
"version_url": "https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/alpha/release/version.txt",
|
||||
"offline": false,
|
||||
"github": false
|
||||
};
|
||||
|
||||
exports.adafruit = {
|
||||
|
|
|
|||
|
|
@ -1,148 +1,30 @@
|
|||
var fs_helper = require('../helpers/fs_helper'),
|
||||
winston = require('winston'),
|
||||
editor_setup = require('../helpers/editor_setup'),
|
||||
path = require('path'),
|
||||
redis = require('redis'),
|
||||
client = redis.createClient(),
|
||||
git_helper = require('../helpers/git_helper'),
|
||||
updater = require('../helpers/updater'),
|
||||
scheduler = require('../helpers/scheduler'),
|
||||
debug_helper = require('../helpers/python/debug_helper'),
|
||||
exec_helper = require('../helpers/exec_helper'),
|
||||
scheduler = require('../helpers/scheduler'),
|
||||
config = require('../config/config'),
|
||||
db = require('../models/webideModel'),
|
||||
sanitize = require('validator');
|
||||
|
||||
var REPOSITORY_PATH = path.resolve(__dirname, "../repositories");
|
||||
check = require('validator').check,
|
||||
sanitize = require('validator').sanitize;
|
||||
|
||||
//Loads the editor
|
||||
exports.index = function(req, res) {
|
||||
req.session.message = undefined;
|
||||
db.findOne({"type": "user"}, function(err, user) {
|
||||
if (!user) {
|
||||
req.session.message = "Set your name and email prior to continuing to the editor.";
|
||||
res.redirect('/setup');
|
||||
var shown_notification = false;
|
||||
client.get('editor:shown_notification', function(err, result) {
|
||||
if (result) {
|
||||
shown_notification = result;
|
||||
} else {
|
||||
res.render('editor/index', {profile: req.user, version: config.editor.version, shown_notification: false});
|
||||
client.set('editor:shown_notification', true);
|
||||
}
|
||||
res.render('editor/index', {profile: req.user, version: config.editor.version, shown_notification: shown_notification});
|
||||
});
|
||||
};
|
||||
|
||||
exports.editor = function(ws, req) {
|
||||
config.editor_ws = ws;
|
||||
winston.debug('socket io connection completed');
|
||||
|
||||
function send_message(type, data) {
|
||||
ws.send(JSON.stringify({type: type, data: data}));
|
||||
}
|
||||
|
||||
//emit on first connection
|
||||
send_message('cwd-init', {dirname: REPOSITORY_PATH});
|
||||
scheduler.emit_scheduled_jobs(ws);
|
||||
|
||||
ws.on('message', function(msg) {
|
||||
var message = JSON.parse(msg);
|
||||
var type = message.type;
|
||||
var data = message.data;
|
||||
|
||||
winston.debug("Editor action type: " + type);
|
||||
|
||||
switch (type) {
|
||||
case 'self-check-request':
|
||||
winston.debug('self-check-request');
|
||||
editor_setup.health_check(ws);
|
||||
break;
|
||||
case 'git-delete':
|
||||
git_helper.remove_commit_push(data.file, function(err, status) {
|
||||
send_message('git-delete-complete', {err: err, status: status});
|
||||
});
|
||||
break;
|
||||
case 'git-pull':
|
||||
var name = data.file ? data.file.name : "";
|
||||
git_helper.pull(name, "origin", "master", function(err, status) {
|
||||
send_message('git-pull-complete', {err: err, status: status});
|
||||
});
|
||||
break;
|
||||
case 'git-is-modified':
|
||||
git_helper.is_modified(data.file, function(err, status) {
|
||||
send_message('git-is-modified-complete', {is_modified: status});
|
||||
});
|
||||
break;
|
||||
case 'commit-file':
|
||||
var commit_message = "";
|
||||
|
||||
if (data.message) {
|
||||
commit_message = data.message;
|
||||
} else {
|
||||
commit_message = "Modified " + data.file.name;
|
||||
}
|
||||
|
||||
git_helper.commit_push_and_save(data.file, commit_message, function(err, status) {
|
||||
send_message('commit-file-complete', {err: err, status: status});
|
||||
});
|
||||
break;
|
||||
case 'move-file':
|
||||
git_helper.move_commit_push(data.file, function(err) {
|
||||
console.log('move-file', err);
|
||||
send_message('move-file-complete', {err: err});
|
||||
});
|
||||
break;
|
||||
case 'editor-check-updates':
|
||||
// TODO: Explore adding auto-updater again
|
||||
// updater.check_for_updates(ws);
|
||||
break;
|
||||
case 'editor-update':
|
||||
updater.update(ws);
|
||||
break;
|
||||
case 'trace-file':
|
||||
exec_helper.trace_program(data.file, ws);
|
||||
break;
|
||||
case 'debug-command':
|
||||
debug_helper.debug_command(data, ws);
|
||||
break;
|
||||
case 'debug-file':
|
||||
debug_helper.start_debug(data.file, ws);
|
||||
break;
|
||||
case 'commit-run-file':
|
||||
exec_helper.execute_program(data.file, false);
|
||||
git_helper.commit_push_and_save(data.file, "Modified " + data.file.name, function(err, status) {
|
||||
send_message('commit-file-complete', {message: "Save was successful"});
|
||||
});
|
||||
break;
|
||||
case 'stop-script-execution':
|
||||
exec_helper.stop_program(data.file, false);
|
||||
break;
|
||||
case 'submit-schedule':
|
||||
scheduler.add_schedule(data, ws);
|
||||
break;
|
||||
case 'schedule-delete-job':
|
||||
scheduler.delete_job(data, ws);
|
||||
break;
|
||||
case 'schedule-toggle-job':
|
||||
scheduler.toggle_job(data, ws);
|
||||
break;
|
||||
case 'set-settings':
|
||||
data["type"] = "editor:settings";
|
||||
db.findOne({type: "editor:settings"}, function(err, settings) {
|
||||
db.update({type: "editor:settings"}, Object.assign(settings || {}, data || {}), { upsert: true }, function(err) {
|
||||
data["type"] = "editor:settings";
|
||||
if (err) winston.error(err);
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
ws.on('disconnect', function() {
|
||||
debug_helper.client_disconnect();
|
||||
debug_helper.kill_debug();
|
||||
});
|
||||
}
|
||||
|
||||
exports.create_repository = function(req, res) {
|
||||
var repository_url = sanitize.trim(req.body.repository_url);
|
||||
var repository_url = sanitize(req.body.repository_url).xss().trim();
|
||||
var retain_remote = sanitize(req.body.retain_remote).xss().trim();
|
||||
|
||||
git_helper.clone_update_remote_push(req.user, repository_url, function(err, status) {
|
||||
git_helper.clone_update_remote_push(req.user, repository_url, retain_remote, function(err, status) {
|
||||
if (err) res.send(err, 404);
|
||||
else res.send(status, 200);
|
||||
});
|
||||
|
|
@ -150,7 +32,7 @@ exports.create_repository = function(req, res) {
|
|||
|
||||
//Opens an image clicked from the editor navigator
|
||||
exports.image = function(req, res) {
|
||||
var temp_path = sanitize(req.query.path).trim().replace('/filesystem/', '/repositories/');
|
||||
var temp_path = sanitize(req.query.path).xss().trim().replace('/filesystem/', '/repositories/');
|
||||
//strip basic attempted path traversals
|
||||
temp_path = temp_path.replace('..', '');
|
||||
|
||||
|
|
@ -161,15 +43,13 @@ exports.image = function(req, res) {
|
|||
};
|
||||
|
||||
exports.upload_file = function(req, res) {
|
||||
console.log(req.file);
|
||||
console.log(req.file.originalname);
|
||||
console.log(req.file.path);
|
||||
console.log(req.files.files[0]);
|
||||
|
||||
var temp_path = sanitize.trim(req.file.path);
|
||||
var file_name = sanitize.trim(req.file.originalname);
|
||||
var temp_path = sanitize(req.files.files[0].path).xss().trim();
|
||||
var file_name = sanitize(req.files.files[0].name).xss().trim();
|
||||
file_name = file_name.replace(" ", "_");
|
||||
var folder_path = sanitize.trim(req.body.path).replace('filesystem', 'repositories');
|
||||
|
||||
var folder_path = sanitize(req.body.path).xss().trim().replace('filesystem', 'repositories');
|
||||
|
||||
var new_path = __dirname + '/..' + folder_path + file_name;
|
||||
new_path = path.resolve(new_path);
|
||||
|
||||
|
|
@ -178,9 +58,9 @@ exports.upload_file = function(req, res) {
|
|||
res.send(false, 200);
|
||||
} else {
|
||||
var comment = "Uploaded new File.";
|
||||
git_helper.commit_push_and_save({path: folder_path + file_name}, comment, function(err, status) {
|
||||
git_helper.commit_push_and_save({path: folder_path + file_name}, comment, null, function(err, status) {
|
||||
res.send(true, 200);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
var request_helper = require('../helpers/request_helper');
|
||||
|
||||
exports.index = function(req, res){
|
||||
res.redirect('/editor');
|
||||
};
|
||||
if (req.user) {
|
||||
res.redirect('/editor');
|
||||
}
|
||||
};
|
||||
|
|
@ -1,44 +1,68 @@
|
|||
var path = require('path'),
|
||||
db = require('../models/webideModel'),
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient(),
|
||||
scripts_helper = require('../helpers/scripts_helper'),
|
||||
config = require('../config/config'),
|
||||
sanitize = require('validator');
|
||||
check = require('validator').check,
|
||||
sanitize = require('validator').sanitize;
|
||||
|
||||
// Instructional page that displays the setup steps
|
||||
exports.login = function(req, res){
|
||||
res.render('users/login', { title: 'test', user: req.user, github: config.editor.github });
|
||||
};
|
||||
|
||||
exports.logout = function(req, res){
|
||||
req.logout();
|
||||
res.redirect('/');
|
||||
};
|
||||
|
||||
// Instructional page that displays the bitbucket setup steps,
|
||||
// and inputs for OAuth and Git config
|
||||
exports.setup = function(req, res) {
|
||||
var locals = {
|
||||
consumer_key: "",
|
||||
consumer_secret: "",
|
||||
name: "",
|
||||
email: "",
|
||||
hostname: ""
|
||||
hostname: "",
|
||||
github: config.editor.github
|
||||
};
|
||||
|
||||
res.render('users/setup', locals);
|
||||
};
|
||||
|
||||
// Saves the git config setup information in nedb,
|
||||
// Saves the bitbucket and git config setup information in Redis,
|
||||
// submitted as a post from /setup
|
||||
exports.submit_setup = function(req, res) {
|
||||
var name, email, message;
|
||||
var key, secret, name, email, message;
|
||||
req.session.message = undefined;
|
||||
|
||||
function common_setup(name, email) {
|
||||
db.update({"type": "user"}, {"type": "user", "name": name, "email": email}, { upsert: true }, function() {
|
||||
client.hmset("user", "name", name, "email", email, function() {
|
||||
req.session.message = "Settings Successfully Configured.";
|
||||
res.redirect('/editor');
|
||||
res.redirect('/login');
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
name = sanitize.trim(req.body.name);
|
||||
email = sanitize.trim(req.body.email);
|
||||
sanitize.isEmail(email);
|
||||
key = sanitize(req.body.key).xss().trim();
|
||||
secret = sanitize(req.body.secret).xss().trim();
|
||||
name = sanitize(req.body.name).xss().trim();
|
||||
email = sanitize(req.body.email).xss().trim();
|
||||
check(email).isEmail();
|
||||
} catch (e) {
|
||||
req.session.message = e.message;
|
||||
console.log(e.message);
|
||||
}
|
||||
|
||||
if (name && email) {
|
||||
common_setup(name, email);
|
||||
if (key && secret && name && email) {
|
||||
if (config.editor.github) {
|
||||
client.hmset("github_oauth", "consumer_key", key, "consumer_secret", secret, function() {
|
||||
common_setup(name, email);
|
||||
});
|
||||
} else {
|
||||
client.hmset("bitbucket_oauth", "consumer_key", key, "consumer_secret", secret, function() {
|
||||
common_setup(name, email);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!req.session.message) {
|
||||
req.session.message = "Please set all fields, at the bottom of this page, in order to continue.";
|
||||
|
|
@ -49,31 +73,31 @@ exports.submit_setup = function(req, res) {
|
|||
|
||||
|
||||
exports.config = function(req, res) {
|
||||
db.findOne({type: "server"}, function (err, server) {
|
||||
client.hgetall('server', function (err, server) {
|
||||
var locals = {
|
||||
hostname: "",
|
||||
wifi_ssid: "",
|
||||
wifi_password: "",
|
||||
port: (server ? (server.port || "") : "")
|
||||
};
|
||||
|
||||
|
||||
res.render('users/config', locals);
|
||||
});
|
||||
};
|
||||
|
||||
// Saves the git config setup information in nedb,
|
||||
// Saves the bitbucket and git config setup information in Redis,
|
||||
// submitted as a post from /setup
|
||||
|
||||
//TODO: Refactor this...it's out of control!
|
||||
exports.submit_config = function(req, res) {
|
||||
var name, email, message;
|
||||
var key, secret, name, email, message;
|
||||
req.session.message = undefined;
|
||||
|
||||
try {
|
||||
hostname = sanitize.trim(req.body.hostname);
|
||||
wifi_ssid = sanitize.trim(req.body.wifi_ssid);
|
||||
wifi_password = sanitize.trim(req.body.wifi_password);
|
||||
port = sanitize.trim(req.body.port);
|
||||
hostname = sanitize(req.body.hostname).xss().trim();
|
||||
wifi_ssid = sanitize(req.body.wifi_ssid).xss().trim();
|
||||
wifi_password = sanitize(req.body.wifi_password).xss().trim();
|
||||
port = sanitize(req.body.port).xss().trim();
|
||||
if (hostname) {
|
||||
check(hostname).len(3, 25);
|
||||
}
|
||||
|
|
@ -95,8 +119,7 @@ exports.submit_config = function(req, res) {
|
|||
});
|
||||
}
|
||||
if (port) {
|
||||
db.update({type: "server"}, { $set: {"port": port}}, {}, function() {
|
||||
|
||||
client.hmset("server", "port", port, function() {
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -118,4 +141,4 @@ exports.set_datetime = function(req, res) {
|
|||
scripts_helper.set_datetime(function() {
|
||||
res.redirect('/login');
|
||||
});
|
||||
};
|
||||
};
|
||||
4
db/.gitignore
vendored
4
db/.gitignore
vendored
|
|
@ -1,4 +0,0 @@
|
|||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
|
|
@ -1,70 +1,140 @@
|
|||
var path = require('path'),
|
||||
winston = require('winston'),
|
||||
db = require('../models/webideModel'),
|
||||
exec = require('child_process').exec,
|
||||
fs = require ('fs'),
|
||||
git_helper = require('./git_helper.js'),
|
||||
fs_helper = require('./fs_helper'),
|
||||
ws_helper = require('./websocket_helper'),
|
||||
config = require('../config/config');
|
||||
var exec = require('child_process').exec,
|
||||
fs = require ('fs'),
|
||||
path = require('path'),
|
||||
git_helper = require('./git_helper'),
|
||||
fs_helper = require('./fs_helper'),
|
||||
redis = require('redis'),
|
||||
client = redis.createClient(),
|
||||
request_helper = require('./request_helper'),
|
||||
config = require('../config/config');
|
||||
|
||||
fs.exists || (fs.exists = path.exists);
|
||||
|
||||
exports.setup_adafruit_libraries = function(ws) {
|
||||
exports.setup_github = function(socket) {
|
||||
git_helper.set_config(function() {
|
||||
this.setup_adafruit_libraries(socket);
|
||||
});
|
||||
};
|
||||
|
||||
exports.setup_adafruit_libraries = function(socket) {
|
||||
git_helper.clone_adafruit_libraries(config.adafruit.repository, config.adafruit.remote, function(cloned_libraries) {
|
||||
ws_helper.send_message(ws, "self-check-message", "Cloning remote Adafruit repository");
|
||||
socket.emit("self-check-message", "Cloning remote Adafruit repository");
|
||||
//cloned_libraries is false if they already existed...if false, let's pull the latest version of the adafruit libraries
|
||||
if (!cloned_libraries) {
|
||||
git_helper.pull(config.adafruit.repository, "origin", "master", function() {
|
||||
ws_helper.send_message(ws, "self-check-message", "Adafruit repository updated");
|
||||
socket.emit("self-check-message", "Adafruit repository updated");
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.health_check = function(ws) {
|
||||
//TODO redis to nedb
|
||||
db.findOne({type: "editor:settings"}, function(err, settings) {
|
||||
if (settings) {
|
||||
settings.offline = true;
|
||||
} else {
|
||||
settings = {offline: true};
|
||||
}
|
||||
winston.debug("getting settings", settings);
|
||||
ws_helper.send_message(ws, "self-check-settings", settings);
|
||||
})
|
||||
exports.offline_health_check = function(socket) {
|
||||
client.hgetall('editor:settings', function(err, settings) {
|
||||
|
||||
this.setup_adafruit_libraries(ws);
|
||||
if (settings) {
|
||||
settings.offline = true;
|
||||
} else {
|
||||
settings = {offline: true};
|
||||
}
|
||||
console.log("getting settings", settings);
|
||||
socket.emit("self-check-settings", settings);
|
||||
});
|
||||
|
||||
console.log('self-check-complete');
|
||||
socket.emit('self-check-complete');
|
||||
};
|
||||
|
||||
//TODO this is a terrible mess..clean this up, no reason to have these big blocks of callbacks...uffda.
|
||||
exports.health_check = function(socket, profile) {
|
||||
var that = this;
|
||||
console.log(config.editor.offline);
|
||||
|
||||
if (config.editor.github) {
|
||||
this.setup_github(socket);
|
||||
}
|
||||
|
||||
if (config.editor.offline || config.editor.github) {
|
||||
this.offline_health_check(socket);
|
||||
return;
|
||||
}
|
||||
|
||||
var project_repository = 'git@bitbucket.org:' + profile.username + '/my-pi-projects.git';
|
||||
console.log(project_repository);
|
||||
|
||||
client.hgetall('editor:settings', function(err, settings) {
|
||||
if (typeof settings === 'undefined' || !settings) {
|
||||
settings = {};
|
||||
}
|
||||
|
||||
console.log("getting settings", settings);
|
||||
socket.emit("self-check-settings", settings);
|
||||
});
|
||||
|
||||
//check if the adafruit libraries exist, if not, clone them.
|
||||
request_helper.post_ssh_key(profile, function(err, response) {
|
||||
that.setup_adafruit_libraries(socket);
|
||||
|
||||
git_helper.set_config(function() {
|
||||
var my_repository = "my-pi-projects";
|
||||
fs_helper.check_for_repository(my_repository, function(err, exists) {
|
||||
ws_helper.send_message(ws, "self-check-message", "Validated my-pi-projects");
|
||||
winston.debug(exists);
|
||||
if (exists) {
|
||||
git_helper.pull(my_repository, "origin", "master", function(err, status) {
|
||||
ws_helper.send_message(ws, "self-check-message", "Updated my-pi-projects");
|
||||
ws_helper.send_message(ws, 'self-check-complete');
|
||||
});
|
||||
} else {
|
||||
git_helper.create_local_repository(my_repository, function(err, response) {
|
||||
ws_helper.send_message(ws, "self-check-message", "Cloned my-pi-projects on local system");
|
||||
fs_helper.create_project_gitignore(function(err, file) {
|
||||
ws_helper.send_message(ws, "self-check-message", "Added .gitignore in my-pi-projects");
|
||||
fs_helper.create_project_readme(function(err, file) {
|
||||
ws_helper.send_message(ws, "self-check-message", "Added README.md in my-pi-projects");
|
||||
winston.debug(file);
|
||||
if (err) winston.error(err);
|
||||
request_helper.list_repositories(profile, function(err, list) {
|
||||
var exists = list.some(function(repository) {
|
||||
return (repository.name.toLowerCase() === config.defaults.repository.toLowerCase());
|
||||
});
|
||||
|
||||
git_helper.commit_push_and_save(file, "Added README.md and .gitignore", function(err, response) {
|
||||
ws_helper.send_message(ws, "self-check-message", "Pushed changes to my-pi-projects");
|
||||
ws_helper.send_message(ws, 'self-check-complete');
|
||||
if (!exists) {
|
||||
request_helper.create_repository(profile, config.defaults.repository, function(err, response) {
|
||||
socket.emit("self-check-message", "Created my-pi-projects in Bitbucket");
|
||||
|
||||
git_helper.clone_repository(project_repository, function(err, response) {
|
||||
socket.emit("self-check-message", "Cloned my-pi-projects on local system");
|
||||
fs_helper.create_project_gitignore(function(err, file) {
|
||||
socket.emit("self-check-message", "Added .gitignore in my-pi-projects");
|
||||
fs_helper.create_project_readme(function(err, file) {
|
||||
socket.emit("self-check-message", "Added README.md in my-pi-projects");
|
||||
if (err) console.log(err);
|
||||
console.log(file);
|
||||
|
||||
git_helper.commit_push_and_save(file, "Added README.md and .gitignore", null, function(err, response) {
|
||||
socket.emit("self-check-message", "Pushed changes to my-pi-projects to Bitbucket");
|
||||
socket.emit('self-check-complete');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
//check if repository exists here
|
||||
var my_repository = "my-pi-projects";
|
||||
fs_helper.check_for_repository(my_repository, function(err, exists) {
|
||||
socket.emit("self-check-message", "Validated my-pi-projects");
|
||||
if (exists) {
|
||||
git_helper.pull(my_repository, "origin", "master", function(err, status) {
|
||||
socket.emit("self-check-message", "Updated my-pi-projects");
|
||||
socket.emit('self-check-complete');
|
||||
});
|
||||
} else {
|
||||
git_helper.clone_repository(project_repository, function(err, response) {
|
||||
socket.emit("self-check-message", "Cloned my-pi-projects on local system");
|
||||
fs_helper.create_project_gitignore(function(err, file) {
|
||||
socket.emit("self-check-message", "Added .gitignore in my-pi-projects");
|
||||
fs_helper.create_project_readme(function(err, file) {
|
||||
socket.emit("self-check-message", "Added README.md in my-pi-projects");
|
||||
console.log(file);
|
||||
if (err) console.log(err);
|
||||
|
||||
git_helper.commit_push_and_save(file, "Added README.md and .gitignore", null, function(err, response) {
|
||||
socket.emit("self-check-message", "Pushed changes to my-pi-projects to Bitbucket");
|
||||
socket.emit('self-check-complete');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
winston.debug("after everything");
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
}); // end of list repositories
|
||||
}); //end of git set config
|
||||
}); //end of post ssh key
|
||||
|
||||
};
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
var spawn = require('child_process').spawn,
|
||||
ws_helper = require('./websocket_helper'),
|
||||
//pty = require('pty.js'),
|
||||
path = require('path'),
|
||||
ipython, spawn_list = [];
|
||||
|
|
@ -9,7 +8,7 @@ var spawn = require('child_process').spawn,
|
|||
};*/
|
||||
|
||||
exports.execute_program = function(file, is_job) {
|
||||
|
||||
|
||||
console.log(file);
|
||||
if (file.extension === 'py') {
|
||||
execute_program(file, "python", is_job);
|
||||
|
|
@ -32,7 +31,7 @@ exports.stop_program = function(file, is_job) {
|
|||
|
||||
exports.trace_program = function(file, socket) {
|
||||
var file_path = path.resolve(__dirname + "/../repositories/" + file.path.replace('/filesystem/', ''));
|
||||
console.log(file_path);
|
||||
console.log(file_path);
|
||||
if (file.extension === 'py') {
|
||||
execute_python_trace(file_path, socket);
|
||||
} else if (file.extension === 'rb') {
|
||||
|
|
@ -55,12 +54,12 @@ function execute_python_trace(file_path, socket) {
|
|||
});
|
||||
|
||||
prog.stderr.on('data', function(data) {
|
||||
ws_helper.send_message(socket, 'trace-program-stderr', {output: data.toString()});
|
||||
socket.emit('trace-program-stderr', {output: data.toString()});
|
||||
console.log(data.toString());
|
||||
});
|
||||
|
||||
prog.on('exit', function(code) {
|
||||
ws_helper.send_message(socket, 'trace-program-exit', {output: program_output});
|
||||
socket.emit('trace-program-exit', {output: program_output});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -69,16 +68,16 @@ function execute_python_trace(file_path, socket) {
|
|||
ipython.removeAllListeners('data');
|
||||
require('../server').get_socket(file.username, function(socket) {
|
||||
if (is_job) {
|
||||
ws_helper.send_message(socket, 'scheduler-start', {file: file});
|
||||
socket.emit('scheduler-start', {file: file});
|
||||
}
|
||||
ipython.on('data', function(data) {
|
||||
console.log(data);
|
||||
//data = data.replace(/\[0;.*?In\s\[.*?\[0m/, '~-prompt-~');
|
||||
//data = data.replace(/In\s\[.*?\]:/, '~-prompt-~');
|
||||
if (is_job) {
|
||||
ws_helper.send_message(socket, 'scheduler-executing', {file: file});
|
||||
socket.emit('scheduler-executing', {file: file});
|
||||
} else {
|
||||
ws_helper.send_message(socket, 'program-stdout', {output: data});
|
||||
socket.emit('program-stdout', {output: data});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -105,39 +104,41 @@ function execute_program(file, type, is_job) {
|
|||
console.log('execute_program');
|
||||
console.log(file_path);
|
||||
|
||||
console.log(file);
|
||||
var cwd = get_cwd(file_path);
|
||||
var prog = spawn("sudo", [type, file_path], {cwd: cwd});
|
||||
var key = get_key(file);
|
||||
spawn_list.push({key: key, prog: prog});
|
||||
if (socket) {
|
||||
console.log('found socket, executing');
|
||||
handle_output(prog, file, is_job, socket);
|
||||
}
|
||||
require('../server').get_socket(file.username, function(socket) {
|
||||
console.log(file);
|
||||
var cwd = get_cwd(file_path);
|
||||
var prog = spawn("sudo", [type, file_path], {cwd: cwd});
|
||||
var key = get_key(file);
|
||||
spawn_list.push({key: key, prog: prog});
|
||||
if (socket) {
|
||||
console.log('found socket, executing');
|
||||
handle_output(prog, file, is_job, socket);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handle_output(prog, file, is_job, socket) {
|
||||
if (is_job) {
|
||||
ws_helper.send_message(socket, 'scheduler-start', {file: file});
|
||||
socket.emit('scheduler-start', {file: file});
|
||||
}
|
||||
|
||||
prog.stdout.on('data', function(data) {
|
||||
if (is_job) {
|
||||
console.log(data.toString());
|
||||
ws_helper.send_message(socket, 'scheduler-executing', {file: file});
|
||||
socket.emit('scheduler-executing', {file: file});
|
||||
} else {
|
||||
console.log(data.toString());
|
||||
ws_helper.send_message(socket, 'program-stdout', {output: data.toString()});
|
||||
socket.emit('program-stdout', {output: data.toString()});
|
||||
}
|
||||
});
|
||||
|
||||
prog.stderr.on('data', function(data) {
|
||||
if (is_job) {
|
||||
console.log(data.toString());
|
||||
ws_helper.send_message(socket, 'scheduler-error', {file: file, error: data});
|
||||
socket.emit('scheduler-error', {file: file, error: data});
|
||||
} else {
|
||||
console.log(data.toString());
|
||||
ws_helper.send_message(socket, 'program-stderr', {output: data.toString()});
|
||||
socket.emit('program-stderr', {output: data.toString()});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -150,10 +151,10 @@ function handle_output(prog, file, is_job, socket) {
|
|||
}
|
||||
|
||||
if (is_job) {
|
||||
ws_helper.send_message(socket, 'scheduler-exit', {code: code, file: file});
|
||||
socket.emit('scheduler-exit', {code: code, file: file});
|
||||
} else {
|
||||
ws_helper.send_message(socket, 'program-exit', {code: code});
|
||||
socket.emit('program-exit', {code: code});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
config = require('../config/config'),
|
||||
winston = require('winston'),
|
||||
util = require('util'),
|
||||
config = require('../config/config');
|
||||
exec = require('child_process').exec;
|
||||
|
||||
fs.exists || (fs.exists = path.exists);
|
||||
|
||||
/*
|
||||
* Checks to see if an ssh key exists already.
|
||||
* Checks to see if a bitbucket ssh key exists already.
|
||||
*/
|
||||
exports.has_ssh_key = function has_ssh_key(key_name, cb) {
|
||||
fs.exists(path.resolve(process.env['HOME'], '/.ssh/', key_name), function(exists) {
|
||||
exports.has_ssh_key = function has_ssh_key(cb) {
|
||||
fs.exists(process.env['HOME'] + '/.ssh/id_rsa_bitbucket.pub', function(exists) {
|
||||
if (exists) {
|
||||
cb(true);
|
||||
} else {
|
||||
|
|
@ -18,15 +20,15 @@ exports.has_ssh_key = function has_ssh_key(key_name, cb) {
|
|||
};
|
||||
|
||||
/*
|
||||
* Generates an ssh key
|
||||
* Generates an ssh key for Bitbucket
|
||||
*/
|
||||
exports.generate_ssh_key = function(key_name, cb) {
|
||||
exports.generate_ssh_key = function(cb) {
|
||||
var self = this;
|
||||
self.has_ssh_key(key_name, function(exists) {
|
||||
self.has_ssh_key(function(exists) {
|
||||
if (exists) {
|
||||
cb();
|
||||
} else {
|
||||
exec("ssh-keygen -b 2048 -N '' -f ~/.ssh/" + key_name + "-t rsa -q", function(err, stdout, stderr) {
|
||||
exec("ssh-keygen -b 2048 -N '' -f ~/.ssh/id_rsa_bitbucket -t rsa -q", function(err, stdout, stderr) {
|
||||
//console.log(err, stdout, stderr);
|
||||
self.append_to_ssh_config(function() {
|
||||
cb();
|
||||
|
|
@ -36,17 +38,46 @@ exports.generate_ssh_key = function(key_name, cb) {
|
|||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Append bitbucket.org to the ssh config file to disable StrictHostKeyChecking.
|
||||
* This isn't great, but we need a way for beginners to get past the known_host checks.
|
||||
*/
|
||||
exports.append_to_ssh_config = function append_to_ssh_config(cb) {
|
||||
var ssh_config_file = process.env['HOME'] + '/.ssh/config';
|
||||
var identity_info = "Host bitbucket.org \r\n\tHostName bitbucket.org\r\n\tStrictHostKeyChecking no\r\n\tPreferredAuthentications publickey\r\n\tIdentityFile ~/.ssh/id_rsa_bitbucket";
|
||||
|
||||
exports.read_or_generate_key = function(key_name, cb) {
|
||||
fs.exists(ssh_config_file, function(exists) {
|
||||
if (exists) {
|
||||
//file exists, let's check if it has the bitbucket host in it, otherwise add it
|
||||
fs.readFile(ssh_config_file, 'ascii', function(err, data) {
|
||||
if (data.indexOf('bitbucket.org') !== -1) {
|
||||
cb();
|
||||
} else {
|
||||
var file = fs.createWriteStream(ssh_config_file, {'flags': 'a'});
|
||||
file.write(identity_info, function() {
|
||||
cb();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fs.writeFile(ssh_config_file, identity_info, function(err) {
|
||||
if(err) console.log(err);
|
||||
cb();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.read_or_generate_key = function(cb) {
|
||||
var self = this;
|
||||
self.has_ssh_key(key_name, function(has_key) {
|
||||
self.has_ssh_key(function(has_key) {
|
||||
if (has_key) {
|
||||
fs.readFile(process.env['HOME'] + '/.ssh/' + key_name, 'ascii', function(err,data){
|
||||
fs.readFile(process.env['HOME'] + '/.ssh/id_rsa_bitbucket.pub', 'ascii', function(err,data){
|
||||
cb(data);
|
||||
});
|
||||
} else {
|
||||
self.generate_ssh_key(key_name, function() {
|
||||
fs.readFile(process.env['HOME'] + '/.ssh/' + key_name, 'ascii', function(err,data){
|
||||
self.generate_ssh_key(function() {
|
||||
fs.readFile(process.env['HOME'] + '/.ssh/id_rsa_bitbucket.pub', 'ascii', function(err,data){
|
||||
cb(data);
|
||||
});
|
||||
});
|
||||
|
|
@ -80,11 +111,9 @@ exports.move_uploaded_file = function(temp_path, new_path, cb) {
|
|||
var is = fs.createReadStream(temp_path);
|
||||
var os = fs.createWriteStream(new_path);
|
||||
|
||||
is.pipe(os);
|
||||
|
||||
is.on("close", function() {
|
||||
fs.unlinkSync(temp_path);
|
||||
cb();
|
||||
util.pump(is, os, function() {
|
||||
fs.unlinkSync(temp_path);
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -116,11 +145,9 @@ exports.create_project_readme = function(cb) {
|
|||
|
||||
var is = fs.createReadStream(source);
|
||||
var os = fs.createWriteStream(destination);
|
||||
|
||||
is.pipe(os);
|
||||
|
||||
is.on("close", function() {
|
||||
cb(null, file);
|
||||
util.pump(is, os, function(err) {
|
||||
console.log(err);
|
||||
cb(err, file);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -139,11 +166,9 @@ exports.create_project_gitignore = function(cb) {
|
|||
|
||||
var is = fs.createReadStream(source);
|
||||
var os = fs.createWriteStream(destination);
|
||||
is.pipe(os);
|
||||
|
||||
is.on("close", function() {
|
||||
winston.debug("IN OS END");
|
||||
cb(null, file);
|
||||
util.pump(is, os, function(err) {
|
||||
console.log(err);
|
||||
cb(err, file);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,50 +1,31 @@
|
|||
var path = require('path'),
|
||||
db = require('../models/webideModel'),
|
||||
git = require('gitty'),
|
||||
Command = require('../node_modules/gitty/lib/command'),
|
||||
var git = require('gitty'),
|
||||
url = require('url'),
|
||||
path = require('path'),
|
||||
winston = require('winston'),
|
||||
fs = require('fs'),
|
||||
fs_helper = require('./fs_helper'),
|
||||
ws_helper = require('./websocket_helper'),
|
||||
redis = require("redis"),
|
||||
client = redis.createClient(),
|
||||
request_helper = require('./request_helper'),
|
||||
config = require('../config/config');
|
||||
|
||||
var REPOSITORY_PATH = path.resolve(__dirname + "/../repositories") + "/";
|
||||
var push_queue = [], pushInterval, PUSH_TIMER = 30000;
|
||||
|
||||
/* extend gitty */
|
||||
git.prototype.remove_recursive = function(path, callback) {
|
||||
var self = this;
|
||||
var cmd = new Command(self, 'rm', ['-r', '--cached'], path);
|
||||
|
||||
cmd.exec(function(error, stdout, stderr) {
|
||||
callback(error || stderr || null);
|
||||
});
|
||||
};
|
||||
|
||||
git.prototype.move = function(source, destination, callback) {
|
||||
var self = this;
|
||||
var cmd = new Command(self, 'mv', [], source, destination);
|
||||
|
||||
cmd.exec(function(error, stdout, stderr) {
|
||||
callback(error || stderr || null);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Creates a simple queue that is used for pushing git changes to the remote repositories.
|
||||
* The queue is currently set using the PUSH_TIMER to delay the remote pushes.
|
||||
*/
|
||||
function push_queue_interval() {
|
||||
winston.debug('git push queue init');
|
||||
console.log('git push queue init');
|
||||
function push(repository_path, remote, branch, username) {
|
||||
var repo = git(repository_path);
|
||||
repo.push(remote, branch, function(err) {
|
||||
if (err) {
|
||||
winston.error(err);
|
||||
ws_helper.send_message(null, 'git-push-error', {err: "Error: Failure pushing code to remote repository"});
|
||||
}
|
||||
//winston.debug(obj);
|
||||
git.push(repository_path, remote, branch, function(obj) {
|
||||
require('../server').get_socket(username, function(socket) {
|
||||
if (obj.error) {
|
||||
winston.error(obj);
|
||||
socket.emit('git-push-error', {err: "Error: Failure pushing code to remote repository"});
|
||||
}
|
||||
//console.log(obj);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +35,7 @@ function push_queue_interval() {
|
|||
}
|
||||
|
||||
while(push_queue.length > 0) {
|
||||
winston.debug('pushing code to remote repository');
|
||||
console.log('pushing code to remote repository');
|
||||
var element = push_queue.shift();
|
||||
push(element.repository_path, element.remote, element.branch, element.username);
|
||||
}
|
||||
|
|
@ -69,8 +50,8 @@ push_queue_interval();
|
|||
exports.clone_adafruit_libraries = function(adafruit_repository, remote, cb) {
|
||||
fs_helper.check_for_repository(adafruit_repository, function(err, status) {
|
||||
if (!err && !status) {
|
||||
git.clone(REPOSITORY_PATH, remote, function(err) {
|
||||
winston.debug(err);
|
||||
git.clone(REPOSITORY_PATH, remote, function(output) {
|
||||
console.log(output);
|
||||
cb(true);
|
||||
});
|
||||
} else {
|
||||
|
|
@ -79,46 +60,75 @@ exports.clone_adafruit_libraries = function(adafruit_repository, remote, cb) {
|
|||
});
|
||||
};
|
||||
|
||||
exports.clone_update_remote_push = function(repository_url, cb) {
|
||||
/*
|
||||
* This does a few things in order to clone a repository, and save it to your Bitbucket profile.
|
||||
* This allows you to clone from any remote repository, including Github (it's overly complicated...).
|
||||
* 1. It first checks if the repository already exists in your bitbucket profile.
|
||||
* 2. If not 1, it creates the repository in Bitbucket using the API.
|
||||
* 3. It then clones the remote repository you're interested in.
|
||||
* 4. It then updates the git remote for that repository to your bitbucket repository.
|
||||
* 5. Finally, it pushes the cloned repository to your remote account.
|
||||
*/
|
||||
exports.clone_update_remote_push = function(profile, repository_url, retain_remote, cb) {
|
||||
var self = this;
|
||||
|
||||
var repository_name = path.basename(repository_url, '.git');
|
||||
|
||||
self.clone_repository(repository_url, function(err, results) {
|
||||
winston.debug("clone repository locally: " + repository_name);
|
||||
cb(err, true);
|
||||
});
|
||||
if (config.editor.offline || config.editor.github || (retain_remote === 'on')) {
|
||||
self.clone_repository(repository_url, function(err, results) {
|
||||
console.log("clone repository locally: " + repository_name);
|
||||
cb(err, true);
|
||||
});
|
||||
} else {
|
||||
request_helper.list_repositories(profile, function(err, list) {
|
||||
var exists = list.some(function(repository) {
|
||||
return (repository.name === repository_name);
|
||||
});
|
||||
if (!exists) {
|
||||
//TODO need better error handling eventually
|
||||
request_helper.create_repository(profile, repository_name, function(err, response) {
|
||||
console.log("created repository in bitbucket: " + repository_name);
|
||||
self.clone_repository(repository_url, function(err, results) {
|
||||
console.log("clone repository locally: " + repository_name);
|
||||
self.update_remote(profile, repository_name, function(err, response) {
|
||||
console.log("updated remote for repository: " + repository_name);
|
||||
self.push(repository_name, "origin", "master", profile, function(err, response) {
|
||||
console.log("git push for repository: " + repository_name);
|
||||
cb(err, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
if (repository_url.toLowerCase().indexOf("bitbucket.org") === -1) {
|
||||
cb("Repository Already Exists in Bitbucket, clone with Bitbucket URL.", false);
|
||||
} else {
|
||||
self.clone_repository(repository_url, function(err, results) {
|
||||
console.log("clone repository locally: " + repository_name);
|
||||
cb(err, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.clone_repository = function(repository_path, cb) {
|
||||
winston.debug("clone_repository", repository_path);
|
||||
console.log(repository_path);
|
||||
var repository_url = url.parse(repository_path);
|
||||
|
||||
winston.debug("cloning", repository_path);
|
||||
|
||||
git.clone(REPOSITORY_PATH, repository_url.href, function(err, output) {
|
||||
cb(err, output);
|
||||
});
|
||||
};
|
||||
|
||||
exports.create_local_repository = function(name, cb) {
|
||||
winston.debug("create_repository", name);
|
||||
//create directory
|
||||
var repository_path = REPOSITORY_PATH + name;
|
||||
if (!fs.existsSync(repository_path)){
|
||||
fs.mkdirSync(repository_path);
|
||||
}
|
||||
|
||||
var repo = git(repository_path);
|
||||
repo.init(function(err, output) {
|
||||
cb(err, output);
|
||||
console.log("cloning", repository_path);
|
||||
git.clone(REPOSITORY_PATH, repository_url.href, function(output) {
|
||||
cb(output.error, output.message);
|
||||
});
|
||||
};
|
||||
|
||||
exports.validate_config = function validate_config(cb) {
|
||||
git.getConfig("user.email", function(err, email) {
|
||||
git.getConfig("user.name", function(err, name) {
|
||||
git.config("user.email", null, function(err, email) {
|
||||
git.config("user.name", null, function(err, name) {
|
||||
if (err) winston.error("git_helper.validate_config err", err);
|
||||
|
||||
if (name && email) {
|
||||
cb(true);
|
||||
} else {
|
||||
|
|
@ -132,15 +142,15 @@ exports.set_config = function(cb) {
|
|||
var self = this;
|
||||
self.validate_config(function(is_valid) {
|
||||
if (is_valid) {
|
||||
winston.debug('git config is valid');
|
||||
console.log('git config is valid');
|
||||
cb();
|
||||
} else {
|
||||
winston.error('git config is invalid');
|
||||
db.findOne({type: "user"}, function (err, user) {
|
||||
winston.debug("set_config user", user);
|
||||
git.setConfig("user.email", user.email, function(err, email) {
|
||||
git.setConfig("user.name", user.name, function(err, name) {
|
||||
winston.debug("git config set", email, name);
|
||||
client.hgetall('user', function (err, user) {
|
||||
console.log("set_config user", user);
|
||||
git.config("user.email", user.email, function(err, email) {
|
||||
git.config("user.name", user.name, function(err, name) {
|
||||
console.log("git config set", email, name);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
|
@ -150,14 +160,24 @@ exports.set_config = function(cb) {
|
|||
|
||||
};
|
||||
|
||||
/*
|
||||
* Updates the remote repository to the users bitbucket repository.
|
||||
*/
|
||||
exports.update_remote = function(profile, repository, cb) {
|
||||
var remote_url = "ssh://git@bitbucket.org/" + profile.username + "/" + repository.toLowerCase() + ".git";
|
||||
git.remote.update(REPOSITORY_PATH + repository, "origin", remote_url, function(output) {
|
||||
//console.log(output);
|
||||
cb(output.error, output.message);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Adds an additional remote to a repository.
|
||||
*/
|
||||
exports.add_remote = function(repository, remote_name, remote_url, cb) {
|
||||
var repo = git(REPOSITORY_PATH + repository);
|
||||
repo.addRemote(remote_name, remote_url, function(err, message) {
|
||||
winston.debug(err);
|
||||
cb(err, message);
|
||||
git.remote.add(REPOSITORY_PATH + repository, remote_name, remote_url, function(output) {
|
||||
//console.log(output);
|
||||
cb(output.error, output.message);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -171,10 +191,10 @@ exports.add = function add(repository, files, cb) {
|
|||
files = [files];
|
||||
}
|
||||
var repository_path = REPOSITORY_PATH + repository;
|
||||
var repo = git(repository_path);
|
||||
repo.add(files, function(err, added) {
|
||||
winston.debug(err);
|
||||
cb(err, added);
|
||||
git.add(repository_path, files, function(output) {
|
||||
//console.log(output.errors);
|
||||
//console.log(output);
|
||||
cb(output.errors, output.added);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -188,10 +208,9 @@ exports.remove = function remove(repository, files, cb) {
|
|||
files = [files];
|
||||
}
|
||||
var repository_path = REPOSITORY_PATH + repository;
|
||||
var repo = git(repository_path);
|
||||
repo.remove(files, function(err, added) {
|
||||
winston.debug(err);
|
||||
cb(err, added);
|
||||
git.remove(repository_path, files, function(output) {
|
||||
//console.log(output.errors);
|
||||
cb(output.errors, output.added);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -203,10 +222,9 @@ exports.remove = function remove(repository, files, cb) {
|
|||
exports.remove_recursive = function remove_recursive(repository, path, cb) {
|
||||
var repository_path = REPOSITORY_PATH + repository;
|
||||
|
||||
var repo = git(repository_path);
|
||||
repo.remove_recursive(path, function(err, data) {
|
||||
winston.debug(err);
|
||||
cb(err, data);
|
||||
git.remove_recursive(repository_path, path, function(output) {
|
||||
console.log(output);
|
||||
cb(output.errors, output.added);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -216,10 +234,9 @@ exports.remove_recursive = function remove_recursive(repository, path, cb) {
|
|||
*/
|
||||
exports.move = function move(repository, source, destination, cb) {
|
||||
var repository_path = REPOSITORY_PATH + repository;
|
||||
var repo = git(repository_path);
|
||||
repo.move(source, destination, function(err, message) {
|
||||
//winston.debug(obj);
|
||||
cb(err, message);
|
||||
git.move(repository_path, source, destination, function(obj) {
|
||||
//console.log(obj);
|
||||
cb(obj.error, obj.message);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -230,11 +247,10 @@ exports.move = function move(repository, source, destination, cb) {
|
|||
*/
|
||||
exports.commit = function commit(repository, message, cb) {
|
||||
var repository_path = REPOSITORY_PATH + repository;
|
||||
winston.debug(repository_path);
|
||||
var repo = git(repository_path);
|
||||
repo.commit(message, function(err, message) {
|
||||
//winston.debug(obj);
|
||||
cb(err, message);
|
||||
console.log(repository_path);
|
||||
git.commit(repository_path, message, function(obj) {
|
||||
//console.log(obj);
|
||||
cb(obj.error, obj.message);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -249,10 +265,9 @@ exports.is_modified = function (file, cb) {
|
|||
var item_path = path_array.slice(3).join('/');
|
||||
|
||||
var is_modified = false;
|
||||
var repo = git(repository_path);
|
||||
repo.status(function(err, output) {
|
||||
git.status(repository_path, function(output) {
|
||||
|
||||
winston.debug(err, output);
|
||||
console.log(output);
|
||||
|
||||
if (output.not_staged.length > 0) {
|
||||
output.not_staged.forEach(function(item, index) {
|
||||
|
|
@ -266,7 +281,7 @@ exports.is_modified = function (file, cb) {
|
|||
is_modified = true;
|
||||
}
|
||||
|
||||
cb(err, is_modified);
|
||||
cb(output.errors, is_modified);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -280,19 +295,18 @@ exports.is_untracked = function (file, cb) {
|
|||
var repository_path = path.resolve(REPOSITORY_PATH, repository);
|
||||
var item_path = path_array.slice(3).join('/');
|
||||
|
||||
winston.debug(item_path);
|
||||
console.log(item_path);
|
||||
|
||||
var is_untracked = false;
|
||||
var repo = git(repository_path);
|
||||
repo.status(function(err, output) {
|
||||
git.status(repository_path, function(output) {
|
||||
|
||||
winston.debug(err, output);
|
||||
console.log(output);
|
||||
|
||||
if (output.untracked.indexOf(item_path) !== -1) {
|
||||
is_untracked = true;
|
||||
}
|
||||
|
||||
cb(err, is_untracked);
|
||||
cb(output.errors, is_untracked);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -300,10 +314,10 @@ exports.is_untracked = function (file, cb) {
|
|||
* git push the committed changes. Adds it to the push queue.
|
||||
* repository: the name of the repository that resides in the repositories folder.
|
||||
*/
|
||||
exports.push = function push(repository, remote, branch, cb) {
|
||||
exports.push = function push(repository, remote, branch, profile, cb) {
|
||||
var repository_path = REPOSITORY_PATH + repository;
|
||||
var key = repository + remote + branch;
|
||||
winston.debug('called push ' + key);
|
||||
console.log('called push ' + key);
|
||||
|
||||
//if the repository, remote and branch are already on the queue, just skip it...otherwise add it to the end
|
||||
if (push_queue.length > 0) {
|
||||
|
|
@ -311,13 +325,14 @@ exports.push = function push(repository, remote, branch, cb) {
|
|||
if (push_queue[i].key === key) {
|
||||
break;
|
||||
} else {
|
||||
winston.debug('added to queue ' + key);
|
||||
console.log('added to queue ' + key);
|
||||
push_queue.push({
|
||||
key: key,
|
||||
repository_path: repository_path,
|
||||
repository: repository,
|
||||
remote: remote,
|
||||
branch: branch
|
||||
branch: branch,
|
||||
username: profile ? profile.username : ''
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -327,7 +342,8 @@ exports.push = function push(repository, remote, branch, cb) {
|
|||
repository_path: repository_path,
|
||||
repository: repository,
|
||||
remote: remote,
|
||||
branch: branch
|
||||
branch: branch,
|
||||
username: profile ? profile.username : ''
|
||||
});
|
||||
}
|
||||
cb();
|
||||
|
|
@ -339,29 +355,29 @@ exports.push = function push(repository, remote, branch, cb) {
|
|||
*/
|
||||
exports.pull = function pull(repository, remote, branch, cb) {
|
||||
var repository_path = REPOSITORY_PATH + repository;
|
||||
var repo = git(repository_path);
|
||||
repo.pull(remote, branch, function(err, message) {
|
||||
if (err) {
|
||||
winston.error(err);
|
||||
cb("Error: Failure updating from remote repository", message);
|
||||
git.pull(repository_path, remote, branch, function(obj) {
|
||||
//console.log(obj);
|
||||
if (obj.error) {
|
||||
winston.error(obj.error);
|
||||
cb("Error: Failure updating from remote repository", obj.message);
|
||||
} else {
|
||||
cb(null, message);
|
||||
cb(null, obj.message);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Simply removes a file or directory, commits it, and pushes it out.
|
||||
*/
|
||||
exports.remove_commit_push = function(item, cb) {
|
||||
exports.remove_commit_push = function(item, profile, cb) {
|
||||
var self = this;
|
||||
winston.debug(item);
|
||||
console.log(item);
|
||||
var path_array = item.path.split('/');
|
||||
var repository = path_array[2];
|
||||
var item_path = path_array.slice(3).join('/');
|
||||
winston.debug(item_path);
|
||||
winston.debug(repository);
|
||||
console.log(item_path);
|
||||
console.log(repository);
|
||||
|
||||
|
||||
if (item.type === 'directory') {
|
||||
|
|
@ -376,7 +392,7 @@ exports.remove_commit_push = function(item, cb) {
|
|||
cb("Error: Failure comitting removed folder", status);
|
||||
return;
|
||||
}
|
||||
self.push(repository, "origin", "master", function() {
|
||||
self.push(repository, "origin", "master", profile, function() {
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
|
@ -393,7 +409,7 @@ exports.remove_commit_push = function(item, cb) {
|
|||
cb("Error: Failure comitting removed file", status);
|
||||
return;
|
||||
}
|
||||
self.push(repository, "origin", "master", function() {
|
||||
self.push(repository, "origin", "master", profile, function() {
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
|
@ -404,7 +420,7 @@ exports.remove_commit_push = function(item, cb) {
|
|||
/*
|
||||
* Simply moves a file or directory, commits it, and pushes it out.
|
||||
*/
|
||||
exports.move_commit_push = function(item, cb) {
|
||||
exports.move_commit_push = function(item, profile, cb) {
|
||||
var self = this;
|
||||
var path_array = item.path.split('/');
|
||||
var repository = path_array[2];
|
||||
|
|
@ -423,18 +439,18 @@ exports.move_commit_push = function(item, cb) {
|
|||
self.move(repository, item_path, destination_path, function(err, status) {
|
||||
var commit_message = "Moved " + item.name;
|
||||
if (err) {
|
||||
winston.debug ("has error returning");
|
||||
console.log ("has error returning");
|
||||
cb("Error: Failure moving file (renaming)");
|
||||
return;
|
||||
}
|
||||
self.commit(repository, commit_message, function(err, status) {
|
||||
winston.debug("Committed Moved File");
|
||||
console.log("Committed Moved File");
|
||||
if (err) {
|
||||
cb("Error: Failure comitting file into git");
|
||||
return;
|
||||
}
|
||||
self.push(repository, "origin", "master", function() {
|
||||
winston.debug("Pushed latest changes");
|
||||
self.push(repository, "origin", "master", profile, function() {
|
||||
console.log("Pushed latest changes");
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
|
@ -447,7 +463,7 @@ exports.move_commit_push = function(item, cb) {
|
|||
/*
|
||||
* Simply commits a file or directory, commits it, and pushes it out.
|
||||
*/
|
||||
exports.commit_push_and_save = function(file, commit_message, cb) {
|
||||
exports.commit_push_and_save = function(file, commit_message, profile, cb) {
|
||||
var self = this,
|
||||
path_array, repository, file_path;
|
||||
if (!file.repository) {
|
||||
|
|
@ -459,26 +475,26 @@ exports.commit_push_and_save = function(file, commit_message, cb) {
|
|||
file_path = file.path;
|
||||
}
|
||||
|
||||
winston.debug(commit_message);
|
||||
console.log(commit_message);
|
||||
|
||||
|
||||
|
||||
self.add(repository, file_path, function(err, status) {
|
||||
winston.debug("added", err, status);
|
||||
console.log("added", err, status);
|
||||
if (err && err.length > 0) {
|
||||
cb("Error: Failure adding file to git", status);
|
||||
return;
|
||||
}
|
||||
self.commit(repository, commit_message, function(err, status) {
|
||||
winston.debug("committed", err, status);
|
||||
console.log("committed", err, status);
|
||||
if (err && err.length > 0) {
|
||||
cb("Error: Failure comitting file into git", status);
|
||||
return;
|
||||
}
|
||||
self.push(repository, "origin", "master", function() {
|
||||
winston.debug("added to push queue");
|
||||
self.push(repository, "origin", "master", profile, function() {
|
||||
console.log("added to push queue");
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
var spawn = require('child_process').spawn,
|
||||
exec = require('child_process').exec,
|
||||
db = require('../../models/webideModel'),
|
||||
net = require('net'),
|
||||
path = require('path'),
|
||||
ws_helper = require('../websocket_helper'),
|
||||
debug_program, debug_client,
|
||||
client_connected = false,
|
||||
HOST = '127.0.0.1',
|
||||
|
|
@ -30,46 +28,39 @@ exports.start_debug = function start_debug(file, socket) {
|
|||
console.log(!debug_program);
|
||||
if (!debug_program) {
|
||||
console.log('spawn debugger');
|
||||
db.findOne({type: "editor:settings"}, function(err, settings) {
|
||||
var command = 'python';
|
||||
if (typeof settings !== 'undefined' && settings.python_version === '3') {
|
||||
command = 'python3';
|
||||
debug_program = spawn("sudo", ["python", "debugger.py"], {cwd: __dirname});
|
||||
var buffer = "";
|
||||
debug_program.stdout.on('data', function(data) {
|
||||
console.log(data.toString());
|
||||
|
||||
buffer += data.toString();
|
||||
|
||||
if (buffer.indexOf("DEBUGGER READY") !== -1 && !client_connected) {
|
||||
console.log("DEBUGGER READY");
|
||||
connect_client(file, socket);
|
||||
console.log("after connect_client");
|
||||
}
|
||||
|
||||
debug_program = spawn("sudo", [command, "debugger.py"], {cwd: __dirname});
|
||||
var buffer = "";
|
||||
debug_program.stdout.on('data', function(data) {
|
||||
console.log(data.toString());
|
||||
});
|
||||
|
||||
buffer += data.toString();
|
||||
debug_program.stderr.on('data', function(data) {
|
||||
console.log(data.toString());
|
||||
socket.emit('debug-error', {file: file, error: data});
|
||||
});
|
||||
|
||||
if (buffer.indexOf("DEBUGGER READY") !== -1 && !client_connected) {
|
||||
console.log("DEBUGGER READY");
|
||||
connect_client(file, socket);
|
||||
console.log("after connect_client");
|
||||
}
|
||||
debug_program.on('error', function(data) {
|
||||
console.log("DEBUG PROGRAM ERROR:");
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
});
|
||||
debug_program.on('exit', function(code) {
|
||||
console.log('Debug Program Exit');
|
||||
console.log(code);
|
||||
debug_program = null;
|
||||
|
||||
debug_program.stderr.on('data', function(data) {
|
||||
console.log(data.toString());
|
||||
ws_helper.send_message(socket, 'debug-error', {file: file, error: data});
|
||||
});
|
||||
|
||||
debug_program.on('error', function(data) {
|
||||
console.log("DEBUG PROGRAM ERROR:");
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
debug_program.on('exit', function(code) {
|
||||
console.log('Debug Program Exit');
|
||||
console.log(code);
|
||||
debug_program = null;
|
||||
|
||||
if (enable_debug) {
|
||||
self.start_debug(file, socket);
|
||||
}
|
||||
});
|
||||
if (enable_debug) {
|
||||
self.start_debug(file, socket);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//console.log('resetting debugger');
|
||||
|
|
@ -91,7 +82,6 @@ function connect_client(file, socket) {
|
|||
debug_client = new net.Socket();
|
||||
debug_client.connect(PORT, HOST, function() {
|
||||
socket.emit('debug-client-connected');
|
||||
ws_helper.send_message(socket, 'debug-client-connected', "");
|
||||
client_connected = true;
|
||||
console.log('connected to python debugger: ' + HOST + ':' + PORT);
|
||||
console.log(file_path);
|
||||
|
|
@ -105,7 +95,7 @@ function connect_client(file, socket) {
|
|||
var temp_buff = buffer.split('\n');
|
||||
for (var i=0; i<temp_buff.length-1; i++) {
|
||||
console.log(JSON.parse(temp_buff[i]));
|
||||
ws_helper.send_message(socket, 'debug-file-response', JSON.parse(temp_buff[i]));
|
||||
socket.emit('debug-file-response', JSON.parse(temp_buff[i]));
|
||||
}
|
||||
|
||||
buffer = temp_buff.slice(temp_buff.length);
|
||||
|
|
|
|||
110
helpers/request_helper.js
Normal file
110
helpers/request_helper.js
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
var request = require('request'),
|
||||
qs = require('querystring'),
|
||||
fs_helper = require('./fs_helper');
|
||||
|
||||
/*
|
||||
* Call the Bitbucket OAuth API to post the ssh key to the users profile.
|
||||
*/
|
||||
exports.post_ssh_key = function(profile, cb) {
|
||||
var url = "https://api.bitbucket.org/1.0/ssh-keys/";
|
||||
var oauth = { consumer_key: profile.consumer_key,
|
||||
consumer_secret: profile.consumer_secret,
|
||||
token: profile.token,
|
||||
token_secret: profile.token_secret };
|
||||
|
||||
fs_helper.read_or_generate_key(function(data) {
|
||||
var params = { key: data.trim(), label: 'raspeditor'};
|
||||
|
||||
request.post({
|
||||
url:url,
|
||||
body: qs.stringify(params),
|
||||
oauth:oauth
|
||||
}, function (e, r, body) {
|
||||
console.log(e);
|
||||
console.log(r.statusCode);
|
||||
console.log(body);
|
||||
cb (e, body);
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Call the Bitbucket OAuth API to createa a repository on the users profile.
|
||||
*/
|
||||
exports.set_repository_private = function set_repository_private(profile, repository_name) {
|
||||
var username = profile.username;
|
||||
//console.log('set_repository_private');
|
||||
//console.log(profile);
|
||||
var url = "https://api.bitbucket.org/1.0/repositories/" + username + "/" + repository_name;
|
||||
var oauth = { consumer_key: profile.consumer_key,
|
||||
consumer_secret: profile.consumer_secret,
|
||||
token: profile.token,
|
||||
token_secret: profile.token_secret };
|
||||
|
||||
|
||||
var params = {is_private: true};
|
||||
|
||||
request.put({
|
||||
url:url,
|
||||
body: qs.stringify(params),
|
||||
oauth:oauth
|
||||
}, function (e, r, body) {
|
||||
//console.log(e);
|
||||
console.log(r.statusCode);
|
||||
if (r.statusCode === 200) {
|
||||
console.log("successfully set repository private");
|
||||
}
|
||||
//console.log(body);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Call the Bitbucket OAuth API to get a list of the repositories on the users profile.
|
||||
*/
|
||||
exports.list_repositories = function(profile, cb) {
|
||||
var self = this;
|
||||
var url = "https://api.bitbucket.org/1.0/user/repositories/";
|
||||
var oauth = { consumer_key: profile.consumer_key,
|
||||
consumer_secret: profile.consumer_secret,
|
||||
token: profile.token,
|
||||
token_secret: profile.token_secret };
|
||||
|
||||
request.get({
|
||||
url:url,
|
||||
oauth:oauth,
|
||||
json: true
|
||||
}, function (e, r, body) {
|
||||
console.log(e);
|
||||
//console.log(r.statusCode);
|
||||
//console.log(body);
|
||||
cb (e, body);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Call the Bitbucket OAuth API to createa a repository on the users profile.
|
||||
*/
|
||||
exports.create_repository = function(profile, repository_name, cb) {
|
||||
var url = "https://api.bitbucket.org/1.0/repositories/";
|
||||
var oauth = { consumer_key: profile.consumer_key,
|
||||
consumer_secret: profile.consumer_secret,
|
||||
token: profile.token,
|
||||
token_secret: profile.token_secret };
|
||||
|
||||
|
||||
var params = { name: repository_name, scm: 'git', is_private: true};
|
||||
|
||||
request.post({
|
||||
url:url,
|
||||
body: qs.stringify(params),
|
||||
oauth:oauth
|
||||
}, function (e, r, body) {
|
||||
console.log(e);
|
||||
console.log(r.statusCode);
|
||||
console.log(body);
|
||||
cb (e, body);
|
||||
});
|
||||
};
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
var path = require('path'),
|
||||
db = require('../models/jobModel'),
|
||||
exec = require('child_process').exec,
|
||||
fs = require ('fs'),
|
||||
winston = require('winston'),
|
||||
exec_helper = require('./exec_helper'),
|
||||
ws_helper = require('./websocket_helper'),
|
||||
later = require('later'),
|
||||
job_queue = [];
|
||||
var exec = require('child_process').exec,
|
||||
fs = require ('fs'),
|
||||
path = require('path'),
|
||||
winston = require('winston'),
|
||||
exec_helper = require('./exec_helper'),
|
||||
redis = require('redis'),
|
||||
client = redis.createClient(),
|
||||
later = require('later').later;
|
||||
enParser = require('later').enParser,
|
||||
job_queue = [];
|
||||
|
||||
fs.exists || (fs.exists = path.exists);
|
||||
|
||||
|
|
@ -19,88 +20,96 @@ function execute_job(file) {
|
|||
console.log("execute_job");
|
||||
console.log(file.key);
|
||||
|
||||
file.last_run = new Date();
|
||||
db.update({key: file.key}, file, {upsert: true}, function(err) {
|
||||
|
||||
client.hmset(file.key, "last_run", new Date(), function() {
|
||||
//repopulate the job list in the editor
|
||||
});
|
||||
} else {
|
||||
winston.info('scheduled job no longer exists, deleting from queue: ' + file_path);
|
||||
//TODO redis to nedb
|
||||
db.remove({key: file.key});
|
||||
client.del(file.key);
|
||||
client.srem("jobs", file.key);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function schedule_job(key, job) {
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
var is_new_job = true,
|
||||
l = later(60),
|
||||
schedule = enParser().parse(job.text);
|
||||
|
||||
var is_new_job = true,
|
||||
schedule = later.parse.text(job.text);
|
||||
l.exec(schedule, new Date(), execute_job, job);
|
||||
console.log("Job Scheduled: ", schedule);
|
||||
|
||||
later.date.localTime();
|
||||
var job_timer = later.setInterval(execute_job.bind(null, job), schedule);
|
||||
console.log("Job Scheduled: ", schedule);
|
||||
var len = job_queue.length;
|
||||
for (var i=0; i<len; i++) {
|
||||
if (job_queue[i].key === key) {
|
||||
//job already exists, but has been modified, let's stop the existing one
|
||||
job_queue[i].later.stopExec();
|
||||
|
||||
var len = job_queue.length;
|
||||
for (var i=0; i<len; i++) {
|
||||
if (job_queue[i].key === key) {
|
||||
//job already exists, but has been modified, let's stop the existing one
|
||||
job_queue[i].job_timer.clear();
|
||||
//replace it in the queue
|
||||
job_queue[i] = {key: key, later: l};
|
||||
|
||||
//replace it in the queue
|
||||
job_queue[i] = {key: key, job_timer: job_timer};
|
||||
is_new_job = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
is_new_job = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_new_job) {
|
||||
job_queue.push({key: key, later: l});
|
||||
}
|
||||
|
||||
if (is_new_job) {
|
||||
job_queue.push({key: key, job_timer: job_timer});
|
||||
}
|
||||
|
||||
//console.log(job_queue);
|
||||
//console.log(job_queue);
|
||||
}
|
||||
|
||||
|
||||
exports.emit_scheduled_jobs = function emit_scheduled_jobs(socket) {
|
||||
winston.debug("emit_scheduled_jobs");
|
||||
db.find({type: "job"}, function(err, data) {
|
||||
ws_helper.send_message(socket, 'scheduled-job-list', data);
|
||||
exports.emit_scheduled_jobs = function emit_scheduled_jobs(username, socket) {
|
||||
var job_list = [];
|
||||
client.smembers("jobs", function(err, res) {
|
||||
res.forEach(function(key, i) {
|
||||
client.hgetall(key, function(err, job_data) {
|
||||
if (job_data.username === username) {
|
||||
job_list.push(job_data);
|
||||
}
|
||||
|
||||
if (res.length === (i+1)) {
|
||||
socket.emit('scheduled-job-list', job_list);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Create new schedule
|
||||
*/
|
||||
exports.add_schedule = function(schedule, socket) {
|
||||
exports.add_schedule = function(schedule, socket, session) {
|
||||
var self = this;
|
||||
schedule.file.username = session.username;
|
||||
var file_path = schedule.file.path.replace('\/filesystem\/', '\/repositories\/');
|
||||
var key = "jobs:" + file_path.replace(/\W/g, ''); //keep only alphanumeric for key
|
||||
var job_data = {
|
||||
type: "job",
|
||||
text: schedule.text,
|
||||
name: schedule.file.name,
|
||||
key: key,
|
||||
last_run: "",
|
||||
active: "1",
|
||||
path: file_path,
|
||||
extension: schedule.file.extension
|
||||
extension: schedule.file.extension,
|
||||
username: schedule.file.username
|
||||
};
|
||||
console.log("add_schedule");
|
||||
console.log(job_data);
|
||||
|
||||
db.update({key: key}, job_data, {upsert: true}, function(err, numReplaced, upsert) {
|
||||
schedule_job(key, job_data);
|
||||
//repopulate the job list in the editor
|
||||
self.emit_scheduled_jobs(socket);
|
||||
client.sadd("jobs", key, function() {
|
||||
client.hmset(key, job_data, function() {
|
||||
schedule_job(key, job_data);
|
||||
//repopulate the job list in the editor
|
||||
self.emit_scheduled_jobs(session.username, socket);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.delete_job = function(key, socket) {
|
||||
exports.delete_job = function(key, socket, session) {
|
||||
var self = this;
|
||||
var len = job_queue.length;
|
||||
for (var i=0; i<len; i++) {
|
||||
|
|
@ -110,21 +119,24 @@ exports.delete_job = function(key, socket) {
|
|||
//remove from array
|
||||
job_queue.splice(i, 1);
|
||||
//remove from redis
|
||||
db.remove({key: key});
|
||||
client.del(key);
|
||||
client.srem("jobs", key);
|
||||
//emit change to front-end
|
||||
self.emit_scheduled_jobs(socket);
|
||||
self.emit_scheduled_jobs(session.username, socket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.toggle_job = function(key, socket) {
|
||||
exports.toggle_job = function(key, socket, session) {
|
||||
var self = this;
|
||||
console.log(key);
|
||||
db.findOne({key: key}, function(err, job) {
|
||||
client.hgetall(key, function(err, job) {
|
||||
console.log(job);
|
||||
//toggle status
|
||||
job.active = 1-job.active;
|
||||
|
||||
db.update({key: key}, job, function() {
|
||||
client.hmset(key, "active", job.active, function() {
|
||||
if (!job.active) {
|
||||
//remove job from queue, but not redis
|
||||
var len = job_queue.length;
|
||||
|
|
@ -135,24 +147,31 @@ exports.toggle_job = function(key, socket) {
|
|||
//remove from array
|
||||
job_queue.splice(i, 1);
|
||||
//emit change to front-end
|
||||
self.emit_scheduled_jobs(socket);
|
||||
self.emit_scheduled_jobs(session.username, socket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
schedule_job(key, job);
|
||||
//repopulate the job list in the editor
|
||||
self.emit_scheduled_jobs(socket);
|
||||
self.emit_scheduled_jobs(session.username, socket);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Jobs initialized at server startup
|
||||
*/
|
||||
exports.initialize_jobs = function() {
|
||||
db.find({type: "job"}, function(err, data) {
|
||||
schedule_job(data.key, data);
|
||||
client.smembers("jobs", function(err, res) {
|
||||
res.forEach(function(key) {
|
||||
client.hgetall(key, function(err, job_data) {
|
||||
schedule_job(key, job_data);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
var config = require('../config/config');
|
||||
|
||||
exports.send_message = function send_message(ws, type, data) {
|
||||
if (!ws) {
|
||||
ws = config.editor_ws;
|
||||
}
|
||||
ws.send(JSON.stringify({type: type, data: data}));
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var Datastore = require('nedb'),
|
||||
path = require('path');
|
||||
|
||||
var jobsDb = new Datastore({
|
||||
filename: path.resolve(__dirname, '../db/jobs_data_store'),
|
||||
autoload: true
|
||||
});
|
||||
|
||||
module.exports = jobsDb;
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var Datastore = require('nedb'),
|
||||
path = require('path');
|
||||
|
||||
var webideDb = new Datastore({
|
||||
filename: path.resolve(__dirname, '../db/webide_data_store'),
|
||||
autoload: true
|
||||
});
|
||||
|
||||
module.exports = webideDb;
|
||||
12
monitor.js
12
monitor.js
|
|
@ -1,12 +0,0 @@
|
|||
var forever = require('forever-monitor');
|
||||
|
||||
var child = new (forever.Monitor)('server.js', {
|
||||
silent: false,
|
||||
args: []
|
||||
});
|
||||
|
||||
child.on('exit', function () {
|
||||
console.log('your-filename.js has exited after 3 restarts');
|
||||
});
|
||||
|
||||
child.start();
|
||||
3617
package-lock.json
generated
3617
package-lock.json
generated
File diff suppressed because it is too large
Load diff
39
package.json
39
package.json
|
|
@ -4,28 +4,23 @@
|
|||
"version": "0.1.2",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"body-parser": "1.18.2",
|
||||
"cookie": "0.2.3",
|
||||
"cookie-parser": "1.4.3",
|
||||
"express": "4.16.2",
|
||||
"express": "3.1.0",
|
||||
"express-session": "1.12.1",
|
||||
"express-ws": "3.0.0",
|
||||
"gitty": "^3.6.0",
|
||||
"jsDAV": "jwcooper/jsDAV#629ded2",
|
||||
"later": "^1.2.0",
|
||||
"method-override": "2.3.10",
|
||||
"morgan": "1.9.0",
|
||||
"multer": "^1.3.0",
|
||||
"nedb": "1.8.0",
|
||||
"node-pty": "0.7.4",
|
||||
"pug": "2.0.1",
|
||||
"request": "2.83.0",
|
||||
"serve-static": "1.13.1",
|
||||
"validator": "9.4.0",
|
||||
"winston": "2.4.0",
|
||||
"xterm": "3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"forever-monitor": "^1.7.1"
|
||||
"cookie": "0.2.3",
|
||||
"passport": "0.1.15",
|
||||
"passport-bitbucket": "0.1.2",
|
||||
"passport-github": "0.1.3",
|
||||
"jade": "0.28.1",
|
||||
"request": "2.14.0",
|
||||
"socket.io": "0.9.13",
|
||||
"gitty": "git://github.com/jwcooper/Gitty.git",
|
||||
"jsDAV": "git://github.com/jwcooper/jsDAV.git",
|
||||
"connect": "2.7.3",
|
||||
"connect-redis": "2.x",
|
||||
"redis": "0.8.2",
|
||||
"tty.js": "git://github.com/jwcooper/tty.js.git",
|
||||
"validator": "0.4.25",
|
||||
"winston": "0.6.2",
|
||||
"later": "git://github.com/jwcooper/later.git"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -6,6 +6,7 @@ body {
|
|||
}
|
||||
|
||||
#container {
|
||||
padding-top: 40px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
|
@ -174,7 +175,7 @@ a.navigator-settings i.settings-enabled {
|
|||
float: right;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
padding: 4px 15px 0 0;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
#navigator-folder .refresh-directory:hover {
|
||||
|
|
@ -255,7 +256,7 @@ a.navigator-settings i.settings-enabled {
|
|||
.fileinput-button span {
|
||||
font-size: 16px;
|
||||
color: #E4E5E7;
|
||||
font-weight: bold;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.navigator-item-upload, .navigator-item-create:nth-child(2) {
|
||||
|
|
@ -300,7 +301,6 @@ a.navigator-settings i.settings-enabled {
|
|||
|
||||
#create-modal .modal-body input[type="text"] {
|
||||
width: 97%;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#confirm-modal p {
|
||||
|
|
@ -337,7 +337,7 @@ a.navigator-settings i.settings-enabled {
|
|||
padding: 3px 7px 3px 7px;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.rename-submit:hover {
|
||||
|
|
@ -345,9 +345,6 @@ a.navigator-settings i.settings-enabled {
|
|||
}
|
||||
|
||||
.create-input-wrapper input[type='text'], .rename-input-wrapper input[type='text'] {
|
||||
width: 185px;
|
||||
margin: 5px;
|
||||
height: 30px;
|
||||
background-color: #FFFFFF;
|
||||
border: none;
|
||||
-webkit-box-shadow: none;
|
||||
|
|
@ -356,7 +353,12 @@ a.navigator-settings i.settings-enabled {
|
|||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
-o-transition: none;
|
||||
transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.create-input-wrapper input[type='text'] {
|
||||
width: 185px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.rename-input-wrapper {
|
||||
|
|
@ -399,8 +401,7 @@ a.navigator-settings i.settings-enabled {
|
|||
left: 300px;
|
||||
right: 0;
|
||||
top: 50px;
|
||||
bottom: 0px;
|
||||
margin-bottom: 40px;
|
||||
bottom: 40px;
|
||||
border-bottom: 1px solid #EDEDED;
|
||||
}
|
||||
|
||||
|
|
@ -452,10 +453,9 @@ a.navigator-settings i.settings-enabled {
|
|||
#editor, #schedule-manager, #settings-manager {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
right: 0;
|
||||
top: 40px;
|
||||
bottom: 0;
|
||||
margin-bottom: -40px;
|
||||
border-top: 1px solid #EDEDED;
|
||||
border-right: 1px solid #EDEDED;
|
||||
}
|
||||
|
|
@ -525,12 +525,12 @@ a.navigator-settings i.settings-enabled {
|
|||
background-color: #EDEEEE;
|
||||
color: #2F3133;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
margin: 0 1px 0 0;
|
||||
}
|
||||
|
||||
.settings-element .font-size-value, .soft-tab-value, .tab-size-value, .invisibles-value, .manual-git-value, .python-version {
|
||||
.settings-element .font-size-value, .soft-tab-value, .tab-size-value, .invisibles-value, .manual-git-value {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
|
@ -544,7 +544,6 @@ a.navigator-settings i.settings-enabled {
|
|||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
#editor-output {
|
||||
|
|
@ -674,6 +673,10 @@ a.navigator-settings i.settings-enabled {
|
|||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#setup-content .bitbucket-signup {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#setup-content form {
|
||||
}
|
||||
|
||||
|
|
@ -689,7 +692,6 @@ a.navigator-settings i.settings-enabled {
|
|||
|
||||
#setup-content form input[type='text'], #setup-content form input[type='password'] {
|
||||
width: 350px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#setup-content form .skip-button {
|
||||
|
|
@ -753,13 +755,13 @@ a.navigator-settings i.settings-enabled {
|
|||
color: #E4E5E7;
|
||||
}
|
||||
|
||||
.ace_gutter-cell.ace_breakpoint{
|
||||
.ace_gutter-cell.ace_breakpoint{
|
||||
background-color: #BB1142;
|
||||
}
|
||||
|
||||
.debug-line {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
z-index: 5;
|
||||
background-color: #BB1142;
|
||||
}
|
||||
|
||||
|
|
@ -769,4 +771,4 @@ a.navigator-settings i.settings-enabled {
|
|||
|
||||
.debug-link-disabled:hover {
|
||||
cursor: wait;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,3 @@
|
|||
-0.8.0
|
||||
Add simple python3 support
|
||||
Fix debug populating variables
|
||||
|
||||
-0.7.0
|
||||
Update pug dependency
|
||||
Updates to installer and uninstaller
|
||||
|
||||
-0.6.0
|
||||
Initial pre-release of the simplified webide
|
||||
|
||||
-0.3.12
|
||||
Add missing cookie package
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
0.8.0
|
||||
https://github.com/adafruit/Adafruit-WebIDE/archive/0.8.0.tar.gz
|
||||
0.3.12
|
||||
http://adafruit-download.s3.amazonaws.com/webide-0.3.12-update.tar.gz
|
||||
https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/alpha/release/changelog.txt
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
# for examples
|
||||
|
||||
# If not running interactively, don't do anything
|
||||
case $- in
|
||||
*i*) ;;
|
||||
*) return;;
|
||||
esac
|
||||
[ -z "$PS1" ] && return
|
||||
|
||||
# don't put duplicate lines or lines starting with space in the history.
|
||||
# See bash(1) for more options
|
||||
|
|
@ -31,13 +28,13 @@ shopt -s checkwinsize
|
|||
#[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
|
||||
|
||||
# set variable identifying the chroot you work in (used in the prompt below)
|
||||
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
|
||||
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
|
||||
debian_chroot=$(cat /etc/debian_chroot)
|
||||
fi
|
||||
|
||||
# set a fancy prompt (non-color, unless we know we "want" color)
|
||||
case "$TERM" in
|
||||
xterm-color|*-256color) color_prompt=yes;;
|
||||
xterm-color) color_prompt=yes;;
|
||||
esac
|
||||
|
||||
# uncomment for a colored prompt, if the terminal has the capability; turned
|
||||
|
|
@ -47,17 +44,17 @@ force_color_prompt=yes
|
|||
|
||||
if [ -n "$force_color_prompt" ]; then
|
||||
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
|
||||
# We have color support; assume it's compliant with Ecma-48
|
||||
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
|
||||
# a case would tend to support setf rather than setaf.)
|
||||
color_prompt=yes
|
||||
# We have color support; assume it's compliant with Ecma-48
|
||||
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
|
||||
# a case would tend to support setf rather than setaf.)
|
||||
color_prompt=yes
|
||||
else
|
||||
color_prompt=
|
||||
color_prompt=
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$color_prompt" = yes ]; then
|
||||
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w \$\[\033[00m\] '
|
||||
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\] \[\033[01;34m\]\w \$\[\033[00m\] '
|
||||
else
|
||||
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
|
||||
fi
|
||||
|
|
@ -84,9 +81,6 @@ if [ -x /usr/bin/dircolors ]; then
|
|||
alias egrep='egrep --color=auto'
|
||||
fi
|
||||
|
||||
# colored GCC warnings and errors
|
||||
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
|
||||
|
||||
# some more ls aliases
|
||||
#alias ll='ls -l'
|
||||
#alias la='ls -A'
|
||||
|
|
@ -104,10 +98,6 @@ fi
|
|||
# enable programmable completion features (you don't need to enable
|
||||
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
|
||||
# sources /etc/bash.bashrc).
|
||||
if ! shopt -oq posix; then
|
||||
if [ -f /usr/share/bash-completion/bash_completion ]; then
|
||||
. /usr/share/bash-completion/bash_completion
|
||||
elif [ -f /etc/bash_completion ]; then
|
||||
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
|
||||
. /etc/bash_completion
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
# ~/.profile: executed by the command interpreter for login shells.
|
||||
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
|
||||
# exists.
|
||||
# see /usr/share/doc/bash/examples/startup-files for examples.
|
||||
# the files are located in the bash-doc package.
|
||||
|
||||
# the default umask is set in /etc/profile; for setting the umask
|
||||
# for ssh logins, install and configure the libpam-umask package.
|
||||
#umask 022
|
||||
|
||||
# if running bash
|
||||
if [ -n "$BASH_VERSION" ]; then
|
||||
# include .bashrc if it exists
|
||||
if [ -f "$HOME/.bashrc" ]; then
|
||||
. "$HOME/.bashrc"
|
||||
fi
|
||||
fi
|
||||
|
||||
# set PATH so it includes user's private bin if it exists
|
||||
if [ -d "$HOME/bin" ] ; then
|
||||
PATH="$HOME/bin:$PATH"
|
||||
fi
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
[Unit]
|
||||
Description=Adafruit-WebIDE
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/node /usr/share/adafruit/webide/server.js
|
||||
WorkingDirectory=/usr/share/adafruit/webide
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=webide
|
||||
# Change to a non-root user
|
||||
User=webide
|
||||
Group=webide
|
||||
# Set environment options
|
||||
Environment=NODE_ENV=production PORT=8080
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -33,7 +33,7 @@ set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Adafruit")
|
|||
set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}-ubuntu")
|
||||
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "misc")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "nodejs, nodejs-legacy, redis-server, git, avahi-daemon, i2c-tools, python-smbus")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "nodejs, nodejs-legacy, redis-server, git, restartd, libcap2-bin, avahi-daemon, i2c-tools, python-smbus")
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst;${CMAKE_CURRENT_SOURCE_DIR}/prerm;${CMAKE_CURRENT_SOURCE_DIR}/postrm;")
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "armhf")
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,17 @@ echo 'webide "node" "service adafruit-webide.sh restart" ""' >> /etc/restartd.co
|
|||
|
||||
cd /etc/init.d
|
||||
|
||||
NODE_PATH=""
|
||||
ARCH=$(dpkg --print-architecture)
|
||||
if [ $ARCH = armhf ]; then
|
||||
NODE_PATH="\/usr\/share\/adafruit\/webide\/bin\/node_hf\/node"
|
||||
chmod +x "$WEBIDE_ROOT/bin/node_hf/node"
|
||||
else
|
||||
NODE_PATH="\/usr\/share\/adafruit\/webide\/bin\/node_sf\/node"
|
||||
chmod +x "$WEBIDE_ROOT/bin/node_sf/node"
|
||||
fi
|
||||
sed -i "s/NODE_PATH/$NODE_PATH/g" adafruit-webide.sh
|
||||
|
||||
update-rc.d adafruit-webide.sh defaults
|
||||
|
||||
echo "Attempting to force reload date and time from ntp server"
|
||||
|
|
@ -47,4 +58,4 @@ echo "**** The Adafruit WebIDE is installed and running! ****"
|
|||
echo "**** Commands: sudo service adafruit-webide.sh {start,stop,restart} ****"
|
||||
echo "**** Navigate to http://$(hostname).local$PORT_USED to use the WebIDE"
|
||||
|
||||
exit 0
|
||||
exit 0
|
||||
|
|
@ -68,12 +68,12 @@ echo "Attempting to force reload date and time from ntp server"
|
|||
/usr/bin/ntpdate -b -s -u pool.ntp.org
|
||||
|
||||
echo "**** Downloading the latest version of the WebIDE ****"
|
||||
curl -L https://adafruit-download.s3.amazonaws.com/webide-0.3.12.tar.gz | tar xzf -
|
||||
curl -L http://adafruit-download.s3.amazonaws.com/webide-0.3.12.tar.gz | tar xzf -
|
||||
|
||||
echo "**** Installing required libraries ****"
|
||||
echo "**** (redis-server git avahi-daemon i2c-tools python-smbus openssh-keygen) ****"
|
||||
opkg update
|
||||
opkg install nodejs git avahi-daemon i2c-tools python-smbus openssh-keygen
|
||||
opkg install nodejs git avahi-daemon i2c-tools python-smbus libcap2 libcap-bin openssh-keygen
|
||||
|
||||
if ! redis-cli PING
|
||||
then
|
||||
|
|
|
|||
|
|
@ -53,25 +53,29 @@ WEBIDE_ROOT="/usr/share/adafruit/webide"
|
|||
#needed for SSH key and config access at this point.
|
||||
WEBIDE_HOME="/home/webide"
|
||||
|
||||
#NODE_PATH="/usr/local/lib/node"
|
||||
|
||||
#if [ ! -d "$NODE_PATH" ]; then
|
||||
# mkdir -p "$NODE_PATH"
|
||||
# # Control will enter here if $DIRECTORY doesn't exist.
|
||||
#fi
|
||||
|
||||
mkdir -p "$WEBIDE_ROOT"
|
||||
mkdir -p "$WEBIDE_HOME/tmp"
|
||||
mkdir -p "$WEBIDE_HOME"
|
||||
cd "$WEBIDE_ROOT"
|
||||
|
||||
echo "**** Downloading the latest version of the WebIDE ****"
|
||||
curl -L https://github.com/adafruit/Adafruit-WebIDE/archive/0.8.0.tar.gz | tar xzf - --strip-components=1
|
||||
curl -L http://adafruit-download.s3.amazonaws.com/webide-0.3.12.tar.gz | tar xzf -
|
||||
|
||||
echo "**** Installing required libraries ****"
|
||||
echo "**** (nodejs-legacy npm git i2c-tools python-smbus ntp libkrb5-dev) ****"
|
||||
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
|
||||
echo "**** (redis-server git restartd libcap2-bin avahi-daemon i2c-tools python-smbus) ****"
|
||||
apt-get update
|
||||
apt-get install nodejs git i2c-tools python-smbus ntp libkrb5-dev -y
|
||||
npm install -g npm
|
||||
apt-get install nodejs nodejs-legacy redis-server git restartd libcap2-bin avahi-daemon i2c-tools python-smbus ntp -y
|
||||
|
||||
echo "**** Create webide user and group ****"
|
||||
groupadd webide || true
|
||||
useradd -g webide webide || true
|
||||
usermod -a -G i2c,sudo webide || true
|
||||
chsh -s /bin/bash webide
|
||||
|
||||
echo "**** Adding webide user to sudoers ****"
|
||||
if [ -f "/etc/sudoers.tmp" ]; then
|
||||
|
|
@ -89,28 +93,75 @@ chown -R webide:webide "$WEBIDE_HOME"
|
|||
chown -R webide:webide "$WEBIDE_ROOT"
|
||||
chmod 775 "$WEBIDE_ROOT"
|
||||
|
||||
echo "**** Installing webide dependencies ****"
|
||||
sudo -u webide npm install
|
||||
|
||||
echo "**** Adding default .bashrc file for webide user ****"
|
||||
cp "$WEBIDE_ROOT/scripts/.bashrc" "$WEBIDE_HOME"
|
||||
|
||||
echo "**** Installing the WebIDE as a service ****"
|
||||
echo "**** (to uninstall service, execute: 'sudo update-rc.d -f adafruit-webide.sh remove') ****"
|
||||
cp "$WEBIDE_ROOT/scripts/adafruit-webide.sh" "/etc/init.d"
|
||||
cd /etc/init.d
|
||||
chmod 755 adafruit-webide.sh
|
||||
|
||||
NODE_PATH=""
|
||||
ARCH=$(dpkg --print-architecture)
|
||||
if [ $ARCH = armhf ]; then
|
||||
NODE_PATH="\/usr\/share\/adafruit\/webide\/bin\/node_hf\/node"
|
||||
chmod +x "$WEBIDE_ROOT/bin/node_hf/node"
|
||||
else
|
||||
NODE_PATH="\/usr\/share\/adafruit\/webide\/bin\/node_sf\/node"
|
||||
chmod +x "$WEBIDE_ROOT/bin/node_sf/node"
|
||||
fi
|
||||
sed -i "s/NODE_PATH/$NODE_PATH/g" adafruit-webide.sh
|
||||
|
||||
update-rc.d adafruit-webide.sh defaults
|
||||
|
||||
#set binaries as executable
|
||||
|
||||
echo "Attempting to force reload date and time from ntp server"
|
||||
/etc/init.d/ntp force-reload
|
||||
|
||||
# echo "**** Installing the WebIDE as a service ****"
|
||||
# echo "**** (to uninstall service, execute: 'sudo update-rc.d -f adafruit-webide.sh remove') ****"
|
||||
cp "$WEBIDE_ROOT/scripts/adafruit-webide.service" "/etc/systemd/system/adafruit-webide.service"
|
||||
systemctl enable adafruit-webide.service
|
||||
systemctl start adafruit-webide.service
|
||||
#Check if port 80 is in use, use 8080 if so.
|
||||
PORT_USED=""
|
||||
if netstat -lnt | awk '$6 == "LISTEN" && $4 ~ ".80"' | grep -q "LISTEN"
|
||||
then
|
||||
redis-cli HMSET server port 8090
|
||||
PORT_USED=":8090"
|
||||
echo "**** WARNING: PORT 80 IN USE. FALLING BACK TO 8090. ****"
|
||||
echo "**** TO CHOOSE A DIFFERENT PORT USE THE FOLLOWING COMMAND: ****"
|
||||
echo "**** redis-cli HMSET server port 8090 ****"
|
||||
echo "**** AND RESTART THE SERVER ****"
|
||||
fi
|
||||
|
||||
if $OFFLINE
|
||||
then
|
||||
redis-cli HMSET server offline 1
|
||||
fi
|
||||
|
||||
if $GITHUB
|
||||
then
|
||||
redis-cli HMSET server github 1
|
||||
fi
|
||||
|
||||
service adafruit-webide.sh start
|
||||
|
||||
if grep -q adafruit-webide.sh /etc/restartd.conf
|
||||
then
|
||||
echo "restartd already configured"
|
||||
else
|
||||
echo 'webide "node" "service adafruit-webide.sh restart" ""' >> /etc/restartd.conf
|
||||
fi
|
||||
|
||||
#kill all restartd processes, and restart one
|
||||
pkill -f restartd || true
|
||||
sleep 5s
|
||||
restartd
|
||||
|
||||
echo "**** Starting the server...(please wait) ****"
|
||||
sleep 20s
|
||||
|
||||
echo "**** The Adafruit WebIDE is installed and running! ****"
|
||||
echo "**** Commands: sudo systemctl {start,stop,restart} adafruit-webide ****"
|
||||
echo "**** Navigate to http://$(hostname).local:8080 to use the WebIDE"
|
||||
echo "**** Commands: sudo service adafruit-webide.sh {start,stop,restart} ****"
|
||||
echo "**** Navigate to http://$(hostname).local$PORT_USED to use the WebIDE"
|
||||
#echo "**** To run the editor: ****"
|
||||
#echo "**** cd ~/Adafruit/WebIDE ****"
|
||||
#echo "**** node webide ****"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
cd ~
|
||||
git clone git://github.com/adafruit/Adafruit-WebIDE.git
|
||||
cd Adafruit-WebIDE
|
||||
chmod +x bin/node_hf/node
|
||||
sudo ln -s /home/pi/Adafruit-WebIDE/bin/node_hf/node /usr/bin/node
|
||||
sudo ln -s /home/pi/Adafruit-WebIDE/bin/node_hf/node /usr/lib/node
|
||||
curl -L https://npmjs.org/install.sh | sudo sh
|
||||
npm install
|
||||
cd ..
|
||||
cp -r Adafruit-WebIDE Adafruit-WebIDE-Update
|
||||
cd Adafruit-WebIDE-Update/node_modules
|
||||
rm -rf winston socket.io jsDAV connect-redis request connect express gitty jade redis validator
|
||||
rm -rf winston passport-bitbucket socket.io jsDAV connect-redis request connect passport express gitty jade redis validator
|
||||
|
|
@ -42,4 +42,4 @@ echo "**** libraries installed that we did not uninstall as ****"
|
|||
echo "**** we're not able to determine if other applications are dependent ****"
|
||||
echo "**** on them. If you are not using them, you can uninstall by executing ****"
|
||||
echo "**** the following command: ****"
|
||||
echo "**** opkg remove nodejs git avahi-daemon i2c-tools python-smbus ****"
|
||||
echo "**** opkg remove nodejs git avahi-daemon i2c-tools python-smbus libcap2 libcap-bin ****"
|
||||
|
|
@ -3,10 +3,17 @@
|
|||
# curl https://raw.githubusercontent.com/adafruit/Adafruit-WebIDE/alpha/scripts/uninstall.sh | sudo sh
|
||||
|
||||
|
||||
WEBIDE_ROOT="/usr/share/adafruit/webide"
|
||||
WEBIDE_ROOT="/usr/share/adafruit"
|
||||
WEBIDE_HOME="/home/webide"
|
||||
NODE_PATH=""
|
||||
|
||||
echo "**** Removing restartd WebIDE configuration ****"
|
||||
sed -i '/adafruit-webide.sh/ d' /etc/restartd.conf
|
||||
#kill all restartd processes, and restart one
|
||||
pkill -f restartd || true
|
||||
sleep 5s
|
||||
restartd
|
||||
|
||||
echo "**** Removing webide user from sudoers ****"
|
||||
if [ -f "/etc/sudoers.tmp" ]; then
|
||||
rm /etc/sudoers.tmp
|
||||
|
|
@ -19,28 +26,35 @@ if [ "$?" -eq "0" ]; then
|
|||
fi
|
||||
rm /etc/sudoers.tmp
|
||||
|
||||
echo "**** Removing access to port 80 for node ****"
|
||||
NODE_PATH=""
|
||||
ARCH=$(dpkg --print-architecture)
|
||||
if [ $ARCH = armhf ]; then
|
||||
NODE_PATH="/usr/share/adafruit/webide/bin/node_hf/node"
|
||||
else
|
||||
NODE_PATH="/usr/share/adafruit/webide/bin/node_sf/node"
|
||||
fi
|
||||
setcap -r "$NODE_PATH"
|
||||
|
||||
echo "**** Stopping the Adafruit WebIDE ****"
|
||||
service adafruit-webide.sh stop
|
||||
sleep 5s
|
||||
|
||||
echo "**** Removing systemd service ****"
|
||||
systemctl stop adafruit-webide
|
||||
systemctl disable adafruit-webide
|
||||
rm /etc/systemd/system/adafruit-webide.service
|
||||
systemctl daemon-reload
|
||||
systemctl reset-failed
|
||||
|
||||
echo "**** Removing update-rc.d service ****"
|
||||
update-rc.d -f adafruit-webide.sh remove
|
||||
rm /etc/init.d/adafruit-webide.sh
|
||||
echo "**** Removing the WebIDE Folder ****"
|
||||
shopt -s extglob
|
||||
rm -rf "$WEBIDE_ROOT"/!(repositories)
|
||||
rm -rf "$WEBIDE_ROOT"
|
||||
echo "**** Removing webide user ****"
|
||||
userdel -r webide
|
||||
|
||||
echo "**** Removing redis server setting ****"
|
||||
redis-cli del server
|
||||
|
||||
echo "**** The Adafruit WebIDE is now uninstalled! ****"
|
||||
echo "**** Your code and repositories remain at $WEBIDE_ROOT ****"
|
||||
echo "**** During the installation process, there were a few ****"
|
||||
echo "**** libraries installed that we did not uninstall as ****"
|
||||
echo "**** we're not able to determine if other applications are dependent ****"
|
||||
echo "**** on them. If you are not using them, you can uninstall by executing ****"
|
||||
echo "**** the following command: ****"
|
||||
echo "**** sudo apt-get remove nodejs-legacy yarn git i2c-tools python-smbus ntp libkrb5-dev ****"
|
||||
echo "**** sudo apt-get remove nodejs npm redis-server git restartd libcap2-bin avahi-daemon i2c-tools python-smbus ****"
|
||||
534
server.js
534
server.js
|
|
@ -1,37 +1,42 @@
|
|||
var express = require('express'),
|
||||
session = require('express-session'),
|
||||
bodyParser = require('body-parser'),
|
||||
methodOverride = require('method-override'),
|
||||
cookieParser = require('cookie-parser'),
|
||||
serveStatic = require('serve-static'),
|
||||
morgan = require('morgan'),
|
||||
tty = require('tty.js'),
|
||||
app = express(),
|
||||
expressWs = require('express-ws')(app),
|
||||
multer = require('multer'),
|
||||
upload = multer({ dest: './uploads' }),
|
||||
util = require('util'),
|
||||
io = require('socket.io'),
|
||||
passport = require('passport'),
|
||||
util = require('util'),
|
||||
BitbucketStrategy = require('passport-bitbucket').Strategy,
|
||||
GitHubStrategy = require('passport-github').Strategy,
|
||||
site = require('./controllers/site'),
|
||||
editor = require('./controllers/editor'),
|
||||
user = require('./controllers/user'),
|
||||
jsDAV = require("jsDAV/lib/jsdav"),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
updater = require('./helpers/updater'),
|
||||
scheduler = require('./helpers/scheduler'),
|
||||
editor_setup = require('./helpers/editor_setup'),
|
||||
git_helper = require('./helpers/git_helper'),
|
||||
exec_helper = require('./helpers/exec_helper'),
|
||||
fs_helper = require('./helpers/fs_helper'),
|
||||
exec_helper = require('./helpers/exec_helper'),
|
||||
request_helper = require('./helpers/request_helper'),
|
||||
debug_helper = require('./helpers/python/debug_helper'),
|
||||
RedisStore = require('connect-redis')(session),
|
||||
redis = require("redis"),
|
||||
client = redis.createClient(),
|
||||
config = require('./config/config'),
|
||||
winston = require('winston'),
|
||||
db = require('./models/webideModel'),
|
||||
pty = require('node-pty');
|
||||
winston = require('winston');
|
||||
|
||||
var davServer,
|
||||
HOSTNAME,
|
||||
IS_PASSPORT_SETUP = false,
|
||||
REPOSITORY_PATH = path.resolve(__dirname + "/repositories");
|
||||
|
||||
winston.info("REPOSITORY_PATH", REPOSITORY_PATH);
|
||||
|
||||
|
||||
var terminals = {}, logs = {};
|
||||
//exec_helper.spawn_ipython();
|
||||
|
||||
//check for the existence of the logs directory, if it doesn't
|
||||
//exist, create it prior to starting the child process.
|
||||
|
|
@ -41,12 +46,80 @@ if (!exists) {
|
|||
winston.info('created logs folder');
|
||||
}
|
||||
|
||||
//winston.add(winston.transports.File, { filename: __dirname + '/logs/output.log', json: false });
|
||||
//winston.handleExceptions(new winston.transports.File({ filename: __dirname + '/logs/errors.log', json: false }));
|
||||
//winston.remove(winston.transports.Console);
|
||||
winston.add(winston.transports.File, { filename: __dirname + '/logs/output.log', json: false });
|
||||
winston.handleExceptions(new winston.transports.File({ filename: __dirname + '/logs/errors.log', json: false }));
|
||||
winston.remove(winston.transports.Console);
|
||||
|
||||
// Passport session setup.
|
||||
// To support persistent login sessions, Passport needs to be able to
|
||||
// serialize users into and deserialize users out of the session. Typically,
|
||||
// this will be as simple as storing the user ID when serializing, and finding
|
||||
// the user by ID when deserializing. However, since this example does not
|
||||
// have a database of user records, the complete Bitbucket profile is
|
||||
// serialized and deserialized.
|
||||
|
||||
|
||||
winston.info("REPOSITORY_PATH", REPOSITORY_PATH);
|
||||
// Use the BitbucketStrategy within Passport.
|
||||
// Strategies in passport require a `verify` function, which accept
|
||||
// credentials (in this case, a token, tokenSecret, and Bitbucket profile),
|
||||
// and invoke a callback with a user object.
|
||||
function setup_bitbucket_passport(consumer_key, consumer_secret) {
|
||||
winston.info("http://" + HOSTNAME + "/auth/bitbucket/callback");
|
||||
passport.use(new BitbucketStrategy({
|
||||
consumerKey: consumer_key,
|
||||
consumerSecret: consumer_secret,
|
||||
callbackURL: "http://" + HOSTNAME + "/auth/bitbucket/callback"
|
||||
},
|
||||
function(token, tokenSecret, profile, done) {
|
||||
// asynchronous verification, for effect...
|
||||
process.nextTick(function () {
|
||||
profile.token = token;
|
||||
profile.token_secret = tokenSecret;
|
||||
profile.consumer_key = consumer_key;
|
||||
profile.consumer_secret = consumer_secret;
|
||||
|
||||
return done(null, profile);
|
||||
});
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
// Use the GitHubStrategy within Passport.
|
||||
// Strategies in passport require a `verify` function, which accept
|
||||
// credentials (in this case, a token, tokenSecret, and Github profile),
|
||||
// and invoke a callback with a user object.
|
||||
function setup_github_passport(consumer_key, consumer_secret) {
|
||||
winston.info("http://" + HOSTNAME + "/auth/github/callback");
|
||||
passport.use(new GitHubStrategy({
|
||||
clientID: consumer_key,
|
||||
clientSecret: consumer_secret,
|
||||
callbackURL: "http://" + HOSTNAME + "/auth/github/callback",
|
||||
userAgent: HOSTNAME
|
||||
},
|
||||
function(accessToken, refreshToken, profile, done) {
|
||||
// asynchronous verification, for effect...
|
||||
process.nextTick(function () {
|
||||
profile.token = accessToken;
|
||||
profile.refresh_token = refreshToken;
|
||||
profile.consumer_key = consumer_key;
|
||||
profile.consumer_secret = consumer_secret;
|
||||
|
||||
return done(null, profile);
|
||||
});
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
passport.serializeUser(function(user, done) {
|
||||
client.set(user.username, JSON.stringify(user));
|
||||
done(null, user.username);
|
||||
});
|
||||
|
||||
passport.deserializeUser(function(obj, done) {
|
||||
client.get(obj, function(err, reply) {
|
||||
done(null, JSON.parse(reply));
|
||||
});
|
||||
});
|
||||
|
||||
//redirect anything with /filesystem in the url to the WebDav server.
|
||||
app.use(function(req, res, next) {
|
||||
|
|
@ -58,118 +131,93 @@ app.use(function(req, res, next) {
|
|||
}
|
||||
});
|
||||
|
||||
app.set('view engine', 'pug');
|
||||
var sessionStore = new RedisStore();
|
||||
app.set('view engine', 'jade');
|
||||
app.set('views', __dirname + '/views');
|
||||
//logging
|
||||
app.use(morgan('tiny'));
|
||||
app.use(serveStatic(__dirname + '/public'));
|
||||
app.use(serveStatic(__dirname + '/node_modules/xterm/dist'));
|
||||
app.use(cookieParser());
|
||||
var sessionMiddleware = session({
|
||||
app.use(express.logger());
|
||||
//app.use(express.logger("dev"));
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
app.use(express.static(__dirname + '/node_modules/tty.js/static'));
|
||||
app.use(express.cookieParser());
|
||||
app.use(session({
|
||||
store: sessionStore,
|
||||
key: 'sid',
|
||||
secret: 'cat nap',
|
||||
resave: true,
|
||||
saveUninitialized: true
|
||||
});
|
||||
app.use(sessionMiddleware);
|
||||
app.use(bodyParser.json())
|
||||
app.use(bodyParser.urlencoded({ extended: true }))
|
||||
app.use(methodOverride());
|
||||
}));
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.methodOverride());
|
||||
app.use(passport.initialize());
|
||||
app.use(passport.session());
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
res.locals.session = req.session;
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/', site.index);
|
||||
app.use(app.router);
|
||||
|
||||
app.get('/editor', editor.index);
|
||||
app.get('/editor/image', editor.image);
|
||||
app.use(errorHandler);
|
||||
|
||||
app.post('/editor/upload', upload.single('obj'), editor.upload_file);
|
||||
|
||||
app.post('/create/repository', editor.create_repository);
|
||||
app.get('/', ensureAuthenticated, site.index);
|
||||
|
||||
app.get('/editor', ensureAuthenticated, editor.index);
|
||||
app.get('/editor/image', ensureAuthenticated, editor.image);
|
||||
app.post('/editor/upload', ensureAuthenticated, editor.upload_file);
|
||||
|
||||
app.post('/create/repository', ensureAuthenticated, editor.create_repository);
|
||||
|
||||
app.get('/setup', user.setup);
|
||||
app.post('/setup', user.submit_setup);
|
||||
app.get('/config', user.config);
|
||||
app.post('/config', user.submit_config);
|
||||
app.get('/set-datetime', user.set_datetime);
|
||||
app.get('/login', ensureOauth, user.login);
|
||||
app.get('/logout', user.logout);
|
||||
|
||||
app.post('/terminals', function (req, res) {
|
||||
var cols = parseInt(req.query.cols),
|
||||
rows = parseInt(req.query.rows),
|
||||
cwd = req.query.cwd;
|
||||
|
||||
var term = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : 'bash', [], {
|
||||
name: 'xterm-color',
|
||||
cols: cols || 80,
|
||||
rows: rows || 24,
|
||||
cwd: path.resolve(cwd),
|
||||
env: process.env
|
||||
});
|
||||
|
||||
console.log('Created terminal with PID: ' + term.pid);
|
||||
terminals[term.pid] = term;
|
||||
logs[term.pid] = '';
|
||||
term.on('data', function(data) {
|
||||
logs[term.pid] += data;
|
||||
// GET /auth/bitbucket
|
||||
// Use passport.authenticate() as route middleware to authenticate the
|
||||
// request. The first step in Bitbucket authentication will involve redirecting
|
||||
// the user to bitbucket.org. After authorization, Bitbucket will redirect the user
|
||||
// back to this application at /auth/bitbucket/callback
|
||||
app.get('/auth/bitbucket',
|
||||
passport.authenticate('bitbucket'),
|
||||
function(req, res){
|
||||
// The request will be redirected to Bitbucket for authentication, so this
|
||||
// function will not be called.
|
||||
});
|
||||
res.send(term.pid.toString());
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.post('/terminals/:pid/size', function (req, res) {
|
||||
var pid = parseInt(req.params.pid),
|
||||
cols = parseInt(req.query.cols),
|
||||
rows = parseInt(req.query.rows),
|
||||
term = terminals[pid];
|
||||
|
||||
term.resize(cols, rows);
|
||||
console.log('Resized terminal ' + pid + ' to ' + cols + ' cols and ' + rows + ' rows.');
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.ws('/terminals/:pid', function (ws, req) {
|
||||
var term = terminals[parseInt(req.params.pid)];
|
||||
console.log('Connected to terminal ' + term.pid);
|
||||
ws.send(logs[term.pid]);
|
||||
|
||||
term.on('data', function(data) {
|
||||
try {
|
||||
ws.send(data);
|
||||
} catch (ex) {
|
||||
// The WebSocket is not open, ignore
|
||||
}
|
||||
// GET /auth/bitbucket/callback
|
||||
// Use passport.authenticate() as route middleware to authenticate the
|
||||
// request. If authentication fails, the user will be redirected back to the
|
||||
// login page. Otherwise, the primary route function function will be calsled,
|
||||
// which, in this example, will redirect the user to the home page.
|
||||
app.get('/auth/bitbucket/callback',
|
||||
passport.authenticate('bitbucket', { failureRedirect: '/login' }),
|
||||
function(req, res) {
|
||||
res.redirect('/editor');
|
||||
});
|
||||
ws.on('message', function(msg) {
|
||||
try {
|
||||
msg = JSON.parse(msg);
|
||||
} catch (e) {
|
||||
//not json, just a string...
|
||||
}
|
||||
|
||||
if (msg.type === 'input') {
|
||||
term.write(msg.data.toString() + '\r');
|
||||
} else {
|
||||
term.write(msg.toString());
|
||||
}
|
||||
// GET /auth/github
|
||||
app.get('/auth/github',
|
||||
passport.authenticate('github'),
|
||||
function(req, res){
|
||||
// The request will be redirected to Github for authentication, so this
|
||||
// function will not be called.
|
||||
});
|
||||
ws.on('close', function () {
|
||||
term.kill();
|
||||
console.log('Closed terminal ' + term.pid);
|
||||
// Clean things up
|
||||
delete terminals[term.pid];
|
||||
delete logs[term.pid];
|
||||
|
||||
// GET /auth/github/callback
|
||||
app.get('/auth/github/callback',
|
||||
passport.authenticate('github', { failureRedirect: '/login' }),
|
||||
function(req, res) {
|
||||
res.redirect('/editor');
|
||||
});
|
||||
});
|
||||
|
||||
app.ws('/editor', editor.editor);
|
||||
|
||||
app.use(errorHandler);
|
||||
|
||||
serverInitialization(app);
|
||||
|
||||
|
||||
function errorHandler(err, req, res, next) {
|
||||
winston.error(err);
|
||||
if (err.name === "InternalOAuthError") {
|
||||
|
|
@ -181,6 +229,93 @@ function errorHandler(err, req, res, next) {
|
|||
}
|
||||
}
|
||||
|
||||
// Simple route middleware to ensure user is authenticated.
|
||||
// Use this route middleware on any resource that needs to be protected. If
|
||||
// the request is authenticated (typically via a persistent login session),
|
||||
// the request will proceed. Otherwise, the user will be redirected to the
|
||||
// login page.
|
||||
function ensureAuthenticated(req, res, next) {
|
||||
setHostName(req);
|
||||
|
||||
if (config.editor.offline) {
|
||||
req.user = { provider: 'offline',
|
||||
username: 'offline user' };
|
||||
return next();
|
||||
}
|
||||
|
||||
function authRoute(req, res, next) {
|
||||
if (req.isAuthenticated()) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!IS_PASSPORT_SETUP) {
|
||||
res.redirect('/setup');
|
||||
} else {
|
||||
res.redirect('/login');
|
||||
}
|
||||
}
|
||||
|
||||
//use the correct key for redis, either github or bitbucket
|
||||
var oauth_key = 'bitbucket_oauth';
|
||||
if (config.editor.github) {
|
||||
oauth_key = 'github_oauth';
|
||||
}
|
||||
|
||||
if (!IS_PASSPORT_SETUP) {
|
||||
//need to setup passport on server startup, if the oauth is already setup
|
||||
client.hgetall(oauth_key, function (err, oauth) {
|
||||
if (oauth) {
|
||||
if (config.editor.github) {
|
||||
setup_github_passport(oauth.consumer_key, oauth.consumer_secret);
|
||||
} else {
|
||||
setup_bitbucket_passport(oauth.consumer_key, oauth.consumer_secret);
|
||||
}
|
||||
IS_PASSPORT_SETUP = true;
|
||||
|
||||
}
|
||||
authRoute(req, res, next);
|
||||
});
|
||||
} else {
|
||||
authRoute(req, res, next);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function ensureOauth(req, res, next) {
|
||||
setHostName(req);
|
||||
|
||||
if (config.editor.offline) {
|
||||
req.user = { provider: 'offline',
|
||||
username: 'offline user' };
|
||||
return next();
|
||||
}
|
||||
|
||||
//use the correct key for redis, either github or bitbucket
|
||||
var oauth_key = 'bitbucket_oauth';
|
||||
if (config.editor.github) {
|
||||
oauth_key = 'github_oauth';
|
||||
}
|
||||
|
||||
client.hgetall(oauth_key, function (err, oauth) {
|
||||
if (!oauth) {
|
||||
res.redirect('/setup');
|
||||
} else {
|
||||
if (config.editor.github) {
|
||||
setup_github_passport(oauth.consumer_key, oauth.consumer_secret);
|
||||
} else {
|
||||
setup_bitbucket_passport(oauth.consumer_key, oauth.consumer_secret);
|
||||
}
|
||||
|
||||
if (!IS_PASSPORT_SETUP) {
|
||||
IS_PASSPORT_SETUP = true;
|
||||
res.redirect('/login');
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setHostName(req) {
|
||||
//set it each time, it's quick, and hostname may change (internal IP vs external IP).
|
||||
HOSTNAME = req.headers.host;
|
||||
|
|
@ -208,31 +343,189 @@ function serverInitialization(app) {
|
|||
scheduler.initialize_jobs();
|
||||
|
||||
start_server(function(server) {
|
||||
socket_listeners();
|
||||
mount_dav(server);
|
||||
});
|
||||
}
|
||||
|
||||
function start_server(cb) {
|
||||
db.find('server', function (err, server_data) {
|
||||
server = require('http').createServer(app);
|
||||
io = io.listen(server);
|
||||
io.configure(function() {
|
||||
io.enable('browser client minification');
|
||||
io.enable('browser client etag');
|
||||
io.set('transports', ['websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling']);
|
||||
});
|
||||
|
||||
new tty.Server(config.term, app, server, io);
|
||||
|
||||
client.hgetall('server', function (err, server_data) {
|
||||
var port;
|
||||
|
||||
if (server_data && server_data.port) {
|
||||
port = server_data.port;
|
||||
} else if (process.env.PORT) {
|
||||
port = process.env.PORT
|
||||
} else {
|
||||
port = config.editor.port;
|
||||
}
|
||||
|
||||
if (server_data && server_data.offline) {
|
||||
config.editor.offline = (server_data.offline == 1) ? true : false;
|
||||
}
|
||||
|
||||
if (server_data && server_data.github) {
|
||||
config.editor.github = (server_data.github == 1) ? true : false;
|
||||
}
|
||||
|
||||
winston.info('listening on port ' + port);
|
||||
cb(app.listen(port));
|
||||
cb(server.listen(port));
|
||||
});
|
||||
}
|
||||
|
||||
function socket_listeners() {
|
||||
io.sockets.authorization(function(handshakeData, callback) {
|
||||
if (!handshakeData.headers.cookie) return callback('socket.io: cookie not found.', false);
|
||||
var signedCookies = require('cookie').parse(handshakeData.headers.cookie);
|
||||
handshakeData.cookies = require('connect/lib/utils').parseSignedCookies(signedCookies, 'cat nap');
|
||||
|
||||
sessionStore.get(handshakeData.cookies['sid'], function(err, session) {
|
||||
if (config.editor.offline) {
|
||||
handshakeData.session = { provider: 'offline', username: 'offline user' };
|
||||
return callback(null, true);
|
||||
} else {
|
||||
client.get(session.passport.user, function(err, user) {
|
||||
if (err || !session) return callback('socket.io: session not found.', false);
|
||||
handshakeData.session = JSON.parse(user);
|
||||
if (handshakeData.session) {
|
||||
return callback(null, true);
|
||||
} else {
|
||||
return callback('socket.io: session user not found', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.set('username', socket.handshake.session.username);
|
||||
|
||||
//emit on first connection
|
||||
socket.emit('cwd-init', {dirname: REPOSITORY_PATH});
|
||||
scheduler.emit_scheduled_jobs(socket.handshake.session.username, socket);
|
||||
|
||||
socket.on('disconnect', function() {
|
||||
debug_helper.client_disconnect();
|
||||
debug_helper.kill_debug();
|
||||
});
|
||||
|
||||
//listen for events
|
||||
socket.on('git-delete', function(data) {
|
||||
git_helper.remove_commit_push(data.file, socket.handshake.session, function(err, status) {
|
||||
socket.emit('git-delete-complete', {err: err, status: status});
|
||||
});
|
||||
});
|
||||
|
||||
//listen for events
|
||||
socket.on('git-pull', function(data) {
|
||||
console.log(data);
|
||||
var name = data.file ? data.file.name : "";
|
||||
git_helper.pull(name, "origin", "master", function(err, status) {
|
||||
socket.emit('git-pull-complete', {err: err, status: status});
|
||||
});
|
||||
});
|
||||
|
||||
//listen for events
|
||||
socket.on('git-is-modified', function(data) {
|
||||
git_helper.is_modified(data.file, function(err, status) {
|
||||
socket.emit('git-is-modified-complete', {is_modified: status});
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('commit-file', function (data) {
|
||||
var commit_message = "";
|
||||
|
||||
if (data.message) {
|
||||
commit_message = data.message;
|
||||
} else {
|
||||
commit_message = "Modified " + data.file.name;
|
||||
}
|
||||
|
||||
git_helper.commit_push_and_save(data.file, commit_message, socket.handshake.session, function(err, status) {
|
||||
socket.emit('commit-file-complete', {err: err, status: status});
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('move-file', function (data) {
|
||||
git_helper.move_commit_push(data.file, socket.handshake.session, function(err) {
|
||||
console.log('move-file', err);
|
||||
socket.emit('move-file-complete', {err: err});
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('self-check-request', function() {
|
||||
editor_setup.health_check(socket, socket.handshake.session);
|
||||
});
|
||||
|
||||
socket.on('editor-check-updates', function() {
|
||||
updater.check_for_updates(socket);
|
||||
});
|
||||
|
||||
socket.on('editor-update', function() {
|
||||
updater.update(socket);
|
||||
});
|
||||
|
||||
socket.on('trace-file', function(data) {
|
||||
exec_helper.trace_program(data.file, socket);
|
||||
});
|
||||
|
||||
socket.on('debug-command', function(data) {
|
||||
debug_helper.debug_command(data, socket);
|
||||
});
|
||||
|
||||
socket.on('debug-file', function(data) {
|
||||
debug_helper.start_debug(data.file, socket);
|
||||
});
|
||||
|
||||
socket.on('commit-run-file', function(data) {
|
||||
if (data && data.file) {
|
||||
data.file.username = socket.handshake.session.username;
|
||||
}
|
||||
|
||||
exec_helper.execute_program(data.file, false);
|
||||
git_helper.commit_push_and_save(data.file, "Modified " + data.file.name, socket.handshake.session, function(err, status) {
|
||||
socket.emit('commit-file-complete', {message: "Save was successful"});
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('stop-script-execution', function(data) {
|
||||
exec_helper.stop_program(data.file, false);
|
||||
});
|
||||
|
||||
socket.on('submit-schedule', function(schedule) {
|
||||
scheduler.add_schedule(schedule, socket, socket.handshake.session);
|
||||
});
|
||||
|
||||
socket.on('schedule-delete-job', function(key) {
|
||||
scheduler.delete_job(key, socket, socket.handshake.session);
|
||||
});
|
||||
|
||||
socket.on('schedule-toggle-job', function(key) {
|
||||
scheduler.toggle_job(key, socket, socket.handshake.session);
|
||||
});
|
||||
|
||||
socket.on('set-settings', function(value) {
|
||||
client.hmset("editor:settings", value, function(err) {
|
||||
if (err) winston.error(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
io.sockets.on('disconnect', function(socket) {
|
||||
exec_helper.set_sockets(io.sockets.sockets);
|
||||
});
|
||||
|
||||
function mount_dav(server) {
|
||||
var jsDAV_FS_Tree = require("jsDAV/lib/DAV/backends/fs/tree");
|
||||
var jsDAV_Tree_Filesystem = require("jsDAV/lib/DAV/tree/filesystem").jsDAV_Tree_Filesystem;
|
||||
//jsDAV.debugMode = true;
|
||||
davServer = jsDAV.mount({
|
||||
path: REPOSITORY_PATH,
|
||||
|
|
@ -240,33 +533,32 @@ function mount_dav(server) {
|
|||
plugins: ["codesearch", "tree", "filelist", "filesearch", "locks", "mount", "temporaryfilefilter"],
|
||||
server: server,
|
||||
standalone: false,
|
||||
tree: jsDAV_FS_Tree.new(REPOSITORY_PATH)
|
||||
tree: new jsDAV_Tree_Filesystem(REPOSITORY_PATH)
|
||||
});
|
||||
winston.info('webdav filesystem mounted');
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
winston.info("process and worker cleanup");
|
||||
Object.keys(terminals).forEach(function (pid) {
|
||||
var term = terminals[pid];
|
||||
console.log('Closed terminal ' + term.pid);
|
||||
term.kill();
|
||||
});
|
||||
exports.get_socket = function (username, cb) {
|
||||
for (var socketId in io.sockets.sockets) {
|
||||
io.sockets.sockets[socketId].get('username', function(err, sock_username) {
|
||||
if (username === sock_username) {
|
||||
cb(io.sockets.sockets[socketId]);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
winston.info("\nShutting down from SIGINT");
|
||||
// some other closing procedures go here
|
||||
debug_helper.kill_debug(false, function() {
|
||||
//no need to wait for this
|
||||
});
|
||||
}
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
winston.info("Shutting down from SIGINT");
|
||||
cleanup();
|
||||
process.exit();
|
||||
});
|
||||
|
||||
process.on('uncaughtException', function(err) {
|
||||
winston.error("Shutting down from uncaughtException");
|
||||
winston.error(err.stack);
|
||||
cleanup();
|
||||
process.exit();
|
||||
debug_helper.kill_debug(false, function() {
|
||||
//no need to wait for this
|
||||
});
|
||||
});
|
||||
|
|
|
|||
3
uploads/.gitignore
vendored
3
uploads/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
|||
*
|
||||
*/
|
||||
!.gitignore
|
||||
|
|
@ -7,7 +7,7 @@ block content
|
|||
#navigator
|
||||
if profile
|
||||
input(type="hidden", name="username", value="#{profile.username}")
|
||||
|
||||
|
||||
#navigator-top
|
||||
p
|
||||
#navigator-folder
|
||||
|
|
@ -28,21 +28,21 @@ block content
|
|||
form(method="post", action="/editor/settings")
|
||||
.settings-element
|
||||
span Select Font Size (px):
|
||||
span.font-size-value._10px 10
|
||||
span.font-size-value._12px 12
|
||||
span.font-size-value._14px 14
|
||||
span.font-size-value._16px 16
|
||||
span.font-size-value._20px 20
|
||||
span.font-size-value.10px 10
|
||||
span.font-size-value.12px 12
|
||||
span.font-size-value.14px 14
|
||||
span.font-size-value.16px 16
|
||||
span.font-size-value.20px 20
|
||||
.settings-element
|
||||
span Use Soft Tabs:
|
||||
span.soft-tab-value.on On
|
||||
span.soft-tab-value.off Off
|
||||
.settings-element
|
||||
span Tab Size:
|
||||
span.tab-size-value._2-value 2
|
||||
span.tab-size-value._4-value 4
|
||||
span.tab-size-value._6-value 6
|
||||
span.tab-size-value._8-value 8
|
||||
span.tab-size-value.2-value 2
|
||||
span.tab-size-value.4-value 4
|
||||
span.tab-size-value.6-value 6
|
||||
span.tab-size-value.8-value 8
|
||||
.settings-element
|
||||
span Show Invisibles:
|
||||
span.invisibles-value.on On
|
||||
|
|
@ -51,10 +51,6 @@ block content
|
|||
span Manual Git commit and push (advanced)
|
||||
span.manual-git-value.on On
|
||||
span.manual-git-value.off Off
|
||||
.settings-element
|
||||
span Python Version:
|
||||
span.python-version._2 2
|
||||
span.python-version._3 3
|
||||
#editor
|
||||
#editor-output-wrapper
|
||||
.dragbar
|
||||
|
|
@ -68,7 +64,7 @@ block content
|
|||
pre
|
||||
.navbar.navbar-fixed-bottom.navbar-inverse
|
||||
.navbar-inner
|
||||
div.editor-version Adafruit WebIDE v#{version} /
|
||||
div.editor-version Adafruit WebIDE v#{version} /
|
||||
a(href="https://github.com/adafruit/Adafruit-WebIDE/issues", class="", target="_blank") Report Bug
|
||||
div.schedule-footer
|
||||
span.schedule-status Scheduler Active
|
||||
|
|
@ -79,10 +75,10 @@ block content
|
|||
.modal-footer
|
||||
button.btn.btn-primary.modal-yes Save Files
|
||||
button.btn.btn-danger.modal-no Don't Save
|
||||
button.btn.modal-cancel Cancel
|
||||
button.btn.modal-cancel Cancel
|
||||
#manual-git-modal(class="modal hide fade")
|
||||
.modal-header
|
||||
button.close(type="button", data-dismiss="modal", aria-hidden="true") ×
|
||||
button.close(type="button", data-dismiss-"modal", aria-hidden="true") ×
|
||||
h3#create-modal-label Git Commit and Push
|
||||
.modal-body
|
||||
p Add a comment to your edited filed, and click Commit and Push.
|
||||
|
|
@ -91,24 +87,24 @@ block content
|
|||
input(type="text", name="comment", value="")
|
||||
.modal-footer
|
||||
button.btn(data-dismiss="modal", aria-hidden="true") Close
|
||||
button.btn.btn-primary.modal-submit Commit and Push
|
||||
button.btn.btn-primary.modal-submit Commit and Push
|
||||
#create-modal(class="modal hide fade")
|
||||
.modal-header
|
||||
button.close(type="button", data-dismiss="modal", aria-hidden="true") ×
|
||||
button.close(type="button", data-dismiss-"modal", aria-hidden="true") ×
|
||||
h3#create-modal-label
|
||||
.modal-body
|
||||
p
|
||||
p
|
||||
.modal-footer
|
||||
button.btn(data-dismiss="modal", aria-hidden="true") Close
|
||||
button.btn.btn-primary.modal-submit Save
|
||||
#schedule-modal(class="modal hide fade")
|
||||
.modal-header
|
||||
button.close(type="button", data-dismiss="modal", aria-hidden="true") ×
|
||||
button.close(type="button", data-dismiss-"modal", aria-hidden="true") ×
|
||||
h3#create-modal-label Job Scheduler
|
||||
.modal-body
|
||||
p Schedule your script to run at specific time periods. There are many combinations you can use to schedule.
|
||||
| For example, by typing "every 5 minutes" into the input, your script will run every 5 minutes until you tell
|
||||
| it to stop.
|
||||
| it to stop.
|
||||
p You can click a few of the pre-set combinations we've provided to give you an idea of the flexibility
|
||||
| of the parser.
|
||||
div.scheduler-error
|
||||
|
|
@ -125,25 +121,48 @@ block content
|
|||
a(href="", class="btn btn-small") every 2 weeks of the year
|
||||
a(href="", class="btn btn-small") on tuesday at 11:00 am
|
||||
a(href="", class="btn btn-small") on the 1st day of the month
|
||||
a(href="", class="btn btn-small") on the 15,18,20 minute
|
||||
a(href="", class="btn btn-small") on the 15,18,20 minute
|
||||
.modal-footer
|
||||
button.btn(data-dismiss="modal", aria-hidden="true") Close
|
||||
button.btn.btn-primary.modal-submit Submit
|
||||
button.btn.btn-primary.modal-submit Submit
|
||||
#notification-modal(class="modal hide fade")
|
||||
.modal-header
|
||||
button.close(type="button", data-dismiss-"modal", aria-hidden="true") ×
|
||||
h3#create-modal-label WebIDE Message
|
||||
.modal-body
|
||||
p Please ensure your repositories are listed private or public at Bitbucket based on your preferences.
|
||||
p You can validate them by viewing your <a href="https://bitbucket.org" target="_blank">bitbucket profile page</a>
|
||||
| , and looking for the padlock to the left of the repository
|
||||
| name in the "Repositories" sidebar.
|
||||
p To make the repository private or public, click the repository name, and then the gear in the header on the
|
||||
| the repository page. Then click the checkbox in the form to make the repository private or public,
|
||||
| and click submit.
|
||||
p This particular notification will only display one time. Thank you!
|
||||
.modal-footer
|
||||
button.btn(data-dismiss="modal", aria-hidden="true") Dismiss
|
||||
script(type="text/javascript")
|
||||
if(!#{shown_notification}) {
|
||||
setTimeout(function() {
|
||||
$('#notification-modal').modal({show: true, backdrop: 'static'});
|
||||
}, 20000);
|
||||
|
||||
}
|
||||
script(src="/javascripts/ace/ace.js")
|
||||
script(src="/socket.io/socket.io.js")
|
||||
script(src="/term.js")
|
||||
script(src="/options.js")
|
||||
script(src="/tty.js")
|
||||
script(src="/javascripts/trace/d3.v2.min.js")
|
||||
script(src="/javascripts/trace/jquery.ba-bbq.min.js")
|
||||
script(src="/javascripts/trace/jquery.jsPlumb-1.3.10-all-min.js")
|
||||
script(src="/javascripts/trace/pytutor.js")
|
||||
script(src="/javascripts/trace/pytutor.js")
|
||||
script(src="/javascripts/fileupload/js/vendor/jquery.ui.widget.js")
|
||||
script(src="/javascripts/fileupload/js/jquery.fileupload.js")
|
||||
script(src="/javascripts/fileupload/js/jquery.fileupload-ui.js")
|
||||
script(src="/javascripts/fileupload/js/jquery.fileupload-ui.js")
|
||||
script(src="/javascripts/davFS.js")
|
||||
script(src="/xterm.js")
|
||||
script(src="/addons/fit/fit.js")
|
||||
script(src="/addons/attach/attach.js")
|
||||
script(src="/javascripts/later/later-recur.min.js")
|
||||
script(src="/javascripts/later/later.min.js")
|
||||
script(src="/javascripts/jquery.colorbox-min.js")
|
||||
script(src="/javascripts/context_menu.js")
|
||||
script(src="/javascripts/webide_utils.js")
|
||||
script(src="/javascripts/editor.js")
|
||||
script(src="/javascripts/occ_editor.js")
|
||||
|
|
@ -3,6 +3,7 @@ extends layout
|
|||
block content
|
||||
#login-wrapper
|
||||
#login-content
|
||||
p There was an error with your request. Please try again, or visit
|
||||
p There was an error with your request. Please try again, or visit
|
||||
a(href="http://learn.adafruit.com/webide/faq") the FAQ for assistance
|
||||
p #{error}
|
||||
| .
|
||||
p #{error}
|
||||
|
|
@ -6,6 +6,6 @@ head
|
|||
link(rel="stylesheet", href="/javascripts/fileupload/css/jquery.fileupload-ui.css")
|
||||
link(rel="stylesheet", href="/stylesheets/colorbox.css")
|
||||
link(rel="stylesheet", href="/stylesheets/app.css")
|
||||
link(rel="stylesheet", href="/xterm.css")
|
||||
link(rel="stylesheet", href="/style.css")
|
||||
link(rel="stylesheet", href="/stylesheets/pytutor.css")
|
||||
script(src='/javascripts/jquery.min.js')
|
||||
script(src='/javascripts/jquery.min.js')
|
||||
12
views/index.jade
Normal file
12
views/index.jade
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
extends layout
|
||||
|
||||
block content
|
||||
- if (!user)
|
||||
h4 Welcome! Please log in.
|
||||
a(href="/auth/bitbucket") Login with Bitbucket
|
||||
- else
|
||||
h4 Hello, #{user.username}
|
||||
p Please choose a repository
|
||||
for repository in user._json.repositories
|
||||
.repository
|
||||
a(href="/editor/#{repository.name}") #{repository.name}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
!!! 5
|
||||
html
|
||||
include header
|
||||
body
|
||||
|
|
@ -6,9 +7,12 @@ html
|
|||
.container-fluid
|
||||
a.brand(href="/")
|
||||
img(src="/images/WebIDE_Logo_Beta@2x.png", style="height:30px;")
|
||||
p.logout-wrapper
|
||||
- if (typeof profile !== "undefined")
|
||||
a(href="/logout") Log out
|
||||
p.update-wrapper
|
||||
div.connection-state
|
||||
|
||||
#container
|
||||
block content
|
||||
script(src='/javascripts/bootstrap.min.js')
|
||||
script(src='/javascripts/bootstrap.min.js')
|
||||
13
views/oauth_error.jade
Normal file
13
views/oauth_error.jade
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
extends layout
|
||||
|
||||
block content
|
||||
#login-wrapper
|
||||
#login-content
|
||||
p There was an error signing in. It could be any number of reasons, but first ensure that your date/time is set accurately on your Pi.
|
||||
| For More help, visit
|
||||
a(href="http://learn.adafruit.com/webide/faq") the FAQ for assistance
|
||||
| .
|
||||
p To try and repair the error, by setting your date and time, click the below link. You will be redirected to the login page after 5-10 seconds to try login in again.
|
||||
p
|
||||
a(href="/set-datetime") Set the Date and Time
|
||||
p #{error}
|
||||
|
|
@ -11,7 +11,7 @@ block content
|
|||
| of your Pi here. You can also configure the Wifi settings. Both of these
|
||||
| features are optional, and may be skipped.
|
||||
p If you leave these fields blank, they will not overwrite your existing settings.
|
||||
p You can update these settings at any time in the future.
|
||||
p You can update these settings at any time in the future.
|
||||
p Change your Pi Hostname (optional)
|
||||
form(method="post", action="/config", class="form-horizontal")
|
||||
div.control-group
|
||||
|
|
@ -22,7 +22,7 @@ block content
|
|||
div.control-group
|
||||
label(for="port", class="control-label") Port:
|
||||
div.controls
|
||||
input(type="text", name="port", value=port, autocomplete="off")
|
||||
input(type="text", name="port", value=port, autocomplete="off")
|
||||
p Configure your WIFI settings (optional)
|
||||
div.control-group
|
||||
label(for="wifi_ssid", class="control-label") WiFi SSID:
|
||||
|
|
@ -35,4 +35,4 @@ block content
|
|||
p
|
||||
input(type="submit", class="btn btn-primarybtn-large", name="Submit")
|
||||
p Note: It's not recommended to change these settings while accessing the Pi through an external
|
||||
| network, as the connection is not secure.
|
||||
| network, as the connection is not secure.
|
||||
19
views/users/login.jade
Normal file
19
views/users/login.jade
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
extends ../layout
|
||||
|
||||
block content
|
||||
#login-wrapper
|
||||
#login-content
|
||||
if (typeof(session.message) != 'undefined')
|
||||
div.login-info
|
||||
div.alert.alert-info
|
||||
p #{session.message}
|
||||
#{session.message = undefined}
|
||||
if !github
|
||||
img(src="/images/login/login2_logos.jpg")
|
||||
if github
|
||||
a(href="/auth/github", rel="external", class="btn btn-large") Click here to log in to your Github Account
|
||||
else
|
||||
a(href="/auth/bitbucket", rel="external", class="btn btn-large") Click here to log in to your Bitbucket Account
|
||||
.login-help
|
||||
b Need Help?
|
||||
a(href="http://learn.adafruit.com/webide", target="_blank") Learn how to use the Adafruit webIDE here.
|
||||
59
views/users/setup.jade
Normal file
59
views/users/setup.jade
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
extends ../layout
|
||||
|
||||
block content
|
||||
#setup-wrapper
|
||||
#setup-content
|
||||
h3 Welcome to the Adafruit webIDE powered by the Adafruit Learning System
|
||||
if (typeof(session.message) != 'undefined')
|
||||
div.alert.alert-error
|
||||
p #{session.message}
|
||||
p Setting up your Raspberry Pi or Beaglebone will only take a few minutes. Let's get started.
|
||||
p Are you setting up more than one Raspberry Pi or Beaglebone? Visit the config to
|
||||
a(href="/config") change hostname and WiFi.
|
||||
if !github
|
||||
p One of the many useful features of the webIDE is that all of your code will be
|
||||
| stored in the cloud over at bitbucket.org. So, before we can go any further, you
|
||||
| will want to create your free Bitbucket account. If you already have one, you can use
|
||||
| your existing account, or create one specifically for the webIDE.
|
||||
p
|
||||
a.btn.btn-large.btn-info.bitbucket-signup(href="https://bitbucket.org/account/signup/", target="_blank") Click here to create your free bitbucket account
|
||||
p
|
||||
img(src="/images/setup/step1.png")
|
||||
p In your Account page, click on the Integrated Applications link in the left column:
|
||||
p
|
||||
img(src="/images/setup/step2.png")
|
||||
p Now, click on the '+ Add consumer' button:
|
||||
p
|
||||
img(src="/images/setup/step3.png")
|
||||
p For the name, type in Adafruit webIDE, then click the 'Add consumer' button:
|
||||
p
|
||||
img(src="/images/setup/step4.png")
|
||||
p What we are after is the Key, and the Secret text. Copy each of those and paste in the boxes below.
|
||||
p
|
||||
img(src="/images/setup/step5.png")
|
||||
p Copy the key and Secret codes into these text boxes, and then click submit:
|
||||
if github
|
||||
p Enter your Github OAuth Consumer Key and Secret here:
|
||||
form(method="post", action="/setup", class="form-horizontal")
|
||||
div.control-group
|
||||
label(for="key", class="control-label") Key:
|
||||
div.controls
|
||||
input(type="text", name="key", value=consumer_key)
|
||||
div.control-group
|
||||
label(for="secret", class="control-label") Secret:
|
||||
div.controls
|
||||
input(type="text", name="secret", value=consumer_secret)
|
||||
if github
|
||||
p Add your Full Name and Email to attach to saved files at Github (git config)
|
||||
else
|
||||
p Add your Full Name and Email to attach to saved files at Bitbucket (git config)
|
||||
div.control-group
|
||||
label(for="name", class="control-label") Full Name:
|
||||
div.controls
|
||||
input(type="text", name="name", value=name)
|
||||
div.control-group
|
||||
label(for="email", class="control-label") Email:
|
||||
div.controls
|
||||
input(type="text", name="email", value=email)
|
||||
p
|
||||
input(type="submit", class="btn btn-primary btn-large", name="Submit")
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
extends ../layout
|
||||
|
||||
block content
|
||||
#setup-wrapper
|
||||
#setup-content
|
||||
h3 Welcome to the Adafruit webIDE powered by the Adafruit Learning System
|
||||
if (typeof(session.message) != 'undefined')
|
||||
div.alert.alert-error
|
||||
p #{session.message}
|
||||
p Setting up your Raspberry Pi or Beaglebone will only take a few minutes. Let's get started.
|
||||
p Are you setting up more than one Raspberry Pi or Beaglebone? Visit the config to
|
||||
a(href="/config") change hostname and WiFi.
|
||||
form(method="post", action="/setup", class="form-horizontal")
|
||||
p Add your Name and Email for git config
|
||||
div.control-group
|
||||
label(for="name", class="control-label") Full Name:
|
||||
div.controls
|
||||
input(type="text", name="name", value=name)
|
||||
div.control-group
|
||||
label(for="email", class="control-label") Email:
|
||||
div.controls
|
||||
input(type="text", name="email", value=email)
|
||||
p
|
||||
input(type="submit", class="btn btn-primary btn-large", name="Submit")
|
||||
Loading…
Reference in a new issue