MSYS2からdeployer で "The source and destination cannot both be remote"

半年～1年ぶりくらいに[deployer](https://deployer.org/)を実行したら失敗したのでその対応メモ。

- php-7.3.2 (Windows10)
- deployer-6.4.3
- MSYS2 (ssh, ssh-agent, git, tar...)

```bash
$ ./deployer-6.4.3.phar --file=./config.php deploy --tag=3.2.5 --roles=production_web
➤ Executing task deploy:prepare
✔ Ok
➤ Executing task deploy:lock
✔ Ok
➤ Executing task deploy:release
✔ Ok
➤ Executing task deploy:archive
✔ Ok
➤ Executing task deploy:update_code
➤ Executing task deploy:failed
✔ Ok
➤ Executing task deploy:unlock
✔ Ok

In Process.php line 239:

  The command "rsync -azP -e 'ssh -A' "C:\msys64\home\pen\work\release\ukulelebot\app.tar.gz" "pen@xxx.xxx.xxx.xxx:/va
  r/www/vhosts/ukulelebot/releases/10/app.tar.gz"" failed.

  Exit Code: 1(General error)

  Working directory: C:\projects\poppy\ukulelebot\scripts\deploy

  Output:
  ================


  Error Output:
  ================
  The source and destination cannot both be remote.
  rsync error: syntax or usage error (code 1) at main.c(1303) [Receiver=3.1.3]


deploy [-p|--parallel] [-l|--limit LIMIT] [--no-hooks] [--log LOG] [--roles ROLES] [--hosts HOSTS] [-o|--option OPTION] [--] [<stage>]
```

## 原因

以前動いていたことから推測するに、MSYS2のrsyncがWindows形式のパスを受け付けなくなったぽい？

```bash
mkdir -p ~/work/rsync
cd ~/work/rsync

mkdir -p dir1
touch ./dir1/one ./dir1/two
mkdir dir1/dir1-1

rm -rf ./dir2

### Windows形式だとエラーになる
[21:22:48 pen@pink2 rsync]$ echo $(cygpath -w $(pwd)/dir1)
C:\msys64\home\pen\work\rsync\dir1
[21:23:52 pen@pink2 rsync]$ rsync -av C:\msys64\home\pen\work\rsync\dir1 ./dir2
ssh: Could not resolve hostname c: Name or service not known
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: unexplained error (code 255) at io.c(226) [Receiver=3.1.3]

### multiの形式でもエラーになる
[21:26:52 pen@pink2 rsync]$ echo $(cygpath -m $(pwd)/dir1)
C:/msys64/home/pen/work/rsync/dir1
[21:27:10 pen@pink2 rsync]$ rsync -av C:/msys64/home/pen/work/rsync/dir1 ./dir2
ssh: Could not resolve hostname c: Name or service not known
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(226) [Receiver=3.1.3]
[21:27:28 pen@pink2 rsync]$

### Unix形式なら動く
[21:27:34 pen@pink2 rsync]$ echo $(cygpath -u $(pwd)/dir1)
/home/pen/work/rsync/dir1
[21:27:45 pen@pink2 rsync]$ rsync -av /home/pen/work/rsync/dir1 ./dir2
sending incremental file list
created directory ./dir2
dir1/
dir1/one
dir1/two
dir1/dir1-1/

sent 219 bytes  received 95 bytes  628.00 bytes/sec
total size is 0  speedup is 0.00
```

## 対応

`upload()` に渡しているソースパス `$source` を、MSYS2の場合だけ `cygpath -u` にかけてから渡す `uploadViaMsys2()` を作って回避した。

```diff
diff --git a/scripts/deploy/config.php b/scripts/deploy/config.php
index dd84b67..8efc3e0 100644
--- a/scripts/deploy/config.php
+++ b/scripts/deploy/config.php
@@ -8,6 +8,7 @@
  */
 namespace Deployer;
 require_once 'recipe/common.php';
+require_once 'functions.php';

 $appName = 'ukulelebot';

@@ -72,7 +73,7 @@ task('deploy:archive', function() {
 task('deploy:update_code', function() use ($appName){
     $clonedDir = get('clonedDir');
     $archive = realpath($clonedDir."/../app.tar.gz");
-    upload($archive, "{{release_path}}".'/'.basename($archive));
+    uploadViaMsys2($archive, "{{release_path}}".'/'.basename($archive));

     cd("{{release_path}}");
     run("tar -zxpf " . basename($archive));

diff --git a/scripts/deploy/functions.php b/scripts/deploy/functions.php
new file mode 100644
index 0000000..0a077b2
--- /dev/null
+++ b/scripts/deploy/functions.php
@@ -0,0 +1,24 @@
+<?php
+namespace Deployer;
+
+/**
+ * @param string $source
+ * @param string $destination
+ * @param array $config
+ */
+function uploadViaMsys2($source, $destination, array $config = [])
+{
+    if(strpos(PHP_OS, 'WIN') === 0) {
+        $output = null;
+        exec('uname', $output, $ret);
+        if($ret === 0 && strpos($output[0], 'MSYS') === 0) {
+            $output = null;
+            exec("cygpath -u ${source}", $output, $ret);
+            if($ret === 0) {
+                $source = $output[0];
+            }
+        }
+    }
+
+    return upload($source, $destination, $config);
+}
```

## 成功ログ

```bash
[22:27:33 pen@pink2 deploy]$ ./deployer-6.4.3.phar --file=./config.php deploy --tag=3.2.7 --roles=production_web
➤ Executing task deploy:prepare
✔ Ok
➤ Executing task deploy:lock
✔ Ok
➤ Executing task deploy:release
✔ Ok
➤ Executing task deploy:archive
✔ Ok
➤ Executing task deploy:update_code
✔ Ok
➤ Executing task deploy:create_dirs
✔ Ok
➤ Executing task deploy:shared
✔ Ok
➤ Executing task deploy:writable
✔ Ok
➤ Executing task deploy:clear_paths
✔ Ok
➤ Executing task deploy:symlink
✔ Ok
➤ Executing task apache:reload
✔ Ok
➤ Executing task deploy:unlock
✔ Ok
➤ Executing task cleanup
✔ Ok
Successfully deployed!
/c/projects/poppy/ukulelebot/scripts/deploy
```