Skip to content

Commit b472570

Browse files
committed
clean up github repos synclet, fixes LockerProject#725. Also, make author name/email handling consistent (remove previous locker-only authorName and authorEmail). Finally, update to lastest mkdirp and remove unused node-fs
1 parent 0178187 commit b472570

File tree

9 files changed

+103
-73
lines changed

9 files changed

+103
-73
lines changed

Apps/dashboardv3/static/common

Submodule common updated 1 file

Apps/dashboardv3/static/js/dashboard.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ function doAppHeader(appName) {
142142
registry.getUnConnectedServices(app.uses, function(unconnected) {
143143
registry.getMyAuthoredApps(function(myAuthoredApps) {
144144
var mine = myAuthoredApps[appName];
145-
if (mine) app.author = registry.localAuthor;
145+
if (mine) app.author = {name: registry.localAuthor};
146146
dust.render('appHeader', {
147147
app:app,
148148
connected:connected,

Apps/dashboardv3/static/templates/appHeader.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<span id="appTitle">{app.title}</span>
2-
by <a class="orange iframeLink" href="#" data-id="AppGallery-Author?author={app.authorName}">{app.authorName}</a>{~s}
2+
by <a class="orange iframeLink" href="#" data-id="AppGallery-Author?author={app.author.name}">{app.author.name}</a>{~s}
33
with{~s}{#app.uses.types}<a class="orange iframeLink" href="#" data-id="AppGallery-Filter?types={.}">{.}</a>{@sep} + {/sep}{/app.uses.types}
44
{~s}from
55
<span class='appServices'>

Common/node/lservicemanager.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ exports.mapUpsert = function (file) {
133133
var repo = js.repository;
134134
delete js.repository;
135135
lutil.extend(true, js, repo);
136+
lutil.parseAuthor(js);
136137
if(!js.handle) throw new Error("no handle");
137138
js.handle = js.handle.toLowerCase(); // sanity
138139
// synclets are in their own file, extend them in too
139140
var sync = path.join(lconfig.lockerDir, path.dirname(file),"synclets.json");
140-
if(path.existsSync(sync))
141-
{
141+
if(path.existsSync(sync)) {
142142
js = lutil.extend(js, JSON.parse(fs.readFileSync(sync, 'utf8')));
143143
}
144144
} catch (E) {

Common/node/lutil.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -303,19 +303,21 @@ exports.avatarUrlFromMap = function (storagePath, lockerBase, callback) {
303303
};
304304

305305
exports.parseAuthor = function(js) {
306-
if (!js.author) return;
306+
if (!js.author || typeof js.author !== 'string') return;
307307
js.author = exports.strip(js.author);
308308

309309
if (js.author.indexOf('@') !== -1) {
310310
var match = js.author.match(/(.*)\s*<(.*)>/);
311311
if (match) {
312-
js.authorName = exports.strip(match[1]);
313-
js.authorEmail = exports.strip(match[2]);
312+
js.author = {
313+
name: exports.strip(match[1]),
314+
email: exports.strip(match[2])
315+
};
314316
} else {
315-
js.authorEmail = js.author;
317+
js.author = {email: js.author};
316318
}
317-
} else {
318-
js.authorName = js.author;
319+
} else {
320+
js.author = {name: js.author};
319321
}
320322
};
321323

Connectors/GitHub/repos.js

+82-51
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
var request = require('request')
22
, async = require('async')
3-
, nfs = require('node-fs')
3+
, mkdirp = require('mkdirp')
44
, fs = require('fs')
55
, lockerUrl
66
, auth
@@ -10,8 +10,7 @@ exports.sync = function(processInfo, cb) {
1010
auth = processInfo.auth;
1111
auth.headers = {"Authorization":"token "+auth.accessToken, "Connection":"keep-alive"};
1212
var cached = {};
13-
if (processInfo.config && processInfo.config.cached)
14-
cached = processInfo.config.cached;
13+
if (processInfo.config && processInfo.config.cached) cached = processInfo.config.cached;
1514
lockerUrl = processInfo.lockerUrl;
1615
exports.syncRepos(cached, function(err, repos) {
1716
if (err) console.error(err);
@@ -33,23 +32,15 @@ exports.syncRepos = function(cached, callback) {
3332
if(cached[repo.id] == ckey) return cb(); // if it hasn't changed!
3433
cached[repo.id] = ckey;
3534
// get the watchers, is nice
36-
// logger.debug("checking "+repo.id);
37-
request.get({url:"https://api.github.com/repos/"+repo.id+"/watchers", json:true, headers:auth.headers}, function(err, resp, watchers) {
35+
getWatchers(repo, function(err, resp, watchers) {
3836
repo.watchers = watchers;
3937
// now see if it's an app special on isle 9
40-
request.get({uri:'https://raw.github.com/'+repo.id+'/HEAD/package.json', headers:auth.headers}, function(err, resp, pkg) {
41-
if(err || !pkg) return cb();
42-
try {
43-
pkg = JSON.parse(pkg);
44-
} catch(E) { return cb(); } // this is going to be really hard to catch, but what can we do from here to let someone know? console.error?
45-
var repository = pkg.repository;
46-
if(!(repository && (repository.static == "true" || repository.static == true) && repository.type == "app")) return cb();
38+
getPackage(repo, cb, function(pkg) {
4739
// ok, we've got an app, make sure settings are valid
48-
request.get({uri:"https://api.github.com/repos/" + repo.id + "/git/trees/HEAD?recursive=1", headers:auth.headers, json:true}, function(err, resp, tree) {
40+
getTree(repo, function(err, resp, tree) {
4941
if(err || !tree || !tree.tree) return cb();
5042
syncRepo(repo, tree.tree, function(err) {
51-
if(err)
52-
{
43+
if(err) {
5344
delete cached[repo.id]; // invalidate the cache, it never sync'd
5445
console.error(err);
5546
return cb();
@@ -58,19 +49,25 @@ exports.syncRepos = function(cached, callback) {
5849
pkg.repository.handle = repo.id.replace("/", "-").toLowerCase();
5950
pkg.name = pkg.repository.handle;
6051
pkg.repository.url = 'https://github.com/' + repo.id;
61-
if(!pkg.author) pkg.author = auth.profile.name + ' <'+auth.profile.email+'>';
52+
if(!pkg.author && auth.profile.name) {
53+
pkg.author = {name:auth.profile.name};
54+
if(auth.profile.email) pkg.author.email = auth.profile.email;
55+
}
6256
if(!pkg.version) pkg.version = "0.0.0";
6357
if(!pkg.repository.title) pkg.repository.title = repo.name;
58+
// XXX: hmmm, these next two if statements should never be true since we only sync the repo
59+
// if static == true and type == "app" per line 46 (smurthas)
6460
if(!pkg.repository.hasOwnProperty('static')) pkg.repository.static = true;
6561
if(!pkg.repository.hasOwnProperty('type')) pkg.repository.type = "app";
6662
if(!pkg.repository.hasOwnProperty('update')) pkg.repository.update = "auto";
6763
fs.writeFileSync(repo.id+"/package.json", JSON.stringify(pkg)); // overwriting :/
6864
request.post({url:lockerUrl+'/map/upsert?manifest=Me/github/'+repo.id+'/package.json'}, function(err, resp) {
6965
if(err) console.error(err);
70-
cb();
66+
// XXX: shouldn't we handle this error!!?! (smurthas)
67+
return cb();
7168
});
7269
});
73-
})
70+
});
7471
});
7572
});
7673
}, function(err){
@@ -80,50 +77,84 @@ exports.syncRepos = function(cached, callback) {
8077
}
8178

8279
function getIDFromUrl(url) {
83-
if(typeof url !== 'string')
84-
return url;
80+
if(typeof url !== 'string') return url;
8581
return url.substring(url.lastIndexOf('/', url.lastIndexOf('/') - 1) + 1);
8682
}
8783

88-
function syncRepo(repo, tree, callback)
89-
{
84+
function getWatchers(repo, callback) {
85+
request.get({url:"https://api.github.com/repos/"+repo.id+"/watchers",
86+
headers:auth.headers, json:true}, callback);
87+
}
88+
89+
function getPackage(repo, notAppCallback, isAppCallback) {
90+
request.get({uri: 'https://raw.github.com/'+repo.id+'/HEAD/package.json',
91+
headers:auth.headers}, function(err, resp, pkg) {
92+
if(resp.statusCode === 404) return notAppCallback();
93+
try {
94+
pkg = JSON.parse(pkg);
95+
if(!isApp(pkg)) return notAppCallback();
96+
} catch(E) {
97+
console.error('for repo ' + repo.id + ', found a package.json, but couldn\'t parse it, or it wasn\'t an app', pkg);
98+
return notAppCallback();
99+
} // this is going to be really hard to catch, but what can we do from here to let someone know?
100+
return isAppCallback(pkg);
101+
});
102+
}
103+
104+
function getTree(repo, callback) {
105+
request.get({uri:"https://api.github.com/repos/" + repo.id + "/git/trees/HEAD?recursive=1",
106+
headers:auth.headers, json:true}, callback);
107+
}
108+
109+
function isApp(pkg) {
110+
var repository = pkg.repository;
111+
return repository && (repository.static == "true" || repository.static == true) && repository.type == "app";
112+
}
113+
114+
function syncRepo(repo, tree, callback) {
90115
var existing = {};
91116
try {
92117
var oldtree = JSON.parse(fs.readFileSync(repo.id+".tree.json"));
93-
for(var i=0; i < oldtree.length; i++)
94-
{
95-
existing[oldtree[i].path] = oldtree[i].sha;
96-
}
97-
} catch(e){};
118+
for(var i in oldtree) existing[oldtree[i].path] = oldtree[i].sha;
119+
} catch(e) {
120+
if(e.code !== 'ENOENT') return callback(e);
121+
}
98122
// make sure there's at least one tree entry for the repo dir itself
99123
tree.push({path:".",sha:"na",type:"tree"});
100-
async.forEach(tree, function(t, cb){
101-
if(t.type != "tree") return cb();
102-
if(existing[t.path] == t.sha) return cb(); // no changes
103-
nfs.mkdir(repo.id + "/" + t.path, 0777, true, cb);
104-
}, function(){
124+
async.forEachSeries(tree, function(t, cbTree) {
125+
if(t.type !== "tree") return cbTree();
126+
if(existing[t.path] === t.sha) return cbTree(); // no changes
127+
mkdirp(repo.id + "/" + t.path, 0777, function(err) {
128+
if(err && err.code !== 'EEXIST') return cbTree(err);
129+
return cbTree();
130+
});
131+
}, function(err) {
105132
// then the blobs
106133
var errors = [];
107-
async.forEachSeries(tree, function(t, cb){
108-
if(t.type != "blob") return cb();
109-
if(existing[t.path] == t.sha) return cb(); // no changes
110-
request.get({uri:'https://raw.github.com/'+repo.id+'/HEAD/'+t.path, encoding: 'binary', headers:auth.headers}, function(err, resp, body) {
111-
// logger.debug(resp.statusCode + " for "+ t.path);
112-
if(err || !resp || resp.statusCode != 200) {
113-
// don't save the sha so it gets retried again
114-
errors.push(repo.id+": error fetching "+t.path+" status code "+(resp ? resp.statusCode : 0)+" body "+body);
115-
t.sha = "";
116-
return cb();
117-
}
118-
if (body) {
119-
fs.writeFile(repo.id + "/" + t.path, body, 'binary', cb);
120-
} else {
121-
cb();
122-
}
134+
async.forEachSeries(tree, function(treeItem, cb) {
135+
return saveBlob(treeItem, repo, existing, cb);
136+
}, function(err) {
137+
fs.writeFile(repo.id+".tree.json", JSON.stringify(tree), function(err) {
138+
if(err) errors.push(err);
139+
return callback(errors.length > 0 ? errors : null);
123140
});
124-
}, function(){
125-
fs.writeFile(repo.id+".tree.json", JSON.stringify(tree));
126-
callback(errors.length > 0 ? errors : null);
127141
});
128142
});
129143
}
144+
145+
function saveBlob(treeItem, repo, existing, cb) {
146+
if(treeItem.type !== "blob") return cb();
147+
if(existing[treeItem.path] === treeItem.sha) return cb(); // no changes
148+
request.get({uri:'https://raw.github.com/'+repo.id+'/HEAD/'+treeItem.path,
149+
encoding: 'binary',
150+
headers:auth.headers},
151+
function(err, resp, body) {
152+
if(err || !resp || resp.statusCode !== 200 || body === undefined || body === null) {
153+
// don't save the sha so it gets retried again
154+
errors.push(repo.id+": error fetching "+repo.id + "/" + treeItem.path+" status code "+(resp ? resp.statusCode : 0)+" body "+body);
155+
treeItem.sha = "";
156+
return cb();
157+
}
158+
fs.writeFile(repo.id + "/" + treeItem.path, body, 'binary', cb);
159+
});
160+
}

package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@
5050
"ejs": "=0.4.3",
5151
"forever": "=0.6.7",
5252
"graceful-fs": "1.1.2",
53-
"node-fs": "=0.1.0",
5453
"nodemailer": "=0.2.3",
5554
"semver": "=1.0.10",
5655
"ini": "=1.0.1",
5756
"uglify-js": "=1.1.1",
5857
"connect-form": "0.2.1",
5958
"imagemagick": "https://github.com/lpatters/node-imagemagick/tarball/master",
6059
"moment": "=1.3.0",
60+
"mkdirp": "0.3.0",
6161

6262

6363
"hashish": "=0.0.4",
@@ -74,7 +74,6 @@
7474
"wordwrap": "0.0.2",
7575
"pkginfo": "0.2.2",
7676
"commander": "0.5.1",
77-
"mkdirp": "0.0.7",
7877
"underscore": "1.1.7",
7978
"htmlparser2": "1.0.0",
8079
"loggly": "0.3.8",

test/common/lutil.test.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -155,20 +155,20 @@ describe("lutil", function () {
155155
it("parses the full name/email format", function() {
156156
var data = {author : "E. X. Ample <[email protected]>"};
157157
lutil.parseAuthor(data);
158-
data.authorName.should.equal("E. X. Ample");
159-
data.authorEmail.should.equal("[email protected]");
158+
data.author.name.should.equal("E. X. Ample");
159+
data.author.email.should.equal("[email protected]");
160160
});
161161

162162
it("parses just an email", function() {
163163
var data = {author: "[email protected]"};
164164
lutil.parseAuthor(data);
165-
data.authorEmail.should.equal("[email protected]");
165+
data.author.email.should.equal("[email protected]");
166166
});
167167

168168
it("parses just a name", function() {
169169
var data = {author: "E. X. Ample"};
170170
lutil.parseAuthor(data);
171-
data.authorName.should.equal("E. X. Ample");
171+
data.author.name.should.equal("E. X. Ample");
172172
});
173173
});
174174

tests/integration/spec/integration/dashboard_spec.rb

+3-5
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22

33
#describe 'home page', :type => :request do
44
describe 'dashboard' do
5-
it 'allows people to see the connect page' do
5+
it 'allows people to see the EXPLORE page' do
66
visit '/'
7-
within_frame 'appFrame' do
8-
page.should have_content("Nobody Selected")
9-
end
7+
page.should have_content("Contacts (DEMO)by Singly, Inc. with contacts from { see the code }")
108
end
119

12-
it 'should allow people to access the develop interface' do
10+
it 'should allow people to access the DEVELOP page' do
1311
visit '/'
1412
click_link 'Develop'
1513
within_frame 'appFrame' do

0 commit comments

Comments
 (0)