Class: ChkBuild::Build
- Inherits:
-
Object
- Object
- ChkBuild::Build
- Includes:
- Util
- Defined in:
- lib/chkbuild/build.rb,
lib/chkbuild/scm/cvs.rb,
lib/chkbuild/scm/git.rb,
lib/chkbuild/scm/svn.rb,
lib/chkbuild/scm/xforge.rb
Defined Under Namespace
Classes: CommandError, GitHub
Constant Summary collapse
- RECENT_HTMLTemplate =
<<'End' <html> <head> <title><%= h title %></title> <meta name="author" content="chkbuild"> <meta name="generator" content="chkbuild"> </head> <body> <h1><%= h title %></h1> <p> <a href="../">chkbuild</a> <a href="summary.html">summary</a> <a href="recent.html">recent</a> <a href="last.html.gz">last</a> </p> <%= recent_summary.chomp %> <hr> <p> <a href="../">chkbuild</a> <a href="summary.html">summary</a> <a href="recent.html">recent</a> <a href="last.html.gz">last</a> </p> </body> </html> End
- LAST_HTMLTemplate =
<<'End' <html> <head> <title><%= h title %></title> <meta name="author" content="chkbuild"> <meta name="generator" content="chkbuild"> </head> <body> <h1><%= h title %></h1> <p> <a href="../">chkbuild</a> <a href="summary.html">summary</a> <a href="recent.html">recent</a> <a href="<%=h permalink %>">permalink</a> % if has_diff <a href="<%=h diff_permalink %>">diff</a> % end </p> <pre><%= markup log %></pre> <hr> <p> <a href="../">chkbuild</a> <a href="summary.html">summary</a> <a href="recent.html">recent</a> <a href="<%=h permalink %>">permalink</a> % if has_diff <a href="<%=h diff_permalink %>">diff</a> % end </p> </body> </html> End
- SignalNum2Name =
Hash.new('unknown signal')
Instance Attribute Summary collapse
-
#depbuilds ⇒ Object
readonly
Returns the value of attribute depbuilds.
-
#logfile ⇒ Object
readonly
Returns the value of attribute logfile.
-
#suffixes ⇒ Object
readonly
Returns the value of attribute suffixes.
-
#target ⇒ Object
readonly
Returns the value of attribute target.
-
#target_dir ⇒ Object
readonly
Returns the value of attribute target_dir.
Instance Method Summary collapse
- #build ⇒ Object
- #build_dir ⇒ Object
- #build_in_child(dep_dirs) ⇒ Object
- #build_time_sequence ⇒ Object
- #catch_error(name = nil) ⇒ Object
- #child_build_target(*branch_info) ⇒ Object
- #child_build_wrapper(parent_pipe, *branch_info) ⇒ Object
- #compress_file(src, dst) ⇒ Object
- #cvs(cvsroot, mod, branch, opts = {}) ⇒ Object
- #cvs_internal(cvsroot, mod, branch, opts = {}) ⇒ Object
- #cvs_print_changes(h1, h2, viewcvs = nil) ⇒ Object
- #cvs_print_revisions(h1, h2, viewcvs = nil) ⇒ Object
- #cvs_revisions ⇒ Object
- #cvs_uri(viewcvs, repository, filename, r1, r2) ⇒ Object
- #depsuffixed_name ⇒ Object
- #different_sections(tmp1, tmp2) ⇒ Object
- #dir ⇒ Object
- #git(cloneurl, working_dir, opts = {}) ⇒ Object
- #git_head_commit ⇒ Object
- #git_internal(cloneurl, working_dir, opts = {}) ⇒ Object
- #git_logfile(opts) ⇒ Object
- #git_oneline_logs(old_head = nil) ⇒ Object
- #git_parse_status(f) ⇒ Object
- #git_path_sort(ary) ⇒ Object
- #git_print_logs(old_head, logs, urigen = nil) ⇒ Object
- #git_revisions ⇒ Object
- #git_with_file(basename) {|name| ... } ⇒ Object
- #github(user, project, working_dir, opts = {}) ⇒ Object
- #gnu_savannah_cvs(proj, mod, branch, opts = {}) ⇒ Object
-
#initialize(target, suffixes, depbuilds) ⇒ Build
constructor
A new instance of Build.
- #log_time_sequence ⇒ Object
- #make(*args) ⇒ Object
- #make_diff ⇒ Object
- #make_diff_content(time) ⇒ Object
- #make_html_log(log_filename, title, has_diff, dst) ⇒ Object
- #make_local_tmpdir ⇒ Object
- #markup(str) ⇒ Object
- #network_access(name = nil) ⇒ Object
- #open_gziped_log(time, &block) ⇒ Object
- #output_change_lines(t2, out) ⇒ Object
- #output_diff(t1, t2, out) ⇒ Object
- #output_status_section ⇒ Object
- #remove_old_build(current, num) ⇒ Object
- #run(command, *args, &block) ⇒ Object
- #run_in_child(opts, command, *args) ⇒ Object
- #show_backtrace(err = $!) ⇒ Object
- #sort_diff_content(time1, tmp1, time2, tmp2) ⇒ Object
- #start_time ⇒ Object
- #status ⇒ Object
- #success? ⇒ Boolean
- #suffixed_name ⇒ Object
- #svn(svnroot, rep_dir, working_dir, opts = {}) ⇒ Object
- #svn_diff_uri(viewvc, d, f, r1, r2) ⇒ Object
- #svn_dir_uri(viewvc, d, f, r) ⇒ Object
- #svn_internal(svnroot, rep_dir, working_dir, opts = {}) ⇒ Object
- #svn_markup_uri(viewvc, d, f, r) ⇒ Object
- #svn_parse_status(f) ⇒ Object
- #svn_path_sort(ary) ⇒ Object
- #svn_print_add_line(f, r, uri) ⇒ Object
- #svn_print_changes(h1, h2, viewvc = nil, rep_dir = nil) ⇒ Object
- #svn_print_chg_line(f, r1, r2, uri) ⇒ Object
- #svn_print_del_line(f, r, uri) ⇒ Object
- #svn_rev_uri(viewvc, r) ⇒ Object
- #svn_revisions ⇒ Object
- #traverse_depbuild(&block) ⇒ Object
- #update_recent ⇒ Object
- #update_summary(title, different_sections) ⇒ Object
- #version ⇒ Object
- #with_procmemsize(opts) ⇒ Object
Methods included from Util
#atomic_make_file, #force_link, #mkcd, #product, #product_each, #resource_limit, #resource_unlimit, #rproduct, #sha256_digest_file, #simple_hostname, #with_tempfile
Constructor Details
#initialize(target, suffixes, depbuilds) ⇒ Build
Returns a new instance of Build.
51 52 53 54 55 56 57 58 59 60 |
# File 'lib/chkbuild/build.rb', line 51 def initialize(target, suffixes, depbuilds) @target = target @suffixes = suffixes @depbuilds = depbuilds @target_dir = ChkBuild.build_top + self.depsuffixed_name @public = ChkBuild.public_top + self.depsuffixed_name @public_log = @public+"log" @current_txt = @public+"current.txt" end |
Instance Attribute Details
#depbuilds ⇒ Object (readonly)
Returns the value of attribute depbuilds.
61 62 63 |
# File 'lib/chkbuild/build.rb', line 61 def depbuilds @depbuilds end |
#logfile ⇒ Object (readonly)
Returns the value of attribute logfile.
238 239 240 |
# File 'lib/chkbuild/build.rb', line 238 def logfile @logfile end |
#suffixes ⇒ Object (readonly)
Returns the value of attribute suffixes.
61 62 63 |
# File 'lib/chkbuild/build.rb', line 61 def suffixes @suffixes end |
#target ⇒ Object (readonly)
Returns the value of attribute target.
61 62 63 |
# File 'lib/chkbuild/build.rb', line 61 def target @target end |
#target_dir ⇒ Object (readonly)
Returns the value of attribute target_dir.
62 63 64 |
# File 'lib/chkbuild/build.rb', line 62 def target_dir @target_dir end |
Instance Method Details
#build ⇒ Object
107 108 109 110 111 112 113 114 |
# File 'lib/chkbuild/build.rb', line 107 def build dep_dirs = [] @depbuilds.each {|depbuild| dep_dirs << "#{depbuild.target.target_name}=#{depbuild.dir}" } status = self.build_in_child(dep_dirs) status.to_i == 0 end |
#build_dir ⇒ Object
290 |
# File 'lib/chkbuild/build.rb', line 290 def build_dir() @build_dir end |
#build_in_child(dep_dirs) ⇒ Object
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/chkbuild/build.rb', line 116 def build_in_child(dep_dirs) if defined? @built_status raise "already built" end branch_info = @suffixes + dep_dirs start_time_obj = Time.now @start_time = start_time_obj.strftime("%Y%m%dT%H%M%S") dir = ChkBuild.build_top + self.depsuffixed_name + @start_time r, w = IO.pipe r.close_on_exec = true w.close_on_exec = true pid = fork { r.close if child_build_wrapper(w, *branch_info) exit 0 else exit 1 end } w.close str = r.read r.close status = Process.wait2(pid)[1] begin version = Marshal.load(str) rescue ArgumentError version = self.suffixed_name end @built_status = status @built_dir = dir @built_version = version return status end |
#build_time_sequence ⇒ Object
87 88 89 90 91 92 |
# File 'lib/chkbuild/build.rb', line 87 def build_time_sequence dirs = @target_dir.entries.map {|e| e.to_s } dirs.reject! {|d| /\A\d{8}T\d{6}\z/ !~ d } # year 10000 problem dirs.sort! dirs end |
#catch_error(name = nil) ⇒ Object
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/chkbuild/build.rb', line 257 def catch_error(name=nil) err = nil begin yield rescue Exception => err end return true unless err @errors << err @logfile.start_section("#{name} error") if name show_backtrace err unless CommandError === err GDB.check_core(@build_dir) if CommandError === err puts "failed(#{err.reason})" else if err.respond_to? :reason puts "failed(#{err.reason} #{err.class})" else puts "failed(#{err.class})" end end return false end |
#child_build_target(*branch_info) ⇒ Object
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/chkbuild/build.rb', line 197 def child_build_target(*branch_info) opts = @target.opts @build_dir = @target_dir + @start_time @log_filename = @build_dir + 'log' mkcd @target_dir raise "already exist: #{@start_time}" if File.exist? @start_time Dir.mkdir @start_time # fail if it is already exists. Dir.chdir @start_time @logfile = ChkBuild::LogFile.write_open(@log_filename, self) @logfile.change_default_output @public.mkpath @public_log.mkpath force_link "log", @current_txt make_local_tmpdir remove_old_build(@start_time, opts.fetch(:old, ChkBuild.num_oldbuilds)) @logfile.start_section 'start' ret = nil with_procmemsize(opts) { ret = catch_error { @target.build_proc.call(self, *branch_info) } output_status_section @logfile.start_section 'end' } force_link @current_txt, @public+'last.txt' if @current_txt.file? titlegen = ChkBuild::Title.new(@target, @logfile) title_succ = catch_error('run_hooks') { titlegen.run_hooks } title = titlegen.make_title title << " (titlegen.run_hooks error)" if !title_succ Marshal.dump(titlegen.version, @parent_pipe) @parent_pipe.close @compressed_log_basename = "#{@start_time}.log.txt.gz" @compressed_diff_basename = "#{@start_time}.diff.txt.gz" compress_file(@log_filename, @public_log+@compressed_log_basename) different_sections = make_diff update_summary(title, different_sections) update_recent make_html_log(@log_filename, title, different_sections, @public+"last.html") compress_file(@public+"last.html", @public+"last.html.gz") ChkBuild.run_upload_hooks(self.suffixed_name) ret end |
#child_build_wrapper(parent_pipe, *branch_info) ⇒ Object
182 183 184 185 186 187 188 189 |
# File 'lib/chkbuild/build.rb', line 182 def child_build_wrapper(parent_pipe, *branch_info) ret = ChkBuild.lock_puts(self.depsuffixed_name) { @parent_pipe = parent_pipe @errors = [] child_build_target(*branch_info) } ret end |
#compress_file(src, dst) ⇒ Object
431 432 433 434 435 436 437 |
# File 'lib/chkbuild/build.rb', line 431 def compress_file(src, dst) Zlib::GzipWriter.wrap(open(dst, "w")) {|z| open(src) {|f| FileUtils.copy_stream(f, z) } } end |
#cvs(cvsroot, mod, branch, opts = {}) ⇒ Object
28 29 30 31 32 |
# File 'lib/chkbuild/scm/cvs.rb', line 28 def cvs(cvsroot, mod, branch, opts={}) network_access { cvs_internal(cvsroot, mod, branch, opts) } end |
#cvs_internal(cvsroot, mod, branch, opts = {}) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/chkbuild/scm/cvs.rb', line 34 def cvs_internal(cvsroot, mod, branch, opts={}) opts = opts.dup opts[:section] ||= 'cvs' working_dir = opts.fetch(:working_dir, mod) if !File.exist? "#{ENV['HOME']}/.cvspass" opts['ENV:CVS_PASSFILE'] = '/dev/null' # avoid warning end if File.directory?(working_dir) Dir.chdir(working_dir) { h1 = cvs_revisions self.run("cvs", "-f", "-z3", "-Q", "update", "-kb", "-dP", opts) h2 = cvs_revisions cvs_print_revisions(h1, h2, opts[:viewvc]||opts[:viewcvs]||opts[:cvsweb]) } else h1 = nil if File.identical?(@build_dir, '.') && !(ts = build_time_sequence - [@start_time]).empty? && File.directory?(old_working_dir = "#{@target_dir}/#{ts.last}/#{working_dir}") Dir.chdir(old_working_dir) { h1 = cvs_revisions } end if branch self.run("cvs", "-f", "-z3", "-Qd", cvsroot, "co", "-kb", "-d", working_dir, "-Pr", branch, mod, opts) else self.run("cvs", "-f", "-z3", "-Qd", cvsroot, "co", "-kb", "-d", working_dir, "-P", mod, opts) end Dir.chdir(working_dir) { h2 = cvs_revisions cvs_print_revisions(h1, h2, opts[:viewvc]||opts[:viewcvs]||opts[:cvsweb]) } end end |
#cvs_print_changes(h1, h2, viewcvs = nil) ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/chkbuild/scm/cvs.rb', line 100 def cvs_print_changes(h1, h2, viewcvs=nil) (h1.keys | h2.keys).sort.each {|k| f = k.flatten.join('/') cvsroot1, repository1, r1 = h1[k] || [nil, nil, 'none'] cvsroot2, repository2, r2 = h2[k] || [nil, nil, 'none'] if r1 != r2 if r1 == 'none' line = "ADD" elsif r2 == 'none' line = "DEL" else line = "CHG" end line << " #{f}\t#{r1}->#{r2}" if viewcvs line << "\t" << cvs_uri(viewcvs, repository1 || repository2, k[1], r1, r2) end puts line end } end |
#cvs_print_revisions(h1, h2, viewcvs = nil) ⇒ Object
122 123 124 125 126 127 128 129 130 131 |
# File 'lib/chkbuild/scm/cvs.rb', line 122 def cvs_print_revisions(h1, h2, viewcvs=nil) cvs_print_changes(h1, h2, viewcvs) if h1 puts 'revisions:' h2.keys.sort.each {|k| f = k.flatten.join('/') cvsroot2, repository2, r2 = h2[k] || [nil, nil, 'none'] digest = sha256_digest_file(f) puts "#{f}\t#{r2}\t#{digest}" } end |
#cvs_revisions ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/chkbuild/scm/cvs.rb', line 69 def cvs_revisions h = {} Dir.glob("**/CVS").each {|cvs_dir| cvsroot = IO.read("#{cvs_dir}/Root").chomp repository = IO.read("#{cvs_dir}/Repository").chomp ds = cvs_dir.split(%r{/})[0...-1] IO.foreach("#{cvs_dir}/Entries") {|line| h[[ds, $1]] = [cvsroot, repository, $2] if %r{^/([^/]+)/([^/]*)/} =~ line } } h end |
#cvs_uri(viewcvs, repository, filename, r1, r2) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/chkbuild/scm/cvs.rb', line 82 def cvs_uri(viewcvs, repository, filename, r1, r2) uri = URI.parse(viewcvs) path = uri.path.dup path << "/" << Escape.uri_path(repository).to_s if repository != '.' path << "/" << Escape.uri_path(filename).to_s uri.path = path query = (uri.query || '').split(/[;&]/) if r1 == 'none' query << "rev=#{r2}" elsif r2 == 'none' query << "rev=#{r1}" else query << "r1=#{r1}" << "r2=#{r2}" end uri.query = query.join(';') uri.to_s end |
#depsuffixed_name ⇒ Object
72 73 74 75 76 77 78 |
# File 'lib/chkbuild/build.rb', line 72 def depsuffixed_name name = self.suffixed_name @depbuilds.each {|depbuild| name << '_' << depbuild.suffixed_name } name end |
#different_sections(tmp1, tmp2) ⇒ Object
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
# File 'lib/chkbuild/build.rb', line 519 def different_sections(tmp1, tmp2) logfile1 = ChkBuild::LogFile.read_open(tmp1.path) logfile2 = ChkBuild::LogFile.read_open(tmp2.path) secnames1 = logfile1.secnames secnames2 = logfile2.secnames different_sections = secnames1 - secnames2 secnames2.each {|secname| if !secnames1.include?(secname) different_sections << secname elsif logfile1.section_size(secname) != logfile2.section_size(secname) different_sections << secname elsif logfile1.get_section(secname) != logfile2.get_section(secname) different_sections << secname end } different_sections end |
#dir ⇒ Object
172 173 174 175 |
# File 'lib/chkbuild/build.rb', line 172 def dir return @built_dir if defined? @built_dir raise "#{self.suffixed_name}: no dir yet" end |
#git(cloneurl, working_dir, opts = {}) ⇒ Object
57 58 59 60 61 |
# File 'lib/chkbuild/scm/git.rb', line 57 def git(cloneurl, working_dir, opts={}) network_access { git_internal(cloneurl, working_dir, opts) } end |
#git_head_commit ⇒ Object
146 147 148 149 150 151 152 |
# File 'lib/chkbuild/scm/git.rb', line 146 def git_head_commit IO.popen("git rev-list --max-count=1 HEAD") {|f| # <sha1><LF> # 4db0223676a371da8c4247d9a853529ef50a3b01 f.read.chomp } end |
#git_internal(cloneurl, working_dir, opts = {}) ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/chkbuild/scm/git.rb', line 63 def git_internal(cloneurl, working_dir, opts={}) urigen = nil opts = opts.dup opts[:section] ||= 'git' if opts[:github] urigen = GitHub.new(*opts[:github]) end if shared_dir = opts[:shared_gitdir] opts_shared = opts.dup opts_shared[:section] += "(shared)" Dir.chdir(shared_dir) { if File.directory?(working_dir) && File.exist?("#{working_dir}/.git") Dir.chdir(working_dir) { git_logfile(opts_shared) {|opts2| self.run("git", "pull", opts2) } } else FileUtils.rm_rf(working_dir) if File.exist?(working_dir) pdir = File.dirname(working_dir) FileUtils.mkdir_p(pdir) if !File.directory?(pdir) git_logfile(opts_shared) {|opts2| self.run "git", "clone", "-q", cloneurl, working_dir, opts2 } end cloneurl = "#{shared_dir}/#{working_dir}" } end if File.exist?(working_dir) && File.exist?("#{working_dir}/.git") Dir.chdir(working_dir) { old_head = git_head_commit git_logfile(opts) {|opts2| self.run "git", "pull", opts2 } logs = git_oneline_logs(old_head) git_print_logs(old_head, logs, urigen) } else FileUtils.rm_rf(working_dir) if File.exist?(working_dir) pdir = File.dirname(working_dir) FileUtils.mkdir_p(pdir) if !File.directory?(pdir) old_head = nil if File.identical?(self.build_dir, '.') && !(ts = self.build_time_sequence - [self.start_time]).empty? && File.directory?(old_working_dir = self.target_dir + ts.last + working_dir) Dir.chdir(old_working_dir) { old_head = git_head_commit } end git_logfile(opts) {|opts2| self.run "git", "clone", "-q", cloneurl, working_dir, opts2 } Dir.chdir(working_dir) { logs = git_oneline_logs(old_head) git_print_logs(old_head, logs, urigen) } end end |
#git_logfile(opts) ⇒ Object
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/chkbuild/scm/git.rb', line 41 def git_logfile(opts) git_with_file("git.log.") {|errfile| opts2 = opts.dup opts2[:stderr] = errfile begin yield opts2 ensure if File.exist?(errfile) errcontent = File.read(errfile) errcontent.gsub!(/^.*[\r\e].*\n/, "") puts errcontent if !errcontent.empty? end end } end |
#git_oneline_logs(old_head = nil) ⇒ Object
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/chkbuild/scm/git.rb', line 128 def git_oneline_logs(old_head=nil) result = [] if old_head command = "git log --pretty=oneline #{old_head}..HEAD" else command = "git log --pretty=oneline --max-count=1" end IO.popen(command) {|f| f.each_line {|line| # <sha1><sp><title line> if /\A([0-9a-fA-F]+)\s+(.*)/ =~ line result << [$1, $2] end } } result end |
#git_parse_status(f) ⇒ Object
167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/chkbuild/scm/git.rb', line 167 def git_parse_status(f) h = {} f.each_line("\0") {|line| # <mode> SP <type> SP <object> TAB <file>\0 # 100644 blob 9518934185ea26856cf1bcdf75f7cc51fcd82534 core/array/allocate_spec.rb if /\A\d+ [^ ]+ ([0-9a-fA-F]+)\t([^\0]+)\0\z/ =~ line rev = $1 path = $2 h[path] = rev end } h end |
#git_path_sort(ary) ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/chkbuild/scm/git.rb', line 181 def git_path_sort(ary) ary.sort_by {|path| path.gsub(%r{([^/]+)(/|\z)}) { if $2 == "" if $1 == '.' "A" else "B#{$1}" end else "C#{$1}\0" end } } end |
#git_print_logs(old_head, logs, urigen = nil) ⇒ Object
209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/chkbuild/scm/git.rb', line 209 def git_print_logs(old_head, logs, urigen=nil) if !old_head puts "last commit:" end logs.each {|commit_hash, title_line| if urigen commit = urigen.commit_uri(commit_hash) else commit = commit_hash end line = "COMMIT #{title_line}\t#{commit}" puts line } end |
#git_revisions ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/chkbuild/scm/git.rb', line 154 def git_revisions h = IO.popen("git ls-tree -z -r HEAD") {|f| git_parse_status(f) } IO.popen("git rev-list --max-count=1 HEAD") {|f| # <sha1><LF> # 4db0223676a371da8c4247d9a853529ef50a3b01 commit_hash = f.read.chomp h[nil] = commit_hash } h end |
#git_with_file(basename) {|name| ... } ⇒ Object
33 34 35 36 37 38 39 |
# File 'lib/chkbuild/scm/git.rb', line 33 def git_with_file(basename) n = 1 until !File.exist?(name = "#{self.build_dir}/#{basename}#{n}") n += 1 end yield name end |
#github(user, project, working_dir, opts = {}) ⇒ Object
122 123 124 125 126 |
# File 'lib/chkbuild/scm/git.rb', line 122 def github(user, project, working_dir, opts={}) opts = opts.dup opts[:github] = [user, project] git("git://github.com/#{user}/#{project}.git", working_dir, opts) end |
#gnu_savannah_cvs(proj, mod, branch, opts = {}) ⇒ Object
28 29 30 31 32 |
# File 'lib/chkbuild/scm/xforge.rb', line 28 def gnu_savannah_cvs(proj, mod, branch, opts={}) opts = opts.dup opts[:viewcvs] ||= "http://savannah.gnu.org/cgi-bin/viewcvs/#{proj}?diff_format=u" self.cvs(":pserver:[email protected]:/sources/#{proj}", mod, branch, opts) end |
#log_time_sequence ⇒ Object
94 95 96 97 98 99 100 101 102 103 |
# File 'lib/chkbuild/build.rb', line 94 def log_time_sequence return [] if !@public_log.directory? names = @public_log.entries.map {|e| e.to_s } result = [] names.each {|n| result << $1 if /\A(\d{8}T\d{6})(?:\.log)?\.txt\.gz\z/ =~ n } result.sort! result end |
#make(*args) ⇒ Object
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 |
# File 'lib/chkbuild/build.rb', line 699 def make(*args) opts = {} opts = args.pop if Hash === args.last opts = opts.dup opts[:alt_commands] = ['make'] make_opts, targets = args.partition {|a| /=/ =~ a } if targets.empty? opts[:section] ||= 'make' self.run("gmake", *(make_opts + [opts])) else targets.each {|target| h = opts.dup h[:reason] = target h[:section] ||= target self.run("gmake", target, *(make_opts + [h])) } end end |
#make_diff ⇒ Object
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 |
# File 'lib/chkbuild/build.rb', line 444 def make_diff time2 = @start_time entries = Dir.entries(@public_log) time_seq = [] entries.each {|f| if /\A(\d{8}T\d{6})(?:\.log)?\.txt\.gz\z/ =~ f # year 10000 problem time_seq << $1 end } time_seq.sort! time_seq.delete time2 while !time_seq.empty? && open_gziped_log(time_seq.last) {|f| neterror = false f.each_line {|line| line.force_encoding("ascii-8bit") if line.respond_to? :force_encoding if /\A== neterror / =~ line neterror = true break end } if neterror true else false end } time_seq.pop end return nil if time_seq.empty? time1 = time_seq.last different_sections = nil output_path = @public_log+@compressed_diff_basename Zlib::GzipWriter.wrap(open(output_path, "w")) {|z| different_sections = output_diff(time1, time2, z) } if !different_sections output_path.unlink return nil end return different_sections end |
#make_diff_content(time) ⇒ Object
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 |
# File 'lib/chkbuild/build.rb', line 537 def make_diff_content(time) times = [time] uncompressed = Tempfile.open("#{time}.u.") open_gziped_log(time) {|z| FileUtils.copy_stream(z, uncompressed) } uncompressed.flush logfile = ChkBuild::LogFile.read_open(uncompressed.path) logfile.dependencies.each {|dep_suffixed_name, dep_time, dep_version| times << dep_time } pat = Regexp.union(*times.uniq) tmp = Tempfile.open("#{time}.d.") open_gziped_log(time) {|z| z.each_line {|line| line = line.gsub(pat, '<buildtime>') @target.each_diff_preprocess_hook {|block| catch_error(block.to_s) { line = block.call(line) } } tmp << line } } tmp.flush tmp end |
#make_html_log(log_filename, title, has_diff, dst) ⇒ Object
422 423 424 425 426 427 428 429 |
# File 'lib/chkbuild/build.rb', line 422 def make_html_log(log_filename, title, has_diff, dst) log = File.read(log_filename) log.force_encoding("ascii-8bit") if log.respond_to? :force_encoding permalink = "log/#{@compressed_log_basename}" diff_permalink = "log/#{@compressed_diff_basename}" content = ERB.new(LAST_HTMLTemplate, nil, '%').result(binding) atomic_make_file(dst, content) end |
#make_local_tmpdir ⇒ Object
191 192 193 194 195 |
# File 'lib/chkbuild/build.rb', line 191 def make_local_tmpdir tmpdir = @build_dir + 'tmp' tmpdir.mkpath ENV['TMPDIR'] = tmpdir.to_s end |
#markup(str) ⇒ Object
377 378 379 380 381 382 383 384 385 386 387 |
# File 'lib/chkbuild/build.rb', line 377 def markup(str) result = '' i = 0 str.scan(/#{URI.regexp(['http'])}/o) { result << h(str[i...$~.begin(0)]) if i < $~.begin(0) result << "<a href=\"#{h $&}\">#{h $&}</a>" i = $~.end(0) } result << h(str[i...str.length]) if i < str.length result end |
#network_access(name = nil) ⇒ Object
280 281 282 283 284 285 286 287 288 |
# File 'lib/chkbuild/build.rb', line 280 def network_access(name=nil) begin yield ensure if err = $! @logfile.start_section("neterror") end end end |
#open_gziped_log(time, &block) ⇒ Object
598 599 600 601 602 603 604 605 |
# File 'lib/chkbuild/build.rb', line 598 def open_gziped_log(time, &block) if File.file?(@public_log+"#{time}.log.txt.gz") filename = @public_log+"#{time}.log.txt.gz" else filename = @public_log+"#{time}.txt.gz" end Zlib::GzipReader.wrap(open(filename), &block) end |
#output_change_lines(t2, out) ⇒ Object
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
# File 'lib/chkbuild/build.rb', line 501 def output_change_lines(t2, out) has_diff = false open_gziped_log(t2) {|f| has_change_line = false f.each {|line| if ChkBuild::Target::CHANGE_LINE_PAT =~ line out.puts line has_change_line = true end } if has_change_line out.puts has_diff = true end } has_diff end |
#output_diff(t1, t2, out) ⇒ Object
487 488 489 490 491 492 493 494 495 496 497 498 499 |
# File 'lib/chkbuild/build.rb', line 487 def output_diff(t1, t2, out) has_change_line = output_change_lines(t2, out) tmp1 = make_diff_content(t1) tmp2 = make_diff_content(t2) tmp1, tmp2 = sort_diff_content(t1, tmp1, t2, tmp2) header = "--- #{t1}\n+++ #{t2}\n" has_diff = has_change_line | UDiff.diff(tmp1.path, tmp2.path, out, header) return nil if !has_diff ret = [] ret << 'src' if has_change_line ret.concat different_sections(tmp1, tmp2) ret end |
#output_status_section ⇒ Object
253 254 255 |
# File 'lib/chkbuild/build.rb', line 253 def output_status_section @logfile.start_section 'success' if @errors.empty? end |
#remove_old_build(current, num) ⇒ Object
292 293 294 295 296 297 298 299 300 |
# File 'lib/chkbuild/build.rb', line 292 def remove_old_build(current, num) dirs = build_time_sequence dirs.delete current return if dirs.length <= num dirs[-num..-1] = [] dirs.each {|d| (@target_dir+d).rmtree } end |
#run(command, *args, &block) ⇒ Object
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 |
# File 'lib/chkbuild/build.rb', line 616 def run(command, *args, &block) opts = @target.opts.dup opts.update args.pop if Hash === args.last if opts.include?(:section) secname = opts[:section] else secname = opts[:reason] || File.basename(command) end @logfile.start_section(secname) if secname if !opts.include?(:output_interval_timeout) opts[:output_interval_timeout] = '10min' end puts "+ #{Escape.shell_command [command, *args]}" pos = STDOUT.pos begin command_status = TimeoutCommand.timeout_command(opts.fetch(:timeout, '1h'), STDERR, opts) { run_in_child(opts, command, *args) } ensure exc = $! if exc && secname class << exc attr_accessor :reason end exc.reason = secname end end begin if command_status.exitstatus != 0 if command_status.exited? puts "exit #{command_status.exitstatus}" elsif command_status.signaled? puts "signal #{SignalNum2Name[command_status.termsig]} (#{command_status.termsig})" elsif command_status.stopped? puts "stop #{SignalNum2Name[command_status.stopsig]} (#{command_status.stopsig})" else p command_status end raise CommandError.new(command_status, opts.fetch(:section, command)) end end end |
#run_in_child(opts, command, *args) ⇒ Object
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 |
# File 'lib/chkbuild/build.rb', line 662 def run_in_child(opts, command, *args) opts.each {|k, v| next if /\AENV:/ !~ k.to_s ENV[$'] = v } if Process.respond_to? :setrlimit resource_unlimit(:RLIMIT_CORE) limit = ChkBuild.get_limit opts.each {|k, v| limit[$'.intern] = v if /\Ar?limit_/ =~ k.to_s } resource_limit(:RLIMIT_CPU, limit.fetch(:cpu)) resource_limit(:RLIMIT_STACK, limit.fetch(:stack)) resource_limit(:RLIMIT_DATA, limit.fetch(:data)) resource_limit(:RLIMIT_AS, limit.fetch(:as)) #system('sh', '-c', "ulimit -a") end alt_commands = opts.fetch(:alt_commands, []) if opts.include?(:stdout) STDOUT.reopen(opts[:stdout], "w") end if opts.include?(:stderr) STDERR.reopen(opts[:stderr], "w") end begin exec [command, command], *args rescue Errno::ENOENT if !alt_commands.empty? command = alt_commands.shift retry else raise end end end |
#show_backtrace(err = $!) ⇒ Object
439 440 441 442 |
# File 'lib/chkbuild/build.rb', line 439 def show_backtrace(err=$!) puts "|#{err.} (#{err.class})" err.backtrace.each {|pos| puts "| #{pos}" } end |
#sort_diff_content(time1, tmp1, time2, tmp2) ⇒ Object
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 |
# File 'lib/chkbuild/build.rb', line 563 def sort_diff_content(time1, tmp1, time2, tmp2) pat = @target.diff_preprocess_sort_pattern return tmp1, tmp2 if !pat h1, h2 = [tmp1, tmp2].map {|tmp| h = {} tmp.rewind tmp.gather_each(pat) {|lines| next unless 1 < lines.length && pat =~ lines.first h[$&] = Digest::SHA256.hexdigest(lines.sort.join('')) } h } h0 = {} h1.each_key {|k| h0[k] = true if h1[k] == h2[k] } newtmp1, newtmp2 = [[time1, tmp1], [time2, tmp2]].map {|time, tmp| newtmp = Tempfile.open("#{time}.d.") tmp.rewind tmp.gather_each(pat) {|lines| if 1 < lines.length && pat =~ lines.first && h0[$&] newtmp.print lines.sort.join('') else newtmp.print lines.join('') end } tmp.close(true) newtmp.rewind newtmp } return newtmp1, newtmp2 end |
#start_time ⇒ Object
150 151 152 153 |
# File 'lib/chkbuild/build.rb', line 150 def start_time return @start_time if defined? @start_time raise "#{self.suffixed_name}: no start_time yet" end |
#status ⇒ Object
167 168 169 170 |
# File 'lib/chkbuild/build.rb', line 167 def status return @built_status if defined? @built_status raise "#{self.suffixed_name}: no status yet" end |
#success? ⇒ Boolean
155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/chkbuild/build.rb', line 155 def success? if defined? @built_status if @built_status.to_i == 0 true else false end else nil end end |
#suffixed_name ⇒ Object
64 65 66 67 68 69 70 |
# File 'lib/chkbuild/build.rb', line 64 def suffixed_name name = @target.target_name.dup @suffixes.each {|suffix| name << '-' << suffix } name end |
#svn(svnroot, rep_dir, working_dir, opts = {}) ⇒ Object
71 72 73 74 75 |
# File 'lib/chkbuild/scm/svn.rb', line 71 def svn(svnroot, rep_dir, working_dir, opts={}) network_access { svn_internal(svnroot, rep_dir, working_dir, opts) } end |
#svn_diff_uri(viewvc, d, f, r1, r2) ⇒ Object
166 167 168 169 |
# File 'lib/chkbuild/scm/svn.rb', line 166 def svn_diff_uri(viewvc, d, f, r1, r2) return nil if !viewvc viewvc.diff_uri(d, f, r1, r2) end |
#svn_dir_uri(viewvc, d, f, r) ⇒ Object
161 162 163 164 |
# File 'lib/chkbuild/scm/svn.rb', line 161 def svn_dir_uri(viewvc, d, f, r) return nil if !viewvc viewvc.dir_uri(d, f, r) end |
#svn_internal(svnroot, rep_dir, working_dir, opts = {}) ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/chkbuild/scm/svn.rb', line 77 def svn_internal(svnroot, rep_dir, working_dir, opts={}) url = svnroot + '/' + rep_dir opts = opts.dup opts[:section] ||= 'svn' if opts[:viewvc]||opts[:viewcvs] viewvc = ChkBuild::ViewVC.new(opts[:viewvc]||opts[:viewcvs], opts[:viewcvs]!=nil) else viewvc = nil end if File.exist?(working_dir) && File.exist?("#{working_dir}/.svn") Dir.chdir(working_dir) { self.run "svn", "cleanup", opts opts[:section] = nil h1 = svn_revisions self.run "svn", "update", "-q", opts h2 = svn_revisions svn_print_changes(h1, h2, viewvc, rep_dir) } else if File.exist?(working_dir) FileUtils.rm_rf(working_dir) end h1 = h2 = nil if File.identical?(self.build_dir, '.') && !(ts = self.build_time_sequence - [self.start_time]).empty? && File.directory?(old_working_dir = self.target_dir + ts.last + working_dir) Dir.chdir(old_working_dir) { h1 = svn_revisions } end self.run "svn", "checkout", "-q", url, working_dir, opts Dir.chdir(working_dir) { h2 = svn_revisions svn_print_changes(h1, h2, viewvc, rep_dir) if h1 } end end |
#svn_markup_uri(viewvc, d, f, r) ⇒ Object
156 157 158 159 |
# File 'lib/chkbuild/scm/svn.rb', line 156 def svn_markup_uri(viewvc, d, f, r) return nil if !viewvc viewvc.markup_uri(d, f, r) end |
#svn_parse_status(f) ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/chkbuild/scm/svn.rb', line 121 def svn_parse_status(f) h = {} f.each {|line| if /\d+\s+(\d+)\s+\S+\s+(.+)/ =~ line rev = $1.to_i path = $2 dir = File.directory?(path) path << '/' if dir && path != '.' h[path] = [rev, dir] end } h end |
#svn_path_sort(ary) ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/chkbuild/scm/svn.rb', line 135 def svn_path_sort(ary) ary.sort_by {|path| path.gsub(%r{([^/]+)(/|\z)}) { if $2 == "" if $1 == '.' "A" else "B#{$1}" end else "C#{$1}\0" end } } end |
#svn_print_add_line(f, r, uri) ⇒ Object
209 210 211 212 213 |
# File 'lib/chkbuild/scm/svn.rb', line 209 def svn_print_add_line(f, r, uri) line = "ADD #{f}\tnone->#{r}" line << "\t" << uri.to_s if uri puts line end |
#svn_print_changes(h1, h2, viewvc = nil, rep_dir = nil) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/chkbuild/scm/svn.rb', line 171 def svn_print_changes(h1, h2, viewvc=nil, rep_dir=nil) top_r1, _ = h1['.'] top_r2, _ = h2['.'] h1.delete '.' h2.delete '.' return if top_r1 == top_r2 svn_print_chg_line('.', top_r1, top_r2, svn_rev_uri(viewvc, top_r2)) svn_path_sort(h1.keys|h2.keys).each {|f| r1, d1 = h1[f] || ['none', nil] r2, d2 = h2[f] || ['none', nil] next if r1 == r2 # no changes next if d1 && d2 # skip directory changes if !d1 && !d2 && r1 != 'none' && r2 != 'none' svn_print_chg_line(f, r1, r2, svn_diff_uri(viewvc, rep_dir, f, top_r1, top_r2)) else svn_print_del_line(f, r1, d1 ? svn_dir_uri(viewvc, rep_dir, f, top_r1) : svn_markup_uri(viewvc, rep_dir, f, top_r1)) if r1 != 'none' svn_print_add_line(f, r2, d2 ? svn_dir_uri(viewvc, rep_dir, f, top_r2) : svn_markup_uri(viewvc, rep_dir, f, top_r2)) if r2 != 'none' end } end |
#svn_print_chg_line(f, r1, r2, uri) ⇒ Object
197 198 199 200 201 |
# File 'lib/chkbuild/scm/svn.rb', line 197 def svn_print_chg_line(f, r1, r2, uri) line = "CHG #{f}\t#{r1}->#{r2}" line << "\t" << uri.to_s if uri puts line end |
#svn_print_del_line(f, r, uri) ⇒ Object
203 204 205 206 207 |
# File 'lib/chkbuild/scm/svn.rb', line 203 def svn_print_del_line(f, r, uri) line = "DEL #{f}\t#{r}->none" line << "\t" << uri.to_s if uri puts line end |
#svn_rev_uri(viewvc, r) ⇒ Object
151 152 153 154 |
# File 'lib/chkbuild/scm/svn.rb', line 151 def svn_rev_uri(viewvc, r) return nil if !viewvc viewvc.rev_uri(r) end |
#svn_revisions ⇒ Object
115 116 117 118 119 |
# File 'lib/chkbuild/scm/svn.rb', line 115 def svn_revisions IO.popen("svn status -v") {|f| svn_parse_status(f) } end |
#traverse_depbuild(&block) ⇒ Object
80 81 82 83 84 85 |
# File 'lib/chkbuild/build.rb', line 80 def traverse_depbuild(&block) @depbuilds.each {|depbuild| yield depbuild depbuild.traverse_depbuild(&block) } end |
#update_recent ⇒ Object
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/chkbuild/build.rb', line 355 def update_recent start_time = @start_time summary_path = @public+"summary.html" lines = [] summary_path.open {|f| while l = f.gets lines << l lines.shift if 10 < lines.length end } while !lines.empty? && /\A<a / !~ lines[0] lines.shift end title = "#{self.depsuffixed_name} recent build summary" recent_summary = lines.reverse.join content = ERB.new(RECENT_HTMLTemplate).result(binding) recent_path = @public+"recent.html" atomic_make_file(recent_path, content) end |
#update_summary(title, different_sections) ⇒ Object
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/chkbuild/build.rb', line 302 def update_summary(title, different_sections) start_time = @start_time if different_sections if different_sections.empty? diff_txt = "diff" else diff_txt = "diff:#{different_sections.join(',')}" end end open(@public+"summary.txt", "a") {|f| f.print "#{start_time} #{title}" f.print " (#{diff_txt})" if diff_txt f.puts } open(@public+"summary.html", "a") {|f| if f.stat.size == 0 f.puts "<title>#{h self.depsuffixed_name} build summary</title>" f.puts "<h1>#{h self.depsuffixed_name} build summary</h1>" f.puts "<p><a href=\"../\">chkbuild</a></p>" end f.print "<a href=\"log/#{h @compressed_log_basename}\" name=\"#{start_time}\">#{h start_time}</a> #{h title}" f.print " (<a href=\"log/#{h @compressed_diff_basename}\">#{h diff_txt}</a>)" if diff_txt f.puts "<br>" } end |
#version ⇒ Object
177 178 179 180 |
# File 'lib/chkbuild/build.rb', line 177 def version return @built_version if defined? @built_version raise "#{self.suffixed_name}: no version yet" end |
#with_procmemsize(opts) ⇒ Object
240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/chkbuild/build.rb', line 240 def with_procmemsize(opts) if opts[:procmemsize] current_pid = $$ procmemsize_pid = fork { exec *%W[procmemsize -p #{current_pid}] } ret = yield Process.kill :TERM, procmemsize_pid Process.wait procmemsize_pid else ret = yield end ret end |