Skip to main content

Inheriting your Drupal profile from an existing distribution

Mike Potter | Principal Engineer, CMS

June 28, 2012


 

Overview

In Drupal you can have base themes and sub-themes where sub-themes inherit the functionality of their base theme. Wouldn't it be cool if you could do the same thing with Drupal install profiles and make files? Imagine creating your own profile that inherited all the functionality of OpenPublic. Now you can, and this article will show you how easy it is.

Inheriting a profile

The first question you should probably ask is: "Why would I want to inherit from an existing profile?" After all, you can always just copy the profile.make, profile.profile, and profile.info files, rename them to be your own and then have your own profile. Having your own profile gives you complete control over it's contents. Inheriting from an existing profile requires some level of trust that the creators of the base distribution are including the correct versions of the modules that you need. Why give up that control? On the flip-side, do you really want to be in charge of figuring out which patches to apply to which module versions needed with the latest Drupal update? If a distribution is using 40 modules, the effort involved in keeping everything in the distribution working well across upgrades is non-trivial. Do you really want to spend your time dealing with module upgrades all the time? Everybody will probably have different answers to these questions. But what if you could leverage the work from existing distributions *without* giving up control over specific module versions and patches? Turns out you can.

Installation profiles

A basic Drupal installation profile looks similar to a Drupal module. You create a myprofile.info file that names the profile and lists which modules to enable: (for more detail, see "How to Write a Drupal 7 Installation Profile")

name = Profile Name
description = Description of what the profile does.
core = 7.x
dependencies[] = views
dependencies[] = views_ui
dependencies[] = node_reference
dependencies[] = features
...

Then you create a myprofile.profile file which contains anything else you need to do (similar to a *.module file for modules). When inheriting from other profiles you might need to add functions to call the parent routines. For example, if I inherited from OpenPublic, I probably want to inherit it's app server config:

/**
 * Implements hook_apps_servers_info.
 */
require_once ("profiles/openpublic/openpublic.profile");
function myprofile_apps_servers_info() {
  return openpublic_apps_servers_info();
}

Drush Make files

Profiles are great for just enabling modules within Drupal. But what about downloading the other modules to your site in the first place? That is where "make" files come into play. A "make" file is a list of resources (modules, themes, etc) to be downloaded to create the actual Drupal file structure. Instead of just manually downloading Drupal and the modules you need, you "run" your make file using a tool called Drush (If you haven't used Drush, go download it and learn about it as it's the most important tool you can have to manage a Drupal site). A simple myprofile.make file might look like this:

api = 2
core = 7.x
; specify which version of Drupal to download
projects[drupal][type] = core
projects[drupal][version] = 7.14

; now specify which modules and themes we want
projects[views][version] = 3.3
projects[references][version] = 2.0
projects[features][version] = 1.0-rc3
projects[omega][version] = 3.1  ; themes are just like modules
...

To build your initial Drupal directory structure using this make file, you simply do: drush make myprofile.make /path/to/drupal and drush will download the specified Drupal core files along with all specified module files. Once you have built your Drupal site, add a symbolic link to your profile: ln -s /path/to/profile /path/to/drupal/profiles/profilename Then when you go to your new site page in your web browser, it should run install.php and show your profile as one of the install options. Drupal will then configure the site and enable the modules specified in the profile.info file. You can also add libraries to your make file, like this:

libraries[ckeditor][download][type] = get
libraries[ckeditor][download][url] = http://download.cksource.com/CKEditor/CKEditor/CKEditor%203.6.1/ckeditor...
libraries[ckeditor][directory_name] = ckeditor

using http GET or via git (change type to "git"). The archive will be expanded and placed in the specified sub-directory of the sites/all/libraries folder.

Specifying Versions and Patches

One of the really cool features of drush make files is the ability to specify the exact revision of a module and also apply patches to it. In the above example, we downloaded the "7.x-1.0-rc3" release of the Features module. But what if a module doesn't have an official release and we need a specific "dev" version or branch? Just add lines to your make file with the revision or branch name:

projects[features][type] = module
projects[features][download][type] = git
projects[features][download][url] = http://git.drupal.org/project/features.git
projects[features][download][revision] = a4d3fc9593a65aba335de617feccc86a2bc9947e

where the "revision" can be the name of a branch or the uuid of a specific revision (as shown above). You should never just refer to a "dev" version of a module since it might change at any time; always point your profiles to a specific version of a module. To apply a patch to a module, add patch lines to the make file telling Drush where to find them:

projects[views][patch][] = http://drupal.org/files/Overide-Title-displays-Key-1477814-3.patch

