r-train 0.10.8 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 32ff41b8ff5978a069895749aa4552622ce66f83
4
- data.tar.gz: aee9c30afa4e65ad9ecce338aeb2b331a53fd35f
3
+ metadata.gz: 32041a577502de9c77d37eb40ff8fc7110693b7f
4
+ data.tar.gz: 8202709105de66980ebd1901ec4106ab32d9899e
5
5
  SHA512:
6
- metadata.gz: 672801e1cd8849041f0736eb53d52f473b027e9f046f9669d351b36804c6ea6a3ae956552f393e8df9fbfca6bee980f7a54da64bdb147899d178243bbb36c6e3
7
- data.tar.gz: 9fd2658924b66145474edb62497f5bab9790e00a1b0793f7f058a3cb2dca8bc7ea2694d77b20cfe2bbb06368cfaeea3ac8ca9d0f7e9477d1fbd9e3374c691fa9
6
+ metadata.gz: f19534cf0741a0c400eff0c151f9f056bdb1df3f6043ed9c61e968c7ff0a99c8f07b5a24376f95e52d321dc27619fe72476b66657ea3d6a29b7ec0e83fb03c9e
7
+ data.tar.gz: d758c0e2af5abbad797f94d93f7c0ada74dea5ab070d785fea79ac72ee53d0c67cd7013d98107e11625cf411c0572a13b1dfa01be45f681ffa29a254bb426c9e
data/CHANGELOG.md CHANGED
@@ -1,7 +1,18 @@
1
1
  # Change Log
2
2
 
3
- ## [0.10.8](https://github.com/chef/train/tree/0.10.8) (2016-04-25)
4
- [Full Changelog](https://github.com/chef/train/compare/v0.10.7...0.10.8)
3
+ ## [0.11.0](https://github.com/chef/train/tree/0.11.0) (2016-04-28)
4
+ [Full Changelog](https://github.com/chef/train/compare/v0.10.8...0.11.0)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - Overhault file\(...\) and stat\(...\); point to destination of symlinks [\#92](https://github.com/chef/train/pull/92) ([arlimus](https://github.com/arlimus))
9
+
10
+ **Fixed bugs:**
11
+
12
+ - validate the backend configuration [\#91](https://github.com/chef/train/pull/91) ([arlimus](https://github.com/arlimus))
13
+
14
+ ## [v0.10.8](https://github.com/chef/train/tree/v0.10.8) (2016-04-25)
15
+ [Full Changelog](https://github.com/chef/train/compare/v0.10.7...v0.10.8)
5
16
 
6
17
  **Implemented enhancements:**
7
18
 
data/lib/train.rb CHANGED
@@ -62,6 +62,7 @@ module Train
62
62
 
63
63
  return conf if conf[:target].to_s.empty?
64
64
 
65
+ # split up the target's host/scheme configuration
65
66
  uri = URI.parse(conf[:target].to_s)
66
67
  unless uri.host.nil? and uri.scheme.nil?
67
68
  conf[:backend] ||= uri.scheme
@@ -79,6 +80,24 @@ module Train
79
80
  conf
80
81
  end
81
82
 
83
+ def self.validate_backend(conf, default = :local)
84
+ return default if conf.nil?
85
+ res = conf[:backend]
86
+ return res if !res.nil?
87
+
88
+ if !conf[:target].nil?
89
+ fail Train::UserError, 'Cannot determine backend from target '\
90
+ "configuration #{conf[:target].inspect}. Valid example: ssh://192.168.0.1."
91
+ end
92
+
93
+ if !conf[:host].nil?
94
+ fail Train::UserError, 'Host configured, but no backend was provided. Please '\
95
+ 'specify how you want to connect. Valid example: ssh://192.168.0.1.'
96
+ end
97
+
98
+ conf[:backend] = default
99
+ end
100
+
82
101
  def self.group_keys_and_keyfiles(conf)
83
102
  # in case the user specified a key-file, register it that way
84
103
  # we will clear the list of keys and put keys and key_files separately
@@ -10,14 +10,20 @@ module Train::Extras
10
10
  # interface methods: these fields should be implemented by every
11
11
  # backend File
12
12
  %w{
13
- exist? mode owner group link_target link_path content mtime size
14
- selinux_label product_version file_version path
13
+ exist? mode owner group uid gid content mtime size selinux_label path
14
+ product_version file_version
15
15
  }.each do |m|
16
16
  define_method m.to_sym do
17
17
  fail NotImplementedError, "File must implement the #{m}() method."
18
18
  end
19
19
  end
20
20
 
21
+ def initialize(backend, path, follow_symlink = true)
22
+ @backend = backend
23
+ @path = path
24
+ @follow_symlink = follow_symlink
25
+ end
26
+
21
27
  def type
22
28
  :unknown
23
29
  end
@@ -44,31 +50,39 @@ module Train::Extras
44
50
  # Additional methods for convenience
45
51
 
46
52
  def file?
47
- target_type == :file
53
+ type == :file
48
54
  end
49
55
 
50
56
  def block_device?
51
- target_type == :block_device
57
+ type == :block_device
52
58
  end
53
59
 
54
60
  def character_device?
55
- target_type == :character_device
61
+ type == :character_device
56
62
  end
57
63
 
58
64
  def socket?
59
- target_type == :socket
65
+ type == :socket
60
66
  end
61
67
 
62
68
  def directory?
63
- target_type == :directory
69
+ type == :directory
64
70
  end
65
71
 
66
72
  def symlink?
67
- type == :symlink
73
+ source.type == :symlink
74
+ end
75
+
76
+ def source
77
+ if @follow_symlink
78
+ self.class.new(@backend, @path, false)
79
+ else
80
+ self
81
+ end
68
82
  end
69
83
 
70
84
  def pipe?
71
- target_type == :pipe
85
+ type == :pipe
72
86
  end
73
87
 
74
88
  def mode?(sth)
@@ -87,6 +101,10 @@ module Train::Extras
87
101
  link_path == dst
88
102
  end
89
103
 
104
+ def link_path
105
+ symlink? ? path : nil
106
+ end
107
+
90
108
  def version?(version)
91
109
  product_version == version or
92
110
  file_version == version
@@ -123,15 +141,6 @@ module Train::Extras
123
141
  path[idx..-1]
124
142
  end
125
143
 
126
- def target_type
127
- # Just return the type unless this is a symlink
128
- return type unless type == :symlink
129
- # Get the link's target type, i.e. the real destination's type
130
- return link_target.type unless link_target.nil?
131
- # Return unknown if we don't know where this is pointing to
132
- :unknown
133
- end
134
-
135
144
  UNIX_MODE_OWNERS = {
136
145
  all: 00777,
137
146
  owner: 00700,
@@ -8,9 +8,8 @@ require 'train/extras/stat'
8
8
  module Train::Extras
9
9
  class UnixFile < FileCommon
10
10
  attr_reader :path
11
- def initialize(backend, path)
12
- @backend = backend
13
- @path = path
11
+ def initialize(backend, path, follow_symlink = true)
12
+ super(backend, path, follow_symlink)
14
13
  @spath = Shellwords.escape(@path)
15
14
  end
16
15
 
@@ -27,21 +26,15 @@ module Train::Extras
27
26
 
28
27
  def exist?
29
28
  @exist ||= (
30
- @backend.run_command("test -e #{@spath}")
29
+ f = @follow_symlink ? '' : " || test -L #{@spath}"
30
+ @backend.run_command("test -e #{@spath}"+f)
31
31
  .exit_status == 0
32
32
  )
33
33
  end
34
34
 
35
- def link_target
36
- return @link_target if defined? @link_target
37
- return @link_target = nil if link_path.nil?
38
- @link_target = @backend.file(link_path)
39
- end
40
-
41
- def link_path
42
- return nil unless symlink?
43
- @link_path ||=
44
- @backend.run_command("readlink #{@spath}").stdout.chomp
35
+ def path
36
+ return @path unless @follow_symlink && symlink?
37
+ @link_path ||= read_target_path
45
38
  end
46
39
 
47
40
  def mounted
@@ -50,7 +43,7 @@ module Train::Extras
50
43
  end
51
44
 
52
45
  %w{
53
- type mode owner group mtime size selinux_label
46
+ type mode owner group uid gid mtime size selinux_label
54
47
  }.each do |field|
55
48
  define_method field.to_sym do
56
49
  stat[field.to_sym]
@@ -67,7 +60,20 @@ module Train::Extras
67
60
 
68
61
  def stat
69
62
  return @stat if defined?(@stat)
70
- @stat = Train::Extras::Stat.stat(@spath, @backend)
63
+ @stat = Train::Extras::Stat.stat(@spath, @backend, @follow_symlink)
64
+ end
65
+
66
+ private
67
+
68
+ # Returns full path of a symlink target(real dest) or '' on symlink loop
69
+ def read_target_path
70
+ full_path = @backend.run_command("readlink -n #{@spath} -f").stdout
71
+ # Needed for some OSes like OSX that returns relative path
72
+ # when the link and target are in the same directory
73
+ if !full_path.start_with?('/') && full_path != ''
74
+ full_path = File.expand_path("../#{full_path}", @spath)
75
+ end
76
+ full_path
71
77
  end
72
78
  end
73
79
  end
@@ -11,9 +11,8 @@ require 'train/extras/stat'
11
11
  module Train::Extras
12
12
  class WindowsFile < FileCommon
13
13
  attr_reader :path
14
- def initialize(backend, path)
15
- @backend = backend
16
- @path = path
14
+ def initialize(backend, path, follow_symlink)
15
+ super(backend, path, follow_symlink)
17
16
  @spath = sanitize_filename(@path)
18
17
  end
19
18
 
@@ -44,10 +43,6 @@ module Train::Extras
44
43
  "(Test-Path -Path \"#{@spath}\").ToString()").stdout.chomp == 'True'
45
44
  end
46
45
 
47
- def link_target
48
- nil
49
- end
50
-
51
46
  def link_path
52
47
  nil
53
48
  end
@@ -57,11 +52,16 @@ module Train::Extras
57
52
  end
58
53
 
59
54
  def type
55
+ if attributes.include?('Archive')
56
+ return :file
57
+ elsif attributes.include?('Directory')
58
+ return :directory
59
+ end
60
60
  :unknown
61
61
  end
62
62
 
63
63
  %w{
64
- mode owner group mtime size selinux_label
64
+ mode owner group uid gid mtime size selinux_label
65
65
  }.each do |field|
66
66
  define_method field.to_sym do
67
67
  nil
@@ -85,16 +85,7 @@ module Train::Extras
85
85
  def attributes
86
86
  return @attributes if defined?(@attributes)
87
87
  @attributes = @backend.run_command(
88
- "(Get-ItemProperty -Path \"#{@spath}\").attributes.ToString()").stdout.chomp.split(',')
89
- end
90
-
91
- def target_type
92
- if attributes.include?('Archive')
93
- return :file
94
- elsif attributes.include?('Directory')
95
- return :directory
96
- end
97
- :unknown
88
+ "(Get-ItemProperty -Path \"#{@spath}\").attributes.ToString()").stdout.chomp.split(/\s*,\s*/)
98
89
  end
99
90
  end
100
91
  end
@@ -19,22 +19,23 @@ module Train::Extras
19
19
  res.nil? ? :unknown : res[0]
20
20
  end
21
21
 
22
- def self.stat(shell_escaped_path, backend)
22
+ def self.stat(shell_escaped_path, backend, follow_symlink)
23
23
  # use perl scripts for aix and solaris 10
24
24
  if backend.os.aix? || (backend.os.solaris? && backend.os[:release].to_i < 11)
25
- return aix_stat(shell_escaped_path, backend)
25
+ return aix_stat(shell_escaped_path, backend, follow_symlink)
26
26
  end
27
- return bsd_stat(shell_escaped_path, backend) if backend.os.bsd?
27
+ return bsd_stat(shell_escaped_path, backend, follow_symlink) if backend.os.bsd?
28
28
  # linux and solaris 11 will use standard linux stats
29
- return linux_stat(shell_escaped_path, backend) if backend.os.unix?
29
+ return linux_stat(shell_escaped_path, backend, follow_symlink) if backend.os.unix?
30
30
  # all other cases we don't handle
31
31
  # TODO: print an error if we get here, as it shouldn't be invoked
32
32
  # on non-unix
33
33
  {}
34
34
  end
35
35
 
36
- def self.linux_stat(shell_escaped_path, backend)
37
- res = backend.run_command("stat #{shell_escaped_path} 2>/dev/null --printf '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'")
36
+ def self.linux_stat(shell_escaped_path, backend, follow_symlink)
37
+ lstat = follow_symlink ? ' -L' : ''
38
+ res = backend.run_command("stat#{lstat} #{shell_escaped_path} 2>/dev/null --printf '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'")
38
39
 
39
40
  # ignore the exit_code: it is != 0 if selinux labels are not supported
40
41
  # on the system.
@@ -47,17 +48,19 @@ module Train::Extras
47
48
  selinux = nil if selinux == '?' or selinux == '(null)'
48
49
 
49
50
  {
50
- type: find_type(tmask),
51
- mode: tmask & 07777,
51
+ type: find_type(tmask),
52
+ mode: tmask & 07777,
52
53
  owner: fields[2],
54
+ uid: fields[3].to_i,
53
55
  group: fields[4],
56
+ gid: fields[5].to_i,
54
57
  mtime: fields[7].to_i,
55
- size: fields[0].to_i,
58
+ size: fields[0].to_i,
56
59
  selinux_label: selinux,
57
60
  }
58
61
  end
59
62
 
60
- def self.bsd_stat(shell_escaped_path, backend)
63
+ def self.bsd_stat(shell_escaped_path, backend, follow_symlink)
61
64
  # From stat man page on FreeBSD:
62
65
  # z The size of file in bytes (st_size).
63
66
  # p File type and permissions (st_mode).
@@ -72,8 +75,9 @@ module Train::Extras
72
75
  # in combination with:
73
76
  # ...
74
77
  # gu Display group or user name.
78
+ lstat = follow_symlink ? ' -L' : ''
75
79
  res = backend.run_command(
76
- "stat -f '%z\n%p\n%Su\n%u\n%Sg\n%g\n%a\n%m' "\
80
+ "stat#{lstat} -f '%z\n%p\n%Su\n%u\n%Sg\n%g\n%a\n%m' "\
77
81
  "#{shell_escaped_path}")
78
82
 
79
83
  return {} if res.exit_status != 0
@@ -84,24 +88,27 @@ module Train::Extras
84
88
  tmask = fields[1].to_i(8)
85
89
 
86
90
  {
87
- type: find_type(tmask),
88
- mode: tmask & 07777,
91
+ type: find_type(tmask),
92
+ mode: tmask & 07777,
89
93
  owner: fields[2],
94
+ uid: fields[3].to_i,
90
95
  group: fields[4],
96
+ gid: fields[5].to_i,
91
97
  mtime: fields[7].to_i,
92
- size: fields[0].to_i,
98
+ size: fields[0].to_i,
93
99
  selinux_label: fields[8],
94
100
  }
95
101
  end
96
102
 
97
- def self.aix_stat(shell_escaped_path, backend)
103
+ def self.aix_stat(shell_escaped_path, backend, follow_symlink)
98
104
  # Perl here b/c it is default on AIX
105
+ lstat = follow_symlink ? 'lstat' : 'stat'
99
106
  stat_cmd = <<-EOP
100
107
  perl -e '
101
- @a = lstat(shift) or exit 2;
108
+ @a = #{lstat}(shift) or exit 2;
102
109
  $u = getpwuid($a[4]);
103
110
  $g = getgrgid($a[5]);
104
- printf("0%o\\n%s\\n%s\\n%d\\n%d\\n", $a[2], $u, $g, $a[9], $a[7])
111
+ printf("0%o\\n%s\\n%d\\n%s\\n%d\\n%d\\n%d\\n", $a[2], $u, $a[4], $u, $a[5], $a[9], $a[7])
105
112
  ' #{shell_escaped_path}
106
113
  EOP
107
114
 
@@ -115,9 +122,11 @@ module Train::Extras
115
122
  type: find_type(tmask),
116
123
  mode: tmask & 07777,
117
124
  owner: fields[1],
118
- group: fields[2],
119
- mtime: fields[3].to_i,
120
- size: fields[4].to_i,
125
+ uid: fields[2].to_i,
126
+ group: fields[3],
127
+ gid: fields[4].to_i,
128
+ mtime: fields[5].to_i,
129
+ size: fields[6].to_i,
121
130
  selinux_label: nil,
122
131
  }
123
132
  end
@@ -23,7 +23,12 @@ class Train::Transports::Local::Connection
23
23
 
24
24
  def link_path
25
25
  return nil unless symlink?
26
- @link_path ||= ::File.readlink(@path)
26
+ begin
27
+ @link_path ||= ::File.realpath(@path)
28
+ rescue Errno::ELOOP => _
29
+ # Leave it blank on symbolic loop, same as readlink
30
+ @link_path = ''
31
+ end
27
32
  end
28
33
 
29
34
  def block_device?
@@ -52,7 +57,12 @@ class Train::Transports::Local::Connection
52
57
  return @stat if defined? @stat
53
58
 
54
59
  begin
55
- file_stat = ::File.lstat(@path)
60
+ file_stat =
61
+ if @follow_symlink
62
+ ::File.stat(@path)
63
+ else
64
+ ::File.lstat(@path)
65
+ end
56
66
  rescue StandardError => _err
57
67
  return @stat = {}
58
68
  end
@@ -63,10 +73,13 @@ class Train::Transports::Local::Connection
63
73
  mtime: file_stat.mtime.to_i,
64
74
  size: file_stat.size,
65
75
  owner: pw_username(file_stat.uid),
76
+ uid: file_stat.uid,
66
77
  group: pw_groupname(file_stat.gid),
78
+ gid: file_stat.gid,
67
79
  }
68
80
 
69
- res = @backend.run_command("stat #{@spath} 2>/dev/null --printf '%C'")
81
+ lstat = @follow_symlink ? ' -L' : ''
82
+ res = @backend.run_command("stat#{lstat} #{@spath} 2>/dev/null --printf '%C'")
70
83
  if res.exit_status == 0 && !res.stdout.empty? && res.stdout != '?'
71
84
  @stat[:selinux_label] = res.stdout.strip
72
85
  end
@@ -127,22 +127,21 @@ end
127
127
  class Train::Transports::Mock::Connection
128
128
  class File < FileCommon
129
129
  %w{
130
- exist? mode owner group link_target link_path content mtime size
130
+ exist? mode owner group link_path content mtime size
131
131
  selinux_label product_version file_version path type
132
132
  }.each do |m|
133
133
  attr_accessor m.tr('?', '').to_sym
134
134
  end
135
135
 
136
- def initialize(runtime, path)
137
- @path = path
136
+ def initialize(backend, path, follow_symlink = true)
137
+ super(backend, path, follow_symlink)
138
138
  @type = :unknown
139
139
  @exist = false
140
- @runtime = runtime
141
140
  end
142
141
 
143
142
  def mounted
144
143
  @mounted ||=
145
- @runtime.run_command("mount | grep -- ' on #{@path}'")
144
+ @backend.run_command("mount | grep -- ' on #{@path}'")
146
145
  end
147
146
  end
148
147
  end
data/lib/train/version.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  # Author:: Dominik Richter (<dominik.richter@gmail.com>)
4
4
 
5
5
  module Train
6
- VERSION = '0.10.8'.freeze
6
+ VERSION = '0.11.0'.freeze
7
7
  end
@@ -22,8 +22,8 @@ describe 'file interface' do
22
22
  file.directory?.must_equal(false)
23
23
  end
24
24
 
25
- it 'has type :symlink' do
26
- file.type.must_equal(:symlink)
25
+ it 'has type :file' do
26
+ file.type.must_equal(:file)
27
27
  end
28
28
 
29
29
  it 'has content' do
@@ -34,16 +34,28 @@ describe 'file interface' do
34
34
  file.owner.must_equal('root')
35
35
  end
36
36
 
37
+ it 'has uid 0' do
38
+ file.uid.must_equal(0)
39
+ end
40
+
37
41
  it 'has group name' do
38
42
  file.group.must_equal(Test.root_group(backend.os))
39
43
  end
40
44
 
45
+ it 'has gid 0' do
46
+ file.gid.must_equal(0)
47
+ end
48
+
41
49
  it 'has mode 0777' do
42
- file.mode.must_equal(00777)
50
+ file.source.mode.must_equal(00777)
51
+ end
52
+
53
+ it 'has mode 0765' do
54
+ file.mode.must_equal(00765)
43
55
  end
44
56
 
45
- it 'checks mode? 0777' do
46
- file.mode?(00777).must_equal(true)
57
+ it 'checks mode? 0765' do
58
+ file.mode?(00765).must_equal(true)
47
59
  end
48
60
 
49
61
  it 'has link_path' do
@@ -5,6 +5,7 @@ require 'train/extras/file_common'
5
5
 
6
6
  describe 'file common' do
7
7
  let(:cls) { Train::Extras::FileCommon }
8
+ let(:new_cls) { cls.new(nil, nil, false) }
8
9
 
9
10
  def mockup(stubs)
10
11
  Class.new(cls) do
@@ -13,35 +14,35 @@ describe 'file common' do
13
14
  v
14
15
  end
15
16
  end
16
- end.new
17
+ end.new(nil, nil, false)
17
18
  end
18
19
 
19
20
  it 'has the default type of unknown' do
20
- cls.new.type.must_equal :unknown
21
+ new_cls.type.must_equal :unknown
21
22
  end
22
23
 
23
24
  it 'calculates md5sum from content' do
24
25
  content = 'hello world'
25
- cls.new.stub :content, content do |i|
26
+ new_cls.stub :content, content do |i|
26
27
  i.md5sum.must_equal '5eb63bbbe01eeed093cb22bb8f5acdc3'
27
28
  end
28
29
  end
29
30
 
30
31
  it 'sets md5sum of nil content to nil' do
31
- cls.new.stub :content, nil do |i|
32
+ new_cls.stub :content, nil do |i|
32
33
  i.md5sum.must_be_nil
33
34
  end
34
35
  end
35
36
 
36
37
  it 'calculates md5sum from content' do
37
38
  content = 'hello world'
38
- cls.new.stub :content, content do |i|
39
+ new_cls.stub :content, content do |i|
39
40
  i.sha256sum.must_equal 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
40
41
  end
41
42
  end
42
43
 
43
44
  it 'sets sha256sum of nil content to nil' do
44
- cls.new.stub :content, nil do |i|
45
+ new_cls.stub :content, nil do |i|
45
46
  i.sha256sum.must_be_nil
46
47
  end
47
48
  end
@@ -11,9 +11,9 @@ describe 'file common' do
11
11
  backend
12
12
  }
13
13
 
14
- def mock_stat(path, out, err = '', code = 0)
14
+ def mock_stat(args, out, err = '', code = 0)
15
15
  backend.mock_command(
16
- "stat path 2>/dev/null --printf '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'",
16
+ "stat #{args} 2>/dev/null --printf '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'",
17
17
  out, err, code,
18
18
  )
19
19
  end
@@ -34,7 +34,7 @@ describe 'file common' do
34
34
 
35
35
  it 'reads file contents' do
36
36
  backend.mock_command('cat path || echo -n', '')
37
- mock_stat('path', '', 'some error...', 1)
37
+ mock_stat('-L path', '', 'some error...', 1)
38
38
  cls.new(backend, 'path').content.must_equal nil
39
39
  end
40
40
 
@@ -51,16 +51,8 @@ describe 'file common' do
51
51
  it 'retrieves the link path' do
52
52
  out = rand.to_s
53
53
  mock_stat('path', "13\na1ff\nz\n1001\nz\n1001\n1444573475\n1444573475\n?")
54
- backend.mock_command('readlink path', out)
55
- cls.new(backend, 'path').link_path.must_equal out
56
- end
57
-
58
- it 'retrieves the linked file' do
59
- out = rand.to_s
60
- mock_stat('path', "13\na1ff\nz\n1001\nz\n1001\n1444573475\n1444573475\n?")
61
- backend.mock_command('readlink path', out)
62
- f = backend.file(out)
63
- cls.new(backend, 'path').link_target.must_equal f
54
+ backend.mock_command('readlink -n path -f', out)
55
+ cls.new(backend, 'path').link_path.must_equal File.join(Dir.pwd, out)
64
56
  end
65
57
 
66
58
  it 'checks a mounted path' do
@@ -77,30 +69,84 @@ describe 'file common' do
77
69
  end
78
70
 
79
71
  describe 'stat on a file' do
80
- before { mock_stat('path', "13\na1ff\nz\n1001\nz\n1001\n1444573475\n1444573475\nlabels") }
72
+ before { mock_stat('-L path', "13\na1ff\nz\n1001\nz2\n1002\n1444573475\n1444573475\nlabels") }
73
+ let(:f) { cls.new(backend, 'path') }
74
+
75
+ it 'retrieves the file type' do
76
+ f.type.must_equal :symlink
77
+ end
78
+
79
+ it 'retrieves the file mode' do
80
+ f.mode.must_equal 00777
81
+ end
82
+
83
+ it 'retrieves the file owner' do
84
+ f.owner.must_equal 'z'
85
+ end
86
+
87
+ it 'retrieves the file uid' do
88
+ f.uid.must_equal 1001
89
+ end
90
+
91
+ it 'retrieves the file group' do
92
+ f.group.must_equal 'z2'
93
+ end
94
+
95
+ it 'retrieves the file gid' do
96
+ f.gid.must_equal 1002
97
+ end
98
+
99
+ it 'retrieves the file mtime' do
100
+ f.mtime.must_equal 1444573475
101
+ end
102
+
103
+ it 'retrieves the file size' do
104
+ f.size.must_equal 13
105
+ end
106
+
107
+ it 'retrieves the file selinux_label' do
108
+ f.selinux_label.must_equal 'labels'
109
+ end
110
+ end
111
+
112
+ describe 'stat on the source file' do
113
+ before { mock_stat('path', "13\na1ff\nz\n1001\nz2\n1002\n1444573475\n1444573475\nlabels") }
114
+ let(:f) { cls.new(backend, 'path').source }
81
115
 
