Trimming Load from General to Specific

13 views
Skip to first unread message

Sean DeNigris

unread,
Jun 10, 2020, 11:44:56 AM6/10/20
to Metacello
I'm working on the Magritte baseline (here is the Pharo part) and it gets more and more complex as time goes on because there are so many platform packages and also because certain features were not available on older platforms (e.g. GT wasn't available on early Pharo versions), resulting in ranges like: 

for: #(#'pharo5.x' #'pharo6.x' #'pharo7.x' #'pharo8.x')

My goal is to have the spec for the current version of Pharo to be crystal clear and concise, with older platforms getting more complex. I'd like to say "for P9, do this; but for P8, do P9 except..."

For the feature range thing, I was thinking maybe do a general spec with the current functionality and then "turn things off" in older versions.

For example, let's say I have:
spec
 
for: #(#'pharo')
 
do: [
 spec
 
package: 'Magritte-GT' ];

Is there a way to say:
spec
 
for: #(#'pharo4.x')
 
do: [
 
"Don't load Magritte-GT (because GT wasn't available back then" ];

To put the question in a more general way, I had just asked on the Pharo Discord:
What are thoughts on best practice for maintaining a library that is expected to be used on multiple versions of Pharo? In the git world, I guess this would be done with branches, which is what Pharo itself does. Pharo seems suited to this due to limited backporting, with most commits going to the latest version. However, for a library as described, this seems like a lot of work to cherry pick to multiple branches, especially since I assume one would have to drop down to the command line rather than Iceberg. Another way, formerly used in Monticello, would be to have packages of the form MyProject-Platform-Pharo7, but then there is the issue of factoring platform specific code down to each platform version so there's not duplication.

Dale Henrichs

unread,
Jun 10, 2020, 1:34:35 PM6/10/20
to meta...@googlegroups.com


On 6/10/20 8:44 AM, Sean DeNigris wrote:
I'm working on the Magritte baseline (here is the Pharo part) and it gets more and more complex as time goes on because there are so many platform packages and also because certain features were not available on older platforms (e.g. GT wasn't available on early Pharo versions), resulting in ranges like: 

for: #(#'pharo5.x' #'pharo6.x' #'pharo7.x' #'pharo8.x')

My goal is to have the spec for the current version of Pharo to be crystal clear and concise, with older platforms getting more complex. I'd like to say "for P9, do this; but for P8, do P9 except..."

For the feature range thing, I was thinking maybe do a general spec with the current functionality and then "turn things off" in older versions.

For example, let's say I have:
spec
 
for: #(#'pharo')
 
do: [
 spec
 
package: 'Magritte-GT' ];

Is there a way to say:
spec
 
for: #(#'pharo4.x')
 
do: [
 
"Don't load Magritte-GT (because GT wasn't available back then" ];

Yes there is a way ...

spec
  for: #( #pharo4.x )
  do: [
    spec removePackage: 'Magritte-GT' ]

There are a handful of remove* methods available. See MetacelloAbstractVersionConstructor, `api` category, for the list of methods that can be used in a spec. ConfigurationOfMetacello happens to use all three remove* methods, since Metacello was undergoing significant changes during the early years. If you have specific questions about any of the methods, ping me again and I'll dig up an example:)

To put the question in a more general way, I had just asked on the Pharo Discord:
What are thoughts on best practice for maintaining a library that is expected to be used on multiple versions of Pharo? In the git world, I guess this would be done with branches, which is what Pharo itself does. Pharo seems suited to this due to limited backporting, with most commits going to the latest version. However, for a library as described, this seems like a lot of work to cherry pick to multiple branches, especially since I assume one would have to drop down to the command line rather than Iceberg. Another way, formerly used in Monticello, would be to have packages of the form MyProject-Platform-Pharo7, but then there is the issue of factoring platform specific code down to each platform version so there's not duplication.

First off, I think that Semantic Versioning[1] should be used ... in a volatile project like Pharo there needs to be relatively clear demarcations when the api breaking change boundaries are crossed. It is only fair to end users to formerly declare via the version number that as of this point forward, the API is incompatible.

Assuming semantic versioning, then it seems to make sense to create a master branch for each major/minor version pair ... in practical terms this means that If I expect use version 1.2.x of project Foo, then I would checkout the master1.2 branch of the project and always update to the head of the branch, because any new commits on that branch are not supposed to break the api and only fix bugs ... If I am interested in new features then I can choose to move to master1.3 and still be assured that the api has not changed other additions.

I am using this model with Rowan and it seems to work ... I have a candidate1.2 branch where changes are collected (bleeding edge) until I'm ready to release to master1.2 branch ... the candidate 1.3 branch is branched off of the candidate1.2 branch so any bug fixes I make on the candidate1.2 branch can be merged into the candidate!.3 branch and so on ... I also have and candidate2.0 branch branched off of candidate1.3 and in theory I can merge bugfixes across the boundary. I did that for the first year of working on candidate2.0, but at this point the the api has progresses to the point where very little code can be merged without work, so any bugfixes across the 2.0 boundary will have to be done by cherrypicking.

Notice that this is not a branch per platform model ... multiple platforms are supported in the master1.2 branch ... but the set of platforms supported are not required to span the major version boundary ... which can simplify things goind forward and having older branches/versions supported over the long term makes it simpler for projects to continue putting along using ancient versions of a project ...

I used a platform per branch in the FileTree project and it did not work well ... the separate platform branches evelved independently and it was nearly impossible to manage the common set of functionality.

Does this help?

Dale

[1] https://semver.org/
[2] https://github.com/dalehenrich/filetree
--
You received this message because you are subscribed to the Google Groups "Metacello" group.
To unsubscribe from this group and stop receiving emails from it, send an email to metacello+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/metacello/5953a565-dff0-4a73-b78f-90a5b09479aeo%40googlegroups.com.

Sean DeNigris

unread,
Jul 20, 2020, 1:21:24 PM7/20/20
to Metacello
Yes there is a way ... There are a handful of remove* methods available. 
Perfect! Thanks :)

Does this help?

Quite a bit. One thing I'm not crystal clear on (I think because it looks like Rowan currently supports only Gemstone) is your platform package naming convention. I see a few candidates:
- Rowan-GemStone-3215
- Rowan-GemStone-32x
- Rowan-GemStone-35x
- Rowan-GemStone-Components-Extensions 
- etc

Dale Henrichs

unread,
Jul 20, 2020, 2:42:52 PM7/20/20
to meta...@googlegroups.com

I'm not sure what your point is ... package names are always interesting ... as  a project evolves, a name that made sense in the moment, is likely to reach a point where the name no longer makes sense (for a variety of reasons) and there is always tension between keeping package names stable so that merging issues are a bit more manageable and changing package names to match their current usage ...

If you look at this component definition for Rowan[1], you'll see that the Rowan-GemStone-3215 package is expected to be loaded for all GemStone 3.x versions starting from 3.2.0 (condition gs3.[2-]), along with the packages GemStone-Interactions-Core and GemStone-Interactions-Kernel.

And looking at this component[2], you'll see that the package Rowan-GemStone-32x is intended for GemStone 3.2.0 through 3.4.x (condition gs3.[2-4]),

For Rowan-GemStone-35x the component[3] shows that it is intended for GemStone 3.5.0 and beyond (condition gs3.[5-]).

Finally these components[4]and [5] show that Rowan-GemStone-Components-Extensions is intended for all versions of gemstone (condition gemstone & condition componentsV2). Note that there are two packages in the the component  common/componentsV2/platforms/gemstone/Components:
Rowan-GemStone-Components and Rowan-GemStone-Components-Extensions ... the distinction between these two packages is that Rowan-GemStone-Components is to be loaded into the Globals symbol dictionary (the default ) and Rowan-GemStone-Components-Extensions is to beloaded into the RowanTools symbol dictionary ...

The Rowan meta data you are looking at in these links is for Rowan V2.0.0, but some of the packages date back to RowanV1.0.0.

I have been pushing Rowan packages around quite a bit as I get closer to finishing Rowan V2.0.0, but I am holding off renaming packages until Rowan itself is stabilized ... which brings up another tension on package naming which is running out of time as one approaches release dates.

A final point that I have been playing with is that I am hoping that in the Rowan development environment, developers will use component structures for organizing code within the development environment rather than having only package names to work with --- given the necessity of relying heavily on extension methods and platform-specific classes in platform-specific packages, the package structure can get very fragmented --- So I'm thinking that basing the code browsers on component structure[6], will provide a way for developers to organize their code logically without having to invent arcane package naming schemes.

Notice that the 5-6 package names that have come up in this discussion are organized into only 2 components (Core and Components).

If you look at the structure in the common/components directory[7], you can see that the 100+ Rowan packages are divided into about 10 components and that there is additional component structure that is driven by conditional requirements ... and of course the structure you see here is also not the final structure as at this point I have different ideas as to how I want how to best organize the code:)

Dale

[1] https://github.com/GemTalk/Rowan/blob/issue_626/rowan/components/common/platforms/gemstone32-/Core.ston
[2] https://github.com/GemTalk/Rowan/blob/issue_626/rowan/components/common/platforms/gemstone32-4/Core.ston

Sean DeNigris

unread,
Jul 23, 2020, 9:28:13 AM7/23/20
to Metacello
On Monday, July 20, 2020 at 2:42:52 PM UTC-4, Dale wrote:

I'm not sure what your point is ...

Ha ha, sorry. I meant in reference to my earlier question about platform (Smalltalk, not OS) compatibility packages. I've seen things like: "MyProject-Platform-Pharo7", "MyProject-PlatformSqueak", etc in the wild. Your "x.x" notation seemed a  bit more sophisticated, and you seem to have dropped the word "Platform", so I was wondering if you had evolved your naming scheme so I could learn something!

Dale Henrichs

unread,
Jul 23, 2020, 12:23:22 PM7/23/20
to meta...@googlegroups.com

Sorry to disappoint:) I'm still casting about and as I mentioned, due to the shifting sands underneath every platform-specific package name ... one is lucky if the intended meaning of a name survives a couple of releases ... so  I suppose I use the x.x notation to indicate the starting point for a platform package that may well be applicable to more than one minor or major version increment ...

Dale 

--
You received this message because you are subscribed to the Google Groups "Metacello" group.
To unsubscribe from this group and stop receiving emails from it, send an email to metacello+...@googlegroups.com.

Sean DeNigris

unread,
Jul 19, 2021, 7:13:36 PM7/19/21
to Metacello
On Wednesday, June 10, 2020 at 1:34:35 PM UTC-4 Dale wrote:

There are a handful of remove* methods available. See MetacelloAbstractVersionConstructor, `api` category, for the list of methods that can be used in a spec.

 I was able to use that to remove a package. However, now I need to remove a baseline and it seems there is no removal method - I only see project, package , and group

Dale Henrichs

unread,
Jul 20, 2021, 3:34:39 PM7/20/21
to meta...@googlegroups.com, Metacello
Sean,

I've read the code a bit and it looks to me like #removeProject: should work for a baseline (they are stored by name in the same data structure) ... There are no tests for this, so it might not work, but there is a good chance that it will "work" ...

Dale
--
You received this message because you are subscribed to the Google Groups "Metacello" group.
To unsubscribe from this group and stop receiving emails from it, send an email to metacello+...@googlegroups.com.

Sean DeNigris

unread,
Jul 26, 2021, 11:38:56 AM7/26/21
to Metacello
I've read the code a bit and it looks to me like #removeProject: should work for a baseline

It worked! But I realize the other half is removing references to the now-nonexistent project. If I have:
    spec package: 'Tesseract' with: [ spec requires: #('NonExistentProject') ]
How do I remove that requirement? IIRC simply passing a collection which conflicts with another platform simply merges them.

p.s. I recall there used to be a one-pager showing every conceivable operation in a baseline spec, but I couldn't find it linked from the GH repo - mostly stuff about the scripting API. Is that still available?

Sean DeNigris

unread,
Jul 26, 2021, 11:46:14 AM7/26/21
to Metacello
I recall there used to be a one-pager showing every conceivable operation in a baseline spec
Found!

Which led me to (I think) the solution:
    spec package: 'Tesseract' overrides: [  spec requires: ... ];
 
I couldn't find it linked from the GH repo
Might be good to link there (assuming I didn't miss one!) 

Dale Henrichs

unread,
Jul 26, 2021, 2:04:16 PM7/26/21
to meta...@googlegroups.com, Metacello
Sean,

By jove, I think you've got it :)

Is this the page you were thinking of[1]? It looks like it ... If it is I'll either embed it in the Readme(?) or add a link ...

Dale

--
You received this message because you are subscribed to the Google Groups "Metacello" group.
To unsubscribe from this group and stop receiving emails from it, send an email to metacello+...@googlegroups.com.

Sean DeNigris

unread,
Jul 26, 2021, 3:30:34 PM7/26/21
to Metacello
By jove, I think you've got it :)
Yes, it worked :)
 
Is this the page you were thinking of[1]? It looks like it ... If it is I'll either embed it in the Readme(?) or add a link ...
That's it. Whichever you think best, as long as it's discoverable 

Dale Henrichs

unread,
Jul 26, 2021, 7:13:25 PM7/26/21
to meta...@googlegroups.com, Metacello
DONE...
--
You received this message because you are subscribed to the Google Groups "Metacello" group.
To unsubscribe from this group and stop receiving emails from it, send an email to metacello+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages