-
Notifications
You must be signed in to change notification settings - Fork 15
/
local.js
154 lines (129 loc) · 3.33 KB
/
local.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
* This is specifically for the builder where the
* dependencies have been resolved and you just want
* to access the component.jsons locally.
*/
var semver = require('semver');
var fs = require('graceful-fs');
var join = require('path').join;
var resolve = require('path').resolve;
var debug = require('debug')('remotes:local');
var Remote = require('../remote')
module.exports = Local
Remote.extend(Local)
function Local(options) {
if (!(this instanceof Local))
return new Local(options)
options = Object.create(options || {});
this.out = resolve(options.out
|| options.dir
|| 'components')
debug('checking local components at %s', this.out);
Remote.call(this, options)
}
Local.prototype.name = 'local';
/**
* Local resolution is a little different than other remotes.
* In particular, if no `ref` is set,
* we check for any version.
*
* @param {String} repo
* @return {this}
* @api public
*/
Local.prototype.resolve = function* (remotes, repo, ref) {
debug('resolving local remote');
if (typeof remotes === 'string') {
ref = repo;
repo = remotes;
} else if (Array.isArray(remotes) && !~remotes.indexOf('local')) {
// if the current remote is not in this list,
// then it's obviously not valid.
return;
}
var folders = yield* this.folders(repo);
// none installed
if (!folders || !folders.length) return;
// no specific version we care about
if (!ref) return this;
// exact tag version
if (~folders.indexOf(ref)) return this;
// check for equal semantic versions
if (semver.maxSatisfying(folders.filter(valid), ref)) return this;
}
/**
* Get the currently downloaded versions of a repo.
*
* @param {String} repo
* @return {Array} folders
* @api public
*/
Local.prototype.folders = function* (repo) {
try {
var frags = repo.toLowerCase().split('/');
// ignore malformed repos for now
if (frags.length !== 2) return;
var folder = join(this.out, frags[0], frags[1]);
debug('checking folder: %s', folder);
var folders = yield readdir(folder);
debug('got folders: %s', folders.join(', '));
return folders.filter(noLeadingDot);
} catch (err) {
if (err.code === 'ENOENT') return;
throw err;
}
}
/**
* Return the currently downloaded components' semantic versions.
*
* @param {String} repo
* @return {Array} references
* @api public
*/
Local.prototype._versions = function* (repo) {
return yield* this.folders(repo);
}
/**
* Return the existing component.json, if any.
* @param {String} repo
* @param {String} reference
* @return {Object} component.json
* @api public
*/
Local.prototype._json = function* (repo, ref) {
var body;
var filename = join(this.out, repo, ref, 'component.json');
try {
body = yield read(filename);
} catch (err) {
if (err.code === 'ENOENT') return;
throw err;
}
try {
return JSON.parse(body);
} catch (_err) {
throw new Error('JSON parsing error with "' + filename + '"');
}
}
/**
* NOT RELEVANT WITH THIS REMOTE
*/
Local.prototype._tree = function* () {
/* jshint noyield:true */
}
function valid(x) {
return semver.valid(x, true);
}
function noLeadingDot(x) {
return x[0] !== '.';
}
function readdir(root) {
return function (done) {
fs.readdir(root, done)
}
}
function read(filename) {
return function (done) {
fs.readFile(filename, 'utf8', done)
}
}