deployer
                                
                                 deployer copied to clipboard
                                
                                    deployer copied to clipboard
                            
                            
                            
                        rsync_src is not specify to working dir, while using yml recipe
- Deployer version: 7.0.0-rc.8
- Deployment OS: Ubuntu 20.04
From documentation:
set('rsync_src', __DIR__);
If I dont define rsync_src in deploy.yml i got the following output:
[localhost] run rsync -rz -e 'ssh '-p' '522' '-A' '-o' 'ControlMaster=auto' '-o' 'ControlPersist=60' '-o' 'ControlPath=/dev/shm/[email protected]:522'' --delete --exclude='.git' --exclude='deploy.yml' --exclude='.gitlab-ci.yml' 'phar:///usr/local/bin/dep/contrib/' '[email protected]:/srv/example.com/releases/1/'
[localhost] The source and destination cannot both be remote.
[localhost] rsync error: syntax or usage error (code 1) at main.c(1420) [Receiver=3.2.3]
While i define it with __DIR__ or  "__DIR__" got following output:
  rsync_src: __DIR__
[localhost] run rsync -rz -e 'ssh '-p' '522' '-A' '-o' 'ControlMaster=auto' '-o' 'ControlPersist=60' '-o' 'ControlPath=/dev/shm/[email protected]'' --delete --exclude='.git' --exclude='deploy.yml' --exclude='.gitlab-ci.yml' '__DIR__/' '[email protected]:/srv/example.com/releases/1/'
[localhost] rsync: [sender] change_dir "/builds/deployer/test-deploy-project/__DIR__" failed: No such file or directory (2)
[localhost] rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1330) [sender=3.2.3]
  rsync_src: "__DIR__"
[localhost] run rsync -rz -e 'ssh '-p' '522' '-A' '-o' 'ControlMaster=auto' '-o' 'ControlPersist=60' '-o' 'ControlPath=/dev/shm/[email protected]'' --delete --exclude='.git' --exclude='deploy.yml' --exclude='.gitlab-ci.yml' '__DIR__/' '[email protected]:/srv/example.com/releases/1/'
[localhost] rsync: [sender] change_dir "/builds/deployer/test-deploy-project/__DIR__" failed: No such file or directory (2)
[localhost] rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1330) [sender=3.2.3]
deploy.yml
import:
  - contrib/rsync.php
hosts:
  stage:
    hostname: "example.com"
config:
  rsync:
    exclude:
      - .git
      - deploy.yml
      - .gitlab-ci.yml
    exclude-file: false
    include: [ ]
    include-file: false
    filter: [ ]
    filter-file: false
    filter-perdir: false
    flags: rz
    options:
      - delete
    timeout: 30
tasks:
  deploy:
    - rsync
My fix is:
  rsync_src: './'
or
  rsync_src: '.'
With that output all working fine:
run rsync -rz -e 'ssh '-p' '522' '-A' '-o' 'ControlMaster=auto' '-o' 'ControlPersist=60' '-o' 'ControlPath=/dev/shm/[email protected]'' --delete --exclude='.git' --exclude='deploy.yml' --exclude='.gitlab-ci.yml' './/' '[email protected]:/srv/example.com/releases/20/'
So, I'm not sure if this problem is related to the missing source!
If you look very closely at the command you will notice that there are quite a few single quotes.
The argument:
-e 'ssh '-p' '522' '-A' '-o' 'ControlMaster=auto' '-o' 'ControlPersist=60' '-o' 'ControlPath=/dev/shm/[email protected]''
is actually an argument that belongs to rsync and tells rsync to establish an SSH connection with the arguments behind it. So everything starting with 'ssh' is part of the SSH command and is also enclosed at the end with another single quote. That's why there are two at the end!
I have the same problem with the rsync contrib. I can't establish a connection either. But from my point of view it is rather the function "escapeshellarg" which encloses all SSH arguments in the Host class with single quotes. Then in the rsync contrib more single quotes were used to enclose the complete SSH command.
src/Host/Host.php:
    public function connectionOptionsString(): string
    {
        return implode(' ', array_map('escapeshellarg', $this->connectionOptionsArray()));
    }
conrtib/rsync.php:
    $sshArguments = $host->connectionOptionsString();
    runLocally("rsync -{$config['flags']} -e 'ssh $sshArguments' {{rsync_options}}{{rsync_includes}}{{rsync_excludes}}{{rsync_filter}} '$src/' '{$host->connectionString()}:$dst/'", $config);
The release documentation for the v7.0.0-rc.8 release states:
● Refactored ssh client and host connection option.
So this part is obviously new and doesn't work like that!
And maybe as a side note, __DIR__ is a predefined constant of php and it is not known in the yaml cosmos!
But the variable rsync_src is already set to this constant by default in the rsync contrib:
conrtib/rsync.php:
set('rsync_src', __DIR__);
Oh man, so if you look with your eyes....
Then you will see that it is not because of the strange single quotation marks.
You were right! It is indeed because of the source rsync_src. Which also makes sense, because if you leave the variable set in the contrib the default is not in the deploy.yaml directory (which I assumed) but of course in the directory of the rsync post.
If you then install the deployer.phar globally like I did, a totally confusing source is created:
phar:///usr/local/bin/dep/contrib/
and the delpoyment crashes!
So, you definitely need to set the variable yourself and __DIR__ is not an alternative in the yaml file!
You can import a php file and create the variable rsync_src there or you have to live with your solution. As said, the predefined php constant __DIR__ represents the current directory where your source code is executed and is only available in php!!!
If it would be possible for the maintainer of the project to save the path to the deploy.php/deploy.yaml file as a configuration variable (let's say "local_path") when initializing the deployer you could also do the following:
config:
  rsync_src: '{{local_path}}'
Let’s throw an exception in resync_src not set.
Hello @oheinemann This work nice with deploy.php, so i clarified that problem while using yml file, where not accessible DIR variable. That would be nice to extract path to deployer into another defined variable. I seen some related issues with current problem but in different situations (example: https://github.com/deployphp/deployer/issues/3165)
@antonmedv Yes, I think throwing an error would probably be a better solution than using the wrong directory by default.
I looked a little deeper into the code and found out that in the dep file in deployer/deployer/bin the constant DEPLOYER_DEPLOY_FILE is set and the path to deploy.php/deploy.yaml/deploy.yml is stored there.
And in the file ProcessRunner.php in deployer/deployer/src/Component/ProcessRunner exactly this constant is used for the WorkingDirectory of the process.
Here also the environment variable DEPLOYER_ROOT is checked which according to the documentation can also be set to define the WorkingDirectory.
With all this information I created a function in php which generates a local path:
set('local_path', function () {
    $deployerRoot = getenv('DEPLOYER_ROOT') !== false ? getenv('DEPLOYER_ROOT') : (defined('DEPLOYER_DEPLOY_FILE') ? dirname(DEPLOYER_DEPLOY_FILE) : null);
    if ($deployerRoot === null) {
        throw new \RuntimeException('Could not determine a local path!');
    }
    return rtrim($deployerRoot, '/') . '/';
});
I personally would like to have some functions in the yaml file, which unfortunately I can currently only solve with php. As an example: I change the release name in all my projects to the current timestamp:
set('timestamp', function () {
    return date('YmdHis');
});
Unfortunately this is not possible in the yaml file, so I import a php file in each case to implement exactly that.
To have predefined variables for such typical issues would be a dream!
And as another side note!
I really have no idea why that works with all the silly single quotes!
However, I use exactly this function of the host in a separate task where I have a problem with exactly these single quotes.
So I rewrote this function for my task:
    public function connectionOptionsString(): string
    {
         return implode(' ', array_map(function($value) {
            return substr($value, 0, 1) !== '-' ? escapeshellarg($value) : $value;
        }, $this->connectionOptionsArray()));
    }
In my opinion, not all arguments need to be enclosed in single quotes. Especially the argument identifiers do not.
Also, I would mask the single quotes in the rsync conrtib again with slashes. Since here the string is inside single quotes.
addslashes($sshArguments = $host->connectionOptionsString());
@antonmedv Maybe this solution finds a way into your source code.
PR?