ceedling 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #!/usr/bin/env ruby
  2. #these are always used
  3. require 'rubygems'
  4. require 'fileutils'
  5. # Check for the main project file (either the one defined in the ENV or the default)
  6. main_filepath = ENV['CEEDLING_MAIN_PROJECT_FILE']
  7. project_found = (!main_filepath.nil? && File.exists?(main_filepath))
  8. if (!project_found)
  9. main_filepath = "project.yml"
  10. project_found = File.exists?(main_filepath)
  11. end
  12. def is_windows?
  13. return ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw/) ? true : false) if defined?(RbConfig)
  14. return ((Config::CONFIG['host_os'] =~ /mswin|mingw/) ? true : false)
  15. end
  16. unless (project_found)
  17. #===================================== We Do Not Have A Project ================================================
  18. puts "Welcome to Ceedling!"
  19. require 'thor'
  20. def here
  21. File.dirname(__FILE__) + "/.."
  22. end
  23. class CeedlingTasks < Thor
  24. include Thor::Actions
  25. desc "new PROJECT_NAME", "create a new ceedling project"
  26. method_option :docs, :type => :boolean, :default => false, :desc => "Add docs in project vendor directory"
  27. method_option :local, :type => :boolean, :default => false, :desc => "Create a copy of Ceedling in the project vendor directory"
  28. method_option :gitignore, :type => :boolean, :default => false, :desc => "Create a gitignore file for ignoring ceedling generated files"
  29. method_option :no_configs, :type => :boolean, :default => false, :desc => "Don't install starter configuration files"
  30. method_option :noconfigs, :type => :boolean, :default => false
  31. #deprecated:
  32. method_option :no_docs, :type => :boolean, :default => false
  33. method_option :nodocs, :type => :boolean, :default => false
  34. method_option :as_gem, :type => :boolean, :default => false
  35. method_option :asgem, :type => :boolean, :default => false
  36. method_option :with_ignore, :type => :boolean, :default => false
  37. method_option :withignore, :type => :boolean, :default => false
  38. def new(name, silent = false)
  39. copy_assets_and_create_structure(name, silent, false, options)
  40. end
  41. desc "upgrade PROJECT_NAME", "upgrade ceedling for a project (not req'd if gem used)"
  42. method_option :docs, :type => :boolean, :default => false, :desc => "Add docs in project vendor directory"
  43. method_option :local, :type => :boolean, :default => false, :desc => "Create a copy of Ceedling in the project vendor directory"
  44. method_option :no_configs, :type => :boolean, :default => false, :desc => "Don't install starter configuration files"
  45. method_option :noconfigs, :type => :boolean, :default => false
  46. #deprecated:
  47. method_option :no_docs, :type => :boolean, :default => false
  48. method_option :nodocs, :type => :boolean, :default => false
  49. def upgrade(name, silent = false)
  50. copy_assets_and_create_structure(name, silent, true, options || {:upgrade => true})
  51. end
  52. no_commands do
  53. def copy_assets_and_create_structure(name, silent=false, force=false, options = {})
  54. puts "WARNING: --no_docs deprecated. It is now the default. Specify -docs if you want docs installed." if (options[:no_docs] || options[:nodocs])
  55. puts "WARNING: --as_gem deprecated. It is now the default. Specify -local if you want ceedling installed to this project." if (options[:as_gem] || options[:asgem])
  56. puts "WARNING: --with_ignore deprecated. It is now called -gitignore" if (options[:with_ignore] || options[:with_ignore])
  57. use_docs = options[:docs] || false
  58. use_configs = !(options[:no_configs] || options[:noconfigs] || false)
  59. use_gem = !(options[:local])
  60. use_ignore = options[:gitignore] || false
  61. is_upgrade = options[:upgrade] || false
  62. ceedling_path = File.join(name, 'vendor', 'ceedling')
  63. source_path = File.join(name, 'src')
  64. test_path = File.join(name, 'test')
  65. test_support_path = File.join(name, 'test/support')
  66. # If it's not an upgrade, make sure we have the paths we expect
  67. if (!is_upgrade)
  68. [source_path, test_path, test_support_path].each do |d|
  69. FileUtils.mkdir_p d
  70. end
  71. end
  72. # Genarate gitkeep in test support path
  73. FileUtils.touch(File.join(test_support_path, '.gitkeep'))
  74. # If documentation requested, create a place to dump them and do so
  75. if use_docs
  76. doc_path = File.join(ceedling_path, 'docs')
  77. FileUtils.mkdir_p doc_path
  78. in_doc_path = lambda {|f| File.join(doc_path, f)}
  79. doc_files = [
  80. 'docs/CeedlingPacket.md',
  81. 'vendor/c_exception/docs/CException.md',
  82. 'vendor/cmock/docs/CMock_Summary.md',
  83. 'vendor/unity/docs/UnityAssertionsCheatSheetSuitableforPrintingandPossiblyFraming.pdf',
  84. 'vendor/unity/docs/UnityAssertionsReference.md',
  85. 'vendor/unity/docs/UnityConfigurationGuide.md',
  86. 'vendor/unity/docs/UnityGettingStartedGuide.md',
  87. 'vendor/unity/docs/UnityHelperScriptsGuide.md',
  88. 'vendor/unity/docs/ThrowTheSwitchCodingStandard.md',
  89. ]
  90. doc_files.each do |f|
  91. copy_file(f, in_doc_path.call(File.basename(f)), :force => force)
  92. end
  93. end
  94. # If installed locally to project, copy ceedling, unity, cmock, & supports to vendor
  95. unless use_gem
  96. FileUtils.mkdir_p ceedling_path
  97. #copy full folders from ceedling gem into project
  98. %w{plugins lib bin}.map do |f|
  99. {:src => f, :dst => File.join(ceedling_path, f)}
  100. end.each do |f|
  101. directory(f[:src], f[:dst], :force => force)
  102. end
  103. # mark ceedling as an executable
  104. File.chmod(0755, File.join(ceedling_path, 'bin', 'ceedling')) unless is_windows?
  105. #copy necessary subcomponents from ceedling gem into project
  106. sub_components = [
  107. {:src => 'vendor/c_exception/lib/', :dst => 'vendor/c_exception/lib'},
  108. {:src => 'vendor/cmock/config/', :dst => 'vendor/cmock/config'},
  109. {:src => 'vendor/cmock/lib/', :dst => 'vendor/cmock/lib'},
  110. {:src => 'vendor/cmock/src/', :dst => 'vendor/cmock/src'},
  111. {:src => 'vendor/deep_merge/lib/', :dst => 'vendor/deep_merge/lib'},
  112. {:src => 'vendor/diy/lib', :dst => 'vendor/diy/lib'},
  113. {:src => 'vendor/unity/auto/', :dst => 'vendor/unity/auto'},
  114. {:src => 'vendor/unity/src/', :dst => 'vendor/unity/src'},
  115. ]
  116. sub_components.each do |c|
  117. directory(c[:src], File.join(ceedling_path, c[:dst]), :force => force)
  118. end
  119. end
  120. # We're copying in a configuration file if we haven't said not to
  121. if (use_configs)
  122. if use_gem
  123. copy_file(File.join('assets', 'project_as_gem.yml'), File.join(name, 'project.yml'), :force => force)
  124. else
  125. copy_file(File.join('assets', 'project_with_guts.yml'), File.join(name, 'project.yml'), :force => force)
  126. if is_windows?
  127. copy_file(File.join('assets', 'ceedling.cmd'), File.join(name, 'ceedling.cmd'), :force => force)
  128. else
  129. copy_file(File.join('assets', 'ceedling'), File.join(name, 'ceedling'), :force => force)
  130. File.chmod(0755, File.join(name, 'ceedling'))
  131. end
  132. end
  133. end
  134. # Copy the gitignore file if requested
  135. if (use_ignore)
  136. copy_file(File.join('assets', 'default_gitignore'), File.join(name, '.gitignore'), :force => force)
  137. end
  138. unless silent
  139. puts "\n"
  140. puts "Project '#{name}' #{force ? "upgraded" : "created"}!"
  141. puts " - Tool documentation is located in vendor/ceedling/docs" if use_docs
  142. puts " - Execute 'ceedling help' to view available test & build tasks"
  143. puts ''
  144. end
  145. end
  146. end
  147. desc "examples", "list available example projects"
  148. def examples()
  149. puts "Available sample projects:"
  150. FileUtils.cd(File.join(here, "examples")) do
  151. Dir["*"].each {|proj| puts " #{proj}"}
  152. end
  153. end
  154. desc "example PROJ_NAME [DEST]", "new specified example project (in DEST, if specified)"
  155. def example(proj_name, dest=nil)
  156. if dest.nil? then dest = proj_name end
  157. copy_assets_and_create_structure(dest, true, false, {:local=>true, :docs=>true})
  158. dest_src = File.join(dest,'src')
  159. dest_test = File.join(dest,'test')
  160. dest_project = File.join(dest,'project.yml')
  161. directory "examples/#{proj_name}/src", dest_src
  162. directory "examples/#{proj_name}/test", dest_test
  163. remove_file dest_project
  164. copy_file "examples/#{proj_name}/project.yml", dest_project
  165. puts "\n"
  166. puts "Example project '#{proj_name}' created!"
  167. puts " - Tool documentation is located in vendor/ceedling/docs"
  168. puts " - Execute 'ceedling help' to view available test & build tasks"
  169. puts ''
  170. end
  171. desc "version", "return the version of the tools installed"
  172. def version()
  173. require 'ceedling/version.rb'
  174. puts " Ceedling:: #{Ceedling::Version::CEEDLING}"
  175. puts " CMock:: #{Ceedling::Version::CMOCK}"
  176. puts " Unity:: #{Ceedling::Version::UNITY}"
  177. puts " CException:: #{Ceedling::Version::CEXCEPTION}"
  178. end
  179. end
  180. if (ARGV[0] =~ /^\-T$/)
  181. puts "\n(No Project Detected, Therefore Showing Options to Create Projects)"
  182. CeedlingTasks.tasks.each_pair do |k,v|
  183. puts v.usage.ljust(25,' ') + v.description
  184. end
  185. puts "\n"
  186. else
  187. CeedlingTasks.source_root here
  188. CeedlingTasks.start
  189. end
  190. #===================================== We Have A Project Already ================================================
  191. else
  192. require 'yaml'
  193. require 'rbconfig'
  194. #determine platform
  195. platform = begin
  196. case(RbConfig::CONFIG['host_os'])
  197. when /mswin|mingw|cygwin/i
  198. :mswin
  199. when /darwin/
  200. :osx
  201. else
  202. :linux
  203. end
  204. rescue
  205. :linux
  206. end
  207. #create our default meta-runner option set
  208. options = {
  209. :pretest => nil,
  210. :args => [],
  211. :add_path => [],
  212. :path_connector => (platform == :mswin) ? ";" : ":",
  213. :graceful_fail => false,
  214. :which_ceedling => (Dir.exists?("vendor/ceedling") ? "vendor/ceedling" : 'gem'),
  215. :default_tasks => [ 'test:all' ],
  216. :list_tasks => false
  217. }
  218. #guess that we need a special script file first if it exists
  219. if (platform == :mswin)
  220. options[:pretest] = File.exists?("#{ platform.to_s }_setup.bat") ? "#{ platform.to_s }_setup.bat" : nil
  221. else
  222. options[:pretest] = File.exists?("#{ platform.to_s }_setup.sh") ? "source #{ platform.to_s }_setup.sh" : nil
  223. end
  224. #merge in project settings if they can be found here
  225. yaml_options = YAML.load_file(main_filepath)
  226. if (yaml_options[:paths])
  227. options[:add_path] = yaml_options[:paths][:tools] || []
  228. else
  229. options[:add_path] = []
  230. end
  231. options[:graceful_fail] = yaml_options[:graceful_fail] if yaml_options[:graceful_fail]
  232. options[:which_ceedling] = yaml_options[:project][:which_ceedling] if (yaml_options[:project] && yaml_options[:project][:which_ceedling])
  233. options[:default_tasks] = yaml_options[:default_tasks] if yaml_options[:default_tasks]
  234. #sort through command line options
  235. ARGV.each do |v|
  236. case(v)
  237. when /^(?:new|examples?|templates?)$/
  238. puts "\nOops. You called ceedling with argument '#{v}'.\n" +
  239. " This is an operation that will create a new project... \n" +
  240. " but it looks like you're already in a project. If you really \n" +
  241. " want to do this, try moving to an empty folder.\n\n"
  242. abort
  243. when /^help$/
  244. options[:list_tasks] = true
  245. when /^-T$/
  246. options[:list_tasks] = true
  247. when /^project:(\w+)/
  248. ENV['CEEDLING_USER_PROJECT_FILE'] = "#{$1}.yml"
  249. else
  250. options[:args].push(v)
  251. end
  252. end
  253. #add to the path
  254. if (options[:add_path] && !options[:add_path].empty?)
  255. path = ENV["PATH"]
  256. options[:add_path].each do |p|
  257. f = File.expand_path(File.dirname(__FILE__),p)
  258. path = (f + options[:path_connector] + path) unless path.include? f
  259. end
  260. ENV["PATH"] = path
  261. end
  262. # Load Ceedling (either through the rakefile OR directly)
  263. if (File.exists?("rakefile.rb"))
  264. load 'rakefile.rb'
  265. else
  266. if (options[:which_ceedling] == 'gem')
  267. require 'ceedling'
  268. else
  269. load "#{options[:which_ceedling]}/lib/ceedling.rb"
  270. end
  271. Ceedling.load_project
  272. end
  273. Rake.application.standard_exception_handling do
  274. if options[:list_tasks]
  275. # Display helpful task list when requested. This required us to dig into Rake internals a bit
  276. Rake.application.define_singleton_method(:name=) {|n| @name = n}
  277. Rake.application.name = 'ceedling'
  278. Rake.application.options.show_tasks = :tasks
  279. Rake.application.options.show_task_pattern = /^(?!.*build).*$/
  280. Rake.application.display_tasks_and_comments()
  281. else
  282. task :default => options[:default_tasks]
  283. # Run our Tasks!
  284. Rake.application.collect_command_line_tasks(options[:args])
  285. Rake.application.top_level
  286. end
  287. end
  288. true
  289. #===================================================================================================================
  290. end