capistrano/sshkit

Append text in a file

wonderer007 opened this issue · 4 comments

I am trying to append text at the bottom of a file with
execute(:printf, "%s\n%s\n", "hello", "world", ">>", "schedule.rb")

This produce error

(Backtrace restricted to imported tasks)
cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as deploy@139.59.138.154: printf exit status: 127
printf stdout: Nothing written
printf stderr: bash: line 1: fg: no job control
bash: line 2: hello: command not found

SSHKit::Command::Failed: printf exit status: 127
printf stdout: Nothing written
printf stderr: bash: line 1: fg: no job control
bash: line 2: hello: command not found

Tasks: TOP => deploy:restart => deploy:staging_files
(See full trace by running task with --trace)
The deploy has failed with an error: Exception while executing as deploy@139.59.138.154: printf exit status: 127
printf stdout: Nothing written
printf stderr: bash: line 1: fg: no job control
bash: line 2: hello: command not found

Is there any alternative to it ? Thanks!

GitHub is not used for support, please ask your question at StackOverflow where the community can support you better.

Here's an example of me appending to a file [straight in SSHKit]:

    def test
      SSHKit::Backend::Netssh.configure do |ssh|
        ssh.ssh_options = {
          user: 'myuser' # since we will be using execute() without mappings, we must set our user in this way.   Thus your unmapped commands will not inherit as() blocks.   See the README.
        }
        SSHKit.config.output_verbosity= Logger::DEBUG
      end        
      on(ip_address) do
        as(:myuser) do
            execute(:touch,"/tmp/foo")    # first arg is a symbol, so the command is mapped.   See the README.md
            execute("echo bar >> /tmp/foo") # first arg is a string, so command is not mapped AND is fed straight to the shell
          end
        end
      end
    end

@leehambley - does that look right?

That looks correct @bretweinraub

Here's a version without side-effects.

I'm gettting some mileage out of this. Seems like it is probably not thread safe, but useful if you are going to be using un-mapped executes()s and need them to run as a particular user:

    # run a sshkit command as user [not using as() mappings, as you cant do complex shell magic in those]
    def sshkit_as_user(user)
      cached_user = SSHKit::Backend::Netssh.configure { | ssh | puts ssh.ssh_options[:user]} ||  `whoami`.chomp
      begin
        SSHKit::Backend::Netssh.configure do |ssh|
          ssh.ssh_options = {
            user: user
          }
        end
        yield
      ensure
        SSHKit::Backend::Netssh.configure do |ssh|
          ssh.ssh_options = {
            user: cached_user
          }
        end
      end
    end

So the above becomes:

sskit_as_user(:myuser) do
  on(ip_address) do
    execute(:touch,"/tmp/foo")    # first arg is a symbol, so the command is mapped.   See the README.md
    execute("echo bar >> /tmp/foo") # first arg is a string, so command is not mapped AND is fed straight to the shell
  end
end