Right, so lets look at these one by one:

>  "The importer's version range matches the exporter's version. See Semantic 
> Versioning 
> <https://osgi.org/specification/osgi.core/7.0.0/framework.module.html#framework.module-semantic.versioning>.”
>  The reference to semantic versioning makes the content of that section part 
> of the specification of the resolving process. But as you and others have 
> pointed out, build/packaging and resolving are "very separate steps". How to 
> apply exactly the information from section "Semantic Versioning" to the 
> resolving process (i.e. to matching the importer's and exporter's versions) 
> is left open to interpretation. Reading the specification, I was unsure if 
> the recommendation to ignore the micro part should be applied to the 
> resolving process. This caused a lot of confusion on my side. Unless 
> everybody agrees that reading the specification in this way is my fault only 
> and the intended meaning is obvious to everybody else -- even without a 
> decade of OSGi experience -- I think there is room for improvement.
> 
So I think your confusion here comes from the difference between “normative” 
statements, which lay out the strict rules that must be followed, and 
“recommendations” (usually following the word “should”). A normative definition 
of version range syntax and meaning is available in Version Ranges 
<https://osgi.org/specification/osgi.core/7.0.0/framework.module.html#i3189032>.
 This strictly defines what version ranges are, including what matches and what 
doesn’t. You will note that micro versions are *never* ignored. If your version 
range puts a micro version into its floor or ceiling then that defines the 
matching space.

The Semantic Versioning section starts with the following statement: 

"Though the OSGi frameworks do not enforce a specific encoding for a 
compatibility policy, it is strongly recommended to use the following 
semantics."

This is the first big hint to say “this is a non-normative part of the spec, 
it’s useful information but doesn’t restrict what you do”. The end of the 
section goes on to recommend:

"Both consumers and providers should use the version they are compiled against 
as their base version. It is recommended to ignore the micro part of the 
version because systems tend to become very rigid if they require the latest 
bug fix to be deployed all the time. For example, when compiled against version 
4.2.1.V201007221030, the base version should be 4.2.

A consumer of an API should therefore import a range that starts with the base 
version and ends with the next major change, for example:[4.2,5). A provider of 
an API should import a range that starts with the base version up to the next 
minor change, for example:[4.2,4.3)."

This exactly the default that bnd provides when packaging your bundle. It tries 
to find the lowest version bundle to compile against, then sets the version 
range in your Import Package statement appropriately. This default behaviour 
what you need to override to get a minimum import version including a micro 
version.

> Applying the information from the section "Semantic Versioning" to the 
> build/packaging process, I stumble about the recommendation "to ignore the 
> micro part of the version because systems tend to become very rigid if they 
> require the latest bug fix to be deployed all the time." Sorry for being 
> obstinate, but when you read this and have my use case in mind (trying to 
> make sure that the resolver rules out everything below a specific bug fix 
> version) this recommendation simply does not make sense. And there is no 
> mentioning that specifying a lower bound with a micro part greater zero might 
> make sense (as everybody seems to be able to agree upon -- unless we are 
> talking about the special case of a bundle that only contains interfaces and 
> DTOs). Specifying a lower bound with a micro part effectively adds to the 
> information about two bundle's (their packages' to be precise) API 
> compatibility a "hint" for the resolver to only consider a subset of (API 
> compatible) providing bundles. This limits the flexibility (the resolver is 
> no longer allowed to compute a result with the buggy version(s) of the 
> referenced packages) but this is a limitation I intend. Of course, the spec 
> only "recommends" ignoring the micro part. But if a specification provides a 
> recommendation, it should also mention the scope to which it applies. And it 
> doesn't apply to my use case, which I -- obviously -- wouldn't consider 
> "exotic".
> 

The key part of this is that "Of course, the spec only "recommends" ignoring 
the micro part”. You are free to ignore recommendations when they don’t fit 
what you need. The expectation that a micro version greater than zero is a 
valid thing to do is implicit because
The version range syntax explicitly includes it and describes how to do it
The Semantic Versioning section recommends, rather than requires setting it to 
zero, and explains why setting it to zero is a good idea. If that “good idea” 
goes against your requirements then clearly the recommendation doesn’t apply to 
you.

One additional point I would make is that "Specifying a lower bound with a 
micro part effectively adds to the information about two bundle's (their 
packages' to be precise) API compatibility a "hint" for the resolver to only 
consider a subset of (API compatible) providing bundles.” Is an incorrect 
statement. Specifying a lower bound with a micro part isn’t a hint, it’s a hard 
requirement telling the resolver (and the framework) that under no 
circumstances is the package acceptable. It has exactly the same force as 
setting a different major or minor version.

> If the OSGi module layer wanted to keep the API compatibility expressed by 
> the Import-/Export-Package versions clean of hints for the resolver then it 
> should provide another means to propagate this requirement. (Nobody brought 
> this up, so it is probably a dead end: I did ponder if an additional 
> "Require-Bundle" header with bundle-version [2.0.3,3) would be a better means 
> to propagate the version requirement to the resolver [instead of 
> Import-Package with micro part greater 0]. But as the usage of Require-Bundle 
> is discouraged, I ruled this out. It would, however, be a method to separate 
> the API compatibility specification from the resolver hint -- a remedy with 
> side-effects, of course).
> 


The reason that this wasn’t raised by anyone is that it is simply unnecessary. 
As I say above (and the specification says in the version range section) the 
normative behaviour for a version range includes micro versions. They aren’t 
hints, they are the law. Therefore the correct way to restrict this is to set 
the floor of your version range appropriately.