82
116
  it 'retrieves the file type' do
83
- cls.new(backend, 'path').type.must_equal :symlink
117
+ f.type.must_equal :symlink
84
118
  end
85
119
 
86
120
  it 'retrieves the file mode' do
87
- cls.new(backend, 'path').mode.must_equal 00777
121
+ f.mode.must_equal 00777
88
122
  end
89
123
 
90
124
  it 'retrieves the file owner' do
91
- cls.new(backend, 'path').owner.must_equal 'z'
125
+ f.owner.must_equal 'z'
126
+ end
127
+
128
+ it 'retrieves the file uid' do
129
+ f.uid.must_equal 1001
130
+ end
131
+
132
+ it 'retrieves the file group' do
133
+ f.group.must_equal 'z2'
134
+ end
135
+
136
+ it 'retrieves the file gid' do
137
+ f.gid.must_equal 1002
92
138
  end
93
139
 
94
140
  it 'retrieves the file mtime' do
95
- cls.new(backend, 'path').mtime.must_equal 1444573475
141
+ f.mtime.must_equal 1444573475
96
142
  end
97
143
 
98
144
  it 'retrieves the file size' do
99
- cls.new(backend, 'path').size.must_equal 13
145
+ f.size.must_equal 13
100
146
  end
101
147
 
