dply 0.2.19 → 0.3.0

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 (96) hide show
  1. checksums.yaml +5 -5
  2. data/.rspec +4 -0
  3. data/Rakefile +0 -14
  4. data/TODO +0 -1
  5. data/code_dump/old_remote_task.rb +2 -0
  6. data/{dev_bin → dev_exe}/dplyr +0 -0
  7. data/{dev_bin → dev_exe}/drake +1 -1
  8. data/dply.gemspec +2 -2
  9. data/{bin → exe}/dplyr +0 -0
  10. data/{bin → exe}/drake +12 -14
  11. data/lib/dply/TEST_TODO +50 -0
  12. data/lib/dply/app_config.rb +108 -0
  13. data/lib/dply/base_config.rb +110 -0
  14. data/lib/dply/build.rb +17 -11
  15. data/lib/dply/build_config.rb +28 -96
  16. data/lib/dply/bundle.rb +7 -30
  17. data/lib/dply/cli/build.rb +5 -12
  18. data/lib/dply/cli/ctl.rb +7 -8
  19. data/lib/dply/cli/deploy.rb +6 -10
  20. data/lib/dply/cli/devbuild.rb +6 -10
  21. data/lib/dply/cli/install_pkgs.rb +2 -3
  22. data/lib/dply/cli/run.rb +27 -0
  23. data/lib/dply/cli/status.rb +1 -2
  24. data/lib/dply/cli/task.rb +6 -12
  25. data/lib/dply/code_archive.rb +123 -0
  26. data/lib/dply/command.rb +57 -0
  27. data/lib/dply/config_downloader.rb +3 -2
  28. data/lib/dply/curl.rb +1 -5
  29. data/lib/dply/custom_logger.rb +18 -1
  30. data/lib/dply/deplist.rb +16 -48
  31. data/lib/dply/deploy_config.rb +34 -0
  32. data/lib/dply/elf.rb +60 -0
  33. data/lib/dply/env.rb +9 -0
  34. data/lib/dply/git.rb +15 -8
  35. data/lib/dply/helper.rb +21 -33
  36. data/lib/dply/linker.rb +27 -27
  37. data/lib/dply/lock.rb +2 -9
  38. data/lib/dply/logger.rb +1 -1
  39. data/lib/dply/pkgs.rb +9 -11
  40. data/lib/dply/release.rb +2 -2
  41. data/lib/dply/{archive.rb → remote_archive.rb} +1 -1
  42. data/lib/dply/repo.rb +3 -3
  43. data/lib/dply/rpm.rb +12 -20
  44. data/lib/dply/scripts/depcheck.rb +4 -0
  45. data/lib/dply/shared_dirs.rb +1 -1
  46. data/lib/dply/strategy/archive.rb +15 -22
  47. data/lib/dply/strategy/base.rb +82 -0
  48. data/lib/dply/strategy/git.rb +18 -19
  49. data/lib/dply/task_dsl.rb +101 -0
  50. data/lib/dply/util.rb +75 -0
  51. data/lib/dply/venv.rb +53 -0
  52. data/lib/dply/version.rb +1 -1
  53. data/lib/dply/yum.rb +21 -31
  54. data/lib/dplyr/consul.rb +1 -1
  55. data/spec/dply/base_config_spec.rb +178 -0
  56. data/spec/dply/bundle_spec.rb +100 -0
  57. data/spec/dply/command_spec.rb +190 -0
  58. data/spec/dply/curl_spec.rb +41 -0
  59. data/spec/dply/deplist_spec.rb +48 -0
  60. data/spec/dply/elf_spec.rb +64 -0
  61. data/spec/dply/env_spec.rb +57 -0
  62. data/spec/dply/git_spec.rb +136 -0
  63. data/spec/dply/helper_spec.rb +168 -0
  64. data/spec/dply/linker_spec.rb +81 -0
  65. data/spec/dply/lock_spec.rb +24 -0
  66. data/spec/dply/pkgs_spec.rb +105 -0
  67. data/spec/dply/repo_spec.rb +58 -0
  68. data/spec/dply/rpm_spec.rb +32 -0
  69. data/spec/dply/yum_spec.rb +29 -0
  70. data/spec/integration/archive_flow_spec.rb +87 -0
  71. data/spec/integration/git_flow_spec.rb +63 -0
  72. data/spec/repo.rb +27 -0
  73. data/spec/spec_helper.rb +44 -0
  74. data/spec/test_data/build.tar.gz +0 -0
  75. data/spec/test_data/build.tar.gz.md5 +1 -0
  76. data/spec/test_data/bundle/gems_installed/Gemfile +1 -0
  77. data/spec/test_data/bundle/gems_not_installed/Gemfile +2 -0
  78. data/spec/test_data/bundle/no_gemfile/.gitkeep +0 -0
  79. data/spec/test_data/command/test.rb +7 -0
  80. data/spec/test_data/elf/elf +0 -0
  81. data/spec/test_data/elf/libpgtypes.so.3 +0 -0
  82. data/spec/test_data/elf/not_elf +1 -0
  83. data/spec/test_data/sample_repo/.dply.lock +0 -0
  84. data/spec/test_data/sample_repo/Gemfile +2 -0
  85. data/spec/test_data/sample_repo/Rakefile +3 -0
  86. data/spec/test_data/sample_repo/app.rb +1 -0
  87. data/spec/test_data/sample_repo/dply/app.rb +33 -0
  88. data/spec/test_data/sample_repo/lib/libacl.so.1 +0 -0
  89. data/spec/test_data/sample_repo/pkgs.yml +2 -0
  90. data/spec/webserver.rb +21 -0
  91. metadata +96 -28
  92. data/lib/dply/cli/app_task.rb +0 -38
  93. data/lib/dply/config.rb +0 -120
  94. data/lib/dply/config_struct.rb +0 -52
  95. data/lib/dply/rakelib/drake.rake +0 -33
  96. data/lib/dply/tasks.rb +0 -136