As a final point, you mention that your use case is not exotic. I would agree, 
however I think that you’re looking at it from the wrong perspective. You are 
assuming in your version range the everything from 2.0.3 up to (but not 
including) 3.0.0 will work for your bundle, but what if someone introduces a 
new bug (or re-introduces the old bug) in a future release? There will *always* 
be the potential for bugs to prevent things working properly, and the correct 
way to avoid deploying a buggy version is to avoid having it as a candidate 
when you resolve. The Import-Package statement is primarily about API 
compatibility, not about functional correctness. This is because we can’t make 
guarantees about future code being bug free, but we can at least make 
guarantees about the binary compatibility of its API. This is why, in your 
position, I would *not* set my minimum import version to 2.0.3 (I would use 
2.0.0), but I would make sure that I only included “working" versions of the 
library in any repository that I resolved against. This is then an ongoing job 
in the future, making sure I protect myself against future broken versions as 
well as past broken versions.

I hope that this helps.

All the best,

Tim

> On 19 Jun 2019, at 15:25, Michael Lipp <m...@mnl.de> wrote:
> 
> Thanks for engaging yourself with my question.
> 
> I think my problems boil down to two issues that could (and maybe should) be 
> improved in the specification.
> 
>> I’ll try to take the questions individually, and we can attempt to separate 
>> your questions about build/packaging (i.e. creating your bundle) and 
>> resolving (i.e. creating your deployment). These are two very separate steps.
> And the steps have different rules. My problem is that the specification 
> lumps them together. I've cited this before: "The importer's version range 
> matches the exporter's version. See Semantic Versioning 
> <https://osgi.org/specification/osgi.core/7.0.0/framework.module.html#framework.module-semantic.versioning>."
>  
> [https://osgi.org/specification/osgi.core/7.0.0/framework.module.html#framework.module.resolvingprocess
>  
> <https://osgi.org/specification/osgi.core/7.0.0/framework.module.html#framework.module.resolvingprocess>].
>  The reference to semantic versioning makes the content of that section part 
> of the specification of the resolving process. But as you and others have 
> pointed out, build/packaging and resolving are "very separate steps". How to 
> apply exactly the information from section "Semantic Versioning" to the 
> resolving process (i.e. to matching the importer's and exporter's versions) 
> is left open to interpretation. Reading the specification, I was unsure if 
> the recommendation to ignore the micro part should be applied to the 
> resolving process. This caused a lot of confusion on my side. Unless 
> everybody agrees that reading the specification in this way is my fault only 
> and the intended meaning is obvious to everybody else -- even without a 
> decade of OSGi experience -- I think there is room for improvement.
> 
>>> If I know some bundle (one of its exported packages to be precise) to be 
>>> buggy up to (and including) version x.y.z then why should I not explicitly 
>>> reference x.y.z+1 (i.e. the first fixed version) as a requirement for the 
>>> Import-Package?
>>> 
>> You absolutely can have a dependency on a micro version, but this isn’t a 
>> resolver issue, it’s a build/packaging issue. That’s the point at which you 
>> define the version range for your import package. If you know that you need 
>> a specific bug fix package then by all means put that as your base version. 
>> The recommendation to avoid micro versions in the import range still applies 
>> though as tight restrictions limit deployment flexibility. You obviously 
>> understand this on some level because you haven’t been trying to limit the 
>> upper version to A-2.0.4, but instead to A-3.
> Applying the information from the section "Semantic Versioning" to the 
> build/packaging process, I stumble about the recommendation "to ignore the 
> micro part of the version because systems tend to become very rigid if they 
> require the latest bug fix to be deployed all the time." Sorry for being 
> obstinate, but when you read this and have my use case in mind (trying to 
> make sure that the resolver rules out everything below a specific bug fix 
> version) this recommendation simply does not make sense. And there is no 
> mentioning that specifying a lower bound with a micro part greater zero might 
> make sense (as everybody seems to be able to agree upon -- unless we are 
> talking about the special case of a bundle that only contains interfaces and 
> DTOs). Specifying a lower bound with a micro part effectively adds to the 
> information about two bundle's (their packages' to be precise) API 
> compatibility a "hint" for the resolver to only consider a subset of (API 
> compatible) providing bundles. This limits the flexibility (the resolver is 
> no longer allowed to compute a result with the buggy version(s) of the 
> referenced packages) but this is a limitation I intend. Of course, the spec 
> only "recommends" ignoring the micro part. But if a specification provides a 
> recommendation, it should also mention the scope to which it applies. And it 
> doesn't apply to my use case, which I -- obviously -- wouldn't consider 
> "exotic". 
> 
> If the OSGi module layer wanted to keep the API compatibility expressed by 
> the Import-/Export-Package versions clean of hints for the resolver then it 
> should provide another means to propagate this requirement. (Nobody brought 
> this up, so it is probably a dead end: I did ponder if an additional 
> "Require-Bundle" header with bundle-version [2.0.3,3) would be a better means 
> to propagate the version requirement to the resolver [instead of 
> Import-Package with micro part greater 0]. But as the usage of Require-Bundle 
> is discouraged, I ruled this out. It would, however, be a method to separate 
> the API compatibility specification from the resolver hint -- a remedy with 
> side-effects, of course).
> 
> (As a side note: I do know about the difference between package versions and 
> bundle versions and the possible benefits of versioning packages 
> individually. However, bundle "A" is a library that also has its usages 
> outside the OSGi "ecosystem". And therefore -- as described e.g. in "Wrapping 
> libraries" [https://bnd.bndtools.org/chapters/390-wrapping.html 
> <https://bnd.bndtools.org/chapters/390-wrapping.html>] and as it is common 
> practice when building such libraries with an OSGi compliant manifest in the 
> first place -- all packages are exported with the same version which also 
> matches the bundle version.)
> 
> Thanks again!
> 
>  - Michael
> 
> 

_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to