diff --git a/README.md b/README.md
index d6d50ed..059712d 100755
--- a/README.md
+++ b/README.md
@@ -1,37 +1,98 @@
-# Google drive upload
+
Google drive upload
+
+
+
+
+
-Google drive upload is a Bash script based on v3 google APIs to upload files/directories into google drive. This is a minimalistic shell script which utilizes google OAuth2.0 device flow to generate access tokens to authorize application to upload files to your google drive.
+> Google drive upload is a bash compliant script based on v3 google APIs.
-Further usage documentation can be found at my blog page [Labbots.com](https://labbots.com/google-drive-upload-bash-script/ "Labbots.com").
+> It utilizes google OAuth2.0 to generate access tokens and to authorize application for uploading files/folders to your google drive.
-## Dependencies
+- Minimal
+- Upload or Update files/folders
+- Recursive folder uploading
+- Sync your folders
+ - Overwrite or skip existing files.
+- Resume Interrupted Uploads
+- Share files/folders
+ - To anyone or a specific email.
+- Config file support
+ - Easy to use on multiple machines.
+- Latest gdrive api used i.e v3
+- Pretty logging
+- Easy to install and update
-This script does not have very many dependencies. Most of the dependencies are available by default in most linux platforms. This script explicitly requires the following packages:
+## Table of Contents
-- Bash ( 4.x + )
-- Curl
-- grep
-- sed ( Stream editor )
-- file/mimetype ( generating mimetype for extensionless files )
-- find command ( for recursive uploading )
-- xargs ( for parallel uploading )
+- [Compatibility](#compatibility)
+ - [Linux or MacOS](#linux-or-macos)
+ - [Android](#android)
+ - [iOS](#ios)
+ - [Windows](#windows)
+- [Installing and Updating](#installing-and-updating)
+ - [Native Dependencies](#native-dependencies)
+ - [Installation](#installation)
+ - [Basic Method](#basic-method)
+ - [Advanced Method](#advanced-method)
+ - [Updation](#updation)
+- [Usage](#usage)
+ - [Generating Oauth Credentials](#generating-oauth-credentials)
+ - [First Run](#first-run)
+ - [Upload](#upload)
+ - [Custom Flags](#custom-flags)
+ - [Resuming Interrupted Uploads](#resuming-interrupted-uploads)
+- [Uninstall](#Uninstall)
+- [Inspired By](#inspired-by)
+- [License](#license)
-## Features
+## Compatibility
-- Upload files and folders normally/parallelly.
-- Upload sub-folders and content inside it hierarchically.
-- Upload multiple files / folders with single command.
-- Update (overwrite) your files/folder, like synchronisation.
-- Config file support ( easy to use script on multiple machines ).
-- Uses latest gdrive v3 api.
-- Share files after uploading ( to an email or just anyone ).
-- Pretty Logging.
-- Easy to install and update.
-- Resume interrupted uploads.
+As this is a bash script, there aren't many dependencies. See [Native Dependencies](#native-dependencies) after this section for explicitly required program list.
-## Installation
+### Linux or MacOS
-### Default values set by installation script
+For Linux or MacOS, you hopefully don't need to configure anything extra, it should work by default.
+
+### Android
+
+Install [Termux](https://wiki.termux.com/wiki/Main_Page) and done.
+
+It's fully tested for all usecases of this script.
+
+### iOS
+
+Install [iSH](https://ish.app/)
+
+While it has not been officially tested, but should work given the description of the app. Report if you got it working by creating an issue.
+
+### Windows
+
+Use [Windows Subsystem](https://docs.microsoft.com/en-us/windows/wsl/install-win10)
+
+Again, it has not been officially tested on windows, their shouldn't be anything preventing it from working. Report if you got it working by creating an issue.
+
+## Installing and Updating
+
+### Native Dependencies
+
+The script explicitly requires the following programs:
+
+| Program | Role In Script |
+| --------| -------------- |
+| Bash | Execution of script |
+| Curl | All network requests |
+| file/mimetype | Mimetype generation for extension less files |
+| find | To find files and folders for recursive folder uploads |
+| xargs | For parallel uploading |
+| grep | Miscellaneous |
+| sed | Miscellaneous |
+
+### Installation
+
+You can install the script by automatic installation script provided in the repository.
+
+Default values set by automatic installation script:
Repo: `labbots/google-drive-upload`
@@ -47,51 +108,73 @@ Shell file: `.bashrc` or `.zshrc` or `.profile`
For custom command names, repo, shell file, etc, see advanced installation method.
-### Basic Installation
+**Now, for automatic install script, there are two ways:**
+
+#### Basic Method
To install google-drive-upload in your system, you can run the below command:
-`curl --compressed -# -o- https://raw.githubusercontent.com/labbots/google-drive-upload/master/install.sh | bash`
+```shell
+bash <(curl --compressed -s https://raw.githubusercontent.com/labbots/google-drive-upload/master/install.sh)
+```
and done.
-### Advanced Installation
+#### Advanced Method
-This section provides on how to utilise the install.sh script fully for custom usescases.
+This section provides information on how to utilise the install.sh script for custom usescases.
-First, we need to download the script, run the following command:
+These are the flags that are available in the install.sh script:
-`curl --compressed -# https://raw.githubusercontent.com/labbots/google-drive-upload/master/install.sh -o install.sh`
+- **-i | --interactive**
-These are the flags that are available in the install.sh script:
+ Install script interactively, will ask for all the variables one by one.
+
+ Note: This will disregard all arguments given with below flags.
+
+- **-p | --path **
- -i | --interactive - Install script interactively, will ask for all the varibles one by one.
+ Custom path where you want to install the script.
- Note: This will disregard all arguments given with below flags.
+- **-c | --cmd **
- -p | --path - Custom path where you want to install script.
+ Custom command name, after installation, script will be available as the input argument.
- -c | --cmd - Custom command name, after installation script will be available as the input argument.
+- **-r | --repo **
- -r | --repo - Upload script from your custom repo,e.g --repo labbots/google-drive-upload, make sure your repo file structure is same as official repo.
+ Install script from your custom repo, e.g --repo labbots/google-drive-upload, make sure your repo file structure is same as official repo.
- -B | --branch - Specify branch name for the github repo, applies to custom and default repo both.
+- **-B | --branch **
- -R | --release - Specify tag name for the github repo, applies to custom and default repo both.
+ Specify branch name for the github repo, applies to custom and default repo both.
- -s | --shell-rc - Specify custom rc file, where PATH is appended, by default script detects .zshrc and .bashrc.
+- **-R | --release **
- -D | --debug - Display script command trace.
+ Specify tag name for the github repo, applies to custom and default repo both.
- -h | --help - Display usage instructions.
+- **-s | --shell-rc **
+
+ Specify custom rc file, where PATH is appended, by default script detects .zshrc, .bashrc. and .profile.
+
+- **-D | --debug**
+
+ Display script command trace.
+
+- **-h | --help**
+
+ Display usage instructions.
Now, run the script and use flags according to your usecase.
-E.g: `bash install.sh -r username/reponame -p somepath -s shell_file -c command_name -B branch_name`
+E.g:
+
+```shell
+bash <(curl --compressed -s https://raw.githubusercontent.com/labbots/google-drive-upload/master/install.sh) -r username/reponame -p somepath -s shell_file -c command_name -B branch_name
+```
-## Updation
+### Updation
-If you have followed the above method to install the script, then you can automatically update the script.
+If you have followed the automatic method to install the script, then you can automatically update the script.
There are two methods:
@@ -101,131 +184,193 @@ There are two methods:
This will update the script where it is installed.
- **If you use the this flag without actually installing the script, e.g just by `bash upload.sh -u` then it will install the script or update if already installed.**
+ **If you use the this flag without actually installing the script,**
+
+ **e.g just by `bash upload.sh -u` then it will install the script or update if already installed.**
2. Run the installation script again.
Yes, just run the installation script again as we did in install section, and voila, it's done.
-### Note: Both above methods obeys the values set by user in advanced installation, e.g if you have installed the script with different repo, say `myrepo/gdrive-upload`, then the update will be also fetched from the same repo
+**Note: Both above methods obeys the values set by user in advanced installation,**
+**e.g if you have installed the script with different repo, say `myrepo/gdrive-upload`, then the update will be also fetched from the same repo.**
## Usage
-When the script is executed for the first time. It asks for few configuration variables interactively to connect with google APIs. The script requires Client ID and Client secret to access the APIs which can be generated at [google console].
+First, we need to obtain our Oauth credentials, here's how to do it:
+
+### Generating Oauth Credentials
+
+- Log into google developer console at [google console](https://console.developers.google.com/).
+- Create new Project or use existing project.
+- Creating new OAuth 2.0 Credentials:
+ - Select Application type "other".
+ - Provide name for the new credentials. ( anything )
+ - This would provide a new Client ID and Client Secret.
+ - Download your credentials.json by clicking on the download button.
+- Enable Google Drive API for the project under "Library".
+
+Now, we have obtained our credentials, move to next section to use those credentials to setup:
+
+### First Run
+
+On first run, the script asks for all the required credentials, which we have obtained in the previous section.
+
+Execute the script: `gupload filename`
+
+Now, it will ask for following credentials:
+
+**Client ID:** Copy and paste from credentials.json
+
+**Client Secret:** Copy and paste from credentials.json
+
+**Refresh Token:** If you have previously generated a refresh token authenticated to your account, then enter it, otherwise leave blank.
+If you don't have refresh token, script outputs a URL on the terminal script, open that url in a web browser and tap on allow. Copy the code and paste in the terminal.
+
+**Root Folder:** Gdrive folder url/id from your account which you want to set as root folder. You can leave it blank and it takes `root` folder as default.
+
+If everything went fine, all the required credentials have been set, read the next section on how to upload a file/folder.
+
+### Upload
+
+For uploading files, the syntax is simple;
-### Generating Google OAuth2 Credentials
-
-- Log into google developer console at [google console].
-- Create new Project or use existing project if you don't have a project already created.
-- Create new OAuth 2.0 Credentials
- - Select Application type "other"
- - Provide name for the new credentials
- - This would provide a new client ID and Client Secret
-- Enable Google Drive API for the project under "Library"
+`gupload filename/foldername gdrive_folder_name`
-*Note:* When the script is run for the first time. The script must be authorized in browser. This may show a certificate warning if the application authorized domain is not configured on google console project.
+where `filename/foldername` is input file/folder and `gdrive_folder_name` is the name of the folder on gdrive, where the input file/folder will be uploaded.
-### Running the script
+If gdrive_folder_name is present on gdrive, then script will upload there, else will make a folder with that name.
-Script also asks for root folder to be set to which the script uploads documents by default.
-The default folder will be the root of your google drive. If you want to upload documents to any specific directory by default then provide the google folder ID or URL of that folder when root folder ID/URL is requested.
+Apart from basic usage, this script provides many flags for custom usecases, like parallel uploading, skipping upload of existing files, overwriting, etc.
-For example
-`https://drive.google.com/drive/folders/8ZzWiO_pMAtBrLpARBZJNV09TVmM`
+### Custom Flags
-In the above URL. The folder id is ***8ZzWiO_pMAtBrLpARBZJNV09TVmM***
+These are the custom flags that are currently implemented:
-Note: You can input either URL or ID.
+- **-z | --config**
-The default configurations of the script are store under **$HOME/.googledrive.conf**
+ Override default config file with custom config file.
-The script can be used in the following way
+ Default Config: `"${HOME}/.googledrive.conf`
- ./upload.sh
-Above command will create a folder under the pre-configured root directory and upload the specified file under the folder name. If the folder already exists then the file is uploaded under the folder.
+- **-C | --create-dir **
-Other Options available are
+ Option to create directory. Will provide folder id. Can be used to specify workspace folder for uploading files/folders.
- -C | --create-dir - option to create directory. Will provide folder id. Can be used to specify workspace folder for uploading files/folders.
+- **-r | --root-dir **
- -r | --root-dir - google folder id or url to which the file/directory to upload.
-
- -s | --skip-subdirs - Skip creation of sub folders and upload all files inside the INPUT folder/sub-folders in the INPUT folder, use this along with -p/--parallel option to speed up the uploads.
-
- -p | --parallel - Upload multiple files in parallel, Max value = 10, use with folders.
-
- Note :
- This command is only helpful if you are uploading many files which aren't big enough to utilise your full bandwidth, using it otherwise will not speed up your upload and even error sometimes,
- 1 - 6 value is recommended, but can use upto 10. If errors with a high value, use smaller number.
- Beaware, this isn't magic, obviously it comes at a cost of increased cpu/ram utilisation as it forks multiple bash processes to upload ( google how xargs works with -P option ).
-
- -o | --overwrite - Overwrite the files with the same name, if present in the root folder/input folder, also works with recursive folders and single/multiple files.
-
- Note :
- If you use this flag along with -d/--skip-duplicates, the skip duplicates flag is preferred.
-
- -d | --skip-duplicates - Do not upload the files with the same name, if already present in the root folder/input folder, also works with recursive folders.
-
- -f | --[file/folder] - Specify files and folders explicitly in one command, use multiple times for multiple folder/files.
+ Google folder id or url to which the file/directory to upload.
- For uploading multiple input into the same folder:
- 1. Use -C / --create-dir ( e.g `./upload.sh -f file1 -f folder1 -f file2 -C ` ) option.
- 2. Give two initial arguments which will use the second argument as the folder you wanna upload ( e.g: `./upload.sh filename -f filename -f foldername` ).
-
- This flag can also be used for uploading files/folders which have `-` character in their name, normally it won't work, because of the flags, but using `-f -[file|folder]namewithhyphen` works. Applies for -C/--create-dir too.
- Also, as specified by longflags ( `--[file|folder]` ), you can simultaneously upload a folder and a file.
- Incase of multiple -f flag having duplicate arguments, it takes the last duplicate of the argument to upload, in the same order provided.
-
- -S | --share - Share the uploaded input file/folder, grant reader permission to provided email address or to everyone with the shareable link.
-
- -q | --quiet - Supress the normal output, only show success/error upload messages for files, and one extra line at the beginning for folder showing no. of files and sub folders.
-
- -v | --verbose - Display detailed message (only for non-parallel uploads).
-
- -V | --verbose-progress - Display detailed message and detailed upload progress(only for non-parallel uploads).
-
- -i | --save-info - Save uploaded files info to the given filename."
-
- -u | --update - Update the installed script in your system, if not installed, then install.
-
- --info - Show detailed info, only if script is installed system wide.
-
- -h | --help - Display usage instructions.
-
- -z | --config - Override default config file with custom config file.
-
- -D | --debug - Display script command trace."
+- **-s | --skip-subdirs**
-To create a folder:
+ Skip creation of sub folders and upload all files inside the INPUT folder/sub-folders in the INPUT folder, use this along with -p/--parallel option to speed up the uploads.
- ./upload.sh -C -r
+- **-p | --parallel **
-This will give the folder id of the newly created folder which can be used to upload files to specific directory in google drive.
+ Upload multiple files in parallel, Max value = 10, use with folders.
-To Upload file to specific google folder
+ Note:
+ - This command is only helpful if you are uploading many files which aren't big enough to utilise your full bandwidth, using it otherwise will not speed up your upload and even error sometimes,
+ - 1 - 6 value is recommended, but can use upto 10. If errors with a high value, use smaller number.
+ - Beaware, this isn't magic, obviously it comes at a cost of increased cpu/ram utilisation as it forks multiple bash processes to upload ( google how xargs works with -P option ).
- ./upload.sh -r
+- **-o | --overwrite**
-The script also allows to upload directories. If directory path is provided as argument to the script then the script recursively uploads all the sub-folder and files present in the heirarchial way as it is present on the local machine.
+ Overwrite the files with the same name, if present in the root folder/input folder, also works with recursive folders and single/multiple files.
-### Resume interrupted uploads.
+ Note: If you use this flag along with -d/--skip-duplicates, the skip duplicates flag is preferred.
-Either interrupted due to bad internet connection or manual interruption.
-
- - It checks 3 things, filesize, name and workspace folder. If a upload was interrupted, then resumable upload link is saved in "$HOME/.google-drive-upload/", later on when running the same command as before, if applicable, resumes the upload from the same position as before.
- - Small files cannot be resumed, less that 1 MB, and the amount of size uploaded should be more than 1 MB to resume.
- - No progress bars for resumable uploads it messes up with output.
- - You can interrupt many times you want, it will resume( hopefully ).
+- **-d | --skip-duplicates**
+
+ Do not upload the files with the same name, if already present in the root folder/input folder, also works with recursive folders.
+
+- **-f | --[file/folder]**
+
+ Specify files and folders explicitly in one command, use multiple times for multiple folder/files.
+
+ For uploading multiple input into the same folder:
+
+ - Use -C / --create-dir ( e.g `./upload.sh -f file1 -f folder1 -f file2 -C ` ) option.
+ - Give two initial arguments which will use the second argument as the folder you wanna upload ( e.g: `./upload.sh filename -f filename -f foldername` ).
+
+ This flag can also be used for uploading files/folders which have `-` character in their name, normally it won't work, because of the flags, but using `-f -[file|folder]namewithhyphen` works. Applies for -C/--create-dir too.
+
+ Also, as specified by longflags ( `--[file|folder]` ), you can simultaneously upload a folder and a file.
+
+ Incase of multiple -f flag having duplicate arguments, it takes the last duplicate of the argument to upload, in the same order provided.
+
+- **-S | --share **
+
+ Share the uploaded input file/folder, grant reader permission to provided email address or to everyone with the shareable link.
+
+- **-q | --quiet**
+
+ Supress the normal output, only show success/error upload messages for files, and one extra line at the beginning for folder showing no. of files and sub folders.
+
+- **-v | --verbose**
+
+ Dislay detailed message (only for non-parallel uploads).
+
+- **-V | --verbose-progress**
+
+ Display detailed message and detailed upload progress(only for non-parallel uploads).
+
+- **-i | --save-info **
+
+ Save uploaded files info to the given filename."
+
+- **-u | --update**
+
+ Update the installed script in your system, if not installed, then install.
+
+- **--info**
+
+ Show detailed info, only if script is installed system wide.
+
+- **-h | --help**
+
+ Display usage instructions.
+
+- **-D | --debug**
+
+ Display script command trace.
+
+### Resuming Interrupted Uploads
+
+Uploads interrupted either due to bad internet connection or manual interruption, can be resumed from the same position.
+
+- Script checks 3 things, filesize, name and workspace folder. If an upload was interrupted, then resumable upload link is saved in `"$HOME/.google-drive-upload/"`, which later on when running the same command as before, if applicable, resumes the upload from the same position as before.
+- Small files cannot be resumed, less that 1 MB, and the amount of size uploaded should be more than 1 MB to resume.
+- No progress bars for resumable uploads as it messes up with output.
+- You can interrupt many times you want, it will resume ( hopefully ).
+
+## Uninstall
+
+If you have followed the automatic method to install the script, then you can automatically uninstall the script.
+
+There are two methods:
+
+1. Use the script itself to uninstall the script.
+
+ `gupload -U or gupload --uninstall`
+
+ This will remove the script related files and remove path change from shell file.
+
+2. Run the installation script again with -U/--uninstall flag
+
+ ```shell
+ bash <(curl --compressed -s https://raw.githubusercontent.com/labbots/google-drive-upload/master/install.sh) --uninstall
+ ```
+
+ Yes, just run the installation script again with the flag and voila, it's done.
+
+**Note: Both above methods obeys the values set by user in advanced installation,**
## Inspired By
-- [github-bashutils] - soulseekah/bash-utils
-- [deanet-gist] - Uploading File into Google Drive
+- [github-bashutils](https://github.com/soulseekah/bash-utils) - soulseekah/bash-utils
+- [deanet-gist](https://gist.github.com/deanet/3427090) - Uploading File into Google Drive
## License
MIT
-
-[github-bashutils]:
-[deanet-gist]:
-[google console]:
diff --git a/google-oauth2.sh b/google-oauth2.sh
index 6673c36..47c58bd 100755
--- a/google-oauth2.sh
+++ b/google-oauth2.sh
@@ -34,21 +34,31 @@ jsonValue() {
grep -o "\"""${1}""\"\:.*" | sed -e "s/.*\"""${1}""\": //" -e 's/[",]*$//' -e 's/["]*$//' -e 's/[,]*$//' -e "s/\"//" -n -e "${num}"p
}
+# Remove array duplicates, maintain the order as original.
+# Usage: removeArrayDuplicates "${somearray[@]}"
+# https://stackoverflow.com/a/37962595
+removeArrayDuplicates() {
+ [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
+ declare -A Aseen
+ Aunique=()
+ for i in "$@"; do
+ { [[ -z ${i} || ${Aseen[${i}]} ]]; } && continue
+ Aunique+=("${i}") && Aseen[${i}]=x
+ done
+ printf '%s\n' "${Aunique[@]}"
+}
+
# Update Config. Incase of old value, update, for new value add.
# Usage: updateConfig valuename value configpath
updateConfig() {
[[ $# -lt 3 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
declare VALUE_NAME="${1}" VALUE="${2}" CONFIG_PATH="${3}" FINAL=()
- declare -A Aseen
printf "" >> "${CONFIG_PATH}" # If config file doesn't exist.
- mapfile -t VALUES < "${CONFIG_PATH}" && VALUES+=("${VALUE_NAME}=${VALUE}")
+ mapfile -t VALUES < "${CONFIG_PATH}" && VALUES+=("${VALUE_NAME}=\"${VALUE}\"")
for i in "${VALUES[@]}"; do
[[ ${i} =~ ${VALUE_NAME}\= ]] && FINAL+=("${VALUE_NAME}=\"${VALUE}\"") || FINAL+=("${i}")
done
- for i in "${FINAL[@]}"; do
- [[ ${Aseen[${i}]} ]] && continue
- printf "%s\n" "${i}" && Aseen[${i}]=x
- done >| "${CONFIG_PATH}"
+ removeArrayDuplicates "${FINAL[@]}" >| "${CONFIG_PATH}"
}
printf "Starting script..\n"
@@ -75,9 +85,9 @@ if [[ -z ${CLIENT_SECRET} ]]; then
fi
for _ in {1..2}; do clearLine 1; done
-printf "Required credentials set.\n"
if [[ ${1} = create ]]; then
+ printf "Required credentials set.\n"
printf "Visit the below URL, tap on allow and then enter the code obtained:\n"
URL="https://accounts.google.com/o/oauth2/auth?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPE}&response_type=code&prompt=consent"
printf "%s\n\n" "${URL}"
@@ -90,16 +100,33 @@ if [[ ${1} = create ]]; then
ACCESS_TOKEN="$(jsonValue access_token <<< "${RESPONSE}")"
REFRESH_TOKEN="$(jsonValue refresh_token <<< "${RESPONSE}")"
- printf "Access Token: %s\n" "${ACCESS_TOKEN}"
- printf "Refresh Token: %s\n" "${REFRESH_TOKEN}"
+ if [[ -n ${ACCESS_TOKEN} && -n ${REFRESH_TOKEN} ]]; then
+ updateConfig REFRESH_TOKEN "${REFRESH_TOKEN}" "${CONFIG:-${HOME}/.googledrive.conf}"
+ updateConfig ACCESS_TOKEN "${ACCESS_TOKEN}" "${CONFIG:-${HOME}/.googledrive.conf}"
+
+ printf "Access Token: %s\n" "${ACCESS_TOKEN}"
+ printf "Refresh Token: %s\n" "${REFRESH_TOKEN}"
+ else
+ printf "Error: Wrong code given, make sure you copy the exact code\n"
+ exit 1
+ fi
else
printf "\nNo code provided, run the script and try again.\n"
exit 1
fi
elif [[ ${1} = refresh ]]; then
+ # Method to regenerate access_token ( also updates in config ).
+ # Make a request on https://www.googleapis.com/oauth2/""${API_VERSION}""/tokeninfo?access_token=${ACCESS_TOKEN} url and check if the given token is valid, if not generate one.
+ # Requirements: Refresh Token
+ getTokenandUpdate() {
+ RESPONSE="$(curl --compressed -s -X POST --data "client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&refresh_token=${REFRESH_TOKEN}&grant_type=refresh_token" "${TOKEN_URL}")"
+ ACCESS_TOKEN="$(jsonValue access_token <<< "${RESPONSE}")"
+ updateConfig ACCESS_TOKEN "${ACCESS_TOKEN}" "${CONFIG:-${HOME}/.googledrive.conf}"
+ }
if [[ -n ${REFRESH_TOKEN} ]]; then
- RESPONSE="$(curl --compressed -s -X POST --data "client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&refresh_token=${REFRESH_TOKEN}&grant_type=refresh_token" ${TOKEN_URL})"
- ACCESS_TOKEN="$(echo "${RESPONSE}" | jsonValue access_token)"
+ printf "Required credentials set.\n"
+ getTokenandUpdate
+ clearLine 1
printf "Access Token: %s\n" "${ACCESS_TOKEN}"
else
printf "Refresh Token not set, use %s create to generate one.\n" "${0}"
diff --git a/install.sh b/install.sh
index 7ec0140..d792959 100755
--- a/install.sh
+++ b/install.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# Install or Update google-drive-upload
+# Install, Update or Uninstall google-drive-upload
usage() {
printf "
@@ -13,8 +13,10 @@ Options:\n
-p | --path - Custom path where you want to install script.\nDefault Path: %s/.google-drive-upload \n
-c | --cmd - Custom command name, after installation script will be available as the input argument.\nDefault Name: upload \n
-r | --repo - Upload script from your custom repo,e.g --repo labbots/google-drive-upload, make sure your repo file structure is same as official repo.\n
+ -R | --release - Specify tag name for the github repo, applies to custom and default repo both.\n
-B | --branch - Specify branch name for the github repo, applies to custom and default repo both.\n
-s | --shell-rc - Specify custom rc file, where PATH is appended, by default script detects .zshrc and .bashrc.\n
+ -U | --uninstall - Uninstall the script and remove related files.\n
-D | --debug - Display script command trace.\n
-h | --help - Display usage instructions.\n\n" "${0##*/}" "${HOME}"
exit 0
@@ -35,21 +37,31 @@ isTerminal() {
[[ -t 1 || -z ${TERM} ]] && return 0 || return 1
}
+# Remove array duplicates, maintain the order as original.
+# Usage: removeArrayDuplicates "${somearray[@]}"
+# https://stackoverflow.com/a/37962595
+removeArrayDuplicates() {
+ [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
+ declare -A Aseen
+ Aunique=()
+ for i in "$@"; do
+ { [[ -z ${i} || ${Aseen[${i}]} ]]; } && continue
+ Aunique+=("${i}") && Aseen[${i}]=x
+ done
+ printf '%s\n' "${Aunique[@]}"
+}
+
# Update Config. Incase of old value, update, for new value add.
# Usage: updateConfig valuename value configpath
updateConfig() {
[[ $# -lt 3 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
declare VALUE_NAME="${1}" VALUE="${2}" CONFIG_PATH="${3}" FINAL=()
- declare -A Aseen
printf "" >> "${CONFIG_PATH}" # If config file doesn't exist.
- mapfile -t VALUES < "${CONFIG_PATH}" && VALUES+=("${VALUE_NAME}=${VALUE}")
+ mapfile -t VALUES < "${CONFIG_PATH}" && VALUES+=("${VALUE_NAME}=\"${VALUE}\"")
for i in "${VALUES[@]}"; do
[[ ${i} =~ ${VALUE_NAME}\= ]] && FINAL+=("${VALUE_NAME}=\"${VALUE}\"") || FINAL+=("${i}")
done
- for i in "${FINAL[@]}"; do
- [[ ${Aseen[${i}]} ]] && continue
- printf "%s\n" "${i}" && Aseen[${i}]=x
- done >| "${CONFIG_PATH}"
+ removeArrayDuplicates "${FINAL[@]}" >| "${CONFIG_PATH}"
}
# Detect profile file
@@ -99,7 +111,7 @@ variables() {
TYPE_VALUE="latest"
SHELL_RC="$(detectProfile)"
# shellcheck source=/dev/null
- if [[ -f ${INFO_PATH}/google-drive-upload.info ]]; then
+ if [[ -r ${INFO_PATH}/google-drive-upload.info ]]; then
source "${INFO_PATH}"/google-drive-upload.info
fi
}
@@ -140,7 +152,7 @@ install() {
done
updateConfig LATEST_INSTALLED_SHA "${LATEST_CURRENT_SHA}" "${INFO_PATH}"/google-drive-upload.info
updateConfig PATH "${INSTALL_PATH}:${PATH}" "${INFO_PATH}"/google-drive-upload.binpath
- if ! grep "source ${INFO_PATH}/google-drive-upload.binpath" "${SHELL_RC}" 1> /dev/null 2>&1; then
+ if ! grep "source ${INFO_PATH}/google-drive-upload.binpath" "${SHELL_RC}" &> /dev/null; then
printf "\nsource %s/google-drive-upload.binpath" "${INFO_PATH}" >> "${SHELL_RC}"
fi
clearLine 1
@@ -158,7 +170,7 @@ install() {
# Update the script
update() {
printf "Fetching latest version info..\n"
- LATEST_CURRENT_SHA="$(getLatestSHA "${REPO}" "${TYPE}" "${TYPE_VALUE}")"
+ LATEST_CURRENT_SHA="$(getLatestSHA "${TYPE}" "${TYPE_VALUE}" "${REPO}")"
if [[ -z "${LATEST_CURRENT_SHA}" ]]; then
printf "Cannot fetch remote latest version.\n"
exit 1
@@ -171,7 +183,7 @@ update() {
curl --compressed -Ls "https://raw.githubusercontent.com/${REPO}/${LATEST_CURRENT_SHA}/upload.sh" -o "${INSTALL_PATH}/${COMMAND_NAME}"
updateConfig LATEST_INSTALLED_SHA "${LATEST_CURRENT_SHA}" "${INFO_PATH}"/google-drive-upload.info
updateConfig PATH "${INSTALL_PATH}:${PATH}" "${INFO_PATH}"/google-drive-upload.binpath
- if ! grep "source ${INFO_PATH}/google-drive-upload.binpath" "${SHELL_RC}" 1> /dev/null 2>&1; then
+ if ! grep "source ${INFO_PATH}/google-drive-upload.binpath" "${SHELL_RC}" &> /dev/null; then
printf "\nsource %s/google-drive-upload.binpath" "${INFO_PATH}" >> "${SHELL_RC}"
fi
clearLine 1
@@ -183,6 +195,21 @@ update() {
fi
}
+# Uninstall the script
+uninstall() {
+ printf "Uninstalling..\n"
+ __bak="source ${INFO_PATH}/google-drive-upload.binpath"
+ if sed -i "s|${__bak}||g" "${SHELL_RC}"; then
+ rm -f "${INSTALL_PATH}/${COMMAND_NAME}"
+ rm -f "${INFO_PATH}/google-drive-upload.info"
+ rm -f "${INFO_PATH}/google-drive-upload.binpath"
+ clearLine 1
+ printf "Uninstall complete\n"
+ else
+ printf 'Error: Uninstall failed\n'
+ fi
+}
+
# Setup the varibles and process getopts flags.
setupArguments() {
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
@@ -231,6 +258,9 @@ setupArguments() {
checkLongoptions
SHELL_RC="${!OPTIND}" && OPTIND=$((OPTIND + 1))
;;
+ uninstall)
+ UNINSTALL="true"
+ ;;
debug)
DEBUG=true
;;
@@ -267,7 +297,6 @@ setupArguments() {
TYPE=branch
TYPE_VALUE="${OPTARG}"
;;
-
R)
TYPE=release
TYPE_VALUE="${OPTARG}"
@@ -275,6 +304,9 @@ setupArguments() {
s)
SHELL_RC="${OPTARG}"
;;
+ U)
+ UNINSTALL="true"
+ ;;
D)
DEBUG=true
;;
@@ -335,11 +367,19 @@ main() {
if [[ -n ${INTERACTIVE} ]]; then
startInteractive
fi
-
- if type -a "${COMMAND_NAME}" > /dev/null 2>&1; then
- update
+ if [[ -n ${UNINSTALL} ]]; then
+ if type -a "${COMMAND_NAME}" &> /dev/null; then
+ uninstall
+ else
+ printf "google-drive-upload is not installed\n"
+ exit 1
+ fi
else
- install
+ if type -a "${COMMAND_NAME}" &> /dev/null; then
+ update
+ else
+ install
+ fi
fi
}
diff --git a/upload.sh b/upload.sh
index 7f096c4..8e1a233 100755
--- a/upload.sh
+++ b/upload.sh
@@ -23,6 +23,7 @@ Options:\n
-V | --verbose-progress - Display detailed message and detailed upload progress(only for non-parallel uploads).\n
-u | --update - Update the installed script in your system.\n
--info - Show detailed info, only if script is installed system wide.\n
+ -U | --uninstall - Uninstall script, remove related files.\n
-D | --debug - Display script command trace.\n
-h | --help - Display usage instructions.\n" "${0##*/}"
exit 0
@@ -43,11 +44,6 @@ isTerminal() {
[[ -t 1 || -z ${TERM} ]] && return 0 || return 1
}
-# Check for -q/--quiet
-isNotQuiet() {
- [[ -z ${QUIET} ]] && return 0 || return 1
-}
-
# Usage: bashSleep 1 ( where is time in seconds )
# https://github.com/dylanaraps/pure-bash-bible#use-read-as-an-alternative-to-the-sleep-command
bashSleep() {
@@ -55,57 +51,65 @@ bashSleep() {
}
# Move cursor to nth no. of line and clear it to the begining.
+# Usage: clearLine x ( where x is the no of line you wanna clear )
clearLine() {
printf "\033[%sA\033[2K" "${1}"
}
# Convert bytes to human readable form, pure bash.
+# Usage: bytesToHuman bytes
# https://unix.stackexchange.com/a/259254
bytesToHuman() {
declare b=${1:-0} d='' s=0 S=(Bytes {K,M,G,T,P,E,Y,Z}B)
while ((b > 1024)); do
d="$(printf ".%02d" $((b % 1024 * 100 / 1024)))"
- b=$((b / 1024))
- ((s++))
+ b=$((b / 1024)) && ((s++))
done
printf "%s\n" "${b}${d} ${S[${s}]}"
}
-# Usage: dirname "path"
+# Default curl command for every curl request in this script, just to decrease script line :p
+curlCmd() {
+ curl --compressed "${@}"
+}
+
+# Usage: dirname "path" ( alternative to dirname command )
+# https://github.com/dylanaraps/pure-bash-bible#get-the-directory-name-of-a-file-path
dirname() {
declare tmp=${1:-.}
- [[ $tmp != *[!/]* ]] && { printf '/\n' && return; }
+ [[ ${tmp} != *[!/]* ]] && { printf '/\n' && return; }
tmp="${tmp%%"${tmp##*[!/]}"}"
- [[ $tmp != */* ]] && { printf '.\n' && return; }
+ [[ ${tmp} != */* ]] && { printf '.\n' && return; }
tmp=${tmp%/*} && tmp="${tmp%%"${tmp##*[!/]}"}"
printf '%s\n' "${tmp:-/}"
}
-# Update the script
+# Update ( install, uninstall ) the script
update() {
- printf 'Fetching update script..\n'
+ declare job="${1}"
+ printf 'Fetching %s script..\n' "${job:-update}"
# shellcheck source=/dev/null
if [[ -f "${HOME}/.google-drive-upload/google-drive-upload.info" ]]; then
source "${HOME}/.google-drive-upload/google-drive-upload.info"
fi
declare REPO="${REPO:-labbots/google-drive-upload}" TYPE_VALUE="${TYPE_VALUE:-latest}"
if [[ ${TYPE} = branch ]]; then
- if __SCRIPT="$(curl --compressed -Ls "https://raw.githubusercontent.com/${REPO}/${TYPE_VALUE}/install.sh")"; then
- bash <<< "${__SCRIPT}"
+ if __SCRIPT="$(curlCmd -Ls "https://raw.githubusercontent.com/${REPO}/${TYPE_VALUE}/install.sh")"; then
+ bash <(printf "%s\n" "${__SCRIPT}") --"${job:-}"
else
- printf "Error: Cannot download update script..\n"
+ printf "Error: Cannot download %s script..\n" "${job:-update}"
fi
else
declare LATEST_SHA
- LATEST_SHA="$(hash="$(curl -L --compressed -s "https://github.com/${REPO}/releases/${TYPE_VALUE}" | grep "=\"/""${REPO}""/commit")" &&
+ LATEST_SHA="$(hash="$(curlCmd -L -s "https://github.com/${REPO}/releases/${TYPE_VALUE}" | grep "=\"/""${REPO}""/commit")" &&
read -r firstline <<< "${hash}" && : "${hash/*commit\//}" && printf "%s\n" "${_/\"*/}")"
- if __SCRIPT="$(curl --compressed -Ls "https://raw.githubusercontent.com/${REPO}/${LATEST_SHA}/install.sh")"; then
- bash <<< "${__SCRIPT}"
+ if __SCRIPT="$(curlCmd -Ls "https://raw.githubusercontent.com/${REPO}/${LATEST_SHA}/install.sh")"; then
+ bash <(printf "%s\n" "${__SCRIPT}") --"${job:-}"
else
- printf "Error: Cannot download update script..\n"
+ printf "Error: Cannot download %s script..\n" "${job:-update}"
fi
fi
}
@@ -114,7 +118,7 @@ update() {
versionInfo() {
# shellcheck source=/dev/null
if [[ -f "${HOME}/.google-drive-upload/google-drive-upload.info" ]]; then
- cat "${HOME}/.google-drive-upload/google-drive-upload.info"
+ printf "%s\n" "$(< "${HOME}/.google-drive-upload/google-drive-upload.info")"
else
printf "google-drive-upload is not installed system wide.\n"
fi
@@ -122,6 +126,7 @@ versionInfo() {
# Print a text to center interactively and fill the rest of the line with text specified.
# This function is fine-tuned to this script functionality, so may appear unusual.
+# Usage: printCenter normal/justify sometext filler_symbol or sometext sometext2 filler_symbol
# https://gist.github.com/TrinityCoder/911059c83e5f7a351b785921cf7ecda
printCenter() {
[[ $# -lt 3 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
@@ -166,7 +171,7 @@ printCenter() {
return 0
}
-# Usage: count < "file" or count <<< "$variable" or pipe some output.
+# Usage: count < "file" or count <<< "$variable" or pipe some output. ( alt to wc -l )
# https://github.com/dylanaraps/pure-bash-bible#get-the-number-of-lines-in-a-file
count() {
mapfile -tn 0 lines
@@ -182,13 +187,14 @@ jsonValue() {
}
# Remove array duplicates, maintain the order as original.
+# Usage: removeArrayDuplicates "${somearray[@]}"
# https://stackoverflow.com/a/37962595
removeArrayDuplicates() {
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
declare -A Aseen
Aunique=()
for i in "$@"; do
- [[ ${Aseen[${i}]} ]] && continue
+ { [[ -z ${i} || ${Aseen[${i}]} ]]; } && continue
Aunique+=("${i}") && Aseen[${i}]=x
done
printf '%s\n' "${Aunique[@]}"
@@ -199,16 +205,12 @@ removeArrayDuplicates() {
updateConfig() {
[[ $# -lt 3 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
declare VALUE_NAME="${1}" VALUE="${2}" CONFIG_PATH="${3}" FINAL=()
- declare -A Aseen
printf "" >> "${CONFIG_PATH}" # If config file doesn't exist.
- mapfile -t VALUES < "${CONFIG_PATH}" && VALUES+=("${VALUE_NAME}=${VALUE}")
+ mapfile -t VALUES < "${CONFIG_PATH}" && VALUES+=("${VALUE_NAME}=\"${VALUE}\"")
for i in "${VALUES[@]}"; do
[[ ${i} =~ ${VALUE_NAME}\= ]] && FINAL+=("${VALUE_NAME}=\"${VALUE}\"") || FINAL+=("${i}")
done
- for i in "${FINAL[@]}"; do
- [[ ${Aseen[${i}]} ]] && continue
- printf "%s\n" "${i}" && Aseen[${i}]=x
- done >| "${CONFIG_PATH}"
+ removeArrayDuplicates "${FINAL[@]}" >| "${CONFIG_PATH}"
}
# Extract file/folder ID from the given INPUT in case of gdrive URL.
@@ -249,10 +251,7 @@ driveInfo() {
declare FOLDER_ID="${1}" FETCH="${2}" TOKEN="${3}"
declare SEARCH_RESPONSE FETCHED_DATA
- SEARCH_RESPONSE="$(curl \
- --compressed \
- --silent \
- -XGET \
+ SEARCH_RESPONSE="$(curlCmd -s \
-H "Authorization: Bearer ${TOKEN}" \
"${API_URL}/drive/${API_VERSION}/files/${FOLDER_ID}?fields=${FETCH}&supportsAllDrives=true")"
@@ -271,10 +270,7 @@ checkExistingFile() {
QUERY="$(urlEncode "name='${NAME}' and '${ROOTDIR}' in parents and trashed=false and 'me' in writers")"
- SEARCH_RESPONSE="$(curl \
- --compressed \
- --silent \
- -XGET \
+ SEARCH_RESPONSE="$(curlCmd -s \
-H "Authorization: Bearer ${TOKEN}" \
"${API_URL}/drive/${API_VERSION}/files?q=${QUERY}&fields=files(id)")"
@@ -291,10 +287,7 @@ createDirectory() {
QUERY="$(urlEncode "mimeType='application/vnd.google-apps.folder' and name='${DIRNAME}' and trashed=false and '${ROOTDIR}' in parents")"
- SEARCH_RESPONSE="$(curl \
- --compressed \
- --silent \
- -XGET \
+ SEARCH_RESPONSE="$(curlCmd -s \
-H "Authorization: Bearer ${TOKEN}" \
"${API_URL}/drive/${API_VERSION}/files?q=${QUERY}&fields=files(id)&supportsAllDrives=true")"
@@ -303,9 +296,7 @@ createDirectory() {
if [[ -z ${FOLDER_ID} ]]; then
declare CREATE_FOLDER_POST_DATA CREATE_FOLDER_RESPONSE
CREATE_FOLDER_POST_DATA="{\"mimeType\": \"application/vnd.google-apps.folder\",\"name\": \"${DIRNAME}\",\"parents\": [\"${ROOTDIR}\"]}"
- CREATE_FOLDER_RESPONSE="$(curl \
- --compressed \
- --silent \
+ CREATE_FOLDER_RESPONSE="$(curlCmd -s \
-X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json; charset=UTF-8" \
@@ -330,11 +321,12 @@ uploadFile() {
INPUTSIZE="$(wc -c < "${INPUT}")"
READABLE_SIZE="$(bytesToHuman "${INPUTSIZE}")"
+ # Handle extension-less files
if [[ ${INPUTNAME} = "${EXTENSION}" ]]; then
declare MIME_TYPE
- if type -p mimetype > /dev/null 2>&1; then
+ if type -p mimetype &> /dev/null; then
MIME_TYPE="$(mimetype --output-format %m "${INPUT}")"
- elif type -p file > /dev/null 2>&1; then
+ elif type -p file &> /dev/null; then
MIME_TYPE="$(file --brief --mime-type "${INPUT}")"
else
printCenter "justify" "Error: file or mimetype command not found." && printf "\n"
@@ -353,41 +345,35 @@ uploadFile() {
FILE_LINK="${SKIP_DUPLICATES_FILE_ID/${SKIP_DUPLICATES_FILE_ID}/https://drive.google.com/open?id=${SKIP_DUPLICATES_FILE_ID}}"
else
# https://developers.google.com/drive/api/""${API_VERSION}""/reference/files/update
- REQUEST_METHOD=PATCH
+ REQUEST_METHOD="PATCH"
URL="${API_URL}/upload/drive/${API_VERSION}/files/${EXISTING_FILE_ID}?uploadType=resumable&supportsAllDrives=true&supportsTeamDrives=true"
# JSON post data to specify the file name and folder under while the file to be updated
POSTDATA="{\"mimeType\": \"${MIME_TYPE}\",\"name\": \"${SLUG}\",\"addParents\": [\"${FOLDER_ID}\"]}"
- STRING=Updated
+ STRING="Updated"
fi
else
- JOB=create
+ JOB="create"
fi
fi
if [[ -n ${SKIP_DUPLICATES_FILE_ID} ]]; then
- if isNotQuiet; then
- printCenter "justify" "${SLUG}" " already exists." "="
- else
- printCenterQuiet "[ ${SLUG} already exists. ]"
- fi
+ # Stop upload if already exists ( -d/--skip-duplicates )
+ "${QUIET:-printCenter}" "justify" "${SLUG}" " already exists." "="
else
# Set proper variables for creating files
if [[ ${JOB} = create ]]; then
URL="${API_URL}/upload/drive/${API_VERSION}/files?uploadType=resumable&supportsAllDrives=true&supportsTeamDrives=true"
- REQUEST_METHOD=POST
+ REQUEST_METHOD="POST"
# JSON post data to specify the file name and folder under while the file to be created
POSTDATA="{\"mimeType\": \"${MIME_TYPE}\",\"name\": \"${SLUG}\",\"parents\": [\"${FOLDER_ID}\"]}"
- STRING=Uploaded
+ STRING="Uploaded"
fi
[[ -z ${PARALLEL} ]] && printCenter "justify" "${INPUT##*/}" " | ${READABLE_SIZE}" "="
generateUploadLink() {
- UPLOADLINK="$(curl \
- --compressed \
- --silent \
+ UPLOADLINK="$(curlCmd -s \
-X "${REQUEST_METHOD}" \
- -H "Host: www.googleapis.com" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json; charset=UTF-8" \
-H "X-Upload-Content-Type: ${MIME_TYPE}" \
@@ -400,12 +386,9 @@ uploadFile() {
uploadFilefromURI() {
# Curl command to push the file to google drive.
- # If the file size is large then the content can be split to chunks and uploaded.
- # In that case content range needs to be specified. # Not implemented yet.
[[ -z ${PARALLEL} ]] && clearLine 1 && printCenter "justify" "Uploading.." "-"
# shellcheck disable=SC2086 # Because unnecessary to another check because ${CURL_ARGS} won't be anything problematic.
- UPLOAD_BODY="$(curl \
- --compressed \
+ UPLOAD_BODY="$(curlCmd \
-X PUT \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: ${MIME_TYPE}" \
@@ -436,39 +419,24 @@ uploadFile() {
}
normalLogging() {
- if [[ -n ${VERBOSE_PROGRESS} ]]; then
- if isNotQuiet; then
- printCenter "justify" "${SLUG} " "| ${READABLE_SIZE} | ${STRING}" "="
- else
- printCenterQuiet "[ ${SLUG} | ${READABLE_SIZE} | ${STRING} ]"
- fi
- else
- if isNotQuiet; then
- [[ -z ${PARALLEL} ]] && for _ in {1..3}; do clearLine 1; done
- printCenter "justify" "${SLUG} " "| ${READABLE_SIZE} | ${STRING}" "="
- else
- printCenterQuiet "[ ${SLUG} | ${READABLE_SIZE} | ${STRING} ]"
- fi
+ if [[ -z ${VERBOSE_PROGRESS:-${PARALLEL}} ]]; then
+ for _ in {1..3}; do clearLine 1; done
fi
+ "${QUIET:-printCenter}" "justify" "${SLUG} " "| ${READABLE_SIZE} | ${STRING}" "="
}
errorLogging() {
- if isNotQuiet; then
- printCenter "justify" "Upload link generation ERROR" ", ${SLUG} not ${STRING}." "=" 1>&2 && [[ -z ${PARALLEL} ]] && printf "\n\n\n"
- else
- printCenterQuiet "Upload link generation ERROR, ${SLUG} not ${STRING}." 1>&2
- fi
- UPLOAD_STATUS=ERROR && export UPLOAD_STATUS # Send a error status, used in folder uploads.
+ "${QUIET:-printCenter}" "justify" "Upload link generation ERROR" ", ${SLUG} not ${STRING}." "=" 1>&2 && [[ -z ${PARALLEL} ]] && printf "\n\n\n" 1>&2
+ UPLOAD_STATUS="ERROR" && export UPLOAD_STATUS # Send a error status, used in folder uploads.
}
+ # Used for resuming interrupted uploads
logUploadSession() {
- __file="${HOME}/.google-drive-upload/${SLUG}__::__${FOLDER_ID}__::__${INPUTSIZE}"
{ [[ ${INPUTSIZE} -gt 1000000 ]] && printf "%s\n" "${UPLOADLINK}" >| "${__file}"; } || :
}
removeUploadSession() {
- __file="${HOME}/.google-drive-upload/${SLUG}__::__${FOLDER_ID}__::__${INPUTSIZE}"
- { [[ -f "${__file}" ]] && rm "${__file}"; } || :
+ rm -f "${__file}"
}
fullUpload() {
@@ -487,15 +455,14 @@ uploadFile() {
errorLogging
fi
}
- # https://developers.google.com/drive/api/v3/manage-uploads
+
__file="${HOME}/.google-drive-upload/${SLUG}__::__${FOLDER_ID}__::__${INPUTSIZE}"
- if [[ -f "${__file}" ]]; then
- RESUMABLE="$(< "${__file}")"
- UPLOADLINK="${RESUMABLE}"
- HTTP_CODE="$(curl -X PUT "${UPLOADLINK}" -s --write-out %"{http_code}")"
- if [[ ${HTTP_CODE} = "308" ]]; then
- UPLOADED_RANGE="$(: "$(curl \
- --compressed -s \
+ # https://developers.google.com/drive/api/v3/manage-uploads
+ if [[ -r "${__file}" ]]; then
+ UPLOADLINK="$(< "${__file}")"
+ HTTP_CODE="$(curlCmd -s -X PUT "${UPLOADLINK}" --write-out %"{http_code}")"
+ if [[ ${HTTP_CODE} = "308" ]]; then # Active Resumable URI give 308 status
+ UPLOADED_RANGE="$(: "$(curlCmd -s \
-X PUT \
-H "Content-Range: bytes */${INPUTSIZE}" \
--url "${UPLOADLINK}" \
@@ -504,16 +471,14 @@ uploadFile() {
if [[ ${UPLOADED_RANGE} =~ (^[0-9]) ]]; then
CONTENT_RANGE="$(printf "bytes %s-%s/%s\n" "$((UPLOADED_RANGE + 1))" "$((INPUTSIZE - 1))" "${INPUTSIZE}")"
CONTENT_LENGTH="$((INPUTSIZE - $((UPLOADED_RANGE + 1))))"
- [[ -z ${PARALLEL} ]] && printCenter "justify" "Resuming interrupted upload.." "-"
- # Curl command to push the file to google drive.
- # If the file size is large then the content can be split to chunks and uploaded.
- # In that case content range needs to be specified. # Not implemented yet.
- [[ -z ${PARALLEL} ]] && printCenter "justify" "Uploading.." "-"
+ [[ -z ${PARALLEL} ]] && {
+ printCenter "justify" "Resuming interrupted upload.." "-"
+ printCenter "justify" "Uploading.." "-"
+ }
# shellcheck disable=SC2086 # Because unnecessary to another check because ${CURL_ARGS} won't be anything problematic.
# Resuming interrupted uploads needs http1.1
- UPLOAD_BODY="$(curl \
+ UPLOAD_BODY="$(curlCmd -s \
--http1.1 \
- --compressed \
-X PUT \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: ${MIME_TYPE}" \
@@ -523,8 +488,7 @@ uploadFile() {
-T "${INPUT}" \
-o- \
--url "${UPLOADLINK}" \
- --globoff \
- -s)" || :
+ --globoff)" || :
if [[ -n ${UPLOAD_BODY} ]]; then
collectFileInfo
normalLogging resume
@@ -536,17 +500,16 @@ uploadFile() {
[[ -z ${PARALLEL} ]] && printCenter "justify" "Generating upload link.." "-"
fullUpload
fi
- elif [[ ${HTTP_CODE} =~ 40* ]]; then
+ elif [[ ${HTTP_CODE} =~ 40* ]]; then # Dead Resumable URI give 400,404.. status
[[ -z ${PARALLEL} ]] && printCenter "justify" "Generating upload link.." "-"
fullUpload
- elif [[ ${HTTP_CODE} =~ [200,201] ]]; then
+ elif [[ ${HTTP_CODE} =~ [200,201] ]]; then # Completed Resumable URI give 200 or 201 status
UPLOAD_BODY="${HTTP_CODE}"
collectFileInfo
normalLogging
removeUploadSession
fi
else
- # Curl command to initiate resumable upload session and grab the location URL
[[ -z ${PARALLEL} ]] && printCenter "justify" "Generating upload link.." "-"
fullUpload
fi
@@ -557,20 +520,16 @@ uploadFile() {
# Requirements: Given file/folder ID, type, role and access_token.
shareID() {
[[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
- declare LC_ALL=C ID="${1}" TOKEN="${2}" SHARE_EMAIL="${3}" ROLE="reader"
+ declare LC_ALL=C ID="${1}" TOKEN="${2}" SHARE_EMAIL="${3}" ROLE="reader" TYPE="anyone"
declare TYPE SHARE_POST_DATA SHARE_POST_DATA SHARE_RESPONSE SHARE_ID
if [[ -n ${SHARE_EMAIL} ]]; then
TYPE="user"
SHARE_POST_DATA="{\"role\":\"${ROLE}\",\"type\":\"${TYPE}\",\"emailAddress\":\"${SHARE_EMAIL}\"}"
else
- TYPE="anyone"
SHARE_POST_DATA="{\"role\":\"${ROLE}\",\"type\":\"${TYPE}\"}"
fi
- SHARE_RESPONSE="$(curl \
- --compressed \
- --silent \
- --output /dev/null \
+ SHARE_RESPONSE="$(curlCmd -s \
-X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json; charset=UTF-8" \
@@ -602,7 +561,7 @@ setupArguments() {
REDIRECT_URI="urn:ietf:wg:oauth:2.0:oob"
TOKEN_URL="https://accounts.google.com/o/oauth2/token"
- SHORTOPTS=":qvVi:sp:odf:Shur:C:Dz:-:"
+ SHORTOPTS=":qvVi:sp:odf:ShuUr:C:Dz:-:"
while getopts "${SHORTOPTS}" OPTION; do
case "${OPTION}" in
# Parse longoptions # https://stackoverflow.com/questions/402377/using-getopts-to-process-long-and-short-command-line-options/28466267#28466267
@@ -614,12 +573,13 @@ setupArguments() {
usage
;;
update)
- update
- exit $?
+ update && exit $?
+ ;;
+ uninstall)
+ update uninstall && exit $?
;;
info)
- versionInfo
- exit $?
+ versionInfo && exit $?
;;
create-dir)
checkLongoptions
@@ -633,7 +593,7 @@ setupArguments() {
checkLongoptions
CONFIG="${!OPTIND}" && OPTIND=$((OPTIND + 1))
# shellcheck source=/dev/null
- [[ -n ${CONFIG} && -f ${CONFIG} ]] &&
+ [[ -r ${CONFIG} ]] &&
source "${CONFIG}" || printf "Warning: Given config file (%s) doesn't exist, will use existing config or prompt for credentials..\n" "${OPTARG}"
;;
save-info)
@@ -641,7 +601,7 @@ setupArguments() {
LOG_FILE_ID="${!OPTIND}" && OPTIND=$((OPTIND + 1))
;;
skip-subdirs)
- SKIP_SUBDIRS=true
+ SKIP_SUBDIRS="true"
;;
parallel)
checkLongoptions
@@ -655,38 +615,39 @@ setupArguments() {
[[ ${NO_OF_PARALLEL_JOBS} -gt 10 ]] && { NO_OF_PARALLEL_JOBS=10 || NO_OF_PARALLEL_JOBS="${!OPTIND}"; }
;;
esac
- PARALLEL_UPLOAD=true && OPTIND=$((OPTIND + 1))
+ PARALLEL_UPLOAD="true" && OPTIND=$((OPTIND + 1))
;;
overwrite)
- OVERWRITE=Overwrite
+ OVERWRITE="Overwrite" && UPLOAD_METHOD="update"
;;
skip-duplicates)
- SKIP_DUPLICATES=true
+ SKIP_DUPLICATES="true" && UPLOAD_METHOD="update"
;;
file | folder)
checkLongoptions
INPUT_ARRAY+=("${!OPTIND}") && OPTIND=$((OPTIND + 1))
;;
share)
- SHARE=true
+ SHARE="true"
+ # https://stackoverflow.com/a/57295993
+ # Optional arguments # https://stackoverflow.com/questions/402377/using-getopts-to-process-long-and-short-command-line-options/28466267#28466267
+ EMAIL_REGEX="^([A-Za-z]+[A-Za-z0-9]*\+?((\.|\-|\_)?[A-Za-z]+[A-Za-z0-9]*)*)@(([A-Za-z0-9]+)+((\.|\-|\_)?([A-Za-z0-9]+)+)*)+\.([A-Za-z]{2,})+$"
if [[ -n ${!OPTIND} && ! ${!OPTIND} =~ ^(\-|\-\-) ]]; then
SHARE_EMAIL="${!OPTIND}" && ! [[ ${SHARE_EMAIL} =~ ${EMAIL_REGEX} ]] && printf "\nError: Provided email address for share option is invalid.\n" && exit 1
OPTIND=$((OPTIND + 1))
fi
;;
quiet)
- QUIET=true
- CURL_ARGS="-s"
+ QUIET="printCenterQuiet" && CURL_ARGS="-s"
;;
verbose)
- VERBOSE=true
+ VERBOSE="true"
;;
verbose-progress)
- VERBOSE_PROGRESS=true
- CURL_ARGS=""
+ VERBOSE_PROGRESS="true" && CURL_ARGS=""
;;
debug)
- DEBUG=true
+ DEBUG="true"
;;
'')
shorthelp
@@ -700,8 +661,10 @@ setupArguments() {
usage
;;
u)
- update
- exit $?
+ update && exit $?
+ ;;
+ U)
+ update uninstall && exit $?
;;
C)
FOLDERNAME="${OPTARG}"
@@ -712,14 +675,14 @@ setupArguments() {
z)
CONFIG="${OPTARG}"
# shellcheck source=/dev/null
- [[ -n ${CONFIG} && -f ${CONFIG} ]] &&
+ [[ -r ${CONFIG} ]] &&
source "${CONFIG}" || printf "Warning: Given config file (%s) doesn't exist, will use existing config or prompt for credentials..\n" "${OPTARG}"
;;
i)
LOG_FILE_ID="${OPTARG}"
;;
s)
- SKIP_SUBDIRS=true
+ SKIP_SUBDIRS="true"
;;
p)
NO_OF_PARALLEL_JOBS="${OPTARG}"
@@ -732,13 +695,13 @@ setupArguments() {
[[ ${NO_OF_PARALLEL_JOBS} -gt 10 ]] && { NO_OF_PARALLEL_JOBS=10 || NO_OF_PARALLEL_JOBS="${OPTARG}"; }
;;
esac
- PARALLEL_UPLOAD=true
+ PARALLEL_UPLOAD="true"
;;
o)
- OVERWRITE=Overwrite
+ OVERWRITE="Overwrite" && UPLOAD_METHOD="update"
;;
d)
- SKIP_DUPLICATES="Skip Existing"
+ SKIP_DUPLICATES="Skip Existing" && UPLOAD_METHOD="update"
;;
f)
INPUT_ARRAY+=("${OPTARG}")
@@ -751,21 +714,19 @@ setupArguments() {
SHARE_EMAIL="${!OPTIND}" && ! [[ ${SHARE_EMAIL} =~ ${EMAIL_REGEX} ]] && printf "\nError: Provided email address for share option is invalid.\n" && exit 1
OPTIND=$((OPTIND + 1))
fi
- SHARE=true
+ SHARE=" (SHARED)"
;;
q)
- QUIET=true
- CURL_ARGS="-s"
+ QUIET="printCenterQuiet" && CURL_ARGS="-s"
;;
v)
- VERBOSE=true
+ VERBOSE="true"
;;
V)
- VERBOSE_PROGRESS=true
- CURL_ARGS=""
+ VERBOSE_PROGRESS="true" && CURL_ARGS=""
;;
D)
- DEBUG=true
+ DEBUG="true"
;;
:)
printf '%s: -%s: option requires an argument\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1
@@ -779,7 +740,7 @@ setupArguments() {
# Incase ${1} argument was not taken as input, check if any arguments after all the valid flags have been passed, for INPUT and FOLDERNAME.
# Also check, if folder or dir, else exit.
- if [[ -z ${INPUT_ARRAY[*]} ]]; then
+ if [[ -z ${INPUT_ARRAY[0]} ]]; then
if [[ -n ${1} && -f ${1} || -d ${1} ]]; then
FINAL_INPUT_ARRAY+=("${1}")
{ [[ -n ${2} && ${2} != -* ]] && FOLDER_INPUT="${2}"; } || :
@@ -789,7 +750,7 @@ setupArguments() {
else
for array in "${INPUT_ARRAY[@]}"; do
{ [[ -f ${array} || -d ${array} ]] && FINAL_INPUT_ARRAY+=("${array[@]}"); } || {
- printf "\nError: Invalid Input ( %s ), no such file or directory.\n\n" "${array}"
+ printf "\nError: Invalid Input ( %s ), no such file or directory.\n" "${array}"
exit 1
}
done
@@ -804,14 +765,14 @@ setupArguments() {
# To avoid spamming in debug mode.
checkDebug() {
- printCenterQuiet() { printf "%s\n" "${1}"; }
+ printCenterQuiet() { { [[ $# = 3 ]] && printf "%s\n" "${2}"; } || { printf "%s%s\n" "${2}" "${3}"; }; }
if [[ -n ${DEBUG} ]]; then
set -x
printCenter() { { [[ $# = 3 ]] && printf "%s\n" "${2}"; } || { printf "%s%s\n" "${2}" "${3}"; }; }
clearLine() { :; } && newLine() { :; }
else
set +x
- if isNotQuiet; then
+ if [[ -z ${QUIET} ]]; then
if isTerminal; then
# This refreshes the interactive shell so we can use the ${COLUMNS} variable in the printCenter function.
shopt -s checkwinsize && (: && :)
@@ -840,34 +801,33 @@ checkInternet() {
if isTerminal; then
CHECK_INTERNET="$(sh -ic 'exec 3>&1 2>/dev/null; { curl --compressed -Is google.com 1>&3; kill 0; } | { sleep 10; kill 0; }' || :)"
else
- CHECK_INTERNET="$(curl --compressed -Is google.com -m 10)"
+ CHECK_INTERNET="$(curlCmd -s -I google.com -m 10)"
fi
- if [[ -z $CHECK_INTERNET ]]; then
- clearLine 1 && newLine "\n" && printCenter "justify" "Error: Internet connection not available" "=" && newLine "\n"
+ clearLine 1
+ if [[ -z ${CHECK_INTERNET} ]]; then
+ newLine "\n" && printCenter "justify" "Error: Internet connection not available" "="
exit 1
- else
- clearLine 1
fi
}
# Set the path and random name for temp file ( used for showing parallel uploads progress ).
setupTempfile() {
- type -p mktemp > /dev/null && { TMPFILE="$(mktemp -u)" || TMPFILE="${PWD}/$((RANDOM * 2)).LOG"; }
- trap '[[ -f "${TMPFILE}"SUCCESS ]] && rm "${TMPFILE}"SUCCESS ; [[ -f "${TMPFILE}"ERROR ]] && rm "${TMPFILE}"ERROR' EXIT
+ type -p mktemp &> /dev/null && { TMPFILE="$(mktemp -u)" || TMPFILE="${PWD}/$((RANDOM * 2)).LOG"; }
+ trap 'rm -f "${TMPFILE}"SUCCESS ; rm -f "${TMPFILE}"ERROR' EXIT
}
# Credentials
checkCredentials() {
# shellcheck source=/dev/null
# Config file is created automatically after first run
- [[ -f ${HOME}/.googledrive.conf ]] && source "${HOME}"/.googledrive.conf
+ [[ -r ${CONFIG:-${HOME}/.googledrive.conf} ]] && source "${CONFIG:-${HOME}/.googledrive.conf}"
[[ -z ${CLIENT_ID} ]] && read -r -p "Client ID: " CLIENT_ID && {
- updateConfig CLIENT_ID "${CLIENT_ID}" "${HOME}"/.googledrive.conf
+ updateConfig CLIENT_ID "${CLIENT_ID}" "${CONFIG:-${HOME}/.googledrive.conf}"
}
[[ -z ${CLIENT_SECRET} ]] && read -r -p "Client Secret: " CLIENT_SECRET && {
- updateConfig CLIENT_SECRET "${CLIENT_SECRET}" "${HOME}"/.googledrive.conf
+ updateConfig CLIENT_SECRET "${CLIENT_SECRET}" "${CONFIG:-${HOME}/.googledrive.conf}"
}
# Method to obtain refresh_token.
@@ -876,22 +836,26 @@ checkCredentials() {
read -r -p "If you have a refresh token generated, then type the token, else leave blank and press return key..
Refresh Token: " REFRESH_TOKEN && REFRESH_TOKEN="${REFRESH_TOKEN//[[:space:]]/}"
if [[ -n ${REFRESH_TOKEN} ]]; then
- updateConfig REFRESH_TOKEN "${REFRESH_TOKEN}" "${HOME}"/.googledrive.conf
+ updateConfig REFRESH_TOKEN "${REFRESH_TOKEN}" "${CONFIG:-${HOME}/.googledrive.conf}"
else
printf "\nVisit the below URL, tap on allow and then enter the code obtained:\n"
URL="https://accounts.google.com/o/oauth2/auth?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPE}&response_type=code&prompt=consent"
- printf "%s\n\n" "${URL}"
- read -r -p "Enter the authorization code: " CODE
+ printf "%s\n" "${URL}" && read -r -p "Enter the authorization code: " CODE
CODE="${CODE//[[:space:]]/}"
if [[ -n ${CODE} ]]; then
- RESPONSE="$(curl --compressed -s -X POST \
+ RESPONSE="$(curlCmd -s -X POST \
--data "code=${CODE}&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&redirect_uri=${REDIRECT_URI}&grant_type=authorization_code" "${TOKEN_URL}")"
ACCESS_TOKEN="$(jsonValue access_token <<< "${RESPONSE}")"
REFRESH_TOKEN="$(jsonValue refresh_token <<< "${RESPONSE}")"
- updateConfig REFRESH_TOKEN "${REFRESH_TOKEN}" "${HOME}"/.googledrive.conf
- updateConfig ACCESS_TOKEN "${ACCESS_TOKEN}" "${HOME}"/.googledrive.conf
+ if [[ -n ${ACCESS_TOKEN} && -n ${REFRESH_TOKEN} ]]; then
+ updateConfig REFRESH_TOKEN "${REFRESH_TOKEN}" "${CONFIG:-${HOME}/.googledrive.conf}"
+ updateConfig ACCESS_TOKEN "${ACCESS_TOKEN}" "${CONFIG:-${HOME}/.googledrive.conf}"
+ else
+ printf "Error: Wrong code given, make sure you copy the exact code.\n"
+ exit 1
+ fi
else
printf "\n"
printCenter "normal" "No code provided, run the script and try again" " "
@@ -900,53 +864,46 @@ checkCredentials() {
fi
fi
- # Method to regenerate access_token.
+ # Method to regenerate access_token ( also updates in config ).
# Make a request on https://www.googleapis.com/oauth2/""${API_VERSION}""/tokeninfo?access_token=${ACCESS_TOKEN} url and check if the given token is valid, if not generate one.
# Requirements: Refresh Token
- if [[ -z ${ACCESS_TOKEN} ]]; then
- RESPONSE="$(curl --compressed -s -X POST --data "client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&refresh_token=${REFRESH_TOKEN}&grant_type=refresh_token" "${TOKEN_URL}")"
+ getTokenandUpdate() {
+ RESPONSE="$(curlCmd -s -X POST --data "client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&refresh_token=${REFRESH_TOKEN}&grant_type=refresh_token" "${TOKEN_URL}")"
ACCESS_TOKEN="$(jsonValue access_token <<< "${RESPONSE}")"
- updateConfig ACCESS_TOKEN "${ACCESS_TOKEN}" "${HOME}"/.googledrive.conf
- elif curl --compressed -s "${API_URL}/oauth2/""${API_VERSION}""/tokeninfo?access_token=${ACCESS_TOKEN}" | jsonValue error_description > /dev/null 2>&1; then
- RESPONSE="$(curl --compressed -s -X POST --data "client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&refresh_token=${REFRESH_TOKEN}&grant_type=refresh_token" "${TOKEN_URL}")"
- ACCESS_TOKEN="$(jsonValue access_token <<< "${RESPONSE}")"
- updateConfig ACCESS_TOKEN "${ACCESS_TOKEN}" "${HOME}"/.googledrive.conf
+ updateConfig ACCESS_TOKEN "${ACCESS_TOKEN}" "${CONFIG:-${HOME}/.googledrive.conf}"
+ }
+ if [[ -z ${ACCESS_TOKEN} ]]; then
+ getTokenandUpdate
+ elif curlCmd -s "${API_URL}/oauth2/""${API_VERSION}""/tokeninfo?access_token=${ACCESS_TOKEN}" | jsonValue error_description &> /dev/null; then
+ getTokenandUpdate
fi
}
# Setup root directory where all file/folders will be uploaded.
setupRootdir() {
- if [[ -n ${ROOTDIR} ]]; then
- ROOT_FOLDER="${ROOTDIR//[[:space:]]/}"
+ checkROOTID() {
+ ROOT_FOLDER="$(driveInfo "$(extractID "${ROOT_FOLDER}")" "id" "${ACCESS_TOKEN}")" || {
+ { [[ ${ROOT_FOLDER} =~ "File not found" ]] && "${QUIET:-printCenter}" "justify" "Given root folder " " ID/URL invalid." "="; } || { printf "%s\n" "${ROOT_FOLDER}"; }
+ exit 1
+ }
if [[ -n ${ROOT_FOLDER} ]]; then
- ROOT_FOLDER="$(driveInfo "$(extractID "${ROOT_FOLDER}")" "id" "${ACCESS_TOKEN}")" || {
- { [[ ${ROOT_FOLDER} =~ "File not found" ]] && printCenter "justify" "Given root folder " " ID/URL invalid." "="; } || { printf "%s\n" "${ROOT_FOLDER}"; }
- exit 1
- }
- if [[ -n ${ROOT_FOLDER} ]]; then
- updateConfig ROOT_FOLDER "${ROOT_FOLDER}" "${HOME}"/.googledrive.conf
- else
- printCenter "justify" "Given root folder " " ID/URL invalid." "="
- exit 1
- fi
+ updateConfig ROOT_FOLDER "${ROOT_FOLDER}" "${CONFIG:-${HOME}/.googledrive.conf}"
+ else
+ "${QUIET:-printCenter}" "justify" "Given root folder " " ID/URL invalid." "="
+ exit 1
fi
+ }
+ if [[ -n ${ROOTDIR} ]]; then
+ ROOT_FOLDER="${ROOTDIR//[[:space:]]/}"
+ { [[ -n ${ROOT_FOLDER} ]] && checkROOTID; } || :
elif [[ -z ${ROOT_FOLDER} ]]; then
read -r -p "Root Folder ID or URL (Default: root): " ROOT_FOLDER
ROOT_FOLDER="${ROOT_FOLDER//[[:space:]]/}"
if [[ -n ${ROOT_FOLDER} ]]; then
- ROOT_FOLDER="$(driveInfo "$(extractID "${ROOT_FOLDER}")" "id" "${ACCESS_TOKEN}")" || {
- { [[ ${ROOT_FOLDER} =~ "File not found" ]] && printCenter "justify" "Given root folder " " ID/URL invalid." "="; } || { printf "%s\n" "${ROOT_FOLDER}"; }
- exit 1
- }
- if [[ -n ${ROOT_FOLDER} ]]; then
- updateConfig ROOT_FOLDER "${ROOT_FOLDER}" "${HOME}"/.googledrive.conf
- else
- printCenter "justify" "Given root folder " " ID/URL invalid." "="
- exit 1
- fi
+ checkROOTID
else
- ROOT_FOLDER=root
- updateConfig ROOT_FOLDER "${ROOT_FOLDER}" "${HOME}"/.googledrive.conf
+ ROOT_FOLDER="root"
+ updateConfig ROOT_FOLDER "${ROOT_FOLDER}" "${CONFIG:-${HOME}/.googledrive.conf}"
fi
fi
}
@@ -967,15 +924,10 @@ processArguments() {
# Check if the argument is a file or a directory.
if [[ -f ${INPUT} ]]; then
printCenter "justify" "Given Input" ": FILE" "="
- if [[ -n ${OVERWRITE} || -n ${SKIP_DUPLICATES} ]]; then
- printCenter "justify" "Upload Method" ": ${SKIP_DUPLICATES:-$OVERWRITE}" "-" && newLine "\n"
- uploadFile update "${INPUT}" "${WORKSPACE_FOLDER_ID}" "${ACCESS_TOKEN}"
- else
- printCenter "justify" "Upload Method" ": Create" "-" && newLine "\n"
- uploadFile create "${INPUT}" "${WORKSPACE_FOLDER_ID}" "${ACCESS_TOKEN}"
- fi
+ printCenter "justify" "Upload Method" ": ${SKIP_DUPLICATES:-${OVERWRITE:-Create}}" "=" && newLine "\n"
+ uploadFile "${UPLOAD_METHOD:-create}" "${INPUT}" "${WORKSPACE_FOLDER_ID}" "${ACCESS_TOKEN}"
FILE_ID="${SKIP_DUPLICATES_FILE_ID:-${FILE_ID}}"
- [[ ${UPLOAD_STATUS} = ERROR ]] && for _ in {1..2}; do clearLine 1; done && return 1
+ [[ ${UPLOAD_STATUS} = ERROR ]] && for _ in {1..2}; do clearLine 1; done && continue
if [[ -n "${SHARE}" ]]; then
printCenter "justify" "Sharing the file.." "-"
if SHARE_MSG="$(shareID "${FILE_ID}" "${ACCESS_TOKEN}" "${SHARE_EMAIL}")"; then
@@ -983,24 +935,19 @@ processArguments() {
else
clearLine 1
fi
- printCenter "justify" "DriveLink" " (SHARED)" "-"
- else
- printCenter "justify" "DriveLink" "-"
fi
+ printCenter "justify" "DriveLink" "${SHARE:-}" "-"
isTerminal && printCenter "normal" "$(printf "\xe2\x86\x93 \xe2\x86\x93 \xe2\x86\x93\n")" " "
printCenter "normal" "${FILE_LINK}" " "
printf "\n"
elif [[ -d ${INPUT} ]]; then
- unset EMPTY
- # Unset PARALLEL value if input is file, for preserving the logging output.
- [[ -n ${PARALLEL_UPLOAD} ]] && { parallel=true || unset parallel; }
-
- FOLDER_NAME="${INPUT##*/}"
+ INPUT="$(cd "${INPUT}" && pwd)" # to handle dirname when current directory (.) is given as input.
+ unset EMPTY # Used when input folder is empty
+ parallel="${PARALLEL_UPLOAD:-}" # Unset PARALLEL value if input is file, for preserving the logging output.
printCenter "justify" "Upload Method" ": ${SKIP_DUPLICATES:-${OVERWRITE:-Create}}" "="
-
printCenter "justify" "Given Input" ": FOLDER" "-" && newLine "\n"
- printCenter "justify" "Folder: ${FOLDER_NAME}" "="
+ FOLDER_NAME="${INPUT##*/}" && printCenter "justify" "Folder: ${FOLDER_NAME}" "="
NEXTROOTDIRID="${WORKSPACE_FOLDER_ID}"
@@ -1011,46 +958,34 @@ processArguments() {
if [[ -n ${FILENAMES[0]} ]]; then
NO_OF_FILES="${#FILENAMES[@]}"
for _ in {1..2}; do clearLine 1; done
- if isNotQuiet; then
- printCenter "justify" "Folder: ${FOLDER_NAME} " "| ${NO_OF_FILES} File(s)" "=" && printf "\n"
- else
- printCenterQuiet "[ Folder: ${FOLDER_NAME} | ${NO_OF_FILES} File(s) ]"
- fi
- ID="$(createDirectory "${INPUT}" "${NEXTROOTDIRID}" "${ACCESS_TOKEN}")"
+ "${QUIET:-printCenter}" "justify" "Folder: ${FOLDER_NAME} " "| ${NO_OF_FILES} File(s)" "=" && printf "\n"
+ printCenter "justify" "Creating folder.." "-"
+ ID="$(createDirectory "${INPUT}" "${NEXTROOTDIRID}" "${ACCESS_TOKEN}")" && clearLine 1
DIRIDS[1]="${ID}"
if [[ -n ${parallel} ]]; then
{ [[ ${NO_OF_PARALLEL_JOBS} -gt ${NO_OF_FILES} ]] && NO_OF_PARALLEL_JOBS_FINAL="${NO_OF_FILES}"; } || { NO_OF_PARALLEL_JOBS_FINAL="${NO_OF_PARALLEL_JOBS}"; }
# Export because xargs cannot access if it is just an internal variable.
- export ID CURL_ARGS="-s" PARALLEL ACCESS_TOKEN STRING OVERWRITE COLUMNS API_URL API_VERSION LOG_FILE_ID SKIP_DUPLICATES
- export -f uploadFile printCenter clearLine jsonValue urlEncode checkExistingFile isNotQuiet
+ export ID CURL_ARGS="-s" ACCESS_TOKEN STRING OVERWRITE COLUMNS API_URL API_VERSION LOG_FILE_ID SKIP_DUPLICATES QUIET UPLOAD_METHOD
+ export -f uploadFile printCenter clearLine jsonValue urlEncode checkExistingFile printCenterQuiet newLine bytesToHuman curlCmd
[[ -f ${TMPFILE}SUCCESS ]] && rm "${TMPFILE}"SUCCESS
[[ -f ${TMPFILE}ERROR ]] && rm "${TMPFILE}"ERROR
# shellcheck disable=SC2016
printf "%s\n" "${FILENAMES[@]}" | xargs -n1 -P"${NO_OF_PARALLEL_JOBS_FINAL}" -i bash -c '
- if [[ -n ${OVERWRITE} || -n ${SKIP_DUPLICATES} ]]; then
- uploadFile update "{}" "${ID}" "${ACCESS_TOKEN}" parallel
- else
- uploadFile create "{}" "${ID}" "${ACCESS_TOKEN}" parallel
- fi
- ' 1>| "${TMPFILE}"SUCCESS 2>| "${TMPFILE}"ERROR &
+ uploadFile "${UPLOAD_METHOD:-create}" "{}" "${ID}" "${ACCESS_TOKEN}" parallel
+ ' 1>| "${TMPFILE}"SUCCESS 2>| "${TMPFILE}"ERROR &
while true; do [[ -f "${TMPFILE}"SUCCESS || -f "${TMPFILE}"ERROR ]] && { break || bashSleep 0.5; }; done
+
newLine "\n"
ERROR_STATUS=0 SUCCESS_STATUS=0
while true; do
SUCCESS_STATUS="$(count < "${TMPFILE}"SUCCESS)"
ERROR_STATUS="$(count < "${TMPFILE}"ERROR)"
bashSleep 1
- if isNotQuiet; then
- if [[ $(((SUCCESS_STATUS + ERROR_STATUS))) != "${TOTAL}" ]]; then
- clearLine 1 && printCenter "justify" "Status" ": ${SUCCESS_STATUS} Uploaded | ${ERROR_STATUS} Failed" "="
- fi
- else
- if [[ $(((SUCCESS_STATUS + ERROR_STATUS))) != "${TOTAL}" ]]; then
- clearLine 1 && printCenterQuiet "Status: ${SUCCESS_STATUS} Uploaded | ${ERROR_STATUS} Failed"
- fi
+ if [[ $(((SUCCESS_STATUS + ERROR_STATUS))) != "${TOTAL}" ]]; then
+ clearLine 1 && "${QUIET:-printCenter}" "justify" "Status" ": ${SUCCESS_STATUS} Uploaded | ${ERROR_STATUS} Failed" "="
fi
TOTAL="$(((SUCCESS_STATUS + ERROR_STATUS)))"
[[ ${TOTAL} = "${NO_OF_FILES}" ]] && break
@@ -1063,18 +998,13 @@ processArguments() {
ERROR_STATUS=0 SUCCESS_STATUS=0
for file in "${FILENAMES[@]}"; do
DIRTOUPLOAD="${ID}"
- if [[ -n ${OVERWRITE} || -n ${SKIP_DUPLICATES} ]]; then
- uploadFile update "${file}" "${DIRTOUPLOAD}" "${ACCESS_TOKEN}"
- else
- uploadFile create "${file}" "${DIRTOUPLOAD}" "${ACCESS_TOKEN}"
- fi
+ uploadFile "${UPLOAD_METHOD:-create}" "${file}" "${DIRTOUPLOAD}" "${ACCESS_TOKEN}"
[[ ${UPLOAD_STATUS} = ERROR ]] && ERROR_STATUS="$((ERROR_STATUS + 1))" || SUCCESS_STATUS="$((SUCCESS_STATUS + 1))" || :
- if [[ ${VERBOSE} = true || ${VERBOSE_PROGRESS} = true ]]; then
+ if [[ -n ${VERBOSE:-${VERBOSE_PROGRESS}} ]]; then
printCenter "justify" "Status: ${SUCCESS_STATUS} Uploaded" " | ${ERROR_STATUS} Failed" "=" && newLine "\n"
else
for _ in {1..2}; do clearLine 1; done
printCenter "justify" "Status: ${SUCCESS_STATUS} Uploaded" " | ${ERROR_STATUS} Failed" "="
-
fi
done
fi
@@ -1096,18 +1026,10 @@ processArguments() {
if [[ -n ${FILENAMES[0]} ]]; then
NO_OF_FILES="${#FILENAMES[@]}"
for _ in {1..3}; do clearLine 1; done
- if isNotQuiet; then
- if [[ ${NO_OF_SUB_FOLDERS} != 0 ]]; then
- printCenter "justify" "${FOLDER_NAME} " "| ${NO_OF_FILES} File(s) | ${NO_OF_SUB_FOLDERS} Sub-folders" "="
- else
- printCenter "justify" "${FOLDER_NAME} " "| ${NO_OF_FILES} File(s)" "="
- fi
+ if [[ ${NO_OF_SUB_FOLDERS} != 0 ]]; then
+ "${QUIET:-printCenter}" "justify" "${FOLDER_NAME} " "| ${NO_OF_FILES} File(s) | ${NO_OF_SUB_FOLDERS} Sub-folders" "="
else
- if [[ ${NO_OF_SUB_FOLDERS} != 0 ]]; then
- printCenterQuiet "[ ${FOLDER_NAME} | ${NO_OF_FILES} File(s) | ${NO_OF_SUB_FOLDERS} Sub-folders ]"
- else
- printCenterQuiet "[ ${FOLDER_NAME} | ${NO_OF_FILES} File(s) ]"
- fi
+ "${QUIET:-printCenter}" "justify" "${FOLDER_NAME} " "| ${NO_OF_FILES} File(s)" "="
fi
newLine "\n"
printCenter "justify" "Creating Folder(s).." "-"
@@ -1150,23 +1072,19 @@ processArguments() {
if [[ -n ${parallel} ]]; then
{ [[ ${NO_OF_PARALLEL_JOBS} -gt ${NO_OF_FILES} ]] && NO_OF_PARALLEL_JOBS_FINAL="${NO_OF_FILES}"; } || { NO_OF_PARALLEL_JOBS_FINAL="${NO_OF_PARALLEL_JOBS}"; }
# Export because xargs cannot access if it is just an internal variable.
- export CURL_ARGS="-s" ACCESS_TOKEN STRING OVERWRITE COLUMNS API_URL API_VERSION LOG_FILE_ID QUIET
- export -f uploadFile printCenter clearLine jsonValue urlEncode checkExistingFile isNotQuiet printCenterQuiet newLine
+ export CURL_ARGS="-s" ACCESS_TOKEN STRING OVERWRITE COLUMNS API_URL API_VERSION LOG_FILE_ID SKIP_DUPLICATES QUIET UPLOAD_METHOD
+ export -f uploadFile printCenter clearLine jsonValue urlEncode checkExistingFile printCenterQuiet newLine bytesToHuman curlCmd
[[ -f "${TMPFILE}"SUCCESS ]] && rm "${TMPFILE}"SUCCESS
[[ -f "${TMPFILE}"ERROR ]] && rm "${TMPFILE}"ERROR
# shellcheck disable=SC2016
printf "%s\n" "${FINAL_LIST[@]}" | xargs -n1 -P"${NO_OF_PARALLEL_JOBS_FINAL}" -i bash -c '
- LIST="{}"
- FILETOUPLOAD="${LIST//*"|:_//_:|"}"
- DIRTOUPLOAD="$(: "|:_//_:|""${FILETOUPLOAD}" && : "${LIST::-${#_}}" && printf "%s\n" "${_//*"|:_//_:|"}")"
- if [[ -n ${OVERWRITE} || -n ${SKIP_DUPLICATES} ]]; then
- uploadFile update "${FILETOUPLOAD}" "${DIRTOUPLOAD}" "${ACCESS_TOKEN}" parallel
- else
- uploadFile create "${FILETOUPLOAD}" "${DIRTOUPLOAD}" "${ACCESS_TOKEN}" parallel
- fi
- ' 1>| "${TMPFILE}"SUCCESS 2>| "${TMPFILE}"ERROR &
+ LIST="{}"
+ FILETOUPLOAD="${LIST//*"|:_//_:|"}"
+ DIRTOUPLOAD="$(: "|:_//_:|""${FILETOUPLOAD}" && : "${LIST::-${#_}}" && printf "%s\n" "${_//*"|:_//_:|"}")"
+ uploadFile "${UPLOAD_METHOD:-create}" "${FILETOUPLOAD}" "${DIRTOUPLOAD}" "${ACCESS_TOKEN}" parallel
+ ' 1>| "${TMPFILE}"SUCCESS 2>| "${TMPFILE}"ERROR &
while true; do [[ -f "${TMPFILE}"SUCCESS || -f "${TMPFILE}"ERROR ]] && { break || bashSleep 0.5; }; done
@@ -1175,14 +1093,8 @@ processArguments() {
SUCCESS_STATUS="$(count < "${TMPFILE}"SUCCESS)"
ERROR_STATUS="$(count < "${TMPFILE}"ERROR)"
bashSleep 1
- if isNotQuiet; then
- if [[ $(((SUCCESS_STATUS + ERROR_STATUS))) != "${TOTAL}" ]]; then
- clearLine 1 && printCenter "justify" "Status" ": ${SUCCESS_STATUS} Uploaded | ${ERROR_STATUS} Failed" "="
- fi
- else
- if [[ $(((SUCCESS_STATUS + ERROR_STATUS))) != "${TOTAL}" ]]; then
- clearLine 1 && printCenterQuiet "Status: ${SUCCESS_STATUS} Uploaded | ${ERROR_STATUS} Failed"
- fi
+ if [[ $(((SUCCESS_STATUS + ERROR_STATUS))) != "${TOTAL}" ]]; then
+ clearLine 1 && "${QUIET:-printCenter}" "justify" "Status" ": ${SUCCESS_STATUS} Uploaded | ${ERROR_STATUS} Failed" "="
fi
TOTAL="$(((SUCCESS_STATUS + ERROR_STATUS)))"
[[ ${TOTAL} = "${NO_OF_FILES}" ]] && break
@@ -1196,13 +1108,9 @@ processArguments() {
for LIST in "${FINAL_LIST[@]}"; do
FILETOUPLOAD="${LIST//*"|:_//_:|"/}"
DIRTOUPLOAD="$(: "|:_//_:|""${FILETOUPLOAD}" && : "${LIST::-${#_}}" && printf "%s\n" "${_//*"|:_//_:|"/}")"
- if [[ -n ${OVERWRITE} || -n ${SKIP_DUPLICATES} ]]; then
- uploadFile update "${FILETOUPLOAD}" "${DIRTOUPLOAD}" "${ACCESS_TOKEN}"
- else
- uploadFile create "${FILETOUPLOAD}" "${DIRTOUPLOAD}" "${ACCESS_TOKEN}"
- fi
+ uploadFile "${UPLOAD_METHOD:-create}" "${FILETOUPLOAD}" "${DIRTOUPLOAD}" "${ACCESS_TOKEN}"
[[ ${UPLOAD_STATUS} = ERROR ]] && ERROR_STATUS="$((ERROR_STATUS + 1))" || SUCCESS_STATUS="$((SUCCESS_STATUS + 1))" || :
- if [[ -n ${VERBOSE} || -n ${VERBOSE_PROGRESS} ]]; then
+ if [[ -n ${VERBOSE:-${VERBOSE_PROGRESS}} ]]; then
printCenter "justify" "Status" ": ${SUCCESS_STATUS} Uploaded | ${ERROR_STATUS} Failed" "=" && newLine "\n"
else
for _ in {1..2}; do clearLine 1; done
@@ -1225,30 +1133,19 @@ processArguments() {
else
clearLine 1
fi
- printCenter "justify" "FolderLink " " (SHARED)" "="
- else
- printCenter "justify" "FolderLink" "="
fi
+ printCenter "justify" "FolderLink" "${SHARE:-}" "-"
isTerminal && printCenter "normal" "$(printf "\xe2\x86\x93 \xe2\x86\x93 \xe2\x86\x93\n")" " "
printCenter "normal" "$(: "$(read -r firstline <<< "${DIRIDS[1]}" &&
printf "%s\n" "${firstline/"|:_//_:|"*/}")" && printf "%s\n" "${_/$_/https://drive.google.com/open?id=$_}")" " "
fi
newLine "\n"
- if isNotQuiet; then
- [[ ${SUCCESS_STATUS} -gt 0 ]] && printCenter "justify" "Total Files " "Uploaded: ${SUCCESS_STATUS}" "="
- [[ ${ERROR_STATUS} -gt 0 ]] && printCenter "justify" "Total Files " "Failed: ${ERROR_STATUS}" "="
- else
- [[ ${SUCCESS_STATUS} -gt 0 ]] && printCenterQuiet "[ Total Files Uploaded: ${SUCCESS_STATUS} ]"
- [[ ${ERROR_STATUS} -gt 0 ]] && printCenterAuiet "[ Total Files Failed: ${ERROR_STATUS} ]"
- fi
+ [[ ${SUCCESS_STATUS} -gt 0 ]] && "${QUIET:-printCenter}" "justify" "Total Files " "Uploaded: ${SUCCESS_STATUS}" "="
+ [[ ${ERROR_STATUS} -gt 0 ]] && "${QUIET:-printCenter}" "justify" "Total Files " "Failed: ${ERROR_STATUS}" "="
printf "\n"
else
- if isNotQuiet; then
- for _ in {1..2}; do clearLine 1; done
- printCenter 'justify' "Empty Folder." "-"
- else
- printCenterQuiet "Empty Folder.\n"
- fi
+ for _ in {1..2}; do clearLine 1; done
+ "${QUIET:-printCenter}" 'justify' "Empty Folder." "-"
printf "\n"
fi
fi
@@ -1258,11 +1155,9 @@ processArguments() {
main() {
[[ $# = 0 ]] && shortHelp
- # To cleanup subprocesses.
- trap 'exit' INT TERM && trap 'kill -- $$' EXIT
+ trap 'exit "$?"' INT TERM && trap 'exit "$?"' EXIT
- set -o errexit -o noclobber -o pipefail
- checkBashVersion
+ checkBashVersion && set -o errexit -o noclobber -o pipefail
setupArguments "${@}"
checkDebug && checkInternet
@@ -1288,11 +1183,7 @@ main() {
END="$(printf "%(%s)T\\n" "-1")"
DIFF="$((END - START))"
- if isNotQuiet; then
- printCenter "normal" " Time Elapsed: ""$((DIFF / 60))"" minute(s) and ""$((DIFF % 60))"" seconds. " "="
- else
- printCenterQuiet "Time Elapsed: ""$((DIFF / 60))"" minute(s) and ""$((DIFF % 60))"" seconds."
- fi
+ "${QUIET:-printCenter}" "normal" " Time Elapsed: ""$((DIFF / 60))"" minute(s) and ""$((DIFF % 60))"" seconds. " "="
}
main "${@}"