Here we give it the exact http download path for the patch file. You should generally test to ensure your patch files will apply properly to the version of the module you are downloading before putting them into your make file. One beauty of this method is that your profile.make file completely documents exactly which modules and versions are being used on your site, along with which patches. No longer do you need to worry that some module on your site has been modified without anybody knowing about it. Never modify the module files directly; create a patch for the issue you are having and place that patch somewhere accessible by your make file (preferably the module issue queue on drupal.org). You don't need to wait for the module maintainer to apply your patch, you can still download it and apply it yourself in your make file. As you build your web site, it's good practice to export your various content types, views, and other configuration into Features (using the Features module) and then add those exported modules to your profile.make file. With this strategy you can rebuild all of the code for your site at any time by re-executing the drush make command. Paired with a sql dump of your database, this makes it easy to deploy your site.

Inherited Profiles

To actually inherit from an existing profile we need to change two things: 1) Tell Drupal the "base" profile name, 2) Tell Drush to execute the "base" make file. To tell Drupal the name of the base profile, add this line to your profilename.info file:

base = base-profile-name

where "base-profile-name" is the name of the profile you wish to inherit from, such as "openpublic". This should be the filename of the base profile without any extension or path. To execute the make file of your base profile, simply add it to your profile.make file similar to referencing another module:

projects[openpublic][type] = profile
projects[openpublic][download][type] = git
projects[openpublic][download][url] = http://git.drupal.org/project/openpublic.git
projects[openpublic][download][branch] = 7.x-1.0.4

Simple, right! Just specify the "type" of "profile" instead of "module" and drush will download it and then recursively run the make file of the base profile. In fact, you can nest this as far as you want, creating sub-sub-profiles that inherited from sub-profiles that inherit from profiles.

Drupal Patch Needed

But wait, there is one final detail. While drush has recursive nesting of profiles built-in, Drupal itself still needs a small tweak. When you reference a module in Drupal, you need to tell it what order to look into the other profile directories. You want any module within your main profile directory to take precedence over any module with the same name in the base profile. This allows your profile to use a newer version of a module or apply different patches than the same module in the base distribution. The patch needed for Drupal is here: Make install profiles inheritable. A patch for both Drupal 7 and Drupal 8 is provided and the issue is marked for back-porting to Drupal 7. The patch itself is very simple and has no effect on any site unless the "base = base-profile-name" line is found in the profile.info file. You can easily include this patch in your make file near the top where you specify the version of Drupal you are using:

projects[drupal][type] = core
projects[drupal][version] = 7.14
projects[drupal][patch][] = http://drupal.org/files/1356276-make-D7-21.patch

Any other needed core patches can be added in the same way.

Versions of Drush

If your profile installs a different version of a module that was already included in the base profile, the result will vary depending upon what version of Drush you are using. With Drush 4.5, drush will actually *remove* the old module from the base profile directory. For example, if you override the Features module in your profile, the /profiles/base-profile/modules/features directory will be deleted and only the new version of the Features module will be added to your /sites/all/modules/features directory. While this helped the old version of drush find the correct version of a module (by deleting the old version), it wasn't really the expected functionality. This issue was "fixed" in Drush 5. In Drush 5.4, both versions of the module will be retained and drush will properly use the modules in /sites/all/modules over the version in the /profiles/modules directory. Drush will also modify the module.info file to indicate that it has been overridden, so if you look at the module info using "drush pmi modulename" you might see a version like "7.x-1.0-rc2+0-dev" where the "+0-dev" was added by drush to indicate the module is overridden. You can surpress this behavior using the --no-gitinfofile option for "drush make". When patching modules from the base profile and using Drush 5, you will end up with two copies of the module: 1) the original module from the base make file (in profiles/base-profile-name), and 2) the newly patched module in sites/all/modules. At some later time, the base distribution might be updated to include your patch. When you remove your patch from your own make file and just use the updated distribution you'll go back to only having a single copy of the module in the profiles/base-profile-name directory. But your Drupal database will still be looking for the module in sites/modules/all. If this happens and Drupal does not automatically locate the new module, simply rebuild the Drush registry using the "drush rr" command. If your version of Drush does not have the registry-rebuild command, simply download it via "drush dl registry-rebuild".

Future Plans

Currently the patch to Drupal core only involves changing the search path for modules. In the future we could also include the base *.profile file automatically so you don't need to call it from your own profile. We could also run the install hooks for the base profile that your profile does not override. Most of this work involves deciding how we want profiles to work in Drupal 8 so that inherited profiles are part of the supported functionality.

Conclusion

As shown above, you can create your own profile that inherits from any existing Drupal profile. In your own profile you can override any module version and even add different patches to modules. You might end up with multiple copies of modules on your site, but the patch to Drupal core will ensure that the correct module version is used. In your profile.install file you can disable any modules in the base distribution that you don't want. In your profile.profile file you can call any functions in the base distribution to configure features such as app servers. You'll end up with the best of both worlds: a completely customizable profile that defers the configuration of base modules to the community. Let the community do the work of determining which modules are compatible and just focus on your project-specific profile work.


Recommended Next
Development
A Developer's Guide For Contributing To Drupal
Black pixels on a grey background
Development
3 Steps to a Smooth Salesforce Integration
Black pixels on a grey background
Development
Drupal 8 End of Life: What You Need To Know
Woman working on a laptop
Jump back to top