Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nesting 'with' fails #43

Closed
clintonb opened this issue Oct 31, 2013 · 10 comments
Closed

Nesting 'with' fails #43

clintonb opened this issue Oct 31, 2013 · 10 comments

Comments

@clintonb
Copy link

I have some example code below from my Capistrano v3 tasks for Django. It seems that nesting 'with' calls is broken. Is this functionality supposed to be supported? The docs state "One will notice that it's quite low level, but exposes a convenient API, the as()/within()/with() are nestable in any order, repeatable, and stackable."

My current work around is to wrap the body of with_virtualenv in a begin-rescue block that captures the NameError and check for the message "instance variable @_env not defined".

Note that my intention is to keep the Django and virtualenv tasks in separate files/gems, hence my not simply merging the with calls.

def with_virtualenv(&block)
  with path: "#{fetch(:virtualenv_dir)}/bin:$PATH" do
    block.call
  end
end

def django_manage(*args)
  within release_path do
    with_virtualenv do
      with app_environment: fetch(:stage) do
        execute :python, 'manage.py', args
      end
    end
  end
end

# Results in "instance variable @_env not defined"
namespace :django do
  task :migrate do
    on primary fetch(:migration_role) do
      django_manage 'syncdb', '--noinput', '--migrate'
    end
  end
end
@leehambley
Copy link
Member

Unfortunately it won't work that way because of the way (instance val) that
the DSL blocks are implemented.

You don't have to use the nested DSL, 'execute' also accepts all the DSL
method names as options in a hash as it's final argument, then you can
manage your own state merges between components.

On Thursday, October 31, 2013, Clinton Blackburn wrote:

I have some example code below from my Capistrano v3 tasks for Django. It
seems that nesting 'with' calls is broken. Is this functionality supposed
to be supported? The docs state "One will notice that it's quite low level,
but exposes a convenient API, the as()/within()/with() are nestable in any
order, repeatable, and stackable."

My current work around is to wrap the body of with_virtualenv in a
begin-rescue block that captures the NameError and check for the message
"instance variable @_env not defined".

Note that my intention is to keep the Django and virtualenv tasks in
separate files/gems, hence my not simply merging the with calls.

def with_virtualenv(&block)
with path: "#{fetch(:virtualenv_dir)}/bin:$PATH" do
block.call
end
end

def django_manage(*args)
within release_path do
with_virtualenv do
with app_environment: fetch(:stage) do
execute :python, 'manage.py', args
end
end
end
end

Results in "instance variable @_env not defined"

namespace :django do
task :migrate do
on primary fetch(:migration_role) do
django_manage 'syncdb', '--noinput', '--migrate'
end
end
end


Reply to this email directly or view it on GitHubhttps://github.com//issues/43
.

Lee Hambley

http://lee.hambley.name/
+49 (0) 170 298 5667

@clintonb
Copy link
Author

clintonb commented Nov 1, 2013

Can you provide an example? My code below doesn't work as expected. The final argument seems is ignored.

def django_manage(*args)
  within release_path do
    execute :python, 'manage.py', {:with => {:path => "#{fetch(:virtualenv_dir)}/bin:$PATH"}}
  end
end

@leehambley
Copy link
Member