102
148
  it 'retrieves the file selinux_label' do
103
- cls.new(backend, 'path').selinux_label.must_equal 'labels'
149
+ f.selinux_label.must_equal 'labels'
104
150
  end
105
151
  end
106
152
  end
@@ -48,19 +48,21 @@ describe 'stat' do
48
48
  res = Minitest::Mock.new
49
49
  res.expect :stdout, ''
50
50
  backend.expect :run_command, res, [String]
51
- cls.linux_stat('/path', backend).must_equal({})
51
+ cls.linux_stat('/path', backend, false).must_equal({})
52
52
  end
53
53
 
54
54
  it 'reads correct stat results' do
55
55
  res = Minitest::Mock.new
56
56
  # 43ff is 41777; linux_stat strips the 4
57
- res.expect :stdout, "360\n43ff\nroot\n0\nroot\n0\n1444520846\n1444522445\n?"
57
+ res.expect :stdout, "360\n43ff\nroot\n0\nrootz\n1\n1444520846\n1444522445\n?"
58
58
  backend.expect :run_command, res, [String]
59
- cls.linux_stat('/path', backend).must_equal({
59
+ cls.linux_stat('/path', backend, false).must_equal({
60
60
  type: :directory,
61
61
  mode: 01777,
62
62
  owner: 'root',
63
- group: 'root',
63
+ uid: 0,
64
+ group: 'rootz',
65
+ gid: 1,
64
66
  mtime: 1444522445,
65
67
  size: 360,
66
68
  selinux_label: nil,
@@ -76,7 +78,7 @@ describe 'stat' do
76
78
  res.expect :stdout, '.....'
77
79
  res.expect :exit_status, 1
78
80
  backend.expect :run_command, res, [String]
79
- cls.bsd_stat('/path', backend).must_equal({})
81
+ cls.bsd_stat('/path', backend, false).must_equal({})
80
82
  end
81
83
 
82
84
  it 'ignores wrong stat results' do
@@ -84,19 +86,21 @@ describe 'stat' do
84
86
  res.expect :stdout, ''
85
87
  res.expect :exit_status, 0
86
88
  backend.expect :run_command, res, [String]
87
- cls.bsd_stat('/path', backend).must_equal({})
89
+ cls.bsd_stat('/path', backend, false).must_equal({})
88
90
  end
89
91
 
90
92
  it 'reads correct stat results' do
91
93
  res = Minitest::Mock.new
92
- res.expect :stdout, "360\n41777\nroot\n0\nroot\n0\n1444520846\n1444522445"
94
+ res.expect :stdout, "360\n41777\nroot\n0\nrootz\n1\n1444520846\n1444522445"
93
95
  res.expect :exit_status, 0
94
96
  backend.expect :run_command, res, [String]
95
- cls.bsd_stat('/path', backend).must_equal({
97
+ cls.bsd_stat('/path', backend, false).must_equal({
96
98
  type: :directory,
97
99
  mode: 01777,
98
100
  owner: 'root',
99
- group: 'root',
101
+ uid: 0,
102
+ group: 'rootz',
103
+ gid: 1,
100
104
  mtime: 1444522445,
101
105
  size: 360,
102
106
  selinux_label: nil,
@@ -12,15 +12,15 @@ describe 'file common' do
12
12
  }
13
13
 
14
14
  it 'provides the full path' do
15
- cls.new(backend, 'C:\dir\file').path.must_equal 'C:\dir\file'
15
+ cls.new(backend, 'C:\dir\file', false).path.must_equal 'C:\dir\file'
16
16
  end
17
17
 
18
18
  it 'provides the basename to a unix path' do
19
- cls.new(backend, 'C:\dir\file').basename.must_equal 'file'
19
+ cls.new(backend, 'C:\dir\file', false).basename.must_equal 'file'
20
20
  end
21
21
 
22
22
  it 'provides the full path with whitespace' do
23
- wf = cls.new(backend, 'C:\Program Files\file name')
23
+ wf = cls.new(backend, 'C:\Program Files\file name', false)
24
24
  wf.path.must_equal 'C:\Program Files\file name'
25
25
  wf.basename.must_equal 'file name'
26
26
  end
@@ -28,11 +28,11 @@ describe 'file common' do
28
28
  it 'reads file contents' do
29
29
  out = rand.to_s
30
30
  backend.mock_command('Get-Content("path") | Out-String', out)
31
- cls.new(backend, 'path').content.must_equal out
31
+ cls.new(backend, 'path', false).content.must_equal out
32
32
  end
33
33
 
34
34
  it 'check escaping of invalid chars in path' do
35
- wf = cls.new(nil, nil)
35
+ wf = cls.new(nil, nil, false)
36
36
  wf.sanitize_filename('c:/test') .must_equal 'c:/test'
37
37
  wf.sanitize_filename('c:/test directory') .must_equal 'c:/test directory'
38
38
  %w{ < > " * ?}.each do |char|
@@ -129,4 +129,28 @@ describe Train do
129
129
  res.must_equal nu
130
130
  end
131
131
  end
132
+
133
+ describe '#validate_backend' do
134
+ it 'just returns the backend if it is provided' do
135
+ x = rand
136
+ Train.validate_backend({ backend: x }).must_equal x
137
+ end
138
+
139
+ it 'returns the local backend if nothing was provided' do
140
+ Train.validate_backend({}).must_equal :local
141
+ end
142
+
143
+ it 'returns the default backend if nothing was provided' do
144
+ x = rand
145
+ Train.validate_backend({}, x).must_equal x
146
+ end
147
+
148
+ it 'fails if no backend was given but a target is provided' do
149
+ proc { Train.validate_backend({ target: rand }) }.must_raise Train::UserError
150
+ end
151
+
152
+ it 'fails if no backend was given but a host is provided' do
153
+ proc { Train.validate_backend({ host: rand }) }.must_raise Train::UserError
154
+ end
155
+ end
132
156
  end
@@ -42,7 +42,7 @@ describe 'local file transport' do
42
42
 
43
43
  it 'checks a file\'s link path' do
44
44
  out = rand.to_s
45
- File.stub :readlink, out do
45
+ File.stub :realpath, out do
46
46
  File.stub :symlink?, true do
47
47
  connection.file(rand.to_s).link_path.must_equal out
48
48
  end
@@ -51,7 +51,9 @@ describe 'local file transport' do
51
51
 
52
52
  describe 'file metadata' do
53
53
  let(:stat) { Struct.new(:mode, :size, :mtime, :uid, :gid) }
54
- let(:statres) { stat.new(00140755, rand, (rand*100).to_i, rand, rand) }
54
+ let(:uid) { rand }
55
+ let(:gid) { rand }
56
+ let(:statres) { stat.new(00140755, rand, (rand*100).to_i, uid, gid) }
55
57
 
56
58
  def meta_stub(method, param, &block)
57
59
  pwres = Struct.new(:name)
@@ -63,43 +65,55 @@ describe 'local file transport' do
63
65
  end
64
66
 
65
67
  it 'recognizes type' do
66
- meta_stub :lstat, statres do
68
+ meta_stub :stat, statres do
67
69
  connection.file(rand.to_s).type.must_equal :socket
68
70
  end
69
71
  end
70
72
 
71
73
  it 'recognizes mode' do
72
- meta_stub :lstat, statres do
74
+ meta_stub :stat, statres do
73
75
  connection.file(rand.to_s).mode.must_equal 00755
74
76
  end
75
77
  end
76
78
 
77
79
  it 'recognizes mtime' do
78
- meta_stub :lstat, statres do
80
+ meta_stub :stat, statres do
79
81
  connection.file(rand.to_s).mtime.must_equal statres.mtime
80
82
  end
81
83
  end
82
84
 
83
85
  it 'recognizes size' do
84
- meta_stub :lstat, statres do
86
+ meta_stub :stat, statres do
85
87
  connection.file(rand.to_s).size.must_equal statres.size
86
88
  end
87
89
  end
88
90
 
89
91
  it 'recognizes owner' do
90
- meta_stub :lstat, statres do
92
+ meta_stub :stat, statres do
91
93
  connection.file(rand.to_s).owner.must_equal 'owner'
92
94
  end
93
95
  end
94
96
 
97
+ it 'recognizes uid' do
98
+ meta_stub :stat, statres do
99
+ connection.file(rand.to_s).uid.must_equal uid
100
+ end
101
+ end
102
+
95
103
  it 'recognizes group' do
96
- meta_stub :lstat, statres do
104
+ meta_stub :stat, statres do
97
105
  connection.file(rand.to_s).group.must_equal 'group'
98
106
  end
99
107
  end
100
108
 
109
+ it 'recognizes gid' do
110
+ meta_stub :stat, statres do
111
+ connection.file(rand.to_s).gid.must_equal gid
112
+ end
113
+ end
114
+
101
115
  it 'recognizes selinux label' do
102
- meta_stub :lstat, statres do
116
+ meta_stub :stat, statres do
103
117
  label = rand.to_s
104
118
  res = Train::Extras::CommandResult.new(label, nil, 0)
105
119
  connection.stub :run_command, res do
@@ -107,6 +121,64 @@ describe 'local file transport' do
107
121
  end
108
122
  end
109
123
  end
124
+
125
+ it 'recognizes source type' do
126
+ meta_stub :lstat, statres do
127
+ connection.file(rand.to_s).source.type.must_equal :socket
128
+ end
129
+ end
130
+
131
+ it 'recognizes source mode' do
132
+ meta_stub :lstat, statres do
133
+ connection.file(rand.to_s).source.mode.must_equal 00755
134
+ end
135
+ end
136
+
137
+ it 'recognizes source mtime' do
138
+ meta_stub :lstat, statres do
139
+ connection.file(rand.to_s).source.mtime.must_equal statres.mtime
140
+ end
141
+ end
142
+
143
+ it 'recognizes source size' do
144
+ meta_stub :lstat, statres do
145
+ connection.file(rand.to_s).source.size.must_equal statres.size
146
+ end
147
+ end
148
+
149
+ it 'recognizes source owner' do
150
+ meta_stub :lstat, statres do
151
+ connection.file(rand.to_s).source.owner.must_equal 'owner'
152
+ end
153
+ end
154
+
155
+ it 'recognizes source uid' do
156
+ meta_stub :lstat, statres do
157
+ connection.file(rand.to_s).source.uid.must_equal uid
158
+ end
159
+ end
160
+
161
+ it 'recognizes source owner' do
162
+ meta_stub :lstat, statres do
163
+ connection.file(rand.to_s).source.owner.must_equal 'owner'
164
+ end
165
+ end
166
+
167
+ it 'recognizes source gid' do
168
+ meta_stub :lstat, statres do
169
+ connection.file(rand.to_s).source.gid.must_equal gid
170
+ end
171
+ end
172
+
173
+ it 'recognizes source selinux label' do
174
+ meta_stub :lstat, statres do
175
+ label = rand.to_s
176
+ res = Train::Extras::CommandResult.new(label, nil, 0)
177
+ connection.stub :run_command, res do
178
+ connection.file(rand.to_s).source.selinux_label.must_equal label
179
+ end
180
+ end
181
+ end
110
182
  end
111
183
 
112
184
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: r-train
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.8
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-25 00:00:00.000000000 Z
11
+ date: 2016-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -238,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
238
238
  version: '0'
239
239
  requirements: []
240
240
  rubyforge_project:
241
- rubygems_version: 2.4.6
241
+ rubygems_version: 2.5.1
242
242
  signing_key:
243
243
  specification_version: 4
244
244
  summary: Transport interface to talk to different backends.