mirror of
				https://gitcode.com/gh_mirrors/re/react-native-pushy.git
				synced 2025-10-31 21:33:12 +08:00 
			
		
		
		
	Move cli to separated repo
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,8 +1,5 @@ | |||||||
| /.idea | /.idea | ||||||
| /node_modules | /node_modules | ||||||
| /local-cli/lib |  | ||||||
| /react-native-pushy-cli/node_modules |  | ||||||
| /react-native-pushy-cli/lib |  | ||||||
| /android/build | /android/build | ||||||
| /android/obj | /android/obj | ||||||
| *.iml | *.iml | ||||||
|   | |||||||
| @@ -4,8 +4,6 @@ | |||||||
| /.eslintrc | /.eslintrc | ||||||
| /.nvmrc | /.nvmrc | ||||||
| /.travis.yml | /.travis.yml | ||||||
| /local-cli/src |  | ||||||
| /react-native-pushy-cli |  | ||||||
| /Example | /Example | ||||||
| /android/build | /android/build | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,14 +0,0 @@ | |||||||
| { |  | ||||||
|   "plugins": [ |  | ||||||
|     "syntax-object-rest-spread", |  | ||||||
|     "syntax-async-functions", |  | ||||||
|     "transform-es2015-arrow-functions", |  | ||||||
|     "transform-async-to-generator", |  | ||||||
|     "transform-es2015-modules-commonjs", |  | ||||||
|     "transform-es2015-destructuring", |  | ||||||
|     "transform-es2015-spread", |  | ||||||
|     "transform-object-rest-spread", |  | ||||||
|     "transform-es2015-parameters", |  | ||||||
|     "transform-strict-mode" |  | ||||||
|   ] |  | ||||||
| } |  | ||||||
| @@ -1,162 +0,0 @@ | |||||||
| { |  | ||||||
|   "useCommand": true, |  | ||||||
|   "defaultCommand": "help", |  | ||||||
|   "commands": { |  | ||||||
|     "help": { |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     "login":{ |  | ||||||
|     }, |  | ||||||
|     "logout": { |  | ||||||
|     }, |  | ||||||
|     "me": { |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     "createApp": { |  | ||||||
|       "options": { |  | ||||||
|         "name": { |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "platform": { |  | ||||||
|           "hasValue": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "apps": { |  | ||||||
|       "options": { |  | ||||||
|         "platform": { |  | ||||||
|           "hasValue": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "deleteApp": { |  | ||||||
|     }, |  | ||||||
|     "selectApp": { |  | ||||||
|       "options": { |  | ||||||
|         "platform": { |  | ||||||
|           "hasValue": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     "uploadIpa": { |  | ||||||
|     }, |  | ||||||
|     "uploadApk": { |  | ||||||
|     }, |  | ||||||
|     "packages": { |  | ||||||
|       "options": { |  | ||||||
|         "platform": { |  | ||||||
|           "hasValue": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     "publish": { |  | ||||||
|       "options": { |  | ||||||
|         "platform": { |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "name": { |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "description": { |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "metaInfo": { |  | ||||||
|           "hasValue": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "versions": { |  | ||||||
|       "options": { |  | ||||||
|         "platform": { |  | ||||||
|           "hasValue": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     "update": { |  | ||||||
|       "options": { |  | ||||||
|         "platform": { |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "versionId": { |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "packageId": { |  | ||||||
|           "hasValue": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     "build": { |  | ||||||
|       "description": "Bundle javascript and copy assets." |  | ||||||
|     }, |  | ||||||
|     "bundle": { |  | ||||||
|       "description": "Bundle javascript code only.", |  | ||||||
|       "options": { |  | ||||||
|         "dev": { |  | ||||||
|           "default": "false", |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "platform": { |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "bundleName":{ |  | ||||||
|           "default": "index.bundlejs", |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "entryFile": { |  | ||||||
|           "default": "index.js", |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "intermediaDir": { |  | ||||||
|           "default": "build/intermedia/${platform}", |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "output": { |  | ||||||
|           "default": "build/output/${platform}.${time}.ppk", |  | ||||||
|           "hasValue": true |  | ||||||
|         }, |  | ||||||
|         "verbose": { |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "release": { |  | ||||||
|       "description": "Push builded file to server." |  | ||||||
|     }, |  | ||||||
|     "diff": { |  | ||||||
|       "description": "Create diff patch", |  | ||||||
|       "options": { |  | ||||||
|         "output": { |  | ||||||
|           "default": "build/output/diff", |  | ||||||
|           "hasValue": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "diffFromApk": { |  | ||||||
|       "description": "Create diff patch from a Android package(.apk)", |  | ||||||
|       "options": { |  | ||||||
|         "output": { |  | ||||||
|           "default": "build/output/diff-${time}.apk-patch", |  | ||||||
|           "hasValue": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "diffFromIpa": { |  | ||||||
|       "description": "Create diff patch from a iOS package(.ipa)", |  | ||||||
|       "options": { |  | ||||||
|         "output": { |  | ||||||
|           "default": "build/output/diff-${time}.ipa-patch", |  | ||||||
|           "hasValue": true |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   "globalOptions":{ |  | ||||||
|     "no-interactive": { |  | ||||||
|       "default": false |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Created by tdzl2003 on 2/22/16. |  | ||||||
|  */ |  | ||||||
| module.exports = require('./lib'); |  | ||||||
| @@ -1,132 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Created by tdzl2003 on 2/13/16. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| const fetch = require('isomorphic-fetch'); |  | ||||||
| let host = process.env.PUSHY_REGISTRY || 'https://update.reactnative.cn/api'; |  | ||||||
| const fs = require('fs-extra'); |  | ||||||
| import request from 'request'; |  | ||||||
| import ProgressBar from 'progress'; |  | ||||||
|  |  | ||||||
| let session = undefined; |  | ||||||
| let savedSession = undefined; |  | ||||||
|  |  | ||||||
| exports.loadSession = async function() { |  | ||||||
|   if (fs.existsSync('.update')) { |  | ||||||
|     try { |  | ||||||
|       exports.replaceSession(JSON.parse(fs.readFileSync('.update', 'utf8'))); |  | ||||||
|       savedSession = session; |  | ||||||
|     } catch (e) { |  | ||||||
|       console.error('Failed to parse file `.update`. Try to remove it manually.'); |  | ||||||
|       throw e; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| exports.getSession = function() { |  | ||||||
|   return session; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| exports.replaceSession = function(newSession) { |  | ||||||
|   session = newSession; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| exports.saveSession = function() { |  | ||||||
|   // Only save on change. |  | ||||||
|   if (session !== savedSession) { |  | ||||||
|     const current = session; |  | ||||||
|     const data = JSON.stringify(current, null, 4); |  | ||||||
|     fs.writeFileSync('.update', data, 'utf8'); |  | ||||||
|     savedSession = current; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| exports.closeSession = function() { |  | ||||||
|   if (fs.existsSync('.update')) { |  | ||||||
|     fs.unlinkSync('.update'); |  | ||||||
|     savedSession = undefined; |  | ||||||
|   } |  | ||||||
|   session = undefined; |  | ||||||
|   host = process.env.PUSHY_REGISTRY || 'https://update.reactnative.cn'; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| async function query(url, options) { |  | ||||||
|   const resp = await fetch(url, options); |  | ||||||
|   const json = await resp.json(); |  | ||||||
|   if (resp.status !== 200) { |  | ||||||
|     throw Object.assign(new Error(json.message || json.error), { status: resp.status }); |  | ||||||
|   } |  | ||||||
|   return json; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function queryWithoutBody(method) { |  | ||||||
|   return function(api) { |  | ||||||
|     return query(host + api, { |  | ||||||
|       method, |  | ||||||
|       headers: { |  | ||||||
|         'X-AccessToken': session ? session.token : '', |  | ||||||
|       }, |  | ||||||
|     }); |  | ||||||
|   }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function queryWithBody(method) { |  | ||||||
|   return function(api, body) { |  | ||||||
|     return query(host + api, { |  | ||||||
|       method, |  | ||||||
|       headers: { |  | ||||||
|         'Content-Type': 'application/json', |  | ||||||
|         'X-AccessToken': session ? session.token : '', |  | ||||||
|       }, |  | ||||||
|       body: JSON.stringify(body), |  | ||||||
|     }); |  | ||||||
|   }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| exports.get = queryWithoutBody('GET'); |  | ||||||
| exports.post = queryWithBody('POST'); |  | ||||||
| exports.put = queryWithBody('PUT'); |  | ||||||
| exports.doDelete = queryWithBody('DELETE'); |  | ||||||
|  |  | ||||||
| async function uploadFile(fn) { |  | ||||||
|   const { url, fieldName, formData } = await exports.post('/upload', {}); |  | ||||||
|   let realUrl = url; |  | ||||||
|  |  | ||||||
|   if (!/^https?\:\/\//.test(url)) { |  | ||||||
|     realUrl = host + url; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   const fileSize = fs.statSync(fn).size; |  | ||||||
|  |  | ||||||
|   const bar = new ProgressBar('  Uploading [:bar] :percent :etas', { |  | ||||||
|     complete: '=', |  | ||||||
|     incomplete: ' ', |  | ||||||
|     total: fileSize, |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   const info = await new Promise((resolve, reject) => { |  | ||||||
|     formData.file = fs.createReadStream(fn); |  | ||||||
|  |  | ||||||
|     formData.file.on('data', function(data) { |  | ||||||
|       bar.tick(data.length); |  | ||||||
|     }); |  | ||||||
|     request.post( |  | ||||||
|       realUrl, |  | ||||||
|       { |  | ||||||
|         formData, |  | ||||||
|       }, |  | ||||||
|       (err, resp, body) => { |  | ||||||
|         if (err) { |  | ||||||
|           return reject(err); |  | ||||||
|         } |  | ||||||
|         if (resp.statusCode > 299) { |  | ||||||
|           return reject(Object.assign(new Error(body), { status: resp.statusCode })); |  | ||||||
|         } |  | ||||||
|         resolve(JSON.parse(body)); |  | ||||||
|       }, |  | ||||||
|     ); |  | ||||||
|   }); |  | ||||||
|   return info; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| exports.uploadFile = uploadFile; |  | ||||||
| @@ -1,110 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Created by tdzl2003 on 2/13/16. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| import {question} from './utils'; |  | ||||||
| import * as fs from 'fs-extra'; |  | ||||||
|  |  | ||||||
| const { |  | ||||||
|   post, |  | ||||||
|   get, |  | ||||||
|   doDelete, |  | ||||||
| } = require('./api'); |  | ||||||
|  |  | ||||||
| const validPlatforms = { |  | ||||||
|   ios: 1, |  | ||||||
|   android: 1, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export function checkPlatform(platform) { |  | ||||||
|   if (!validPlatforms[platform]) { |  | ||||||
|     throw new Error(`Invalid platform '${platform}'`); |  | ||||||
|   } |  | ||||||
|   return platform |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function getSelectedApp(platform) { |  | ||||||
|   checkPlatform(platform); |  | ||||||
|  |  | ||||||
|   if (!fs.existsSync('update.json')){ |  | ||||||
|     throw new Error(`App not selected. run 'pushy selectApp --platform ${platform}' first!`); |  | ||||||
|   } |  | ||||||
|   const updateInfo = JSON.parse(fs.readFileSync('update.json', 'utf8')); |  | ||||||
|   if (!updateInfo[platform]) { |  | ||||||
|     throw new Error(`App not selected. run 'pushy selectApp --platform ${platform}' first!`); |  | ||||||
|   } |  | ||||||
|   return updateInfo[platform]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export async function listApp(platform){ |  | ||||||
|   const {data} = await get('/app/list'); |  | ||||||
|   const list = platform?data.filter(v=>v.platform===platform):data; |  | ||||||
|   for (const app of list) { |  | ||||||
|     console.log(`${app.id}) ${app.name}(${app.platform})`); |  | ||||||
|   } |  | ||||||
|   if (platform) { |  | ||||||
|     console.log(`\nTotal ${list.length} ${platform} apps`); |  | ||||||
|   } else { |  | ||||||
|     console.log(`\nTotal ${list.length} apps`); |  | ||||||
|   } |  | ||||||
|   return list; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export async function chooseApp(platform) { |  | ||||||
|   const list = await listApp(platform); |  | ||||||
|  |  | ||||||
|   while (true) { |  | ||||||
|     const id = await question('Enter appId:'); |  | ||||||
|     const app = list.find(v=>v.id === (id|0)); |  | ||||||
|     if (app) { |  | ||||||
|       return app; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const commands = { |  | ||||||
|   createApp: async function ({options}) { |  | ||||||
|     const name = options.name || await question('App Name:'); |  | ||||||
|     const {downloadUrl} = options; |  | ||||||
|     const platform = checkPlatform(options.platform || await question('Platform(ios/android):')); |  | ||||||
|     const {id} = await post('/app/create', {name, platform}); |  | ||||||
|     console.log(`Created app ${id}`); |  | ||||||
|     await this.selectApp({ |  | ||||||
|       args: [id], |  | ||||||
|       options: {platform, downloadUrl}, |  | ||||||
|     }); |  | ||||||
|   }, |  | ||||||
|   deleteApp: async function ({args, options}) { |  | ||||||
|     const {platform} = options; |  | ||||||
|     const id = args[0] || chooseApp(platform); |  | ||||||
|     if (!id) { |  | ||||||
|       console.log('Canceled'); |  | ||||||
|     } |  | ||||||
|     await doDelete(`/app/${id}`); |  | ||||||
|     console.log('Ok.'); |  | ||||||
|   }, |  | ||||||
|   apps: async function ({options}){ |  | ||||||
|     const {platform} = options; |  | ||||||
|     listApp(platform); |  | ||||||
|   }, |  | ||||||
|   selectApp: async function({args, options}) { |  | ||||||
|     const platform = checkPlatform(options.platform || await question('Platform(ios/android):')); |  | ||||||
|     const id = args[0] || (await chooseApp(platform)).id; |  | ||||||
|  |  | ||||||
|     let updateInfo = {}; |  | ||||||
|     if (fs.existsSync('update.json')) { |  | ||||||
|       try { |  | ||||||
|         updateInfo = JSON.parse(fs.readFileSync('update.json', 'utf8')); |  | ||||||
|       } catch (e) { |  | ||||||
|         console.error('Failed to parse file `update.json`. Try to remove it manually.'); |  | ||||||
|         throw e; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     const {appKey} = await get(`/app/${id}`); |  | ||||||
|     updateInfo[platform] = { |  | ||||||
|       appId: id, |  | ||||||
|       appKey, |  | ||||||
|     }; |  | ||||||
|     fs.writeFileSync('update.json', JSON.stringify(updateInfo, null, 4), 'utf8'); |  | ||||||
|   }, |  | ||||||
| } |  | ||||||
| @@ -1,508 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Created by tdzl2003 on 2/22/16. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| const path = require('path'); |  | ||||||
| import { getRNVersion, translateOptions } from './utils'; |  | ||||||
| import * as fs from 'fs-extra'; |  | ||||||
| import { ZipFile } from 'yazl'; |  | ||||||
| import { open as openZipFile } from 'yauzl'; |  | ||||||
| import { question } from './utils'; |  | ||||||
| import { checkPlatform } from './app'; |  | ||||||
| const { spawn, spawnSync, execSync } = require('child_process'); |  | ||||||
| const g2js = require('gradle-to-js/lib/parser'); |  | ||||||
| const os = require('os'); |  | ||||||
|  |  | ||||||
| var diff; |  | ||||||
| try { |  | ||||||
|   var bsdiff = require('node-bsdiff'); |  | ||||||
|   diff = typeof bsdiff != 'function' ? bsdiff.diff : bsdiff; |  | ||||||
| } catch (e) { |  | ||||||
|   diff = function() { |  | ||||||
|     console.warn( |  | ||||||
|       'This function needs "node-bsdiff". Please run "npm i node-bsdiff" from your project directory first!', |  | ||||||
|     ); |  | ||||||
|     throw new Error('This function needs module "node-bsdiff". Please install it first.'); |  | ||||||
|   }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function exec(command) { |  | ||||||
|   const commandResult = spawnSync(command, { |  | ||||||
|     shell: true, |  | ||||||
|     stdio: 'inherit', |  | ||||||
|   }); |  | ||||||
|   if (commandResult.error) { |  | ||||||
|     throw commandResult.error; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function runReactNativeBundleCommand( |  | ||||||
|   bundleName, |  | ||||||
|   development, |  | ||||||
|   entryFile, |  | ||||||
|   outputFolder, |  | ||||||
|   platform, |  | ||||||
|   sourcemapOutput, |  | ||||||
|   config, |  | ||||||
| ) { |  | ||||||
|   let reactNativeBundleArgs = []; |  | ||||||
|  |  | ||||||
|   let envArgs = process.env.PUSHY_ENV_ARGS; |  | ||||||
|  |  | ||||||
|   if (envArgs) { |  | ||||||
|     Array.prototype.push.apply(reactNativeBundleArgs, envArgs.trim().split(/\s+/)); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   fs.emptyDirSync(outputFolder); |  | ||||||
|  |  | ||||||
|   Array.prototype.push.apply(reactNativeBundleArgs, [ |  | ||||||
|     path.join("node_modules", "react-native", "local-cli", "cli.js"),  |  | ||||||
|     "bundle", |  | ||||||
|     '--assets-dest', |  | ||||||
|     outputFolder, |  | ||||||
|     '--bundle-output', |  | ||||||
|     path.join(outputFolder, bundleName), |  | ||||||
|     '--dev', |  | ||||||
|     development, |  | ||||||
|     '--entry-file', |  | ||||||
|     entryFile, |  | ||||||
|     '--platform', |  | ||||||
|     platform, |  | ||||||
|     '--reset-cache', |  | ||||||
|   ]); |  | ||||||
|  |  | ||||||
|   if (sourcemapOutput) { |  | ||||||
|     reactNativeBundleArgs.push('--sourcemap-output', sourcemapOutput); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (config) { |  | ||||||
|     reactNativeBundleArgs.push('--config', config); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   const reactNativeBundleProcess = spawn('node', reactNativeBundleArgs); |  | ||||||
|   console.log(`Running bundle command: node ${reactNativeBundleArgs.join(' ')}`); |  | ||||||
|  |  | ||||||
|   return new Promise((resolve, reject) => { |  | ||||||
|     reactNativeBundleProcess.stdout.on('data', data => { |  | ||||||
|       console.log(data.toString().trim()); |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     reactNativeBundleProcess.stderr.on('data', data => { |  | ||||||
|       console.error(data.toString().trim()); |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     reactNativeBundleProcess.on('close', async exitCode => { |  | ||||||
|       if (exitCode) { |  | ||||||
|         reject(new Error(`"react-native bundle" command exited with code ${exitCode}.`)); |  | ||||||
|       } else { |  | ||||||
|         if (platform === 'android') { |  | ||||||
|           await compileHermesByteCode(bundleName, outputFolder); |  | ||||||
|         } |  | ||||||
|         resolve(null); |  | ||||||
|       } |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function getHermesOSBin() { |  | ||||||
|   if (os.platform() === 'win32') return 'win64-bin'; |  | ||||||
|   if (os.platform() === 'darwin') return 'osx-bin'; |  | ||||||
|   if (os.platform() === 'linux') return 'linux64-bin'; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function compileHermesByteCode(bundleName, outputFolder) { |  | ||||||
|   let enableHermes = false; |  | ||||||
|   try { |  | ||||||
|     const gradleConfig = await g2js.parseFile('android/app/build.gradle'); |  | ||||||
|     const projectConfig = gradleConfig['project.ext.react']; |  | ||||||
|     for (const packagerConfig of projectConfig) { |  | ||||||
|       if (packagerConfig.includes('enableHermes') && packagerConfig.includes('true')) { |  | ||||||
|         enableHermes = true; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } catch (e) {} |  | ||||||
|   if (enableHermes) { |  | ||||||
|     console.log(`Hermes enabled, now compiling to hermes bytecode:\n`); |  | ||||||
|     const hermesPath = fs.existsSync('node_modules/hermes-engine') |  | ||||||
|       ? 'node_modules/hermes-engine' |  | ||||||
|       : 'node_modules/hermesvm'; |  | ||||||
|     execSync( |  | ||||||
|       `${hermesPath}/${getHermesOSBin()}/hermes -emit-binary -out ${outputFolder}/${bundleName} ${outputFolder}/${bundleName} -O`, |  | ||||||
|       { stdio: 'ignore' }, |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function pack(dir, output) { |  | ||||||
|   console.log('Packing'); |  | ||||||
|   fs.ensureDirSync(path.dirname(output)); |  | ||||||
|   await new Promise((resolve, reject) => { |  | ||||||
|     var zipfile = new ZipFile(); |  | ||||||
|  |  | ||||||
|     function addDirectory(root, rel) { |  | ||||||
|       if (rel) { |  | ||||||
|         zipfile.addEmptyDirectory(rel); |  | ||||||
|       } |  | ||||||
|       const childs = fs.readdirSync(root); |  | ||||||
|       for (const name of childs) { |  | ||||||
|         if (name === '.' || name === '..') { |  | ||||||
|           continue; |  | ||||||
|         } |  | ||||||
|         const fullPath = path.join(root, name); |  | ||||||
|         const stat = fs.statSync(fullPath); |  | ||||||
|         if (stat.isFile()) { |  | ||||||
|           //console.log('adding: ' + rel+name); |  | ||||||
|           zipfile.addFile(fullPath, rel + name); |  | ||||||
|         } else if (stat.isDirectory()) { |  | ||||||
|           //console.log('adding: ' + rel+name+'/'); |  | ||||||
|           addDirectory(fullPath, rel + name + '/'); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     addDirectory(dir, ''); |  | ||||||
|  |  | ||||||
|     zipfile.outputStream.on('error', err => reject(err)); |  | ||||||
|     zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', function() { |  | ||||||
|       resolve(); |  | ||||||
|     }); |  | ||||||
|     zipfile.end(); |  | ||||||
|   }); |  | ||||||
|   console.log('Bundled saved to: ' + output); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function readEntire(entry, zipFile) { |  | ||||||
|   const buffers = []; |  | ||||||
|   return new Promise((resolve, reject) => { |  | ||||||
|     zipFile.openReadStream(entry, (err, stream) => { |  | ||||||
|       stream.pipe({ |  | ||||||
|         write(chunk) { |  | ||||||
|           buffers.push(chunk); |  | ||||||
|         }, |  | ||||||
|         end() { |  | ||||||
|           resolve(Buffer.concat(buffers)); |  | ||||||
|         }, |  | ||||||
|         prependListener() {}, |  | ||||||
|         on() {}, |  | ||||||
|         once() {}, |  | ||||||
|         emit() {}, |  | ||||||
|       }); |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function basename(fn) { |  | ||||||
|   const m = /^(.+\/)[^\/]+\/?$/.exec(fn); |  | ||||||
|   return m && m[1]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function diffFromPPK(origin, next, output) { |  | ||||||
|   fs.ensureDirSync(path.dirname(output)); |  | ||||||
|  |  | ||||||
|   const originEntries = {}; |  | ||||||
|   const originMap = {}; |  | ||||||
|  |  | ||||||
|   let originSource; |  | ||||||
|  |  | ||||||
|   await enumZipEntries(origin, (entry, zipFile) => { |  | ||||||
|     originEntries[entry.fileName] = entry; |  | ||||||
|     if (!/\/$/.test(entry.fileName)) { |  | ||||||
|       // isFile |  | ||||||
|       originMap[entry.crc32] = entry.fileName; |  | ||||||
|  |  | ||||||
|       if (entry.fileName === 'index.bundlejs') { |  | ||||||
|         // This is source. |  | ||||||
|         return readEntire(entry, zipFile).then(v => (originSource = v)); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   originSource = originSource || new Buffer(0); |  | ||||||
|  |  | ||||||
|   const copies = {}; |  | ||||||
|  |  | ||||||
|   var zipfile = new ZipFile(); |  | ||||||
|  |  | ||||||
|   const writePromise = new Promise((resolve, reject) => { |  | ||||||
|     zipfile.outputStream.on('error', err => { |  | ||||||
|       throw err; |  | ||||||
|     }); |  | ||||||
|     zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', function() { |  | ||||||
|       resolve(); |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   const addedEntry = {}; |  | ||||||
|  |  | ||||||
|   function addEntry(fn) { |  | ||||||
|     //console.log(fn); |  | ||||||
|     if (!fn || addedEntry[fn]) { |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     const base = basename(fn); |  | ||||||
|     if (base) { |  | ||||||
|       addEntry(base); |  | ||||||
|     } |  | ||||||
|     zipfile.addEmptyDirectory(fn); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   const newEntries = {}; |  | ||||||
|  |  | ||||||
|   await enumZipEntries(next, (entry, nextZipfile) => { |  | ||||||
|     newEntries[entry.fileName] = entry; |  | ||||||
|  |  | ||||||
|     if (/\/$/.test(entry.fileName)) { |  | ||||||
|       // Directory |  | ||||||
|       if (!originEntries[entry.fileName]) { |  | ||||||
|         addEntry(entry.fileName); |  | ||||||
|       } |  | ||||||
|     } else if (entry.fileName === 'index.bundlejs') { |  | ||||||
|       //console.log('Found bundle'); |  | ||||||
|       return readEntire(entry, nextZipfile).then(newSource => { |  | ||||||
|         //console.log('Begin diff'); |  | ||||||
|         zipfile.addBuffer(diff(originSource, newSource), 'index.bundlejs.patch'); |  | ||||||
|         //console.log('End diff'); |  | ||||||
|       }); |  | ||||||
|     } else { |  | ||||||
|       // If same file. |  | ||||||
|       const originEntry = originEntries[entry.fileName]; |  | ||||||
|       if (originEntry && originEntry.crc32 === entry.crc32) { |  | ||||||
|         // ignore |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       // If moved from other place |  | ||||||
|       if (originMap[entry.crc32]) { |  | ||||||
|         const base = basename(entry.fileName); |  | ||||||
|         if (!originEntries[base]) { |  | ||||||
|           addEntry(base); |  | ||||||
|         } |  | ||||||
|         copies[entry.fileName] = originMap[entry.crc32]; |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       // New file. |  | ||||||
|       addEntry(basename(entry.fileName)); |  | ||||||
|  |  | ||||||
|       return new Promise((resolve, reject) => { |  | ||||||
|         nextZipfile.openReadStream(entry, function(err, readStream) { |  | ||||||
|           if (err) { |  | ||||||
|             return reject(err); |  | ||||||
|           } |  | ||||||
|           zipfile.addReadStream(readStream, entry.fileName); |  | ||||||
|           readStream.on('end', () => { |  | ||||||
|             //console.log('add finished'); |  | ||||||
|             resolve(); |  | ||||||
|           }); |  | ||||||
|         }); |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   const deletes = {}; |  | ||||||
|  |  | ||||||
|   for (var k in originEntries) { |  | ||||||
|     if (!newEntries[k]) { |  | ||||||
|       console.log('Delete ' + k); |  | ||||||
|       deletes[k] = 1; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   //console.log({copies, deletes}); |  | ||||||
|   zipfile.addBuffer(new Buffer(JSON.stringify({ copies, deletes })), '__diff.json'); |  | ||||||
|   zipfile.end(); |  | ||||||
|   await writePromise; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function diffFromPackage(origin, next, output, originBundleName, transformPackagePath = v => v) { |  | ||||||
|   fs.ensureDirSync(path.dirname(output)); |  | ||||||
|  |  | ||||||
|   const originEntries = {}; |  | ||||||
|   const originMap = {}; |  | ||||||
|  |  | ||||||
|   let originSource; |  | ||||||
|  |  | ||||||
|   await enumZipEntries(origin, (entry, zipFile) => { |  | ||||||
|     if (!/\/$/.test(entry.fileName)) { |  | ||||||
|       const fn = transformPackagePath(entry.fileName); |  | ||||||
|       if (!fn) { |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       //console.log(fn); |  | ||||||
|       // isFile |  | ||||||
|       originEntries[fn] = entry.crc32; |  | ||||||
|       originMap[entry.crc32] = fn; |  | ||||||
|  |  | ||||||
|       if (fn === originBundleName) { |  | ||||||
|         // This is source. |  | ||||||
|         return readEntire(entry, zipFile).then(v => (originSource = v)); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   originSource = originSource || new Buffer(0); |  | ||||||
|  |  | ||||||
|   const copies = {}; |  | ||||||
|  |  | ||||||
|   var zipfile = new ZipFile(); |  | ||||||
|  |  | ||||||
|   const writePromise = new Promise((resolve, reject) => { |  | ||||||
|     zipfile.outputStream.on('error', err => { |  | ||||||
|       throw err; |  | ||||||
|     }); |  | ||||||
|     zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', function() { |  | ||||||
|       resolve(); |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   await enumZipEntries(next, (entry, nextZipfile) => { |  | ||||||
|     if (/\/$/.test(entry.fileName)) { |  | ||||||
|       // Directory |  | ||||||
|       zipfile.addEmptyDirectory(entry.fileName); |  | ||||||
|     } else if (entry.fileName === 'index.bundlejs') { |  | ||||||
|       //console.log('Found bundle'); |  | ||||||
|       return readEntire(entry, nextZipfile).then(newSource => { |  | ||||||
|         //console.log('Begin diff'); |  | ||||||
|         zipfile.addBuffer(diff(originSource, newSource), 'index.bundlejs.patch'); |  | ||||||
|         //console.log('End diff'); |  | ||||||
|       }); |  | ||||||
|     } else { |  | ||||||
|       // If same file. |  | ||||||
|       if (originEntries[entry.fileName] === entry.crc32) { |  | ||||||
|         copies[entry.fileName] = ''; |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|       // If moved from other place |  | ||||||
|       if (originMap[entry.crc32]) { |  | ||||||
|         copies[entry.fileName] = originMap[entry.crc32]; |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       return new Promise((resolve, reject) => { |  | ||||||
|         nextZipfile.openReadStream(entry, function(err, readStream) { |  | ||||||
|           if (err) { |  | ||||||
|             return reject(err); |  | ||||||
|           } |  | ||||||
|           zipfile.addReadStream(readStream, entry.fileName); |  | ||||||
|           readStream.on('end', () => { |  | ||||||
|             //console.log('add finished'); |  | ||||||
|             resolve(); |  | ||||||
|           }); |  | ||||||
|         }); |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   zipfile.addBuffer(new Buffer(JSON.stringify({ copies })), '__diff.json'); |  | ||||||
|   zipfile.end(); |  | ||||||
|   await writePromise; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function enumZipEntries(zipFn, callback) { |  | ||||||
|   return new Promise((resolve, reject) => { |  | ||||||
|     openZipFile(zipFn, { lazyEntries: true }, (err, zipfile) => { |  | ||||||
|       if (err) { |  | ||||||
|         return reject(err); |  | ||||||
|       } |  | ||||||
|       zipfile.on('end', resolve); |  | ||||||
|       zipfile.on('error', reject); |  | ||||||
|       zipfile.on('entry', entry => { |  | ||||||
|         const result = callback(entry, zipfile); |  | ||||||
|         if (result && typeof result.then === 'function') { |  | ||||||
|           result.then(() => zipfile.readEntry()); |  | ||||||
|         } else { |  | ||||||
|           zipfile.readEntry(); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|       zipfile.readEntry(); |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const commands = { |  | ||||||
|   bundle: async function({ options }) { |  | ||||||
|     const platform = checkPlatform(options.platform || (await question('Platform(ios/android):'))); |  | ||||||
|  |  | ||||||
|     let { bundleName, entryFile, intermediaDir, output, dev, verbose } = translateOptions({ |  | ||||||
|       ...options, |  | ||||||
|       platform, |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     // const sourcemapOutput = path.join(intermediaDir, bundleName + ".map"); |  | ||||||
|  |  | ||||||
|     const realOutput = output.replace(/\$\{time\}/g, '' + Date.now()); |  | ||||||
|  |  | ||||||
|     if (!platform) { |  | ||||||
|       throw new Error('Platform must be specified.'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const { version, major, minor } = getRNVersion(); |  | ||||||
|  |  | ||||||
|     console.log('Bundling with React Native version: ', version); |  | ||||||
|  |  | ||||||
|     await runReactNativeBundleCommand(bundleName, dev, entryFile, intermediaDir, platform); |  | ||||||
|  |  | ||||||
|     await pack(path.resolve(intermediaDir), realOutput); |  | ||||||
|  |  | ||||||
|     const v = await question('Would you like to publish it?(Y/N)'); |  | ||||||
|     if (v.toLowerCase() === 'y') { |  | ||||||
|       await this.publish({ |  | ||||||
|         args: [realOutput], |  | ||||||
|         options: { |  | ||||||
|           platform, |  | ||||||
|         }, |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   async diff({ args, options }) { |  | ||||||
|     const [origin, next] = args; |  | ||||||
|     const { output } = options; |  | ||||||
|  |  | ||||||
|     const realOutput = output.replace(/\$\{time\}/g, '' + Date.now()); |  | ||||||
|  |  | ||||||
|     if (!origin || !next) { |  | ||||||
|       console.error('pushy diff <origin> <next>'); |  | ||||||
|       process.exit(1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     await diffFromPPK(origin, next, realOutput, 'index.bundlejs'); |  | ||||||
|     console.log(`${realOutput} generated.`); |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   async diffFromApk({ args, options }) { |  | ||||||
|     const [origin, next] = args; |  | ||||||
|     const { output } = options; |  | ||||||
|  |  | ||||||
|     const realOutput = output.replace(/\$\{time\}/g, '' + Date.now()); |  | ||||||
|  |  | ||||||
|     if (!origin || !next) { |  | ||||||
|       console.error('pushy diffFromApk <origin> <next>'); |  | ||||||
|       process.exit(1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     await diffFromPackage(origin, next, realOutput, 'assets/index.android.bundle'); |  | ||||||
|     console.log(`${realOutput} generated.`); |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   async diffFromIpa({ args, options }) { |  | ||||||
|     const [origin, next] = args; |  | ||||||
|     const { output } = options; |  | ||||||
|  |  | ||||||
|     const realOutput = output.replace(/\$\{time\}/g, '' + Date.now()); |  | ||||||
|  |  | ||||||
|     if (!origin || !next) { |  | ||||||
|       console.error('pushy diffFromIpa <origin> <next>'); |  | ||||||
|       process.exit(1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     await diffFromPackage(origin, next, realOutput, 'main.jsbundle', v => { |  | ||||||
|       const m = /^Payload\/[^/]+\/(.+)$/.exec(v); |  | ||||||
|       return m && m[1]; |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     console.log(`${realOutput} generated.`); |  | ||||||
|   }, |  | ||||||
| }; |  | ||||||
| @@ -1,39 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Created by tdzl2003 on 2/13/16. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| const {loadSession} = require('./api'); |  | ||||||
|  |  | ||||||
| function printUsage({args}) { |  | ||||||
|   // const commandName = args[0]; |  | ||||||
|   // TODO: print usage of commandName, or print global usage. |  | ||||||
|  |  | ||||||
|   console.log('Usage is under development now.') |  | ||||||
|   console.log('Visit `https://github.com/reactnativecn/react-native-pushy` for early document.'); |  | ||||||
|   process.exit(1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const commands = { |  | ||||||
|   ...require('./user').commands, |  | ||||||
|   ...require('./bundle').commands, |  | ||||||
|   ...require('./app').commands, |  | ||||||
|   ...require('./package').commands, |  | ||||||
|   ...require('./versions').commands, |  | ||||||
|   help: printUsage, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| exports.run = function () { |  | ||||||
|   const argv = require('cli-arguments').parse(require('../cli.json')); |  | ||||||
|   global.NO_INTERACTIVE = argv.options['no-interactive']; |  | ||||||
|  |  | ||||||
|   loadSession() |  | ||||||
|     .then(()=>commands[argv.command](argv)) |  | ||||||
|     .catch(err=>{ |  | ||||||
|       if (err.status === 401) { |  | ||||||
|         console.log('Not loggined.\nRun `pushy login` at your project directory to login.'); |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|       console.error(err.stack); |  | ||||||
|       process.exit(-1); |  | ||||||
|     }); |  | ||||||
| }; |  | ||||||
| @@ -1,87 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Created by tdzl2003 on 4/2/16. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| const { get, post, uploadFile } = require('./api'); |  | ||||||
| import { question } from './utils'; |  | ||||||
|  |  | ||||||
| import { checkPlatform, getSelectedApp } from './app'; |  | ||||||
|  |  | ||||||
| import { getApkInfo, getIpaInfo } from './utils'; |  | ||||||
| const Table = require('tty-table'); |  | ||||||
|  |  | ||||||
| export async function listPackage(appId) { |  | ||||||
|   const { data } = await get(`/app/${appId}/package/list?limit=1000`); |  | ||||||
|  |  | ||||||
|   const header = [{ value: 'Package Id' }, { value: 'Version' }]; |  | ||||||
|   const rows = []; |  | ||||||
|   for (const pkg of data) { |  | ||||||
|     const { version } = pkg; |  | ||||||
|     let versionInfo = ''; |  | ||||||
|     if (version) { |  | ||||||
|       versionInfo = ` - ${version.id} ${version.hash.slice(0, 8)} ${version.name}`; |  | ||||||
|     } else { |  | ||||||
|       versionInfo = ' (newest)'; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     rows.push([pkg.id, `${pkg.name}(${pkg.status})${versionInfo}`]); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   console.log(Table(header, rows).render()); |  | ||||||
|   console.log(`\nTotal ${data.length} package(s).`); |  | ||||||
|   return data; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export async function choosePackage(appId) { |  | ||||||
|   const list = await listPackage(appId); |  | ||||||
|  |  | ||||||
|   while (true) { |  | ||||||
|     const id = await question('Enter Package Id:'); |  | ||||||
|     const app = list.find(v => v.id === (id | 0)); |  | ||||||
|     if (app) { |  | ||||||
|       return app; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const commands = { |  | ||||||
|   uploadIpa: async function({ args }) { |  | ||||||
|     const fn = args[0]; |  | ||||||
|     if (!fn) { |  | ||||||
|       throw new Error('Usage: pushy uploadIpa <ipaFile>'); |  | ||||||
|     } |  | ||||||
|     const { versionName, buildTime } = await getIpaInfo(fn); |  | ||||||
|     const { appId } = await getSelectedApp('ios'); |  | ||||||
|  |  | ||||||
|     const { hash } = await uploadFile(fn); |  | ||||||
|  |  | ||||||
|     const { id } = await post(`/app/${appId}/package/create`, { |  | ||||||
|       name: versionName, |  | ||||||
|       hash, |  | ||||||
|       buildTime, |  | ||||||
|     }); |  | ||||||
|     console.log(`Ipa uploaded: ${id}`); |  | ||||||
|   }, |  | ||||||
|   uploadApk: async function({ args }) { |  | ||||||
|     const fn = args[0]; |  | ||||||
|     if (!fn) { |  | ||||||
|       throw new Error('Usage: pushy uploadApk <apkFile>'); |  | ||||||
|     } |  | ||||||
|     const { versionName, buildTime } = await getApkInfo(fn); |  | ||||||
|     const { appId } = await getSelectedApp('android'); |  | ||||||
|  |  | ||||||
|     const { hash } = await uploadFile(fn); |  | ||||||
|  |  | ||||||
|     const { id } = await post(`/app/${appId}/package/create`, { |  | ||||||
|       name: versionName, |  | ||||||
|       hash, |  | ||||||
|       buildTime, |  | ||||||
|     }); |  | ||||||
|     console.log(`Apk uploaded: ${id}`); |  | ||||||
|   }, |  | ||||||
|   packages: async function({ options }) { |  | ||||||
|     const platform = checkPlatform(options.platform || (await question('Platform(ios/android):'))); |  | ||||||
|     const { appId } = await getSelectedApp(platform); |  | ||||||
|     await listPackage(appId); |  | ||||||
|   }, |  | ||||||
| }; |  | ||||||
| @@ -1,43 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Created by tdzl2003 on 2/13/16. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| import {question} from './utils'; |  | ||||||
| const { |  | ||||||
|   post, |  | ||||||
|   get, |  | ||||||
|   replaceSession, |  | ||||||
|   saveSession, |  | ||||||
|   closeSession, |  | ||||||
| } = require('./api'); |  | ||||||
| const crypto = require('crypto'); |  | ||||||
|  |  | ||||||
| function md5(str) { |  | ||||||
|   return crypto.createHash('md5').update(str).digest('hex'); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| exports.commands = { |  | ||||||
|   login: async function ({args}){ |  | ||||||
|     const email = args[0] || await question('email:'); |  | ||||||
|     const pwd = args[1] || await question('password:', true); |  | ||||||
|     const {token, info} = await post('/user/login', { |  | ||||||
|       email, |  | ||||||
|       pwd: md5(pwd), |  | ||||||
|     }); |  | ||||||
|     replaceSession({token}); |  | ||||||
|     await saveSession(); |  | ||||||
|     console.log(`Welcome, ${info.name}.`); |  | ||||||
|   }, |  | ||||||
|   logout: async function (){ |  | ||||||
|     await closeSession(); |  | ||||||
|     console.log('Logged out.'); |  | ||||||
|   }, |  | ||||||
|   me: async function (){ |  | ||||||
|     const me = await get('/user/me'); |  | ||||||
|     for (const k in me) { |  | ||||||
|       if (k !== 'ok') { |  | ||||||
|         console.log(`${k}: ${me[k]}`); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
| } |  | ||||||
| @@ -1,84 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Created by tdzl2003 on 2/13/16. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| import * as path from 'path'; |  | ||||||
| import * as fs from 'fs-extra'; |  | ||||||
| const AppInfoParser = require('app-info-parser'); |  | ||||||
|  |  | ||||||
| var read = require('read'); |  | ||||||
|  |  | ||||||
| export function question(query, password) { |  | ||||||
|   if (NO_INTERACTIVE) { |  | ||||||
|     return Promise.resolve(''); |  | ||||||
|   } |  | ||||||
|   return new Promise((resolve, reject) => |  | ||||||
|     read( |  | ||||||
|       { |  | ||||||
|         prompt: query, |  | ||||||
|         silent: password, |  | ||||||
|         replace: password ? '*' : undefined, |  | ||||||
|       }, |  | ||||||
|       (err, result) => (err ? reject(err) : resolve(result)), |  | ||||||
|     ), |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function translateOptions(options) { |  | ||||||
|   const ret = {}; |  | ||||||
|   for (let key in options) { |  | ||||||
|     const v = options[key]; |  | ||||||
|     if (typeof v === 'string') { |  | ||||||
|       ret[key] = v.replace(/\$\{(\w+)\}/g, function(v, n) { |  | ||||||
|         return options[n] || process.env[n] || v; |  | ||||||
|       }); |  | ||||||
|     } else { |  | ||||||
|       ret[key] = v; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return ret; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function getRNVersion() { |  | ||||||
|   const version = JSON.parse(fs.readFileSync(path.resolve('node_modules/react-native/package.json'))).version; |  | ||||||
|  |  | ||||||
|   // We only care about major and minor version. |  | ||||||
|   const match = /^(\d+)\.(\d+)\./.exec(version); |  | ||||||
|   return { |  | ||||||
|     version, |  | ||||||
|     major: match[1] | 0, |  | ||||||
|     minor: match[2] | 0, |  | ||||||
|   }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export async function getApkInfo(fn) { |  | ||||||
|   const appInfoParser = new AppInfoParser(fn); |  | ||||||
|   const { versionName, application } = await appInfoParser.parse(); |  | ||||||
|   let buildTime = 0; |  | ||||||
|   if (Array.isArray(application.metaData)) { |  | ||||||
|     for (const meta of application.metaData) { |  | ||||||
|       if (meta.name === 'pushy_build_time') { |  | ||||||
|         buildTime = meta.value[0]; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   if (buildTime == 0) { |  | ||||||
|     throw new Error('Can not get build time for this app.'); |  | ||||||
|   } |  | ||||||
|   return { versionName, buildTime }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export async function getIpaInfo(fn) { |  | ||||||
|   const appInfoParser = new AppInfoParser(fn); |  | ||||||
|   const { CFBundleShortVersionString: versionName } = await appInfoParser.parse(); |  | ||||||
|   let buildTimeTxtBuffer = await appInfoParser.parser.getEntry(/payload\/.+?\.app\/pushy_build_time.txt/); |  | ||||||
|   if (!buildTimeTxtBuffer) { |  | ||||||
|     // Not in root bundle when use `use_frameworks` |  | ||||||
|     buildTimeTxtBuffer = await appInfoParser.parser.getEntry(/payload\/.+?\.app\/frameworks\/react_native_update.framework\/pushy_build_time.txt/); |  | ||||||
|   } |  | ||||||
|   if (!buildTimeTxtBuffer) { |  | ||||||
|     throw new Error('Can not get build time for this app.'); |  | ||||||
|   } |  | ||||||
|   const buildTime = buildTimeTxtBuffer.toString().replace('\n', ''); |  | ||||||
|   return { versionName, buildTime }; |  | ||||||
| } |  | ||||||
| @@ -1,111 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Created by tdzl2003 on 4/2/16. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| const { |  | ||||||
|   get, |  | ||||||
|   post, |  | ||||||
|   put, |  | ||||||
|   uploadFile, |  | ||||||
| } = require('./api'); |  | ||||||
| import { question } from './utils'; |  | ||||||
|  |  | ||||||
| import { checkPlatform, getSelectedApp } from './app'; |  | ||||||
| import { choosePackage } from './package'; |  | ||||||
|  |  | ||||||
| async function showVersion(appId, offset) { |  | ||||||
|   const { data, count } = await get(`/app/${appId}/version/list`); |  | ||||||
|   console.log(`Offset ${offset}`); |  | ||||||
|   for (const version of data) { |  | ||||||
|     let packageInfo = version.packages.slice(0, 3).map(v=>v.name).join(', '); |  | ||||||
|     const count = version.packages.length; |  | ||||||
|     if (count > 3) { |  | ||||||
|       packageInfo += `...and ${count-3} more`; |  | ||||||
|     } |  | ||||||
|     if (count === 0) { |  | ||||||
|       packageInfo = `(no package)`; |  | ||||||
|     } else { |  | ||||||
|       packageInfo = `[${packageInfo}]`; |  | ||||||
|     } |  | ||||||
|     console.log(`${version.id}) ${version.hash.slice(0, 8)} ${version.name} ${packageInfo}`); |  | ||||||
|   } |  | ||||||
|   return data; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function listVersions(appId) { |  | ||||||
|   let offset = 0; |  | ||||||
|   while (true) { |  | ||||||
|     await showVersion(appId, offset); |  | ||||||
|     const cmd = await question('page Up/page Down/Begin/Quit(U/D/B/Q)'); |  | ||||||
|     switch (cmd.toLowerCase()) { |  | ||||||
|       case 'u': offset = Math.max(0, offset - 10); break; |  | ||||||
|       case 'd': offset += 10; break; |  | ||||||
|       case 'b': offset = 0; break; |  | ||||||
|       case 'q': return; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function chooseVersion(appId) { |  | ||||||
|   let offset = 0; |  | ||||||
|   while (true) { |  | ||||||
|     const data = await showVersion(appId, offset); |  | ||||||
|     const cmd = await question('Enter versionId or page Up/page Down/Begin(U/D/B)'); |  | ||||||
|     switch (cmd.toLowerCase()) { |  | ||||||
|       case 'U': offset = Math.max(0, offset - 10); break; |  | ||||||
|       case 'D': offset += 10; break; |  | ||||||
|       case 'B': offset = 0; break; |  | ||||||
|       default: |  | ||||||
|       { |  | ||||||
|         const v = data.find(v=>v.id === (cmd | 0)); |  | ||||||
|         if (v) { |  | ||||||
|           return v; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const commands = { |  | ||||||
|   publish: async function({args, options}) { |  | ||||||
|     const fn = args[0]; |  | ||||||
|     const {name, description, metaInfo } = options; |  | ||||||
|  |  | ||||||
|     if (!fn || !fn.endsWith('.ppk')) { |  | ||||||
|       throw new Error('Usage: pushy publish <ppkFile> --platform ios|android'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const platform = checkPlatform(options.platform || await question('Platform(ios/android):')); |  | ||||||
|     const { appId } = await getSelectedApp(platform); |  | ||||||
|  |  | ||||||
|     const { hash } = await uploadFile(fn); |  | ||||||
|  |  | ||||||
|     const { id } = await post(`/app/${appId}/version/create`, { |  | ||||||
|       name: name || await question('Enter version name:') || '(未命名)', |  | ||||||
|       hash, |  | ||||||
|       description: description || await question('Enter description:'), |  | ||||||
|       metaInfo: metaInfo || await question('Enter meta info:'), |  | ||||||
|     }); |  | ||||||
|     console.log(`Version published: ${id}`); |  | ||||||
|  |  | ||||||
|     const v = await question('Would you like to bind packages to this version?(Y/N)'); |  | ||||||
|     if (v.toLowerCase() === 'y') { |  | ||||||
|       await this.update({args:[], options:{versionId: id, platform}}); |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   versions: async function({options}) { |  | ||||||
|     const platform = checkPlatform(options.platform || await question('Platform(ios/android):')); |  | ||||||
|     const { appId } = await getSelectedApp(platform); |  | ||||||
|     await listVersions(appId); |  | ||||||
|   }, |  | ||||||
|   update: async function({args, options}) { |  | ||||||
|     const platform = checkPlatform(options.platform || await question('Platform(ios/android):')); |  | ||||||
|     const { appId } = await getSelectedApp(platform); |  | ||||||
|     const versionId = options.versionId || (await chooseVersion(appId)).id; |  | ||||||
|     const pkgId = options.packageId || (await choosePackage(appId)).id; |  | ||||||
|     await put(`/app/${appId}/package/${pkgId}`, { |  | ||||||
|       versionId, |  | ||||||
|     }); |  | ||||||
|     console.log('Ok.'); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
							
								
								
									
										31
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								package.json
									
									
									
									
									
								
							| @@ -5,8 +5,7 @@ | |||||||
|   "main": "lib/index.js", |   "main": "lib/index.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "test": "echo \"Error: no test specified\" && exit 1", |     "test": "echo \"Error: no test specified\" && exit 1", | ||||||
|     "build-lib": "$ANDROID_HOME/ndk-bundle/ndk-build NDK_PROJECT_PATH=android APP_BUILD_SCRIPT=android/jni/Android.mk NDK_LIBS_OUT=android/lib", |     "build-lib": "$ANDROID_HOME/ndk-bundle/ndk-build NDK_PROJECT_PATH=android APP_BUILD_SCRIPT=android/jni/Android.mk NDK_LIBS_OUT=android/lib" | ||||||
|     "prepare": "node_modules/.bin/babel local-cli/src --out-dir local-cli/lib" |  | ||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "git", |     "type": "git", | ||||||
| @@ -27,31 +26,5 @@ | |||||||
|     "react-native": ">=0.27.0" |     "react-native": ">=0.27.0" | ||||||
|   }, |   }, | ||||||
|   "homepage": "https://github.com/reactnativecn/react-native-pushy#readme", |   "homepage": "https://github.com/reactnativecn/react-native-pushy#readme", | ||||||
|   "dependencies": { |   "dependencies": {} | ||||||
|     "app-info-parser": "^0.3.5", |  | ||||||
|     "cli-arguments": "^0.2.1", |  | ||||||
|     "fs-extra": "^8.1.0", |  | ||||||
|     "gradle-to-js": "^2.0.0", |  | ||||||
|     "isomorphic-fetch": "^2.2.1", |  | ||||||
|     "progress": "^1.1.8", |  | ||||||
|     "read": "^1.0.7", |  | ||||||
|     "request": "^2.69.0", |  | ||||||
|     "tty-table": "^2.7.0", |  | ||||||
|     "yauzl": "^2.10.0", |  | ||||||
|     "yazl": "2.3.0" |  | ||||||
|   }, |  | ||||||
|   "devDependencies": { |  | ||||||
|     "babel-cli": "^6.5.1", |  | ||||||
|     "babel-eslint": "^4.1.6", |  | ||||||
|     "babel-plugin-syntax-async-functions": "^6.5.0", |  | ||||||
|     "babel-plugin-syntax-object-rest-spread": "^6.5.0", |  | ||||||
|     "babel-plugin-transform-async-to-generator": "^6.3.13", |  | ||||||
|     "babel-plugin-transform-es2015-arrow-functions": "^6.5.2", |  | ||||||
|     "babel-plugin-transform-es2015-destructuring": "^6.3.15", |  | ||||||
|     "babel-plugin-transform-es2015-modules-commonjs": "^6.3.16", |  | ||||||
|     "babel-plugin-transform-es2015-parameters": "^6.5.0", |  | ||||||
|     "babel-plugin-transform-es2015-spread": "^6.5.2", |  | ||||||
|     "babel-plugin-transform-object-rest-spread": "^6.5.0", |  | ||||||
|     "babel-plugin-transform-strict-mode": "^6.5.2" |  | ||||||
|   } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +0,0 @@ | |||||||
| { |  | ||||||
|   "plugins": [ |  | ||||||
|     "transform-es2015-modules-commonjs", |  | ||||||
|     "transform-strict-mode" |  | ||||||
|   ] |  | ||||||
| } |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| /.idea |  | ||||||
| /src |  | ||||||
| /.babelrc |  | ||||||
| /.npmignore |  | ||||||
| /.eslintrc |  | ||||||
| /.nvmrc |  | ||||||
| /.travis.yml |  | ||||||
| @@ -1,34 +0,0 @@ | |||||||
| { |  | ||||||
|   "name": "react-native-update-cli", |  | ||||||
|   "version": "0.1.0", |  | ||||||
|   "description": "Command tools for javaScript updater with `pushy` service for react native apps.", |  | ||||||
|   "main": "index.js", |  | ||||||
|   "bin": { |  | ||||||
|     "pushy": "lib/cli.js" |  | ||||||
|   }, |  | ||||||
|   "scripts": { |  | ||||||
|     "test": "echo \"Error: no test specified\" && exit 1", |  | ||||||
|     "prepublish": "node_modules/.bin/babel src --out-dir lib" |  | ||||||
|   }, |  | ||||||
|   "repository": { |  | ||||||
|     "type": "git", |  | ||||||
|     "url": "git+https://github.com/reactnativecn/react-native-pushy.git" |  | ||||||
|   }, |  | ||||||
|   "keywords": [ |  | ||||||
|     "react-native", |  | ||||||
|     "ios", |  | ||||||
|     "android", |  | ||||||
|     "update" |  | ||||||
|   ], |  | ||||||
|   "author": "reactnativecn", |  | ||||||
|   "license": "BSD-3-Clause", |  | ||||||
|   "bugs": { |  | ||||||
|     "url": "https://github.com/reactnativecn/react-native-pushy/issues" |  | ||||||
|   }, |  | ||||||
|   "homepage": "https://github.com/reactnativecn/react-native-pushy/tree/master/react-native-pushy-cli", |  | ||||||
|   "devDependencies": { |  | ||||||
|     "babel-cli": "^6.5.1", |  | ||||||
|     "babel-plugin-transform-es2015-modules-commonjs": "^6.5.2", |  | ||||||
|     "babel-plugin-transform-strict-mode": "^6.5.2" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										53
									
								
								react-native-pushy-cli/src/cli.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								react-native-pushy-cli/src/cli.js
									
									
									
									
										vendored
									
									
								
							| @@ -1,53 +0,0 @@ | |||||||
| #!/usr/bin/env node |  | ||||||
| /** |  | ||||||
|  * Created by tdzl2003 on 2/13/16. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| import * as path from 'path'; |  | ||||||
| import * as fs from 'fs-extra'; |  | ||||||
|  |  | ||||||
| const CLI_MODULE_PATH = function() { |  | ||||||
|   return path.resolve( |  | ||||||
|     process.cwd(), |  | ||||||
|     'node_modules', |  | ||||||
|     'react-native-update', |  | ||||||
|     'local-cli' |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const PACKAGE_JSON_PATH = function() { |  | ||||||
|   return path.resolve( |  | ||||||
|     process.cwd(), |  | ||||||
|     'node_modules', |  | ||||||
|     'react-native-update', |  | ||||||
|     'package.json' |  | ||||||
|   ); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| checkForVersionCommand(); |  | ||||||
|  |  | ||||||
| let cli; |  | ||||||
| const cliPath = CLI_MODULE_PATH(); |  | ||||||
| if (fs.existsSync(cliPath)) { |  | ||||||
|   cli = require(cliPath); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| if (cli) { |  | ||||||
|   cli.run(); |  | ||||||
| } else { |  | ||||||
|   console.error('Are you at home directory of a react-native project?'); |  | ||||||
|   console.error('`pushy install` is under development, please run `npm install react-native-update` to install pushy manually.'); |  | ||||||
|   process.exit(1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function checkForVersionCommand() { |  | ||||||
|   if (process.argv.indexOf('-v') >= 0 || process.argv[2] === 'version') { |  | ||||||
|     console.log('react-native-update-cli: ' + require('../package.json').version); |  | ||||||
|     try { |  | ||||||
|       console.log('react-native-update: ' + require(PACKAGE_JSON_PATH()).version); |  | ||||||
|     } catch (e) { |  | ||||||
|       console.log('react-native-update: n/a - not inside a React Native project directory') |  | ||||||
|     } |  | ||||||
|     process.exit(); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user
	 sunnylqm
					sunnylqm