Hokay, this is pretty much my response to the string vs int stuff, 
slammed into one email.

First clarifying the assumption I'm after a max test for eapi testing; 
not the case- stated so already in this thread.

Restating it again, for stable, a check of if it's > 0 (with int 
conversion failures being knocked up to 1 fex) is effectively the same 
thing as if str(portage_const.EAPI) in ("", "0").  Stated also that 
for rewrite, this approach won't work, and you're stuck specifying 
either a range of supported EAPI (max *and* min), or specifying every 
single individual eapi identifier, which I'll clarify before is going 
to burn any maintainer of such code.

On Wed, Aug 31, 2005 at 12:52:53PM +0200, Marius Mauch wrote:
> On 08/30/05  Brian Harring wrote:
> 
> > Why am I being so damned stubborn about numbers for this?  Cause I 
> > don't want users having to dink around with knowing that eapi="really 
> > cool version" somehow maps out to 3.1.  Further, eapi version *likely*
> > will wind up as the slotting for any split out portage-ebuild package,
> > and slots traditionally have always been ints.
> 
> Thanks for that last comment, it actually prooves our point ;)
> Yes, SLOTs are *generally* numeric strings, as they are generally tied
> to major versions. But as soon as more than the major part of the
> version is important ints don't work anymore (and never ever mention
> float again, version numbers aren't floats), and in some cases you find
> non-version data in SLOT (like $CTARGET).

Summation of string based failings.

First off, a modifier of an EAPI, say EAPI=3-strict isn't valid; why?  
strict is most likely a restriction, a specific negation of some 
aspect of eapi3.
  
Restrict is the place for it, or a similar metadata key.  Yes this 
doesn't hold across all cases (someone could've just decided 3-strict 
was a cool name fex), but throwing it out there to point out that eapi 
is ebuild templates, not restrictions.

Further, any deviation where loss of backwards compatibility would 
occur (limiting or extending bash syntax) is implicitly another 
format, thus beyond eapi's keen.  EAPI is ebuild (the format) spec/api 
*only*, see comments below re: format support for further explanation. 

Re: tagging EAPI at the top of a file, infra would probably shoot me 
for doing such- till a live, fully compatible and *roughly* equivalent 
parser is available, portage would have to do a bit of grepping, 
jacking up the regen times.

One thing I'm going to clarify also, is that the rewrite *does not* 
make it hard to tag new formats in.  There's no reason to jam 
everything into ebuilds, especially considering we are bound by 
existing definitions, and a body of 20,000 live ebuilds users/devs 
would get rather pissed off about if we forced a change across it.

If it's not an adjustment, a tweak, an extension/subtraction of ebuild
functionality, eapi isn't applicable imo, and a seperate format is the 
route to go (one that could easily live alongside in the tree).

EAPI is just for ebuild format.  alt formats (whether sh based or 
otherwise) would be wise to version their version also.


Either way, getting to the point of why strings suck badly in the 
point where it matters- as format version identifiers for the code 
that does the actual work.

Example code for numeric, say we have eapi 0-5 at this point.

def configure(self):
	if self.pkg.eapi > 0:
		...call configure phase...
	return


example code for strings

def configure(self):
	if self.pkg.eapi in ("0", "1", "2", "3", "4", "5"):
		...call configure phase...
	return

This sucks.

the response is "well, stick it into a list somewhere".  Can do, but 
you have to mangle each list everytime you add a new eapi.  That's a 
good way to lead to dumb ass bugs when tinkering with a new eapi 
level.

or... capabilities, as suggested.

capabilities = 	{"0":["configure"],
		"1":["configure"],
		"2":["configure"],
		"3":["configure"],
		"4":["configure"],
		"5":["configure"],}
		
def has_capability(eapi, capability):
	try:			return capability in capabilities[eapi]:
	except KeyError:	return False


def configure(self):
	if has_capability(self.pkg.eapi, "configure"):
		...call configure phase...
	return


or (slightly nastier example)

# eapi5 being eapi4, just with bash side changes.  implicit is that 
# their is bash side changes between each eapi, just stating it 
# explicitly to avoid the 'wtf' 

capabilities = 	{"0":["configure"],
		"1":["configure", "test_src_uri"],
		"2":["configure", "test_src_uri"],
		"3":["configure", "test_src_uri", "full_depriving"],
		"4":["configure", "test_src_uri", "full_depriving", "user_management"],
		"5":["configure", "test_src_uri", "full_depriving", "user_management"],}

def configure(self):
	if "configure" in capabilities.get(eapi, []):
		...call configure phase...
	return

Suggestions regarding using enumerations still dodge that point that 
via strings, you're building a finite set of matching strings to 
execute a block of code under, rather then establishing a min/max 
during which an int eapi should execute a block of code.  Latter's a 
helluva lot simpler then the former.

The arguement here is that it's somehow cleaner; it's not really.  You 
still have magic strings ("configure"), and a massive table of 
capabilities.  I used a single capability; if you're doing 
"has_capability" for every logic check, you're going to get into some 
very ugly terrain of magic const's all over the place.

Further, if attempting to map out what has changed between each eapi 
version, it's the wrong place to do so; that's implementation right 
there, specifically python side knowledge of how to support that 
version.

Proper design would actually use a magic constant at the top of the 
file, CONFIGURE_REQUIRED = 1 or something of the sort.

If I want to work on the next extension of eapi, I create an ebuild 
that has the new incremented #, and I can *already* have that eapi up 
and running, usurping the previous eapi definition.  No forced 
manual redefinition of stuff that is an easy way to induce bugs 
(increased manual work == bugs).  I can start extending the previous 
definition, tweaking it to I want without having to gut half of the 
controlling code.

Yes, I'm talking about it from the code perspective, but remember that 
this is the area that ultimately *matters*; control of the ebuild env 
is via the python side of things.  Keeping that as bug free, and clean 
as possible is what matters from where I sit; we can extend the ebuild 
env/template without issue, but swiveling from template to template is 
totally controlled by python side portage, which means that bit of 
code best be clean and robust.

That said, if you dig through my earlier patch, and comments about 
needing to handle int conversion better rather then flattening it to 
0, the code *is* forwards compatible if someone decides to stick strings 
into EAPI.  In other words, it's a moot debate due to the fact that 
the internal representation of eapi (is it a string, or is it an int?) 
is specific to that portage version; whatever version supports an eapi 
with strings tagged into has the fun of addressing the issues I've 
brought up above.

So basically the debate over string vs int can be left to when someone 
tries to add a non int eapi; forewarning: I'll bring up these points 
again when it's raised.  It's a Bad Idea (tm), and there is a damn 
good reason you don't see it elsewhere when dealing with versions of 
something :)

Final comment on this; there's a reason pkgs are release with 
major/minor as numeric; detection of capabilities, handling 
capabilities is *much* cleaner via such an approach.

~harring