@@ -0,0 +1,123 @@
1
+ require 'fileutils'
2
+ require_relative 'helper'
3
+
4
+ module Dply
5
+ class CodeArchive
6
+
7
+ include Helper
8
+
9
+ attr_reader :name, :branch
10
+ attr_writer :skip_depcheck
11
+
12
+ def initialize(name, revision:)
13
+ @name = name
14
+ @branch = get_branch
15
+ @revision = revision
16
+ @dir = "tmp/build_artifacts"
17
+ validate
18
+ end
19
+
20
+ def build(git: true, gnu_tar: false, &block)
21
+ make_dir
22
+ create_tar git, gnu_tar
23
+ instance_eval &block if block
24
+ add_git_commit_id
25
+ add_revision
26
+ add_archive_name
27
+ depcheck
28
+ compress
29
+ end
30
+
31
+ private
32
+
33
+ def get_branch
34
+ out = cmd "git rev-parse --abbrev-ref HEAD", return_output: true
35
+ out.chomp.tr("/", "_")
36
+ end
37
+
38
+ def tar
39
+ @tar ||= "#{@dir}/#{@name}-#{@revision}-#{@branch}.tar"
40
+ end
41
+
42
+ def make_dir
43
+ FileUtils.mkdir @dir if not File.directory? @dir
44
+ end
45
+
46
+ def create_tar(git, gnu_tar)
47
+ tmp_dir = "tmp/app_code"
48
+ if git
49
+ if gnu_tar
50
+ FileUtils.rm_rf tmp_dir if File.exists? tmp_dir
51
+ FileUtils.mkdir tmp_dir
52
+ sh "git archive HEAD | tar xf - -C #{tmp_dir}"
53
+ cmd "tar cf #{tar} -C #{tmp_dir} ."
54
+ else
55
+ cmd "git archive -o #{tar} HEAD"
56
+ end
57
+ else
58
+ cmd "tar -cf #{tar} -T /dev/null"
59
+ end
60
+ ensure
61
+ FileUtils.rm_rf tmp_dir if File.exists? tmp_dir
62
+ end
63
+
64
+ def add(file, chdir: nil)
65
+ if chdir
66
+ cmd %(tar -h -C #{chdir} --append -f "#{tar}" "#{file}")
67
+ else
68
+ cmd %(tar -h --append -f "#{tar}" "#{file}")
69
+ end
70
+ end
71
+
72
+ def remove(file)
73
+ cmd %(tar --delete -f "#{tar}" "#{file}")
74
+ end
75
+
76
+ def add_git_commit_id
77
+ commit_id = `git rev-parse HEAD`.chomp!
78
+ file = "GIT_COMMIT_ID"
79
+ File.write(file, commit_id)
80
+ add file
81
+ end
82
+
83
+ def add_revision
84
+ file = "REVISION"
85
+ File.write(file, @revision)
86
+ add file
87
+ end
88
+
89
+ def add_archive_name
90
+ file = "ARCHIVE_NAME"
91
+ File.write(file, @name)
92
+ add file
93
+ end
94
+
95
+ def add_bundle
96
+ add ".bundle"
97
+ add "vendor/bundle"
98
+ end
99
+
100
+ def depcheck
101
+ return if @skip_depcheck
102
+ command = %(ruby -W0 "#{__dir__}/scripts/depcheck.rb" #{tar})
103
+ logger.bullet "depcheck #{tar}"
104
+ cmd command, display: false
105
+ end
106
+
107
+ def compress
108
+ cmd %(#{gzip} -f -9 "#{tar}")
109
+ end
110
+
111
+ def gzip
112
+ File.exists?("/usr/bin/pigz") ? "pigz" : "gzip"
113
+ end
114
+
115
+ def validate
116
+ [:name, :branch, :revision, :dir].each do |i|
117
+ ivar = "@#{i}"
118
+ v = instance_variable_get(ivar)
119
+ raise Error, "archive param :#{i} is empty" if (!v || v.strip.empty?)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,57 @@
1
+ require_relative 'error'
2
+ require 'shellwords'
3
+
4
+ module Dply
5
+ class Command
6
+
7
+ def initialize(command, env: {}, shell: false)
8
+ @command = command
9
+ @env = env
10
+ @shell = shell
11
+ validate!
12
+ end
13
+
14
+ def run
15
+ assert_success { system(@env, *command, unsetenv_others: true, 2 => 1) }
16
+ end
17
+
18
+ def capture
19
+ assert_success { IO.popen(@env, command, unsetenv_others: true) { |f| f.read } }
20
+ end
21
+
22
+ private
23
+
24
+ def assert_success(&block)
25
+ ret = yield
26
+ exitstatus = $?.exitstatus
27
+ if exitstatus != 0
28
+ raise Error, "non zero exit for \"#{command_str}\""
29
+ end
30
+ ret
31
+ end
32
+
33
+ def command
34
+ @shell ? command_str : command_arr
35
+ end
36
+
37
+ def command_arr
38
+ @command_arr ||= begin
39
+ command_arr = @command.is_a?(Array) ? @command : @command.shellsplit
40
+ raise Error, "empty command \"#{@command}\"" if command_arr.empty?
41
+ command_arr[0] = command_arr[0].shellescape if command_arr.size == 1
42
+ command_arr
43
+ end
44
+ end
45
+
46
+ def command_str
47
+ @command_str ||= @command.is_a?(String) ? @command : @command.join(" ")
48
+ end
49
+
50
+ def validate!
51
+ if @shell && @command.is_a?(Array)
52
+ raise Error, "command cannot be an array when shell: true"
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -8,9 +8,10 @@ module Dply
8
8
  include Helper
9
9
  attr_writer :skip_download
10
10
 
11
- def initialize(config_files , base_url)
11
+ def initialize(config_files , base_url, dir: "config")
12
12
  @config_files = config_files
13
13
  @base_url = base_url
14
+ @dir = dir
14
15
  @skip_download = []
15
16
  end
16
17
 
@@ -20,7 +21,7 @@ module Dply
20
21
  logger.debug "skipping to download file #{f}"
21
22
  next
22
23
  end
23
- curl.download "#{@base_url}/#{f}", "config/#{f}"
24
+ curl.download "#{@base_url}/#{f}", "#{@dir}/#{f}"
24
25
  end
25
26
  end
26
27
 
@@ -27,11 +27,7 @@ module Dply
27
27
  private
28
28
 
29
29
  def log(msg)
30
- if @quiet
31
- logger.debug msg
32
- else
33
- logger.bullet msg
34
- end
30
+ @quiet ? logger.debug(msg) : logger.bullet(msg)
35
31
  end
36
32
 
37
33
  end
@@ -1,5 +1,6 @@
1
1
  require 'logger'
2
- require 'dply/ext/string'
2
+ require_relative 'ext/string'
3
+
3
4
  module Dply
4
5
  class CustomLogger < ::Logger
5
6
 
@@ -8,6 +9,7 @@ module Dply
8
9
  def initialize(file)
9
10
  super(file)
10
11
  @level = ::Logger::INFO
12
+ # @trace_mode = false
11
13
  end
12
14
 
13
15
  def format_message(severity, timestamp, progname, msg)
@@ -23,6 +25,21 @@ module Dply
23
25
  end
24
26
  end
25
27
 
28
+ def command(command, mode:)
29
+ case mode
30
+ when :arrow
31
+ arrow command
32
+ when :bullet
33
+ bullet command
34
+ else
35
+ debug command
36
+ end
37
+ end
38
+
39
+ def arrow(msg)
40
+ info "#{"\u2023".green.bold} #{msg}"
41
+ end
42
+
26
43
  def bullet(msg)
27
44
  info "#{"\u2219".bold.blue} #{msg}"
28
45
  end
@@ -1,29 +1,27 @@
1
- require 'filemagic'
2
- require 'elf'
3
- require 'dply/helper'
4
- require 'dply/rpm'
5
- require 'dply/pkgs'
6
1
  require 'tmpdir'
2
+ require 'set'
3
+ require_relative 'helper'
4
+ require_relative 'rpm'
5
+ require_relative 'pkgs'
6
+ require_relative 'elf'
7
7
 
8
8
  module Dply
9
9
  class Deplist
10
10
 
11
11
  include Helper
12
12
 
13
- def initialize(path)
14
- if Pathname.new(path).relative?
15
- @path = "#{Dir.pwd}/#{path}"
16
- else
17
- @path = path
18
- end
13
+ BASE_PACKAGES = Set["glibc", "libgcc", "libstdc++", "openssl", "ruby-alt", "jemalloc"]
14
+
15
+ def initialize(tar_path)
16
+ @tar_path = Pathname.new(tar_path).realpath
19
17
  end
20
18
 
21
19
  def verify!
22
- error "#{@path} not readable" if not File.readable? @path
20
+ error "#{@tar_path} not readable" if not File.readable? @tar_path
23
21
  tmp_dir do
24
22
  logger.info "(in #{Dir.pwd})"
25
- cmd "tar xf #{@path}"
26
- pkgs_list = Pkgs.new.runtime
23
+ cmd "tar xf #{@tar_path}"
24
+ pkgs_list = Pkgs.new("pkgs.yml").runtime
27
25
 
28
26
  @libs_files_map = libs_files_map
29
27
  libs = @libs_files_map.keys
@@ -33,7 +31,7 @@ module Dply
33
31
  pp @libs_files_map
34
32
  end
35
33
 
36
- deps = rpm.libs_packages_map libs
34
+ deps = Rpm.libs_pkgs_map libs
37
35
  verify_deps(deps, pkgs_list)
38
36
  end
39
37
  end
@@ -42,6 +40,7 @@ module Dply
42
40
 
43
41
  def verify_deps(deps, pkgs_list)
44
42
  deps.each do |lib, pkgs|
43
+ next if pkgs.find { |pkg| BASE_PACKAGES.include? pkg }
45
44
  if not pkgs.any? { |pkg| pkgs_list.include? pkg }
46
45
  logger.error "missing from pkgs.yml : any of #{pkgs} (lib: #{lib}, files: #{@libs_files_map[lib]})"
47
46
  @error = true
@@ -51,17 +50,6 @@ module Dply
51
50
  puts "all dependencies satisfied".green
52
51
  end
53
52
 
54
- def magic
55
- @magic ||= begin
56
- flags = FileMagic::FLAGS_BY_SYM.select { |k,v| k.to_s =~ /no_check_/ }.keys
57
- not_required_flags = [:no_check_soft, :no_check_elf, :no_check_builtin]
58
- not_required_flags.each {|x| flags.delete(x) }
59
- fm = FileMagic.new
60
- fm.flags = flags
61
- fm
62
- end
63
- end
64
-
65
53
  def tmp_dir(&block)
66
54
  dir = File.exist?("tmp") ? "tmp" : "/tmp"
67
55
  Dir.mktmpdir(nil, dir) do |d|
@@ -72,8 +60,7 @@ module Dply
72
60
  def libs_files_map
73
61
  libs = {}
74
62
  Dir["./**/*"].each do |f|
75
- type = magic.file(f)
76
- next if not type =~ /ELF/
63
+ next if not Elf.elf? f
77
64
  dynamic_libs(f).each do |l|
78
65
  libs[l] ||= []
79
66
  libs[l] << f
@@ -83,26 +70,7 @@ module Dply
83
70
  end
84
71
 
85
72
  def dynamic_libs(file)
86
- path = Pathname.new(file)
87
- Elf::File.open(file) do |ef|
88
- return [] if not ef.has_section? ".dynamic"
89
- lib_type = ef.elf_class.desc == "64-bit" ? "()(64bit)" : ""
90
- dynamic = ef[".dynamic"].needed_libraries.keys
91
- rpath = ef[".dynamic"].rpath.map { |i| i.sub("$ORIGIN", "#{path.dirname}") }
92
- external = dynamic.reject { |l| lib_in_rpath? l, rpath }.map { |l| "#{l}#{lib_type}" }
93
- logger.debug { "[#{file}]: dynamic:#{dynamic.size} rpath:#{dynamic.size - external.size} ext:#{external.size}" } if logger.debug?
94
- external
95
- end
96
- rescue Exception
97
- return []
98
- end
99
-
100
- def lib_in_rpath?(lib, rpath)
101
- rpath.any? { |i| File.exist? "#{i}/#{lib}" }
102
- end
103
-
104
- def rpm
105
- @rpm ||= Rpm.new
73
+ Elf.new(file).external_libs
106
74
  end
107
75
 
108
76
  end
@@ -0,0 +1,34 @@
1
+ require 'dply/base_config'
2
+
3
+ module Dply
4
+ class DeployConfig < BaseConfig
5
+ define_opts do
6
+ opt :name
7
+ opt :repo
8
+ opt :mirror
9
+ opt :branch
10
+ opt :strategy, type: Symbol
11
+ opt :target
12
+ opt :build_url
13
+ opt :shared_dirs, type: Array
14
+ opt :config_map, type: Hash
15
+ opt :dir_map, type: Hash
16
+ opt :config_download_url
17
+ opt :config_skip_download, type: Array
18
+ opt :verify_checksum
19
+ opt :revision
20
+ opt :dir
21
+ end
22
+
23
+ def default_config
24
+ dir Dir.pwd
25
+ branch "master"
26
+ shared_dirs []
27
+ dir_map({
28
+ "tmp" => "tmp",
29
+ "log" => "log"
30
+ })
31
+ verify_checksum true
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,60 @@
1
+ require 'elf'
2
+ require_relative 'helper'
3
+
4
+ module Dply
5
+ class Elf
6
+
7
+ include Helper
8
+
9
+ MAGIC_STRING = "\177ELF"
10
+
11
+ def self.elf?(path)
12
+ return false if not File.file? path
13
+ IO.binread(path, 4) == MAGIC_STRING
14
+ end
15
+
16
+ attr_reader :path
17
+
18
+ def initialize(path)
19
+ @path = Pathname.new(path)
20
+ @elf = ::Elf::File.new(path)
21
+ end
22
+
23
+ def external_libs
24
+ return [] if not @elf.has_section? ".dynamic"
25
+ dynamic = dynamic_libs()
26
+ external = dynamic.reject { |i| lib_in_relative_rpath? i }.map { |l| "#{l}#{lib_type}" }
27
+ logger.debug { "[#{@path}]: dynamic:#{dynamic.size} rpath:#{dynamic.size - external.size} ext:#{external.size}" } if logger.debug?
28
+ external
29
+ end
30
+
31
+ private
32
+
33
+ def dynamic_libs
34
+ @elf[".dynamic"].needed_libraries.keys
35
+ end
36
+
37
+ def lib_type
38
+ @lib_type ||= @elf.elf_class.desc == "64-bit" ? "()(64bit)" : ""
39
+ end
40
+
41
+ def relative_rpath
42
+ @relative_rpath ||= begin
43
+ # include both rpath and runpaths
44
+ rpaths = @elf[".dynamic"].rpath + @elf[".dynamic"].runpath
45
+ # expand $ORIGIN
46
+ rpaths = rpaths.map { |i| i.sub("$ORIGIN", "#{@path.dirname}") }
47
+ # convert all paths to realpath
48
+ rpaths = rpaths.map { |i| Pathname.new(i).realpath }
49
+ # select paths which start with cwd or are subpaths to cwd
50
+ cwd = Dir.pwd
51
+ rpaths.select { |i| i.to_s.start_with? cwd }
52
+ end
53
+ end
54
+
55
+ def lib_in_relative_rpath?(lib)
56
+ relative_rpath.any? { |i| File.exist? "#{i}/#{lib}" }
57
+ end
58
+
59
+ end
60
+ end