This patch is sponsored by Acquia (as well as a fair amount of my own time) and is a first attempt at rewriting Drupal's installer to allow non-interactive, command line installations.
There are obviously a number of projects that want to be able to install Drupal without clicking through pages in a web browser:
- Aegir and Drush.
- PIFR, which runs the Drupal 7 testbot.
- Simpletest itself, which needs to install Drupal 7 before each test suite is run.
- I hear Acquia has a project in the works... :)
Currently, all of the above are forced to install Drupal via fragile, hacked-together methods. The goal of this patch is to make it so they have a simple, clean, robust way to do so. #1, #2, and #4 should be immediately achievable with this patch - #3 is more complicated since the installation happens within the context of an already-installed D7 site, but hopefully would be achievable down the road.
As a side-effect of the refactoring that needed to occur to write this patch, this also hopefully improves the experience of writing install profiles. Currently, the installer passes a string to install profiles and asks them to modify it in such a way that they "implement a state machine" if they want to run more than one custom task. (Huh?) After this patch, install profiles would simply define a structured array describing as many tasks as they want to run, and the installer automatically takes care of stepping through the tasks correctly, for either interactive (browser-based) or non-interactive (command line) installations.
Currently, the patch works (although I have not tested all edge cases), but there are two things to note:
- There are deliberate code style violations in this patch (indentation), in order to keep it from being totally unreviewable. Obviously those would be easy to fix later.
- For a similar reason, the patch currently leaves all the installer functionality in install.php, though we'd obviously want to follow up by moving all these functions into a separate
includes/installer.inckind of file, where command line scripts could actually access it. Therefore, to actually test a command line installation with this patch, you currently need to hack the bottom of install.php and replaceinstall_drupal()with code similar to the following:
$settings = array( 'parameters' => array( 'profile' => 'default', 'locale' => 'en', ), 'forms' => array( 'install_settings_form' => array( 'driver' => 'mysql', 'database' => 'my_db_name', 'username' => 'my_db_username', 'password' => 'my_db_password', ), 'install_configure_form' => array( 'site_name' => 'My site', 'site_mail' => 'admin@example.com', 'account' => array( 'name' => 'admin', 'mail' => 'admin@example.com', 'pass' => array( 'pass1' => 'my_site_password', 'pass2' => 'my_site_password', ), ), 'update_status_module' => array(1 => TRUE), 'clean_url' => TRUE, ), ), ); install_drupal($settings);You can then run
php install.phpfrom the command line directly.
| Comment | File | Size | Author |
|---|---|---|---|
| #117 | install.core_.524728.117.patch | 147.29 KB | David_Rothstein |
| #115 | tmp.diff | 147.18 KB | moshe weitzman |
| #110 | install.core_.524728.110.patch | 147.18 KB | David_Rothstein |
| #104 | installcore.helper.1.txt | 761 bytes | David_Rothstein |
| #104 | installcore.helper.2.txt | 1.08 KB | David_Rothstein |
Comments
Comment #1
David_Rothstein commentedHere is the patch.
Thanks to Joshua Rogers for helping to review and debug earlier versions of this. Just based on looking at the patch, he predicted a couple specific tests that this might break (at least the earlier version of the patch), so we'll see if he was right - I have not actually run the tests yet at all :)
Comment #3
David_Rothstein commentedWell, that is a truly impressive number of failures - in fact, it may set the record :)
I promise that if you actually install Drupal with this patch and click around your site, it doesn't seem broken, so I guess we'll have to investigate to figure out what's going on.
Comment #4
David_Rothstein commentedDid not mean to set it back to need review -- certainly no need to relive the experience of seeing "7236 passes, 5600 fails, 991 exceptions" appear on the screen :)
Comment #5
moshe weitzman commentedsubscribe. thanks for your work here, david.
Comment #6
David_Rothstein commentedTurns out Mr. Rogers was 100% correct. The hacked installation in DrupalWebTestCase just needed to be hacked in a different way as a result of this patch.
This should hopefully fix most (if not all) of the test failures.
Comment #7
SeanBannister commentedSub, this is awesome.
Comment #8
cbrookins commentedAwesome work David
Comment #9
pwolanin commented@David - currently we specifically block simpletest from using install.php for security reasons. However, it would seem to make sense to get most of the code out of install.php and into a .inc file or some such (e.g. the way xmlrpc.php has nearly no code in it).
Comment #10
adrian commentedWe are using hacked together methods in aegir because we need to support d6 too.
we support making d7 easier to install from the command line.
Regarding tasks in .info files, I need to re-evaluate moving them back.
I believe that for most developers (except those developing exceptionally complex install profiles), they would be better served by having them in a simple format.
I am working on several issues regarding install profiles, and one of the issues I am working on is to make install profiles have access to all the drupal hooks, which would allow them to be extended via hook_info_alter.
see: #509404: Fix some conceptual problems with install profiles and make them actually usable
The other side effect of this would be that we could work towards making it possible for modules to add tasks during install.
I am aiming to make install profiles more like modules than they are now, and therefor I want to reduce the amount of additional hooks that are exclusively used in install profiles.
Comment #11
dries commentedAdrian, while I appreciate the install profile status update and the work you're doing (rock on!), I'm not sure how some of these comments are relevant to the patch. While install profiles can be improved so that they become more powerful and module-aware, there is always the initial Drupal install (e.g. installing the database, essential configuration, etc). Long story short, I'm not entirely sure what you're suggesting relative to this patch. Care to elaborate or to write a review?
Comment #12
adrian commentedDries : David commented on this related issue of mine (http://drupal.org/node/509392#comment-1830106)
This patch reverts some of the changes from there. I should have linked back to the previous issue.
I simply stated my concern in that the patch was adding back a hook that I removed to make install profiles easier to write, and also made the implementation of the hook more complex. This goes against my goal of making install profiles more like modules, as I would like install profiles to be using the standard Drupal API as much as possible without inventing their own special case hooks that might be served just as well by existing hooks.
I fully intend on writing a proper review of this patch, and I've been in contact with David regarding the approach and possible difficulties as well.
Comment #13
dries commentedAh, thanks for clarifying -- that helps. I don't know what you guys discussed in private, but I'm sure David (or you) will follow up. It sounds like it might have been an oversight/timing issue instead of an intentional re-introduction. I'm with you on making install profiles more like modules though! :) Looking forward to the follow-ups.
Comment #14
adrian commentedAfter discussion with David, I have come across an idea that I believe would simplify the process of automating Drupal installations, without being affected by the edge cases that install profiles can present :
#525594: Installation should consist of 2 phases instead of one
This mechanism would also be a preferred solution when building a hosted service such as acquia gardens or an aegir based solution, as it dramatically reduces the install profile specific information that is needed to be able to successfully provision a site.
Comment #15
boombatower commentedTo followup in regards to PIFR.
Since PIFR runs in 6.x and will test an externally installed Drupal 7 site it needs to be able to install it without changing any code. I assume that is in the words are you wrote.
The current script is as follows.
It would appear from reading that the re-factor supports what is needed, except as of now it require code modification to fill in the settings array. I assume is in the works to make something from command line that PIFR can just execute with parameters.
Overall, this appears to be exactly what is needed!
Comment #16
David_Rothstein commentedTo summarize a couple other things I discussed with @adrian:
1. The issue with the tasks is that currently in Drupal HEAD, a regular Drupal install profile does not need to deal with the task system at all, whereas with my patch they would have to write code like this:
This is a bit unfortunate and would be nice not to have to do.
My patch is much better in the case of a more complex install profile. For example, for an install profile that implements an extra installation step with a form, my patch requires only this:
And then myprofile_settings_form() is just a standard form API definition. I think this is a definite improvement over the current Drupal HEAD, where this kind of install profile would need to define this task in the .info file, rather than in a hook (that part is fine) but then would need to figure out on its own how to implement a "state machine" (that part's insane!).
I think that for now, the best way to get the benefits of both approaches is to look at @adrian's issue at #509400: Introduce .install files for install profiles. With that, simple profiles (that do not add anything to the user interface) would be able to put all their code in hook_install() and once again not need to deal with tasks at all, whereas more complex install profiles would be able to benefit from a more powerful and easier to use tasks system.
2. The second major issue we discussed had to do with scriptability of the Drupal installation. My patch works fine for simple profiles (for example, the code I posted at the top of this issue works exactly the same for the default and expert profiles - all you have to do is change
'profile' => 'default'to'profile' => 'expert'and everything works the same). It also works fine for more complicated install profiles, provided the person writing the script knows which profile is going to be installed and what extra data it needs to receive beyond that normally required for a core installation.It does not, however, allow you to write a generic installation script that works for any profile. If you tried to write such a script, certain profiles would cause your script to fail in such a catastrophic way that Drupal would never get installed at all. Getting around that limitation is the idea behind @adrian's proposal at #525594: Installation should consist of 2 phases instead of one -- as well as the fact that it would also enable other neat things, like a configuration wizard that runs when a new module is enabled on an existing site, etc.
In terms of the current patch, I don't think that idea affects things too much. Install profiles were not the main focus here -- the code I wrote works with them, but they could easily be taken out of this system later and moved elsewhere without changing much of the code. The vast majority of the code I wrote was there to support the core installation tasks.
The only possible simplification this might lead to down the line is that if we know every Drupal installation requires the same user input, then instead of doing programmatic form submission via drupal_form_submit() as the patch currently does, we might be able to have a command line script just ask for and save the data directly. However, currently profiles are allowed to modify the core "site configuration" form via hook_form_alter(), so we can't easily get rid of the form-based approach due to that.
If we could get rid of it, it would be nice, since currently the sample code I originally pasted in this issue requires a command line script to do things like this:
which is less than ideal and could be avoided if we did not have to implement a form-based approach.
In summary, I don't personally foresee any major changes that would be needed to get this patch committable, although we do have some interesting followup issues that can be pursued.
Comment #17
David_Rothstein commentedA couple more technical notes from my conversation with @adrian - putting them here to remember to think about them later. Most of them have to do with issues that might arise with the command line installer trying to do things in one page request that are traditionally done over many requests:
None of the above things seem to cause any problems with the default or expert profiles at the moment, but they could potentially be an issue with other, non-core install profiles.
Comment #18
adrian commentedDavid , while I still haven't had time to review the patch, my only concern with the current approach (and it's really a nitpick), is that this refactoring doesn't really turn it into a command line script but turns it into an API.
If it was a command line script, i would be able to do :
From my perspective (aegir and drush), I would be served fine by the API-fication, but if this issue is about installing Drupal from the command line it feels unfinished unless you can actually install drupal from the command line without having to write additional code.
If this is solely about creating an API for install.php, I think that unless you can include install.php from within a command line script,
this patch in itself lacks usefulness.
I also don't notice a way to install a site other than sites/default with this patch, but i might have missed that in reading the code.
I will take the time to review this patch properly soon.
Comment #19
JacobSingh commentedTested the patch, works great for me.
should probably add this to install.php:
if (realpath($_SERVER['SCRIPT_FILENAME']) == __FILE__) {
install_drupal();
}
This will allow a user to include install.php while not actually running it.
So the example above can run as a standalone script.
Ideally, the constants should either do a defined() check or be inside a block somewhere as well so they can be safely included.
I personally feel that an API is a good first step, and is worth committing. If we build a CLI app later, great, we still want an API. But also, I don't think a command line app is really useful. There would be so many damn switches, it would start to look like ffmpeg. I'd personally prefer a settings file I can pass in, and perhaps some overrides at a first iteration.
What I would change (although I think we should commit what we've got ASAP), is the code design. If it is an API, it should behave like one IMO, which means more than just one function, some validation, etc.
$di = new DrupalInstaller();
$di->setDomain();
try {
$di->setDatabaseDetails();
} catch DrupalInstaller_NoDBException() {
$di->createDatabase();
$di->setDatabaseDetails();
}
Anyway, that's not important for now. RTBC IMO.
Best,
Jacob
Comment #20
JacobSingh commentedOh, one other nitpiky thing... the settings array has pass1 and pass2. That's just kinda silly.
-J
Comment #21
adrian commentedI've read through the patch and I agree 100% with the approach, it's a lot cleaner and a lot simpler. I actually ended up writing my own wrapper around hook_profile_tasks, which ended up working very similarly.
I haven't done a functional test of the code yet however, and I'm still a bit unclear about handling pages that return plain text.
If the change that jacob suggests is implemented (ie: switch to stop the script from running when included), i support it to be RTBC
Comment #22
adrian commentedThis makes one very simple change to dbapi btw, which makes it a lot simpler to provide clean log information.
If we could get another review I'd RTBC it. moshe? dries?
Comment #23
anarcat commentedI have reviewed the patch quickly but I feel I am not in a position to confirm that it is proper as I do not know well enough the internals of the D7 install process. I do however fully support the inclusion of this patch into core as it will make things much easier for us (Aegir/Drush). The code does seem pretty sound. (Plus I want to subscribe to the issue. :)
Comment #24
webchickThe documentation of this patch is fantastic. It's a really big change diff-wise, but the code that's left over is very easy to read and follow IMO. I also really like the move to exception-based error handling rather than compiling a bunch of #markup code.
Let's namespace these so they appear grouped together on api.drupal.org. INSTALL_TASK_XXX. Also, minor, but there is an extra space between define() on #2. The PHPDoc should also be improved to indicate to developers when they might need to use these constants.
If "this" is passed in? What exactly is "this" that I pass in to get this to work from the command line? Is there another function that explains this? If so, let's add a reference to it.
Congratulations on the most well-documented function in all of Drupal! :D That's great!
Some more info here? Is this an array of form callbacks, or an array of $form_state['values'] arrays or..?
Could you define what it means to be at the end of the installation process? Is this after all tasks have completed, or all tasks plus import of languages (I saw a distinction elsewhere), or..?
Can I get a for example? locale and profile? if it's always URL parameters, could we maybe make this url_parameters rather than just parameters?
Why?
Why?
This seems to be in there an awful lot. Should that be the default value?
Indentation off here.
Indentation looks off here.
I know you didn't write this string, but can we please change those to "installation profiles" for consistency with everything else?
I only see - signs next to all calls to theme('install_page'). Did we lose the ability to theme the installer as part of this patch?
Had I not read one of the replies in this thread, I'd have no idea what that was doing. Please add a comment to explain.
This function is a flaming wtf to people who don't spend their lives monkeying about with command-line PHP. Can you add some more information to the PHPDoc as to why this function is needed?
Also, run-tests.sh and drupal.sh in /scripts both seem to have parts very similar to this. Can we replace those with calls to this function instead? And is there stuff from those scripts that needs to be replicated here?
I have no idea why that is here. I see that there's already a function with no PHPDoc explaining below it, so probably not for this patch to change, but why are you returning FALSE instead of nothing like the one below?
Overall, these comment improvements are fantastic! However, since realistically this is the only spot in all of core where we describe the installation process, a bit more overview of how it works here would be good, as I'm still left with questions. How do I know if I want a page request to end? How do I know if setting custom page titles is necessary?
Again, this is a little wishy-washy. Why might or might not I want to use variable_set/get?
Well, I can guess that from the name. ;) What does that actually mean, though? display_name hides a task from the list, this hides it from... the... screen? Then why bother having it in the first place? What's the use case?
Could we itemize the list of possible values as a sub-list so it's a bit easier to scan? See hook_menu() for an example.
Same here. And can you help me again with the "why"?
We should probably also add a @see batch_set() to explain the desired format of a batch array.
I was confused reading this (figured it out a few lines later). How about adding something like, "Here, we define a variable to allow tasks to trigger a batch process if they are about to start a processor-intensive task."
YAY!!! :D Just a question. Does it make sense to generalize this out in another issue to something modules can use as well? I don't know anyone but Jeff Eaton who can explain how multistep forms work currently. :P
This chunk has a lot more of these sort of wishy-washy "might" recommendations. Each time you use that word it leaves me with the question "Well why might I NOT want to do that?" It seems like at least calling variable_del() is a *should* and not a *might*. Maybe rephrase the second part as "if" rather than "might": "If you want the user to pass to the Drupal installation tasks uninterrupted, return no output from this function. Or, if you wish to..."
Comment #25
moshe weitzman commentedIn a follow-up issue, we should really create a new install profile that really configures your site for a blog or a knowledgebase or something. Once plugin manager is in core, is it legit for core profiles to download contrib modules? Good times.
Comment #26
JacobSingh commented@moshe weitzman
Sadly, #395480: Plugin Manager in Core: Part 4 (installation profiles) has not started yet. I hope we can get in, but the process has been rather slow given how straight forward most of the engineering is. Hopefully it will get more streamlined as people realize the deadline is fast approaching. If you would care to donate any precious time to the effort, #395474: Plugin Manager in Core: Part 2 (integration with update status) is pending fixes to make it work in Windows, and something from catch to prioritize minor over major versions.
Sorry to take this off topic.
Best,
Jacob
Comment #27
David_Rothstein commentedThanks for the reviews! I've attached a version with changes made based on @webchick's comments.
Also here are a few things that need responses, for both that review and the other ones:
I added the example as requested, but for now I did not change the name to 'url_parameters' since the URL is only relevant in the case of browser-based installations (not command line ones), and I think we want to keep this as general as possible.
This is definitely used several times, but mainly very early on in the installation process, only by Drupal core. I think it is better to leave the default as the one that install profiles are most likely to use; that way they don't have to worry about specifying it each time they write a task.
Yes, and that is only the most visible example of it -- there are many others :) As mentioned originally, I did this on purpose in order to try to keep the patch size manageable... for example, a lot of code in this patch needed to get moved from if() statements to individual functions, so those would have been gigantic blocks of changes that would have made the patch unreviewable. I could fix them now if you want, but that will make the patch file a lot bigger. (Alternatively, if this gets committed as is, I promise to do a very quick followup patch that fixes all the indentation!)
Nope, all the themed output has been consolidated into the install_display_output() function, which contains this line:
(Note that the switch from 'install_page' page to 'maintenance_page' partway through attempts to mimic what the installer is already doing before this patch is applied; I'm suspicious about whether it is necessary at all and whether we couldn't just use 'maintenance_page' always, but that would be a topic for a followup issue, I think.)
Right, this was added by Jacob as a neat little way to allow install.php to be includable by a command line script, which needs to happen currently since a bunch of API functions are in that file. In the long run I'm guessing we want to move those functions out of install.php and into a separate includable file, so I did add a comment to the code to explain it, but I phrased it more as a TODO.
Also, to respond to what adrian wrote, I agree that this issue is really more about adding an API than about having a command line script directly. It certainly wouldn't be hard to have a followup issue that added an install.sh type of script to core, though (with the caveat that it would only work for simple install profiles, as mentioned earlier). Probably Drush is the perfect place for this kind of thing, however, since as Jacob mentioned, a command line script would involve passing in a whole bunch of parameters, and Drush is well-equipped to handle that sort of thing, e.g. via a drushrc config file that can remember them for you.
I gave it a whirl, although I'm not quite sure I got it right; someone else who has done this more might want to take a look too.
By the way, this also answers @adrian's question about installing sites in places other than sites/default with this patch -- although I haven't actually tried it myself, in theory it should be possible to do that by passing
$settings['server']['url']as part of the array that gets sent to install_drupal().I agree it would be a good idea to use this function in those scripts as well, but I'm hoping that could be left to a followup patch since there could be some subtleties there...
I am honestly not sure exactly which $_SERVER settings do and don't matter in various cases; I sort of built up this function by borrowing from the existing scripts (as well as from Drush), and basically filling things in each time I encountered a new PHP error while testing out the command line installation :) It would certainly be great if someone who understands this better could take a closer look at what I put in drupal_override_server_variables() and see if it makes sense.
The reason that is in this patch is basically a bugfix; cache-install.inc is supposed to include stub implementations of all cache functions, but evidently cache_get_multiple() got added recently without that happening. It turns out that its absence only causes a problem for command line installations, since regular installations start using the real Drupal cache system once the database exists (and therefore only use the stub implementation towards the beginning of the installation), but a command line install which happens in one page request sticks with cache-install.inc throughout, and it turns out that cache_get_multiple() gets called somewhere towards the end of the installation (I think it was in Field API), so we need to add it to avoid a fatal error.
I used
FALSEto match what is returned by cache_get(), but actually I switched it toarray()in the attached patch, since I realized that's what the PHP doc in cache.inc says it is supposed to return. It probably doesn't matter what it returns as long as it's empty. Anyway, this whole file could probably use a cleanup, since it seems Drupal's cache system has changed a lot recently, and now involves implementing an interface, etc.Yes, I think it's possible that kind of generalization could occur as a result of #525594: Installation should consist of 2 phases instead of one. However, I may have oversold it a bit in my code comments; this is not a "true" multistep form because the $form_state['values'] don't accumulate and get passed along. It is really just a bunch of totally different forms that run one after another. I edited the code comment slightly so that it's less likely to get people's hopes up :)
Comment #28
Jaza commentedNice patch. I gave it a whirl, and it's all working smoothly for me.
However, I think that if we're going to support command-line installation, then we should provide at least the bare minimum to allow it to be used without any supporting third-party script (e.g. Drush, PIFR). Of course, anything advanced should be left to those third-party scripts. But the current advice given to testers of this patch — i.e. "hack the bottom of install.php and replace install_drupal() with (settings) code" — is IMHO a pretty clear sign that we need to do more out-of-the-box.
Therefore, I've extended this patch with the following features:
$settingsarray needed to configure the installer, nothing more. This file defaults tosites/default/settings.install.php. The default can be overridden, by passing in a filepath as a command-line argument, e.g. callingphp install.php sites/site2/settings.install.php. This should ease people's worries about having to add a gazillion command-line options to install.php: all I'm suggesting is that we add one (and an optional one, at that).sites/default/default.settings.install.phpfile.Drupal installed successfully. If any exception is thrown by the installer, it is caught and printed out (HTML is stripped, newlines are inserted, entities/symbols are decoded). If thesettings.install.phpfile isn't found, or doesn't contain a$settingsarray, an error and some useful help is printed.(PS: the
install_is_cli()function is borrowed from Drush'sdrush_verify_cli()function.)With these enhancements, it will be possible to download Drupal, to create a
settings.install.phpfile, and to run:php install.phpAnd that's it.
I'm anticipating that many people will consider this to be feature bloat and to not belong in the core installer. To those of you in that camp, I have to disagree: it's currently not even possible to test this patch without an additional hack to install.php. This enhancement at least makes it possible to test a command-line install in 5 seconds. However, I can understand if you insist that this be split into a separate follow-up patch.
Comment #30
JacobSingh commented@Jaza: Nice stuff. I actually did something similar and decided not to add it because I thought it a separate issue.
You can in fact test this patch without hacking install.php.
See the comments above, I added a little condition to check if the script is being run directly or included. This means you can write your own install script which just looks like this:
Best,
J
Comment #31
David_Rothstein commentedThanks, @Jaza -- I like what you added a lot, but I'm also going to vote for making it a followup issue. Partly because this is already a 100K patch even without that, but also, like Jacob said, the code he added already lets the file be included so anyone can try this out with any kind of script they want. If we want to put a script in core, it should probably live in the
scriptsdirectory and use the same kind of mechanism. But I think the code you wrote is a great start at that - I especially like cleaning up the error messages so that they don't spit out HTML to the command line.Anyway, the biggest issue is that the testbot is currently rejecting your patch for some reason that I don't immediately understand, whereas I'm pretty sure mine will still work :) So here is a re-uploaded version of the patch from #27. I also made some additional typo fixes in the code comments, and added a CHANGELOG.txt entry.
Comment #32
Jaza commented@David_Rothstein: sounds good to me. I'm happy to work with yourself and @JacobSingh on this in a follow-up patch.
I also can't understand why my patch gives a 'failed to install HEAD' error. But since I have no idea how PIFR works, I assume that something I did is tripping up the way PIFR triggers the installer. Will leave that problem for another day.
I gave your latest patch a whirl, and it's still working great. +1 from me.
Comment #33
dries commentedInstead of creating a new settings file, can't we re-use the existing settings.php?
As a developer, I'd love to be able to do something like: "./install.php --truncate" or something to start with a clean site. Pretty destructive, i know so maybe I should leave that as a custom script. ;-)
Will do a review shortly, if webchick doesn't beat me to it.
Comment #34
boombatower commentedI agree with Dries having a "truncate" type functionality would be really nice, especially when working on Drupal HEAD and you mess something up or CVS update requires a re-install.
Comment #35
adrian commentedFor provision / aegir, it would actually be better for us if it just used the settings.php we created instead of creating the config file itself.
so the process for installing a site is a) creating the settings.php file, b) running the script.
Comment #36
David_Rothstein commentedNot sure I understand the last few comments - isn't that the way the installer always worked? The patch didn't do anything to change that.
If you create a settings.php file by hand (that has the correct database information already in it), or if you blow away the database on an existing site while leaving the settings.php file behind, the installer will skip creating settings.php and use what's already there.
I'm not sure about shipping the "DROP DATABASE" functionality with core, though :)
Comment #37
hass commentedI wish there would also be a command line update.php... to remove bad fun - updating 500 sites every few weeks...
Comment #38
adrian commented@hass - there already is, check out drupal.org/project/drush
we should definitely tackle making update.php includable next though
Comment #39
David_Rothstein commentedPatch rerolled to chase HEAD (due to changes introduced by #349508: Require UTF8 database encoding).
Comment #40
Anonymous (not verified) commentedI've tested several times, both interactively and through script, to see if I could break the patch. Each time I used a variety of different options. No dice.
The patch works. ;)
Comment #41
boombatower commentedOnce this goes in...either roll a patch for PIFR...or just make sure I am notified and I'll get it in as quickly as possible.
Comment #42
dries commentedCommitted this to CVS HEAD. Coordinated with DamZ so that he disabled the test bot for now. Thanks all!
Comment #43
David_Rothstein commentedCool!
Here is the promised followup patch, which should fix all the whitespace/indentation issues mentioned above.
I thought about combining this with moving the code from install.php to a separate, includable file, but then realized we might want to think a bit more how to handle the defined constants when doing so -- related to the point Jacob brought up in #19, there is a particular problem with the MAINTENANCE_MODE constant, since if that is defined the rest of Drupal will automatically assume the site is in installation mode. So if we simply moved that define() to the top of a new
includes/installer.inc, then anyone merely including that file would automatically trigger the rest of Drupal to be installation mode, which is not good for an API.We could move the define() into a function, although I don't think Drupal does that anywhere else? Or we could simply require that any calling script has to define MAINTENANCE_MODE on their own (similar to the way that scripts currently have to define DRUPAL_ROOT), but that seems pretty ugly. Any ideas?
Anyway, the attached patch should be a pretty quick commit, and then once we get the
includes/installer.incissue done we can move on to the "real" followups.Comment #44
David_Rothstein commentedBy the way, I contacted @boombatower separately, but as far as I know this patch did not break the testbot.
(We might want to have a followup to change PIFR to use the new method, but it shouldn't be required for the testbot to work correctly, since the browser-based installation method that PIFR currently uses works the same way as it did before.)
Comment #45
damien tournoud commentedMAINTENANCE_MODE is a bootstrap-time constant. It belongs into the entry point (for example install.php).
Comment #46
moshe weitzman commentedI would personally move maint mode into a function and actually let it get unset if the caller knows what it is doing.
Comment #47
anarcat commentedI have reviewed the patch and it looks fine to me. I have attached a new version of the patch that removes the whitespace changes to enhance readability. My patch obviously shouldn't be tested or considered for inclusion in HEAD, I just include it so that people can see more easily what are the non-whitespace changes (because there are a few, because of word wrapping) in the patch.
I think this should go in, in short.
Comment #48
dries commentedCommitted #47 to CVS HEAD. Maybe we should create a new patch for the follow-up work?
Comment #49
boombatower commentedWhat I was referring to in #42 was #533676: Take advantage of refactored installation system
Comment #50
boombatower commentedCross post.
Comment #51
anarcat commentedRe: #48 @adrian, the issue for update.php is #233091: Move code from update.php into includes/update.inc.
Otherwise, is this complete? I feel a lot of functions still sit in install.php and while the patch committed makes it possible to include install.php, it's still a sub-standard/hackish API. We should move the functions to install.inc.
Indeed, the end of install.php currently lists:
Quite a hack... Ideally, install.php would be only a few lines long and would handle forms and things like that... Should a new issue be opened for this or should we reopen this one?
Comment #52
David_Rothstein commentedYes, that was what I was thinking - get the file reorganization committed quickly in this issue, and then at that point we are done the gigantic changes so we can close this and open some (normal) followups.
We also need to do something here since it looks to me like Dries committed the "reviewer only" patch in #47 rather than the actual patch in #43 - oh well :) So there are lots of whitespace fixes that didn't yet go in.
I think we can combine both of the above and have done so in the attached patch. To make this, I:
require_once DRUPAL_ROOT . '/includes/install.inc';For now, I went with Damien's suggestion of leaving MAINTENANCE_MODE in install.php, since it's simplest. I think Moshe's idea sounds right, but if I understand it correctly it involves getting rid of the define() altogether, so that probably could use a separate followup issue since it also affects update.php, etc.
Hopefully we can get this in quickly, since obviously it will break if anything else gets committed (and I don't think there are any large installer patches on the horizon that this will conflict with).
Comment #53
kika commentedIt's not very clear by looking at file names what does installer.inc and what install.inc. More logical names perhaps in future bikeshedding followup?
Comment #54
dries commentedLike kika, I agree that installer.inc is a confusing name.
Comment #55
David_Rothstein commentedPersonally I think "install.inc" is actually the confusing one -- since it contains some random mix of utility functions, functions that are used only by update.php, etc.
I have no great ideas for a renaming at the moment.
Comment #56
anarcat commentedI don't think installer.inc is confusing. It's the main installer UI. Install.inc should be a separate file that contains the Drupal Install API, and it should be clearly labeled as such.
I absolutely love seeing install.php reduced to 2 lines and support this patch. I haven't tested it so I'm not marking it as RTBC, but I strongly suggest kicking this in so we unblock the other installer work (like #525594: Installation should consist of 2 phases instead of one).
Comment #58
David_Rothstein commentedI'll gladly reroll this once we have a commitment that it can go in... If no one can come up with a better file naming suggestion now, can we postpone that discussion to a followup?
Like @anarcat said, there are other issues that would benefit from this going in first. It also makes it easier to actually install Drupal via the command line -- currently, I think any custom script would have to be called from the top of the Drupal root directory in order to work (since you need to include install.php which forces its own definition of DRUPAL_ROOT on you, etc).
Comment #59
cweagansRight, so we have a small issue here:
Since this was committed, I haven't been able to install core. I've talked to webchick and ksenzee in IRC and they said to create a new issue (#546390: Fix CLI detection in install.php), but I thought I'd bring it up here since the problem area was in this patch.
My problem is that, from a browser, realpath($_SERVER['SCRIPT_FILENAME']) is returning FALSE, so the installer does not run. IMHO, install.php needs to be another two-liner file with all the install functions moved to the includes dir fairly quickly.
Comment #60
moshe weitzman commentedYes, I think we can defer naming changes. Even kika suggests it ... My .02 are for install_ui or install_wizard
Comment #61
David_Rothstein commentedI can reroll the patch from #52 sometime tomorrow if no one beats me to it.
I think I like "install_wizard.inc"... maybe a little inaccurate when called from a command line script (since it's not much of a "wizard" in that case), but it does seem to get the point across.
Comment #62
JacobSingh commentedMy bad, I thought what I put in was the best method... Not sure why it isn't working, but anyway:
From: http://www.codediesel.com/php/quick-way-to-determine-if-php-is-running-a...
Might be better.
Comment #63
David_Rothstein commentedOK, here is the rerolled patch from #52. I used "install_wizard.inc" as per Moshe's suggestion. It's easy to do a quick switch to something else right before committing (just do a find-replace on the patch file), but other than that, I agree, it would be great to defer any further discussion on the name until later.
So let's see if we can get this RTBC and committed as quickly as possible :)
Comment #64
dries commentedInstead of using wizard, I'd prefer to use something that we can use consistently for other .inc files. Maybe we should use MVC naming patterns? install.view.inc, install.controller.inc, install.model.inc ?
Comment #65
David_Rothstein commentedDries, I think #316916: Create install directory with multiple files and modularized code might be the issue for that.
As things stand, both install.php and install.inc each contain a big mix of stuff, so I'm not sure which MVC-based renaming we'd use here, without totally reorganizing the files, which seems out of scope for this issue :)
Comment #66
JacobSingh commentedI'm confused, what is the problem here?
If you determine that the script is being called from the browser, isn't that good enough to distinguish between an include and a hit from a browser directly?
Comment #67
boombatower commentedJust reporting my results in trying to use this by SimpleTest and PIFR.
PIFR:
Need a way to call this externally, without having to be inside the Drupal 7 codebase. Looks like there might be work to make CLI tool, not sure. I could hack and insert a file into the D7 checkout that purely executes the installation code, but that seems a bit hackish, no more so then what it currently does I suppose.
SimpleTest:
The code needs to be separated into two parts: 1) wizard that syncs with forms and does all the validation of input and settings directory, etc; 2) API code the does what it is told regardless of conditions.
The reasoning behind this is that SimpleTest needs to use the install code to generate a new DB environment, but doesn't want to mess with the settings.php files and such. You can see what I had to do in order to get the code to work in #488182: Shared test runner between webrunner and script and perfectly clean test environment. A hack that I was hoping would be fixed by the time I finished patch.
I haven't read all the comments, so I'm not sure if this stuff is in the works on already in the patch, but it seems that these items make sense to be address so that this code can be utilized (especially the SimpleTest portion as that is necessary for other implementations such as UTS and makes sense in general. We separate API from forms and things work better.).
Comment #68
moshe weitzman commentedLets keep things moving here.
Comment #69
dries commentedI'm not sure why we need to keep this moving. As far as I understand, it doesn't block anything. It is merely a cosmetic patch, and one that I don't necessarily agree with in its current shape.
Comment #71
eaton commentedComment #72
moshe weitzman commentedIt isn't cosmetic. drush can't easily use this as is. install.php *forces* a DRUPAL_ROOT value, for example.
Any chance for a re-roll, David?
Comment #73
dmitrig01 commentedAlso, good luck installing Drupal from the command line without this patch, no matter which installer (Aegir, Drush, Acquia hosting). SimpleTest part can easily be a follow-up
Comment #74
boombatower commentedIf this is abstracted properly. Right now the installer does way to much validation, such as checking for existing db (without reguard to prefix) and for settings.php file. It needs to be split into two aparts.
1) installer.php with validation and such
2) installer.inc pure API which does what its told.
Otherwise SimpleTest cannot use this. Even if command line installer exists, if it checks the stuff above then it won't work for SimpleTest.
Comment #75
David_Rothstein commentedLet's start by getting the whitespace fixes out of the way. Those are uncontroversial and were supposed to have been committed above anyway -- and they are what has been making rerolling the larger patch painful.
@boombatower: While it would be nice to split the installer into two parts along those lines, I don't think it's necessary for getting the installer to work with SimpleTest. The main thing we would need to do is simply, as you say, enable non-interactive installations to work with a different DB prefix, which should be a small change. We should create a separate issue for this (if there isn't one already). I've sort of been assuming that this is the sort of thing that could be done after code freeze, even if it did involve a small change to the API (since the primary purpose would be to improve test coverage), but if not... well, if not, it probably isn't going to happen for Drupal 7 :)
Comment #76
webchickYay! I love whitespace clean-ups. ;) Committed #75 to HEAD.
This will need a re-roll.
Comment #77
David_Rothstein commentedOK, here is a reroll of the patch that moves everything out of install.php.
1. I decided to go with "includes/install_drupal.inc" as the new filename this time - seems simplest :) Again, this can easily be changed by directly editing the patch file.
2. Somewhat annoyingly, I found that even with this patch, a command line script still needs to chdir() to the Drupal root directory in order to successfully complete the installation. The reason is that there appear to be lots of places in core that ignore DRUPAL_ROOT and use relative paths -- an example is in http://api.drupal.org/api/function/drupal_get_filename/7 which simply calls file_exists() on the passed-in relative filename. Not sure if these are known issues or not, but either way, they are bugs and can be dealt with after code freeze.
Comment #78
anarcat commentedAssuming the copy-paste was done properly (which it looks like from a quick review, not byte per byte), this patch looks fine and "compiles" (ie. I can still install Drupal with it applied).Update: I have reviewed the actual diff between the original install.php and the new insta_update.inc and it looks fine to me. Here's the resulting diff, which *should not* be applied and is provided here simply for peer review:
Comment #79
anarcat commentedThis is the final phase of refactoring of install.php, and the fulfillment of the following TODO:
As such, since it's an API change of some sort (well, the functions move from a different file) I think it should go in before the freeze (today?) so that we know where to find the install functions in the long term.
Also note that similar work was done on update.php (#233091: Move code from update.php into includes/update.inc) so it would just make sense to finish the work here and keep install.php small (like update.php).
Now to specifically adress this:
@Dries - could you expand on what you don't agree with in the current patch?
Thanks,
Comment #80
moshe weitzman commentedRight - this is just moving code around to match update.php. Lets please commit or elaborate on objections.
Comment #82
David_Rothstein commentedWell, I'm amazed that it lasted over two weeks :)
I'm really not sure what to do here, but constantly rerolling the patch (it basically requires a complete manual reroll each time) is a waste of time. Should we wait until the RTBC queue is smaller to try this again?
We all know what the patch does - it moves a bunch of stuff to a new
includes/install_drupal.incfile and then makes the other necessary small changes for that to work correctly. I'm therefore somewhat tempted to force this issue to stay at RTBC by uploading a tiny dummy patch that does nothing - that way the testbot won't set it back, and we can actually reroll the real patch once more, when it's actually going to be committed.....Comment #83
JacobSingh commentedSomething has broken here recently I think, still tracking it down.
As a side note, when investigating, I saw this:
// The user agent header is used to pass a database prefix in the request when
// running tests. However, for security reasons, it is imperative that no
// installation be permitted using such a prefix.
if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], "simpletest") !== FALSE) {
header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
exit;
}
I don't see how this protects anything. I can easily change my user agent to simpletest, and since it is in Drupal core, it's not like it is a secret or anything.
-J
Comment #84
JacobSingh commentedAh... I just up'd to snow leopard which uses php 5.3.0, and command line install doesn't work from there.
I don't know exactly what the issue is, but the output is something about PDO not getting what it is looking for in terms of a driver name.
If someone is interested / has a quick idea:
Comment #85
boombatower commentedThe reason for the check being so simple in that location is bootstraps does a proper check...so we just want to know that it is a simpletest user agent at that point.
This again seems to point out that we need a proper separation...the install.php which has UI and that check...and an API that can be called from CLI script and UI.
Comment #86
David_Rothstein commentedJacob, I'm not sure about the PDO error, but the second error you saw sounds exactly like #547846: Drupal installation fails on MAMP & XAMPP due to pass-by-reference error, so either a regression there or something similar occurring for a different reason... (and the errors that occur after that are likely side effects of that one).
Comment #87
JacobSingh commentedOkay, here is a new one. This is a regression in PHP 5.2:
#524728: Refactor install.php to allow Drupal to be installed from the command line (committed 2 days ago).
Tries to access a cache before it is created.
PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'dev7_drupal.cache' doesn't exist in /Users/jacob/work/github/drupal/includes/database/database.inc on line 1735
Any ideas how to quickly fix this?
Comment #88
JacobSingh commentedsorry, wrong link:
#557542: Cache module_implements()
@catch and I looked at this a bit in IRC, and here is the gist:
During system_requirements check in install_drupal, module_implements gets called. That tries to hit the cache. Normally, we would use the FakeCache
#576096: Port cache-install.inc to the new cache system
However, it is made to unset itself after the DB is setup (when doing a GUI install) and start using the DB cache.
When installing from the GUI, it happens over multiple page loads, so this works.
From the CLI, it don't. The cache_default_cache variable gets unset before we have set up the DB, so it fails for us. By commenting out the line to unset the var it works fine.
here is the code for reference:
install.php:277
@catch found this in CVS:
#151280: After install, old cached variables are used instead of those chosen using installer
Where the comment was added about "the cache properly"
Gabor, et all: Is this still required?
Comment #89
David_Rothstein commentedNice debugging work, Jacob. I experienced a similar problem for a few days (although it magically seems to have gone away for me now!). Anyway, let's continue discussion of that bug at #557542: Cache module_implements() since that is the issue that introduced it.
Here, I'd really like to get this issue closed, and it is still open because we still haven't moved the code out of install.php. So to keep this at RTBC, I'm doing what I suggested above and attaching a patch which will hopefully fool the testbot :) The actual patch that is RTBC is #77 which I will reroll to chase HEAD when asked to do so - i.e., shortly before it is actually going to be committed.
As hinted at above, I don't see how we can ever have a followup issue to let SimpleTest be able to test the installer until this patch is committed (an important goal before releasing Drupal 7, IMO).... The reason is that SimpleTest runs in your web browser, so with the current code that's in core, I don't see how it can include install.php and use parts of it as an API without automatically triggering the code execution.
Comment #90
moshe weitzman commentedComment #91
mcrittenden commentedSub.
Comment #92
dixon_subscribing
Comment #93
seutje commentedsubscribe
Comment #94
sun+1, we absolutely want to do this.
Re-rolled from scratch against HEAD.
Comment #96
sunMissed the line that includes install.inc.
Comment #97
David_Rothstein commentedThanks for the reroll! I think the name "install.wizard.inc" was already rejected above (so we might rather want something like "install.drupal.inc" or "install.core.inc") - however there is no need to bikeshed because this filename can easily be changed by doing a find and replace on the patch file.... the important thing is that we get this in.
I've gone ahead and preemptively created #630446: Allow SimpleTest to test the non-interactive installer and then marked it postponed on this issue.
Comment #98
sunoh I like install.core.inc! - that makes a clear difference from install.inc and install.core.inc.
Comment #99
webchickIt's not clear to me exactly what Dries's previous concerns were with this patch, nor why it's required for Drush (drush installcore works fine for me without it). But, since it was ready before code freeze and in any case is just moving some code around, and since it brings install.php inline with similar changes we made with update.php, I'm ok with committing this.
I'll leave it RTBC for another 48 hours for feedback.
Comment #100
David_Rothstein commentedIt's been more than 48 hours :) But darn - the patch no longer seems to apply... Will you commit it if I reroll it?
I guess it's not strictly-speaking needed for Drush, but is for other issues, such as the one I linked to in #97. Basically, if anyone ever wants to use any of these installer API functions in code that is intended to run in a web browser - for any purpose - they need this patch in order to do so.
Comment #101
scor commentedThe last patch contains trailing whitespaces in several locations.
This review is powered by Dreditor with whitespace detection enabled.
Comment #102
David_Rothstein commentedHm, I actually do not see the trailing whitespace in those places? But even if it's there, this patch is basically just a straight copy-paste of whatever the existing code was, so I don't think we need to fix the whitespace here.
I'm a bit surprised the testbot hasn't found reason to change the RTBC status in the past month... but anyway, it still needs to go in :)
Comment #103
David_Rothstein commentedRerolled the patch.
Comment #104
David_Rothstein commentedOn the off chance that this is not the last time it will need to be rerolled, I've also attached helper patches for rerolling it again. Instructions:
near the top of the file, and ending with:
near the bottom of the file. Put this in a new file called includes/install.core.inc. Make sure that the remaining code in install.php has the standard spacing.
That should do it.
Comment #107
int commentedLast Post "2 weeks 3 days", what is needed here? Commit?
Comment #110
David_Rothstein commentedRerolled using the above instructions. RTBC because it's been that way for months.
Actually, this is kind of amusing. The initial patch in this issue, which basically involved a complete rewrite of the entire Drupal installer, took a week and a half to get in. The followup patch for cutting and pasting code from one file to another - this one's at five and a half months and counting :)
Comment #111
webchick#110: install.core_.524728.110.patch queued for re-testing.
(Edit: Oooooh. I like the new way this feature works!)
Comment #113
anarcat commented#110: install.core_.524728.110.patch queued for re-testing.
I assume the test failure were unrelated with this patch, as they were about some minor javascript generation problem while all other tests were succeeding, requeuing.
Comment #114
sun.core commentedWe are still waiting :)
Comment #115
moshe weitzman commentedRe-post latest patch to awaken bot.
Comment #117
David_Rothstein commentedRerolled.
Comment #118
moshe weitzman commentedWait for green before commit (WFGBC)
Comment #119
webchickLet's do this. It's been ready since forever, it makes this consistent with what we did for update.php, and frankly I'm getting sick and tired of this haunting me in my RTBC queue. ;P
And though the issue status doesn't reflect it atm, qa.drupal.org shows this gets the green light.
Committed to HEAD. Dries, if you strongly disagree, feel free to roll back.
Comment #121
christefano commentedIs this issue summary the only place where this is documented? It's 4 years later but I don't see anything about this in INSTALL.txt or at https://drupal.org/documentation/install/run-script