Skip to content

Commit

Permalink
storage: support rewrite operation (#1663)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenplusplus authored and callmehiphop committed Oct 5, 2016
1 parent 10cd2ac commit ff68eb9
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 7 deletions.
26 changes: 24 additions & 2 deletions packages/storage/src/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ function File(bucket, name, options) {

util.inherits(File, common.ServiceObject);

/*! Developer Documentation
*
* @param {object=} options - Configuration object.
* @param {string} options.token - A previously-returned `rewriteToken` from an
* unfinished rewrite request.
*/
/**
* Copy this file to another file. By default, this will copy the file to the
* same bucket, but you can choose to copy it to another Bucket by providing
Expand Down Expand Up @@ -356,13 +362,21 @@ util.inherits(File, common.ServiceObject);
* // The `copiedFile` parameter is equal to `anotherFile`.
* });
*/
File.prototype.copy = function(destination, callback) {
File.prototype.copy = function(destination, options, callback) {
var self = this;

var noDestinationError = new Error('Destination file should have a name.');

if (!destination) {
throw noDestinationError;
}

if (is.fn(options)) {
callback = options;
options = {};
}

options = options || {};
callback = callback || common.util.noop;

var destBucket;
Expand Down Expand Up @@ -394,12 +408,15 @@ File.prototype.copy = function(destination, callback) {
if (is.defined(this.generation)) {
query.sourceGeneration = this.generation;
}
if (is.defined(options.token)) {
query.rewriteToken = options.token;
}

newFile = newFile || destBucket.file(destName);

this.request({
method: 'POST',
uri: format('/copyTo/b/{bucketName}/o/{fileName}', {
uri: format('/rewriteTo/b/{bucketName}/o/{fileName}', {
bucketName: destBucket.name,
fileName: encodeURIComponent(destName)
}),
Expand All @@ -410,6 +427,11 @@ File.prototype.copy = function(destination, callback) {
return;
}

if (resp.rewriteToken) {
self.copy(newFile, { token: resp.rewriteToken }, callback);
return;
}

callback(null, newFile, resp);
});
};
Expand Down
29 changes: 29 additions & 0 deletions packages/storage/system-test/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,35 @@ describe('storage', function() {
});
});

it('should copy a large file', function(done) {
var otherBucket = storage.bucket(generateName());
var file = bucket.file('Big');
var copiedFile = otherBucket.file(file.name);

async.series([
function(callback) {
var opts = { destination: file };
bucket.upload(FILES.logo.path, opts, callback);
},
function(callback) {
otherBucket.create({
location: 'ASIA-EAST1',
dra: true
}, callback);
},
function(callback) {
file.copy(copiedFile, callback);
}
], function(err) {
assert.ifError(err);
async.series([
copiedFile.delete.bind(copiedFile),
otherBucket.delete.bind(otherBucket),
file.delete.bind(file)
], done);
});
});

it('should copy to another bucket given a gs:// URL', function(done) {
var opts = { destination: 'CloudLogo' };
bucket.upload(FILES.logo.path, opts, function(err, file) {
Expand Down
49 changes: 44 additions & 5 deletions packages/storage/test/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ describe('File', function() {
it('should URI encode file names', function(done) {
var newFile = new File(BUCKET, 'nested/file.jpg');

var expectedPath = format('/copyTo/b/{destBucket}/o/{destName}', {
var expectedPath = format('/rewriteTo/b/{destBucket}/o/{destName}', {
destBucket: file.bucket.name,
destName: encodeURIComponent(newFile.name)
});
Expand Down Expand Up @@ -295,7 +295,7 @@ describe('File', function() {

it('should allow a string', function(done) {
var newFileName = 'new-file-name.png';
var expectedPath = format('/copyTo/b/{destBucket}/o/{destName}', {
var expectedPath = format('/rewriteTo/b/{destBucket}/o/{destName}', {
destBucket: file.bucket.name,
destName: newFileName
});
Expand All @@ -305,7 +305,7 @@ describe('File', function() {

it('should allow a "gs://..." string', function(done) {
var newFileName = 'gs://other-bucket/new-file-name.png';
var expectedPath = format('/copyTo/b/{destBucket}/o/{destName}', {
var expectedPath = format('/rewriteTo/b/{destBucket}/o/{destName}', {
destBucket: 'other-bucket',
destName: 'new-file-name.png'
});
Expand All @@ -314,7 +314,7 @@ describe('File', function() {
});

it('should allow a Bucket', function(done) {
var expectedPath = format('/copyTo/b/{destBucket}/o/{destName}', {
var expectedPath = format('/rewriteTo/b/{destBucket}/o/{destName}', {
destBucket: BUCKET.name,
destName: file.name
});
Expand All @@ -324,7 +324,7 @@ describe('File', function() {

it('should allow a File', function(done) {
var newFile = new File(BUCKET, 'new-file');
var expectedPath = format('/copyTo/b/{destBucket}/o/{destName}', {
var expectedPath = format('/rewriteTo/b/{destBucket}/o/{destName}', {
destBucket: BUCKET.name,
destName: newFile.name
});
Expand All @@ -339,6 +339,45 @@ describe('File', function() {
});
});

describe('not finished copying', function() {
var apiResponse = {
rewriteToken: '...'
};

beforeEach(function() {
file.request = function(reqOpts, callback) {
callback(null, apiResponse);
};
});

it('should continue attempting to copy', function(done) {
var newFile = new File(BUCKET, 'new-file');

file.request = function(reqOpts, callback) {
file.copy = function(newFile_, options, callback) {
assert.strictEqual(newFile_, newFile);
assert.deepEqual(options, { token: apiResponse.rewriteToken });
callback(); // done()
};

callback(null, apiResponse);
};

file.copy(newFile, done);
});

it('should make the subsequent correct API request', function(done) {
var newFile = new File(BUCKET, 'new-file');

file.request = function(reqOpts) {
assert.strictEqual(reqOpts.qs.rewriteToken, apiResponse.rewriteToken);
done();
};

file.copy(newFile, { token: apiResponse.rewriteToken }, assert.ifError);
});
});

describe('returned File object', function() {
beforeEach(function() {
var resp = { success: true };
Expand Down

0 comments on commit ff68eb9

Please sign in to comment.