Rakefile 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  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. elsif !Dir.glob("#{build_tree}/*.ninja").empty?
  133. # ninja
  134. if !numjobs.empty?
  135. build_options = "-j#{numjobs}#{build_options}"
  136. end
  137. filter = ''
  138. else
  139. # make
  140. if numjobs.empty?
  141. case RUBY_PLATFORM
  142. when /linux/
  143. numjobs = (platform == 'emscripten' ? `grep 'core id' /proc/cpuinfo |sort |uniq |wc -l` : `grep -c processor /proc/cpuinfo`).chomp
  144. when /darwin/
  145. numjobs = `sysctl -n hw.#{platform == 'emscripten' ? 'physical' : 'logical'}cpu`.chomp
  146. when /win32|mingw|mswin/
  147. require 'win32ole'
  148. WIN32OLE.connect('winmgmts://').ExecQuery("select NumberOf#{platform == 'emscripten' ? '' : 'Logical'}Processors from Win32_ComputerSystem").each { |out| numjobs = platform == 'emscripten' ? out.NumberOfProcessors : out.NumberOfLogicalProcessors }
  149. else
  150. numjobs = 1
  151. end
  152. end
  153. build_options = "-j#{numjobs}#{build_options}"
  154. filter = ''
  155. end
  156. system "cd \"#{build_tree}\" && #{ccache_envvar} cmake --build . #{cmake_build_options} -- #{build_options} #{filter}" or abort
  157. end
  158. # 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]
  159. desc 'Test run already installed APK in Android (virtual) device, default to Urho3D Samples APK if no parameter is given'
  160. task :android do
  161. parameter = ENV['parameter'] || '--es pickedLibrary Urho3DPlayer'
  162. intent = ENV['intent'] || '.SampleLauncher'
  163. package = ENV['package'] || 'com.github.urho3d'
  164. success_indicator = ENV['success_indicator'] || 'Initialized engine'
  165. payload = ENV['payload'] || 'sleep 30'
  166. api = ENV['api'] || 19
  167. abi = ENV['abi'] || 'armeabi-v7a'
  168. avd = ENV['avd'] || "test_#{api}_#{abi}"
  169. retries = ENV['retries'] || 10 # minutes
  170. retry_interval = ENV['retry_interval'] || 10 # seconds
  171. android_prepare_device api, abi, avd or abort 'Failed to prepare Android (virtual) device for test run'
  172. android_wait_for_device retries, retry_interval or abort 'Failed to start Android (virtual) device'
  173. android_test_run parameter, intent, package, success_indicator, payload or abort "Failed to test run #{package}/#{intent}, make sure the APK has been installed"
  174. end
  175. # Usage: NOT intended to be used manually (if you insist then try: rake ci)
  176. desc 'Configure, build, and test Urho3D project'
  177. task :ci do
  178. # Skip if only performing CI for selected branches and the current branch is not in the list
  179. unless ENV['RELEASE_TAG']
  180. matched = /\[ci only:(.*?)\]/.match(ENV['COMMIT_MESSAGE'])
  181. next if matched && !matched[1].split(/[ ,]/).reject!(&:empty?).map { |i| /#{i}/ =~ ENV['TRAVIS_BRANCH'] }.any?
  182. end
  183. # Obtain our custom data, if any
  184. data = YAML::load(File.open(".travis.yml"))['data']
  185. data['excluded_sample'].each { |name| ENV["EXCLUDE_SAMPLE_#{name}"] = '1' } if data && data['excluded_sample']
  186. # Unshallow the clone's history when necessary
  187. if ENV['CI'] && ENV['PACKAGE_UPLOAD'] && !ENV['RELEASE_TAG']
  188. system 'git fetch --unshallow' or abort 'Failed to unshallow cloned repository'
  189. end
  190. # Packaging always use Release configuration
  191. if ENV['PACKAGE_UPLOAD']
  192. $configuration = 'Release'
  193. $testing = 0
  194. else
  195. $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
  196. # 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
  197. $testing = (ENV['LINUX'] && !ENV['URHO3D_64BIT']) || (ENV['OSX'] && ENV['IOS'].to_i != 1) || ENV['EMSCRIPTEN'] ? 1 : 0
  198. if $testing
  199. ENV['URHO3D_PREFIX_PATH'] = `pwd`.chomp + '/bin'
  200. end
  201. end
  202. # Define the build option string only when the override environment variable is given
  203. $build_options = "-DWIN32=#{ENV['WINDOWS']}" if ENV['WINDOWS']
  204. $build_options = "#{$build_options} -DANDROID_ABI=#{ENV['ABI']}" if ENV['ABI']
  205. $build_options = "#{$build_options} -DANDROID_NATIVE_API_LEVEL=#{ENV['API']}" if ENV['API']
  206. ['URHO3D_64BIT', 'URHO3D_LIB_TYPE', 'URHO3D_OPENGL', 'URHO3D_D3D11', 'URHO3D_TEST_TIMEOUT', 'ANDROID', 'RPI', 'RPI_ABI', 'EMSCRIPTEN', 'EMSCRIPTEN_SHARE_DATA', 'EMSCRIPTEN_EMRUN_BROWSER'].each { |var| $build_options = "#{$build_options} -D#{var}=#{ENV[var]}" if ENV[var] }
  207. if ENV['XCODE']
  208. # xcodebuild
  209. xcode_ci
  210. else
  211. # GCC or Clang
  212. makefile_ci
  213. end
  214. end
  215. # Usage: NOT intended to be used manually
  216. desc 'Setup build cache'
  217. task :ci_setup_cache do
  218. # Use internal cache store instead of using Travis CI one (this is a workaround for using ccache on Travis CI legacy build infra)
  219. if ENV['USE_CCACHE'].to_i == 2
  220. puts 'Setting up build cache'
  221. job_number = ".#{ENV['TRAVIS_JOB_NUMBER'].split('.').last}"
  222. repo_slug = "#{ENV['TRAVIS_REPO_SLUG'].split('/').first}/cache-store.git"
  223. matched = /.*-([^-]+-[^-]+)$/.match(ENV['TRAVIS_BRANCH'])
  224. base_mirror = matched ? matched[1] : nil
  225. # Do not abort even when it fails here
  226. 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"
  227. end
  228. # Clear ccache on demand
  229. system "ccache -z -M #{ENV['CCACHE_MAXSIZE']} #{/\[ccache clear\]/ =~ ENV['COMMIT_MESSAGE'] ? '-C' : ''}"
  230. end
  231. # Usage: NOT intended to be used manually
  232. desc 'Teardown build cache'
  233. task :ci_teardown_cache do
  234. # Upload cache to internal cache store if it is our own
  235. if ENV['USE_CCACHE'].to_i == 2
  236. puts 'Storing build cache'
  237. job_number = ".#{ENV['TRAVIS_JOB_NUMBER'].split('.').last}"
  238. repo_slug = "#{ENV['TRAVIS_REPO_SLUG'].split('/').first}/cache-store.git"
  239. # Do not abort even when it fails here
  240. 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"
  241. end
  242. system 'ccache -s'
  243. end
  244. # Usage: NOT intended to be used manually
  245. desc 'Update site documentation to GitHub Pages'
  246. task :ci_site_update do
  247. # Skip when :ci rake task was skipped
  248. next unless File.exist?('../Build/CMakeCache.txt')
  249. # Pull or clone
  250. 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'
  251. # Update credits from README.md to about.yml
  252. 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'
  253. # Setup doxygen to use minimal theme
  254. 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/Doxyfile" or abort 'Failed to setup doxygen configuration file'
  255. system 'cp ../doc-Build/_includes/Doxygen/minimal-* ../Build/Docs' or abort 'Failed to copy minimal-themed template'
  256. release = ENV['RELEASE_TAG'] || 'HEAD'
  257. unless release == 'HEAD'
  258. system "mkdir -p ../doc-Build/documentation/#{release}" or abort 'Failed to create directory for new document version'
  259. 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'
  260. append_new_release release or abort 'Failed to add new release to document data file'
  261. end
  262. # Generate and sync doxygen pages
  263. 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'
  264. # Supply GIT credentials and push site documentation to urho3d/urho3d.github.io.git
  265. 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'
  266. unless ENV['RELEASE_TAG'] || `git fetch -qf origin #{ENV['TRAVIS_BRANCH']}; git log -1 --pretty=format:'%H' FETCH_HEAD` != ENV['TRAVIS_COMMIT']
  267. # Supply GIT credentials and push API documentation to urho3d/Urho3D.git (only when changes are detected)
  268. 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*'
  269. if system("git commit -qm 'Test commit to detect API changes'")
  270. # Automatically give instruction to do packaging when API has changed, unless the instruction is already given in this commit
  271. bump_soversion 'Source/Urho3D/.soversion' or abort 'Failed to bump soversion'
  272. 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'
  273. system "git push origin HEAD:#{ENV['TRAVIS_BRANCH']} -q >/dev/null 2>&1" or abort 'Failed to update API documentation'
  274. end
  275. end
  276. end
  277. # Usage: NOT intended to be used manually
  278. desc 'Update Emscripten HTML5 samples to GitHub Pages'
  279. task :ci_emscripten_samples_update do
  280. puts "\nUpdating Emscripten samples in main website..."
  281. # Pull or clone
  282. 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'
  283. # Sync Emscripten samples
  284. system "rsync -a --delete --exclude tool ../Build/bin/ ../doc-Build/samples" or abort 'Failed to rsync Emscripten samples'
  285. # Update Emscripten json data file
  286. update_emscripten_data or abort 'Failed to update Emscripten json data file'
  287. root_commit, _ = get_root_commit_and_recipients
  288. 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'
  289. end
  290. # Usage: NOT intended to be used manually
  291. desc 'Create all CI mirror branches'
  292. task :ci_create_mirrors do
  293. # Skip if there are more commits since this one
  294. 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']
  295. 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'
  296. # Limit the scanning to only master branch and limit the frequency of scanning
  297. scan = ENV['TRAVIS_BRANCH'] == 'master' && (`ccache -s |grep 'cache miss'`.split.last.to_i >= ENV['COVERITY_SCAN_THRESHOLD'].to_i || /\[ci scan\]/ =~ ENV['COMMIT_MESSAGE'])
  298. # Determine which CI mirror branches to be auto created
  299. unless ENV['RELEASE_TAG']
  300. matched = /\[ci only:(.*?)\]/.match(ENV['COMMIT_MESSAGE'])
  301. ci_only = matched ? matched[1].split(/[ ,]/).reject!(&:empty?) : nil
  302. ci_only.push('Coverity-Scan') if ci_only && scan
  303. else
  304. ci_only = nil
  305. end
  306. # Obtain the whole stream and process the rest of documents except the first one since travis-build does not do that at the moment
  307. stream = YAML::load_stream(File.open('.travis.yml'))
  308. notifications = stream[0]['notifications']
  309. notifications['email']['recipients'] = get_root_commit_and_recipients().last unless notifications['email']['recipients']
  310. 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))); 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 '#{branch['description']}' && git push -qf -u origin #{ci_branch} >/dev/null 2>&1 && git checkout -q -" or abort "Failed to create #{ci_branch} mirror branch" }
  311. end
  312. # Usage: NOT intended to be used manually
  313. desc 'Delete CI mirror branch'
  314. task :ci_delete_mirror do
  315. # Skip if there are more commits since this one or if this is a release build
  316. matched = /(.*)-[^-]+-[^-]+$/.match(ENV['TRAVIS_BRANCH'])
  317. base_branch = matched ? matched[1] : 'master' # Assume 'master' is the default branch name
  318. 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']
  319. 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'
  320. system "git push -qf origin --delete #{ENV['TRAVIS_BRANCH']}" or abort "Failed to delete #{ENV['TRAVIS_BRANCH']} mirror branch"
  321. end
  322. # Usage: NOT intended to be used manually
  323. desc 'Make binary package and upload it to a designated central hosting server'
  324. task :ci_package_upload do
  325. # Skip when :ci rake task was skipped
  326. next unless File.exist?('../Build/CMakeCache.txt')
  327. if ENV['XCODE']
  328. $configuration = 'Release'
  329. $testing = 0
  330. end
  331. # Generate the documentation if necessary
  332. if ENV['SITE_UPDATE']
  333. if File.exist?('.site_updated')
  334. # Skip if site is already updated before
  335. ENV['SITE_UPDATE'] = nil
  336. end
  337. else
  338. system 'echo Generating documentation...'
  339. if ENV['XCODE']
  340. xcode_build(ENV['IOS'], '../Build/Urho3D.xcodeproj', 'doc', '>/dev/null') or abort 'Failed to generate documentation'
  341. else
  342. system 'cd ../Build && make -j$NUMJOBS doc >/dev/null' or abort 'Failed to generate documentation'
  343. end
  344. end
  345. # Make the package
  346. if ENV['IOS']
  347. # 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
  348. if ENV['CI_START_TIME'] then
  349. elapsed_time = (Time.now - Time.at(ENV['CI_START_TIME'].to_i)) / 60
  350. puts "\niOS checkpoint reached, elapsed time: #{elapsed_time}\n\n"
  351. end
  352. if !ENV['CI_START_TIME'] || elapsed_time < 25 # minutes
  353. # 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)
  354. system 'echo Rebuilding Urho3D library as Mach-O universal binary...'
  355. xcode_build(0, '../Build/Urho3D.xcodeproj', 'Urho3D_universal') or abort 'Failed to build Mach-O universal binary'
  356. end
  357. # There is a bug in CMake/CPack that causes the 'package' target failed to build for IOS platform, workaround by calling cpack directly
  358. system 'cd ../Build && cpack -G TGZ 2>/dev/null' or abort 'Failed to make binary package'
  359. elsif ENV['XCODE']
  360. xcode_build(ENV['IOS'], '../Build/Urho3D.xcodeproj', 'package') or abort 'Failed to make binary package'
  361. else
  362. if ENV['ANDROID'] && !ENV['NO_SDK_SYSIMG']
  363. 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'
  364. end
  365. if ENV['URHO3D_USE_LIB64_RPM']
  366. system "cd ../Build && cmake . -DURHO3D_USE_LIB64_RPM=#{ENV['URHO3D_USE_LIB64_RPM']}" or abort 'Failed to reconfigure to generate 64-bit RPM package'
  367. end
  368. wrapper = ENV['URHO3D_64BIT'] || ENV['RPI'] ? 'setarch i686' : ''
  369. system "cd ../Build && #{wrapper} make package" or abort 'Failed to make binary package'
  370. end
  371. # Determine the upload location
  372. setup_digital_keys
  373. unless ENV['RELEASE_TAG']
  374. upload_dir = "/home/frs/project/#{ENV['TRAVIS_REPO_SLUG']}/Snapshots"
  375. if ENV['SITE_UPDATE']
  376. # Download source packages from GitHub
  377. 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'
  378. # Only keep the snapshots from the last 30 revisions
  379. system "for v in $(sftp [email protected] <<EOF |tr ' ' '\n' |grep Urho3D- |cut -d '-' -f1,2 |uniq |tail -n +31
  380. cd #{upload_dir}
  381. ls -1r
  382. bye
  383. EOF
  384. ); do echo rm #{upload_dir}/${v}*; done |sftp -b - [email protected] >/dev/null 2>&1" or abort 'Failed to housekeep snapshots'
  385. end
  386. else
  387. upload_dir = "/home/frs/project/#{ENV['TRAVIS_REPO_SLUG']}/#{ENV['RELEASE_TAG']}"
  388. if ENV['SITE_UPDATE']
  389. # Download source packages from GitHub
  390. 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'
  391. end
  392. # 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
  393. system "sftp [email protected] <<EOF >/dev/null 2>&1
  394. mkdir #{upload_dir}
  395. bye
  396. EOF" or abort 'Failed to create release directory remotely'
  397. end
  398. if ENV['SITE_UPDATE']
  399. # Upload the source package
  400. system "scp Urho3D-* [email protected]:#{upload_dir}" or abort 'Failed to upload source package'
  401. if ENV['RELEASE_TAG']
  402. # Mark the source tarball as default download for host systems other than Windows/Mac/Linux
  403. 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'
  404. end
  405. # Sync readme and license files, just in case they are updated in the repo
  406. 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'
  407. 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'
  408. # Mark that the site has been updated
  409. File.open('.site_updated', 'w') {}
  410. end
  411. # Upload the binary package
  412. system "scp ../Build/Urho3D-* [email protected]:#{upload_dir} && rm ../Build/Urho3D-*" or abort 'Failed to upload binary package'
  413. if ENV['RELEASE_TAG'] && ENV['SF_DEFAULT']
  414. # Mark the corresponding binary package as default download for each Windows/Mac/Linux host systems
  415. 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'
  416. end
  417. end
  418. def scaffolding dir, project = 'Scaffolding', target = 'Main'
  419. build_script = <<EOF
  420. # Set project name
  421. project (#{project})
  422. # Set minimum version
  423. cmake_minimum_required (VERSION 2.8.6)
  424. if (COMMAND cmake_policy)
  425. cmake_policy (SET CMP0003 NEW)
  426. if (CMAKE_VERSION VERSION_GREATER 2.8.12 OR CMAKE_VERSION VERSION_EQUAL 2.8.12)
  427. # INTERFACE_LINK_LIBRARIES defines the link interface
  428. cmake_policy (SET CMP0022 NEW)
  429. endif ()
  430. if (CMAKE_VERSION VERSION_GREATER 3.0.0 OR CMAKE_VERSION VERSION_EQUAL 3.0.0)
  431. # Disallow use of the LOCATION target property - therefore we set to OLD as we still need it
  432. cmake_policy (SET CMP0026 OLD)
  433. # MACOSX_RPATH is enabled by default
  434. cmake_policy (SET CMP0042 NEW)
  435. endif ()
  436. endif ()
  437. # Set CMake modules search path
  438. set (CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake/Modules)
  439. # Include Urho3D CMake common module
  440. include (Urho3D-CMake-common)
  441. # Find Urho3D library
  442. find_package (Urho3D REQUIRED)
  443. include_directories (${URHO3D_INCLUDE_DIRS})
  444. # Define target name
  445. set (TARGET_NAME #{target})
  446. # Define source files
  447. define_source_files ()
  448. # Setup target with resource copying
  449. setup_main_executable ()
  450. # Setup test cases
  451. if (URHO3D_ANGELSCRIPT)
  452. setup_test (NAME ExternalLibAS OPTIONS Scripts/12_PhysicsStressTest.as -w)
  453. endif ()
  454. if (URHO3D_LUA)
  455. setup_test (NAME ExternalLibLua OPTIONS LuaScripts/12_PhysicsStressTest.lua -w)
  456. endif ()
  457. EOF
  458. # TODO: Rewrite in pure Ruby when it supports symlink creation on Windows platform
  459. if ENV['OS']
  460. 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'
  461. else
  462. 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'
  463. end
  464. end
  465. def makefile_ci
  466. if (ENV['WINDOWS'] && ENV['CI']) || (ENV['ANDROID'] && ENV['ABI'] == 'arm64-v8a') || ENV['EMSCRIPTEN']
  467. # LuaJIT on MinGW build is not possible on Ubuntu 12.04 LTS as its GCC cross-compiler version is too old
  468. # The upstream LuaJIT library does not support Android arm64-v8a ABI at the moment
  469. # LuaJIT on Emscripten is not possible
  470. # Fallback to use Lua library instead
  471. jit = ''
  472. amalg = ''
  473. else
  474. jit = 'JIT'
  475. amalg = '-DURHO3D_LUAJIT_AMALG=1'
  476. end
  477. system "./cmake_generic.sh ../Build #{$build_options} -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'
  478. if ENV['AVD'] && !ENV['PACKAGE_UPLOAD'] # Skip APK test run when packaging
  479. android_prepare_device ENV['API'], ENV['ABI'], ENV['AVD'] or abort 'Failed to prepare Android (virtual) device for test run'
  480. end
  481. # For Emscripten CI build, skip make test and/or scaffolding test if Travis-CI VM took too long to get here, as otherwise overall build time may exceed 50 minutes time limit
  482. test = $testing == 1 ? '&& make test' : ''
  483. system "cd ../Build && make -j$NUMJOBS #{test}" or abort 'Failed to build or test Urho3D library'
  484. unless ENV['CI'] && ENV['EMSCRIPTEN'] && ENV['PACKAGE_UPLOAD'] # For Emscripten, skip scaffolding test when packaging
  485. # Create a new project on the fly that uses newly built Urho3D library in the build tree
  486. scaffolding "../Build/generated/UsingBuildTree"
  487. 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'
  488. ENV['DESTDIR'] = ENV['HOME'] || Dir.home
  489. puts "\nInstalling Urho3D SDK to #{ENV['DESTDIR']}/usr/local...\n" # The default CMAKE_INSTALL_PREFIX is /usr/local
  490. system 'cd ../Build && make -j$NUMJOBS install >/dev/null' or abort 'Failed to install Urho3D SDK'
  491. # Create a new project on the fly that uses newly installed Urho3D SDK
  492. scaffolding "../Build/generated/UsingSDK"
  493. 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'
  494. end
  495. # Make, deploy, and test run Android APK in an Android (virtual) device
  496. if ENV['AVD'] && !ENV['PACKAGE_UPLOAD']
  497. 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'
  498. if android_wait_for_device
  499. system "cd ../Build && ant -Dadb.device.arg='-s #{$specific_device}' installd" or abort 'Failed to deploy Urho3D Samples APK'
  500. android_test_run or abort 'Failed to test run Urho3D Samples APK'
  501. else
  502. puts 'Skipped test running Urho3D Samples APK as emulator failed to start in time'
  503. end
  504. end
  505. end
  506. def get_root_commit_and_recipients
  507. # Root commit is a commit submitted by human
  508. root_commit = `git show -s --format='%H' #{ENV['TRAVIS_COMMIT']}`.rstrip
  509. recipients = `git show -s --format='%ae %ce' #{root_commit}`.chomp.split.uniq
  510. if recipients.include? '[email protected]'
  511. matched = /Commit:.*commit\/(.*?)\n/.match(ENV['COMMIT_MESSAGE'])
  512. if (matched)
  513. root_commit = matched[1]
  514. recipients = `git show -s --format='%ae %ce' #{root_commit}`.chomp.split.uniq
  515. end
  516. end
  517. return root_commit, recipients
  518. end
  519. def android_find_device api = nil, abi = nil
  520. # Return the previously found matching device or if not found yet then try to find the matching device now
  521. return $specific_device if $specific_device
  522. wait = api ? '' : 'wait-for-device'
  523. $specific_api = api.to_s if api
  524. $specific_abi = abi.to_s if abi
  525. for i in `adb #{wait} devices |tail -n +2`.split "\n"
  526. device = i.split.first
  527. 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
  528. return $specific_device = device
  529. end
  530. end
  531. nil
  532. end
  533. def android_prepare_device api, abi = 'armeabi-v7a', name = 'test'
  534. system 'if ! ps |grep -cq adb; then adb start-server; fi'
  535. if !android_find_device api, abi
  536. # Don't have any matching (virtual) device attached, try to attach the named device (create the named device as AVD if necessary)
  537. if !system "android list avd |grep -cq 'Name: #{name}$'"
  538. system "echo 'no' |android create avd -n #{name} -t android-#{api} --abi #{abi}" or abort "Failed to create '#{name}' Android virtual device"
  539. end
  540. 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 &"
  541. end
  542. return 0
  543. end
  544. def android_wait_for_device retries = -1, retry_interval = 10, package = 'android.process.acore' # Waiting for HOME by default
  545. # 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)
  546. str = "\nWaiting for device..."
  547. thread = Thread.new { android_find_device }; sleep 0.5
  548. process_ready = false
  549. retries = retries * 60 / retry_interval unless retries == -1
  550. until retries == 0
  551. if thread.status == false
  552. thread.join
  553. break if process_ready
  554. 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
  555. next
  556. end
  557. 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
  558. sleep retry_interval
  559. retries -= 1 if retries > 0
  560. end
  561. puts "\n\n" if str == '.'; $stdout.flush
  562. return retries == 0 ? nil : 0
  563. end
  564. def android_test_run parameter = '--es pickedLibrary Urho3DPlayer', intent = '.SampleLauncher', package = 'com.github.urho3d', success_indicator = 'Added resource path /apk/CoreData/', payload = 'sleep 30'
  565. # The device should have been found at this point
  566. return nil unless $specific_device
  567. # Capture adb's stdout and interpret it because adb neither uses stderr nor returns proper exit code on error
  568. begin
  569. IO.popen("adb -s #{$specific_device} shell <<EOF
  570. # Try to unlock the device just in case it is locked
  571. input keyevent 82; input keyevent 4
  572. # Clear the log
  573. logcat -c
  574. # Start the app
  575. am start -a android.intent.action.MAIN -n #{package}/#{intent} #{parameter}
  576. # Wait until the process is running
  577. until ps |grep -c #{package} 1>/dev/null; do sleep 1; done
  578. # Execute the payload
  579. #{payload}
  580. # Exit and stop the app
  581. input keyevent 4 && am force-stop #{package}
  582. # Dump the log
  583. logcat -d
  584. # Bye bye
  585. exit
  586. ##
  587. 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 }
  588. # Result of the test run is determined based on the presence of the success indicator string in the log
  589. system "adb -s #{$specific_device} logcat -d |grep -cq '#{success_indicator}'"
  590. rescue
  591. nil
  592. end
  593. end
  594. def wait_for_block comment = '', retries = -1, retry_interval = 60, exit_code_sym = 'exit_code', &block
  595. # 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)
  596. thread = Thread.new &block
  597. str = comment
  598. retries = retries * 60 / retry_interval unless retries == -1
  599. until retries == 0
  600. if thread.status == false
  601. thread.join
  602. break
  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" if str == '.'; $stdout.flush
  609. return retries == 0 ? nil : (exit_code_sym ? thread[exit_code_sym] : 0)
  610. end
  611. def xcode_ci
  612. if ENV['IOS']
  613. # IOS platform does not support LuaJIT
  614. jit = ''
  615. amalg = ''
  616. deployment_target = "-DIPHONEOS_DEPLOYMENT_TARGET=#{ENV['DEPLOYMENT_TARGET']}"
  617. else
  618. jit = 'JIT'
  619. amalg = '-DURHO3D_LUAJIT_AMALG=1'
  620. deployment_target = "-DCMAKE_OSX_DEPLOYMENT_TARGET=#{ENV['DEPLOYMENT_TARGET']}"
  621. end
  622. system "./cmake_macosx.sh ../Build -DIOS=$IOS #{deployment_target} #{$build_options} -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'
  623. xcode_build(ENV['IOS'], '../Build/Urho3D.xcodeproj') or abort 'Failed to build or test Urho3D library'
  624. unless ENV['CI'] && ENV['IOS'] && ENV['PACKAGE_UPLOAD'] # Skip scaffolding test when packaging for iOS
  625. # Create a new project on the fly that uses newly built Urho3D library in the build tree
  626. scaffolding "../Build/generated/UsingBuildTree"
  627. 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'
  628. xcode_build(ENV['IOS'], '../Build/generated/UsingBuildTree/Scaffolding.xcodeproj') or abort 'Failed to build/test temporary project using Urho3D as external library'
  629. ENV['DESTDIR'] = ENV['HOME'] || Dir.home
  630. 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'
  631. # Create a new project on the fly that uses newly installed Urho3D SDK
  632. scaffolding "../Build/generated/UsingSDK"
  633. 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'
  634. xcode_build(ENV['IOS'], '../Build/generated/UsingSDK/Scaffolding.xcodeproj') or abort 'Failed to build/test temporary project using Urho3D as external library'
  635. end
  636. end
  637. def xcode_build ios, project, target = 'ALL_BUILD', extras = ''
  638. sdk = ios.to_i == 1 ? '-sdk iphonesimulator' : ''
  639. # Use xcpretty to filter output from xcodebuild when building
  640. system "xcodebuild -project #{project} -target #{target} -configuration #{$configuration} #{sdk} |xcpretty -c #{extras} && exit ${PIPESTATUS[0]}" or return nil
  641. if $testing == 1 && target == 'ALL_BUILD' # Disable testing for other targets such as 'doc', 'package', etc
  642. # Use vanila xcodebuild when testing as its output is instantaneous (ensure Travis-CI does not kill the process during testing)
  643. system "xcodebuild -project #{project} -target RUN_TESTS -configuration #{$configuration} #{sdk} #{extras}" or return nil
  644. end
  645. return 0
  646. end
  647. def append_new_release release, filename = '../doc-Build/_data/urho3d.json'
  648. begin
  649. urho3d_hash = JSON.parse File.read filename
  650. unless urho3d_hash['releases'].last == release
  651. urho3d_hash['releases'] << release
  652. end
  653. File.open(filename, 'w') { |file| file.puts urho3d_hash.to_json }
  654. return 0
  655. rescue
  656. nil
  657. end
  658. end
  659. def update_emscripten_data dir = '../doc-Build/samples', filename = '../doc-Build/_data/emscripten.json'
  660. begin
  661. emscripten_hash = JSON.parse File.read filename
  662. Dir.chdir(dir) { emscripten_hash['samples'] = Dir['*.html'].sort }
  663. File.open(filename, 'w') { |file| file.puts emscripten_hash.to_json }
  664. return 0
  665. rescue
  666. nil
  667. end
  668. end
  669. def bump_soversion filename
  670. begin
  671. version = File.read(filename).split '.'
  672. bump_version version, 2
  673. File.open(filename, 'w') { |file| file.puts version.join '.' }
  674. return 0
  675. rescue
  676. nil
  677. end
  678. end
  679. def bump_version version, index
  680. if index > 0 && version[index].to_i == 255
  681. version[index] = 0
  682. bump_version version, index - 1
  683. else
  684. version[index] = version[index].to_i + 1
  685. end
  686. end
  687. def setup_digital_keys
  688. system 'mkdir -p ~/.ssh && chmod 700 ~/.ssh' or abort 'Failed to create ~/.ssh directory'
  689. system 'cat <<EOF >>~/.ssh/known_hosts
  690. frs.sourceforge.net,216.34.181.57 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA2uifHZbNexw6cXbyg1JnzDitL5VhYs0E65Hk/tLAPmcmm5GuiGeUoI/B0eUSNFsbqzwgwrttjnzKMKiGLN5CWVmlN1IXGGAfLYsQwK6wAu7kYFzkqP4jcwc5Jr9UPRpJdYIK733tSEmzab4qc5Oq8izKQKIaxXNe7FgmL15HjSpatFt9w/ot/CHS78FUAr3j3RwekHCm/jhPeqhlMAgC+jUgNJbFt3DlhDaRMa0NYamVzmX8D47rtmBbEDU3ld6AezWBPUR5Lh7ODOwlfVI58NAf/aYNlmvl2TZiauBCTa7OPYSyXJnIPbQXg6YQlDknNCr0K769EjeIlAfY87Z4tw==
  691. EOF' or abort 'Failed to append frs.sourceforge.net server public key to known_hosts'
  692. # 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.
  693. system 'cat <<EOF >~/.ssh/id_rsa
  694. -----BEGIN RSA PRIVATE KEY-----
  695. MIIEpQIBAAKCAQEAnZGzFEypdXKY3KDT0Q3NLY4Bv74yKgJ4LIgbXothx8w4CfM0
  696. VeWBL/AE2iRISEWGB07LruM9y+U/wt58WlCVu001GuJuvXwWenlljsvH8qQlErYi
  697. oXlCwAeVVeanILGL8CPS7QlyzOwwnVF6NdcmfDJjTthBVFbvHrWGo5if86zcZyMR
  698. 2BB5QVEr5fU0yOPFp0+2p7J3cA6HQSKwjUiDtJ+lM62UQp7InCCT3qeh5KYHQcYb
  699. KVJTyj5iycVuBujHDwNAivLq82ojG7LcKjP+Ia8fblardCOQyFk6pSDM79NJJ2Dg
  700. 3ZbYIJeUmqSqFhRW/13Bro7Z1aNGrdh/XZkkHwIDAQABAoIBACHcBFJxYtzVIloO
  701. yVWcFKIcaO3OLjNu0monWVJIu1tW3BfvRijLJ6aoejJyJ4I4RmPdn9FWDZp6CeiT
  702. LL+vn21fWvELBWb8ekwZOCSmT7IpaboKn4h5aUmgl4udA/73iC2zVQkQxbWZb5zu
  703. vEdDk4aOwV5ZBDjecYX01hjjnEOdZHGJlF/H/Xs0hYX6WDG3/r9QCJJ0nfd1/Fk2
  704. zdbZRtAbyRz6ZHiYKnFQ441qRRaEbzunkvTBEwu9iqzlE0s/g49LJL0mKEp7rt/J
  705. 4iS3LZTQbJNx5J0ti8ZJKHhvoWb5RJxNimwKvVHC0XBZKTiLMrhnADmcpjLz53F8
  706. $SF_KEY
  707. sx27yCaeBeKXV0tFOeZmgK664VM9EgesjIX4sVOJ5mA3xBJBOtz9n66LjoIlIM58
  708. dvsAnJt7MUBdclL/RBHEjbUxgGBDcazfWSuJe0sGczhnXMN94ox4MSECgYEAx5cv
  709. cs/2KurjtWPanDGSz71LyGNdL/xQrAud0gi49H0tyYr0XmzNoe2CbZ/T5xGSZB92
  710. PBcz4rnHQ/oujo/qwjNpDD0xVLEU70Uy/XiY5/v2111TFC4clfE/syZPywKAztt3
  711. y2l5z+QdsNigRPDhKw+7CFYaAnYBEISxR6nabT8CgYEAqHrM8fdn2wsCNE6XvkZQ
  712. O7ZANHNIKVnaRqW/8HW7EFAWQrlQTgzFbtR4uNBIqAtPsvwSx8Pk652+OR1VKfSv
  713. ya3dtqY3rY/ErXWyX0nfPQEbYj/oh8LbS6zPw75yIorP3ACIwMw3GRNWIvkdAGTn
  714. BMUgpWHUDLWWpWRrSzNi90ECgYEAkxxzQ6vW5OFGv17/NdswO+BpqCTc/c5646SY
  715. ScRWFxbhFclOvv5xPqYiWYzRkmIYRaYO7tGnU7jdD9SqVjfrsAJWrke4QZVYOdgG
  716. cl9eTLchxLGr15b5SOeNrQ1TCO4qZM3M6Wgv+bRI0h2JW+c0ABpTIBzehOvXcwZq
  717. 6MhgD98CgYEAtOPqc4aoIRUy+1oijpWs+wU7vAc8fe4sBHv5fsv7naHuPqZgyQYY
  718. 32a54xZxlsBw8T5P4BDy40OR7fu+6miUfL+WxUdII4fD3grlIPw6bpNE0bCDykv5
  719. RLq28S11hDrKf/ZetXNuIprfTlhl6ISBy+oWQibhXmFZSxEiXNV6hCQ=
  720. -----END RSA PRIVATE KEY-----
  721. EOF' or abort 'Failed to create user private key to id_rsa'
  722. system 'chmod 600 ~/.ssh/id_rsa' or abort 'Failed to change id_rsa file permission'
  723. end
  724. # Load custom rake scripts
  725. Dir['.rake/*.rake'].each { |r| load r }
  726. # vi: set ts=2 sw=2 expandtab: