1010
1111import os
1212import platform
13+ import shlex
1314import subprocess
1415import tempfile
1516from subprocess import CompletedProcess
@@ -94,6 +95,35 @@ def call_rclone_through_script(command: str) -> CompletedProcess:
9495 return output
9596
9697
98+ def call_rclone_with_popen (command : str ) -> subprocess .Popen :
99+ """Call rclone using `subprocess.Popen` for control over process termination.
100+
101+ It is not possible to kill a process while running it using `subprocess.run`.
102+ """
103+ command = "rclone " + command
104+ process = subprocess .Popen (
105+ shlex .split (command ), stdout = subprocess .PIPE , stderr = subprocess .PIPE
106+ )
107+ return process
108+
109+
110+ def await_call_rclone_with_popen_raise_on_fail (
111+ process : subprocess .Popen , log : bool = True
112+ ):
113+ """Await rclone the subprocess.Popen call.
114+
115+ Calling `process.communicate()` waits for the process to complete and returns
116+ the stdout and stderr.
117+ """
118+ stdout , stderr = process .communicate ()
119+
120+ if process .returncode != 0 :
121+ utils .log_and_raise_error (stderr .decode ("utf-8" ), ConnectionError )
122+
123+ if log :
124+ log_rclone_config_output ()
125+
126+
97127# -----------------------------------------------------------------------------
98128# Setup
99129# -----------------------------------------------------------------------------
@@ -182,10 +212,15 @@ def setup_rclone_config_for_gdrive(
182212 rclone_config_name : str ,
183213 gdrive_client_secret : str | None ,
184214 service_account_filepath : Optional [str ] = None ,
185- log : bool = True ,
186- ):
215+ ) -> subprocess .Popen :
187216 """Set up rclone config for connections to Google Drive.
188217
218+ This function uses `call_rclone_with_popen` instead of `call_rclone`. This
219+ is done to have more control over the setup process in case the user wishes to
220+ cancel the setup. Since the rclone setup for google drive uses a local web server
221+ for authentication to google drive, the running process must be killed before the
222+ setup can be started again.
223+
189224 Parameters
190225 ----------
191226 cfg
@@ -203,9 +238,6 @@ def setup_rclone_config_for_gdrive(
203238 service_account_filepath : path to service account file path for connection
204239 without browser
205240
206- log
207- Whether to log, if `True` logger must already be initialised.
208-
209241 """
210242 client_id_key_value = (
211243 f"client_id { cfg ['gdrive_client_id' ]} "
@@ -224,7 +256,7 @@ def setup_rclone_config_for_gdrive(
224256 else f"service_account_file { service_account_filepath } "
225257 )
226258
227- output = call_rclone (
259+ process = call_rclone_with_popen (
228260 f"config create "
229261 f"{ rclone_config_name } "
230262 f"drive "
@@ -233,16 +265,9 @@ def setup_rclone_config_for_gdrive(
233265 f"scope drive "
234266 f"root_folder_id { cfg ['gdrive_root_folder_id' ]} "
235267 f"{ service_account_filepath_arg } " ,
236- pipe_std = True ,
237268 )
238269
239- if output .returncode != 0 :
240- utils .log_and_raise_error (
241- output .stderr .decode ("utf-8" ), ConnectionError
242- )
243-
244- if log :
245- log_rclone_config_output ()
270+ return process
246271
247272
248273def setup_rclone_config_for_aws (
0 commit comments