class Drupid::ProjectInfo

A convenience class that encapsulates methods for detecting some project’s properties from a local copy of a project.

Attributes

info_file[R]

The full path to the main .info file of this project

project_core[R]

The project’s core compatibility number. See Drupid::VersionCore.

project_dir[R]

The full path to the project’s directory.

project_name[R]

The project’s name.

project_type[R]

The project’s type (‘core’, ‘module’, ‘theme’, ‘profile’).

project_version[R]

The project’s version. See Drupid::Version.

Public Class Methods

new(project_or_info_path) click to toggle source

The argument must be the path to a .info file or a project directory. If the path to a directory is passed, then this object will try automatically detect the .info file inside the directory, which is not a trivial task because, among the rest,

  • the .info file may be located in some sub-directory;

  • there may be more than one .info file;

  • the .info file name may be unrelated to the name of its containing directories.

Faithful to its name, Drupid won’t try to be too keen, and it will raise an exception if it cannot reliably detect a .info file.

   # File lib/drupid/project.rb
56 def initialize(project_or_info_path)
57   p = Pathname.new(project_or_info_path).realpath # must exist
58   @project_core = nil
59   @project_type = nil
60   @project_version = nil
61   if '.info' == p.extname
62     @project_name = p.basename('.info').to_s
63     @info_file = p
64     grandparent = @info_file.parent.parent
65     if grandparent.basename.to_s == @project_name
66       @project_dir = grandparent
67     else
68       @project_dir = @info_file.parent
69     end
70   else
71     @project_name = p.basename.to_s
72     @project_dir = p
73     @info_file = _identify_main_info_file
74   end
75   debug "Parsing project info from #{@info_file}"
76   _parse_info_file
77 end

Public Instance Methods

core_project?() click to toggle source
   # File lib/drupid/project.rb
79 def core_project?
80   @is_core_project
81 end

Private Instance Methods

_check_project_name() click to toggle source

If the .info file name differs from the name of the containing directory and the .info file contains a ‘project’ field, do the following:

  • if <project name>.info does not exist and if the ‘project’ field is the same as the .info file name or the directory name, update the project’s name accordingly.

This check will fix, for example, the project’s name for a project like Google Analytics, whose project’s name is ‘google_analytics’ but the .info file is called ‘googleanalytics.info’. It will also fix the project’s name when the directory name has been changed and this object has been passed the path to the project’s directory rather than the path to the .info file.

Testing that <project name>.info does not exist is necessary to avoid renaming projects when more than one .info file exists in the same directory (see for example the Entity module).

    # File lib/drupid/project.rb
176 def _check_project_name
177   dirname = @project_dir.basename.to_s
178   if @project_name != dirname and # E.g., 'featured_news' != 'featured_news_feature'
179   !(@info_file.dirname+(dirname+'.info')).exist? and # E.g., '.../featured_news_feature/featured_news_feature.info' does not exist
180   @info_data.has_key?('project')
181     pn = @info_data['project']
182     if pn == @info_file.basename('.info').to_s or pn == dirname
183       @project_name = pn
184     end
185   end
186 end
_identify_main_info_file() click to toggle source

Returns the absolute path of the “main” .info file of this project. The first file satisfying one of the following heuristics is returned:

  1. ‘./#name.info’ exists.

  2. ‘./#name/#name.info’ exists.

  3. ‘./<any name>.info’ exists and no other .info file exists at the top-level.

  4. ‘./#name/<any name>.info’ exists and no other .info file exists inside ‘./#name’.

  5. There is a unique .info file, anywhere inside the project’s folder.

If none of the above is satisfied, pick any .info file and set the project’s name after the .info file’s ‘project’ field (if any). Then return that .info file.

Finally, if the .info file has no ‘project’ field, give up hoping that one day Drupal will have better specifications and that people will eventually follow the specifications—but complain fiercely by raising an exception.

    # File lib/drupid/project.rb
