Skip to content

Commit d4ff8d7

Browse files
committed
v1.2.6
1 parent 93eb4b6 commit d4ff8d7

9 files changed

Lines changed: 309 additions & 75 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
### 1.2.6
2+
3+
* Fix `fs.chmodSync: Error: ENOENT` for existing projects
4+
* Fix lib update
5+
* Add ionic app task
6+
* Starter projects can provide `app.json` to specify plugins and sass setup
7+
8+
19
### 1.2.5
210

311
* Do not watch `www/lib/` files by default

lib/ionic.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,19 @@ var TASKS = [
223223
title: 'address',
224224
name: 'address',
225225
module: './ionic/serve'
226-
}
226+
},
227+
{
228+
title: 'app',
229+
name: 'app',
230+
// summary: 'Deploy a new Ionic app version or list versions',
231+
// options: {
232+
// '--versions|-v': 'List recently uploaded versions of this app',
233+
// '--deploy|-d': 'Upload the current working copy and mark it as deployed',
234+
// '--note|-n': 'Add a note to a deploy',
235+
// '--uuid|-u': 'Mark an already uploaded version as deployed'
236+
// },
237+
module: './ionic/app'
238+
}
227239
];
228240

229241
Ionic = {

lib/ionic/app.js

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
var fs = require('fs'),
2+
path = require('path'),
3+
parseUrl = require('url').parse,
4+
request = require('request'),
5+
argv = require('optimist').argv,
6+
FormData = require('form-data'),
7+
IonicProject = require('./project'),
8+
IonicTask = require('./task').IonicTask,
9+
IonicStats = require('./stats').IonicStats;
10+
Task = require('./task').Task,
11+
IonicLoginTask = require('./login').IonicTask,
12+
IonicUploadTask = require('./upload').IonicTask;
13+
14+
var IonicTask = function() {};
15+
16+
IonicTask.prototype = new Task();
17+
18+
IonicTask.prototype.run = function(ionic) {
19+
var self = this;
20+
21+
self.ionic = ionic;
22+
self.inputValues = {};
23+
self.useCmdArgs = false;
24+
25+
this.getCmdLineOptions();
26+
27+
var login = new IonicLoginTask();
28+
login.get(ionic, function(jar) {
29+
self.jar = jar;
30+
31+
if (argv['versions'] || argv.v) {
32+
self.versions(self);
33+
} else if (argv['deploy'] || argv.d) {
34+
if (!self.inputValues['uuid']) {
35+
// Deploying a new version
36+
var upload = new IonicUploadTask();
37+
38+
upload.setNote(self.inputValues['note'] || '');
39+
upload.run(self.ionic, function() {
40+
self.deploy(self);
41+
});
42+
} else {
43+
self.deploy(self);
44+
}
45+
}
46+
});
47+
};
48+
49+
IonicTask.prototype.versions = function(self) {
50+
var project = IonicProject.load();
51+
52+
if (!project.get('app_id')) {
53+
console.log("No versions uploaded!".bold.red);
54+
return false;
55+
}
56+
57+
var form = new FormData();
58+
form.append('csrfmiddlewaretoken', self.jar.cookies[0].value);
59+
60+
var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/versions';
61+
var params = parseUrl(url);
62+
63+
form.submit({
64+
protocol: params.protocol,
65+
hostname: params.hostname,
66+
port: params.port,
67+
path: params.path,
68+
headers: form.getHeaders({
69+
cookie: self.jar.cookies.map(function (c) {
70+
return c.name + "=" + encodeURIComponent(c.value);
71+
}).join("; ")
72+
})
73+
},
74+
function (err, response) {
75+
if (err) {
76+
return self.ionic.fail('Error logging in: ' + err);
77+
}
78+
79+
response.setEncoding('utf8');
80+
response.on("data", function(data) {
81+
try {
82+
var d = JSON.parse(data);
83+
if (d.errors && d.errors.length) {
84+
for (var j = 0; j < d.errors.length; j++) {
85+
console.log((d.errors[j]).bold.error);
86+
}
87+
return self.ionic.fail('Unable to fetch versions list');
88+
}
89+
90+
var heading = [' UUID ', ' Created ', ' Note '];
91+
var heading_underline = ['------------', '----------', '----------------------------']
92+
93+
console.log(heading.join('\t'));
94+
console.log(heading_underline.join('\t'));
95+
96+
for (var j = 0; j < d.length; j++) {
97+
var active = (d[j].active) ? ' *' : ' ';
98+
var uuid = (d[j].active) ? d[j].uuid.substring(0,8).green : d[j].uuid.substring(0,8);
99+
var note = d[j].note.substring(0,25) || '\t';
100+
101+
console.log([active + ' ' + uuid, ' ' + d[j].created, ' ' + note].join('\t'));
102+
}
103+
} catch(parseEx) {
104+
return self.ionic.fail('Error response: ' + parseEx);
105+
}
106+
});
107+
});
108+
}
109+
110+
IonicTask.prototype.deploy = function(self) {
111+
var project = IonicProject.load();
112+
113+
var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/deploy';
114+
115+
request({
116+
method: 'POST',
117+
url: url,
118+
jar: self.jar,
119+
form: {
120+
uuid: self.inputValues['uuid'],
121+
csrfmiddlewaretoken: self.jar.cookies[0].value
122+
},
123+
headers: {
124+
cookie: self.jar.cookies.map(function (c) {
125+
return c.name + "=" + encodeURIComponent(c.value);
126+
}).join("; ")
127+
}
128+
},
129+
function (err, response, body) {
130+
if (err) {
131+
return self.ionic.fail('Error deploying version: ' + err);
132+
}
133+
134+
try {
135+
var d = JSON.parse(body);
136+
if (d.errors && d.errors.length) {
137+
for (var j = 0; j < d.errors.length; j++) {
138+
console.log((d.errors[j]).bold.error);
139+
}
140+
return self.ionic.fail('Unable to deploy version');
141+
}
142+
143+
console.log("Successfully deployed " + d.uuid);
144+
145+
} catch (parseEx) {
146+
return self.ionic.fail('Error response: ' + parseEx);
147+
}
148+
}
149+
);
150+
};
151+
152+
IonicTask.prototype.getCmdLineOptions = function() {
153+
var self = this;
154+
155+
function getCmdArgValue(propertyName, shortName) {
156+
var value = argv[propertyName] || argv[shortName];
157+
if(value) {
158+
self.inputValues[propertyName] = value;
159+
self.useCmdArgs = true;
160+
}
161+
}
162+
163+
getCmdArgValue('note', 'n');
164+
getCmdArgValue('uuid', 'u');
165+
};
166+
167+
exports.IonicTask = IonicTask;

lib/ionic/cordova.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ IonicTask.prototype.addHooks = function() {
221221
}
222222

223223
var projectScript = path.join(projectHookPath, hookFilename);
224-
if( !fs.existsSync(projectHookPath) ) {
224+
if( !fs.existsSync(projectScript) ) {
225225
// copy the hook script to the project
226226
try {
227227
var cliScript = path.join(cliHookPath, hookFilename);

lib/ionic/lib.js

Lines changed: 61 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ IonicTask.prototype.getVersionData = function(version) {
9999
return;
100100
}
101101
self.versionData = JSON.parse(body);
102+
self.versionData.version_number = self.versionData.version_number || self.versionData.version;
103+
self.versionData.version_codename = self.versionData.version_codename || self.versionData.codename;
104+
self.versionData.release_date = self.versionData.release_date || self.versionData.date;
105+
102106
q.resolve();
103107
} catch(e) {
104108
console.log('Error loading '.bold.error + version.bold + ' version information'.bold.error );
@@ -192,40 +196,33 @@ IonicTask.prototype.downloadZip = function(version) {
192196
var self = this;
193197

194198
var archivePath = 'https://github.com/driftyco/ionic-bower/archive/v' + version + '.zip';
195-
self.tmpZipPath = path.resolve('www/lib/ionic/ionic.zip');
196199

197-
console.log('Downloading: '.green.bold + archivePath);
200+
self.tmpExtractPath = path.resolve('www/lib/.ionic');
201+
self.tmpZipPath = path.join(self.tmpExtractPath, 'ionic.zip');
198202

199-
var file = fs.createWriteStream(self.tmpZipPath);
200-
file.on('error', function(err) {
201-
console.log( ('downloadZip createWriteStream: ' + err).error );
202-
});
203+
if( !fs.existsSync(self.tmpExtractPath) ) {
204+
fs.mkdirSync(self.tmpExtractPath);
205+
}
206+
207+
console.log('Downloading: '.green.bold + archivePath);
203208

204209
var proxy = process.env.PROXY || null;
205-
request({ url: archivePath, encoding: null, proxy: proxy }, function(err, res, body) {
210+
request({ url: archivePath, rejectUnauthorized: false, encoding: null, proxy: proxy }, function(err, res, body) {
206211
if(err) {
207212
console.log(err);
208213
return;
209214
}
210-
if(res.statusCode == 404) {
215+
if(res.statusCode == 404 || res.statusCode == 406) {
211216
console.log( ('Invalid version: ' + version).bold.red );
212-
try {
213-
file.close();
214-
fs.unlink(self.tmpZipPath);
215-
} catch(e) {
216-
console.error( (e).red );
217-
}
218217
return;
219218
}
220219
if(res.statusCode >= 400) {
221220
console.log('Unable to download zip (' + res.statusCode + ')');
222221
return;
223222
}
224223
try {
225-
file.write(body);
226-
file.close(function(){
227-
self.updateFiles();
228-
});
224+
fs.writeFileSync(self.tmpZipPath, body);
225+
self.updateFiles();
229226
} catch(e) {
230227
console.error( (e).red );
231228
}
@@ -260,63 +257,67 @@ IonicTask.prototype.downloadZip = function(version) {
260257
IonicTask.prototype.updateFiles = function(version) {
261258
var self = this;
262259
var ionicLibDir = path.resolve('www/lib/ionic');
263-
var readStream = fs.createReadStream(self.tmpZipPath);
264260

265261
try {
262+
var readStream = fs.createReadStream(self.tmpZipPath);
263+
readStream.on('error', function(err) {
264+
console.log( ('updateFiles readStream: ' + err).error );
265+
});
266266

267-
function onEntry(entry) {
268-
var libEntryPath = entry.path.replace('ionic-bower-' + self.versionData.version_number + '/', ionicLibDir + '/');
269-
270-
if( /bower.json|readme/gi.test(entry.path) ) {
271-
entry.autodrain();
272-
return;
273-
}
267+
var writeStream = unzip.Extract({ path: self.tmpExtractPath });
268+
writeStream.on('close', function() {
269+
try {
270+
rm('-rf', self.tmpZipPath)
271+
} catch(e){}
274272

275-
if(entry.type == 'Directory') {
276-
if( !fs.existsSync(libEntryPath) ) {
277-
fs.mkdirSync(libEntryPath);
273+
try {
274+
var dir = fs.readdirSync(self.tmpExtractPath);
275+
var copyFrom;
276+
for(var x=0; x<dir.length; x++) {
277+
if( dir[x].indexOf('ionic') === 0 ) {
278+
copyFrom = path.join(self.tmpExtractPath, dir[x], '*');
279+
}
280+
}
281+
if(!copyFrom) {
282+
console.log('updateFiles, invalid zip');
283+
return;
278284
}
279-
} else {
280-
var writeStream = fs.createWriteStream(libEntryPath);
281-
writeStream.on('error', function(err) {
282-
console.log( ('updateFiles error writing, ' + libEntryPath + ': ' + err).error );
283-
});
284-
entry.pipe(writeStream);
285-
}
286285

287-
entry.autodrain();
288-
}
286+
cp('-Rf', copyFrom, ionicLibDir);
289287

290-
readStream.pipe(unzip.Parse())
291-
.on('entry', onEntry)
292-
.on('close', function(){
293-
try{
294-
console.log('Ionic version updated to: '.bold.green + self.versionData.version_number.bold );
295-
IonicStats.t();
288+
try {
289+
rm('-rf', self.tmpExtractPath)
290+
} catch(e){}
296291

297-
self.writeVersionData();
292+
try {
293+
rm('-rf', path.join(ionicLibDir, 'README.md'));
294+
} catch(e){}
298295

299-
var ionicBower = require('./bower').IonicBower;
300-
ionicBower.setIonicVersion(self.versionData.version_number);
296+
try {
297+
rm('-rf', path.join(ionicLibDir, 'bower.json'));
298+
} catch(e){}
301299

302-
} catch(e) {
303-
console.log( ('Error loading version info: ' + e).error.bold );
304-
}
305-
});
300+
console.log('Ionic version updated to: '.bold.green + self.versionData.version_number.bold );
301+
IonicStats.t();
306302

307-
readStream.on('error', function(err){
308-
console.log( ('updateFiles readStream: ' + err).error );
309-
});
303+
self.writeVersionData();
310304

311-
readStream.on('close', function(err){
312-
try {
313-
fs.unlink(self.tmpZipPath);
314-
} catch(e){}
305+
var ionicBower = require('./bower').IonicBower;
306+
ionicBower.setIonicVersion(self.versionData.version_number);
307+
308+
} catch(e){
309+
console.log('updateFiles Error: ' + e);
310+
}
315311
});
312+
writeStream.on('error', function(err) {
313+
console.log( ('updateFiles writeStream: ' + err).error );
314+
});
315+
readStream.pipe(writeStream);
316316

317-
} catch(err) {
318-
console.log('Error: ' + err);
317+
} catch(e) {
318+
console.log('updateFiles Error: ' + e);
319319
}
320+
320321
};
321322

322323
IonicTask.prototype.writeVersionData = function() {

lib/ionic/serve.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ IonicTask.prototype.start = function(ionic) {
127127

128128
// gulpStartupTasks should be an array of tasks set in the project config
129129
// watchSass is for backwards compatible sass: true project config
130-
if(this.gulpStartupTasks || this.watchSass) {
130+
if((this.gulpStartupTasks && this.gulpStartupTasks.length) || this.watchSass) {
131131
var spawn = require('cross-spawn').spawn;
132132
var tasks = this.gulpStartupTasks || ['sass','watch'];
133133

0 commit comments

Comments
 (0)