class Drupid::Project

Base class for projects.

Attributes

core[R]
l10n_path[RW]
l10n_url[RW]
location[RW]
proj_type[RW]

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

from_s(p) click to toggle source

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
new(name, core_num, vers = nil) click to toggle source

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')
Calls superclass method 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

<=>(other) click to toggle source

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
==(other) click to toggle source

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
best_release(version_list) click to toggle source

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
core_project=(c) click to toggle source
    # File lib/drupid/project.rb
414 def core_project=(c)
415   @core_project = c
416 end
core_project?() click to toggle source

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
dependencies(options = {}) click to toggle source

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
drupal?() click to toggle source

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
extended_name() click to toggle source

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
extensions() click to toggle source

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
fetch() click to toggle source
    # 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
fetch_release_history() click to toggle source

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
file_level_compare_with(tgt) click to toggle source

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.

    # 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
has_version?() click to toggle source

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
makefile() click to toggle source

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
profile?() click to toggle source

Returns true if this is a profile; returns false otherwise.

    # File lib/drupid/project.rb
405 def profile?
406   'profile' == proj_type
407 end
reload_project_info() click to toggle source
    # 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
target_path() click to toggle source

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
update_download_url() click to toggle source

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
update_version() click to toggle source

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
version() click to toggle source

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
version=(new_version) click to toggle source

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