use

António P. P. Almeida appa at perusio.net
Sun Jul 24 02:22:37 UTC 2011


On 23 Jul 2011 21h49 WEST, gmm at csdoc.com wrote:

> On 23.07.2011 22:42, António P. P. Almeida wrote:
>
>>> require is just the same directive as include, with one exception
>>> - require ignores all macro definitions during process of
>>> "including".  this is not too complex for implementation in nginx.
>
>> Hmmm...but wouldn't that block any possibility of include defined
>> macros to be used in require?
>
> directive require need only for global config file
> /etc/nginx/nginx.conf for "inclusion" in 'global' config all 'local'
> site config files.
>
> require /etc/nginx/virtual/*.conf;
>
> in /etc/nginx/virtual - separate 'local' config files for each site:
>
> example.com.conf
> example.net.conf
> example.org.conf
> ...and so on
>
>
>> include (global) -> require (vhost) I think that the
>> require/include issue could be circumvented with the possibility of
>> defining macros inside locations and server blocks.
>
> often need macros for multiple related sites,
> wtich defined in one configuration file.
> for example:
>
> example.com
> example.com via https
> image.example.com
> static.example.com
> vip.example.com
> ...and so on
>
> all these virtual hosts can be defined in one config
> example.com.conf
>
> if macros forced to be defined only inside server`s and location`s -
> we again need to copy/paste/paste/paste/paste configuration
> fragments between diffenent server { ... } blocks. or move macro
> definitions to external file and use multiple includes. and we got
> the same problem, which try to solve by macros.
>
>> ## Global scope.
>> define static_images {
>> ## For static images don't log 404s and make the expire be maximal.
>> expires max;
>> log_not_found off;
>> }
>>
>> server {
>>
>> define static_images {
>> ## For static images don't log 404s and make the expire be 45d.
>> expires 45d;
>> log_not_found off;
>> }
>>
>> (...)
>> }
>>
>>
>> Each redefinition overrides the previous. It should issue a warning
>> when there's a reload.
>
> in C all macros are global - from point of definition
> to end of file. if we make C-like syntax and C-like directives
> - behaviour of 'define' directive should be close to C preprocessor
> '#define' directive.
>
> if I define some macro at start of 'local' configuration file -
> I can be sure what this macro will be same to end of this file.
>
> if macro will be redefined multiple times in nested levels -
> this is will be nightmage of support such nginx config files.
>
> to make changes and sure that changes will be applied -
> you will ned to re-read all config file from start to end.
>
> ================================================
>
> define static_images { code1 }
>
> server {
> define static_images { code2 }
>
> location / {
> define static_images { code3 }
> use static_images;                   [1]
> location /nested/ {
> use static_images;               [2]
> define static_images { code4 }
> location /one/more/ {
> use static_images;           [3]


> ================================================
>
> can you easy say which codeX will
> be used for each case [1], [2], [3] ?

Yes: [1] code 3
     [2] code 3
     [3] code 4 

> ...even if such config will contain 100 locations?
 
It could have as many locations as you want it, the more specific
level always gets the priority. 

This is like C, no?

int i = 0;
{
  int i = 1;
  printf("%d", i); // prints 1
}


>> That can be solved by having an internal symbol table for
>> macros. When the configuration is read, a symbol table is built
>> that maps the user defined identifiers to internal identifiers and
>> these internal symbols replace the user defined identifiers.
>
> semantic of static_images will be unexpetedly
> changed from macro to built-it nginx directive.

No problem as long as you constrain the user defined macros to be just
mere syntactic transformations. The builtin directive whose name
collides with the user defined macro, it's processed in a later
phase. 

> and this is will be nightmage of supporting
> nginx config files with volatile semantics.

Semantics? The macros are code generation and that's it. Like in the
case of the C preprocessor.


>> Some Lisp implementations implemented that to avoid macro capture
>> due to identifier
>> collision. https://secure.wikimedia.org/wikipedia/en/wiki/Hygienic_macro
>
> sorry, I can't understand this conglomeration of punctuation
> symbols:
>
> (defmacro my-unless (condition &body body)
> `(if (funcall ',#'not ,condition)
> (progn
> , at body)))

That's OT, but it's terse, which is something to be wished IMHO, and
has a lot of expressive power. Computer languages are not human
vernacular languages. Note that the above is much more complex than
the scheme we're discussing. There's no way to control evaluation on
Nginx config. All you can do is control the flow (to a certain
extent), you cannot subvert the evalution of the expressions. Which is
what you're doing above.

> ==================================================
>
>> This will introduce a new phase when reading the configuration. The
>> first phase would be this internal symbol generation and
>> replacement.
>>
>> Now if there's a new directive static_images and your config has a
>> static_images macro, it wont matter because when reading the
>> configuration:
>>
>> define static_images will be transformed to define :G23113. No
>> chance of collision exists. Of course the parsing of the config
>> will become more complex. But it's a clean process because
>> syntactic substitutions are just that.
>
> when I read config - how I cat understand which semanctic have
>
> fragment of config
>
> static_images /srv/www/img;
>
> - this is new nginx directive or macro with different semactics ?

Yes you're right that would involve semantics to find out what's
what. I agree that 'use' simplifies things significantly. Perhaps we
can use a prefix for user defined macros:

define static_images {

} 

then we just prepend a ':' or a '+' when referring to the user defined
macros.

   location ^~ /img/ {
      :static_images; # or +static_images
   }
   

> the same for all already existing nginx
> directives, which overlaping with macros.
>
>> Having a 'use' keyword puts the burden on you to do
>> that manually. It's less clean IMHO.
>
> use static_images;
> - from first view I can understand: this is macro usage.
>
>>> also - 'defmacro' - this is not C-like syntax.
>>>
>>> because textwihoutspaceshasverybadreadability.
>
>> It comes from Lisp.
>
> nginx config is not lisp-like, it is C-like!!!
>
> defmacro isbad directivecandidate, ithave badreadability.
>
>>> C-like synxax is text_with_underscopes_instead_of_spaces;
>
>>>> The scope could continue to be global and thus it wouldn't touch
>>>> on the location configuration merge process and preserve all the
>>>> current capabilities of hooking into the multitude of aspects of
>>>> nginx processing cycle when writing a module.
>>>
>>> this is dangerous.
>>>
>>> if in one local site config file you write
>>>
>>> define static_images { ... }
>>>
>>> and in other local site config file by mistake you write
>>>
>>> define static_inages { ... }
>>>
>>> - nginx will sliently use static_images from prevous local site
>>> config file and sliently ignone all your changes in current file.
>>>
>>> this is bad approach.
>>
>> I don't think so. If there's a scope for the define
>> directive. Meaning that the more specific wins. It's clear.
>
> this is break rule "Errors should never pass silently".

Not silent. Like I said before, namespace collisions will generate a
warning but it will proceed assuming that DWIM is the way to go.

>> It's your responsibility to be aware of redefinitions and unwanted
>> side effects due to namespace collisions.
>
> do it manually in nginx configurations with 100-200-300 config
> files?

Isn't that the situation now? You cannot preempt logic errors in a
language. Why would Nginx config be any different?

> no.
>
> none warnings, none errors.
>
> example1.com.conf:
>
> define static_images { ... }
> use static_images;
>
> example2.com.conf:
>
> define static_inages { ... }
> use static_images;
>
> nginx.conf:
>
> include example1.com.conf;
> include example2.com.conf;
>
> ==============================
>
> in config file example2.com.conf
> use static_images; - will use
> definitions from example1.com.conf
> and silently ignore definitions
> from example2.com.conf

Nope because the most recent definition wins. It works at all contexts
and it's respected even across contexts.

In example2.com.conf will use the "closest" definition, which is
obviously on that file.

>> See above. OTOH I find that software that is obsessed with backward
>> compatibility becomes sooner or later a maintenance and development
>> nightmare. Sometimes is better to make a clean cut and state
>> explicitly that the new version isn't backward compatible. It's a
>> way to keep the code base lean and clean. Of course that's just my
>> unsolicited opinion. It's Igor, Maxim et al. call to decide the
>> development policy and strategy.
>
> it will be clean code base and easy life for few nginx developers,
> but this will be support nightmare for few million of nginx users.

Not necessarily. It will be made clear that version x.y.z breaks
compatibility and there will be a stable branch and a legacy branch
(like it is now). People on the legacy branch will continue to get
updates until the currently stable version goes legacy and a new
stable release appears.

--- appa



More information about the nginx-devel mailing list