Rakefile 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. #
  2. # Copyright (c) 2008-2015 the Urho3D project.
  3. #
  4. # Permission is hereby granted, free of charge, to any person obtaining a copy
  5. # of this software and associated documentation files (the "Software"), to deal
  6. # in the Software without restriction, including without limitation the rights
  7. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. # copies of the Software, and to permit persons to whom the Software is
  9. # furnished to do so, subject to the following conditions:
  10. #
  11. # The above copyright notice and this permission notice shall be included in
  12. # all copies or substantial portions of the Software.
  13. #
  14. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. # THE SOFTWARE.
  21. #
  22. require 'pathname'
  23. require 'json'
  24. require 'yaml'
  25. # Usage: rake sync (only intended to be used in a fork with remote 'upstream' set to urho3d/Urho3D)
  26. desc 'Fetch and merge upstream urho3d/Urho3D to a Urho3D fork'
  27. task :sync do
  28. system "git fetch upstream && git checkout master && git pull && git merge -m 'Sync at #{Time.now.localtime}.' upstream/master && git push && git checkout -" or abort
  29. end
  30. # Usage: rake scaffolding dir=/path/to/new/project/root [project=Scaffolding] [target=Main]
  31. desc 'Create a new project using Urho3D as external library'
  32. task :scaffolding do
  33. abort 'Usage: rake scaffolding dir=/path/to/new/project/root [project=Scaffolding] [target=Main]' unless ENV['dir']
  34. abs_path = (ENV['OS'] ? ENV['dir'][1, 1] == ':' : ENV['dir'][0, 1] == '/') ? ENV['dir'] : "#{Dir.pwd}/#{ENV['dir']}"
  35. project = ENV['project'] || 'Scaffolding'
  36. target = ENV['target'] || 'Main'
  37. scaffolding(abs_path, project, target)
  38. abs_path = Pathname.new(abs_path).realpath
  39. puts "\nNew project created in #{abs_path}\n\n"
  40. puts "You may need to first set 'URHO3D_HOME' environment variable or use 'URHO3D_HOME' build option to point to your Urho3D build tree or your custom Urho3D SDK installation location."
  41. puts "Please see http://urho3d.github.io/documentation/HEAD/_using_library.html for more detail. For example:\n\n"
  42. if ENV['OS']
  43. puts "set \"URHO3D_HOME=/path/to/Urho3D/build-tree/or/SDK\"\ncd #{abs_path}\nrake cmake URHO3D_LUAJIT=1\nrake make\n\n"
  44. puts "Alternatively you can call one of the batch files directly, such as, cmake_generic.bat ../native-Build -DURHO3D_LUAJIT=1 and build using VS IDE"
  45. else
  46. puts "export URHO3D_HOME=/path/to/Urho3D/build-tree/or/SDK\ncd #{abs_path}\nrake cmake URHO3D_LUAJIT=1\nrake make\n\n"
  47. puts "Alternatively you can call one of the shell scripts directly, such as, ./cmake_generic.sh ../native-Build -DURHO3D_LUAJIT=1 && cd ../native-Build && make"
  48. end
  49. puts "to get a similar result as the last two rake tasks above.\n\n"
  50. end
  51. # Usage: rake cmake [<generator>] [<platform>] [<option>=<value> [<option>=<value>]] [[<platform>_]build_tree=/path/to/build-tree] [fix_scm]
  52. # e.g.: rake cmake clean android; or rake cmake android URHO3D_LIB_TYPE=SHARED; or rake cmake ios URHO3D_LUA=1 build_tree=~/ios-Build
  53. #
  54. # To avoid repeating the customized build tree locations, you can set and export them as environment variables.
  55. # e.g.: export native_build_tree=~/custom-native-Build android_build_tree=~/custom-android-Build mingw_build_tree=~/custom-mingw-Build rpi_build_tree=~/custom-rpi-Build
  56. # rake cmake rpi URHO3D_LUAJIT=1 URHO3D_LUAJIT_AMALG=1 && rake make rpi
  57. # The RPI build tree will be generated in the ~/custom-rpi-Build and then build from there
  58. desc 'Invoke one of the build scripts with the build tree location predetermined based on the target platform'
  59. task :cmake do
  60. script = 'cmake_generic'
  61. platform = 'native'
  62. build_options = ''
  63. ARGV.each { |option|
  64. task option.to_sym do ; end; Rake::Task[option].clear # No-op hack
  65. case option
  66. when 'cmake', 'generic'
  67. # do nothing
  68. when 'clean', 'codeblocks', 'eclipse', 'macosx', 'ninja', 'vs2008', 'vs2010', 'vs2012', 'vs2013', 'vs2015'
  69. script = "cmake_#{option}" unless script == 'cmake_clean'
  70. when 'android', 'emscripten', 'ios', 'mingw', 'rpi'
  71. platform = option
  72. build_options = "#{build_options} -D#{option == 'mingw' ? 'WIN32' : option.upcase}=1" unless script == 'cmake_clean'
  73. script = 'cmake_macosx' if option == 'ios'
  74. script = 'cmake_mingw' if option == 'mingw' && ENV['OS']
  75. when 'fix_scm'
  76. build_options = "#{build_options} --fix-scm" if script == 'cmake_eclipse'
  77. else
  78. build_options = "#{build_options} -D#{option}" unless /build_tree=.*/ =~ option || script == 'cmake_clean'
  79. end
  80. }
  81. build_tree = ENV["#{platform}_build_tree"] || ENV['build_tree'] || "../#{platform}-Build"
  82. unless ENV['OS']
  83. ccache_envvar = ENV['CCACHE_SLOPPINESS'] ? '' : 'CCACHE_SLOPPINESS=pch_defines,time_macros' # Only attempt to do the right thing when user hasn't done it
  84. ccache_envvar = "#{ccache_envvar} CCACHE_COMPRESS=1" unless ENV['CCACHE_COMPRESS']
  85. end
  86. system "#{ccache_envvar} ./#{script}#{ENV['OS'] ? '.bat' : '.sh'} \"#{build_tree}\" #{build_options}" or abort
  87. end
  88. # Usage: rake make [<platform>] [<option>=<value> [<option>=<value>]] [[<platform>_]build_tree=/path/to/build-tree] [numjobs=n] [clean_first] [unfilter]
  89. # e.g.: rake make android; or rake make android doc; or rake make ios config=Debug sdk=iphonesimulator build_tree=~/ios-Build
  90. desc 'Build the generated project in its corresponding build tree'
  91. task :make do
  92. numjobs = ENV['numjobs'] || ''
  93. platform = 'native'
  94. cmake_build_options = ''
  95. build_options = ''
  96. unfilter = false
  97. ARGV.each { |option|
  98. task option.to_sym do ; end; Rake::Task[option].clear # No-op hack
  99. case option
  100. when 'codeblocks', 'eclipse', 'generic', 'macosx', 'make', 'ninja', 'vs2008', 'vs2010', 'vs2012', 'vs2013', 'vs2015'
  101. # do nothing
  102. when 'android', 'emscripten', 'ios', 'mingw', 'rpi'
  103. platform = option
  104. when 'clean_first'
  105. cmake_build_options = "#{cmake_build_options} --clean-first"
  106. when 'unfilter'
  107. unfilter = true
  108. else
  109. if /(?:config|target)=.*/ =~ option
  110. cmake_build_options = "#{cmake_build_options} --#{option.gsub(/=/, ' ')}"
  111. elsif /(?:build_tree|numjobs)=.*/ !~ option
  112. build_options = "#{build_options} #{/=/ =~ option ? '-' + option.gsub(/=/, ' ') : option}"
  113. end
  114. end
  115. }
  116. build_tree = ENV["#{platform}_build_tree"] || ENV['build_tree'] || "../#{platform}-Build"
  117. unless ENV['OS']
  118. ccache_envvar = ENV['CCACHE_SLOPPINESS'] ? '' : 'CCACHE_SLOPPINESS=pch_defines,time_macros' # Only attempt to do the right thing when user hasn't done it
  119. ccache_envvar = "#{ccache_envvar} CCACHE_COMPRESS=1" unless ENV['CCACHE_COMPRESS']
  120. end
  121. if !Dir.glob("#{build_tree}/*.xcodeproj").empty?
  122. # xcodebuild
  123. if !numjobs.empty?
  124. build_options = "-jobs #{numjobs}#{build_options}"
  125. end
  126. filter = !unfilter && system('xcpretty -v >/dev/null 2>&1') ? '|xcpretty -c && exit ${PIPESTATUS[0]}' : ''
  127. elsif !Dir.glob("#{build_tree}/*.sln").empty?
  128. # msbuild
  129. numjobs = ":#{numjobs}" unless numjobs.empty?
  130. build_options = "/maxcpucount#{numjobs}#{build_options}"
  131. filter = unfilter ? '' : '/nologo /verbosity:minimal'
  132. filter = filter + ' /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"' if ENV['APPVEYOR']
  133. elsif !Dir.glob("#{build_tree}/*.ninja").empty?
  134. # ninja
  135. if !numjobs.empty?
  136. build_options = "-j#{numjobs}#{build_options}"
  137. end
  138. filter = ''
  139. else
  140. # make
  141. if numjobs.empty?
  142. case RUBY_PLATFORM
  143. when /linux/
  144. numjobs = (platform == 'emscripten' ? `grep 'core id' /proc/cpuinfo |sort |uniq |wc -l` : `grep -c processor /proc/cpuinfo`).chomp
  145. when /darwin/
  146. numjobs = `sysctl -n hw.#{platform == 'emscripten' ? 'physical' : 'logical'}cpu`.chomp
  147. when /win32|mingw|mswin/
  148. require 'win32ole'
  149. WIN32OLE.connect('winmgmts://').ExecQuery("select NumberOf#{platform == 'emscripten' ? '' : 'Logical'}Processors from Win32_ComputerSystem").each { |out| numjobs = platform == 'emscripten' ? out.NumberOfProcessors : out.NumberOfLogicalProcessors }
  150. else
  151. numjobs = 1
  152. end
  153. end
  154. build_options = "-j#{numjobs}#{build_options}"
  155. filter = ''
  156. end
  157. system "cd \"#{build_tree}\" && #{ccache_envvar} cmake --build . #{cmake_build_options} -- #{build_options} #{filter}" or abort
  158. end
  159. # Usage: rake android [parameter='--es pickedLibrary Urho3DPlayer'] [intent=.SampleLauncher] [package=com.github.urho3d] [success_indicator='Initialized engine'] [payload='sleep 30'] [api=19] [abi=armeabi-v7a] [avd=test_#{api}_#{abi}] [retries=10] [retry_interval=10] [install]
  160. desc 'Test run APK in Android (virtual) device, default to Urho3D Samples APK if no parameter is given'
  161. task :android do
  162. parameter = ENV['parameter'] || '--es pickedLibrary Urho3DPlayer'
  163. intent = ENV['intent'] || '.SampleLauncher'
  164. package = ENV['package'] || 'com.github.urho3d'
  165. success_indicator = ENV['success_indicator'] || 'Initialized engine'
  166. payload = ENV['payload'] || 'sleep 30'
  167. api = ENV['api'] || 19
  168. abi = ENV['abi'] || 'armeabi-v7a'
  169. avd = ENV['avd'] || "test_#{api}_#{abi}"
  170. retries = ENV['retries'] || 10 # minutes
  171. retry_interval = ENV['retry_interval'] || 10 # seconds
  172. build_tree = ENV['android_build_tree'] || ENV['build_tree'] || '../android-Build'
  173. install = false
  174. ARGV.each { |option|
  175. task option.to_sym do ; end; Rake::Task[option].clear # No-op hack
  176. case option
  177. when 'install'
  178. install = true
  179. end
  180. }
  181. android_prepare_device api, abi, avd or abort 'Failed to prepare Android (virtual) device for test run'
  182. if install
  183. system "cd \"#{build_tree}\" && android update project -p . -t $(android list target |grep android-#{api} |cut -d ' ' -f2) && ant debug" or abort 'Failed to generate APK'
  184. end
  185. android_wait_for_device retries, retry_interval or abort 'Failed to start Android (virtual) device'
  186. if install
  187. system "cd \"#{build_tree}\" && ant -Dadb.device.arg='-s #{$specific_device}' installd" or abort 'Failed to install APK'
  188. end
  189. android_test_run parameter, intent, package, success_indicator, payload or abort "Failed to test run #{package}/#{intent}"
  190. end
  191. # Usage: NOT intended to be used manually
  192. desc 'Build and run the Annotate tool (temporary)'
  193. task :ci_annotate do
  194. system 'rake cmake URHO3D_CLANG_TOOLS=1 && rake make annotate' or abort 'Failed to annotate'
  195. system "git config user.name $GIT_NAME && git config user.email $GIT_EMAIL && git remote set-url --push origin https://[email protected]/$TRAVIS_REPO_SLUG.git && if git fetch origin clang-tools:clang-tools 2>/dev/null; then git push -qf origin --delete clang-tools; fi && git checkout -B clang-tools && git stash -q && git reset --hard HEAD~ && git stash pop -q && sed -i \"s/COVERITY_SCAN_THRESHOLD/URHO3D_PCH=0 URHO3D_BINDINGS=1 COVERITY_SCAN_THRESHOLD/g\" .travis.yml && git add -A .travis.yml Source/Urho3D && if git commit -qm 'Result of Annotator tool. [ci only: clang-tools]'; then git push -q -u origin clang-tools >/dev/null 2>&1; fi" or abort 'Failed to push clang-tools branch'
  196. end
  197. # Usage: NOT intended to be used manually
  198. desc 'Push the generated binding source files to clang-tools branch (temporary)'
  199. task :ci_push_bindings do
  200. abort "Skipped pushing to #{ENV['TRAVIS_BRANCH']} branch due to moving HEAD" unless `git fetch -qf origin #{ENV['TRAVIS_PULL_REQUEST'] == 'false' ? ENV['TRAVIS_BRANCH'] : %Q{+refs/pull/#{ENV['TRAVIS_PULL_REQUEST']}/head'}}; git log -1 --pretty=format:'%H' FETCH_HEAD` == ENV['TRAVIS_COMMIT']
  201. system "git config user.name $GIT_NAME && git config user.email $GIT_EMAIL && git remote set-url --push origin https://[email protected]/$TRAVIS_REPO_SLUG.git && git add -A Source/Urho3D && if git commit -qm 'Result of AutoBinder tool. [ci skip]'; then git push -q origin HEAD:#{ENV['TRAVIS_BRANCH']} >/dev/null 2>&1; fi" or abort "Failed to push #{ENV['TRAVIS_BRANCH']} branch"
  202. end
  203. # Usage: NOT intended to be used manually (if you insist then try: rake ci)
  204. desc 'Configure, build, and test Urho3D project'
  205. task :ci do
  206. # Skip if only performing CI for selected branches and the current branch is not in the list
  207. unless ENV['RELEASE_TAG']
  208. matched = /\[ci only:(.*?)\]/.match(ENV['COMMIT_MESSAGE'])
  209. next if matched && !matched[1].split(/[ ,]/).reject!(&:empty?).map { |i| /#{i}/ =~ ENV['TRAVIS_BRANCH'] }.any?
  210. end
  211. # Obtain our custom data, if any
  212. data = YAML::load(File.open(".travis.yml"))['data']
  213. data['excluded_sample'].each { |name| ENV["EXCLUDE_SAMPLE_#{name}"] = '1' } if data && data['excluded_sample']
  214. # Unshallow the clone's history when necessary
  215. if ENV['CI'] && ENV['PACKAGE_UPLOAD'] && !ENV['RELEASE_TAG']
  216. system 'git fetch --unshallow' or abort 'Failed to unshallow cloned repository'
  217. end
  218. # Packaging always use Release configuration
  219. if ENV['PACKAGE_UPLOAD']
  220. $configuration = 'Release'
  221. $testing = 0
  222. else
  223. $configuration = ENV['CI'] && ENV['USE_CCACHE'].to_i > 0 ? 'Release' : 'Debug' # Aways use a same build configuration to keep ccache's cache size small when on Travis CI
  224. # Only 64-bit Linux environment with virtual framebuffer X server support and not MinGW build; or OSX build environment and not iOS build; or Emscripten build environment are capable to run tests
  225. $testing = (ENV['LINUX'] && !ENV['URHO3D_64BIT']) || (ENV['OSX'] && ENV['IOS'].to_i != 1) || ENV['HTML5'] ? 1 : 0
  226. if $testing
  227. ENV['URHO3D_PREFIX_PATH'] = `pwd`.chomp + '/bin'
  228. end
  229. end
  230. # Define the build option string only when the override environment variable is given
  231. $build_options = "-DWIN32=#{ENV['WINDOWS']}" if ENV['WINDOWS']
  232. $build_options = "-DEMSCRIPTEN=#{ENV['HTML5']}" if ENV['HTML5']
  233. $build_options = "#{$build_options} -DANDROID_ABI=#{ENV['ABI']}" if ENV['ABI']
  234. $build_options = "#{$build_options} -DANDROID_NATIVE_API_LEVEL=#{ENV['API']}" if ENV['API']
  235. ['URHO3D_64BIT', 'URHO3D_LIB_TYPE', 'URHO3D_PCH', 'URHO3D_BINDINGS', 'URHO3D_OPENGL', 'URHO3D_D3D11', 'URHO3D_TEST_TIMEOUT', 'URHO3D_UPDATE_SOURCE_TREE', 'ANDROID', 'RPI', 'RPI_ABI', 'EMSCRIPTEN_SHARE_DATA', 'EMSCRIPTEN_EMRUN_BROWSER'].each { |var| $build_options = "#{$build_options} -D#{var}=\"#{ENV[var]}\"" if ENV[var] }
  236. if ENV['XCODE']
  237. # xcodebuild
  238. xcode_ci
  239. else
  240. # GCC or Clang
  241. makefile_ci
  242. end
  243. end
  244. # Usage: NOT intended to be used manually
  245. desc 'Setup build cache'
  246. task :ci_setup_cache do
  247. clear = /\[ccache clear\]/ =~ ENV['COMMIT_MESSAGE']
  248. # Use internal cache store instead of using Travis CI one (this is a workaround for using ccache on Travis CI legacy build infra)
  249. if ENV['USE_CCACHE'].to_i == 2
  250. puts 'Setting up build cache'
  251. job_number = ".#{ENV['TRAVIS_JOB_NUMBER'].split('.').last}"
  252. repo_slug = "#{ENV['TRAVIS_REPO_SLUG'].split('/').first}/cache-store.git"
  253. matched = /.*-([^-]+-[^-]+)$/.match(ENV['TRAVIS_BRANCH'])
  254. base_mirror = matched ? matched[1] : nil
  255. # Do not abort even when it fails here
  256. system "if ! `git clone -q --depth 1 --branch #{ENV['TRAVIS_BRANCH']}#{job_number} https://github.com/#{repo_slug} ~/.ccache 2>/dev/null`; then if ! [ #{base_mirror} ] || ! `git clone -q --depth 1 --branch #{base_mirror}#{job_number} https://github.com/#{repo_slug} ~/.ccache 2>/dev/null`; then git clone -q --depth 1 https://github.com/#{repo_slug} ~/.ccache 2>/dev/null; fi && cd ~/.ccache && git checkout -qf -b #{ENV['TRAVIS_BRANCH']}#{job_number}; fi"
  257. # Preserving .git directory before clearing the cache on Linux host system (ccache on Mac OSX does not have this problem)
  258. `mv ~/.ccache/.git /tmp` if clear && ENV['OSX'].to_i != 1
  259. end
  260. # Clear ccache on demand
  261. system "ccache -z -M #{ENV['CCACHE_MAXSIZE']} #{clear ? '-C' : ''}"
  262. # Restoring .git directory if its backup exists
  263. `if [ -e /tmp/.git ]; then mv /tmp/.git ~/.ccache; fi`
  264. end
  265. # Usage: NOT intended to be used manually
  266. desc 'Teardown build cache'
  267. task :ci_teardown_cache do
  268. # Upload cache to internal cache store if it is our own
  269. if ENV['USE_CCACHE'].to_i == 2
  270. puts 'Storing build cache'
  271. job_number = ".#{ENV['TRAVIS_JOB_NUMBER'].split('.').last}"
  272. repo_slug = "#{ENV['TRAVIS_REPO_SLUG'].split('/').first}/cache-store.git"
  273. # Do not abort even when it fails here
  274. system "cd ~/.ccache && git config user.name $GIT_NAME && git config user.email $GIT_EMAIL && git remote set-url --push origin https://[email protected]/#{repo_slug} && git add -A . && git commit --amend -qm 'Travis CI: cache update at #{Time.now.utc}.' && git push -qf -u origin #{ENV['TRAVIS_BRANCH']}#{job_number} >/dev/null 2>&1"
  275. end
  276. system 'ccache -s'
  277. end
  278. # Usage: NOT intended to be used manually
  279. desc 'Update site documentation to GitHub Pages'
  280. task :ci_site_update do
  281. # Skip when :ci rake task was skipped
  282. next unless File.exist?('../Build/CMakeCache.txt')
  283. # Pull or clone
  284. system 'cd ../doc-Build 2>/dev/null && git pull -q -r || git clone --depth 1 -q https://github.com/urho3d/urho3d.github.io.git ../doc-Build' or abort 'Failed to pull/clone'
  285. # Update credits from README.md to about.yml
  286. system "ruby -lne 'BEGIN { credits = false }; puts $_ if credits; credits = true if /bugfixes by:/; credits = false if /^$/' README.md |ruby -i -le 'credits = STDIN.read; puts ARGF.read.gsub(/(?<=contributors:\n).*?\n\n/m, credits)' ../doc-Build/_data/about.yml" or abort 'Failed to update credits'
  287. # Setup doxygen to use minimal theme
  288. system "ruby -i -pe 'BEGIN { a = {%q{HTML_HEADER} => %q{minimal-header.html}, %q{HTML_FOOTER} => %q{minimal-footer.html}, %q{HTML_STYLESHEET} => %q{minimal-doxygen.css}, %q{HTML_COLORSTYLE_HUE} => 200, %q{HTML_COLORSTYLE_SAT} => 0, %q{HTML_COLORSTYLE_GAMMA} => 20, %q{DOT_IMAGE_FORMAT} => %q{svg}, %q{INTERACTIVE_SVG} => %q{YES}} }; a.each {|k, v| gsub(/\#{k}\s*?=.*?\n/, %Q{\#{k} = \#{v}\n}) }' ../Build/Docs/generated/Doxyfile" or abort 'Failed to setup doxygen configuration file'
  289. system 'cp ../doc-Build/_includes/Doxygen/minimal-* ../Build/Docs' or abort 'Failed to copy minimal-themed template'
  290. release = ENV['RELEASE_TAG'] || 'HEAD'
  291. unless release == 'HEAD'
  292. system "mkdir -p ../doc-Build/documentation/#{release}" or abort 'Failed to create directory for new document version'
  293. system "ruby -i -pe 'gsub(/HEAD/, %q{#{release}})' ../Build/Docs/minimal-header.html" or abort 'Failed to update document version in YAML Front Matter block'
  294. append_new_release release or abort 'Failed to add new release to document data file'
  295. end
  296. # Generate and sync doxygen pages
  297. system "cd ../Build && make -j$NUMJOBS doc >/dev/null 2>&1 && ruby -i -pe 'gsub(/(<\\/?h)3([^>]*?>)/, %q{\\14\\2}); gsub(/(<\\/?h)2([^>]*?>)/, %q{\\13\\2}); gsub(/(<\\/?h)1([^>]*?>)/, %q{\\12\\2})' Docs/html/_*.html && rsync -a --delete Docs/html/ ../doc-Build/documentation/#{release}" or abort 'Failed to generate/rsync doxygen pages'
  298. # Supply GIT credentials and push site documentation to urho3d/urho3d.github.io.git
  299. system "cd ../doc-Build && pwd && git config user.name $GIT_NAME && git config user.email $GIT_EMAIL && git remote set-url --push origin https://[email protected]/urho3d/urho3d.github.io.git && git add -A . && ( git commit -qm \"Travis CI: site documentation update at #{Time.now.utc}.\n\nCommit: https://github.com/$TRAVIS_REPO_SLUG/commit/$TRAVIS_COMMIT\n\nMessage: $COMMIT_MESSAGE\" || true) && git push -q >/dev/null 2>&1" or abort 'Failed to update site'
  300. unless ENV['RELEASE_TAG'] || `git fetch -qf origin #{ENV['TRAVIS_BRANCH']}; git log -1 --pretty=format:'%H' FETCH_HEAD` != ENV['TRAVIS_COMMIT']
  301. # Supply GIT credentials and push API documentation to urho3d/Urho3D.git (only when changes are detected)
  302. system 'pwd && git config user.name $GIT_NAME && git config user.email $GIT_EMAIL && git remote set-url --push origin https://[email protected]/$TRAVIS_REPO_SLUG.git && git add Docs/*API*'
  303. if system("git commit -qm 'Test commit to detect API changes'")
  304. # Automatically give instruction to do packaging when API has changed, unless the instruction is already given in this commit
  305. bump_soversion 'Source/Urho3D/.soversion' or abort 'Failed to bump soversion'
  306. system "git add Source/Urho3D/.soversion && git commit --amend -qm \"Travis CI: API documentation update at #{Time.now.utc}.\n#{ENV['PACKAGE_UPLOAD'] ? '' : '[ci package]'}\n\nCommit: https://github.com/$TRAVIS_REPO_SLUG/commit/$TRAVIS_COMMIT\n\nMessage: $COMMIT_MESSAGE\"" or abort 'Failed to stage .soversion file'
  307. system "git push origin HEAD:#{ENV['TRAVIS_BRANCH']} -q >/dev/null 2>&1" or abort 'Failed to update API documentation'
  308. end
  309. end
  310. end
  311. # Usage: NOT intended to be used manually
  312. desc 'Update Emscripten HTML5 samples to GitHub Pages'
  313. task :ci_emscripten_samples_update do
  314. puts "\nUpdating Emscripten samples in main website..."
  315. # Pull or clone
  316. system 'cd ../doc-Build 2>/dev/null && git pull -q -r || git clone --depth 1 -q https://github.com/urho3d/urho3d.github.io.git ../doc-Build' or abort 'Failed to pull/clone'
  317. # Sync Emscripten samples
  318. system "rsync -a --delete --exclude tool ../Build/bin/ ../doc-Build/samples" or abort 'Failed to rsync Emscripten samples'
  319. # Update Emscripten json data file
  320. update_emscripten_data or abort 'Failed to update Emscripten json data file'
  321. root_commit, _ = get_root_commit_and_recipients
  322. system "cd ../doc-Build && git config user.name $GIT_NAME && git config user.email $GIT_EMAIL && git remote set-url --push origin https://[email protected]/urho3d/urho3d.github.io.git && git add -A . && ( git commit -qm \"Travis CI: Emscripten samples update at #{Time.now.utc}.\n\nCommit: https://github.com/$TRAVIS_REPO_SLUG/commit/#{root_commit}\n\nMessage: #{`git log --format=%B -n 1 #{root_commit}`}\" || true) && git push -q >/dev/null 2>&1" or abort 'Failed to update Emscripten samples'
  323. end
  324. # Usage: NOT intended to be used manually
  325. desc 'Create all CI mirror branches'
  326. task :ci_create_mirrors do
  327. # Skip if there are more commits since this one
  328. abort 'Skipped creating mirror branches due to moving HEAD' unless `git fetch -qf origin #{ENV['TRAVIS_PULL_REQUEST'] == 'false' ? ENV['TRAVIS_BRANCH'] : %Q{+refs/pull/#{ENV['TRAVIS_PULL_REQUEST']}/head'}}; git log -1 --pretty=format:'%H' FETCH_HEAD` == ENV['TRAVIS_COMMIT']
  329. system 'git config user.name $GIT_NAME && git config user.email $GIT_EMAIL && git remote set-url --push origin https://[email protected]/$TRAVIS_REPO_SLUG.git'
  330. # Limit the scanning to only master branch and limit the frequency of scanning
  331. scan = ENV['TRAVIS_BRANCH'] == 'master' && ((/\[ccache clear\]/ !~ ENV['COMMIT_MESSAGE'] && `ccache -s |grep 'cache miss'`.split.last.to_i >= ENV['COVERITY_SCAN_THRESHOLD'].to_i) || /\[ci scan\]/ =~ ENV['COMMIT_MESSAGE'])
  332. # Check if it is time to generate annotation
  333. annotate = ENV['TRAVIS_BRANCH'] == 'master' && (ENV['PACKAGE_UPLOAD'] || /\[ci annotate\]/ =~ ENV['COMMIT_MESSAGE'])
  334. # Determine which CI mirror branches to be auto created
  335. unless ENV['RELEASE_TAG']
  336. matched = /\[ci only:(.*?)\]/.match(ENV['COMMIT_MESSAGE'])
  337. ci_only = matched ? matched[1].split(/[ ,]/).reject!(&:empty?) : nil
  338. if ci_only
  339. ci_only.push('Coverity-Scan') if scan
  340. ci_only.push('Annotate') if annotate
  341. end
  342. else
  343. ci_only = nil
  344. end
  345. # Obtain the whole stream and process the rest of documents except the first one since travis-build does not do that at the moment
  346. stream = YAML::load_stream(File.open('.travis.yml'))
  347. notifications = stream[0]['notifications']
  348. notifications['email']['recipients'] = get_root_commit_and_recipients().last unless notifications['email']['recipients']
  349. stream.drop(1).each { |doc| branch = doc.delete('branch'); ci = branch['name']; ci_branch = ENV['RELEASE_TAG'] || (ENV['TRAVIS_BRANCH'] == 'master' && ENV['TRAVIS_PULL_REQUEST'] == 'false') ? ci : (ENV['TRAVIS_PULL_REQUEST'] == 'false' ? "#{ENV['TRAVIS_BRANCH']}-#{ci}" : "PR ##{ENV['TRAVIS_PULL_REQUEST']}-#{ci}"); unless (ci_only && ci_only.map { |i| /#{i}/ =~ ci }.any?) || (!ci_only && (branch['active'] || (scan && /Scan/ =~ ci) || (annotate && /Annotate/ =~ ci))); system "if git fetch origin #{ci_branch}:#{ci_branch} 2>/dev/null; then git push -qf origin --delete #{ci_branch}; fi"; next; end; lastjob = doc['matrix'] && doc['matrix']['include'] ? doc['matrix']['include'].length : (doc['env']['matrix'] ? doc['env']['matrix'].length : 1); doc['after_script'] = [*doc['after_script']] << (lastjob == 1 ? '%s' : "if [ ${TRAVIS_JOB_NUMBER##*.} == #{lastjob} ]; then %s; fi") % 'rake ci_delete_mirror'; doc['notifications'] = notifications unless doc['notifications']; File.open('.travis.yml.doc', 'w') { |file| file.write doc.to_yaml }; system "git checkout -B #{ci_branch} && rm .travis.yml && mv .travis.yml.doc .travis.yml && git add -A . && git commit -qm '#{ENV['COMMIT_MESSAGE']}' && git push -qf -u origin #{ci_branch} >/dev/null 2>&1 && git checkout -q -" or abort "Failed to create #{ci_branch} mirror branch" }
  350. end
  351. # Usage: NOT intended to be used manually
  352. desc 'Delete CI mirror branch'
  353. task :ci_delete_mirror do
  354. # Skip if there are more commits since this one or if this is a release build
  355. matched = /(.*)-[^-]+-[^-]+$/.match(ENV['TRAVIS_BRANCH'])
  356. base_branch = matched ? matched[1] : 'master' # Assume 'master' is the default branch name
  357. abort "Skipped deleting #{ENV['TRAVIS_BRANCH']} mirror branch" unless `git fetch -qf origin #{/^PR #/ =~ base_branch ? %Q{+refs/pull/#{ENV['TRAVIS_PULL_REQUEST']}/merge'} : base_branch}; git log -1 --pretty=format:'%H' FETCH_HEAD` == `git show -s --format='%H' #{ENV['TRAVIS_COMMIT']}`.rstrip && !ENV['RELEASE_TAG']
  358. system 'git config user.name $GIT_NAME && git config user.email $GIT_EMAIL && git remote set-url --push origin https://[email protected]/$TRAVIS_REPO_SLUG.git'
  359. system "git push -qf origin --delete #{ENV['TRAVIS_BRANCH']}" or abort "Failed to delete #{ENV['TRAVIS_BRANCH']} mirror branch"
  360. end
  361. # Usage: NOT intended to be used manually
  362. desc 'Make binary package and upload it to a designated central hosting server'
  363. task :ci_package_upload do
  364. # Skip when :ci rake task was skipped
  365. next unless File.exist?('../Build/CMakeCache.txt')
  366. if ENV['XCODE']
  367. $configuration = 'Release'
  368. $testing = 0
  369. end
  370. # Generate the documentation if necessary
  371. if ENV['SITE_UPDATE']
  372. if File.exist?('.site_updated')
  373. # Skip if site is already updated before
  374. ENV['SITE_UPDATE'] = nil
  375. end
  376. else
  377. system 'echo Generating documentation...'
  378. if ENV['XCODE']
  379. xcode_build(ENV['IOS'], '../Build/Urho3D.xcodeproj', 'doc', '>/dev/null') or abort 'Failed to generate documentation'
  380. else
  381. system 'cd ../Build && make -j$NUMJOBS doc >/dev/null' or abort 'Failed to generate documentation'
  382. end
  383. end
  384. # Make the package
  385. if ENV['IOS']
  386. # Skip Mach-O universal binary build if Travis-CI VM took too long to get here, as otherwise overall build time may exceed 50 minutes time limit
  387. if ENV['CI_START_TIME'] then
  388. elapsed_time = (Time.now - Time.at(ENV['CI_START_TIME'].to_i)) / 60
  389. puts "\niOS checkpoint reached, elapsed time: #{elapsed_time}\n\n"
  390. end
  391. if !ENV['CI_START_TIME'] || elapsed_time < 25 # minutes
  392. # Build Mach-O universal binary consisting of iphoneos (universal ARM archs including 'arm64' if 64-bit is enabled) and iphonesimulator (i386 arch and also x86_64 arch if 64-bit is enabled)
  393. system 'echo Rebuilding Urho3D library as Mach-O universal binary...'
  394. xcode_build(0, '../Build/Urho3D.xcodeproj', 'Urho3D_universal') or abort 'Failed to build Mach-O universal binary'
  395. end
  396. # There is a bug in CMake/CPack that causes the 'package' target failed to build for IOS platform, workaround by calling cpack directly
  397. system 'cd ../Build && cpack -G TGZ 2>/dev/null' or abort 'Failed to make binary package'
  398. elsif ENV['XCODE']
  399. xcode_build(ENV['IOS'], '../Build/Urho3D.xcodeproj', 'package') or abort 'Failed to make binary package'
  400. else
  401. if ENV['ANDROID'] && !ENV['NO_SDK_SYSIMG']
  402. system "cd ../Build && android update project -p . -t $(android list target |grep android-$API |cut -d ' ' -f2) && ant debug" or abort 'Failed to make Urho3D Samples APK'
  403. end
  404. if ENV['URHO3D_USE_LIB64_RPM']
  405. system "cd ../Build && cmake . -DURHO3D_USE_LIB64_RPM=#{ENV['URHO3D_USE_LIB64_RPM']}" or abort 'Failed to reconfigure to generate 64-bit RPM package'
  406. end
  407. wrapper = ENV['URHO3D_64BIT'] || ENV['RPI'] ? 'setarch i686' : ''
  408. system "cd ../Build && #{wrapper} make package" or abort 'Failed to make binary package'
  409. end
  410. # Determine the upload location
  411. setup_digital_keys
  412. unless ENV['RELEASE_TAG']
  413. upload_dir = "/home/frs/project/#{ENV['TRAVIS_REPO_SLUG']}/Snapshots"
  414. if ENV['SITE_UPDATE']
  415. # Download source packages from GitHub
  416. system "export SNAPSHOT_VER=$(git describe $TRAVIS_COMMIT |ruby -pe 'gsub(/-(?!g)/, %q{.})'); wget -q https://github.com/$TRAVIS_REPO_SLUG/tarball/$TRAVIS_COMMIT -O Urho3D-$SNAPSHOT_VER-Source-snapshot.tar.gz && wget -q https://github.com/$TRAVIS_REPO_SLUG/zipball/$TRAVIS_COMMIT -O Urho3D-$SNAPSHOT_VER-Source-snapshot.zip" or abort 'Failed to get source packages'
  417. # Only keep the snapshots from the last 30 revisions
  418. system "for v in $(sftp [email protected] <<EOF |tr ' ' '\n' |grep Urho3D- |cut -d '-' -f1,2 |uniq |tail -n +31
  419. cd #{upload_dir}
  420. ls -1r
  421. bye
  422. EOF
  423. ); do echo rm #{upload_dir}/${v}*; done |sftp -b - [email protected] >/dev/null 2>&1" or abort 'Failed to housekeep snapshots'
  424. end
  425. else
  426. upload_dir = "/home/frs/project/#{ENV['TRAVIS_REPO_SLUG']}/#{ENV['RELEASE_TAG']}"
  427. if ENV['SITE_UPDATE']
  428. # Download source packages from GitHub
  429. system 'wget -q https://github.com/$TRAVIS_REPO_SLUG/archive/$RELEASE_TAG.tar.gz -O Urho3D-$RELEASE_TAG-Source.tar.gz && wget -q https://github.com/$TRAVIS_REPO_SLUG/archive/$RELEASE_TAG.zip -O Urho3D-$RELEASE_TAG-Source.zip' or abort 'Failed to get source packages'
  430. end
  431. # Make sure the release directory exists remotely, do this in all the build jobs as we don't know which one would start uploading first
  432. system "sftp [email protected] <<EOF >/dev/null 2>&1
  433. mkdir #{upload_dir}
  434. bye
  435. EOF" or abort 'Failed to create release directory remotely'
  436. end
  437. if ENV['SITE_UPDATE']
  438. # Upload the source package
  439. system "scp Urho3D-* [email protected]:#{upload_dir}" or abort 'Failed to upload source package'
  440. if ENV['RELEASE_TAG']
  441. # Mark the source tarball as default download for host systems other than Windows/Mac/Linux
  442. system "curl -H 'Accept: application/json' -X PUT -d 'default=bsd&default=solaris&default=others' -d \"api_key=$SF_API\" https://sourceforge.net/projects/%s/files/%s/#{ENV['RELEASE_TAG']}/Urho3D-#{ENV['RELEASE_TAG']}-Source.tar.gz" % ENV['TRAVIS_REPO_SLUG'].split('/') or abort 'Failed to set source tarball as default download'
  443. end
  444. # Sync readme and license files, just in case they are updated in the repo
  445. system 'for f in README.md License.txt; do mtime=$(git log --format=%ai -n1 $f); touch -d "$mtime" $f; done' or abort 'Failed to acquire file modified time'
  446. system 'rsync -e ssh -az README.md License.txt [email protected]:/home/frs/project/$TRAVIS_REPO_SLUG' or abort 'Failed to sync readme and license files'
  447. # Mark that the site has been updated
  448. File.open('.site_updated', 'w') {}
  449. end
  450. # Upload the binary package
  451. system "scp ../Build/Urho3D-* [email protected]:#{upload_dir} && rm ../Build/Urho3D-*" or abort 'Failed to upload binary package'
  452. if ENV['RELEASE_TAG'] && ENV['SF_DEFAULT']
  453. # Mark the corresponding binary package as default download for each Windows/Mac/Linux host systems
  454. system "curl -H 'Accept: application/json' -X PUT -d 'default=%s' -d \"api_key=$SF_API\" https://sourceforge.net/projects/%s/files/%s/#{ENV['RELEASE_TAG']}/Urho3D-#{ENV['RELEASE_TAG']}-%s" % ENV['SF_DEFAULT'].split(':').insert(1, ENV['TRAVIS_REPO_SLUG'].split('/')).flatten or abort 'Failed to set binary tarball/zip as default download'
  455. end
  456. end
  457. def scaffolding dir, project = 'Scaffolding', target = 'Main'
  458. build_script = <<EOF
  459. # Set project name
  460. project (#{project})
  461. # Set minimum version
  462. cmake_minimum_required (VERSION 2.8.6)
  463. if (COMMAND cmake_policy)
  464. cmake_policy (SET CMP0003 NEW)
  465. if (CMAKE_VERSION VERSION_GREATER 2.8.12 OR CMAKE_VERSION VERSION_EQUAL 2.8.12)
  466. # INTERFACE_LINK_LIBRARIES defines the link interface
  467. cmake_policy (SET CMP0022 NEW)
  468. endif ()
  469. if (CMAKE_VERSION VERSION_GREATER 3.0.0 OR CMAKE_VERSION VERSION_EQUAL 3.0.0)
  470. # Disallow use of the LOCATION target property - therefore we set to OLD as we still need it
  471. cmake_policy (SET CMP0026 OLD)
  472. # MACOSX_RPATH is enabled by default
  473. cmake_policy (SET CMP0042 NEW)
  474. endif ()
  475. endif ()
  476. # Set CMake modules search path
  477. set (CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake/Modules)
  478. # Include Urho3D CMake common module
  479. include (Urho3D-CMake-common)
  480. # Find Urho3D library
  481. find_package (Urho3D REQUIRED)
  482. include_directories (${URHO3D_INCLUDE_DIRS})
  483. # Define target name
  484. set (TARGET_NAME #{target})
  485. # Define source files
  486. define_source_files ()
  487. # Setup target with resource copying
  488. setup_main_executable ()
  489. # Setup test cases
  490. if (URHO3D_ANGELSCRIPT)
  491. setup_test (NAME ExternalLibAS OPTIONS Scripts/12_PhysicsStressTest.as -w)
  492. endif ()
  493. if (URHO3D_LUA)
  494. setup_test (NAME ExternalLibLua OPTIONS LuaScripts/12_PhysicsStressTest.lua -w)
  495. endif ()
  496. EOF
  497. # TODO: Rewrite in pure Ruby when it supports symlink creation on Windows platform
  498. if ENV['OS']
  499. system("@echo off && mkdir '#{dir}'\\bin && copy Source\\Tools\\Urho3DPlayer\\Urho3DPlayer.* '#{dir}' >nul && (for %f in (*.bat Rakefile) do mklink '#{dir}'\\%f %cd%\\%f >nul) && mklink /D '#{dir}'\\CMake %cd%\\CMake && (for %d in (CoreData,Data) do mklink /D '#{dir}'\\bin\\%d %cd%\\bin\\%d >nul)") && File.write("#{dir}/CMakeLists.txt", build_script) or abort 'Failed to create new project using Urho3D as external library'
  500. else
  501. system("bash -c \"mkdir -p '#{dir}'/bin && cp Source/Tools/Urho3DPlayer/Urho3DPlayer.* '#{dir}' && for f in {.,}*.sh Rakefile CMake; do ln -sf `pwd`/\\$f '#{dir}'; done && ln -sf `pwd`/bin/{Core,}Data '#{dir}'/bin\"") && File.write("#{dir}/CMakeLists.txt", build_script) or abort 'Failed to create new project using Urho3D as external library'
  502. end
  503. end
  504. def makefile_ci
  505. if (ENV['WINDOWS'] && ENV['TRAVIS']) || (ENV['ANDROID'] && ENV['ABI'] == 'arm64-v8a') || ENV['HTML5']
  506. # LuaJIT on MinGW build is not possible on Travis-CI with Ubuntu 12.04 LTS as its GCC cross-compiler version is too old
  507. # The upstream LuaJIT library does not support Android arm64-v8a ABI at the moment
  508. # LuaJIT on Emscripten is not possible
  509. # Fallback to use Lua library instead
  510. jit = ''
  511. amalg = ''
  512. else
  513. jit = 'JIT'
  514. amalg = '-DURHO3D_LUAJIT_AMALG=1'
  515. end
  516. system "./cmake_generic.sh ../Build #{$build_options} -DURHO3D_DATABASE_SQLITE=1 -DURHO3D_LUA#{jit}=1 #{amalg} -DURHO3D_SAMPLES=1 -DURHO3D_TOOLS=1 -DURHO3D_EXTRAS=1 -DURHO3D_TESTING=#{$testing} -DCMAKE_BUILD_TYPE=#{$configuration}" or abort 'Failed to configure Urho3D library build'
  517. if ENV['AVD'] && !ENV['PACKAGE_UPLOAD'] # Skip APK test run when packaging
  518. android_prepare_device ENV['API'], ENV['ABI'], ENV['AVD'] or abort 'Failed to prepare Android (virtual) device for test run'
  519. end
  520. # Temporarily put the logic here for clang-tools migration until everything else are in their places
  521. if ENV['URHO3D_BINDINGS']
  522. system "cd ../Build && make -j$NUMJOBS" or abort 'Failed to build or test Urho3D library with annotated source files'
  523. system 'rake ci_push_bindings' or abort
  524. return 0
  525. end
  526. # For Emscripten CI build, skip make test and/or scaffolding test if CI VM took too long to get here, as otherwise overall build time may exceed 50 minutes time limit
  527. test = $testing == 1 ? '&& make test' : ''
  528. system "cd ../Build && make -j$NUMJOBS #{test}" or abort 'Failed to build or test Urho3D library'
  529. unless ENV['CI'] && ENV['HTML5'] && ENV['PACKAGE_UPLOAD'] # For Emscripten, skip scaffolding test when packaging
  530. # Create a new project on the fly that uses newly built Urho3D library in the build tree
  531. scaffolding "../Build/generated/UsingBuildTree"
  532. system "cd ../Build/generated/UsingBuildTree && echo '\nExternal project referencing Urho3D library in its build tree' && ./cmake_generic.sh . #{$build_options} -DURHO3D_HOME=../.. -DURHO3D_LUA#{jit}=1 -DURHO3D_TESTING=#{$testing} -DCMAKE_BUILD_TYPE=#{$configuration} && make -j$NUMJOBS #{test}" or abort 'Failed to configure/build/test temporary project using Urho3D as external library'
  533. ENV['DESTDIR'] = ENV['HOME'] || Dir.home
  534. puts "\nInstalling Urho3D SDK to #{ENV['DESTDIR']}/usr/local...\n" # The default CMAKE_INSTALL_PREFIX is /usr/local
  535. system 'cd ../Build && make -j$NUMJOBS install >/dev/null' or abort 'Failed to install Urho3D SDK'
  536. # Create a new project on the fly that uses newly installed Urho3D SDK
  537. scaffolding "../Build/generated/UsingSDK"
  538. system "export URHO3D_HOME=~/usr/local && cd ../Build/generated/UsingSDK && echo '\nExternal project referencing Urho3D SDK' && ./cmake_generic.sh . #{$build_options} -DURHO3D_LUA#{jit}=1 -DURHO3D_TESTING=#{$testing} -DCMAKE_BUILD_TYPE=#{$configuration} && make -j$NUMJOBS #{test}" or abort 'Failed to configure/build/test temporary project using Urho3D as external library'
  539. end
  540. # Make, deploy, and test run Android APK in an Android (virtual) device
  541. if ENV['AVD'] && !ENV['PACKAGE_UPLOAD']
  542. system "echo '\nTest deploying and running Urho3D Samples APK...' && cd ../Build && android update project -p . -t $( android list target |grep android-$API |cut -d ' ' -f2 ) && ant debug" or abort 'Failed to make Urho3D Samples APK'
  543. if android_wait_for_device
  544. system "cd ../Build && ant -Dadb.device.arg='-s #{$specific_device}' installd" or abort 'Failed to deploy Urho3D Samples APK'
  545. android_test_run or abort 'Failed to test run Urho3D Samples APK'
  546. else
  547. puts 'Skipped test running Urho3D Samples APK as emulator failed to start in time'
  548. end
  549. end
  550. end
  551. def get_root_commit_and_recipients
  552. # Root commit is a commit submitted by human
  553. root_commit = `git show -s --format='%H' #{ENV['TRAVIS_COMMIT']}`.rstrip
  554. recipients = `git show -s --format='%ae %ce' #{root_commit}`.chomp.split.uniq
  555. if recipients.include? '[email protected]'
  556. matched = /Commit:.*commit\/(.*?)\n/.match(ENV['COMMIT_MESSAGE'])
  557. if (matched)
  558. root_commit = matched[1]
  559. recipients = `git show -s --format='%ae %ce' #{root_commit}`.chomp.split.uniq
  560. end
  561. end
  562. return root_commit, recipients
  563. end
  564. def android_find_device api = nil, abi = nil
  565. # Return the previously found matching device or if not found yet then try to find the matching device now
  566. return $specific_device if $specific_device
  567. $specific_api = api.to_s if api
  568. $specific_abi = abi.to_s if abi
  569. loop do
  570. for i in `adb devices |tail -n +2`.split "\n"
  571. device = i.split.first
  572. if `adb -s #{device} wait-for-device shell getprop ro.build.version.sdk`.chomp == $specific_api && `adb -s #{device} shell getprop ro.product.cpu.abi`.chomp == $specific_abi
  573. return $specific_device = device
  574. end
  575. end
  576. break if api
  577. end
  578. nil
  579. end
  580. def android_prepare_device api, abi = 'armeabi-v7a', name = 'test'
  581. system 'if ! ps |grep -cq adb; then adb start-server; fi'
  582. if !android_find_device api, abi
  583. # Don't have any matching (virtual) device attached, try to attach the named device (create the named device as AVD if necessary)
  584. if !system "android list avd |grep -cq 'Name: #{name}$'"
  585. system "echo 'no' |android create avd -n #{name} -t android-#{api} --abi #{abi}" or abort "Failed to create '#{name}' Android virtual device"
  586. end
  587. system "if [ $CI ]; then export OPTS='-no-skin -no-audio -no-window -no-boot-anim -gpu off'; else export OPTS='-gpu on'; fi; emulator -avd #{name} $OPTS &"
  588. end
  589. return 0
  590. end
  591. def android_wait_for_device retries = -1, retry_interval = 10, package = 'android.process.acore' # Waiting for HOME by default
  592. # Wait until the indicator process is running or it is killed externally by user via Ctrl+C or when it exceeds the number of retries (if the retries parameter is provided)
  593. str = "\nWaiting for device..."
  594. thread = Thread.new { android_find_device }; sleep 0.5
  595. process_ready = false
  596. retries = retries * 60 / retry_interval unless retries == -1
  597. until retries == 0
  598. if thread.status == false
  599. thread.join
  600. break if process_ready
  601. process_ready = thread = Thread.new { `adb -s #{$specific_device} shell 'until ps |grep -c #{package} >/dev/null; do sleep #{retry_interval}; done; while ps |grep -c bootanimation >/dev/null; do sleep 1; done'` }; sleep 0.5
  602. next
  603. end
  604. print str; str = '.'; $stdout.flush # Flush the standard output stream in case it is buffered to prevent Travis-CI into thinking that the build/test has stalled
  605. sleep retry_interval
  606. retries -= 1 if retries > 0
  607. end
  608. puts "\n\n" if str == '.'; $stdout.flush
  609. return retries == 0 ? nil : 0
  610. end
  611. def android_test_run parameter = '--es pickedLibrary Urho3DPlayer', intent = '.SampleLauncher', package = 'com.github.urho3d', success_indicator = 'Added resource path /apk/CoreData/', payload = 'sleep 30'
  612. # The device should have been found at this point
  613. return nil unless $specific_device
  614. # Capture adb's stdout and interpret it because adb neither uses stderr nor returns proper exit code on error
  615. begin
  616. IO.popen("adb -s #{$specific_device} shell <<EOF
  617. # Try to unlock the device just in case it is locked
  618. input keyevent 82; input keyevent 4
  619. # Clear the log
  620. logcat -c
  621. # Start the app
  622. am start -a android.intent.action.MAIN -n #{package}/#{intent} #{parameter}
  623. # Wait until the process is running
  624. until ps |grep -c #{package} 1>/dev/null; do sleep 1; done
  625. # Execute the payload
  626. #{payload}
  627. # Exit and stop the app
  628. input keyevent 4 && am force-stop #{package}
  629. # Dump the log
  630. logcat -d
  631. # Bye bye
  632. exit
  633. ##
  634. EOF") { |stdout| echo = false; while output = stdout.gets do if echo && /#\s#/ !~ output then puts output else echo = true if /^##/ =~ output end; return nil if /^error/i =~ output end }
  635. # Result of the test run is determined based on the presence of the success indicator string in the log
  636. system "adb -s #{$specific_device} logcat -d |grep -cq '#{success_indicator}'"
  637. rescue
  638. nil
  639. end
  640. end
  641. def wait_for_block comment = '', retries = -1, retry_interval = 60, exit_code_sym = 'exit_code', &block
  642. # Wait until the code block is completed or it is killed externally by user via Ctrl+C or when it exceeds the number of retries (if the retries parameter is provided)
  643. thread = Thread.new &block
  644. str = comment
  645. retries = retries * 60 / retry_interval unless retries == -1
  646. until retries == 0
  647. if thread.status == false
  648. thread.join
  649. break
  650. end
  651. print str; str = '.'; $stdout.flush # Flush the standard output stream in case it is buffered to prevent Travis-CI into thinking that the build/test has stalled
  652. sleep retry_interval
  653. retries -= 1 if retries > 0
  654. end
  655. puts "\n" if str == '.'; $stdout.flush
  656. return retries == 0 ? nil : (exit_code_sym ? thread[exit_code_sym] : 0)
  657. end
  658. def xcode_ci
  659. if ENV['IOS']
  660. # IOS platform does not support LuaJIT
  661. jit = ''
  662. amalg = ''
  663. deployment_target = "-DIPHONEOS_DEPLOYMENT_TARGET=#{ENV['DEPLOYMENT_TARGET']}"
  664. else
  665. jit = 'JIT'
  666. amalg = '-DURHO3D_LUAJIT_AMALG=1'
  667. deployment_target = "-DCMAKE_OSX_DEPLOYMENT_TARGET=#{ENV['DEPLOYMENT_TARGET']}"
  668. end
  669. system "./cmake_macosx.sh ../Build -DIOS=$IOS #{deployment_target} #{$build_options} -DURHO3D_DATABASE_SQLITE=1 -DURHO3D_LUA#{jit}=1 #{amalg} -DURHO3D_SAMPLES=1 -DURHO3D_TOOLS=1 -DURHO3D_EXTRAS=1 -DURHO3D_TESTING=#{$testing}" or abort 'Failed to configure Urho3D library build'
  670. xcode_build(ENV['IOS'], '../Build/Urho3D.xcodeproj') or abort 'Failed to build or test Urho3D library'
  671. unless ENV['CI'] && ENV['IOS'] && ENV['PACKAGE_UPLOAD'] # Skip scaffolding test when packaging for iOS
  672. # Create a new project on the fly that uses newly built Urho3D library in the build tree
  673. scaffolding "../Build/generated/UsingBuildTree"
  674. system "cd ../Build/generated/UsingBuildTree && echo '\nExternal project referencing Urho3D library in its build tree' && ./cmake_macosx.sh . -DIOS=$IOS #{deployment_target} #{$build_options} -DURHO3D_HOME=../.. -DURHO3D_LUA#{jit}=1 -DURHO3D_TESTING=#{$testing}" or abort 'Failed to configure temporary project using Urho3D as external library'
  675. xcode_build(ENV['IOS'], '../Build/generated/UsingBuildTree/Scaffolding.xcodeproj') or abort 'Failed to build/test temporary project using Urho3D as external library'
  676. ENV['DESTDIR'] = ENV['HOME'] || Dir.home
  677. wait_for_block("\nInstalling Urho3D SDK to #{ENV['DESTDIR']}/usr/local...") { Thread.current[:exit_code] = xcode_build(ENV['IOS'], '../Build/Urho3D.xcodeproj', 'install', '>/dev/null') } or abort 'Failed to install Urho3D SDK'
  678. # Create a new project on the fly that uses newly installed Urho3D SDK
  679. scaffolding "../Build/generated/UsingSDK"
  680. system "export URHO3D_HOME=~/usr/local && cd ../Build/generated/UsingSDK && echo '\nExternal project referencing Urho3D SDK' && ./cmake_macosx.sh . -DIOS=$IOS #{deployment_target} #{$build_options} -DURHO3D_LUA#{jit}=1 -DURHO3D_TESTING=#{$testing}" or abort 'Failed to configure temporary project using Urho3D as external library'
  681. xcode_build(ENV['IOS'], '../Build/generated/UsingSDK/Scaffolding.xcodeproj') or abort 'Failed to build/test temporary project using Urho3D as external library'
  682. end
  683. end
  684. def xcode_build ios, project, target = 'ALL_BUILD', extras = ''
  685. sdk = ios.to_i == 1 ? '-sdk iphonesimulator' : ''
  686. # Use xcpretty to filter output from xcodebuild when building
  687. system "xcodebuild -project #{project} -target #{target} -configuration #{$configuration} #{sdk} |xcpretty -c #{extras} && exit ${PIPESTATUS[0]}" or return nil
  688. if $testing == 1 && target == 'ALL_BUILD' # Disable testing for other targets such as 'doc', 'package', etc
  689. # Use vanila xcodebuild when testing as its output is instantaneous (ensure Travis-CI does not kill the process during testing)
  690. system "xcodebuild -project #{project} -target RUN_TESTS -configuration #{$configuration} #{sdk} #{extras}" or return nil
  691. end
  692. return 0
  693. end
  694. def append_new_release release, filename = '../doc-Build/_data/urho3d.json'
  695. begin
  696. urho3d_hash = JSON.parse File.read filename
  697. unless urho3d_hash['releases'].last == release
  698. urho3d_hash['releases'] << release
  699. end
  700. File.open(filename, 'w') { |file| file.puts urho3d_hash.to_json }
  701. return 0
  702. rescue
  703. nil
  704. end
  705. end
  706. def update_emscripten_data dir = '../doc-Build/samples', filename = '../doc-Build/_data/emscripten.json'
  707. begin
  708. emscripten_hash = JSON.parse File.read filename
  709. Dir.chdir(dir) { emscripten_hash['samples'] = Dir['*.html'].sort }
  710. File.open(filename, 'w') { |file| file.puts emscripten_hash.to_json }
  711. return 0
  712. rescue
  713. nil
  714. end
  715. end
  716. def bump_soversion filename
  717. begin
  718. version = File.read(filename).split '.'
  719. bump_version version, 2
  720. File.open(filename, 'w') { |file| file.puts version.join '.' }
  721. return 0
  722. rescue
  723. nil
  724. end
  725. end
  726. def bump_version version, index
  727. if index > 0 && version[index].to_i == 255
  728. version[index] = 0
  729. bump_version version, index - 1
  730. else
  731. version[index] = version[index].to_i + 1
  732. end
  733. end
  734. def setup_digital_keys
  735. system 'mkdir -p ~/.ssh && chmod 700 ~/.ssh' or abort 'Failed to create ~/.ssh directory'
  736. system 'cat <<EOF >>~/.ssh/known_hosts
  737. frs.sourceforge.net,216.34.181.57 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA2uifHZbNexw6cXbyg1JnzDitL5VhYs0E65Hk/tLAPmcmm5GuiGeUoI/B0eUSNFsbqzwgwrttjnzKMKiGLN5CWVmlN1IXGGAfLYsQwK6wAu7kYFzkqP4jcwc5Jr9UPRpJdYIK733tSEmzab4qc5Oq8izKQKIaxXNe7FgmL15HjSpatFt9w/ot/CHS78FUAr3j3RwekHCm/jhPeqhlMAgC+jUgNJbFt3DlhDaRMa0NYamVzmX8D47rtmBbEDU3ld6AezWBPUR5Lh7ODOwlfVI58NAf/aYNlmvl2TZiauBCTa7OPYSyXJnIPbQXg6YQlDknNCr0K769EjeIlAfY87Z4tw==
  738. EOF' or abort 'Failed to append frs.sourceforge.net server public key to known_hosts'
  739. # Workaround travis encryption key size limitation. Rather than using the solution in their FAQ (using AES to encrypt/decrypt the file and check in the encrypted file into repo), our solution is more pragmatic. The private key below is incomplete. Only the missing portion is encrypted. Much less secure than the original 2048-bit RSA has to offer but good enough for our case.
  740. system 'cat <<EOF >~/.ssh/id_rsa
  741. -----BEGIN RSA PRIVATE KEY-----
  742. MIIEpQIBAAKCAQEAnZGzFEypdXKY3KDT0Q3NLY4Bv74yKgJ4LIgbXothx8w4CfM0
  743. VeWBL/AE2iRISEWGB07LruM9y+U/wt58WlCVu001GuJuvXwWenlljsvH8qQlErYi
  744. oXlCwAeVVeanILGL8CPS7QlyzOwwnVF6NdcmfDJjTthBVFbvHrWGo5if86zcZyMR
  745. 2BB5QVEr5fU0yOPFp0+2p7J3cA6HQSKwjUiDtJ+lM62UQp7InCCT3qeh5KYHQcYb
  746. KVJTyj5iycVuBujHDwNAivLq82ojG7LcKjP+Ia8fblardCOQyFk6pSDM79NJJ2Dg
  747. 3ZbYIJeUmqSqFhRW/13Bro7Z1aNGrdh/XZkkHwIDAQABAoIBACHcBFJxYtzVIloO
  748. yVWcFKIcaO3OLjNu0monWVJIu1tW3BfvRijLJ6aoejJyJ4I4RmPdn9FWDZp6CeiT
  749. LL+vn21fWvELBWb8ekwZOCSmT7IpaboKn4h5aUmgl4udA/73iC2zVQkQxbWZb5zu
  750. vEdDk4aOwV5ZBDjecYX01hjjnEOdZHGJlF/H/Xs0hYX6WDG3/r9QCJJ0nfd1/Fk2
  751. zdbZRtAbyRz6ZHiYKnFQ441qRRaEbzunkvTBEwu9iqzlE0s/g49LJL0mKEp7rt/J
  752. 4iS3LZTQbJNx5J0ti8ZJKHhvoWb5RJxNimwKvVHC0XBZKTiLMrhnADmcpjLz53F8
  753. $SF_KEY
  754. sx27yCaeBeKXV0tFOeZmgK664VM9EgesjIX4sVOJ5mA3xBJBOtz9n66LjoIlIM58
  755. dvsAnJt7MUBdclL/RBHEjbUxgGBDcazfWSuJe0sGczhnXMN94ox4MSECgYEAx5cv
  756. cs/2KurjtWPanDGSz71LyGNdL/xQrAud0gi49H0tyYr0XmzNoe2CbZ/T5xGSZB92
  757. PBcz4rnHQ/oujo/qwjNpDD0xVLEU70Uy/XiY5/v2111TFC4clfE/syZPywKAztt3
  758. y2l5z+QdsNigRPDhKw+7CFYaAnYBEISxR6nabT8CgYEAqHrM8fdn2wsCNE6XvkZQ
  759. O7ZANHNIKVnaRqW/8HW7EFAWQrlQTgzFbtR4uNBIqAtPsvwSx8Pk652+OR1VKfSv
  760. ya3dtqY3rY/ErXWyX0nfPQEbYj/oh8LbS6zPw75yIorP3ACIwMw3GRNWIvkdAGTn
  761. BMUgpWHUDLWWpWRrSzNi90ECgYEAkxxzQ6vW5OFGv17/NdswO+BpqCTc/c5646SY
  762. ScRWFxbhFclOvv5xPqYiWYzRkmIYRaYO7tGnU7jdD9SqVjfrsAJWrke4QZVYOdgG
  763. cl9eTLchxLGr15b5SOeNrQ1TCO4qZM3M6Wgv+bRI0h2JW+c0ABpTIBzehOvXcwZq
  764. 6MhgD98CgYEAtOPqc4aoIRUy+1oijpWs+wU7vAc8fe4sBHv5fsv7naHuPqZgyQYY
  765. 32a54xZxlsBw8T5P4BDy40OR7fu+6miUfL+WxUdII4fD3grlIPw6bpNE0bCDykv5
  766. RLq28S11hDrKf/ZetXNuIprfTlhl6ISBy+oWQibhXmFZSxEiXNV6hCQ=
  767. -----END RSA PRIVATE KEY-----
  768. EOF' or abort 'Failed to create user private key to id_rsa'
  769. system 'chmod 600 ~/.ssh/id_rsa' or abort 'Failed to change id_rsa file permission'
  770. end
  771. # Load custom rake scripts
  772. Dir['.rake/*.rake'].each { |r| load r }
  773. # vi: set ts=2 sw=2 expandtab: