dply 0.2.19 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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