Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

re-work file structure to be more erlangish, Add a rakefile for building

  • Loading branch information...
commit 378ae58c13139f1f4f5b5c890a4901767da00b4b 1 parent 20b82c4
@Vagabond authored
Showing with 309 additions and 3 deletions.
  1. +309 −0 Rakefile
  2. +0 −3  build.sh
  3. 0  { → c_src}/libpurperl.c
View
309 Rakefile
@@ -0,0 +1,309 @@
+require 'rake/clean'
+
+Dir['tasks/**/*.rake'].each { |rake| load rake }
+
+def percent_to_color(per)
+ if ENV['COLORTERM'].to_s.downcase == 'yes' or ENV['TERM'] =~ /-color$/
+ if per >= 90.0
+ colorstart = "\e[1;32m"
+ elsif per >= 75.0
+ colorstart = "\e[0;32m"
+ elsif per >= 50.0
+ colorstart = "\e[0;33m"
+ elsif per >= 25.0
+ colorstart = "\e[0;31m"
+ else
+ colorstart = "\e[1;31m"
+ end
+ return [colorstart, "\e[0m"]
+ else
+ return ["", ""]
+ end
+end
+
+
+ROOTDIR = `erl -noshell -eval 'io:format("~n~s~n", [code:root_dir()]).' -s erlang halt | tail -n 1`.chomp
+
+# TODO - handle things when there's no pkg-config
+$C_FLAGS = " -Wall " + `pkg-config --cflags --libs purple`.chomp
+
+
+INCLUDE = "include"
+
+vertest = `erl -noshell -eval 'io:format("~n~s~n", [erlang:system_info(otp_release)]).' -s erlang halt | tail -n 1`.chomp
+if vertest =~ /(R\d\d[AB])/
+ OTPVERSION = $1
+else
+ STDERR.puts "unable to determine OTP version! (I got #{vertest})"
+ exit -1
+end
+ERLC_FLAGS = "-I#{INCLUDE} -D #{OTPVERSION} +warn_unused_vars +warn_unused_import +warn_exported_vars +warn_untyped_record"
+
+C_SRC = FileList['c_src/*.c']
+SRC = FileList['src/*.erl']
+HEADERS = FileList['include/*.hrl']
+C_HEADERS = FileList['c_src/*.h']
+OBJ = SRC.pathmap("%{src,ebin}X.beam")
+#C_OBJ = C_SRC.pathmap("%{c_src,priv}X.o")
+CONTRIB = FileList['contrib/*']
+DEBUGOBJ = SRC.pathmap("%{src,debug_ebin}X.beam")
+COVERAGE = SRC.pathmap("%{src,coverage}X.txt")
+RELEASE = FileList['src/*.rel.src'].pathmap("%{src,ebin}X")
+
+# check to see if gmake is available, if not fall back on the system make
+if res = `which gmake` and $?.exitstatus.zero? and not res =~ /no gmake in/
+ MAKE = File.basename(res.chomp)
+else
+ MAKE = 'make'
+end
+
+@maxwidth = SRC.map{|x| File.basename(x, 'erl').length}.max
+
+CLEAN.include("ebin/*.beam")
+CLEAN.include("ebin/*.app")
+CLEAN.include("ebin/*.script")
+CLEAN.include("ebin/*.boot")
+CLEAN.include("ebin/*.rel")
+CLEAN.include("debug_ebin/*.beam")
+CLEAN.include("debug_ebin/*.app")
+CLEAN.include("debug_ebin/*.script")
+CLEAN.include("debug_ebin/*.boot")
+CLEAN.include("coverage/*.txt")
+CLEAN.include("coverage/*.txt.failed")
+CLEAN.include("coverage/*.html")
+CLEAN.include("doc/*.html")
+CLEAN.include("c_src/*.o")
+CLEAN.include("priv/*")
+
+verbose(true) unless ENV['quiet']
+
+directory 'ebin'
+directory 'priv'
+directory 'debug_ebin'
+directory 'coverage'
+#directory 'doc'
+
+rule ".beam" => ["%{ebin,src}X.erl"] + HEADERS do |t|
+ sh "erlc -pa ebin -W #{ERLC_FLAGS} +warn_missing_spec -o ebin #{t.source} "
+end
+
+rule ".beam" => ["%{debug_ebin,src}X.erl"] + HEADERS do |t|
+ sh "erlc +debug_info -D EUNIT -pa debug_ebin -W #{ERLC_FLAGS} -o debug_ebin #{t.source} "
+end
+
+rule ".rel" => ["%{ebin,src}X.rel.src"] do |t|
+ contents = File.read(t.source)
+ #p contents
+ while contents =~ /^[\s\t]*([-a-zA-Z0-9_]+),[\s\t]*$/
+ app = $1
+ if app == "erts"
+ version = `erl -noshell -eval 'io:format("~n~s~n", [erlang:system_info(version)]).' -s erlang halt | tail -n 1`.chomp
+ else
+ version = `erl -noshell -eval 'application:load(#{app}), io:format("~n~s~n", [proplists:get_value(#{app}, lists:map(fun({Name, Desc, Vsn}) -> {Name, Vsn} end, application:loaded_applications()))]).' -s erlang halt | tail -n 1`.chomp
+ end
+ if md = /(\d+\.\d+(\.\d+(\.\d+|)|))/.match(version)
+ contents.sub!(app, "{#{app}, \"#{md[1]}\"}")
+ else
+ STDERR.puts "Cannot find application #{app} mentioned in release file!"
+ exit 1
+ end
+ end
+ File.open(t.name, 'w') do |f|
+ f.puts contents
+ end
+end
+
+file "priv/purpleserv" => C_SRC + C_HEADERS do |t|
+ sh "gcc c_src/libpurperl.c #{$C_FLAGS} -o #{t.to_s}"
+end
+
+rule ".txt" => ["%{coverage,debug_ebin}X.beam"] do |t|
+ mod = File.basename(t.source, '.beam')
+ if ENV['modules'] and not ENV['modules'].split(',').include? mod
+ puts "skipping tests for #{mod}"
+ next
+ end
+
+ print " #{mod.ljust(@maxwidth - 1)} : "
+ STDOUT.flush
+ test_output = `erl -noshell -pa debug_ebin -pa contrib/mochiweb/ebin -sname testpx -eval ' cover:start(), cover:compile_beam("#{t.source}"), try eunit:test(#{mod}, [verbose]) of _Any -> cover:analyse_to_file(#{mod}, "coverage/#{mod}.txt"), cover:analyse_to_file(#{mod}, "coverage/#{mod}.html", [html]) catch _:_ -> io:format("This module does not provide a test() function~n"), ok end.' -s erlang halt`
+ if /(All \d+ tests (successful|passed)|There were no tests to run|This module does not provide a test\(\) function|Test (successful|passed))/ =~ test_output
+ File.delete(t.to_s+'.failed') if File.exists?(t.to_s+'.failed')
+ if ENV['verbose']
+ puts test_output.split("\n")[1..-1].map{|x| x.include?('1>') ? x.gsub(/\([a-zA-Z0-9\-@]+\)1>/, '') : x}.join("\n")
+ else
+ out = $1
+ if /(All \d+ tests (successful|passed)|Test (successful|passed))/ =~ test_output
+ colorstart, colorend = percent_to_color(80)
+ #elsif /This module does not provide a test\(\) function/ =~ test_output
+ #colorstart, colorend = percent_to_color(50)
+ else
+ colorstart, colorend = percent_to_color(50)
+ #colorstart, colorend = ["", ""]
+ end
+ puts "#{colorstart}#{out}#{colorend}"
+ #puts " #{mod.ljust(@maxwidth - 1)} : #{out}"
+ end
+ else
+ puts "\e[1;35mFAILED\e[0m"
+ puts test_output.split("\n")[1..-1].map{|x| x.include?('1>') ? x.gsub(/\([a-zA-Z0-9\-@]+\)1>/, '') : x}.join("\n")
+ puts " #{mod.ljust(@maxwidth - 1)} : \e[1;35mFAILED\e[0m"
+ File.delete(t.to_s) if File.exists?(t.to_s)
+ File.new(t.to_s+'.failed', 'w').close
+ end
+end
+
+task :compile => [:contrib, 'ebin', 'priv'] + HEADERS + OBJ + ['priv/purpleserv'] + RELEASE do
+ Dir["ebin/*.rel"].each do |rel|
+ rel = File.basename(rel, '.rel')
+ sh "erl -noshell -eval 'systools:make_script(\"ebin/#{rel}\", [{outdir, \"ebin\"}]).' -s erlang halt -pa ebin"
+ end
+end
+
+task :install => [:compile] do
+ sh "mkdir #{ROOTDIR}/lib/libpurperl-1.0" unless File.directory? "#{ROOTDIR}/lib/libpurperl-1.0"
+ sh "cp -r src ebin c_src priv #{ROOTDIR}/lib/libpurperl-1.0"
+end
+
+task :contrib do
+ CONTRIB.each do |cont|
+ if File.exists? File.join(cont, 'Makefile')
+ sh "#{MAKE} -C #{cont}"
+ elsif File.exists? File.join(cont, 'Rakefile')
+ pwd = Dir.pwd
+ Dir.chdir(cont)
+ sh "#{$0}"
+ Dir.chdir(pwd)
+ end
+ end
+ unless Dir["src/*.app"].length.zero?
+ sh "cp src/*.app ebin/"
+ end
+end
+
+task :default => :compile
+
+task :release => :compile
+
+desc "Alias for test:all"
+task :test => "test:all"
+
+desc "Generate Documentation"
+task :doc do
+ sh('mkdir doc') unless File.directory? 'doc'
+ sh("rm -rf doc/*.html && cd doc && erl -noshell -run edoc files ../#{SRC.join(" ../")} -run init stop")
+end
+
+namespace :test do
+ desc "Compile .beam files with -DEUNIT and +debug_info => debug_ebin"
+ task :compile => [:contrib, 'debug_ebin'] + HEADERS + DEBUGOBJ + ['priv/purpleserv']
+
+ task :contrib do
+ CONTRIB.each do |cont|
+ if File.exists? File.join(cont, 'Makefile')
+ sh "#{MAKE} -C #{cont}"
+ elsif File.exists? File.join(cont, 'Rakefile')
+ pwd = Dir.pwd
+ Dir.chdir(cont)
+ sh "#{$0} debug=yes"
+ Dir.chdir(pwd)
+ end
+ end
+ unless Dir["src/*.app"].length.zero?
+ sh "cp src/*.app debug_ebin/"
+ end
+ end
+
+ desc "run eunit tests and output coverage reports"
+ task :all => [:compile, :eunit, :report_coverage]
+
+ desc "run only the eunit tests"
+ task :eunit => [:compile, 'coverage'] + COVERAGE
+
+ desc "rerun any outstanding tests and report the coverage"
+ task :report_coverage => [:eunit, :report_current_coverage]
+
+ desc "report the percentage code coverage of the last test run"
+ task :report_current_coverage do
+ global_total = 0
+ files = (Dir['coverage/*.txt'] + Dir['coverage/*.txt.failed']).sort
+ maxwidth = files.map{|x| x = File.basename(x, '.failed'); File.basename(x, ".txt").length}.max
+ puts "Code coverage:"
+ files.each do |file|
+ if file =~ /\.txt\.failed$/
+ if ENV['COLORTERM'].to_s.downcase == 'yes' or ENV['TERM'] =~ /-color$/
+ puts " #{File.basename(file, ".txt.failed").ljust(maxwidth)} : \e[1;35mFAILED\e[0m"
+ else
+ puts " #{File.basename(file, ".txt.failed").ljust(maxwidth)} : FAILED"
+ end
+ else
+ total = 0
+ tally = 0
+ File.read(file).each do |line|
+ if line =~ /^\s+[1-9][0-9]*\.\./
+ total += 1
+ tally += 1
+ elsif line =~ /^\s+0\.\./ and not line =~ /^-module/
+ total += 1
+ end
+ end
+ per = tally/total.to_f * 100
+ colorstart, colorend = percent_to_color(per)
+ puts " #{File.basename(file, ".txt").ljust(maxwidth)} : #{colorstart}#{sprintf("%.2f%%", (tally/(total.to_f)) * 100)}#{colorend}"
+ global_total += (tally/(total.to_f)) * 100
+ end
+ end
+ colorstart, colorend = percent_to_color(global_total/files.length)
+ puts "Overall coverage: #{colorstart}#{sprintf("%.2f%%", global_total/files.length)}#{colorend}"
+ end
+
+ task :report_missing_specs do
+ unspecced = []
+ ignored = %w{handle_info handle_cast handle_call code_change terminate init}
+ puts "Functions missing specs:"
+ SRC.each do |src|
+ contents = File.read(src)
+ contents.each do |line|
+ if md = /^([a-z_]+)\(.*?\) ->/.match(line) and not ignored.include?(md[1]) and not md[1][-5..-1] == '_test' and not md[1][-6..-1] == '_test_'
+ unless /^-spec\(#{md[1]}\//.match(contents)
+ unspecced << File.basename(src, '.erl') + ':'+ md[1]
+ end
+ end
+ end
+ end
+ puts " "+unspecced.uniq.join("\n ")
+ end
+
+ desc "run the dialyzer"
+ task :dialyzer do
+ print "running dialyzer..."
+ `dialyzer --check_plt`
+ if $?.exitstatus != 0
+ puts 'no PLT'
+ puts "The dialyzer can't find the initial PLT, you can try building one using `rake test:build_plt`. This can take quite some time."
+ exit(1)
+ end
+ STDOUT.flush
+ # Add -DEUNIT=1 here to make dialyzer evaluate the code in the test cases. This generates some spurious warnings so
+ # it's not set normally but it can be very helpful occasionally.
+ dialyzer_flags = ""
+ dialyzer_flags += " -DEUNIT=1" if ENV['dialyzer_debug']
+ dialyzer_flags += " -Wunderspecs" if ENV['dialyzer_underspecced']
+ contribfiles = Dir['contrib**/*.erl'].join(' ')
+ dialyzer_output = `dialyzer -D#{OTPVERSION}=1 #{dialyzer_flags} --src -I include -c #{SRC.join(' ')} #{contribfiles}`
+ #puts dialyzer_output
+ if $?.exitstatus.zero?
+ puts 'ok'
+ else
+ puts 'not ok'
+ puts dialyzer_output
+ end
+ end
+
+ desc "try to create the dialyzer's initial PLT"
+ task :build_plt do
+ out = `which erlc`
+ foo = out.split('/')[0..-3].join('/')+'/lib/erlang/lib'
+ sh "dialyzer --build_plt -r #{foo}/kernel*/ebin #{foo}/stdlib*/ebin #{foo}/mnesia*/ebin #{foo}/crypto*/ebin #{foo}/eunit*/ebin"
+ end
+end
View
3  build.sh
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-gcc libpurperl.c -o libpurperl -Wall -I/usr/local/include/glib-2.0 -I/usr/local/include/libpurple -L/usr/local/lib -lglib-2.0 -lpurple -g3 -ggdb
View
0  libpurperl.c → c_src/libpurperl.c
File renamed without changes
Please sign in to comment.
Something went wrong with that request. Please try again.