mirror of
https://gitcode.com/gh_mirrors/re/react-native-pushy.git
synced 2025-11-02 14:23:10 +08:00
pushy uploadIpa
This commit is contained in:
@@ -2,25 +2,42 @@
|
|||||||
"useCommand": true,
|
"useCommand": true,
|
||||||
"defaultCommand": "help",
|
"defaultCommand": "help",
|
||||||
"commands": {
|
"commands": {
|
||||||
"login":{
|
"help": {
|
||||||
"options": {
|
},
|
||||||
"username": {
|
|
||||||
|
|
||||||
|
"login":{
|
||||||
|
},
|
||||||
|
"logout": {
|
||||||
|
},
|
||||||
|
"me": {
|
||||||
|
},
|
||||||
|
|
||||||
|
"createApp": {
|
||||||
|
"options": {
|
||||||
|
"name": {
|
||||||
|
"hasValue": true
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"hasValue": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"logout": {
|
"apps": {
|
||||||
|
},
|
||||||
|
"deleteApp": {
|
||||||
|
},
|
||||||
|
"selectApp": {
|
||||||
|
"options": {
|
||||||
|
"platform": {
|
||||||
|
"hasValue": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"uploadIpa": {
|
||||||
|
|
||||||
},
|
},
|
||||||
"me": {
|
|
||||||
|
|
||||||
},
|
|
||||||
"help": {
|
|
||||||
|
|
||||||
},
|
|
||||||
"use": {
|
|
||||||
"description": "Select app created on web and create token for future release."
|
|
||||||
},
|
|
||||||
"build": {
|
"build": {
|
||||||
"description": "Bundle javascript and copy assets."
|
"description": "Bundle javascript and copy assets."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
const fetch = require('isomorphic-fetch');
|
const fetch = require('isomorphic-fetch');
|
||||||
let host = process.env.PUSHY_REGISTRY || 'http://pushy.reactnative.cn';
|
let host = process.env.PUSHY_REGISTRY || 'http://pushy.reactnative.cn';
|
||||||
const fs = require('fs-promise');
|
const fs = require('fs-promise');
|
||||||
|
import * as fsOrigin from 'fs';
|
||||||
|
import request from 'request';
|
||||||
|
import ProgressBar from 'progress';
|
||||||
|
|
||||||
let session = undefined;
|
let session = undefined;
|
||||||
let savedSession = undefined;
|
let savedSession = undefined;
|
||||||
@@ -45,7 +48,7 @@ exports.closeSession = async function(){
|
|||||||
savedSession = undefined;
|
savedSession = undefined;
|
||||||
}
|
}
|
||||||
session = undefined;
|
session = undefined;
|
||||||
host = process.env.PUSHY_REGISTRY || 'http://pushy.reactnative.cn';
|
host = process.env.PUSHY_REGISTRY || 'http://update.reactnative.cn';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function query(url, options) {
|
async function query(url, options) {
|
||||||
@@ -84,3 +87,44 @@ function queryWithBody(method) {
|
|||||||
exports.get = queryWithoutBody('GET');
|
exports.get = queryWithoutBody('GET');
|
||||||
exports.post = queryWithBody('POST');
|
exports.post = queryWithBody('POST');
|
||||||
exports.put = queryWithBody('PUT');
|
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)) {
|
||||||
|
url = host + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileSize = (await fs.stat(fn)).size;
|
||||||
|
|
||||||
|
const bar = new ProgressBar(' Uploading [:bar] :percent :etas', {
|
||||||
|
complete: '=',
|
||||||
|
incomplete: ' ',
|
||||||
|
total: fileSize,
|
||||||
|
});
|
||||||
|
|
||||||
|
const info = await new Promise((resolve, reject) => {
|
||||||
|
formData.file = fsOrigin.createReadStream(fn);
|
||||||
|
|
||||||
|
formData.file.on('data', function(data) {
|
||||||
|
bar.tick(data.length);
|
||||||
|
})
|
||||||
|
request.post({
|
||||||
|
url,
|
||||||
|
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;
|
||||||
91
local-cli/src/app.js
Normal file
91
local-cli/src/app.js
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* Created by tdzl2003 on 2/13/16.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {question} from './utils';
|
||||||
|
import * as fs from 'fs-promise';
|
||||||
|
|
||||||
|
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 async function getSelectedApp(platform) {
|
||||||
|
checkPlatform(platform);
|
||||||
|
|
||||||
|
if (!await fs.exists('update.json')){
|
||||||
|
throw new Error(`App not selected. run 'pushy selectApp --platform ${platform}' first!`);
|
||||||
|
}
|
||||||
|
const updateInfo = JSON.parse(await fs.readFile('update.json', 'utf8'));
|
||||||
|
if (!updateInfo[platform]) {
|
||||||
|
throw new Error(`App not selected. run 'pushy selectApp --platform ${platform}' first!`);
|
||||||
|
}
|
||||||
|
return updateInfo[platform];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const commands = {
|
||||||
|
createApp: async function ({options}) {
|
||||||
|
const name = options.name || await question('App Name:');
|
||||||
|
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},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteApp: async function ({args}) {
|
||||||
|
const id = args[0] || ((await this.apps()), (await question('Choose App to delete:')));
|
||||||
|
if (!id) {
|
||||||
|
console.log('Canceled');
|
||||||
|
}
|
||||||
|
await doDelete(`/app/${id}`);
|
||||||
|
console.log('Ok.');
|
||||||
|
},
|
||||||
|
apps: async function (_, 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`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectApp: async function({args, options}) {
|
||||||
|
const {platform} = options;
|
||||||
|
checkPlatform(platform);
|
||||||
|
const id = args[0] || ((await this.apps(null, platform)), (await question('Choose App used for ${platform}:')));
|
||||||
|
|
||||||
|
let updateInfo = {};
|
||||||
|
if (await fs.exists('update.json')) {
|
||||||
|
try {
|
||||||
|
updateInfo = JSON.parse(await fs.readFile('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,
|
||||||
|
};
|
||||||
|
await fs.writeFile('update.json', JSON.stringify(updateInfo, null, 4), 'utf8');
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -3,8 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const {loadSession} = require('./api');
|
const {loadSession} = require('./api');
|
||||||
const userCommands = require('./user').commands;
|
|
||||||
import {commands as bundleCommands} from './bundle';
|
|
||||||
|
|
||||||
function printUsage({args}) {
|
function printUsage({args}) {
|
||||||
// const commandName = args[0];
|
// const commandName = args[0];
|
||||||
@@ -16,8 +14,10 @@ function printUsage({args}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const commands = {
|
const commands = {
|
||||||
...userCommands,
|
...require('./user').commands,
|
||||||
...bundleCommands,
|
...require('./bundle').commands,
|
||||||
|
...require('./app').commands,
|
||||||
|
...require('./package').commands,
|
||||||
help: printUsage,
|
help: printUsage,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,6 +27,11 @@ exports.run = function () {
|
|||||||
loadSession()
|
loadSession()
|
||||||
.then(()=>commands[argv.command](argv))
|
.then(()=>commands[argv.command](argv))
|
||||||
.catch(err=>{
|
.catch(err=>{
|
||||||
|
if (err.status === 401) {
|
||||||
|
console.log('Not loggined.\nRun `pushy login` at your project directory to login.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(err.message);
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
|||||||
31
local-cli/src/package.js
Normal file
31
local-cli/src/package.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Created by tdzl2003 on 4/2/16.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const {
|
||||||
|
get,
|
||||||
|
post,
|
||||||
|
uploadFile,
|
||||||
|
} = require('./api');
|
||||||
|
|
||||||
|
import { checkPlatform, getSelectedApp } from './app';
|
||||||
|
|
||||||
|
import {getIPAVersion, getApkVersion} from './utils';
|
||||||
|
|
||||||
|
export const commands = {
|
||||||
|
uploadIpa: async function({args}) {
|
||||||
|
const fn = args[0];
|
||||||
|
if (!fn) {
|
||||||
|
throw new Error('Usage: pushy uploadIpa <ipaFile>');
|
||||||
|
}
|
||||||
|
const name = await getIPAVersion(fn);
|
||||||
|
const {appId} = await getSelectedApp('ios');
|
||||||
|
|
||||||
|
const {hash} = await uploadFile(fn);
|
||||||
|
|
||||||
|
await post(`/app/${appId}/package/create`, {
|
||||||
|
name,
|
||||||
|
hash,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -13,35 +13,31 @@ const {
|
|||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
function md5(str) {
|
function md5(str) {
|
||||||
return crypto.createHash('md5').update(str).digest('base64');
|
return crypto.createHash('md5').update(str).digest('hex');
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.commands = {
|
exports.commands = {
|
||||||
login: async function ({args}){
|
login: async function ({args}){
|
||||||
const login = args[0] || await question('user:');
|
const email = args[0] || await question('email:');
|
||||||
const pwd = args[1] || await question('password:', true);
|
const pwd = args[1] || await question('password:', true);
|
||||||
const {token} = await post('/user/login', {
|
const {token, info} = await post('/user/login', {
|
||||||
login,
|
email,
|
||||||
pwd: md5(pwd),
|
pwd: md5(pwd),
|
||||||
});
|
});
|
||||||
replaceSession({token});
|
replaceSession({token});
|
||||||
await saveSession();
|
await saveSession();
|
||||||
console.log('OK.');
|
console.log(`Welcome, ${info.name}.`);
|
||||||
},
|
},
|
||||||
logout: async function (){
|
logout: async function (){
|
||||||
await closeSession();
|
await closeSession();
|
||||||
console.log('Logged out.');
|
console.log('Logged out.');
|
||||||
},
|
},
|
||||||
me: async function (){
|
me: async function (){
|
||||||
try {
|
const me = await get('/user/me');
|
||||||
const me = await get('/user/me');
|
for (const k in me) {
|
||||||
console.log(me);
|
if (k !== 'ok') {
|
||||||
} catch (e) {
|
console.log(`${k}: ${me[k]}`);
|
||||||
if (e.status === 401) {
|
|
||||||
console.log('Not loggined.\nRun `pushy login` at your project directory to login.');
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function getApkVersion(fn) {
|
|||||||
export function getIPAVersion(fn) {
|
export function getIPAVersion(fn) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
ipaMetadata(fn, (err, data) => {
|
ipaMetadata(fn, (err, data) => {
|
||||||
err ? reject(err) : resolve(data);
|
err ? reject(err) : resolve(data.metadata.CFBundleShortVersionString);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,9 @@
|
|||||||
"mkdir-recursive": "^0.2.1",
|
"mkdir-recursive": "^0.2.1",
|
||||||
"node-apk-parser": "^0.2.3",
|
"node-apk-parser": "^0.2.3",
|
||||||
"node-bsdiff": "^0.1.2",
|
"node-bsdiff": "^0.1.2",
|
||||||
|
"progress": "^1.1.8",
|
||||||
"read": "^1.0.7",
|
"read": "^1.0.7",
|
||||||
|
"request": "^2.69.0",
|
||||||
"yauzl": "^2.4.1",
|
"yauzl": "^2.4.1",
|
||||||
"yazl": "^2.3.0"
|
"yazl": "^2.3.0"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user