UNPKG

baidubce-cli

Version:

baidu cloud engine command line tools

376 lines (312 loc) 11.9 kB
/** * Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ var fs = require('fs'); var path = require('path'); var u = require('underscore'); var Q = require('q'); var moment = require('moment'); var bce = require('baidubce-sdk'); var humanize = require('humanize'); var kPattern = /^bs:\/\/([^\/]+)(\/.*)?/; var cmdConfig = require('../config'); var cmdPut = require('./cmd_put'); var argv = require('yargs') .usage('Usage: $0 bs') .boolean('h', {alias: 'help', describe: 'Show this help message.'}) .options('c', {alias: 'config', describe: 'Manage the baidubce configuration', 'boolean': true}) .options('list-buckets', {describe: 'List all buckets.', 'boolean': true}) .example('baidubce bs --list-buckets', 'List all buckets.') .options('create-buckets', {describe: 'Create buckets.', 'boolean': true}) .example('baidubce bs --create-buckets my-bucket-1 my-bucket-2', 'Create one or more buckets.') .options('delete-buckets', {describe: 'Delete buckets.', 'boolean': true}) .example('baidubce bs --delete-buckets my-bucket-1 my-bucket-2', 'Delete buckets') .options('set-bucket-acl', {describe: 'Set bucket acl.', 'boolean': true}) .example('baidubce bs --set-bucket-acl bucket-1 bucket-2 public-read-write', 'Set buckets public-read-write acl') .example('baidubce bs --set-bucket-acl bucket-1 bucket-2 private', 'Set buckets private acl\n') .options('list-objects', {describe: 'List all objects.', 'boolean': true}) .options('start', {describe: 'The 0-based offset.'}) .options('limit', {describe: 'The maximum count.'}) .example('baidubce bs --list-objects my-bucket-1', 'List all objects in the specific bucket') .example('baidubce bs --list-objects my-bucket-1 --start=10 --limit=20', 'List all objects in the specific bucket with `start` and `limit`') .options('put-object', {describe: 'Upload a regular file', requiresArg: true}) .example('baidubce bs --put-object hello.js bs://my-bucket/world.js', 'Upload a regular file') // .options('copy-object', {describe: 'Copy object from one bucket to another', 'boolean': true}) // .example('baidubce bs --copy-object bs://source/sk.js bs://target/tk.js <options>', // 'Copy object from one bucket to another') // .options('put-superfile', {describe: 'Upload a super large file', requiresArg: true}) // .example('baidubce bs --put-superfile hello.js bs://my-bucket/world.js', 'Upload a super large file') .options('delete-objects', {describe: 'Delete objects.', 'boolean': true}) .example('baidubce bs --delete-objects my-bucket-1 hello.js world.js', 'Delete objects') .check(function (args) { var x = ['p', 's']; var c = 0; u.each(x, function (key) { if (u.has(args, key)) { if (!fs.existsSync(args[key])) { throw new Error('No such file or directory ' + args[key]); } c += 1; } }); if (c > 0 && args._.length <= 0) { // We need the destination // baidubce bs --put=hello.js bs://my-bucket/world.js // ^^^^^^^^^^^^^^^^^^^^^^^^ // This is the destination. throw new Error('Please specify the destination bucket and key'); } var destination = args._[0]; if (c > 0 && !kPattern.test(destination)) { throw new Error('Invalid destination pattern, please refer the above ' + 'examples for more information.'); } }); exports.run = function () { var args = argv.argv; if (args.h === true || args.help === true) { argv.showHelp(); return; } else if (process.argv.length <= 2) { argv.showHelp(); return; } if (args.c) { if (!args._.length) { cmdConfig.dump(); } else { cmdConfig.set(args._); } return; } var actionMap = { 'create-buckets': createBuckets, 'list-buckets': listBuckets, 'set-bucket-acl': setBucketsAcl, 'list-objects': listObjects, 'delete-objects': deleteObjects, 'delete-buckets': deleteBuckets, 'copy-object': copyObject }; for (var ak in actionMap) { if (args[ak] === true) { return actionMap[ak](args._, args); } } if (args['put-object'] || args['put-superfile']) { var destination = args._[0]; var match = kPattern.exec(destination); if (!match) { console.error('Invalid destination pattern, please refer the above ' + 'examples for more information.'); return; } var bucket_name = match[1]; var key = getKey(args); var client = getClient(bucket_name); if (args['put-object']) { return cmdPut.putRegularFile(client, bucket_name, key, args['put-object']); } else if (args['put-superfile']) { return cmdPut.putSuperLargeFile(client, bucket_name, key, args['put-superfile']); } } }; function deleteBuckets(buckets) { return Q.all(u.map(buckets, function (bucket) { return getClient(bucket).deleteBucket(bucket); })).then(function (response) { console.log('DONE'); }).catch(function (error) { console.error(error); }); } function safeParse(text) { try { return JSON.parse(text); } catch (ex) { return null; } } function copyObject(args) { if (args.length !== 2) { console.error('Arguments insufficient'); return; } var source = args[0]; var target = args[1]; var options = safeParse(args[2]); var m1 = kPattern.exec(source); var m2 = kPattern.exec(target); var source_bucket_name = m1[1]; var source_key = m1[2]; var target_bucket_name = m2[1]; var target_key = m2[2]; var c1 = getClient(source_bucket_name); var c2 = getClient(target_bucket_name); if (c1.config.endpoint !== c2.config.endpoint) { console.error(source_bucket_name + ' and ' + target_bucket_name + ' belongs to different endpoint.'); return; } return c1.copyObject(source_bucket_name, source_key, target_bucket_name, target_key, options).then(function (response) { console.log('DONE'); }).catch(function (error) { console.error(error); }); } function deleteObjects(args) { if (args.length < 2) { console.error('Arguments insufficient'); return; } var bucket = args.shift(); var objects = args; var client = getClient(bucket); return Q.all(u.map(objects, function (object) { return client.deleteObject(bucket, object); })).then(function (response) { console.log('DONE'); }).catch(function (error) { console.error(error); }); } function listObjects(args, options) { if (!args || !args.length) { console.error('Arguments insufficient'); return; } var bucket_name = args[0]; return getClient(bucket_name).listObjects(bucket_name, u.pick(options, 'start', 'limit')) .then(function (response) { var objects = response.body.object_list; if (!objects.length) { console.log('Empty bucket.'); return; } var table = require('text-table'); var rows = [['No.', 'Name', 'Size', 'Last Modified']]; u.each(objects, function (object, idx) { rows.push([idx + 1, object.object, humanize.filesize(object.size), moment(new Date(1000 * object.mdatetime)).format('YYYY-MM-DD hh:mm:ss')]); }); console.log(table(rows, {stringLength: stringLength})); }).catch(function (error) { console.error(error); }); } function setBucketsAcl(args) { if (args.length < 2) { console.error('Arguments insufficient'); return; } var acl = args.pop(); var buckets = args; return Q.all(u.map(buckets, function (bucket) { return getClient(bucket).setBucketCannedAcl(bucket, acl); })).then(function (response) { console.log('DONE'); }).catch(function (error) { console.log(error); }); } function listBuckets() { getClient().listBuckets() .then(function (response) { var table = require('text-table'); var rows = [['No.', 'Name', 'Region', 'Used', 'Total', 'Create Date']]; u.each(response.body, function (bucket, idx) { rows.push([idx + 1, bucket.bucket_name, bucket.region ? bucket.region : '-', humanize.filesize(bucket.used_capacity), humanize.filesize(bucket.total_capacity), moment(new Date(1000 * bucket.cdatetime)).format('YYYY-MM-DD hh:mm:ss')]); }); console.log(table(rows, {stringLength: stringLength})); }) .catch(function (error) { console.error(error); }); } function createBuckets(buckets) { if (!buckets || !buckets.length) { console.log('Please specify the buckets you want to create.'); return; } return Q.all(u.map(buckets, function (bucket) { return getClient(bucket).createBucket(bucket); })).then(function (response) { console.log('DONE'); }).catch(function (error) { console.error(error); }); } /** * @param {string=} opt_bucket_name The bucket name. * * @return {bce.BcsClient} */ function getClient(opt_bucket_name) { var bucket_name = opt_bucket_name || ''; var ak; var sk; var endpoint; if (bucket_name) { ak = cmdConfig.get('bs.' + bucket_name + '.ak'); sk = cmdConfig.get('bs.' + bucket_name + '.sk'); endpoint = cmdConfig.get('bs.' + bucket_name + '.endpoint'); } ak = ak || cmdConfig.get('bs.ak'); sk = sk || cmdConfig.get('bs.sk'); endpoint = endpoint || cmdConfig.get('bs.endpoint'); if (!ak || !sk || !endpoint) { throw new Error('Please set ak, sk and endpoint.'); } return new bce.BcsClient({ credentials: {ak: ak, sk: sk}, endpoint: endpoint }); } function getKey(args) { // 1. check the destination first var destination = args._[0]; var match = kPattern.exec(destination); var key = match[2]; if (key) { key = key.replace(/^\/+/g, ''); key = key.replace(/\/+$/g, '/'); } // 2. then check the -p or -s argument value the first step failed. var basename = path.basename(args['put-object'] || args['put-superfile']); if (!basename) { throw new Error('Invalid argument, can not find the object name'); } // 3. If the key end with slash, so it's directory, we need append the basename if (/\/$/.test(key)) { key += basename; } else if (!key) { key = basename; } return key; } function stringLength(s) { var a = String(s).length; // Non-ASCII character will produce double width. var b = String(s).replace(/[\x00-\xff]/g, '').length; return a + b; } /* vim: set ts=4 sw=4 sts=4 tw=120: */