Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Apps Script To Copy Entire Google Drive File Structure; How To Avoid Timeouts?

My organization is switching to a Google Business account, and everyone needs to transfer their Drive files to their new accounts. Drive will not allow transfer of ownership between these accounts, so I've created a script to copy files and folders from the old account to the new account. (The old account's contents have been moved into a folder shared with the new account.)

Here's what I have so far:

function copyDrive() {
  var originFolder = DriveApp.getFolderById(originFolderID);
  var destination = DriveApp.getFolderById(destinationID);
  copyFiles(originFolder, destination);

};

function copyFiles(passedFolder, targetFolder) {
  var fileContents = passedFolder.getFiles();
  var file;
  var fileName;

  while(fileContents.hasNext()) {
    file = fileContents.next();
    fileName = file.getName();
    file.makeCopy(fileName, targetFolder);
  }
  copySubFolders(passedFolder, targetFolder);
};

function copySubFolders(passedFolder, targetFolder) {
  var folderContents = passedFolder.getFolders();
  var folder;
  var folderName;

  while(folderContents.hasNext()) {
    folder = folderContents.next();
    folderName = folder.getName();
    var subFolderCopy = targetFolder.createFolder(folderName);
    copyFiles(folder, subFolderCopy);
  }
};

Please pardon any inelegance; I am new at this. The script actually works great and preserves the folder structure, but it times out after copying ~150 files and folders. I've been looking into how to use continuation tokens, and I've read this post closely. I think I'm stuck on a conceptual level, because I'm not sure how the continuation tokens will interact with the recursive functions I've set up. It seems like I will end up with a stack of my copySubFolders function, and they will each need their own continuation tokens. Of course they all use the same variable name for their iterators, so I really have no idea how to set that up.

Any thoughts? Sorry for posting such a helpless newbie question; I hope it will at least be an interesting problem for someone.

like image 221
Bill Avatar asked Mar 24 '15 16:03

Bill


1 Answers

I think I have solved the conceptual problem, though I am getting

We're sorry, a server error occurred. Please wait a bit and try again. (line 9, file "Code")

when I try to execute it.

Basically, I set it up to only try to copy one top-level folder at a time, and for each one of those it uses the recursive functions I had before. It should save continuation tokens for that first level of folders and any files in the root folder so it can pick up in the next execution where it left off. This way, the tokens are not involved in my recursive stack of functions.

function copyDrive() {


  var originFolder = DriveApp.getFolderById(originFolderID);
  var destination = DriveApp.getFolderById(destinationID);

  var scriptProperties = PropertiesService.getScriptProperties();
  var fileContinuationToken = scriptProperties.getProperty('FILE_CONTINUATION_TOKEN');
  var fileIterator = fileContinuationToken == null ?
    originFolder.getFiles() : DriveApp.continueFileIterator(fileContinuationToken);
  var folderContinuationToken = scriptProperties.getProperty('FOLDER_CONTINUATION_TOKEN');
  var folderIterator = folderContinuationToken == null ?
    originFolder.getFolders() : DriveApp.continueFolderIterator(folderContinuationToken);

  try {
    var rootFileName;
    while(fileIterator.hasNext()) {
      var rootFile = fileIterator.next();
      rootFileName = rootFile.getName();
      rootFile.makeCopy(rootFileName, destination);
      }

    var folder = folderIterator.next();
    var folderName = folder.getName();
    var folderCopy = folder.makeCopy(folderName, destination);


    copyFiles(folder, folderCopy);

  } catch(err) {
    Logger.log(err);
  }

  if(fileIterator.hasNext()) {
    scriptProperties.setProperty('FILE_CONTINUATION_TOKEN', fileIterator.getContinuationToken());
  } else {
    scriptProperties.deleteProperty('FILE_CONTINUATION_TOKEN');
  }
  if(folderIterator.hasNext()) {
    scriptProperties.setProperty('FOLDER_CONTINUATION_TOKEN', folderIterator.getContinuationToken());
  } else {
    scriptProperties.deleteProperty('FOLDER_CONTINUATION_TOKEN');
  }

};

function copyFiles(passedFolder, targetFolder) {
  var fileContents = passedFolder.getFiles();
  var file;
  var fileName;

  while(fileContents.hasNext()) {
    file = fileContents.next();
    fileName = file.getName();
    file.makeCopy(fileName, targetFolder);
  }
  copySubFolders(passedFolder, targetFolder);
};

function copySubFolders(passedFolder, targetFolder) {
  var subFolderContents = passedFolder.getFolders();
  var subFolder;
  var subFolderName;

  while(folderContents.hasNext()) {
    subFolder = subFolderContents.next();
    subFolderName = subFolder.getName();
    var subFolderCopy = targetFolder.createFolder(folderName);
    copyFiles(subFolder, subFolderCopy);
  }
};
like image 67
Bill Avatar answered Nov 04 '22 07:11

Bill