train-core 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +780 -0
  3. data/Gemfile +36 -0
  4. data/LICENSE +201 -0
  5. data/README.md +197 -0
  6. data/lib/train.rb +158 -0
  7. data/lib/train/errors.rb +32 -0
  8. data/lib/train/extras.rb +11 -0
  9. data/lib/train/extras/command_wrapper.rb +137 -0
  10. data/lib/train/extras/stat.rb +132 -0
  11. data/lib/train/file.rb +151 -0
  12. data/lib/train/file/local.rb +75 -0
  13. data/lib/train/file/local/unix.rb +96 -0
  14. data/lib/train/file/local/windows.rb +63 -0
  15. data/lib/train/file/remote.rb +36 -0
  16. data/lib/train/file/remote/aix.rb +21 -0
  17. data/lib/train/file/remote/linux.rb +19 -0
  18. data/lib/train/file/remote/qnx.rb +41 -0
  19. data/lib/train/file/remote/unix.rb +106 -0
  20. data/lib/train/file/remote/windows.rb +94 -0
  21. data/lib/train/options.rb +80 -0
  22. data/lib/train/platforms.rb +84 -0
  23. data/lib/train/platforms/common.rb +34 -0
  24. data/lib/train/platforms/detect.rb +12 -0
  25. data/lib/train/platforms/detect/helpers/os_common.rb +145 -0
  26. data/lib/train/platforms/detect/helpers/os_linux.rb +75 -0
  27. data/lib/train/platforms/detect/helpers/os_windows.rb +120 -0
  28. data/lib/train/platforms/detect/scanner.rb +84 -0
  29. data/lib/train/platforms/detect/specifications/api.rb +15 -0
  30. data/lib/train/platforms/detect/specifications/os.rb +578 -0
  31. data/lib/train/platforms/detect/uuid.rb +34 -0
  32. data/lib/train/platforms/family.rb +26 -0
  33. data/lib/train/platforms/platform.rb +101 -0
  34. data/lib/train/plugins.rb +40 -0
  35. data/lib/train/plugins/base_connection.rb +169 -0
  36. data/lib/train/plugins/transport.rb +49 -0
  37. data/lib/train/transports/local.rb +232 -0
  38. data/lib/train/version.rb +7 -0
  39. data/train-core.gemspec +27 -0
  40. metadata +116 -0