102 def _identify_main_info_file
103   attempts = [
104     @project_dir + (@project_name + '.info'),
105     @project_dir + @project_name + (@project_name + '.info'),
106     @project_dir + '*.info',
107     @project_dir + @project_name + '*.info',
108     @project_dir+'**/*.info'
109   ]
110   attempts.each do |p|
111     list = Pathname.glob(p.to_s)
112     if 1 == list.size and list.first.exist?
113       # Set the project's name after the .info file name
114       @project_name = list.first.basename('.info').to_s
115       return list.first
116     end
117   end
118   # We get here if all the above has failed.
119   Pathname.glob(@project_dir.to_s+'/**/*.info').each do |p|
120     data = p.open("r").read
121     match = data.match(/project\s*=\s*["']?(.+)["']?/)
122     unless match.nil?
123       @project_name = match[1].strip
124       return p
125     end
126   end
127   # Give up :/
128   raise "The .info file for #{@project_name} cannot be reliably detected"
129 end
_parse_info_file() click to toggle source

Extracts the relevant information from the .info file.

    # File lib/drupid/project.rb
132 def _parse_info_file
133   _read_info_file
134   _check_project_name
135   _set_project_version
136   _set_project_type
137 end
_read_info_file() click to toggle source

Reads the content of the .info file into a hash. Parses only ‘simple’ key-value pairs (of the form X = v). Then, check for some other keys useful to determine the project’s type (e.g, ‘stylesheets’)

    # File lib/drupid/project.rb
143 def _read_info_file
144   @info_data = Hash.new
145   data = @info_file.open("r").read
146   data.each_line do |l|
147     next if l =~ /^\s*$/
148     next if l =~ /^\s*;/
149     if l.match(/^(.+)=(.+)$/)
150       key   = $~[1].strip
151       value = $~[2].strip.gsub(/\A["']|["']\Z/, '')
152       @info_data[key] = value
153     end
154   end
155   @info_data['stylesheets'] = true if data.match(/^\s*stylesheets */)
156   @info_data['regions'] = true if data.match(/^\s*regions */)
157 end
_set_project_core() click to toggle source
    # File lib/drupid/project.rb
188 def _set_project_core
189   @info_data['core'].match(/^(\d+)\.x$/)
190   raise "Missing mandatory core compatibility for #{@project_name}" unless $1
191   @project_core = VersionCore.new($1)
192 end
_set_project_type() click to toggle source

Requires: @info_data must not be nil

    # File lib/drupid/project.rb
206 def _set_project_type
207   # Determine whether this is a core project
208   if (@info_data.has_key?('package') and @info_data['package'] =~ /Core/i) or
209   (@info_data.has_key?('project') and @info_data['project'] =~ /drupal/i)
210     @is_core_project = true
211   else
212     @is_core_project = false
213   end
214   # Determine the project's type (module, profile or theme)
215   if @info_file.sub_ext('.profile').exist?
216     @project_type = 'profile'
217   elsif @info_file.sub_ext('.module').exist?
218     @project_type = 'module'
219   elsif @info_data.has_key?('engine')  or
220   @info_data.has_key?('Base theme') or
221   @info_data.has_key?('base theme') or
222   @info_data.has_key?('stylesheets') or
223   @info_data.has_key?('regions')
224     @project_type = 'theme'
225   end
226   # If the above didn't work, examine the path the project is in as a last resort.
227   # This is needed, at least, to avoid "type cannot be determined" errors
228   # for some test directories in Drupal Core, which contain an .info file
229   # but no other file :/
230   unless project_type
231     @project_dir.each_filename do |p|
232       case p
233       when 'modules'
234         @project_type = 'module'
235       when 'themes'
236         @project_type = 'theme'
237       when 'profiles'
238         @project_type = 'profile'
239       end
240     end
241   end
242   raise "The project's type for #{@project_name} cannot be determined" unless @project_type
243 end
_set_project_version() click to toggle source
    # File lib/drupid/project.rb
194 def _set_project_version
195   _set_project_core
196   if @info_data.has_key?('version')
197     v = @info_data['version']
198     v = @project_core.to_s + '-' + v if v !~ /^#{@project_core}-/
199     @project_version = Version.from_s(v)
200   else
201     @project_version = nil
202   end   
203 end