-
-
Notifications
You must be signed in to change notification settings - Fork 825
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move log and compilation dirs from "Runtime" to "Paths" #14718
Conversation
(Standard links)
|
jenkins, test this please |
This looks like a good solution to the problem. I bet it's okay to go with the long term solution since people can still override them in the settings file if they have different locations for each. I will hopefully test today. |
CRM/Core/Config/Runtime.php
Outdated
@@ -99,16 +92,6 @@ public function initialize($loadFromDB = TRUE) { | |||
$this->fatal('You need to define CIVICRM_TEMPLATE_COMPILEDIR in civicrm.settings.php'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can probably get rid of this too. \CRM_Utils_File::baseFilePath()
already has a fatal error check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I'll update that.
Civi/Core/Paths.php
Outdated
}) | ||
->register('civicrm.compile', function () { | ||
return [ | ||
'path' => \Civi::paths()->getPath('[civicrm.private]/templates_c'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a problem for $file = CIVICRM_TEMPLATE_COMPILEDIR . "/CachedCiviContainer.{$envId}.php";
in \Civi\Core\Container::loadContainer()
? Can that file be in a private directory? I'm guessing
Same with CRM_Extension_ClassLoader::getCacheFile()
there's this line:
$file = CIVICRM_TEMPLATE_COMPILEDIR . "/CachedExtLoader.{$envId}.php";
Along with this maybe the only place that references CIVICRM_TEMPLATE_COMPILEDIR
should be \CRM_Utils_File::baseFilePath
so that people can't set the template directory twice. The other references could call [civicrm.private]/templates_c
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops. I guess \Civi\Core\Container::loadContainer()
can't expect Civi\Core\Paths
to be available. So CIVICRM_TEMPLATE_COMPILEDIR
needs to stick around at least for this.
On Pantheon I've been setting CIVICRM_TEMPLATE_COMPILEDIR
to the tmp directory to deal with a special issue there, and that works so long as [civicrm.files]
is also set to point to the regular file system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is how civicrm.settings.php would be set up to work on Pantheon:
if (!defined('CIVICRM_TEMPLATE_COMPILEDIR')) {
define( 'CIVICRM_TEMPLATE_COMPILEDIR', '/tmp/civicrm/templates_c/');
}
$civicrm_paths['civicrm.compile']['path'] = CIVICRM_TEMPLATE_COMPILEDIR;
$civicrm_paths['civicrm.files']['path'] = '/app/sites/default/files/civicrm/';
$civicrm_paths['civicrm.private']['path'] = '/app/sites/default/files/private/civicrm/';
For now might not need [civicrm.compile]
since it's not being called anywhere, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So maybe the only thing I'd borrow from #14719 is to make this one:
->register('civicrm.compile', function () {
return [
'path' => CIVICRM_TEMPLATE_COMPILEDIR,
];
})
The other paths are probably fine in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think most remaining references to CIVICRM_TEMPLATE_COMPILEDIR
come late enough during bootstrap that Civi::paths()->getPath()
is viable substitute... but I'm gonna try it with some funny-cases (like GenCode
and install/index.php
) to be sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@herbdool So, going along the lines of your first comment, I've pushed an updated branch which patches \Civi\Core\Container::loadContainer()
, CRM_Extension_ClassLoader
, and CRM_Core_IDS
to replace CIVICRM_TEMPLATE_COMPILEDIR
with Civi::paths()->getFoo()
.
This brings it down to only one reference to CIVICRM_TEMPLATE_COMPILEDIR
(in CRM_Utils_File::baseFilePath()
).
I haven't tested the following claim, but it should mean that it is valid to completely omit CIVICRM_TEMPLATE_COMPILEDIR
and instead specify civicrm.files
and civicrm.private
. By setting those two variables, one bypasses any remaining code-paths that rely directly on baseFilePath()
or CIVICRM_TEMPLATE_COMPILEDIR
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Along the lines of your last comment, I updated the civicrm.compile
calculation so that it consults CIVICRM_TEMPLATE_COMPILEDIR
. Formally, the effective value of civicrm.compile
will be the first defined item from this list:
$civicrm_paths['civicrm.compile']['path']
CIVICRM_TEMPLATE_COMPILEDIR
Civi::paths()->getPath('[civicrm.private]/templates_c')
I think this means that we get backward-compatibility for existing deployments as well as supporting a sensible style for new deployments:
- (Backwards compatible style) If you have an existing deployment and existing
civicrm.settings.php
(withdefine('CIVICRM_TEMPLATE_COMPILEDIR'...)
and no customization to$civicrm_paths
, etc) - thenCIVICRM_TEMPLATE_COMPILEDIR
is still used. - (New style) If you make a new/revised deployment with a new/revised
civicrm.settings.php
(omittingdefine('CIVICRM_TEMPLATE_COMPILEDIR', ...)
; instead, using$civicrm_paths
), then:- The default value of
civicrm.compile
is[civicrm.private]/templates_c
- The default value of
civicrm.log
is[civicrm.private]/ConfigAndLog
- Either can be customized directly (without impacting the parent).
- The default value of
138b4e1
to
a1eb80a
Compare
…perties Overview -------- This corrects a subtle bug in which reading/writing some properties in `CRM_Core_Config_MagicMerge`, which became visible in the tests for PR civicrm#14718. Before ------ * If a property has a simple name (e.g. `maxFileSize`), then `$cache`-reads and `$cache`-writes are consistent. * If a property has a split name (e.g. `maxAttachments`, `max_attachments`), then `$cache`-reads and `$cache`-writes are *not* consistent. Writes basically don't work. After ----- * The typical behavior (which applies to simple names) also applies to split names. Technical Details ----------------- To understand the change, you should skim `MagicMerge` and observe a few things: * In `getPropertyMap()`, observe that: * (a) Most properties have a singular name -- for example, `maxFileSize` has one name, which implies that it's the same name in the high-level facade (`$config->maxFileSize`) and in the underlying data-store (`settings->get('maxFileSize')`). * (b) Some properties are aliased. Ex: `$config->maxAttachments` corresponds to underlying item `settings->get('max_attachments')`. * In `__get()` and `__set()`, note that properties are loaded initally from the underlying data-store once; thereafter, any reads or writes go to `$this->cache`. That's a thread-local place that stores temporary revisions. To see the cache consistency problem, specifically note that: * `__get()` consistently references `$this->cache[$k]` * `__set()` was confused; at the start, it used `$this->cache[$k]`, and later it used `$this->cache[$name]`. This PR adds a unit-test which ensures that the thread-local/cached value works consistently.
…perties Overview -------- `CRM_Core_Config_MagicMerge` allows properties to be temporarily modified (for the duration the object's lifespan). However, this behavior does not work correctly if the property-name uses aliasing. The PR addresses a test-failure that became visible in civicrm#14718, and it adds test-coverage for some typical and atypical examples. Before ------ * (Vast majority of properties) If a property has a simple name (e.g. `maxFileSize`), then `$cache`-reads and `$cache`-writes are consistent. * (Handful of properties) If a property has a split name (e.g. `maxAttachments`, `max_attachments`), then `$cache`-reads and `$cache`-writes are *not* consistent. Writes basically don't work. After ----- * Aliased properties work the same as normal/non-aliased. Technical Details ----------------- To understand the change, you should skim `MagicMerge` and observe a few things: * In `getPropertyMap()`, observe that: * (a) Most properties have a singular name -- for example, `maxFileSize` has one name, which will be the same in the high-level facade (`$config->maxFileSize`) and in the underlying data-store (`settings->get('maxFileSize')`). * (b) Some properties are aliased. Ex: `$config->maxAttachments` corresponds to underlying item `settings->get('max_attachments')`. * In `__get()` and `__set()`, note that properties are loaded initally from the underlying data-store once; thereafter, any reads or writes go to `$this->cache`. That's a thread-local place that stores temporary revisions. To see the cache consistency problem, specifically note that: * `__get()` consistently references `$this->cache[$k]` * `__set()` was confused; at the start, it used `$this->cache[$k]`, and later it used `$this->cache[$name]`. This PR adds a unit-test which ensures that the thread-local/cached value works consistently.
The reported test-failure arises because of a latent bug. Specifically, |
I guess this needs an update from master before bothering to run tests again |
…Runtime" to "Paths". Use hierarchy. This slightly changes the computation of the private log and compilation directories so that: * The definition appears more declarative. * The default is computed on-demand (i.e. later in the process). * The values can be overriden more intuitively. Before ------ The properties `$config->configAndLogDir` and `$config->templateCompileDir` are computed as part of a procedural initialization step in `CRM_Core_Config_Runtime`. After ----- The properties `$config->configAndLogDir` and `$config->templateCompileDir` are computed on-demand by `Civi\Core\Paths`. The values of these properties may: * Be computed automatically in a way that matches the previous output (i.e. `configAndLogDir`=~`CIVICRM_TEMPLATE_COMPILEDIR/../configAndLog`; `templateCompileDir`=~`CIVICRM_TEMPLATE_COMPILEDIR`). * Be customized as a pair (by setting `civicrm.private`) * Be customized individually (by setting `civicrm.logs` or `civicrm.compile`).
1. Previous commits generally removed any responsibility for `CIVICRM_TEMPLATE_COMPILEDIR` from `Runtime.php`, so the validation is longer local/relevant. 2. The `CIVICRM_TEMPLATE_COMPILEDIR` is still used in `CRM_Utils_File::baseFilePath()` which has a similar validation step.
…R to 'civicrm.compile' The broader PR seeks to make path computation more intuitive, which requires computing the path to `templates_c` using a function. This PR replaces the reference to `CIVICRM_TEMPLATE_COMPILEDIR` with a function-call to `Civi::paths()->getVariable()`. Is it safe change to make this change in `CRM_Core_IDS`? Will the `Civi::paths()` be callable? Yes, here's why I believe so: * (Big picture) Civi completes the bootstrap process (`CRM_Core_Config::singleton()`) and brings critical services online *before* the invoker does any routing or page-processing. The invoker (`CRM_Core_Invoke::runItem()`) is the only thing which uses `CRM_Core_IDS`. * (Little picture) In the changed function `CRM_Core_IDS::createBaseConfig()`, observe that it calls `CRM_Core_Config::singleton()` before running this modified code. That's a tell-tale sign of code that already relies on having a booted system.
…M_TEMPLATE_COMPILEDIR to 'civicrm.compile' The broader PR seeks to make path computation more intuitive, which requires computing the path to `templates_c` using a function. This PR replaces the reference to `CIVICRM_TEMPLATE_COMPILEDIR` with a function-call to `Civi::paths()->getPath()`. Why change these two files in the same commit? Because they're basically doing the same thing (writing an executable PHP file to the template cache), and the demonstration of their safety is basically the same. Is it safe to change this reference to `CIVICRM_TEMPLATE_COMPILEDIR` in `Civi\Core\Container::loadContainer()` and `CRM_Extension_ClassLoader::register()/::getCacheFile()`? Yes, I believe so: * Look at `Civi\Core\Container::boot()`. * Observe that it initializes services in two general stages: * First, the `$bootServices` (`runtime`, `paths`, `userSystem`, etc) * Second, the DB/extension-dependent services (`CRM_Utils_Hook`, `CRM_Extension_System`, `loadContainer()`). * The first stage services (e.g. `paths`) provide enough information to process `Civi::paths()->getPath('[civicrm.compile]/foo')`. * All the modified lines run as part of the *second* stage (i.e. after the `$bootServices` have been initialized).
a1eb80a
to
6f50d29
Compare
@herbdool yup, I've rebased again for current |
(NOTE: Edited to use more concrete examples of So, doing a bit of self-review on this, I've been thinking about what the final result looks like to a sysadmin who wants to take control over all the paths -- and the PR aggravates a discrepancy in the overall admin experience. Compare: $civicrm_paths['civicrm.compile']['path'] = '/var/www/files/civicrm/templates_c';
$civicrm_paths['civicrm.log']['path'] = '/var/www/files/civicrm/ConfigAndLog';
$civicrm_settings['domain']['imageUploadDir'] = '/var/www/files/civicrm/persist/contribute';
$civicrm_settings['domain']['extensionsDir'] = '/var/www/files/civicrm/ext'; From an admin perspective, there's very little conceptual difference between "log dir" and "image dir". OTOH, it didn't initially occur to me that But as I reason through it, I don't think the discrepancy is a technical necessity -- one could potentially reconcile by either:
Moving these things out of the DB settings and strictly into config/PHP files feels like a cleaner end-game, but it's going to look like a bigger change. Preferring |
@herbdool have the issues raised / discussed been resolved now? |
@eileenmcnaughton the issues I had have been resolved. Looks like regressions have been fixed, tests passing. As for @totten's questions about approach, I'm leaning towards deprecating using web/UI for setting paths. Perhaps it's possible to first use Civi::paths behind the scenes and have it populate/override paths set in $civicrm_settings? I already usually try to set all the paths in civicrm.settings.php since it's such a pain when we have to create dev environments if we don't. |
I'm going to merge this & this create a documentation issue to follow up & maybe follow through a bit |
Place for follow up discussion https://github.com/civicrm/civicrm-dev-docs/issues/651 |
Overview
This is an update to the path-handling convention for data folders that allows more intuitive management of the file-paths. It aims to:
civicrm.settings.php
(without as much concern for the wonky/legacy/default computations).This PR continues previous work (circa 4.7.x) which added
$civicrm_paths
tocivicrm.settings.php
. It extends the work to address the "private" folders, creating a hierarchy of configurable paths.civicrm.private
sites/default/files/civicrm
civicrm.log
sites/default/files/civicrm/ConfigAndLog
[civicrm.private]/ConfigAndLog
civicrm.compile
sites/default/files/civicrm/templates_c
[civicrm.private]/templates_c
General Effect: Before
In
civicrm.settings.php
, one setsCIVICRM_TEMPLATE_COMPILEDIR
to be some value ending withtemplates_c
, e.g.Changing this field has surprising side-effects on other paths (which do not involve template-compilation) -- such as the public data-folders (
[civicrm.files]
) and the log folder (ConfigAndLog
). Some effects can be mitigated by overriding$civicrm_paths['civicrm.files']
, but not all.General Effect: After
In
civicrm.settings.php
, one may setCIVICRM_TEMPLATE_COMPILEDIR
as before. For good or ill, this will have the same surprising side-effects as before.Alternatively, one may remove
CIVICRM_TEMPLATE_COMPILEDIR
. Instead, set all paths using$civicrm_paths
. We present a few examples -- the consequences should be more intuitive.Example 1: This is a minimalist example in which all public and private data go to the same folder,
sites/default/files/civicrm
.The constant
CIVICRM_TEMPLATE_COMPILEDIR
is never consulted. Updatingcivicrm.files
changes only public data-folders. Updatingcivicrm.private
changes only private data-folders (e.g.templates_c
andConfigAndLogDir
).Example 2: The public and private data are stored in separate places, akin to Drupal's public and private folders.
Example 3: This is a maximalist example in which we reject most of the default paths and instead try to follow Linux FHS.
Mechanics: Before
templateCompileDir
is calculated procedurally byCRM_Core_Config_Runtime
usingCIVICRM_TEMPLATE_COMPILEDIR
.configAndLogDir
is calculated procedurally byCRM_Core_Config_Runtime
usingCRM_Utils_File::baseFilePath() . '/configAndLog'
(which in turn is derived fromCIVICRM_TEMPLATE_COMPILEDIR
).CIVICRM_TEMPLATE_COMPILEDIR
in the codebase.Mechanics: After
templateCompileDir
is calculated on-demand byCivi::paths()
; it will be the first available item from this list:$civicrm_paths['civicrm.compile']['path']
CIVICRM_TEMPLATE_COMPILEDIR
$civicrm_paths['civicrm.private']['path'] . '/templates_c'
(This is a hypothetical scenario which roughly equates to rule "ii" above. It would be more elegant than rule "ii"; however, in some wonky configurations, rule "ii" provides better backward-compatibility. The presence of rule "ii" makes this code-path irrelevant.)CRM_Utils_File::baseFilePath() . '/templates_c'
configAndLogDir
is calculated on-demand byCivi::paths()
; it will be the first available item from this list:$civicrm_paths['civicrm.log']['path']
$civicrm_paths['civicrm.private']['path'] . '/ConfigAndLog'
CRM_Utils_File::baseFilePath() . '/ConfigAndLog'
(which in turn is derived fromCIVICRM_TEMPLATE_COMPILEDIR
)CIVICRM_TEMPLATE_COMPILEDIR
.Comments
This PR only changes the mechanism for determining paths - updates to configuration is left as a separate issue. In the phone meeting circa July 10, we decided to continue using
CIVICRM_TEMPLATE_COMPILEDIR
in the old installer (ieinstall/
,civicrm.settings.php.template
) and start using the new conventions in newer installers (iecivicrm-setup
).Original issue: https://lab.civicrm.org/dev/cloud-native/issues/3