| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  | module MacOS::Xcode extend self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   V4_BUNDLE_ID = "com.apple.dt.Xcode" | 
					
						
							|  |  |  |   V3_BUNDLE_ID = "com.apple.Xcode" | 
					
						
							|  |  |  |   V4_BUNDLE_PATH = Pathname.new("/Applications/Xcode.app") | 
					
						
							|  |  |  |   V3_BUNDLE_PATH = Pathname.new("/Developer/Applications/Xcode.app") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Locate the "current Xcode folder" via xcode-select. See: | 
					
						
							|  |  |  |   # man xcode-select | 
					
						
							| 
									
										
										
										
											2012-08-31 09:51:08 -04:00
										 |  |  |   # NOTE!! use Xcode.prefix rather than this generally! | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |   def folder | 
					
						
							|  |  |  |     @folder ||= `xcode-select -print-path 2>/dev/null`.strip | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Xcode 4.3 tools hang if "/" is set | 
					
						
							| 
									
										
										
										
											2012-07-12 03:10:57 -05:00
										 |  |  |   def bad_xcode_select_path? | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |     folder == "/" | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-17 17:18:17 -04:00
										 |  |  |   def latest_version | 
					
						
							|  |  |  |     case MacOS.version | 
					
						
							| 
									
										
										
										
											2013-06-15 09:33:30 -05:00
										 |  |  |     when "10.4"         then "2.5" | 
					
						
							|  |  |  |     when "10.5"         then "3.1.4" | 
					
						
							|  |  |  |     when "10.6"         then "3.2.6" | 
					
						
							|  |  |  |     when "10.7", "10.8" then "4.6.3" | 
					
						
							|  |  |  |     when "10.9"         then "5.0" | 
					
						
							| 
									
										
										
										
											2012-08-17 17:18:17 -04:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2013-06-04 13:58:08 +01:00
										 |  |  |       # Default to newest known version of Xcode for unreleased OSX versions. | 
					
						
							| 
									
										
										
										
											2013-06-11 14:26:11 +02:00
										 |  |  |       if MacOS.version > 10.9
 | 
					
						
							|  |  |  |         "5.0" | 
					
						
							| 
									
										
										
										
											2013-06-04 13:58:08 +01:00
										 |  |  |       else | 
					
						
							|  |  |  |         raise "Mac OS X '#{MacOS.version}' is invalid" | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-08-17 17:18:17 -04:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-22 22:26:09 -05:00
										 |  |  |   def outdated? | 
					
						
							|  |  |  |     version < latest_version | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-09 20:47:28 -05:00
										 |  |  |   def without_clt? | 
					
						
							|  |  |  |     version >= "4.3" and not MacOS::CLT.installed? | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |   def prefix | 
					
						
							|  |  |  |     @prefix ||= begin | 
					
						
							| 
									
										
										
										
											2012-08-31 09:51:08 -04:00
										 |  |  |       path = Pathname.new(folder) | 
					
						
							| 
									
										
										
										
											2013-04-15 15:00:57 -05:00
										 |  |  |       if path.absolute? and File.executable? "#{path}/usr/bin/make" | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |         path | 
					
						
							|  |  |  |       elsif File.executable? '/Developer/usr/bin/make' | 
					
						
							|  |  |  |         # we do this to support cowboys who insist on installing | 
					
						
							|  |  |  |         # only a subset of Xcode | 
					
						
							| 
									
										
										
										
											2013-04-15 15:00:57 -05:00
										 |  |  |         Pathname.new('/Developer') | 
					
						
							|  |  |  |       elsif File.executable? "#{V4_BUNDLE_PATH}/Contents/Developer/usr/bin/make" | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |         # fallback for broken Xcode 4.3 installs | 
					
						
							| 
									
										
										
										
											2013-04-15 15:00:57 -05:00
										 |  |  |         Pathname.new("#{V4_BUNDLE_PATH}/Contents/Developer") | 
					
						
							| 
									
										
										
										
											2013-07-21 16:41:51 -05:00
										 |  |  |       elsif (path = bundle_path) | 
					
						
							|  |  |  |         path += "Contents/Developer" | 
					
						
							|  |  |  |         path if File.executable? "#{path}/usr/bin/make" | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-21 16:41:51 -05:00
										 |  |  |   # Ask Spotlight where Xcode is. If the user didn't install the | 
					
						
							|  |  |  |   # helper tools and installed Xcode in a non-conventional place, this | 
					
						
							|  |  |  |   # is our only option. See: http://superuser.com/questions/390757 | 
					
						
							|  |  |  |   def bundle_path | 
					
						
							|  |  |  |     MacOS.app_with_bundle_id(V4_BUNDLE_ID) || MacOS.app_with_bundle_id(V3_BUNDLE_ID) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |   def installed? | 
					
						
							| 
									
										
										
										
											2012-12-29 17:16:38 -06:00
										 |  |  |     not prefix.nil? | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def version | 
					
						
							|  |  |  |     # may return a version string | 
					
						
							|  |  |  |     # that is guessed based on the compiler, so do not | 
					
						
							|  |  |  |     # use it in order to check if Xcode is installed. | 
					
						
							| 
									
										
										
										
											2012-08-06 13:46:02 -04:00
										 |  |  |     @version ||= uncached_version | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-06 13:46:02 -04:00
										 |  |  |   def uncached_version | 
					
						
							|  |  |  |     # This is a separate function as you can't cache the value out of a block | 
					
						
							|  |  |  |     # if return is used in the middle, which we do many times in here. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return "0" unless MACOS | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-06 13:46:02 -04:00
										 |  |  |     # this shortcut makes version work for people who don't realise you | 
					
						
							|  |  |  |     # need to install the CLI tools | 
					
						
							| 
									
										
										
										
											2013-04-15 15:00:57 -05:00
										 |  |  |     xcode43build = Pathname.new("#{prefix}/usr/bin/xcodebuild") | 
					
						
							| 
									
										
										
										
											2012-08-06 13:46:02 -04:00
										 |  |  |     if xcode43build.file? | 
					
						
							|  |  |  |       `#{xcode43build} -version 2>/dev/null` =~ /Xcode (\d(\.\d)*)/ | 
					
						
							| 
									
										
										
										
											2012-08-07 14:34:27 -04:00
										 |  |  |       return $1 if $1 | 
					
						
							| 
									
										
										
										
											2012-08-06 13:46:02 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Xcode 4.3 xc* tools hang indefinately if xcode-select path is set thus | 
					
						
							|  |  |  |     raise if bad_xcode_select_path? | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-06 13:46:02 -04:00
										 |  |  |     raise unless which "xcodebuild" | 
					
						
							|  |  |  |     `xcodebuild -version 2>/dev/null` =~ /Xcode (\d(\.\d)*)/ | 
					
						
							|  |  |  |     raise if $1.nil? or not $?.success? | 
					
						
							|  |  |  |     $1 | 
					
						
							|  |  |  |   rescue | 
					
						
							|  |  |  |     # For people who's xcode-select is unset, or who have installed | 
					
						
							|  |  |  |     # xcode-gcc-installer or whatever other combinations we can try and | 
					
						
							|  |  |  |     # supprt. See https://github.com/mxcl/homebrew/wiki/Xcode | 
					
						
							|  |  |  |     case MacOS.llvm_build_version.to_i | 
					
						
							|  |  |  |     when 1..2063 then "3.1.0" | 
					
						
							|  |  |  |     when 2064..2065 then "3.1.4" | 
					
						
							|  |  |  |     when 2366..2325
 | 
					
						
							|  |  |  |       # we have no data for this range so we are guessing | 
					
						
							|  |  |  |       "3.2.0" | 
					
						
							|  |  |  |     when 2326
 | 
					
						
							|  |  |  |       # also applies to "3.2.3" | 
					
						
							|  |  |  |       "3.2.4" | 
					
						
							|  |  |  |     when 2327..2333 then "3.2.5" | 
					
						
							|  |  |  |     when 2335
 | 
					
						
							|  |  |  |       # this build number applies to 3.2.6, 4.0 and 4.1 | 
					
						
							|  |  |  |       # https://github.com/mxcl/homebrew/wiki/Xcode | 
					
						
							|  |  |  |       "4.0" | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       case (MacOS.clang_version.to_f * 10).to_i | 
					
						
							| 
									
										
										
										
											2013-02-04 14:42:37 -06:00
										 |  |  |       when 0       then "dunno" | 
					
						
							| 
									
										
										
										
											2013-01-29 09:51:01 -06:00
										 |  |  |       when 1..14   then "3.2.2" | 
					
						
							|  |  |  |       when 15      then "3.2.4" | 
					
						
							|  |  |  |       when 16      then "3.2.5" | 
					
						
							|  |  |  |       when 17..20  then "4.0" | 
					
						
							|  |  |  |       when 21      then "4.1" | 
					
						
							|  |  |  |       when 22..30  then "4.2" | 
					
						
							|  |  |  |       when 31      then "4.3" | 
					
						
							|  |  |  |       when 40      then "4.4" | 
					
						
							|  |  |  |       when 41      then "4.5" | 
					
						
							|  |  |  |       when 42      then "4.6" | 
					
						
							| 
									
										
										
										
											2013-06-11 14:26:11 +02:00
										 |  |  |       when 50      then "5.0" | 
					
						
							| 
									
										
										
										
											2013-01-29 09:51:01 -06:00
										 |  |  |       else "4.6" | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-07-09 15:19:30 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def provides_autotools? | 
					
						
							|  |  |  |     version.to_f < 4.3
 | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-07-10 21:01:16 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def provides_gcc? | 
					
						
							|  |  |  |     version.to_f < 4.3
 | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-09-14 13:24:28 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def default_prefix? | 
					
						
							|  |  |  |     if version.to_f < 4.3
 | 
					
						
							|  |  |  |       %r{^/Developer} === prefix | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       %r{^/Applications/Xcode.app} === prefix | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module MacOS::CLT extend self | 
					
						
							|  |  |  |   STANDALONE_PKG_ID = "com.apple.pkg.DeveloperToolsCLILeo" | 
					
						
							|  |  |  |   FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI" | 
					
						
							| 
									
										
										
										
											2013-06-25 16:49:08 +01:00
										 |  |  |   STANDALONE_PKG_PATH = Pathname.new("/Library/Developer/CommandLineTools") | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-21 16:41:50 -05:00
										 |  |  |   # True if: | 
					
						
							|  |  |  |   #  - Xcode < 4.3 is installed. The tools are found under /usr. | 
					
						
							|  |  |  |   #  - The "Command Line Tools" package has been installed | 
					
						
							|  |  |  |   #    For OS X < 10.9, the tools are found under /usr. For 10.9, | 
					
						
							|  |  |  |   #    they are found under /Library/Developer/CommandLineTools. | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |   def installed? | 
					
						
							| 
									
										
										
										
											2013-07-21 16:41:50 -05:00
										 |  |  |     mavericks_dev_tools? || usr_dev_tools? | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def mavericks_dev_tools? | 
					
						
							|  |  |  |     MacOS.dev_tools_path == Pathname("#{STANDALONE_PKG_PATH}/usr/bin") && | 
					
						
							|  |  |  |       File.directory?("#{STANDALONE_PKG_PATH}/usr/include") | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def usr_dev_tools? | 
					
						
							|  |  |  |     MacOS.dev_tools_path == Pathname("/usr/bin") && File.directory?("/usr/include") | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-17 17:18:17 -04:00
										 |  |  |   def latest_version? | 
					
						
							| 
									
										
										
										
											2013-01-29 07:44:19 -06:00
										 |  |  |     `/usr/bin/clang --version` =~ %r{clang-(\d+)\.(\d+)\.(\d+)} | 
					
						
							| 
									
										
										
										
											2013-04-16 11:42:49 +10:00
										 |  |  |     $1.to_i >= 425 and $3.to_i >= 28
 | 
					
						
							| 
									
										
										
										
											2012-08-17 17:18:17 -04:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-22 22:26:09 -05:00
										 |  |  |   def outdated? | 
					
						
							|  |  |  |     !latest_version? | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-21 20:09:55 -05:00
										 |  |  |   # Version string (a pretty damn long one) of the CLT package. | 
					
						
							|  |  |  |   # Note, that different ways to install the CLTs lead to different | 
					
						
							|  |  |  |   # version numbers. | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |   def version | 
					
						
							| 
									
										
										
										
											2013-07-21 20:09:55 -05:00
										 |  |  |     @version ||= detect_version | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def detect_version | 
					
						
							|  |  |  |     [STANDALONE_PKG_ID, FROM_XCODE_PKG_ID].find do |id| | 
					
						
							|  |  |  |       version = MacOS.pkgutil_info(id)[/version: (.+)$/, 1] | 
					
						
							|  |  |  |       return version if version | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2012-07-09 15:18:02 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | end |