11from mlc import utils
22import os
33import subprocess
4+ import platform
45
56
67def preprocess (i ):
@@ -11,11 +12,17 @@ def preprocess(i):
1112
1213 cmd_string = ''
1314
14- # pre_run_cmds = env.get('MLC_SSH_PRE_RUN_CMDS', ['source $HOME/cm/bin/activate'])
15+ is_windows = os_info ['platform' ] == 'windows'
16+
17+ # pre_run_cmds = env.get('MLC_SSH_PRE_RUN_CMDS', ['source $HOME/mlcflow/bin/activate'])
1518 pre_run_cmds = env .get ('MLC_SSH_PRE_RUN_CMDS' , [])
1619
1720 files_to_copy = env .get ('MLC_SSH_FILES_TO_COPY' , [])
1821
22+ if "<<<HOME>>>" in env .get ('MLC_SSH_KEY_FILE' , '' ):
23+ env ['MLC_SSH_KEY_FILE' ] = env ['MLC_SSH_KEY_FILE' ].replace (
24+ "<<<HOME>>>" , os .path .expanduser ("~" ))
25+
1926 run_cmds = env .get ('MLC_SSH_RUN_COMMANDS' , [])
2027
2128 run_cmds = pre_run_cmds + run_cmds
@@ -26,8 +33,12 @@ def preprocess(i):
2633 cmd = cmd .replace (";;" , "," )
2734 run_cmds [i ] = cmd
2835
36+ # Use semicolon for Unix-like systems, the remote server will handle it
2937 cmd_string += " ; " .join (run_cmds )
30- user = env .get ('MLC_SSH_USER' , os .environ .get ('USER' ))
38+
39+ # Get username - on Windows, USERNAME is the env var, not USER
40+ user = env .get ('MLC_SSH_USER' , os .environ .get (
41+ 'USER' ) or os .environ .get ('USERNAME' ))
3142 password = env .get ('MLC_SSH_PASSWORD' , None )
3243 host = env .get ('MLC_SSH_HOST' )
3344 port = env .get ('MLC_SSH_PORT' , '22' )
@@ -40,29 +51,47 @@ def preprocess(i):
4051 ssh_cmd = ["ssh" , "-p" , port ]
4152
4253 if env .get ("MLC_SSH_SKIP_HOST_VERIFY" ):
54+ # Use NUL on Windows, /dev/null on Unix
55+ null_device = "NUL" if is_windows else "/dev/null"
4356 ssh_cmd += ["-o" , "StrictHostKeyChecking=no" ,
44- "-o" , "UserKnownHostsFile=/dev/null " ]
57+ "-o" , f "UserKnownHostsFile={ null_device } " ]
4558
4659 key_file = env .get ("MLC_SSH_KEY_FILE" )
4760 if key_file :
4861 ssh_cmd += ["-i" , key_file ]
4962
5063 ssh_cmd_str = " " .join (ssh_cmd )
5164
65+ # Use double quotes on Windows, single quotes on Unix for better
66+ # compatibility
67+ quote_char = '"' if is_windows else "'"
5268 ssh_run_command = ssh_cmd_str + " " + user + "@" + host + \
53- password_string + " ' " + cmd_string + "'"
69+ password_string + " " + quote_char + cmd_string + quote_char
5470 env ['MLC_SSH_CMD' ] = ssh_run_command
5571
56- # ---- Use sshpass if password is provided ----
72+ # ---- Use sshpass if password is provided (only on Unix-like systems) ----
5773 rsync_base = ["rsync" , "-avz" ]
5874
59- if password :
75+ if password and not is_windows :
6076 rsync_base = ["sshpass" , "-p" , password ] + rsync_base
6177
62- target_directory = env [ 'MLC_SSH_TARGET_COPY_DIRECTORY' ]
78+ target_directory = env . get ( 'MLC_SSH_TARGET_COPY_DIRECTORY' , '' )
6379
6480 # ---- Execute copy commands ----
6581 for file in files_to_copy :
82+ # Check if rsync is available
83+ rsync_available = True
84+ try :
85+ subprocess .run (["rsync" , "--version" ],
86+ capture_output = True , check = True )
87+ except (subprocess .CalledProcessError , FileNotFoundError ):
88+ rsync_available = False
89+
90+ if not rsync_available :
91+ print (f"⚠️ rsync not found. Skipping file copy for { file } " )
92+ print (" On Windows, install rsync via WSL, Cygwin, or use Git Bash" )
93+ continue
94+
6695 cmd = [
6796 "rsync" ,
6897 "-avz" ,
0 commit comments