diff --git a/install.js b/install.js index af39263..2faa9ea 100644 --- a/install.js +++ b/install.js @@ -2,8 +2,14 @@ var http = require('http'); var fs = require('fs'); var os = require('os'); var exec = require('child_process').exec; - +var path = require('path'); +var AdmZip = require('adm-zip'); +var aaptExe = 'aapt'; +var doChmod = true; var targetDir = __dirname + '/tools/'; +var dlLink; +var ProgressBar = require('progress'); + try { fs.statSync(targetDir); } catch (e) { @@ -11,36 +17,139 @@ try { } var platform = null; -if (os.type() == 'Darwin') { +var osType = os.type(); +switch(osType){ + case('Darwin'): + dlLink = 'http://dl.google.com/android/adt/22.6.2/adt-bundle-mac-x86_64-20140321.zip'; platform = 'macosx'; -} else if (os.type() == 'Linux') { + break; + case('Linux'): + if(os.arch() === 'x64'){ + dlLink = 'http://dl.google.com/android/adt/22.6.2/adt-bundle-linux-x86_64-20140321.zip'; + }else{ + dlLink = 'http://dl.google.com/android/adt/22.6.2/adt-bundle-linux-x86-20140321.zip'; + } platform = 'linux'; -} else { - throw new Error('Unknown OS!'); + break; + case('Windows_NT'): + if(os.arch() === 'x64'){ + dlLink = 'http://dl.google.com/android/adt/22.6.2/adt-bundle-windows-x86_64-20140321.zip'; + }else{ + dlLink = 'http://dl.google.com/android/adt/22.6.2/adt-bundle-windows-x86-20140321.zip'; + } + platform = 'windows'; + aaptExe = 'aapt.exe'; + doChmod = false; + break; + default: + throw new Error('Unknown OS "'+osType+'"!'); } +var mkDir = function(fpath, callback){ + var dirs = fpath.split(/[\\\/]/); + var root = './'; + var mk = function(){ + var dir = dirs.shift(); + if(dir === ''){ + root = path.sep; + } + fs.exists(root+dir, function(exists){ + if(!exists){ + fs.mkdir(root+dir, function(err){ + if(err){ + return callback(err); + } + root += dir + path.sep; + if(dirs.length){ + return mk(); + }else if(callback){ + return callback(null, root); + } + }); + }else{ + root += dir + path.sep; + if(dirs.length){ + return mk(); + }else if(callback){ + return callback(null, root); + } + } + }); + }; + mk(); +}; + function attemptDownload(attemptsLeft) { + // If you want the latest and greatest versions then comment out the platform-tools_r16- line and uncomment the next line + // know though that that will download a 500+ MB file and it takes forever + //var url = dlLink; var url = "http://dl-ssl.google.com/android/repository/platform-tools_r16-" + platform + ".zip"; - var tempFile = "/tmp/platform-tools-" + (new Date().getTime()) + ".zip"; - - var file = fs.createWriteStream(tempFile); - var request = http.get(url, function(response) { - response.pipe(file); - response.on('end', function () { - exec("unzip -j -o " + tempFile + " platform-tools/aapt -d tools/", function (err) { - if (err) { - if (attemptsLeft === 0) { - throw err; - } else { - attemptDownload(attemptsLeft - 1); - return; - } + var tempFile = "./tmp/platform-tools-" + (new Date().getTime()) + ".zip"; + if(!attemptsLeft){ + throw new Error('Coudln\'t download platform tools in 3 tries... Failing...'); + } + attemptsLeft--; + mkDir('tmp', function(err){ + if(err){ + throw err; + } + var file = fs.createWriteStream(tempFile); + var request = http.get(url, function(response) { + var len = parseInt(response.headers['content-length'], 10); + var bar = new ProgressBar('Downloading Android ADT Bundle [:bar] :percent :current of :total', { + complete: '=', + incomplete: ' ', + width: 20, + total: len + }); + response.pipe(file); + response.on('data', function(chunk){ + bar.tick(chunk.length); + }); + response.on('end', function () { + console.log('\n'); + var zip = new AdmZip(tempFile); + mkDir('tools', function(err){ + if(err){ + throw err; + } + try{ + var zipEntries = zip.getEntries(); + var entryName = false; + zipEntries.forEach(function(zipEntry) { + if (zipEntry.entryName.match(/aapt/)) { + entryName = zipEntry.entryName; + } + }); + if(!entryName){ + throw new Error('Couldn\'t locate aapt application.'); + } + zip.extractEntryTo(entryName, 'tools', false, true); + if(doChmod){ + fs.chmodSync('tools/'+aaptExe, '755'); + } + try{ + fs.unlinkSync(tempFile); + fs.unlinkSync('tmp'); + }catch(e){ + console.log('Failed to remove temp file: '+tempFile); + console.log('You might want to delete that to save disk space'); } - fs.chmodSync('tools/aapt', '755'); - fs.unlinkSync(tempFile); - process.exit(); + }catch(e){ + try{ + fs.unlinkSync(file); + }catch(e){} + console.error(e); + if (attemptsLeft === 0) { + throw err; + } else { + attemptDownload(attemptsLeft); + return; + } + } }); - }); + }); + }); }); } diff --git a/lib/index.js b/lib/index.js index c3cf2ec..c9e8a43 100644 --- a/lib/index.js +++ b/lib/index.js @@ -33,7 +33,7 @@ parseOutput = function(text, cb) { stack = [result]; inManifest = false; for (_i = 0, _len = lines.length; _i < _len; _i++) { - line = lines[_i]; + line = lines[_i].replace(/(\r|\n)+/g, ''); if (line.trim() === 'Android manifest:') { inManifest = true; continue; @@ -47,9 +47,12 @@ parseOutput = function(text, cb) { if (line.match(/^N:/)) { continue; } + if (line.match(/^( +)C:(.*)$/)) { + continue; + } matches = line.match(/^( +)(A|E): ([\w:\-]+)(.*)$/); if (!matches) { - return cb(new Error('Parse failure: ' + line)); + return cb(new Error('Parse failure: ' + line + ' at line ' + _i)); } input = matches[0], indent = matches[1], type = matches[2], name = matches[3], rest = matches[4]; depth = indent.length / 2; diff --git a/package.json b/package.json index 3edd7f3..a053a41 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,20 @@ { "name": "apk-parser", "description": "Extract Android Manifest info from an APK file.", - "version": "0.1.0", + "version": "0.2.0", "homepage": "https://github.com/rubenv/node-apk-parser", "author": { "name": "Ruben Vermeersch", "email": "ruben@savanne.be", "url": "http://savanne.be/" }, + "contributors": [ + { + "name": "Jeremy Darling", + "email": "jeremy.darling@gmail.com", + "url": "http://github.com/jdarling" + } + ], "repository": { "type": "git", "url": "git://github.com/rubenv/node-apk-parser.git" @@ -43,5 +50,9 @@ "keywords": [ "android", "apk" - ] + ], + "dependencies": { + "adm-zip": "^0.4.4", + "progress": "^1.1.5" + } } diff --git a/src/index.coffee b/src/index.coffee index 57cc1f1..27ce898 100644 --- a/src/index.coffee +++ b/src/index.coffee @@ -33,6 +33,9 @@ parseOutput = (text, cb) -> # Ignore namespaces continue if line.match /^N:/ + # Ignore C, not sure what its for + continue if line.match /^( +)C:(.*)$/ + # Match the first part of the line matches = line.match /^( +)(A|E): ([\w:\-]+)(.*)$/ if !matches