Forum OpenACS Improvement Proposals (TIPs): Tip #18 (Proposed): search order for master tag

As per these threads and bug:

https://openacs.org/forums/message-view?message_id=50091
https://openacs.org/forums/message-view?message_id=63062
https://openacs.org/bugtracker/openacs/bug?bug_number=68

I would like to propose that the search order of the <master> tag (when the "src" parameter is not specified) be as follows:

* search for a master template in the current directory (ie, directory-local master)

* if none found, search for a master template in the package's www/ directory (ie, package-local master)

* if none found, use the subsite master template

* special case: if a page is itself a master template and invokes "<master>", then it should obviously ignore itself and begin searching one-level down

* the names of the local masters would be specified as subsite parameters, but would default to "default-master"

Now that we've removed the package-wide masters in most, if not all, of the current packages, this proposal would allow us to regain the flexibility of adding customizations at the directory and package levels.  Examples of this can be found in the aforementioned thread.

PS. I'm not sure how this would be impacted by the ongoing proposal to standardize the package directory structure.

Collapse
Posted by David Cotter on
There was another step discussed on one of the threads that involve "walking up the directory" just after the

* search for a master template in the current directory (ie, directory-local master)

step. So if the current directory is /web/yourserver/www/student/resources/notes then the template is searched in the path in the following order:

/web/yourserver/www/student/resources/notes
/web/yourserver/www/student/resources
/web/yourserver/www/student
/web/yourserver/www

I think this step is very important for a flexible templating system.

Collapse
Posted by Robert Locke on
Thank you, David.  I had forgotten about that. =)
Collapse
Posted by Jun Yamog on
Hi David,

That sounds very much how cofax.org templating search things.

Collapse
Posted by David Cotter on
I hadn't heard of cofax - what's it like? I used this method in Openacs 3.x where ad_header and ad_footer search for templates based on the request URL. The header and footer template files were named: default, index, bboard.index, bboard.q-and-a-fetch-msg etc. and it finds the nearest match so /bboard/q-and-a-fetch-msg.tcl uses bboard.q-and-a-fetch-msg but /bboard/q-and-a.tcl uses default since there's no match. I found it to be very effective.
Collapse
Posted by Tom Jackson on

I think this is related, and maybe a good chance to fix this. If you setup you master tag to take a variable src attribute, things go bad if the variable evaluates to the empty string:


in tcl: 
set template ""
in adp:

<master src="@template@">

The master tag logic compares "@template@" to the empty string to decide what to do. Obviously "@template@" is never empty, causing a very hard to trace problem.

I discuss the problem more here: https://openacs.org/forums/message-view?message_id=124554

Collapse
Posted by Vinod Kurup on
For the record, I think this is a useful proposal and I've created a patch which implements it.

Say the web browser requests foo.adp. If foo.adp's master tag has a src attribute, that file is used as the master template. If foo.adp's master tag has no src attribute, then the current directory is searched for a master.adp file. If one is found, it is used as the master template. If not, then we go one directory up and look again. We keep going up until we find master.adp. If we get to the serverroot without finding one, then we use the master specified in the DefaultMaster parameter.

Now, if the master template that we find also has a master tag in it, then we include whatever we have now (foo.adp + local master.adp) inside DefaultMaster. Note, that we don't look up to the next directory in this case. Confusing, I know.

Here's an example.

/www/content/computer/foo.adp
foo.adp has a <master> tag with no src attribute, so it searches for /www/content/computer/master.adp. Lets say it's not there. It then goes up 1 directory and finds /www/content/master.adp. It dutifully includes all of foo.adp inside the <slave> tag that is in /www/content/master.adp. But we're not done yet because /www/content/master.adp happens to have its own <master> tag. So, we include everything we have and stick in the DefaultMaster's <slave>. Another (better) approach would be to take everything we have and look for the next most local master.adp (i.e. /www/master.adp). I couldn't figure out an easy clean way to do that. Within the scope of the <master> tag, you only have access to the file being requested, not the file being parsed. So it's hard to know which level of the master hierarchy we are at. Perhaps there's a way to do it inside template::adp_parse, but I'd have to do some more research or get help from the templating gods.

The current patch fits my needs, but I could see value in having even more flexibility.

Collapse
Posted by Jeff Davis on
If we do implement this we should probably cache the lookups if PerformanceModeP is set. I suspect walking up the tree doing 4 or 5 stats per page served would not be great on a production system.
Collapse
Posted by Tom Jackson on

Looking over Vinod's patch, I noticed he uses [ns_info server] and comparing that to a part of the url. I think instead he could compare the remaining path to [acs_root_dir], to insure it works in all cases.

I'm working on a patch that handles the bug of comparing the value of the src attribute with the empty string, as opposed to the value of any expression in the src attribute.

The relevant part, untested yet, of Vinod's work is:

      set acs_root_dir [acs_root_dir]

      # are we at acs_root_dir?
      while {![string equal "$cur" "$acs_root_dir"]} {
	  # look for master.adp here
	  if [file exists "${cur}/master.adp"] {
	      # found it
	      set src "${prefix}master"
	      break
	  } 
	  # move up and try again
	  append prefix "../"
	  set cur [file dirname $cur]
      }
Collapse
Posted by Tom Jackson on

I've spent even more time today trying to rid the master tag of the src bug. Again, this is a problem if you pass in a variable, either simple @a@ or array type: @a.b@, where the value of this variable is the empty string.

Well it turns out to be a very stick issue. It isn't at all easy to tell if the value is null.

In reference to the patch by Vinod. This is important for consideration of the method of choosing the master. The master tag is _not evaluated_ on every request! In fact it is evaluated once per thread, per unique url. That means you cannot calculate which master template to use inside the master tag, and then pass this hard coded value along.

I recommend a separate procedure for calculating the master template, and then pass the calculated value into the master tag by using one of the template variable types. Developers can then choose, dynamically, which template to use. This will also make it much easier to debug any template errors,or master template location errors which will show up.

An example of what could happen is that you could add a master template after the server starts up, and after the path to the master had been hard coded into the compiled master tag. The server will still use the old value until a restart.

Any procedure which is used to calculate the master template must always return a value. A null value will result in a very hard to track bug.

Collapse
Posted by Lars Pind on
Approved with the following qualifications:

1. master template found and used will be cached along with the compiled template

2. the name of the template file is "master", not "default-master".

Collapse
Posted by Tom Jackson on

One more note on this, after re-reading the above. Robert's suggestion is one search order, and it sounds reasonable. But, Vinod's patch searchs like this:

/web/server/packages/my-package/www/dir1/dir2/master
/web/server/packages/my-package/www/dir1/master
/web/server/packages/my-package/www/master
/web/server/packages/my-package/master
/web/server/packages/master

Okay one more note: The current master tag does not calculate the src attribute. If it is a variable, it passes it through, same if it is static. If empty, it passes a function call along. I believe what would be more in line with this is to modify this function, or replace it with a new function so that the calculation can still be dynamic per call. Caching the template is different from caching the result of 'one' call to the template, which is what will happen if logic is placed into the master tag.