@@ -0,0 +1,75 @@
1
+ # encoding: utf-8
2
+
3
+ module Train
4
+ class File
5
+ class Local < Train::File
6
+ %w{
7
+ exist? file? socket? directory? symlink? pipe? size basename
8
+ }.each do |m|
9
+ define_method m.to_sym do
10
+ ::File.method(m.to_sym).call(@path)
11
+ end
12
+ end
13
+
14
+ def content
15
+ @content ||= ::File.read(@path, encoding: 'UTF-8')
16
+ rescue StandardError => _
17
+ nil
18
+ end
19
+
20
+ def link_path
21
+ return nil unless symlink?
22
+ begin
23
+ @link_path ||= ::File.realpath(@path)
24
+ rescue Errno::ELOOP => _
25
+ # Leave it blank on symbolic loop, same as readlink
26
+ @link_path = ''
27
+ end
28
+ end
29
+
30
+ def block_device?
31
+ ::File.blockdev?(@path)
32
+ end
33
+
34
+ def character_device?
35
+ ::File.chardev?(@path)
36
+ end
37
+
38
+ def type
39
+ case ::File.ftype(@path)
40
+ when 'blockSpecial'
41
+ :block_device
42
+ when 'characterSpecial'
43
+ :character_device
44
+ when 'link'
45
+ :symlink
46
+ when 'fifo'
47
+ :pipe
48
+ else
49
+ ::File.ftype(@path).to_sym
50
+ end
51
+ end
52
+
53
+ %w{
54
+ mode owner group uid gid mtime selinux_label
55
+ }.each do |field|
56
+ define_method field.to_sym do
57
+ stat[field.to_sym]
58
+ end
59
+ end
60
+
61
+ def mode?(sth)
62
+ mode == sth
63
+ end
64
+
65
+ def linked_to?(dst)
66
+ link_path == dst
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ # subclass requires are loaded after Train::File::Local is defined
73
+ # to avoid superclass mismatch errors
74
+ require 'train/file/local/unix'
75
+ require 'train/file/local/windows'
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+
3
+ require 'shellwords'
4
+ require 'train/extras/stat'
5
+
6
+ module Train
7
+ class File
8
+ class Local
9
+ class Unix < Train::File::Local
10
+ def sanitize_filename(path)
11
+ @spath = Shellwords.escape(path) || @path
12
+ end
13
+
14
+ def stat
15
+ return @stat if defined?(@stat)
16
+
17
+ begin
18
+ file_stat =
19
+ if @follow_symlink
20
+ ::File.stat(@path)
21
+ else
22
+ ::File.lstat(@path)
23
+ end
24
+ rescue StandardError => _err
25
+ return @stat = {}
26
+ end
27
+
28
+ @stat = {
29
+ type: Train::Extras::Stat.find_type(file_stat.mode),
30
+ mode: file_stat.mode & 07777,
31
+ mtime: file_stat.mtime.to_i,
32
+ size: file_stat.size,
33
+ owner: pw_username(file_stat.uid),
34
+ uid: file_stat.uid,
35
+ group: pw_groupname(file_stat.gid),
36
+ gid: file_stat.gid,
37
+ }
38
+
39
+ lstat = @follow_symlink ? ' -L' : ''
40
+ res = @backend.run_command("stat#{lstat} #{@spath} 2>/dev/null --printf '%C'")
41
+ if res.exit_status == 0 && !res.stdout.empty? && res.stdout != '?'
42
+ @stat[:selinux_label] = res.stdout.strip
43
+ end
44
+
45
+ @stat
46
+ end
47
+
48
+ def mounted
49
+ @mounted ||=
50
+ @backend.run_command("mount | grep -- ' on #{@spath} '")
51
+ end
52
+
53
+ def grouped_into?(sth)
54
+ group == sth
55
+ end
56
+
57
+ def unix_mode_mask(owner, type)
58
+ o = UNIX_MODE_OWNERS[owner.to_sym]
59
+ return nil if o.nil?
60
+
61
+ t = UNIX_MODE_TYPES[type.to_sym]
62
+ return nil if t.nil?
63
+
64
+ t & o
65
+ end
66
+
67
+ private
68
+
69
+ def pw_username(uid)
70
+ Etc.getpwuid(uid).name
71
+ rescue ArgumentError => _
72
+ nil
73
+ end
74
+
75
+ def pw_groupname(gid)
76
+ Etc.getgrgid(gid).name
77
+ rescue ArgumentError => _
78
+ nil
79
+ end
80
+
81
+ UNIX_MODE_OWNERS = {
82
+ all: 00777,
83
+ owner: 00700,
84
+ group: 00070,
85
+ other: 00007,
86
+ }.freeze
87
+
88
+ UNIX_MODE_TYPES = {
89
+ r: 00444,
90
+ w: 00222,
91
+ x: 00111,
92
+ }.freeze
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+
3
+ module Train
4
+ class File
5
+ class Local
6
+ class Windows < Train::File::Local
7
+ # Ensures we do not use invalid characters for file names
8
+ # @see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions
9
+ def sanitize_filename(path)
10
+ return if path.nil?
11
+ # we do not filter :, backslash and forward slash, since they are part of the path
12
+ @spath = path.gsub(/[<>"|?*]/, '')
13
+ end
14
+
15
+ def product_version
16
+ @product_version ||= @backend.run_command(
17
+ "[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"#{@spath}\").ProductVersion").stdout.chomp
18
+ end
19
+
20
+ def file_version
21
+ @file_version ||= @backend.run_command(
22
+ "[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"#{@spath}\").FileVersion").stdout.chomp
23
+ end
24
+
25
+ def owner
26
+ owner = @backend.run_command(
27
+ "Get-Acl \"#{@spath}\" | select -expand Owner").stdout.strip
28
+ return if owner.empty?
29
+ owner
30
+ end
31
+
32
+ def stat
33
+ return @stat if defined?(@stat)
34
+
35
+ begin
36
+ file_stat =
37
+ if @follow_symlink
38
+ ::File.stat(@path)
39
+ else
40
+ ::File.lstat(@path)
41
+ end
42
+ rescue StandardError => _err
43
+ return @stat = {}
44
+ end
45
+
46
+ @stat = {
47
+ type: type,
48
+ mode: file_stat.mode,
49
+ mtime: file_stat.mtime.to_i,
50
+ size: file_stat.size,
51
+ owner: owner,
52
+ uid: file_stat.uid,
53
+ group: nil,
54
+ gid: file_stat.gid,
55
+ selinux_label: nil,
56
+ }
57
+
58
+ @stat
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ module Train
4
+ class File
5
+ class Remote < Train::File
6
+ def basename(suffix = nil, sep = '/')
7
+ fail 'Not yet supported: Suffix in file.basename' unless suffix.nil?
8
+ @basename ||= detect_filename(path, sep || '/')
9
+ end
10
+
11
+ def stat
12
+ return @stat if defined?(@stat)
13
+ @stat = Train::Extras::Stat.stat(@spath, @backend, @follow_symlink)
14
+ end
15
+
16
+ # helper methods provided to any implementing class
17
+ private
18
+
19
+ def detect_filename(path, sep)
20
+ idx = path.rindex(sep)
21
+ return path if idx.nil?
22
+ idx += 1
23
+ return detect_filename(path[0..-2], sep) if idx == path.length
24
+ path[idx..-1]
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ # subclass requires are loaded after Train::File::Remote is defined
31
+ # to avoid superclass mismatch errors
32
+ require 'train/file/remote/aix'
33
+ require 'train/file/remote/linux'
34
+ require 'train/file/remote/qnx'
35
+ require 'train/file/remote/unix'
36
+ require 'train/file/remote/windows'
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require 'train/file/remote/unix'
4
+
5
+ module Train
6
+ class File
7
+ class Remote
8
+ class Aix < Train::File::Remote::Unix
9
+ def link_path
10
+ return nil unless symlink?
11
+ @link_path ||=
12
+ @backend.run_command("perl -e 'print readlink shift' #{@spath}").stdout.chomp
13
+ end
14
+
15
+ def mounted
16
+ @mounted ||= @backend.run_command("lsfs -c #{@spath}")
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ require 'train/file/remote/unix'
4
+
5
+ module Train
6
+ class File
7
+ class Remote
8
+ class Linux < Train::File::Remote::Unix
9
+ def content
10
+ return @content if defined?(@content)
11
+ @content = @backend.run_command("cat #{@spath} || echo -n").stdout
12
+ return @content unless @content.empty?
13
+ @content = nil if directory? or size.nil? or size > 0
14
+ @content
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ #
3
+ # author: Christoph Hartmann
4
+ # author: Dominik Richter
5
+
6
+ require 'train/file/remote/unix'
7
+
8
+ module Train
9
+ class File
10
+ class Remote
11
+ class Qnx < Train::File::Remote::Unix
12
+ def content
13
+ cat = 'cat'
14
+ cat = '/proc/boot/cat' if @backend.os[:release].to_i >= 7
15
+ @content ||= case
16
+ when !exist?
17
+ nil
18
+ else
19
+ @backend.run_command("#{cat} #{@spath}").stdout || ''
20
+ end
21
+ end
22
+
23
+ def type
24
+ if @backend.run_command("file #{@spath}").stdout.include?('directory')
25
+ return :directory
26
+ else
27
+ return :file
28
+ end
29
+ end
30
+
31
+ %w{
32
+ mode owner group uid gid mtime size selinux_label link_path mounted stat
33
+ }.each do |field|
34
+ define_method field.to_sym do
35
+ fail NotImplementedError, "QNX does not implement the #{field}() method yet."
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,106 @@
1
+ # encoding: utf-8
2
+
3
+ require 'shellwords'
4
+
5
+ module Train
6
+ class File
7
+ class Remote
8
+ class Unix < Train::File::Remote
9
+ attr_reader :path
10
+
11
+ def sanitize_filename(path)
12
+ @spath = Shellwords.escape(path) || @path
13
+ end
14
+
15
+ def content
16
+ @content ||=
17
+ if !exist? || directory?
18
+ nil
19
+ elsif size.nil? || size.zero?
20
+ ''
21
+ else
22
+ @backend.run_command("cat #{@spath}").stdout || ''
23
+ end
24
+ end
25
+
26
+ def exist?
27
+ @exist ||= (
28
+ f = @follow_symlink ? '' : " || test -L #{@spath}"
29
+ @backend.run_command("test -e #{@spath}"+f)
30
+ .exit_status == 0
31
+ )
32
+ end
33
+
34
+ def mounted
35
+ @mounted ||=
36
+ @backend.run_command("mount | grep -- ' on #{@spath} '")
37
+ end
38
+
39
+ %w{
40
+ type mode owner group uid gid mtime size selinux_label
41
+ }.each do |field|
42
+ define_method field.to_sym do
43
+ stat[field.to_sym]
44
+ end
45
+ end
46
+
47
+ def mode?(sth)
48
+ mode == sth
49
+ end
50
+
51
+ def grouped_into?(sth)
52
+ group == sth
53
+ end
54
+
55
+ def linked_to?(dst)
56
+ link_path == dst
57
+ end
58
+
59
+ def link_path
60
+ symlink? ? path : nil
61
+ end
62
+
63
+ def unix_mode_mask(owner, type)
64
+ o = UNIX_MODE_OWNERS[owner.to_sym]
65
+ return nil if o.nil?
66
+
67
+ t = UNIX_MODE_TYPES[type.to_sym]
68
+ return nil if t.nil?
69
+
70
+ t & o
71
+ end
72
+
73
+ def path
74
+ return @path unless @follow_symlink && symlink?
75
+ @link_path ||= read_target_path
76
+ end
77
+
78
+ private
79
+
80
+ # Returns full path of a symlink target(real dest) or '' on symlink loop
81
+ def read_target_path
82
+ full_path = @backend.run_command("readlink -n #{@spath} -f").stdout
83
+ # Needed for some OSes like OSX that returns relative path
84
+ # when the link and target are in the same directory
85
+ if !full_path.start_with?('/') && full_path != ''
86
+ full_path = ::File.expand_path("../#{full_path}", @spath)
87
+ end
88
+ full_path
89
+ end
90
+
91
+ UNIX_MODE_OWNERS = {
92
+ all: 00777,
93
+ owner: 00700,
94
+ group: 00070,
95
+ other: 00007,
96
+ }.freeze
97
+
98
+ UNIX_MODE_TYPES = {
99
+ r: 00444,
100
+ w: 00222,
101
+ x: 00111,
102
+ }.freeze
103
+ end
104
+ end
105
+ end
106
+ end