I would have expected that to work, it's possible that the hash argument is
called env:, but the DSL method is called with, you'd have to check the
netssh backend in sshkit (sorry, can't look it up on my phone right now)

Lee Hambley

http://lee.hambley.name/
+49 (0) 170 298 5667

On 1 November 2013 14:08, Clinton Blackburn [email protected]:

Can you provide an example? My code below doesn't work as expected. The
final argument seems is ignored.

def django_manage(*args)
within release_path do

execute :python, 'manage.py', {:with => {:path => "#{fetch(:virtualenv_dir)}/bin:$PATH"}}

endend


Reply to this email directly or view it on GitHubhttps://github.com//issues/43#issuecomment-27564142
.

@signedbyte
Copy link
Contributor

Ok, I've been dealing with this issue a few days now and I've figured out with the help of a colleague, a workaround and also I think there might be a need for a change in the code. What you say above won't actually work.

# sshkit / lib / sshkit / backends/abstract.rb
 def command(*args)
        options = args.extract_options!
        SSHKit::Command.new(*[*args, options.merge({in: @pwd.nil? ? nil : File.join(@pwd), env: @env, host: @host, user: @user, group: @group})])
end

Right now the options being passed in or overridden by anything from the dsl. If you give an env option right now, nothing will be passed in. It will be overridden by this merge and you'll either get what you had in a with or you get "".If you flip the above merge and put it on the left then the command arg will take precedent.

#sshkit / lib / sshkit / backends/abstract.rb
 def command(*args)
        options = args.extract_options!
        SSHKit::Command.new(*[*args, {in: @pwd.nil? ? nil : File.join(@pwd), env: @env, host: @host, user: @user, group: @group}.merge(options)])
end

I was about to submit a pull request but wanted to know the intended behaviour before I put together a fix. @leehambley would you like a pull request of this fix it like this?

The workaround using the dsl is to simply create a hash in the with like this:

on 'google.com' do
  with foo: 'foo', bar: 'bar' do
    execute :ls, '-al'
  end
end

@DylanFrese
Copy link
Contributor

Should be fixed with PR #345

@leehambley
Copy link
Member

If someone can confirm, I'd be glad to close this. I'll swing by again in a few days and check.

@ArturT
Copy link

ArturT commented Jun 13, 2016

@leehambley I had a problem during deploy with capistrano and whenever:update_crontab.

cap aborted!
NameError: instance variable @_env not defined

Tasks: TOP => whenever:update_crontab

I switched to sshkit master branch and the PR #345 that was merged solved my problem.

@ansonhoyt
Copy link

@leehambley I echo @ArturT, updating to master fixed it for me.

If it helps confirm, here's output with --trace before I switched to master:

ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
** Invoke bundler:map_bins (first_time)
** Invoke passenger:bundler:hook (first_time)
** Execute passenger:bundler:hook
** Execute bundler:map_bins
** Invoke deploy:set_rails_env (first_time)
** Execute deploy:set_rails_env
** Invoke deploy:set_linked_dirs (first_time)
** Execute deploy:set_linked_dirs
** Invoke deploy:set_rails_env
** Invoke whenever:update_crontab (first_time)
** Execute whenever:update_crontab
00:00 whenever:update_crontab
      01 /usr/local/rvm/bin/rvm ruby-2.3.0@pbis do bundle exec whenever --update-crontab papbs --set environment=demo --roles=web,app,db
      01 [write] crontab file updated
    ✔ 01 ahoyt@demo 3.447s
cap aborted!
NameError: instance variable @_env not defined
/Users/ahoyt/.rvm/gems/ruby-2.3.0@pbis/gems/sshkit-1.10.0/lib/sshkit/backends/abstract.rb:91:in `remove_instance_variable'
/Users/ahoyt/.rvm/gems/ruby-2.3.0@pbis/gems/sshkit-1.10.0/lib/sshkit/backends/abstract.rb:91:in `with'
/Users/ahoyt/.rvm/gems/ruby-2.3.0@pbis/gems/whenever-0.9.6/lib/whenever/capistrano/v3/tasks/whenever.rake:8:in `block (2 levels) in setup_whenever_task'
/Users/ahoyt/.rvm/gems/ruby-2.3.0@pbis/gems/sshkit-1.10.0/lib/sshkit/backends/abstract.rb:80:in `within'
/Users/ahoyt/.rvm/gems/ruby-2.3.0@pbis/gems/whenever-0.9.6/lib/whenever/capistrano/v3/tasks/whenever.rake:7:in `block in setup_whenever_task'
/Users/ahoyt/.rvm/gems/ruby-2.3.0@pbis/gems/sshkit-1.10.0/lib/sshkit/backends/abstract.rb:29:in `instance_exec'
/Users/ahoyt/.rvm/gems/ruby-2.3.0@pbis/gems/sshkit-1.10.0/lib/sshkit/backends/abstract.rb:29:in `run'
/Users/ahoyt/.rvm/gems/ruby-2.3.0@pbis/gems/sshkit-1.10.0/lib/sshkit/runners/parallel.rb:12:in `block (2 levels) in execute'
Tasks: TOP => whenever:update_crontab```

@mattbrictson
Copy link
Member

Thanks for verifying! I'll close this issue since it has been fixed by PR #345.

I'll release 1.11.0 in a few hours.

@mattbrictson
Copy link
Member

🚢 1.11.0

jsonn pushed a commit to jsonn/pkgsrc that referenced this issue Oct 17, 2016
## [1.11.3][] (2016-09-16)

  * Fix known_hosts caching to match on the entire hostlist
    [PR #364](capistrano/sshkit#364) @byroot

## [1.11.2][] (2016-07-29)

### Bug fixes

  * Fixed a crash occurring when `Host@keys` was set to a non-Enumerable.
    @xavierholt [PR #360](capistrano/sshkit#360)

## [1.11.1][] (2016-06-17)

### Bug fixes

  * Fixed a regression in 1.11.0 that would cause
    `ArgumentError: invalid option(s): known_hosts` in some older versions of
    net-ssh. @byroot [#357](capistrano/sshkit#357)

## [1.11.0][] (2016-06-14)

### Bug fixes

  * Fixed colorized output alignment in Logger::Pretty. @xavierholt
    [PR #349](capistrano/sshkit#349)
  * Fixed a bug that prevented nested `with` calls
    [#43](capistrano/sshkit#43)

### Other changes

  * Known hosts lookup optimization is now enabled by default. @byroot

## 1.10.0 (2016-04-22)

  * You can now opt-in to caching of SSH's known_hosts file for a speed boost
    when deploying to a large fleet of servers. Refer to the
    [README](https://github.com/capistrano/sshkit/tree/v1.10.0#known-hosts-caching) for
    details. We plan to turn this on by default in a future version of SSHKit.
    [PR #330](capistrano/sshkit#330) @byroot
  * SSHKit now explicitly closes its pooled SSH connections when Ruby exits;
    this fixes `zlib(finalizer): the stream was freed prematurely` warnings
    [PR #343](capistrano/sshkit#343) @mattbrictson
  * Allow command map entries (`SSHKit::CommandMap#[]`) to be Procs
    [PR #310](capistrano/sshkit#310)
    @mikz

## 1.9.0

**Refer to the 1.9.0.rc1 release notes for a full list of new features, fixes,
and potentially breaking changes since SSHKit 1.8.1.** There are no changes
since 1.9.0.rc1.

## 1.9.0.rc1

### Potentially breaking changes

  * The SSHKit DSL is no longer automatically included when you `require` it.
    **This means you  must now explicitly `include SSHKit::DSL`.**
    See [PR #219](capistrano/sshkit#219) for details.
    @beatrichartz
  * `SSHKit::Backend::Printer#test` now always returns true
    [PR #312](capistrano/sshkit#312) @mikz

### New features

  * `SSHKit::Formatter::Abstract` now accepts an optional Hash of options
    [PR #308](capistrano/sshkit#308) @mattbrictson
  * Add `SSHKit::Backend.current` so that Capistrano plugin authors can refactor
    helper methods and still have easy access to the currently-executing Backend
    without having to use global variables.
  * Add `SSHKit.config.default_runner` options that allows to override default command runner.
    This option also accepts a name of the custom runner class.
  * The ConnectionPool has been rewritten in this release to be more efficient
    and have a cleaner internal API. You can still completely disable the pool
    by setting `SSHKit::Backend::Netssh.pool.idle_timeout = 0`.
    @mattbrictson @byroot [PR #328](capistrano/sshkit#328)

### Bug fixes

  * make sure working directory for commands is properly cleared after `within` blocks
    [PR #307](capistrano/sshkit#307)
    @steved
  * display more accurate string for commands with spaces being output in `Formatter::Pretty`
    [PR #304](capistrano/sshkit#304)
    @steved
    [PR #319](capistrano/sshkit#319) @mattbrictson
  * Fix a race condition experienced in JRuby that could cause multi-server
    deploys to fail. [PR #322](capistrano/sshkit#322)
    @mattbrictson
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants