From 0c5c101d2bb1b90bf5deb95f77dd35c4dfd6c1e9 Mon Sep 17 00:00:00 2001 From: Nikita Riabchenko Date: Wed, 4 Jul 2018 10:10:51 +0300 Subject: [PATCH 01/12] Added dependencies for Google Drive integration. --- build.gradle | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0e99c85..d000153 100644 --- a/build.gradle +++ b/build.gradle @@ -66,7 +66,16 @@ dependencies { ['io.qameta.allure:allure-testng:2.6.0'], // Logging - ['ch.qos.logback:logback-classic:1.2.3'] + ['ch.qos.logback:logback-classic:1.2.3'], + + // Google API client + ['com.google.api-client:google-api-client:1.23.0'], + + // Google OAuth + ['com.google.oauth-client:google-oauth-client-jetty:1.23.0'], + + // Google Drive API services + ['com.google.apis:google-api-services-drive:v3-rev110-1.23.0'] ) } From 22f9e819ac9a594d72511be6083cb669ae0bfcf0 Mon Sep 17 00:00:00 2001 From: Nikita Riabchenko Date: Wed, 4 Jul 2018 10:12:13 +0300 Subject: [PATCH 02/12] Added DriveClient and DriveService. --- .../core/google/drive/DriveClient.groovy | 216 ++++++++++++++++++ .../core/google/drive/DriveService.groovy | 192 ++++++++++++++++ 2 files changed, 408 insertions(+) create mode 100644 src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy create mode 100644 src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy new file mode 100644 index 0000000..5647ef5 --- /dev/null +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy @@ -0,0 +1,216 @@ +package com.sysgears.seleniumbundle.core.google.drive + +import com.google.api.client.auth.oauth2.Credential +import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp +import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver +import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow +import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport +import com.google.api.client.http.javanet.NetHttpTransport +import com.google.api.client.json.JsonFactory +import com.google.api.client.json.jackson2.JacksonFactory +import com.google.api.client.util.store.FileDataStoreFactory +import com.google.api.services.drive.Drive +import com.google.api.services.drive.DriveScopes +import com.google.common.collect.Iterables + +/** + * Provides low-level methods to work with Google Drive. + */ +class DriveClient { + + // TODO Try to set null + private static final String APPLICATION_NAME = "Test application" + + /** + * Instance of JsonFactory to be used by Google Drive API. + */ + private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance() + + + private static final String FOLDER_MIME_TYPE = "application/vnd.google-apps.folder" + + /** + * Instance of HTTP transport to be used by Google Drive API. + */ + private final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport() + + /** + * Instance of service to be used by Google Drive API. + */ + Drive service + + /** + * Path to directory where authorized credentials will be stored. + */ + private static final String CREDENTIALS_FOLDER = "credentials" + + /** + * If modifying scopes, delete your previously saved credentials/ folder. + */ + private static final List SCOPES = Collections.singletonList(DriveScopes.DRIVE) + + /** + * Path to file with client secret. + */ + private static final String CLIENT_SECRET_DIR = "client_secret.json" + + /** + * Creates an instance of DriveClient. + */ + DriveClient() { + this.service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT)) + .setApplicationName(APPLICATION_NAME) + .build() + } + + /** + * Creates an authorized Credential object. + * + * @param HTTP_TRANSPORT The network HTTP Transport + * + * @return An authorized Credential object + * + * @throws IOException If there is no client_secret + */ + static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException { + // Load client secrets + InputStream inputStream = this.getClassLoader().getResourceAsStream(CLIENT_SECRET_DIR) + GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(inputStream)) + + // Build flow and trigger user authorization request + GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES) + .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(CREDENTIALS_FOLDER))) + .setAccessType("offline") + .build() + new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user") + } + + /** + * Get path to file from root folder on Drive. + * + * @param fileId id of a file to get path to + * + * @return path to file on Drive relatively to Drive root folder + */ + String getPathFromRootFolderFor(String fileId) { +// def path = getFileById(fileId).getName() + def file = getFileById(fileId) + def path = [file.getName()] + def parentId = fileId + def rootFolderId = getRootFolderId() + + while (parentId != rootFolderId) { + def parentFile = getParentFor(parentId) + + if (parentFile.getId() == rootFolderId) { + break + } + + parentId = parentFile.getId() + path << parentFile.getName() + } + + path.reverse().join(java.io.File.separator) + } + + /** + * Gets parent for given fileId. + * + * @param fileId id of a file to find a parent for + * + * @return File object which represents parent for given file + */ + File getParentFor(String fileId) { + def parents = getFileById(fileId).getParents() + def parentId = Iterables.getOnlyElement(parents) + + getFileById(parentId) + } + + /** + * Gets files in a folder by the given folderId. + * + * @param folderId id of a folder to search for files in + * + * @return List of File object + */ + List getFilesInDirectory(String folderId) { + getFilesByParent(folderId).findResults { + it.getMimeType() != FOLDER_MIME_TYPE ? it : getFilesInDirectory(it.getId()) + }?.flatten() as List + } + + /** + * Gets File object of the last folder in the path. + * + * @param path path to get the last folder from + * + * @return File object of the last folder in the given path + */ + File getFolder(String path) { + def paths = path.split("/").toList().reverse() + def parentId = getRootFolderId() + + while (paths) { + def currentFolderName = paths.pop() + + parentId = getFilesByParent(parentId).find { + it.getName() == currentFolderName + }.getId() + } + + getFileById(parentId) + } + + File getFolderByParent(String name, String parentId) { + getFilesByParent(parentId).find { + log.info(it.toString()) + it.getName() == name && it.getMimeType() == FOLDER_MIME_TYPE + } + } + + /** + * Gets list of files which have the given parentId. + * + * @param parentId id of a parent file + * + * @return List of Files + */ + List getFilesByParent(String parentId) { + service.files().list().setQ("'" + parentId + "' in parents").set("fields", "files(kind, trashed, parents, " + + "id, name, mimeType)").execute().getFiles() + } + + /** + * Gets id of root folder of the Drive. + * + * @return id of the root folder + */ + String getRootFolderId() { + service.files().get("root").execute().getId() + } + + /** + * Gets File object for given fileId. + * + * @param fileId id of a file to get + * + * @return File object + */ + File getFileById(String fileId) { + service.files().get(fileId).set("fields", "parents, id, name, kind, mimeType, trashed").execute() + } + + /** + * TODO modify the comment + * Gets the name of the last folder from given path which does not contain file in it. + * + * @param path path to extract the last folder name + * + * @return folder name of the last folder in the path + */ + static String getStringValueAfterLastSlash(String path) { + path.substring(path.lastIndexOf("/")) - "/" + } +} diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy new file mode 100644 index 0000000..98ef7a8 --- /dev/null +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy @@ -0,0 +1,192 @@ +package com.sysgears.seleniumbundle.core.google.drive + +import com.google.api.client.http.FileContent +import com.sysgears.seleniumbundle.core.utils.FileHelper +import com.sysgears.seleniumbundle.core.utils.PathHelper + +import javax.activation.MimetypesFileTypeMap + +/** + * Provides methods to interact with files on Google Drive. + */ +class DriveService { + + /** + * Instance of DriveClient. + */ + private DriveClient client + + /** + * Creates an instance of DriveService. + * + * @param client Google Drive Client to be used by the service + */ + DriveService(DriveClient client) { + this.client = client + } + + /** + * Main method to download a file. + * + * @param fileId id of a file to be downloaded + * @param pathToSave path where a file has to be saved locally + */ + void downloadFileById(String fileId, String pathToSave) { + // create folders for new file + def localFile = new java.io.File(pathToSave) + localFile.getParentFile().mkdirs() + + // open streams + FileOutputStream fos = new FileOutputStream(localFile) + OutputStream outputStream = new ByteArrayOutputStream() + + // downloading process + client.service.files().get(fileId).executeMediaAndDownloadTo(outputStream) + outputStream.writeTo(fos) + } + + /** + * Downloads a file from Google Drive. + * + * @param path path to a file to download + * @param pathToSave path where the file will be saved locally + */ + void downloadFile(String path, String pathToSave) { + + //get id of a file to download + def fileId = client.getFilesInDirectory( + client.getFolder(path.substring(0, path.lastIndexOf("/"))).getId()).find { + it.getName() == client.getStringValueAfterLastSlash(path) + }.getId() + + downloadFileById(fileId, pathToSave) + } + + /** + * Downloads all files from given folder on Google Drive. Copies the exact hierarchy of folders and files. + * + * @param directoryPath path to folder from which the files will be downloaded from + * @param localPath path where the files will be saved locally + */ + void downloadFiles(String directoryPath, String localPath) { + client.getFilesInDirectory(client.getFolder(directoryPath).getId()).each { + def remotePath = client.getPathFromRootFolderFor(it.getId()) - directoryPath + + downloadFileById(it.getId(), "$localPath/$remotePath") + } + } + + /** + * Downloads all files from Google Drive. Copies the exact hierarchy of folders and files. + * + * @param localPath path where the files will be saved locally + */ + void downloadAllFiles(String localPath) { + client.getFilesInDirectory(client.getRootFolderId()).each { + def remotePath = client.getPathFromRootFolderFor(it.getId()) + + downloadFileById(it.getId(), "$localPath${java.io.File.separator}$remotePath") + } + } + + /** + * Main method to create a folder. + * + * @param name name of a folder + * @param parentId name of a parent folder, if parent id is not specified, the folder will be created relatively + * to root folder + * + * @return created File object + */ + File createFolder(String name, String parentId = null) { + + // create File object + File fileMetadata = new File() + .setName(name) + .setMimeType("application/vnd.google-apps.folder") + .setParents([parentId ? parentId : client.getRootFolderId()]) + + // create process + client.service.files().create(fileMetadata) + .setFields("id") + .execute() + } + + /** + * Creates folders if they are not created yet. + * + * @param path hierarchy of folders which has to be created + * @param parentId id of a parent folder, if parent id is not specified, the hierarchy will be created relatively + * to root folder + */ + void createFolders(String path, String parentId = null) { + def folderNames = path.split("/").toList().reverse() + parentId = parentId ? parentId : client.getRootFolderId() + + while (folderNames) { + def currentFolderId = client.getFolderByParent(folderNames.last(), parentId)?.getId() + + if (!currentFolderId) { + parentId = createFolder(folderNames.pop(), parentId).getId() + } else { + parentId = currentFolderId + folderNames.pop() + } + } + } + + /** + * Main method to upload a file. If parentId is not provided, the file will be saved to root folder. + * + * @param pathToFile path to local file to be uploaded + * @param parentId id of the parent folder to upload the file to + */ + void uploadFileToParentFolder(String pathToFile, String parentId = null) { + parentId = parentId ? parentId : client.getRootFolderId() + def fileName = client.getStringValueAfterLastSlash(pathToFile) + + // create File object + File fileMetadata = new File() + fileMetadata.setName(fileName) + fileMetadata.setParents(Collections.singletonList(parentId)) + + // read local file + FileContent mediaContent = new FileContent(new MimetypesFileTypeMap().getContentType(fileName), + new java.io.File(pathToFile)) + + // uploading process + client.service.files().create(fileMetadata, mediaContent) + .setFields("id, parents") + .execute() + } + + /** + * Uploads given file to given folder on Google Drive. + * + * @param localPath path to a local file to be uploaded + * @param remotePath path to the file on Google Drive + */ + void uploadFile(String localPath, String remotePath) { + def pathToRemoteDirectory = remotePath.substring(0, remotePath.lastIndexOf("/") + 1) + + createFolders(pathToRemoteDirectory) + + uploadFileToParentFolder(localPath, client.getFolder(pathToRemoteDirectory).getId()) + } + + /** + * Uploads all files in given repository. + * + * @param localPath path to a local directory from which to upload files + * @param remotePath path on Google Drive to save files to + */ + void uploadFiles(String localPath, String remotePath) { + def pathsToFiles = FileHelper.getFiles(localPath).collect { + it.path + } + + pathsToFiles.each { + uploadFile(it, "$remotePath/${PathHelper.getRelativePath(it, localPath)}") + } + } +} From 42fa8dccd5e1253e6562a3e80664c9a067c72d0a Mon Sep 17 00:00:00 2001 From: Nikita Riabchenko Date: Wed, 11 Jul 2018 14:08:31 +0300 Subject: [PATCH 03/12] Reorganized methods in the module to be like in Dropbox module. --- .../core/google/drive/DriveClient.groovy | 246 +++++++++++++----- .../core/google/drive/DriveService.groovy | 155 +---------- .../config/ApplicationProperties.groovy | 8 + 3 files changed, 198 insertions(+), 211 deletions(-) diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy index 5647ef5..431822b 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy @@ -6,61 +6,62 @@ import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport +import com.google.api.client.http.FileContent import com.google.api.client.http.javanet.NetHttpTransport import com.google.api.client.json.JsonFactory import com.google.api.client.json.jackson2.JacksonFactory import com.google.api.client.util.store.FileDataStoreFactory import com.google.api.services.drive.Drive import com.google.api.services.drive.DriveScopes +import com.google.api.services.drive.model.File import com.google.common.collect.Iterables +import com.sysgears.seleniumbundle.core.conf.Config +import groovy.util.logging.Slf4j + +import javax.activation.MimetypesFileTypeMap /** * Provides low-level methods to work with Google Drive. */ +@Slf4j class DriveClient { - // TODO Try to set null - private static final String APPLICATION_NAME = "Test application" - /** * Instance of JsonFactory to be used by Google Drive API. */ private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance() - - private static final String FOLDER_MIME_TYPE = "application/vnd.google-apps.folder" - /** - * Instance of HTTP transport to be used by Google Drive API. + * If modifying scopes, delete your previously saved credentials. */ - private final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport() + private static final List SCOPES = Collections.singletonList(DriveScopes.DRIVE) /** - * Instance of service to be used by Google Drive API. + * Mime type of a folder. */ - Drive service + private static final String FOLDER_MIME_TYPE = "application/vnd.google-apps.folder" /** - * Path to directory where authorized credentials will be stored. + * Instance of service to be used by Google Drive API. */ - private static final String CREDENTIALS_FOLDER = "credentials" + private Drive service /** - * If modifying scopes, delete your previously saved credentials/ folder. + * Instance of HTTP transport to be used by Google Drive API. */ - private static final List SCOPES = Collections.singletonList(DriveScopes.DRIVE) + private final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport() /** - * Path to file with client secret. + * Project properties. */ - private static final String CLIENT_SECRET_DIR = "client_secret.json" + private final Config conf = Config.instance /** * Creates an instance of DriveClient. */ DriveClient() { this.service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT)) - .setApplicationName(APPLICATION_NAME) + .setApplicationName(conf.google.drive.applicationName) .build() } @@ -73,49 +74,70 @@ class DriveClient { * * @throws IOException If there is no client_secret */ - static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException { + private Credential getCredentials(NetHttpTransport HTTP_TRANSPORT) throws IOException { // Load client secrets - InputStream inputStream = this.getClassLoader().getResourceAsStream(CLIENT_SECRET_DIR) + InputStream inputStream = this.class.getClassLoader().getResourceAsStream(conf.google.drive.clientSecret) GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(inputStream)) // Build flow and trigger user authorization request GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES) - .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(CREDENTIALS_FOLDER))) + .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(conf.google.drive.credentials as String))) .setAccessType("offline") .build() new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user") } /** - * Get path to file from root folder on Drive. - * - * @param fileId id of a file to get path to + * Gets id of root folder of the Drive. * - * @return path to file on Drive relatively to Drive root folder + * @return id of the root folder */ - String getPathFromRootFolderFor(String fileId) { -// def path = getFileById(fileId).getName() - def file = getFileById(fileId) - def path = [file.getName()] - def parentId = fileId - def rootFolderId = getRootFolderId() + String getRootFolderId() { + service.files().get("root").execute().getId() + } - while (parentId != rootFolderId) { - def parentFile = getParentFor(parentId) + /** + * Gets File object for given fileId. + * + * @param fileId id of a file to get + * + * @return File object + */ + File getFileById(String fileId) { + service.files().get(fileId).set("fields", "parents, id, name, kind, mimeType, trashed").execute() + } - if (parentFile.getId() == rootFolderId) { - break - } + /** + * Gets File object for a file which is stored by a given path. + * + * @param path path to a file on Google Drive + * + * @return File object + */ + File getFileByPath(String path) { + def folderId = getFolder(path.substring(0, path.lastIndexOf("/"))).getId() - parentId = parentFile.getId() - path << parentFile.getName() + getFilesInFolder(folderId).find { + it.getName() == new java.io.File(path).getName() } + } - path.reverse().join(java.io.File.separator) + /** + * Gets list of files which have the given parentId. + * + * @param parentId id of a parent file + * + * @return List of Files + */ + List getFilesByParent(String parentId) { + service.files().list().setQ("'" + parentId + "' in parents").set("fields", "files(kind, trashed, parents, " + + "id, name, mimeType)").execute().getFiles().findAll { + !it.getTrashed() + } } /** - * Gets parent for given fileId. + * Gets parent of a file with given fileId. * * @param fileId id of a file to find a parent for * @@ -135,9 +157,9 @@ class DriveClient { * * @return List of File object */ - List getFilesInDirectory(String folderId) { + List getFilesInFolder(String folderId) { getFilesByParent(folderId).findResults { - it.getMimeType() != FOLDER_MIME_TYPE ? it : getFilesInDirectory(it.getId()) + it.getMimeType() != FOLDER_MIME_TYPE ? it : getFilesInFolder(it.getId()) }?.flatten() as List } @@ -163,54 +185,148 @@ class DriveClient { getFileById(parentId) } + /** + * Gets File instance of a folder by folder name and its parent id. + * + * @param name name of a folder + * @param parentId id of a parent file + * + * @return File object of the folder + */ File getFolderByParent(String name, String parentId) { getFilesByParent(parentId).find { - log.info(it.toString()) - it.getName() == name && it.getMimeType() == FOLDER_MIME_TYPE + it.getName() == name && it.getMimeType() == FOLDER_MIME_TYPE && !it.getTrashed() } } /** - * Gets list of files which have the given parentId. + * Get path to a file from root folder on Drive. * - * @param parentId id of a parent file + * @param fileId id of a file to get path to * - * @return List of Files + * @return path to file on Drive relatively to Drive root folder */ - List getFilesByParent(String parentId) { - service.files().list().setQ("'" + parentId + "' in parents").set("fields", "files(kind, trashed, parents, " + - "id, name, mimeType)").execute().getFiles() + String getPathFromRootFolderFor(String fileId) { + def path = [getFileById(fileId).getName()] + def parentId = fileId + def rootFolderId = getRootFolderId() + + while (parentId != rootFolderId) { + def parentFile = getParentFor(parentId) + + if (parentFile.getId() == rootFolderId) { + break + } + + parentId = parentFile.getId() + path << parentFile.getName() + } + + path.reverse().join("/") } /** - * Gets id of root folder of the Drive. + * Main method to download a file. * - * @return id of the root folder + * @param fileId id of a file to be downloaded + * @param pathToSave path where a file has to be saved locally */ - String getRootFolderId() { - service.files().get("root").execute().getId() + void downloadFileById(String fileId, String pathToSave) { + + // create folders for new file + def localFile = new java.io.File(pathToSave) + localFile.getParentFile().mkdirs() + + // open streams + FileOutputStream fos = new FileOutputStream(localFile) + OutputStream outputStream = new ByteArrayOutputStream() + + // downloading process + service.files().get(fileId).executeMediaAndDownloadTo(outputStream) + outputStream.writeTo(fos) } /** - * Gets File object for given fileId. + * Main method to upload a file. If parentId is not provided, the file will be saved to root folder. * - * @param fileId id of a file to get + * @param pathToFile path to local file to be uploaded + * @param parentId id of the parent folder to upload the file to + */ + void uploadFileToParentFolder(String pathToFile, String parentId = null) { + parentId = parentId ? parentId : getRootFolderId() + def fileName = new java.io.File(pathToFile).getName() + + // create File object + File fileMetadata = new File() + fileMetadata.setName(fileName) + fileMetadata.setParents(Collections.singletonList(parentId)) + + // read local file + FileContent mediaContent = new FileContent(new MimetypesFileTypeMap().getContentType(fileName), + new java.io.File(pathToFile)) + + // uploading process + service.files().create(fileMetadata, mediaContent) + .setFields("id, parents") + .execute() + } + + /** + * Deletes files by a given fileId. * - * @return File object + * @param fileId id of a file to delete */ - File getFileById(String fileId) { - service.files().get(fileId).set("fields", "parents, id, name, kind, mimeType, trashed").execute() + void delete(String fileId) { + service.files().delete(fileId).execute() } /** - * TODO modify the comment - * Gets the name of the last folder from given path which does not contain file in it. + * Main method to create a folder. * - * @param path path to extract the last folder name + * @param name name of a folder + * @param parentId name of a parent folder, if parent id is not specified, the folder will be created relatively + * to root folder + * + * @return created File object + */ + File createFolder(String name, String parentId = null) { + + // create File object + File fileMetadata = new File() + .setName(name) + .setMimeType("application/vnd.google-apps.folder") + .setParents([parentId ? parentId : getRootFolderId()]) + + // creation process + service.files().create(fileMetadata) + .setFields("id") + .execute() + } + + /** + * Creates folders if they are not created yet. * - * @return folder name of the last folder in the path + * @param path hierarchy of folders which has to be created + * @param parentId id of a parent folder, if parent id is not specified, the hierarchy will be created relatively + * to root folder */ - static String getStringValueAfterLastSlash(String path) { - path.substring(path.lastIndexOf("/")) - "/" + boolean createFolders(String path, String parentId = null) { + def folderNames = path.split("/").toList().reverse() + parentId = parentId ? parentId : getRootFolderId() + def created = false + + while (folderNames) { + def currentFolderId = getFolderByParent(folderNames.last(), parentId)?.getId() + + if (!currentFolderId) { + parentId = createFolder(folderNames.pop(), parentId).getId() + created = true + } else { + parentId = currentFolderId + folderNames.pop() + } + } + + created } -} +} \ No newline at end of file diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy index 98ef7a8..3217dae 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy @@ -1,11 +1,5 @@ package com.sysgears.seleniumbundle.core.google.drive -import com.google.api.client.http.FileContent -import com.sysgears.seleniumbundle.core.utils.FileHelper -import com.sysgears.seleniumbundle.core.utils.PathHelper - -import javax.activation.MimetypesFileTypeMap - /** * Provides methods to interact with files on Google Drive. */ @@ -25,26 +19,6 @@ class DriveService { this.client = client } - /** - * Main method to download a file. - * - * @param fileId id of a file to be downloaded - * @param pathToSave path where a file has to be saved locally - */ - void downloadFileById(String fileId, String pathToSave) { - // create folders for new file - def localFile = new java.io.File(pathToSave) - localFile.getParentFile().mkdirs() - - // open streams - FileOutputStream fos = new FileOutputStream(localFile) - OutputStream outputStream = new ByteArrayOutputStream() - - // downloading process - client.service.files().get(fileId).executeMediaAndDownloadTo(outputStream) - outputStream.writeTo(fos) - } - /** * Downloads a file from Google Drive. * @@ -54,110 +28,9 @@ class DriveService { void downloadFile(String path, String pathToSave) { //get id of a file to download - def fileId = client.getFilesInDirectory( - client.getFolder(path.substring(0, path.lastIndexOf("/"))).getId()).find { - it.getName() == client.getStringValueAfterLastSlash(path) - }.getId() - - downloadFileById(fileId, pathToSave) - } - - /** - * Downloads all files from given folder on Google Drive. Copies the exact hierarchy of folders and files. - * - * @param directoryPath path to folder from which the files will be downloaded from - * @param localPath path where the files will be saved locally - */ - void downloadFiles(String directoryPath, String localPath) { - client.getFilesInDirectory(client.getFolder(directoryPath).getId()).each { - def remotePath = client.getPathFromRootFolderFor(it.getId()) - directoryPath - - downloadFileById(it.getId(), "$localPath/$remotePath") - } - } - - /** - * Downloads all files from Google Drive. Copies the exact hierarchy of folders and files. - * - * @param localPath path where the files will be saved locally - */ - void downloadAllFiles(String localPath) { - client.getFilesInDirectory(client.getRootFolderId()).each { - def remotePath = client.getPathFromRootFolderFor(it.getId()) + def fileId = client.getFileByPath(path).getId() - downloadFileById(it.getId(), "$localPath${java.io.File.separator}$remotePath") - } - } - - /** - * Main method to create a folder. - * - * @param name name of a folder - * @param parentId name of a parent folder, if parent id is not specified, the folder will be created relatively - * to root folder - * - * @return created File object - */ - File createFolder(String name, String parentId = null) { - - // create File object - File fileMetadata = new File() - .setName(name) - .setMimeType("application/vnd.google-apps.folder") - .setParents([parentId ? parentId : client.getRootFolderId()]) - - // create process - client.service.files().create(fileMetadata) - .setFields("id") - .execute() - } - - /** - * Creates folders if they are not created yet. - * - * @param path hierarchy of folders which has to be created - * @param parentId id of a parent folder, if parent id is not specified, the hierarchy will be created relatively - * to root folder - */ - void createFolders(String path, String parentId = null) { - def folderNames = path.split("/").toList().reverse() - parentId = parentId ? parentId : client.getRootFolderId() - - while (folderNames) { - def currentFolderId = client.getFolderByParent(folderNames.last(), parentId)?.getId() - - if (!currentFolderId) { - parentId = createFolder(folderNames.pop(), parentId).getId() - } else { - parentId = currentFolderId - folderNames.pop() - } - } - } - - /** - * Main method to upload a file. If parentId is not provided, the file will be saved to root folder. - * - * @param pathToFile path to local file to be uploaded - * @param parentId id of the parent folder to upload the file to - */ - void uploadFileToParentFolder(String pathToFile, String parentId = null) { - parentId = parentId ? parentId : client.getRootFolderId() - def fileName = client.getStringValueAfterLastSlash(pathToFile) - - // create File object - File fileMetadata = new File() - fileMetadata.setName(fileName) - fileMetadata.setParents(Collections.singletonList(parentId)) - - // read local file - FileContent mediaContent = new FileContent(new MimetypesFileTypeMap().getContentType(fileName), - new java.io.File(pathToFile)) - - // uploading process - client.service.files().create(fileMetadata, mediaContent) - .setFields("id, parents") - .execute() + client.downloadFileById(fileId, pathToSave) } /** @@ -169,24 +42,14 @@ class DriveService { void uploadFile(String localPath, String remotePath) { def pathToRemoteDirectory = remotePath.substring(0, remotePath.lastIndexOf("/") + 1) - createFolders(pathToRemoteDirectory) + if (!client.createFolders(pathToRemoteDirectory)) { + def fileOnDrive = client.getFileByPath(remotePath) - uploadFileToParentFolder(localPath, client.getFolder(pathToRemoteDirectory).getId()) - } - - /** - * Uploads all files in given repository. - * - * @param localPath path to a local directory from which to upload files - * @param remotePath path on Google Drive to save files to - */ - void uploadFiles(String localPath, String remotePath) { - def pathsToFiles = FileHelper.getFiles(localPath).collect { - it.path + if (fileOnDrive && !fileOnDrive.getTrashed()) { + client.delete(fileOnDrive.getId()) + } } - pathsToFiles.each { - uploadFile(it, "$remotePath/${PathHelper.getRelativePath(it, localPath)}") - } + client.uploadFileToParentFolder(localPath, client.getFolder(pathToRemoteDirectory).getId()) } -} +} \ No newline at end of file diff --git a/src/main/resources/config/ApplicationProperties.groovy b/src/main/resources/config/ApplicationProperties.groovy index 04c6c40..a74341d 100644 --- a/src/main/resources/config/ApplicationProperties.groovy +++ b/src/main/resources/config/ApplicationProperties.groovy @@ -22,4 +22,12 @@ ui { difference = "build/reports/tests/uicomparison/difference" // diff images } ignoredElements = "src/test/resources/ignored_elements.yml" // a list of ignored elements for page objects +} + +google { + drive { + applicationName = "Example" // name of the application, it is required by Google + credentials = "credentials" // path to store authorized credentials + clientSecret = "client_secret.json" // path to file with secret filter + } } \ No newline at end of file From 366164b3d65d796e157297cb1a67e34b3c41498b Mon Sep 17 00:00:00 2001 From: Nikita Riabchenko Date: Mon, 6 Aug 2018 13:11:11 +0300 Subject: [PATCH 04/12] Minor changes to comments and code. --- .../core/google/drive/DriveClient.groovy | 63 ++++++++----------- .../core/google/drive/DriveService.groovy | 20 +++--- .../config/ApplicationProperties.groovy | 4 +- 3 files changed, 36 insertions(+), 51 deletions(-) diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy index 431822b..cf23fa7 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy @@ -16,14 +16,12 @@ import com.google.api.services.drive.DriveScopes import com.google.api.services.drive.model.File import com.google.common.collect.Iterables import com.sysgears.seleniumbundle.core.conf.Config -import groovy.util.logging.Slf4j import javax.activation.MimetypesFileTypeMap /** * Provides low-level methods to work with Google Drive. */ -@Slf4j class DriveClient { /** @@ -65,28 +63,6 @@ class DriveClient { .build() } - /** - * Creates an authorized Credential object. - * - * @param HTTP_TRANSPORT The network HTTP Transport - * - * @return An authorized Credential object - * - * @throws IOException If there is no client_secret - */ - private Credential getCredentials(NetHttpTransport HTTP_TRANSPORT) throws IOException { - // Load client secrets - InputStream inputStream = this.class.getClassLoader().getResourceAsStream(conf.google.drive.clientSecret) - GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(inputStream)) - - // Build flow and trigger user authorization request - GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES) - .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(conf.google.drive.credentials as String))) - .setAccessType("offline") - .build() - new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user") - } - /** * Gets id of root folder of the Drive. * @@ -200,7 +176,7 @@ class DriveClient { } /** - * Get path to a file from root folder on Drive. + * Get path to a file from the root folder on Drive. * * @param fileId id of a file to get path to * @@ -229,19 +205,16 @@ class DriveClient { * Main method to download a file. * * @param fileId id of a file to be downloaded - * @param pathToSave path where a file has to be saved locally + * @param pathToSave path where the file has to be saved locally */ void downloadFileById(String fileId, String pathToSave) { - // create folders for new file def localFile = new java.io.File(pathToSave) localFile.getParentFile().mkdirs() - // open streams FileOutputStream fos = new FileOutputStream(localFile) OutputStream outputStream = new ByteArrayOutputStream() - // downloading process service.files().get(fileId).executeMediaAndDownloadTo(outputStream) outputStream.writeTo(fos) } @@ -249,30 +222,27 @@ class DriveClient { /** * Main method to upload a file. If parentId is not provided, the file will be saved to root folder. * - * @param pathToFile path to local file to be uploaded + * @param pathToFile path to a local file to be uploaded * @param parentId id of the parent folder to upload the file to */ void uploadFileToParentFolder(String pathToFile, String parentId = null) { parentId = parentId ? parentId : getRootFolderId() def fileName = new java.io.File(pathToFile).getName() - // create File object File fileMetadata = new File() fileMetadata.setName(fileName) fileMetadata.setParents(Collections.singletonList(parentId)) - // read local file FileContent mediaContent = new FileContent(new MimetypesFileTypeMap().getContentType(fileName), new java.io.File(pathToFile)) - // uploading process service.files().create(fileMetadata, mediaContent) .setFields("id, parents") .execute() } /** - * Deletes files by a given fileId. + * Deletes a file with given fileId. * * @param fileId id of a file to delete */ @@ -290,14 +260,11 @@ class DriveClient { * @return created File object */ File createFolder(String name, String parentId = null) { - - // create File object File fileMetadata = new File() .setName(name) .setMimeType("application/vnd.google-apps.folder") .setParents([parentId ? parentId : getRootFolderId()]) - // creation process service.files().create(fileMetadata) .setFields("id") .execute() @@ -329,4 +296,26 @@ class DriveClient { created } + + /** + * Creates an authorized Credential object. + * + * @param HTTP_TRANSPORT The network HTTP Transport + * + * @return An authorized Credential object + * + * @throws IOException If there is no client_secret + */ + private Credential getCredentials(NetHttpTransport HTTP_TRANSPORT) throws IOException { + // Load client secrets + InputStream inputStream = this.class.getClassLoader().getResourceAsStream(conf.google.drive.clientSecret) + GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(inputStream)) + + // Build flow and trigger user authorization request + GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES) + .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(conf.google.drive.credentials as String))) + .setAccessType("offline") + .build() + new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user") + } } \ No newline at end of file diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy index 3217dae..1bd62c9 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy @@ -22,27 +22,23 @@ class DriveService { /** * Downloads a file from Google Drive. * - * @param path path to a file to download - * @param pathToSave path where the file will be saved locally + * @param remotePath path to a file to download + * @param localPath path where the file will be saved locally */ - void downloadFile(String path, String pathToSave) { - - //get id of a file to download - def fileId = client.getFileByPath(path).getId() - - client.downloadFileById(fileId, pathToSave) + void downloadFile(String remotePath, String localPath) { + client.downloadFileById(client.getFileByPath(remotePath).getId(), localPath) } /** - * Uploads given file to given folder on Google Drive. + * Uploads a file to Google Drive. * * @param localPath path to a local file to be uploaded * @param remotePath path to the file on Google Drive */ void uploadFile(String localPath, String remotePath) { - def pathToRemoteDirectory = remotePath.substring(0, remotePath.lastIndexOf("/") + 1) + def pathToFileDirectory = new File(remotePath).getParentFile().getPath() - if (!client.createFolders(pathToRemoteDirectory)) { + if (!client.createFolders(pathToFileDirectory)) { def fileOnDrive = client.getFileByPath(remotePath) if (fileOnDrive && !fileOnDrive.getTrashed()) { @@ -50,6 +46,6 @@ class DriveService { } } - client.uploadFileToParentFolder(localPath, client.getFolder(pathToRemoteDirectory).getId()) + client.uploadFileToParentFolder(localPath, client.getFolder(pathToFileDirectory).getId()) } } \ No newline at end of file diff --git a/src/main/resources/config/ApplicationProperties.groovy b/src/main/resources/config/ApplicationProperties.groovy index a74341d..3d3081a 100644 --- a/src/main/resources/config/ApplicationProperties.groovy +++ b/src/main/resources/config/ApplicationProperties.groovy @@ -27,7 +27,7 @@ ui { google { drive { applicationName = "Example" // name of the application, it is required by Google - credentials = "credentials" // path to store authorized credentials - clientSecret = "client_secret.json" // path to file with secret filter + credentials = "credentials" // path to a folder to store authorized credentials + clientSecret = "client_secret.json" // path to a file with client secrets, relative to "src/main/resources" } } \ No newline at end of file From 2aa366910e1a29329857bd8fb07d46801d6a84c2 Mon Sep 17 00:00:00 2001 From: Yuriy Vasylenko Date: Wed, 8 Aug 2018 14:48:32 +0300 Subject: [PATCH 05/12] Optimized getFileByPath method for DriverClient. --- .../seleniumbundle/core/google/drive/DriveClient.groovy | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy index cf23fa7..48470a5 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy @@ -16,6 +16,7 @@ import com.google.api.services.drive.DriveScopes import com.google.api.services.drive.model.File import com.google.common.collect.Iterables import com.sysgears.seleniumbundle.core.conf.Config +import org.apache.commons.io.FilenameUtils import javax.activation.MimetypesFileTypeMap @@ -91,10 +92,8 @@ class DriveClient { * @return File object */ File getFileByPath(String path) { - def folderId = getFolder(path.substring(0, path.lastIndexOf("/"))).getId() - - getFilesInFolder(folderId).find { - it.getName() == new java.io.File(path).getName() + getFilesInFolder(getFolder(FilenameUtils.getPath(path)).getId()).find { + it.getName() == FilenameUtils.getName(path) } } From 2bfa1ee00a6ef80033a68123564dfc9df2d74f98 Mon Sep 17 00:00:00 2001 From: Nikita Riabchenko Date: Wed, 8 Aug 2018 15:12:03 +0300 Subject: [PATCH 06/12] Renamed DriveService to GoogleDriveCloudService. --- .../{DriveService.groovy => GoogleDriveCloudService.groovy} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/{DriveService.groovy => GoogleDriveCloudService.groovy} (90%) diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy similarity index 90% rename from src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy rename to src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy index 1bd62c9..de6eb19 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveService.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy @@ -3,7 +3,7 @@ package com.sysgears.seleniumbundle.core.google.drive /** * Provides methods to interact with files on Google Drive. */ -class DriveService { +class GoogleDriveCloudService { /** * Instance of DriveClient. @@ -11,11 +11,11 @@ class DriveService { private DriveClient client /** - * Creates an instance of DriveService. + * Creates an instance of GoogleDriveCloudService. * * @param client Google Drive Client to be used by the service */ - DriveService(DriveClient client) { + GoogleDriveCloudService(DriveClient client) { this.client = client } From 3b1d569d0180809669396efcdb5c3a228f345748 Mon Sep 17 00:00:00 2001 From: Nikita Riabchenko Date: Wed, 8 Aug 2018 15:32:29 +0300 Subject: [PATCH 07/12] Modified GoogleDriveCloudService to comply with a new concept. --- .../drive/GoogleDriveCloudService.groovy | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy index de6eb19..9e4a233 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy @@ -1,5 +1,7 @@ package com.sysgears.seleniumbundle.core.google.drive +import com.sysgears.seleniumbundle.core.utils.FileHelper + /** * Provides methods to interact with files on Google Drive. */ @@ -8,16 +10,7 @@ class GoogleDriveCloudService { /** * Instance of DriveClient. */ - private DriveClient client - - /** - * Creates an instance of GoogleDriveCloudService. - * - * @param client Google Drive Client to be used by the service - */ - GoogleDriveCloudService(DriveClient client) { - this.client = client - } + private DriveClient client = new DriveClient() /** * Downloads a file from Google Drive. @@ -29,6 +22,22 @@ class GoogleDriveCloudService { client.downloadFileById(client.getFileByPath(remotePath).getId(), localPath) } + /** + * Downloads all files stored in remote path on Google Drive. + * + * @param remotePath path to files on Google Drive + * @param localPath local path to download the files to + */ + void downloadFiles(String remotePath, String localPath) { + def folderId = client.getFolder(remotePath).getId() + + client.getFilesInFolder(folderId).each { + def pathOnRemote = client.getPathFromRootFolderFor(it.getId()) + + client.downloadFileById(it.getId(), localPath + (pathOnRemote - remotePath)) + } + } + /** * Uploads a file to Google Drive. * @@ -48,4 +57,17 @@ class GoogleDriveCloudService { client.uploadFileToParentFolder(localPath, client.getFolder(pathToFileDirectory).getId()) } + + /** + * Uploads all files stored in local path to Google Drive. + * + * @param localPath + * @param remotePath + */ + void uploadFiles(String localPath, String remotePath) { + + FileHelper.getFiles(localPath).each { + uploadFiles(it.path, remotePath + (it.path - localPath)) + } + } } \ No newline at end of file From 0a95ca437c9174e8f595b972b37130ebd1445a67 Mon Sep 17 00:00:00 2001 From: Nikita Riabchenko Date: Fri, 10 Aug 2018 16:53:27 +0300 Subject: [PATCH 08/12] Modified methods in DriveClient. --- .../core/google/drive/DriveClient.groovy | 184 +++++++++--------- 1 file changed, 91 insertions(+), 93 deletions(-) diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy index 48470a5..88d6209 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy @@ -17,6 +17,7 @@ import com.google.api.services.drive.model.File import com.google.common.collect.Iterables import com.sysgears.seleniumbundle.core.conf.Config import org.apache.commons.io.FilenameUtils +import org.apache.commons.lang3.StringUtils import javax.activation.MimetypesFileTypeMap @@ -64,26 +65,6 @@ class DriveClient { .build() } - /** - * Gets id of root folder of the Drive. - * - * @return id of the root folder - */ - String getRootFolderId() { - service.files().get("root").execute().getId() - } - - /** - * Gets File object for given fileId. - * - * @param fileId id of a file to get - * - * @return File object - */ - File getFileById(String fileId) { - service.files().get(fileId).set("fields", "parents, id, name, kind, mimeType, trashed").execute() - } - /** * Gets File object for a file which is stored by a given path. * @@ -97,34 +78,6 @@ class DriveClient { } } - /** - * Gets list of files which have the given parentId. - * - * @param parentId id of a parent file - * - * @return List of Files - */ - List getFilesByParent(String parentId) { - service.files().list().setQ("'" + parentId + "' in parents").set("fields", "files(kind, trashed, parents, " + - "id, name, mimeType)").execute().getFiles().findAll { - !it.getTrashed() - } - } - - /** - * Gets parent of a file with given fileId. - * - * @param fileId id of a file to find a parent for - * - * @return File object which represents parent for given file - */ - File getParentFor(String fileId) { - def parents = getFileById(fileId).getParents() - def parentId = Iterables.getOnlyElement(parents) - - getFileById(parentId) - } - /** * Gets files in a folder by the given folderId. * @@ -145,33 +98,15 @@ class DriveClient { * * @return File object of the last folder in the given path */ - File getFolder(String path) { - def paths = path.split("/").toList().reverse() - def parentId = getRootFolderId() + File getFolder(String path, String parentId = getRootFolderId()) { + def currentFolderName = StringUtils.substringBefore(path, java.io.File.separator) + def remainingPath = StringUtils.substringAfter(path, java.io.File.separator) - while (paths) { - def currentFolderName = paths.pop() - - parentId = getFilesByParent(parentId).find { - it.getName() == currentFolderName - }.getId() + def currentFolder = getFilesByParent(parentId).find { + it.getName() == currentFolderName } - getFileById(parentId) - } - - /** - * Gets File instance of a folder by folder name and its parent id. - * - * @param name name of a folder - * @param parentId id of a parent file - * - * @return File object of the folder - */ - File getFolderByParent(String name, String parentId) { - getFilesByParent(parentId).find { - it.getName() == name && it.getMimeType() == FOLDER_MIME_TYPE && !it.getTrashed() - } + remainingPath ? getFolder(remainingPath, currentFolder.getId()) : currentFolder } /** @@ -249,26 +184,6 @@ class DriveClient { service.files().delete(fileId).execute() } - /** - * Main method to create a folder. - * - * @param name name of a folder - * @param parentId name of a parent folder, if parent id is not specified, the folder will be created relatively - * to root folder - * - * @return created File object - */ - File createFolder(String name, String parentId = null) { - File fileMetadata = new File() - .setName(name) - .setMimeType("application/vnd.google-apps.folder") - .setParents([parentId ? parentId : getRootFolderId()]) - - service.files().create(fileMetadata) - .setFields("id") - .execute() - } - /** * Creates folders if they are not created yet. * @@ -296,6 +211,88 @@ class DriveClient { created } + /** + * Gets id of root folder of the Drive. + * + * @return id of the root folder + */ + private String getRootFolderId() { + service.files().get("root").execute().getId() + } + + /** + * Gets File object for given fileId. + * + * @param fileId id of a file to get + * + * @return File object + */ + private File getFileById(String fileId) { + service.files().get(fileId).set("fields", "parents, id, name, kind, mimeType, trashed").execute() + } + + /** + * Gets list of files which have the given parentId. + * + * @param parentId id of a parent file + * + * @return List of Files + */ + private List getFilesByParent(String parentId) { + service.files().list().setQ("'$parentId' in parents").set("fields", "files(kind, trashed, parents, " + + "id, name, mimeType)").execute().getFiles().findAll { + !it.getTrashed() + } + } + + /** + * Gets parent of a file with given fileId. + * + * @param fileId id of a file to find a parent for + * + * @return File object which represents parent for given file + */ + private File getParentFor(String fileId) { + def parents = getFileById(fileId).getParents() + def parentId = Iterables.getOnlyElement(parents) + + getFileById(parentId) + } + + /** + * Gets File instance of a folder by folder name and its parent id. + * + * @param name name of a folder + * @param parentId id of a parent file + * + * @return File object of the folder + */ + private File getFolderByParent(String name, String parentId) { + getFilesByParent(parentId).find { + it.getName() == name && it.getMimeType() == FOLDER_MIME_TYPE && !it.getTrashed() + } + } + + /** + * Main method to create a folder. + * + * @param name name of a folder + * @param parentId name of a parent folder, if parent id is not specified, the folder will be created relatively + * to root folder + * + * @return created File object + */ + private File createFolder(String name, String parentId = null) { + File fileMetadata = new File() + .setName(name) + .setMimeType(FOLDER_MIME_TYPE) + .setParents([parentId ? parentId : getRootFolderId()]) + + service.files().create(fileMetadata) + .setFields("id") + .execute() + } + /** * Creates an authorized Credential object. * @@ -311,7 +308,8 @@ class DriveClient { GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(inputStream)) // Build flow and trigger user authorization request - GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES) + GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, + clientSecrets, SCOPES) .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(conf.google.drive.credentials as String))) .setAccessType("offline") .build() From a0ea26fdc534ca07adc74b8a7f1abab632f2b620 Mon Sep 17 00:00:00 2001 From: Nikita Riabchenko Date: Fri, 10 Aug 2018 16:55:03 +0300 Subject: [PATCH 09/12] Renamed DriveClient to GoogleDriveClient. --- .../{DriveClient.groovy => GoogleDriveCloudClient.groovy} | 6 +++--- .../core/google/drive/GoogleDriveCloudService.groovy | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/{DriveClient.groovy => GoogleDriveCloudClient.groovy} (98%) diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy similarity index 98% rename from src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy rename to src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy index 88d6209..9c8c398 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/DriveClient.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy @@ -24,7 +24,7 @@ import javax.activation.MimetypesFileTypeMap /** * Provides low-level methods to work with Google Drive. */ -class DriveClient { +class GoogleDriveCloudClient { /** * Instance of JsonFactory to be used by Google Drive API. @@ -57,9 +57,9 @@ class DriveClient { private final Config conf = Config.instance /** - * Creates an instance of DriveClient. + * Creates an instance of GoogleDriveCloudClient. */ - DriveClient() { + GoogleDriveCloudClient() { this.service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT)) .setApplicationName(conf.google.drive.applicationName) .build() diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy index 9e4a233..a8c4cdc 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy @@ -8,9 +8,9 @@ import com.sysgears.seleniumbundle.core.utils.FileHelper class GoogleDriveCloudService { /** - * Instance of DriveClient. + * Instance of GoogleDriveCloudClient. */ - private DriveClient client = new DriveClient() + private GoogleDriveCloudClient client = new GoogleDriveCloudClient() /** * Downloads a file from Google Drive. From 4db027a3b57409cf0a1c4e10f2d882af9a7ac2b4 Mon Sep 17 00:00:00 2001 From: Nikita Ryabchenko Date: Tue, 14 Aug 2018 16:44:20 +0300 Subject: [PATCH 10/12] Fixed issues with Google Drive module on Windows. --- .../drive/GoogleDriveCloudService.groovy | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy index a8c4cdc..2a979ed 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy @@ -1,6 +1,7 @@ package com.sysgears.seleniumbundle.core.google.drive import com.sysgears.seleniumbundle.core.utils.FileHelper +import org.apache.commons.io.FilenameUtils /** * Provides methods to interact with files on Google Drive. @@ -19,13 +20,13 @@ class GoogleDriveCloudService { * @param localPath path where the file will be saved locally */ void downloadFile(String remotePath, String localPath) { - client.downloadFileById(client.getFileByPath(remotePath).getId(), localPath) + client.downloadFileById(client.getFileByPath(remotePath).getId(), FilenameUtils.separatorsToSystem(localPath)) } /** * Downloads all files stored in remote path on Google Drive. * - * @param remotePath path to files on Google Drive + * @param remotePath path to a folder on Google Drive * @param localPath local path to download the files to */ void downloadFiles(String remotePath, String localPath) { @@ -34,7 +35,8 @@ class GoogleDriveCloudService { client.getFilesInFolder(folderId).each { def pathOnRemote = client.getPathFromRootFolderFor(it.getId()) - client.downloadFileById(it.getId(), localPath + (pathOnRemote - remotePath)) + client.downloadFileById(it.getId(), + FilenameUtils.separatorsToSystem(localPath) + (pathOnRemote - remotePath)) } } @@ -45,7 +47,7 @@ class GoogleDriveCloudService { * @param remotePath path to the file on Google Drive */ void uploadFile(String localPath, String remotePath) { - def pathToFileDirectory = new File(remotePath).getParentFile().getPath() + def pathToFileDirectory = FilenameUtils.getPath(remotePath) if (!client.createFolders(pathToFileDirectory)) { def fileOnDrive = client.getFileByPath(remotePath) @@ -55,18 +57,19 @@ class GoogleDriveCloudService { } } - client.uploadFileToParentFolder(localPath, client.getFolder(pathToFileDirectory).getId()) + client.uploadFileToParentFolder(FilenameUtils.separatorsToSystem(localPath), + client.getFolder(pathToFileDirectory).getId()) } /** * Uploads all files stored in local path to Google Drive. * - * @param localPath - * @param remotePath + * @param localPath path to a local folder to be uploaded + * @param remotePath path to the remote folder on Google Drive */ void uploadFiles(String localPath, String remotePath) { - FileHelper.getFiles(localPath).each { + FileHelper.getFiles(FilenameUtils.separatorsToSystem(localPath)).each { uploadFiles(it.path, remotePath + (it.path - localPath)) } } From beed935fe1363b344429dba0763cdc7eaf976766 Mon Sep 17 00:00:00 2001 From: Yuriy Vasylenko Date: Fri, 14 Dec 2018 14:47:25 +0200 Subject: [PATCH 11/12] Refactored methods for Drive Client. --- .../drive/GoogleDriveCloudClient.groovy | 240 +++++++++--------- .../drive/GoogleDriveCloudService.groovy | 35 ++- 2 files changed, 131 insertions(+), 144 deletions(-) diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy index 9c8c398..b591497 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy @@ -17,7 +17,6 @@ import com.google.api.services.drive.model.File import com.google.common.collect.Iterables import com.sysgears.seleniumbundle.core.conf.Config import org.apache.commons.io.FilenameUtils -import org.apache.commons.lang3.StringUtils import javax.activation.MimetypesFileTypeMap @@ -27,24 +26,19 @@ import javax.activation.MimetypesFileTypeMap class GoogleDriveCloudClient { /** - * Instance of JsonFactory to be used by Google Drive API. - */ - private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance() - - /** - * If modifying scopes, delete your previously saved credentials. + * Mime type of a folder. */ - private static final List SCOPES = Collections.singletonList(DriveScopes.DRIVE) + private static final String FOLDER_MIME_TYPE = "application/vnd.google-apps.folder" /** - * Mime type of a folder. + * Instance of JsonFactory to be used by Google Drive API. */ - private static final String FOLDER_MIME_TYPE = "application/vnd.google-apps.folder" + private final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance() /** - * Instance of service to be used by Google Drive API. + * If modifying scopes, delete your previously saved credentials. */ - private Drive service + private final List SCOPES = Collections.singletonList(DriveScopes.DRIVE) /** * Instance of HTTP transport to be used by Google Drive API. @@ -56,85 +50,20 @@ class GoogleDriveCloudClient { */ private final Config conf = Config.instance + /** + * Instance of service to be used by Google Drive API. + */ + final Drive service + /** * Creates an instance of GoogleDriveCloudClient. */ GoogleDriveCloudClient() { - this.service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT)) + service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT)) .setApplicationName(conf.google.drive.applicationName) .build() } - /** - * Gets File object for a file which is stored by a given path. - * - * @param path path to a file on Google Drive - * - * @return File object - */ - File getFileByPath(String path) { - getFilesInFolder(getFolder(FilenameUtils.getPath(path)).getId()).find { - it.getName() == FilenameUtils.getName(path) - } - } - - /** - * Gets files in a folder by the given folderId. - * - * @param folderId id of a folder to search for files in - * - * @return List of File object - */ - List getFilesInFolder(String folderId) { - getFilesByParent(folderId).findResults { - it.getMimeType() != FOLDER_MIME_TYPE ? it : getFilesInFolder(it.getId()) - }?.flatten() as List - } - - /** - * Gets File object of the last folder in the path. - * - * @param path path to get the last folder from - * - * @return File object of the last folder in the given path - */ - File getFolder(String path, String parentId = getRootFolderId()) { - def currentFolderName = StringUtils.substringBefore(path, java.io.File.separator) - def remainingPath = StringUtils.substringAfter(path, java.io.File.separator) - - def currentFolder = getFilesByParent(parentId).find { - it.getName() == currentFolderName - } - - remainingPath ? getFolder(remainingPath, currentFolder.getId()) : currentFolder - } - - /** - * Get path to a file from the root folder on Drive. - * - * @param fileId id of a file to get path to - * - * @return path to file on Drive relatively to Drive root folder - */ - String getPathFromRootFolderFor(String fileId) { - def path = [getFileById(fileId).getName()] - def parentId = fileId - def rootFolderId = getRootFolderId() - - while (parentId != rootFolderId) { - def parentFile = getParentFor(parentId) - - if (parentFile.getId() == rootFolderId) { - break - } - - parentId = parentFile.getId() - path << parentFile.getName() - } - - path.reverse().join("/") - } - /** * Main method to download a file. * @@ -184,6 +113,69 @@ class GoogleDriveCloudClient { service.files().delete(fileId).execute() } + /** + * Gets File object for a file which is stored by a given path. + * + * @param path path to a file on Google Drive + * + * @return File object + */ + File getFileByPath(String path) { + getAllFilesInFolder(getFolder(FilenameUtils.getPath(path)).getId()).find { + it.getName() == FilenameUtils.getName(path) + } + } + + /** + * Get path to a file from the root folder on Drive. + * + * @param fileId id of a file to get path to + * + * @return path to file on Drive relatively to Drive root folder + */ + String getPathByFileId(String fileId) { + def file = getFileById(fileId) + def parent = getParentFor(fileId) + def closingElement = file.getMimeType() == FOLDER_MIME_TYPE ? java.io.File.separator : "" + + parent && fileId != getRootFolderId() ? + "${getPathByFileId(parent.getId())}${file.getName()}$closingElement" : + "" + } + + /** + * Gets all (including nested) files in a folder recursively by the given folderId. + * + * @param folderId id of a folder to search for files in + * + * @return List of File object + */ + List getAllFilesInFolder(String folderId) { + getFilesByParent(folderId).findResults { + it.getMimeType() != FOLDER_MIME_TYPE ? it : getAllFilesInFolder(it.getId()) + }?.flatten() as List + } + + /** + * Gets File object of the last folder in the path. + * + * @param path path to get the last folder from + * + * @return File object of the last folder in the given path + */ + File getFolder(String path) { + def folderNames = path.split(java.io.File.separator) + def currentFolderId = getRootFolderId() + + folderNames.each { currentFolderName -> + currentFolderId = getFilesByParent(currentFolderId).find { + it.getName() == currentFolderName + }.getId() + } + + getFileById(currentFolderId) + } + /** * Creates folders if they are not created yet. * @@ -191,24 +183,34 @@ class GoogleDriveCloudClient { * @param parentId id of a parent folder, if parent id is not specified, the hierarchy will be created relatively * to root folder */ - boolean createFolders(String path, String parentId = null) { - def folderNames = path.split("/").toList().reverse() - parentId = parentId ? parentId : getRootFolderId() - def created = false - - while (folderNames) { - def currentFolderId = getFolderByParent(folderNames.last(), parentId)?.getId() - - if (!currentFolderId) { - parentId = createFolder(folderNames.pop(), parentId).getId() - created = true - } else { - parentId = currentFolderId - folderNames.pop() - } + String createFolders(String path) { + def folderNames = path.split(java.io.File.separator) + def currentFolderId = getRootFolderId() + + folderNames.each { currentFolderName -> + currentFolderId = getFolderByParent(currentFolderName, currentFolderId)?.getId() ?: + createFolder(currentFolderName, currentFolderId).getId() } + } - created + /** + * Main method to create a folder. + * + * @param name name of a folder + * @param parentId name of a parent folder, if parent id is not specified, the folder will be created relatively + * to root folder + * + * @return created File object + */ + private File createFolder(String name, String parentId = null) { + File fileMetadata = new File() + .setName(name) + .setMimeType(FOLDER_MIME_TYPE) + .setParents([parentId ? parentId : getRootFolderId()]) + + service.files().create(fileMetadata) + .setFields("id") + .execute() } /** @@ -228,7 +230,9 @@ class GoogleDriveCloudClient { * @return File object */ private File getFileById(String fileId) { - service.files().get(fileId).set("fields", "parents, id, name, kind, mimeType, trashed").execute() + service.files().get(fileId) + .setFields("parents, id, name, kind, mimeType, trashed") + .execute() } /** @@ -237,12 +241,16 @@ class GoogleDriveCloudClient { * @param parentId id of a parent file * * @return List of Files + * + * @throws IOException */ - private List getFilesByParent(String parentId) { - service.files().list().setQ("'$parentId' in parents").set("fields", "files(kind, trashed, parents, " + - "id, name, mimeType)").execute().getFiles().findAll { - !it.getTrashed() - } + private List getFilesByParent(String parentId) throws IOException { + service.files().list() + .setQ("'$parentId' in parents") + .setFields("files(kind, trashed, parents, id, name, mimeType)") + .execute() + .getFiles() + .findAll { !it.getTrashed() } } /** @@ -256,7 +264,7 @@ class GoogleDriveCloudClient { def parents = getFileById(fileId).getParents() def parentId = Iterables.getOnlyElement(parents) - getFileById(parentId) + parentId ? getFileById(parentId) : null } /** @@ -273,26 +281,6 @@ class GoogleDriveCloudClient { } } - /** - * Main method to create a folder. - * - * @param name name of a folder - * @param parentId name of a parent folder, if parent id is not specified, the folder will be created relatively - * to root folder - * - * @return created File object - */ - private File createFolder(String name, String parentId = null) { - File fileMetadata = new File() - .setName(name) - .setMimeType(FOLDER_MIME_TYPE) - .setParents([parentId ? parentId : getRootFolderId()]) - - service.files().create(fileMetadata) - .setFields("id") - .execute() - } - /** * Creates an authorized Credential object. * diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy index 2a979ed..a7cb699 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy @@ -11,7 +11,7 @@ class GoogleDriveCloudService { /** * Instance of GoogleDriveCloudClient. */ - private GoogleDriveCloudClient client = new GoogleDriveCloudClient() + GoogleDriveCloudClient client = new GoogleDriveCloudClient() /** * Downloads a file from Google Drive. @@ -26,17 +26,17 @@ class GoogleDriveCloudService { /** * Downloads all files stored in remote path on Google Drive. * - * @param remotePath path to a folder on Google Drive + * @param remoteFolderPath path to a folder on Google Drive * @param localPath local path to download the files to */ - void downloadFiles(String remotePath, String localPath) { - def folderId = client.getFolder(remotePath).getId() + void downloadFiles(String remoteFolderPath, String localPath) { + def folderId = client.getFolder(remoteFolderPath).getId() - client.getFilesInFolder(folderId).each { - def pathOnRemote = client.getPathFromRootFolderFor(it.getId()) + client.getAllFilesInFolder(folderId).each { + def remoteFilePath = client.getPathByFileId(it.getId()) - client.downloadFileById(it.getId(), - FilenameUtils.separatorsToSystem(localPath) + (pathOnRemote - remotePath)) + downloadFile(remoteFilePath, + FilenameUtils.separatorsToSystem(localPath) + (remoteFilePath - remoteFolderPath)) } } @@ -47,18 +47,17 @@ class GoogleDriveCloudService { * @param remotePath path to the file on Google Drive */ void uploadFile(String localPath, String remotePath) { - def pathToFileDirectory = FilenameUtils.getPath(remotePath) + def fileOnDrive = client.getFileByPath(remotePath) + def parentId - if (!client.createFolders(pathToFileDirectory)) { - def fileOnDrive = client.getFileByPath(remotePath) - - if (fileOnDrive && !fileOnDrive.getTrashed()) { - client.delete(fileOnDrive.getId()) - } + if (fileOnDrive && !fileOnDrive.getTrashed()) { + parentId = fileOnDrive.getParents().first() + client.delete(fileOnDrive.getId()) + } else { + parentId = client.createFolders(FilenameUtils.getPath(remotePath)) } - client.uploadFileToParentFolder(FilenameUtils.separatorsToSystem(localPath), - client.getFolder(pathToFileDirectory).getId()) + client.uploadFileToParentFolder(FilenameUtils.separatorsToSystem(localPath), parentId) } /** @@ -70,7 +69,7 @@ class GoogleDriveCloudService { void uploadFiles(String localPath, String remotePath) { FileHelper.getFiles(FilenameUtils.separatorsToSystem(localPath)).each { - uploadFiles(it.path, remotePath + (it.path - localPath)) + uploadFile(it.path, remotePath + (it.path - localPath)) } } } \ No newline at end of file From cbaf27052e44c308d6f205ac39d2fd9482222623 Mon Sep 17 00:00:00 2001 From: Yuriy Vasylenko Date: Mon, 17 Dec 2018 15:17:57 +0200 Subject: [PATCH 12/12] Added exceptions handling for DriveClient and DriveService. --- .../drive/GoogleDriveCloudClient.groovy | 46 ++++++++++++++----- .../drive/GoogleDriveCloudService.groovy | 16 +++++-- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy index b591497..ab6d0a0 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudClient.groovy @@ -69,8 +69,10 @@ class GoogleDriveCloudClient { * * @param fileId id of a file to be downloaded * @param pathToSave path where the file has to be saved locally + * + * @throws IOException I/O exception */ - void downloadFileById(String fileId, String pathToSave) { + void downloadFileById(String fileId, String pathToSave) throws IOException { def localFile = new java.io.File(pathToSave) localFile.getParentFile().mkdirs() @@ -87,8 +89,10 @@ class GoogleDriveCloudClient { * * @param pathToFile path to a local file to be uploaded * @param parentId id of the parent folder to upload the file to + * + * @throws IOException I/O exception */ - void uploadFileToParentFolder(String pathToFile, String parentId = null) { + void uploadFileToParentFolder(String pathToFile, String parentId = null) throws IOException { parentId = parentId ? parentId : getRootFolderId() def fileName = new java.io.File(pathToFile).getName() @@ -108,8 +112,10 @@ class GoogleDriveCloudClient { * Deletes a file with given fileId. * * @param fileId id of a file to delete + * + * @throws IOException I/O exception */ - void delete(String fileId) { + void delete(String fileId) throws IOException { service.files().delete(fileId).execute() } @@ -119,8 +125,10 @@ class GoogleDriveCloudClient { * @param path path to a file on Google Drive * * @return File object + * + * @throws IOException I/O exception */ - File getFileByPath(String path) { + File getFileByPath(String path) throws IOException { getAllFilesInFolder(getFolder(FilenameUtils.getPath(path)).getId()).find { it.getName() == FilenameUtils.getName(path) } @@ -132,8 +140,10 @@ class GoogleDriveCloudClient { * @param fileId id of a file to get path to * * @return path to file on Drive relatively to Drive root folder + * + * @throws IOException I/O exception */ - String getPathByFileId(String fileId) { + String getPathByFileId(String fileId) throws IOException { def file = getFileById(fileId) def parent = getParentFor(fileId) def closingElement = file.getMimeType() == FOLDER_MIME_TYPE ? java.io.File.separator : "" @@ -149,8 +159,10 @@ class GoogleDriveCloudClient { * @param folderId id of a folder to search for files in * * @return List of File object + * + * @throws IOException I/O exception */ - List getAllFilesInFolder(String folderId) { + List getAllFilesInFolder(String folderId) throws IOException { getFilesByParent(folderId).findResults { it.getMimeType() != FOLDER_MIME_TYPE ? it : getAllFilesInFolder(it.getId()) }?.flatten() as List @@ -162,8 +174,10 @@ class GoogleDriveCloudClient { * @param path path to get the last folder from * * @return File object of the last folder in the given path + * + * @throws IOException I/O exception */ - File getFolder(String path) { + File getFolder(String path) throws IOException { def folderNames = path.split(java.io.File.separator) def currentFolderId = getRootFolderId() @@ -182,8 +196,10 @@ class GoogleDriveCloudClient { * @param path hierarchy of folders which has to be created * @param parentId id of a parent folder, if parent id is not specified, the hierarchy will be created relatively * to root folder + * + * @throws IOException I/O exception */ - String createFolders(String path) { + String createFolders(String path) throws IOException { def folderNames = path.split(java.io.File.separator) def currentFolderId = getRootFolderId() @@ -201,8 +217,10 @@ class GoogleDriveCloudClient { * to root folder * * @return created File object + * + * @throws IOException I/O exception */ - private File createFolder(String name, String parentId = null) { + private File createFolder(String name, String parentId = null) throws IOException { File fileMetadata = new File() .setName(name) .setMimeType(FOLDER_MIME_TYPE) @@ -217,8 +235,10 @@ class GoogleDriveCloudClient { * Gets id of root folder of the Drive. * * @return id of the root folder + * + * @throws IOException I/O exception */ - private String getRootFolderId() { + private String getRootFolderId() throws IOException { service.files().get("root").execute().getId() } @@ -228,8 +248,10 @@ class GoogleDriveCloudClient { * @param fileId id of a file to get * * @return File object + * + * @throws IOException I/O exception */ - private File getFileById(String fileId) { + private File getFileById(String fileId) throws IOException { service.files().get(fileId) .setFields("parents, id, name, kind, mimeType, trashed") .execute() @@ -242,7 +264,7 @@ class GoogleDriveCloudClient { * * @return List of Files * - * @throws IOException + * @throws IOException I/O exception */ private List getFilesByParent(String parentId) throws IOException { service.files().list() diff --git a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy index a7cb699..6d764de 100644 --- a/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy +++ b/src/main/groovy/com/sysgears/seleniumbundle/core/google/drive/GoogleDriveCloudService.groovy @@ -18,8 +18,10 @@ class GoogleDriveCloudService { * * @param remotePath path to a file to download * @param localPath path where the file will be saved locally + * + * @throws IOException I/O exception */ - void downloadFile(String remotePath, String localPath) { + void downloadFile(String remotePath, String localPath) throws IOException { client.downloadFileById(client.getFileByPath(remotePath).getId(), FilenameUtils.separatorsToSystem(localPath)) } @@ -28,8 +30,10 @@ class GoogleDriveCloudService { * * @param remoteFolderPath path to a folder on Google Drive * @param localPath local path to download the files to + * + * @throws IOException I/O exception */ - void downloadFiles(String remoteFolderPath, String localPath) { + void downloadFiles(String remoteFolderPath, String localPath) throws IOException { def folderId = client.getFolder(remoteFolderPath).getId() client.getAllFilesInFolder(folderId).each { @@ -45,8 +49,10 @@ class GoogleDriveCloudService { * * @param localPath path to a local file to be uploaded * @param remotePath path to the file on Google Drive + * + * @throws IOException I/O exception */ - void uploadFile(String localPath, String remotePath) { + void uploadFile(String localPath, String remotePath) throws IOException { def fileOnDrive = client.getFileByPath(remotePath) def parentId @@ -65,8 +71,10 @@ class GoogleDriveCloudService { * * @param localPath path to a local folder to be uploaded * @param remotePath path to the remote folder on Google Drive + * + * @throws IOException I/O exception */ - void uploadFiles(String localPath, String remotePath) { + void uploadFiles(String localPath, String remotePath) throws IOException { FileHelper.getFiles(FilenameUtils.separatorsToSystem(localPath)).each { uploadFile(it.path, remotePath + (it.path - localPath))