├── .gitignore ├── package.json ├── README.md ├── bin └── tisdk └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tisdk", 3 | "version": "2.0.1", 4 | "description": "Install titanium sdk GA releases 4+", 5 | "main": "index.js", 6 | "repository": "https://github.com/dbankier/tisdk", 7 | "bin": { 8 | "tisdk": "bin/tisdk" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "David Bankier", 14 | "license": "MIT", 15 | "dependencies": { 16 | "chalk": "^1.1.0", 17 | "commander": "^2.8.1", 18 | "node-appc": "^0.2.26", 19 | "progress": "^1.1.8", 20 | "request": "^2.58.0", 21 | "rimraf": "^2.4.1", 22 | "semver": "^5.3.0", 23 | "tmp": "0.0.27", 24 | "underscore": "^1.8.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TISDK 2 | 3 | Install GA, RC, Beta, Alpha titanium sdk builds. Works also for v4+. 4 | 5 | This is based on the git tags in the repository and the Appcelerator CI builds. 6 | 7 | ## Install 8 | 9 | ~~~ 10 | $ npm install -g tisdk 11 | ~~~ 12 | 13 | ## Commmands 14 | 15 | `tisdk list` - list available GA and RC builds, use the `--ga-only` flag to hide RCs and Betas 16 | 17 | `tisdk install [version]` - installs the GA sdk , e.g. 4.0.0.GA. `--force` flag overrides existing install. 18 | 19 | `tisdk download [version]` - installs the GA sdk , e.g. 4.0.0.GA. 20 | 21 | `tisdk build [version]` - manually builds the GA sdk from the source, e.g. 5.0.0.GA. `--force` flag overrides existing install. 22 | 23 | ## Manual builds 24 | 25 | When using the `tisdk build` command ensure you have everything installed for the manual build. 26 | See the [Appcelerator Wiki](http://docs.appcelerator.com/platform/latest/#!/guide/Building_the_Titanium_SDK_From_Source). 27 | In short you need node, android sdk API 23 and ndk, scons, python, git, oracle jdk 1.6, ios sdk, etc. 28 | 29 | Also make sure your environment variables are set. For example: 30 | 31 | ``` 32 | export ANDROID_SDK="$HOME/Android" 33 | export ANDROID_NDK="$HOME/android-ndk-r11c" 34 | export ANDROID_PLATFORM="$ANDROID_SDK/platforms/android-25" 35 | export GOOGLE_APIS="$ANDROID_SDK/add-ons/addon-google_apis-google-25" 36 | export JAVA_HOME=$(/usr/libexec/java_home -v 1.7) 37 | export PATH=$ANDROID_SDK/tools:$ANDROID_SDK/platform-tools:$JAVA_HOME/bin:$PATH 38 | ``` 39 | 40 | 41 | 42 | 43 | ### Platforms Support 44 | 45 | * **OSX** - installs the sdk to `~/Library/Application Support/Titanium`. 46 | * **Linux** - installs the sdk to `~/.titanium` (thanks @m1ga) 47 | 48 | 49 | **Licence: MIT** 50 | -------------------------------------------------------------------------------- /bin/tisdk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require("commander"); 4 | var tisdk = require("../index"); 5 | var chalk = require("chalk"); 6 | var fs = require("fs"); 7 | 8 | program 9 | .version(require("../package.json").version); 10 | 11 | program 12 | .command("list") 13 | .option("-g, --ga-only", "List GA releases only") 14 | .description("List available GA releases") 15 | .action(function(o) { 16 | tisdk.getGATags(function(tags) { 17 | tags.map(function(tag) { 18 | var version = tag.name.replace(/_/g, "."); 19 | var type = version.split(".")[3]; 20 | if (type==="GA") { 21 | console.log(chalk.bold.green(version) + "\t" + chalk.grey(tag.commit.sha)); 22 | } else if (!o.gaOnly) { 23 | console.log(version + "\t" + chalk.grey(tag.commit.sha)); 24 | } 25 | }); 26 | }); 27 | }); 28 | 29 | program 30 | .description("Install a GA version") 31 | .command("install [version]") 32 | .option("-f, --force", "Overwrite existing install") 33 | .action(function(version, options) { 34 | var tmp_file = "mobilesdk-" + version + "-"+tisdk.platform+".zip"; 35 | var overwrite = !!options.force; 36 | if (fs.existsSync(tisdk.installTarget(version)) && !overwrite) { 37 | console.log(chalk.red("ERROR") + ": SDK already installed. Use the --force flag to overwrite existing install."); 38 | return; 39 | } 40 | tisdk.install(version, function() { 41 | console.log("Installed Successfully!"); 42 | }); 43 | }); 44 | 45 | program 46 | .description("Download a GA version") 47 | .command("download [version]") 48 | .action(function(version) { 49 | var tmp_file = "mobilesdk-" + version + "-"+tisdk.platform+".zip"; 50 | tisdk.download(version, tmp_file, function(){ 51 | console.log("Done."); 52 | }); 53 | }); 54 | 55 | program 56 | .description("Manual build from the repository") 57 | .command("build [version]") 58 | .option("-f, --force", "Overwrite existing install") 59 | .action(function(version, options) { 60 | var tmp_file = "mobilesdk-" + version + "-"+tisdk.platform+".zip"; 61 | var overwrite = !!options.force; 62 | if (fs.existsSync(tisdk.installTarget(version)) && !overwrite) { 63 | console.log(chalk.red("ERROR") + ": SDK already installed. Use the --force flag to overwrite existing install."); 64 | return; 65 | } 66 | tisdk.manualBuild(version, tmp_file, overwrite, function(){ 67 | console.log("Installed Successfully!"); 68 | }); 69 | }); 70 | 71 | 72 | program.parse(process.argv); 73 | if (program.args.length === 0 || typeof program.args[program.args.length -1] === 'string'){ 74 | program.help(); 75 | } 76 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var request = require("request"); 2 | var ProgressBar = require("progress"); 3 | var _ = require("underscore"); 4 | var fs = require("fs"); 5 | var path = require("path"); 6 | var platform = "osx"; 7 | var os = require('os'); 8 | var tmp = require('tmp'); 9 | var rimraf = require("rimraf"); 10 | var chalk = require("chalk"); 11 | var appc = require("node-appc"); 12 | var semver = require("semver"); 13 | 14 | var _spawn = require('child_process').spawn; 15 | function spawn(cmd,args,props) { 16 | if (process.platform === 'win32') { 17 | args = ['/c',cmd].concat(args); 18 | cmd = process.env.comspec; 19 | } 20 | return _spawn(cmd,args,props); 21 | } 22 | 23 | function spawnPromise(cmd, args, props) { 24 | return new Promise((resolve, reject) => { 25 | var s = spawn(cmd, args, props); 26 | s.on('error',function(err) { reject(err); }); 27 | s.on('exit', function(){ resolve(); }); 28 | }) 29 | } 30 | 31 | var TITANIUM, platform; 32 | if (os.platform()=="linux"){ 33 | TITANIUM = path.join(process.env.HOME, '.titanium'); 34 | platform = "linux"; 35 | } else if (os.platform() === "win32") { 36 | TITANIUM = path.join(process.cwd().split(path.sep)[0], "ProgramData", "Titanium"); 37 | platform = "win32"; 38 | } else { 39 | TITANIUM = path.join(process.env.HOME, 'Library', 'Application Support', 'Titanium'); 40 | platform = "osx"; 41 | } 42 | exports.platform = platform; 43 | 44 | 45 | exports.getGATags = function getGATags(callback) { 46 | request({ 47 | url: "https://api.github.com/repos/appcelerator/titanium_mobile/tags?per_page=50", 48 | headers: { 49 | 'User-Agent': 'Awesome-Octocat-App' 50 | } 51 | }, function(err, res) { 52 | var tags = JSON.parse(res.body).filter(function(a) { return a.name.match(/^\d+_\d+_\d+_.*/); }); 53 | callback(tags); 54 | }); 55 | }; 56 | 57 | exports.getNightlies = function getNightlies(branch, callback) { 58 | request({ 59 | url: "http://builds.appcelerator.com/mobile/" + branch + "/index.json", 60 | headers: { 61 | // 'User-Agent': 'Awesome-Octocat-App' 62 | } 63 | }, function(err, res) { 64 | callback(JSON.parse(res.body)); 65 | }); 66 | }; 67 | 68 | exports.download = function(_version, destination, callback) { 69 | var version = _version.replace(/\./g, "_"); 70 | exports.getGATags(function(tags) { 71 | var tag = _.find(tags, function(tag) { 72 | return tag.name === version; 73 | }); 74 | if (!tag) { 75 | console.error("Invalid GA Version: use the `tisdk list` command"); 76 | return; 77 | } 78 | var nightly = tag.name.split("_").splice(0,2).join("_") + "_" + "X"; 79 | 80 | exports.getNightlies(nightly, function(list) { 81 | var build = _.find(list, function(t) { return t.git_revision === tag.commit.sha;}); 82 | if (!build) { 83 | console.error("Build not available. Try the `tisdk build` command to build the sdk from source."); 84 | return; 85 | } 86 | var file = fs.createWriteStream(destination); 87 | var filename = build.filename; 88 | if (platform=="linux"){ 89 | filename = filename.replace(/osx/g,"linux"); 90 | } else if (platform === "win32") { 91 | filename = filename.replace(/osx/g,"win32"); 92 | } 93 | 94 | var req = request.get("http://builds.appcelerator.com/mobile/" + nightly + "/" + filename); 95 | 96 | req.pipe(file); 97 | req.on('response', function(req) { 98 | var bar = new ProgressBar('Downloading... [:bar] :percent :etas', { 99 | complete: '=', 100 | incomplete: ' ', 101 | width: 40, 102 | total: parseInt(req.headers['content-length']) 103 | }); 104 | req.on('data', function(buffer) { 105 | bar.tick(buffer.length); 106 | }); 107 | }); 108 | file.on('finish', function() { 109 | callback(build); 110 | }); 111 | }); 112 | }); 113 | }; 114 | 115 | exports.install = function(_version, callback) { 116 | var version = _version.replace("_", "."); 117 | spawnPromise('ti', ['sdk', 'install', `http://builds.appcelerator.com/mobile-releases/${version.replace(".GA","")}/mobilesdk-${version}-${platform}.zip`], {stdio: "inherit"}) 118 | .then(callback); 119 | } 120 | 121 | exports.manualBuild = function(_version, destination, overwrite, callback) { 122 | var version = _version.replace(/\./g, "_"); 123 | exports.getGATags(function(tags) { 124 | var tag = _.find(tags, function(tag) { 125 | return tag.name === version; 126 | }); 127 | if (!tag) { 128 | console.error("Invalid GA Version: use the `tisdk list` command"); 129 | return; 130 | } 131 | var tmp_dir = tmp.dirSync({prefix:'tisdk_'}).name; 132 | 133 | var args = "clone --depth 1 --branch " + version + " https://github.com/appcelerator/titanium_mobile " + tmp_dir; 134 | var git = spawn('git', args.split(" "), {stdio: "inherit"}); 135 | git.on('error',function(err) { console.log(err); }); 136 | git.on('exit', function(){ 137 | if (semver.gte(version.split("_").slice(0,3).join("."), "6.0.0")) { 138 | spawnPromise('npm', ['install'], {stdio: "inherit", cwd: tmp_dir}) 139 | .then(() => spawnPromise('npm', ['install', 'fs-extra'], {stdio: "inherit", cwd: tmp_dir})) 140 | .then(() => spawnPromise('node', [path.join('build','scons.js'), 'build'], {stdio: "inherit", cwd: tmp_dir})) 141 | .then(() => spawnPromise('node', [path.join('build','scons.js'), 'package'], {stdio: "inherit", cwd: tmp_dir})) 142 | .then(() => spawnPromise('node', [path.join('build','scons.js'), 'install'], {stdio: "inherit", cwd: tmp_dir})) 143 | .then(callback); 144 | } else { 145 | var scons = spawn('scons', ['-C', tmp_dir], {stdio: "inherit", env: process.env}); 146 | scons.on('error',function(err) { console.log(err); }); 147 | scons.on('exit', function() { 148 | fs.renameSync(path.join(tmp_dir, 'dist', "mobilesdk-" + _version.split(".").splice(0,3).join(".") + "-" + platform + ".zip"), destination); 149 | exports.unzip(version, tmp_file, version.split(".").splice(0,3).join("."), overwrite, callback()); 150 | }); 151 | } 152 | }); 153 | }); 154 | }; 155 | 156 | exports.installTarget = function(version) { 157 | return path.join(TITANIUM, "mobilesdk", platform, version); 158 | }; 159 | 160 | exports.unzip = function(version, src, bundled_version_name, overwrite, callback) { 161 | var target = exports.installTarget(version); 162 | console.log("Unzipping..."); 163 | appc.zip.unzip(src, TITANIUM, { 164 | visitor: function(entry, i, len) { 165 | process.stdout.clearLine(); 166 | process.stdout.cursorTo(0); 167 | process.stdout.write("Unzipping (" + i + "/" + len + ") : " + chalk.grey(entry.entryName) ); 168 | } 169 | }, function() { 170 | var source = path.join(TITANIUM, "mobilesdk", platform, bundled_version_name); 171 | console.log(""); 172 | if (overwrite) { 173 | console.log("Removing old " + target); 174 | rimraf.sync(target); 175 | } 176 | console.log("Renaming " + source + " to " + target); 177 | fs.renameSync(source, target); 178 | fs.unlinkSync(src); 179 | callback(); 180 | }); 181 | }; 182 | 183 | 184 | --------------------------------------------------------------------------------