class Drupid::Project
Base class for projects.
Attributes
The type of this project, which is one among ‘drupal’, ‘module’, ‘theme’ and ‘profile’, or nil if the type has not been determined or assigned. Note that this does not coincide with the ‘type’ field in a Drush
makefile, whose feasible values are ‘core’, ‘module’, ‘theme’, ‘profile’.
Public Class Methods
Creates a new Project
instance from the specified string. Note that the string must at least contain the core version of the project.
Raises a Drupid::NotDrupalVersionError
if the string cannot be parsed.
Examples:
proj = Drupid::Project.from_s 'drupal-7.23' proj = Drupid::Project.from_s 'drupal-8.x' proj = Drupid::Project.from_s 'media-7.x' proj = Drupid::Project.from_s 'tao-7.x-3.0-beta4'
# File lib/drupid/project.rb 289 def self.from_s p 290 matchdata = p.match(/^([^-\/]+)[-\/](\d+.*)$/) 291 raise NotDrupalVersionError if matchdata.nil? 292 name = matchdata[1] 293 vers = nil 294 if ('drupal' == name) and (matchdata[2] =~ /^(\d+)\.(\d+)/) # e.g., drupal-8.0-dev 295 core = $1.to_i 296 vers = matchdata[2] 297 else 298 matchversion = matchdata[2].match(/^(\d+)\.x-?(.*)/) 299 raise NotDrupalVersionError if matchversion.nil? 300 core = matchversion[1].to_i 301 vers = matchversion[2] 302 end 303 Project.new(name, core, vers) 304 end
Creates a new project with a given name and compatibility number. Optionally, specify a short version string (i.e., a version string without core compatibility number).
Examples:
p = Drupid::Project.new('cck', 6) p = Drupid::Project.new('views', 7, '1.2')
Drupid::Component::new
# File lib/drupid/project.rb 269 def initialize name, core_num, vers = nil 270 super(name) 271 @core = VersionCore.new(core_num) 272 @core_project = ('drupal' == @name) ? true : nil 273 @version = (vers.nil? or vers.empty?) ? nil : Version.from_s(@core.to_s + '-' + vers) 274 @proj_type = ('drupal' == @name) ? 'drupal' : nil 275 @info_file = nil 276 @release_xml = nil 277 end
Public Instance Methods
Compares this project with another to determine which is newer. The comparison returns nil if the two projects have different names or at least one of them has no version; otherwise, returns -1 if this project is older than the other, 1 if this project is more recent than the other, 0 if this project has the same version as the other.
# File lib/drupid/project.rb 431 def <=>(other) 432 return nil if @name != other.name 433 c = core <=> other.core 434 if 0 == c 435 return nil unless has_version? and other.has_version? 436 return version <=> other.version 437 else 438 return c 439 end 440 end
See Version
for the reason why we define == explicitly.
# File lib/drupid/project.rb 419 def ==(other) 420 @name == other.name and 421 @core == other.core and 422 @version == other.version 423 end
Returns the “best” version among those in the given list. Returns the current version of the project when version_list is empty.
# File lib/drupid/project.rb 606 def best_release version_list 607 if self.has_version? # Exclude releases older than the current one 608 version_list = version_list.select { |v| v >= self.version } 609 end 610 return self.version if version_list.empty? 611 stable_releases = version_list.select { |v| v.stable? } 612 if stable_releases.empty? 613 version_list.max { |a,b| a.better b } 614 else 615 stable_releases.max { |a,b| a.better b } 616 end 617 end
# File lib/drupid/project.rb 414 def core_project=(c) 415 @core_project = c 416 end
Returns true if this is a core project; returns false otherwise.
# File lib/drupid/project.rb 410 def core_project? 411 @core_project 412 end
Returns a list of the names of the extensions (modules and themes) upon which this project and its subprojects (the projects contained within this one) depend. Returns an empty list if no local copy of this project exists.
If :subprojects is set to false, subprojects’ dependencies are not computed.
Options: subprojects
# File lib/drupid/project.rb 462 def dependencies options = {} 463 return [] unless exist? 464 deps = Array.new 465 if options.has_key?(:subprojects) and (not options[:subprojects]) 466 reload_project_info unless @info_file and @info_file.exist? 467 info_files = [@info_file] 468 else 469 info_files = Dir["#{local_path}/**/*.info"] 470 end 471 info_files.each do |info| 472 f = File.open(info, "r").read 473 f.each_line do |l| 474 matchdata = l.match(/^\s*dependencies\s*\[\s*\]\s*=\s*["']?([^\s("']+)/) 475 if nil != matchdata 476 deps << matchdata[1].strip 477 end 478 matchdata = l.match(/^\s*base +theme\s*=\s*(.+)$/) 479 if nil != matchdata 480 d = matchdata[1].strip 481 deps << d.gsub(/\A["']|["']\Z/, '') # Strip leading and trailing quotes 482 end 483 end 484 end 485 # Remove duplicates and self-dependency 486 deps.uniq! 487 deps.delete(name) 488 return deps 489 end
Returns true if this object corresponds to Drupal core; returns false otherwise.
# File lib/drupid/project.rb 400 def drupal? 401 'drupal' == proj_type 402 end
Returns the name and the version of this project as a string, e.g., ‘media-7.x-2.0-unstable2’ or ‘drupal-7.14’. If no version is specified for this project, returns only the project’s name and core compatibility number.
# File lib/drupid/project.rb 446 def extended_name 447 if has_version? 448 return name + '-' + ((drupal?) ? version.short : version.long) 449 else 450 return name + '-' + core.to_s 451 end 452 end
Returns a list of the names of the extensions (modules and themes) contained in this project. Returns a list containing only the project’s name if no local copy of this project exists.
# File lib/drupid/project.rb 495 def extensions 496 return [name] unless exist? 497 # Note that the project's name may be different from the name of the .info file. 498 ext = [name] 499 Dir["#{local_path}/**/*.info"].map do |p| 500 ext << File.basename(p, '.info') 501 end 502 ext.uniq! 503 return ext 504 end
# File lib/drupid/project.rb 516 def fetch 517 if self.version.nil? and download_url.nil? and download_type.nil? 518 debug "Updating version of #{self.extended_name}" 519 self.update_version 520 end 521 # If the project has no version we fetch it even if it is cached. 522 # If the project has a download type, we fetch it even if it is cached 523 # (say the download type is 'git' and the revision is changed in the 524 # makefile, then the cached project must be updated accordingly). 525 if self.has_version? and self.download_type.nil? and self.cached_location.exist? 526 @local_path = self.cached_location 527 debug "#{self.extended_name} is cached" 528 else 529 blah "Fetching #{self.extended_name}" 530 if 'git' == self.download_type and self.download_url.nil? 531 self.download_url = "http://git.drupal.org/project/#{name}.git" 532 end 533 self.update_download_url if self.download_url.nil? 534 raise "No download URL defined for #{self.extended_name}" unless self.download_url 535 downloader = Drupid.makeDownloader self.download_url.to_s, 536 self.cached_location.dirname.to_s, 537 self.cached_location.basename.to_s, 538 self.download_specs.merge({:type => download_type}) 539 downloader.fetch 540 downloader.stage 541 @local_path = downloader.staged_path 542 end 543 self.reload_project_info unless self.drupal? 544 end
Fetches the release history for this project from updates.drupal.org.
# File lib/drupid/project.rb 379 def fetch_release_history 380 begin 381 debug "Getting release history from http://updates.drupal.org/release-history/#{self.name}/#{self.core}" 382 dont_debug do 383 @release_xml = Nokogiri::XML(open("http://updates.drupal.org/release-history/#{self.name}/#{self.core}")) 384 end 385 if @release_xml.at_xpath('/error') 386 debug "No release history for the given project" 387 @relese_xml = nil 388 else 389 debug "Release history retrieved" 390 end 391 rescue => ex 392 owarn "Could not fetch release history for #{self.extended_name}" 393 debug "fetch_release_history: #{ex}" 394 @release_xml = nil 395 end 396 end
Compares this project with another, returning an array of differences. If this project contains a makefile, ignore the content of the following directories inside the project: libraries, modules, profiles and themes.
Drupid::Component#file_level_compare_with
# File lib/drupid/project.rb 582 def file_level_compare_with tgt 583 args = Array.new 584 if makefile 585 args << '-f' << '- /libraries/***' # this syntax requires rsync >=2.6.7. 586 args << '-f' << '- /modules/***' 587 args << '-f' << '- /profiles/***' 588 args << '-f' << '- /themes/***' 589 end 590 if drupal? 591 args << '-f' << '+ /profiles/default/***' # D6 592 args << '-f' << '+ /profiles/minimal/***' # D7 593 args << '-f' << '+ /profiles/standard/***' # D7 594 args << '-f' << '+ /profiles/testing/***' # D7 595 args << '-f' << '- /profiles/***' 596 args << '-f' << '+ /sites/all/README.txt' 597 args << '-f' << '+ /sites/default/default.settings.php' 598 args << '-f' << '- /sites/***' 599 end 600 super(tgt, args) 601 end
Returns true if a version is specified for this project, false otherwise.
# File lib/drupid/project.rb 307 def has_version? 308 nil != @version 309 end
Returns the path to a makefile contained in this project, if any. Returns nil if this project does not contain any makefile. For an embedded makefile to be recognized, the makefile itself must be named ‘#name.make’ or ‘drupal-org.make’.
Requires: a local copy of this project.
# File lib/drupid/project.rb 567 def makefile 568 return nil unless self.exist? 569 paths = [ 570 local_path + "#{name}.make", 571 local_path + 'drupal-org.make' # Used in Drupal distributions 572 ] 573 paths.each do |p| 574 return p if p.exist? 575 end 576 return nil 577 end
Returns true if this is a profile; returns false otherwise.
# File lib/drupid/project.rb 405 def profile? 406 'profile' == proj_type 407 end
# File lib/drupid/project.rb 506 def reload_project_info 507 project_info = ProjectInfo.new(@local_path) 508 raise "Inconsistent naming: expected #{@name}, got #{project_info.project_name}" unless @name == project_info.project_name 509 raise "Inconsistent core: expected #{@core}, got #{project_info.project_core}" unless @core == project_info.project_core 510 @proj_type = project_info.project_type 511 @core_project = project_info.core_project? 512 @version = project_info.project_version 513 @info_file = project_info.info_file 514 end
Returns the relative path where this project should be installed within a platform. For example, for a module called ‘Foo’, it might be something like ‘modules/contrib/foo’.
# File lib/drupid/project.rb 550 def target_path 551 case proj_type 552 when 'drupal' 553 return Pathname.new('.') 554 when nil 555 raise "Undefined project type for #{name}." 556 else 557 return Pathname.new(proj_type + 's') + subdir + directory_name 558 end 559 end
Updates the download URL for the current version of this project.
Retrieves the release information for this project from updates.drupal.org.
# File lib/drupid/project.rb 360 def update_download_url 361 return unless self.has_version? 362 self.fetch_release_history if @release_xml.nil? 363 return if @release_xml.nil? 364 if @release_xml.at_xpath('/project/releases/release/files/file/variant').nil? 365 variant = '' 366 else 367 variant = "[variant='profile-only']" 368 end 369 v = self.drupal? ? self.version.short : self.version.long 370 url_node = @release_xml.at_xpath("/project/releases/release[status='published'][version='#{v}']/files/file#{variant}/url") 371 if url_node.nil? 372 owarn "Could not get download URL from http://updates.drupal.org for #{extended_name}" 373 else 374 self.download_url = url_node.child.to_s 375 end 376 end
Updates the version of this project to the latest (stable) release.
Retrieves the release information for this project from updates.drupal.org.
See also: Drupid::Project.best_release
# File lib/drupid/project.rb 339 def update_version 340 self.fetch_release_history if @release_xml.nil? 341 return self.version unless @release_xml 342 version_list = [] 343 version_nodes = @release_xml.xpath("/project/releases/release[status='published']/version") 344 version_nodes.each do |n| 345 v = n.child.to_s 346 # Remove version specifications that do not start with self.core. 347 # This seemingly superfluous test is needed because, for example, 348 # imce-7.x has a 'master' version (oh my!). 349 next if v !~ /^#{self.core.to_i}\./ 350 v.sub!("#{self.core}-", '') unless self.drupal? 351 version_list.push(Version.new(self.core, v)) 352 end 353 self.version = self.best_release(version_list) 354 debug "Version updated: #{extended_name}" 355 end
Returns the version of this project as a Drupid::Version
object, or nil if this project has not been assigned a version.
# File lib/drupid/project.rb 313 def version 314 @version 315 end
Assigns a version to this project. The argument must be a String object or a Drupid::Version
object. For the syntax of the String argument, see Drupid::Version
.
# File lib/drupid/project.rb 320 def version=(new_version) 321 return @version = nil if new_version.nil? 322 if new_version.is_a?(Version) 323 temp_version = new_version 324 elsif new_version.is_a?(String) 325 v = new_version 326 temp_version = Version.from_s(v) 327 else 328 raise NotDrupalVersionError 329 end 330 raise NotDrupalVersionError, "Incompatible version for project #{self.extended_name}: #{temp_version.long}" if temp_version.core != self.core 331 @version = temp_version 332 end