Comparing version 0.6.0-9 to 0.6.1-14
@@ -17,2 +17,3 @@ exports.login = require('./lib/login.js'); | ||
exports.configuration = require('./lib/configuration.js'); | ||
exports.account = require('./lib/account.js'); | ||
100
lib/build.js
module.exports = build; | ||
build.usage = "\nfhc build app=<appId> destination=<destination> version=<version> config=<config> keypass=<private key password> certpass=<certificate password>" | ||
build.usage = "\nfhc build app=<appId> destination=<destination> version=<version> config=<config> keypass=<private key password> certpass=<certificate password> download=<true|false> provisioning=<path to provisioning profile>" | ||
+ "\nwhere <destination> is one of: andriod, iphone, ipad, blackberry, windowsphone7" | ||
+ "\nwhere <version> is specific to the destination, see supported destinations here: http://www.feedhenry.com/TODO" | ||
+ "\nwhere <config> is either 'debug' (default), 'distribution', or 'release'" | ||
+ "\n'keypass' and 'certpass' only needed for 'release' builds"; | ||
+ "\nwhere <provisioning> is the path to the provisioning profile" | ||
+ "\n'keypass' and 'certpass' only needed for 'release' builds" | ||
+ "\n'provisioning' is only optional for iphone or ipad builds"; | ||
@@ -16,2 +18,8 @@ var log = require("./utils/log"); | ||
var async = require('async'); | ||
var sys = require("util"); | ||
var http = require("http"); | ||
var url = require("url"); | ||
var path = require("path"); | ||
var fs = require("fs"); | ||
var events = require("events"); | ||
@@ -74,17 +82,77 @@ // main build entry point | ||
var uri = "box/srv/1.1/wid/" + fhc.domain + "/" + args.destination + "/" + args.app + "/deliver"; | ||
var payload = argsToPayload(args); | ||
common.doApiCall(fhreq.getFeedHenryUrl(), uri, payload, "Error reading app: ", function(err, data) { | ||
if(err) return cb(err); | ||
var keys = []; | ||
if(data.cacheKey) keys.push(data.cacheKey); | ||
if(data.stageKey) keys.push(data.stageKey); | ||
if(keys.length > 0) { | ||
async.map(keys, common.waitFor, function(err, results) { | ||
return cb(err, results); | ||
}); | ||
} else { | ||
return cb(err, data); | ||
} | ||
}); | ||
var doCall = function(){ | ||
var payload = argsToPayload(args); | ||
common.doApiCall(fhreq.getFeedHenryUrl(), uri, payload, "Error reading app: ", function(err, data) { | ||
if(err) return cb(err); | ||
var keys = []; | ||
if(data.cacheKey) keys.push(data.cacheKey); | ||
if(data.stageKey) keys.push(data.stageKey); | ||
if(keys.length > 0) { | ||
async.map(keys, common.waitFor, function(err, results) { | ||
if (results[0] !== undefined) { | ||
var build_asset = results[0][0].action.url; | ||
downloadBuild(args, build_asset, null, function() { | ||
return cb(err, results); | ||
}); | ||
} | ||
}); | ||
} else { | ||
return cb(err, data); | ||
} | ||
}); | ||
} | ||
if((args.destination === "iphone" || args.destination === "ipad") && args.provisioning){ | ||
var resourceUrl = "/box/srv/1.1/dev/account/res/upload"; | ||
var fields = {dest: args.destination, resourceType: 'provisioning', buildType: args.config, templateInstance: args.app}; | ||
fhreq.uploadFile(resourceUrl, args.provisioning, fields, "application/octet-stream", function(err, data){ | ||
if(data.result && data.result === "ok"){ | ||
log.info("Provisioning profile uploaded"); | ||
doCall(); | ||
} else { | ||
cb(err, "Failed to upload provisioning profile. Response is " + JSON.stringify(data)); | ||
} | ||
}) | ||
} else { | ||
doCall(); | ||
} | ||
}; | ||
function downloadBuild(args, asset_url, path, callback) { | ||
if (args.download !== 'true') { return callback(); } | ||
var host = url.parse(asset_url).hostname; | ||
var filename = url.parse(asset_url).pathname.split("/").pop(); | ||
var theurl = http.createClient(80, host); | ||
var requestUrl = asset_url; | ||
log.info("Downloading file: " + filename); | ||
log.info("Before download request"); | ||
var request = theurl.request('GET', requestUrl, {"host": host}); | ||
request.end(); | ||
var bar = null; | ||
var dlprogress = 0; | ||
setInterval(function () { | ||
log.info("Download progress: " + dlprogress + " bytes"); | ||
}, 1000); | ||
request.addListener('response', function (response) { | ||
var downloadfile = fs.createWriteStream(filename, {'flags': 'a'}); | ||
var filesize = parseInt(response.headers['content-length']); | ||
log.info("File size " + filename + ": " + filesize + " bytes."); | ||
response.addListener('data', function (chunk) { | ||
dlprogress += chunk.length; | ||
downloadfile.write(chunk, encoding='binary'); | ||
}); | ||
response.addListener("end", function() { | ||
downloadfile.end(); | ||
log.info("Finished downloading " + filename); | ||
return callback(); | ||
}); | ||
}); | ||
} |
@@ -194,3 +194,27 @@ // Misc common functions.. | ||
// Create a generic Table from a single object. The object keys will be the table headers. | ||
function createObjectTable(obj) { | ||
var heads = [], colWidths = [], vals = []; | ||
for (var k in obj) { | ||
heads.push(k.replace( /(^|\s)([a-z])/g , function(m,p1,p2){ return p1+p2.toUpperCase();})); | ||
var v = "" + obj[k]; | ||
vals.push(v); | ||
var width = Math.max(strlen(k), strlen(v)) + 2; | ||
if (width > exports.maxTableCell) width = exports.maxTableCell; | ||
colWidths.push(width); | ||
} | ||
var table = new Table({ | ||
head: heads, | ||
colWidths: colWidths, | ||
style: exports.style() | ||
}); | ||
table.push(vals); | ||
return table; | ||
}; | ||
exports.createNVTable = createNVTable; | ||
exports.createObjectTable = createObjectTable; | ||
exports.listApps = listApps; | ||
@@ -197,0 +221,0 @@ exports.readApp = readApp; |
@@ -45,2 +45,6 @@ module.exports = df; | ||
}; | ||
case "restart": { | ||
if (args.length != 1) return unknown("restart", cb); | ||
else return restart(args[0], cb); | ||
}; | ||
case "url": { | ||
@@ -104,8 +108,11 @@ if (args.length != 1) return unknown("url", cb); | ||
// calculate widths | ||
var maxApp=4, maxDynoMan=8, maxPort=5, maxState=5; | ||
var maxApp=4, maxDynoMan=8, maxPort=5, maxState=5, maxUrl = 3; | ||
for (var a in apps) { | ||
if (common.strlen(a) > maxApp) maxApp = common.strlen(a); | ||
if(common.strlen(a) > maxApp) maxApp = common.strlen(a); | ||
var url = getAppUrl(a); | ||
if(common.strlen(url) > maxUrl) maxUrl = common.strlen(url); | ||
var app = apps[a]; | ||
if(common.strlen(app.host) > maxDynoMan) maxDynoMan = common.strlen(app.host); | ||
if(common.strlen(app.dynoman) > maxDynoMan) maxDynoMan = common.strlen(app.dynoman); | ||
if(common.strlen(app.port) > maxPort) maxPort = common.strlen(app.port); | ||
@@ -117,4 +124,4 @@ if(common.strlen(app.state) > maxState) maxState = common.strlen(app.state); | ||
df.table = new Table({ | ||
head: ['App', 'DynoMan', 'Port', 'State'], | ||
colWidths: [maxApp +2 , maxDynoMan + 2, maxPort + 2, maxState + 2], | ||
head: ['App', 'Url', 'DynoMan', 'Port', 'State'], | ||
colWidths: [maxApp+2 , maxUrl+2, maxDynoMan+2, maxPort+2, maxState+2], | ||
style: common.style() | ||
@@ -125,4 +132,5 @@ }); | ||
for (var a in apps) { | ||
var url = getAppUrl(a); | ||
var app = apps[a]; | ||
df.table.push([a, app.host, app.port, app.state]); | ||
df.table.push([a, url, app.dynoman, app.port || '-', app.state]); | ||
} | ||
@@ -167,6 +175,39 @@ } | ||
request(getDynoFarmUrl() + "start/" + appId, function (err, response, body) { | ||
return cb(nullToUndefined(err), body); | ||
if(err) return cb(err); | ||
var app; | ||
try{ | ||
app = JSON.parse(body); | ||
} catch (x) { | ||
return cb("Error parsing app: " + util.inspect(body) + " error: " + util.inspect(x)); | ||
} | ||
if(ini.get('table') === true) { | ||
df.table = common.createObjectTable(app); | ||
} | ||
return cb(nullToUndefined(err), app); | ||
}); | ||
}; | ||
// Restart app | ||
function restart(appId, cb) { | ||
request(getDynoFarmUrl() + "restart/" + appId, function (err, response, body) { | ||
if(err) return cb(err); | ||
if(response.statusCode !== 200) return cb("Bad response: " + response.statusCode + " " + body); | ||
var app; | ||
try{ | ||
app = JSON.parse(body); | ||
} catch (x) { | ||
return cb("Error parsing app: " + util.inspect(body) + " error: " + util.inspect(x)); | ||
} | ||
if(ini.get('table') === true) { | ||
df.table = common.createObjectTable(app); | ||
} | ||
return cb(nullToUndefined(err), app); | ||
}); | ||
}; | ||
// Given an app id, returns its DynoFarm endpoint | ||
@@ -173,0 +214,0 @@ function url(appId, cb) { |
@@ -67,2 +67,3 @@ | ||
,'build' | ||
,'ota' | ||
,'fhcfg' | ||
@@ -85,2 +86,3 @@ ,'completion' | ||
,'version' | ||
,'account' | ||
] | ||
@@ -87,0 +89,0 @@ , plumbing = [ |
@@ -37,86 +37,12 @@ | ||
log.silly(file, "app import"); | ||
var boundary = Math.random(); | ||
var post_data = []; | ||
post_data.push(new Buffer(EncodeFieldPart(boundary, 'type', 'feedhenry'), 'ascii')); | ||
post_data.push(new Buffer(EncodeFieldPart(boundary, 'location', file), 'ascii')); | ||
post_data.push(new Buffer(EncodeFilePart(boundary, 'application/zip', 'location', file), 'ascii')); | ||
var file_reader = fs.createReadStream(file, {encoding: 'binary'}); | ||
var file_contents = ''; | ||
file_reader.on('data', function(data){ | ||
file_contents += data; | ||
var url = '/box/srv/1.1/ide/apps/app/import?location=appanat.zip'; | ||
fhreq.uploadFile(url, file, {type:'feedhenry', location: file}, 'application/zip', function(err, data){ | ||
if(data.status == 'pending') { | ||
return common.waitForJob(data.cacheKey, 0, cb); | ||
}else { | ||
return cb(undefined, data); | ||
} | ||
}); | ||
file_reader.on('end', function(){ | ||
post_data.push(new Buffer(file_contents, 'binary')); | ||
post_data.push(new Buffer("\r\n--" + boundary + "--"), 'ascii'); | ||
doUpload(post_data, boundary, cb); | ||
}); | ||
}; | ||
// Field encoding | ||
function EncodeFieldPart(boundary,name,value) { | ||
var return_part = "--" + boundary + "\r\n"; | ||
return_part += "Content-Disposition: form-data; name=\"" + name + "\"\r\n\r\n"; | ||
return_part += value + "\r\n"; | ||
return return_part; | ||
} | ||
// File encoding | ||
function EncodeFilePart(boundary,type,name,filename) { | ||
var return_part = "--" + boundary + "\r\n"; | ||
return_part += "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"; | ||
return_part += "Content-Type: " + type + "\r\n\r\n"; | ||
return return_part; | ||
} | ||
// do the actual upload | ||
function doUpload(post_data, boundary, cb) { | ||
var length = 0; | ||
for(var i = 0; i < post_data.length; i++) { | ||
length += post_data[i].length; | ||
} | ||
var post_options = { | ||
host: url.parse(fhreq.getFeedHenryUrl()).hostname, | ||
port: '443', | ||
path: '/box/srv/1.1/ide/apps/app/import?location=appanat.zip', | ||
method: 'POST', | ||
headers : { | ||
'Content-Type' : 'multipart/form-data; boundary=' + boundary, | ||
'Content-Length' : length, | ||
'Cookie' : "feedhenry=" + fhc.config.get("cookie") + ";" | ||
} | ||
}; | ||
var post_request = https.request(post_options, function(response){ | ||
response.setEncoding('utf8'); | ||
var data = ''; | ||
response.on('data', function(chunk){ | ||
data = data + chunk; | ||
}); | ||
response.on('end', function(){ | ||
log.silly(data, 'app import'); | ||
data = JSON.parse(data); | ||
if(data.status == 'pending') { | ||
return common.waitForJob(data.cacheKey, 0, cb); | ||
}else { | ||
return cb(undefined, data); | ||
} | ||
}); | ||
response.on('error', function(err) { | ||
return cb(err); | ||
}); | ||
}); | ||
for (var i = 0; i < post_data.length; i++) { | ||
post_request.write(post_data[i]); | ||
} | ||
post_request.end(); | ||
} | ||
@@ -8,2 +8,3 @@ | ||
request.upload = upload; | ||
request.uploadFile = uploadFile; | ||
request.getFeedHenryUrl = getFeedHenryUrl; | ||
@@ -295,2 +296,87 @@ request.getMessagingUrl = getMessagingUrl; | ||
function uploadFile(url, filepath, fields, contentType, cb){ | ||
var boundary = Math.random(); | ||
var post_data = []; | ||
var path = require('path'); | ||
var filename = path.basename(filepath); | ||
for(var key in fields){ | ||
post_data.push(new Buffer(EncodeFieldPart(boundary, key, fields[key]), 'ascii')); | ||
} | ||
post_data.push(new Buffer(EncodeFilePart(boundary, contentType, 'file', filename), 'ascii')); | ||
var file_reader = fs.createReadStream(filepath, {encoding: 'binary'}); | ||
var file_contents = ''; | ||
file_reader.on('data', function(data){ | ||
file_contents += data; | ||
}); | ||
file_reader.on('end', function(){ | ||
post_data.push(new Buffer(file_contents, 'binary')); | ||
post_data.push(new Buffer("\r\n--" + boundary + "--"), 'ascii'); | ||
doUploadFile(url, post_data, boundary, cb); | ||
}); | ||
} | ||
// Field encoding | ||
function EncodeFieldPart(boundary,name,value) { | ||
var return_part = "--" + boundary + "\r\n"; | ||
return_part += "Content-Disposition: form-data; name=\"" + name + "\"\r\n\r\n"; | ||
return_part += value + "\r\n"; | ||
return return_part; | ||
} | ||
// File encoding | ||
function EncodeFilePart(boundary,type,name,filename) { | ||
var return_part = "--" + boundary + "\r\n"; | ||
return_part += "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"; | ||
return_part += "Content-Type: " + type + "\r\n\r\n"; | ||
return return_part; | ||
} | ||
// do the actual upload | ||
function doUploadFile(urlpath, post_data, boundary, cb) { | ||
var length = 0; | ||
for(var i = 0; i < post_data.length; i++) { | ||
length += post_data[i].length; | ||
} | ||
var url = require('url'); | ||
var https = https || require('https'); | ||
var post_options = { | ||
host: url.parse(getFeedHenryUrl()).hostname, | ||
port: '443', | ||
path: urlpath, | ||
method: 'POST', | ||
headers : { | ||
'Content-Type' : 'multipart/form-data; boundary=' + boundary, | ||
'Content-Length' : length, | ||
'Cookie' : "feedhenry=" + fhc.config.get("cookie") + ";" | ||
} | ||
}; | ||
var post_request = https.request(post_options, function(response){ | ||
response.setEncoding('utf8'); | ||
var data = ''; | ||
response.on('data', function(chunk){ | ||
data = data + chunk; | ||
}); | ||
response.on('end', function(){ | ||
log.silly(data, 'app import'); | ||
data = JSON.parse(data); | ||
return cb(undefined, data); | ||
}); | ||
response.on('error', function(err) { | ||
return cb(err); | ||
}); | ||
}); | ||
for (var i = 0; i < post_data.length; i++) { | ||
post_request.write(post_data[i]); | ||
} | ||
post_request.end(); | ||
} | ||
function File (name, cb) { | ||
@@ -297,0 +383,0 @@ var f = this; |
@@ -5,3 +5,3 @@ { | ||
"keywords" : [ "cli", "feedhenry" ], | ||
"version": "0.6.0-9", | ||
"version": "0.6.1-14", | ||
"preferGlobal" : true, | ||
@@ -8,0 +8,0 @@ "homepage" : "http://git.io/fh-fhc", |
@@ -1,1 +0,1 @@ | ||
0.6.0-9 | ||
0.6.1-14 |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
221581
84
5123
66
11