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

Keep mtime if no change #212

Merged
merged 8 commits into from
Jun 2, 2016

Conversation

nishidayuya
Copy link
Contributor

Before this PR, Itamae always change mtime in file resource edit action.
After this PR, Itamae change mtime only changing file content.

This PR makes edit action mtime behavior as create action.

Except no change case, because after this commit changes its behavior.
* Same behavior as create action.
@nishidayuya
Copy link
Contributor Author

Umm... nishidayuya/keep_mtime_if_no_change branch has following commits.

yuya@yoshiyuki|2:02:05|0% git --no-pager log --reverse origin/master..nishidayuya/keep_mtime_if_no_change
commit 31ac5b8076f03f59685c90219f1201da58f87738
Author: Yuya.Nishida <yuya@...>
Date:   2016-05-06 03:31:28 +0900

    Remove extra blank line.

commit 654a533fc4a84020c355b81b7c1ca9b7d8a844c4
Author: Yuya.Nishida <yuya@...>
Date:   2016-05-05 15:37:20 +0900

    Add spec for mtime in create action

commit f59eeffa3461e9163b86c50f08213b029399332e
Author: Yuya.Nishida <yuya@...>
Date:   2016-05-06 05:05:09 +0900

    Add spec for mtime in edit action

    Except no change case, because after this commit changes its behavior.

commit 25c6e74090dd98d5873c805033757c2043902861
Author: Yuya.Nishida <yuya@...>
Date:   2016-05-04 02:05:56 +0900

    Keep file mtime if no change.

    * Same behavior as create action.

But GitHub.com list commits with sort by Date.

@nishidayuya
Copy link
Contributor Author

Wercker pass rake spec:unit, but SSL connection is failed in rake spec:integration:provision:trusty.

Bringing machine 'trusty' up with 'digital_ocean' provider...
==> trusty: Droplet is already active
/home/ubuntu/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/net/http.rb:923:in `connect': SSL_connect SYSCALL returned=5 errno=0 state=SSLv3 read server session ticket A (Faraday::SSLError)
    from /home/ubuntu/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/net/http.rb:923:in `block in connect'
    from /home/ubuntu/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/timeout.rb:73:in `timeout'
    from /home/ubuntu/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/net/http.rb:923:in `connect'
    from /home/ubuntu/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/net/http.rb:863:in `do_start'
    from /home/ubuntu/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/net/http.rb:852:in `start'
    from /home/ubuntu/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/net/http.rb:1375:in `request'
    from /home/ubuntu/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/net/http.rb:1133:in `get'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/faraday-0.9.2/lib/faraday/adapter/net_http.rb:80:in `perform_request'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/faraday-0.9.2/lib/faraday/adapter/net_http.rb:40:in `block in call'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/faraday-0.9.2/lib/faraday/adapter/net_http.rb:87:in `with_net_http_connection'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/faraday-0.9.2/lib/faraday/adapter/net_http.rb:32:in `call'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/faraday-0.9.2/lib/faraday/request/url_encoded.rb:15:in `call'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/faraday-0.9.2/lib/faraday/rack_builder.rb:139:in `build_response'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/faraday-0.9.2/lib/faraday/connection.rb:377:in `run_request'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/faraday-0.9.2/lib/faraday/connection.rb:140:in `get'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/vagrant-digitalocean-0.9.0/lib/vagrant-digitalocean/helpers/client.rb:41:in `request'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/vagrant-digitalocean-0.9.0/lib/vagrant-digitalocean/provider.rb:15:in `droplet'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/gems/vagrant-digitalocean-0.9.0/lib/vagrant-digitalocean/provider.rb:96:in `state'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/machine.rb:501:in `state'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/machine.rb:144:in `initialize'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/vagrantfile.rb:79:in `new'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/vagrantfile.rb:79:in `machine'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/environment.rb:663:in `machine'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/plugin/v2/command.rb:177:in `block in with_target_vms'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/plugin/v2/command.rb:201:in `call'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/plugin/v2/command.rb:201:in `block in with_target_vms'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/plugin/v2/command.rb:183:in `each'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/plugin/v2/command.rb:183:in `with_target_vms'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/plugins/commands/ssh_config/command.rb:31:in `execute'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/cli.rb:42:in `execute'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/lib/vagrant/environment.rb:302:in `cli'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bundler/gems/vagrant-ced8641c3230/bin/vagrant:174:in `<top (required)>'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bin/vagrant:23:in `load'
    from /pipeline/build/vendor/bundle/ruby/2.2.0/bin/vagrant:23:in `<main>'
rake aborted!
NoMethodError: undefined method `first' for nil:NilClass
/pipeline/build/Rakefile:58:in `block (6 levels) in <top (required)>'
/pipeline/build/Rakefile:53:in `each'
/pipeline/build/Rakefile:53:in `block (5 levels) in <top (required)>'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/lib/bundler/cli/exec.rb:63:in `load'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/lib/bundler/cli/exec.rb:63:in `kernel_load'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/lib/bundler/cli/exec.rb:24:in `run'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/lib/bundler/cli.rb:304:in `exec'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/lib/bundler/vendor/thor/lib/thor.rb:359:in `dispatch'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/lib/bundler/vendor/thor/lib/thor/base.rb:440:in `start'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/lib/bundler/cli.rb:11:in `start'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/exe/bundle:27:in `block in <top (required)>'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/lib/bundler/friendly_errors.rb:98:in `with_friendly_errors'
/home/ubuntu/.rvm/gems/ruby-2.2.3/gems/bundler-1.12.2/exe/bundle:19:in `<top (required)>'
/home/ubuntu/.rvm/gems/ruby-2.2.3/bin/bundle:23:in `load'
/home/ubuntu/.rvm/gems/ruby-2.2.3/bin/bundle:23:in `<main>'
/home/ubuntu/.rvm/gems/ruby-2.2.3/bin/ruby_executable_hooks:15:in `eval'
/home/ubuntu/.rvm/gems/ruby-2.2.3/bin/ruby_executable_hooks:15:in `<main>'
Tasks: TOP => spec => spec:integration:all => spec:integration:trusty => spec:integration:provision:trusty
(See full trace by running task with --trace)

file "/tmp/file_edit_with_content_change_updates_timestamp" do
action :edit
block do |content|
content[0 .. -1] = "Hello, world"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using gsub like content.gsub!(/\A.+\z/, "Hello, world")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your response!

I fixed it using gsub! as /tmp/file_edit_sample. (8a1cf21)

@nishidayuya
Copy link
Contributor Author

memo:

  • run bundle && bundle exec rake spec:integration:trusty on my local environment, works fine.
  • run on CI, failure with following message.
    • 16:34:56?
...
File "/tmp/file_without_content_change_keeping_timestamp"
  mtime
    should eq #<DateTime: 2016-05-01T12:34:56+00:00 ((2457510j,45296s,0n),+0s,2299161j)> (FAILED - 2)

Failures:

  1) File "/tmp/file_edit_without_content_change_keeping_timestamp" mtime should eq #<DateTime: 2016-05-02T12:34:56+00:00 ((2457511j,45296s,0n),+0s,2299161j)>
     On host `trusty'
     Failure/Error: its(:mtime) { should eq(DateTime.iso8601("2016-05-02T12:34:56Z")) }

       expected: #<DateTime: 2016-05-02T12:34:56+00:00 ((2457511j,45296s,0n),+0s,2299161j)>
            got: #<DateTime: 2016-05-02T16:34:56+00:00 ((2457511j,59696s,0n),+0s,2299161j)>

       (compared using ==)

       Diff:
       @@ -1,2 +1,2 @@
       -#<DateTime: 2016-05-02T12:34:56+00:00 ((2457511j,45296s,0n),+0s,2299161j)>
       +#<DateTime: 2016-05-02T16:34:56+00:00 ((2457511j,59696s,0n),+0s,2299161j)>

       /bin/sh -c stat\ -c\ \%Y\ /tmp/file_edit_without_content_change_keeping_timestamp
       1462206896

     # ./spec/integration/default_spec.rb:224:in `block (2 levels) in <top (required)>'

  2) File "/tmp/file_without_content_change_keeping_timestamp" mtime should eq #<DateTime: 2016-05-01T12:34:56+00:00 ((2457510j,45296s,0n),+0s,2299161j)>
     On host `trusty'
     Failure/Error: its(:mtime) { should eq(DateTime.iso8601("2016-05-01T12:34:56Z")) }

       expected: #<DateTime: 2016-05-01T12:34:56+00:00 ((2457510j,45296s,0n),+0s,2299161j)>
            got: #<DateTime: 2016-05-01T16:34:56+00:00 ((2457510j,59696s,0n),+0s,2299161j)>

       (compared using ==)

       Diff:
       @@ -1,2 +1,2 @@
       -#<DateTime: 2016-05-01T12:34:56+00:00 ((2457510j,45296s,0n),+0s,2299161j)>
       +#<DateTime: 2016-05-01T16:34:56+00:00 ((2457510j,59696s,0n),+0s,2299161j)>

       /bin/sh -c stat\ -c\ \%Y\ /tmp/file_without_content_change_keeping_timestamp
       1462120496

     # ./spec/integration/default_spec.rb:256:in `block (2 levels) in <top (required)>'

Finished in 6.41 seconds (files took 3.14 seconds to load)
103 examples, 2 failures

Failed examples:

rspec ./spec/integration/default_spec.rb:224 # File "/tmp/file_edit_without_content_change_keeping_timestamp" mtime should eq #<DateTime: 2016-05-02T12:34:56+00:00 ((2457511j,45296s,0n),+0s,2299161j)>
rspec ./spec/integration/default_spec.rb:256 # File "/tmp/file_without_content_change_keeping_timestamp" mtime should eq #<DateTime: 2016-05-01T12:34:56+00:00 ((2457510j,45296s,0n),+0s,2299161j)>

/home/ubuntu/.rvm/rubies/ruby-2.2.3/bin/ruby -I ./spec/integration -I/pipeline/build/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.4.4/lib:/pipeline/build/vendor/bundle/ruby/2.2.0/gems/rspec-support-3.4.1/lib /pipeline/build/vendor/bundle/ruby/2.2.0/gems/rspec-core-3.4.4/exe/rspec --pattern spec/integration/\*_spec.rb failed

@ryotarai
Copy link
Member

ryotarai commented May 9, 2016

run on CI, failure with following message.

It may be due to timezone. The following can fix the problem

touch -d '2016/05/01 12:34:56+00:00' /tmp/file_with_content_change_updates_timestamp

@nishidayuya
Copy link
Contributor Author

run on CI, failure with following message.

It may be due to timezone. The following can fix the problem

Thanks!

If I set Vagrantfile timezone, I get same failures as CI.
I'll push fixes with test.

diff --git a/spec/integration/Vagrantfile b/spec/integration/Vagrantfile
index e663a73..587e47c 100644
--- a/spec/integration/Vagrantfile
+++ b/spec/integration/Vagrantfile
@@ -17,6 +17,8 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
     mv /tmp/sources.list /etc/apt/sources.list
     apt-get update
   fi
+  echo America/New_York > /etc/timezone
+  dpkg-reconfigure --frontend noninteractive tzdata
       EOC
     end
$ (cd spec/integration && bundle && bundle exec vagrant destroy -f) ; bundle && env -- TZ=UTC bundle exec rake spec:integration:trusty
...
Failures:

  1) File "/tmp/file_edit_without_content_change_keeping_timestamp" mtime should eq #<DateTime: 2016-05-02T12:34:56+00:00 ((2457511j,45296s,0n),+0s,2299161j)>
     On host `trusty'
     Failure/Error: its(:mtime) { should eq(DateTime.iso8601("2016-05-02T12:34:56Z")) }

       expected: #<DateTime: 2016-05-02T12:34:56+00:00 ((2457511j,45296s,0n),+0s,2299161j)>
            got: #<DateTime: 2016-05-02T16:34:56+00:00 ((2457511j,59696s,0n),+0s,2299161j)>

       (compared using ==)

       Diff:
       @@ -1,2 +1,2 @@
       -#<DateTime: 2016-05-02T12:34:56+00:00 ((2457511j,45296s,0n),+0s,2299161j)>
       +#<DateTime: 2016-05-02T16:34:56+00:00 ((2457511j,59696s,0n),+0s,2299161j)>

       sudo -p 'Password: ' /bin/sh -c stat\ -c\ \%Y\ /tmp/file_edit_without_content_change_keeping_timestamp
       1462206896

     # ./spec/integration/default_spec.rb:224:in `block (2 levels) in <top (required)>'

  2) File "/tmp/file_without_content_change_keeping_timestamp" mtime should eq #<DateTime: 2016-05-01T12:34:56+00:00 ((2457510j,45296s,0n),+0s,2299161j)>
     On host `trusty'
     Failure/Error: its(:mtime) { should eq(DateTime.iso8601("2016-05-01T12:34:56Z")) }

       expected: #<DateTime: 2016-05-01T12:34:56+00:00 ((2457510j,45296s,0n),+0s,2299161j)>
            got: #<DateTime: 2016-05-01T16:34:56+00:00 ((2457510j,59696s,0n),+0s,2299161j)>

       (compared using ==)

       Diff:
       @@ -1,2 +1,2 @@
       -#<DateTime: 2016-05-01T12:34:56+00:00 ((2457510j,45296s,0n),+0s,2299161j)>
       +#<DateTime: 2016-05-01T16:34:56+00:00 ((2457510j,59696s,0n),+0s,2299161j)>

       sudo -p 'Password: ' /bin/sh -c stat\ -c\ \%Y\ /tmp/file_without_content_change_keeping_timestamp
       1462120496

     # ./spec/integration/default_spec.rb:256:in `block (2 levels) in <top (required)>'

Finished in 6.6 seconds (files took 2.31 seconds to load)
103 examples, 2 failures

Failed examples:

rspec ./spec/integration/default_spec.rb:224 # File "/tmp/file_edit_without_content_change_keeping_timestamp" mtime should eq #<DateTime: 2016-05-02T12:34:56+00:00 ((2457511j,45296s,0n),+0s,2299161j)>
rspec ./spec/integration/default_spec.rb:256 # File "/tmp/file_without_content_change_keeping_timestamp" mtime should eq #<DateTime: 2016-05-01T12:34:56+00:00 ((2457510j,45296s,0n),+0s,2299161j)>

In Vagrantfile, VirtualBox provider section emulates DigitalOcean provider timezone.
@nishidayuya
Copy link
Contributor Author

I'll push fixes with test.

Done. And Wercker pass.

@ryotarai
Copy link
Member

It may be due to timezone. The following can fix the problem

I didn't meant changing timezone. If you pass time to touch command like touch -d '2016/05/01 12:34:56+00:00' /tmp/foo, the time is parsed as UTC, so regardless of timezone of the system the test will be passed. Changing timezone by modifying /etc/timezone doesn't looks a good idea to me

@nishidayuya
Copy link
Contributor Author

1ebf3cf includes following:

  1. changing touch command like touch -d 2016-05-02T12:34:56Z /tmp/foo.
  2. changing timezone on VirtualBox provider.
    • To simulate DigitalOcean provider on VirtualBox provider.
    • To reject timezone differences between DigitalOcean provider and VirtualBox provider.
    • Itamae users will be free to think that differences.

else
owner = run_specinfra(:get_file_owner_user, attributes.path).stdout.chomp
group = run_specinfra(:get_file_owner_group, attributes.path).stdout.chomp
run_specinfra(:change_file_owner, @temppath, owner)
run_specinfra(:change_file_group, @temppath, group)
run_specinfra(:change_file_owner, change_target, owner)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't make any change because owner is got fromrun_specinfra(:get_file_owner_user, attributes.path)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand following:

  • Case: attributes.modified is true.
    • change_target is @temppath.
    • need :change_file_owner.
  • Case: attributes.modified is false.
    • change_target is attributes.path.
    • DON'T need :change_file_owner.

So I must fix to following:

diff --git a/lib/itamae/resource/file.rb b/lib/itamae/resource/file.rb
index d938523..1d26af7 100644
--- a/lib/itamae/resource/file.rb
+++ b/lib/itamae/resource/file.rb
@@ -95,11 +95,11 @@ def action_edit(options)

         if attributes.owner || attributes.group
           run_specinfra(:change_file_owner, change_target, attributes.owner, attributes.group)
-        else
+        elsif attributes.modified
           owner = run_specinfra(:get_file_owner_user, attributes.path).stdout.chomp
           group = run_specinfra(:get_file_owner_group, attributes.path).stdout.chomp
-          run_specinfra(:change_file_owner, change_target, owner)
-          run_specinfra(:change_file_group, change_target, group)
+          run_specinfra(:change_file_owner, @temppath, owner)
+          run_specinfra(:change_file_group, @temppath, group)
         end

         if attributes.modified

Is it OK?

(elsif attributes.modified removes extra run_specinfra calling)

@ryotarai
Copy link
Member

How about this?

        change_target = attributes.modified ? @temppath : attributes.path

        if attributes.mode || attributes.modified
          mode = attributes.mode || run_specinfra(:get_file_mode, attributes.path).stdout.chomp
          run_specinfra(:change_file_mode, change_target, mode)
        end

        if attributes.owner || attributes.group || attributes.modified
          owner = attributes.owner || run_specinfra(:get_file_owner_user, attributes.path).stdout.chomp
          group = attributes.group || run_specinfra(:get_file_owner_group, attributes.path).stdout.chomp
          run_specinfra(:change_file_owner, change_target, owner, group)
        end

        if attributes.modified
          run_specinfra(:move_file, @temppath, attributes.path)
        end

@nishidayuya
Copy link
Contributor Author

I like it. Its code looks like action_create flow and its lines are less than first code.

I have fixed and Wercker passed.
Thank you.

@ryotarai
Copy link
Member

ryotarai commented Jun 2, 2016

Sorry for late reply. I'll merge this

@ryotarai ryotarai merged commit dfdf16c into itamae-kitchen:master Jun 2, 2016
@nishidayuya
Copy link
Contributor Author

No problem. Thank you for your merging and nice reviews!

@nishidayuya nishidayuya deleted the keep_mtime_if_no_change branch June 2, 2016 12:22
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

Successfully merging this pull request may close these issues.

2 participants