I used to think branches were simple when it came to FreshPorts, but I was wrong. Consider slave ports for example.
If we get a commit for databases/mariadb100-server, we have to update the slave ports, but only the slave ports on the branch, not the slave ports on head.
That sounds easy enough, but keep in mind that FreshPorts only knows about ports which have had a commit. If the first commit is to the master port, then there is no slave port on the branch for FreshPorts.
But wait, you’ll think, the branch is just a branch and it’s a copy of the repo from at the time the branch was … branched, the slave port is always there.
Well, yes, in the repo, but FreshPorts is not a copy of the repo, it is a reflection of commits and that data is extracted via make -V (for the most part).
When that commit for databases/mariadb100-server, there might not be any ports on the branch which have it as a master port. However, there might be commits on other branches, which means the existing SQL might return something like this:
SELECT PA.id AS slave_port_id, PA.name AS slave_port_name, PA.category_id AS slave_category_id, PA.category AS slave_category_name, element_pathname(EP.element_id) FROM ports_active PA, element_pathname EP WHERE PA.master_port = 'databases/mariadb100-server' AND PA.element_id = EP.element_id; slave_port_id | slave_port_name | slave_category_id | slave_category_name | element_pathname ---------------+-------------------+-------------------+---------------------+---------------------------------------------------- 35630 | mariadb100-client | 32 | databases | /ports/head/databases/mariadb100-client 40269 | mariadb100-client | 32 | databases | /ports/branches/2015Q3/databases/mariadb100-client 41023 | mariadb100-client | 32 | databases | /ports/branches/2015Q4/databases/mariadb100-client (3 rows)
As you can see, we have three different slave ports, none of which are on our branch (which is this particular case, is 2016Q2.
I think we need to have a query which takes the path into consideration, so we get only the slave ports on our branch. For example:
SELECT PA.id AS slave_port_id, PA.name AS slave_port_name, PA.category_id AS slave_category_id, PA.category AS slave_category_name, element_pathname(EP.element_id) FROM ports_active PA, element_pathname EP WHERE PA.master_port = 'databases/mariadb100-server' AND EP.pathname ilike '/ports/branches/2016Q2/%' AND PA.element_id = EP.element_id; slave_port_id | slave_port_name | slave_category_id | slave_category_name | element_pathname ---------------+-----------------+-------------------+---------------------+------------------ (0 rows)
This is correct. However, it is not ideal for our purposes. We want a list of ports, whether or not they are already on our branch.
Union to the rescue.
SELECT PA.id AS slave_port_id, PA.name AS slave_port_name, PA.category_id AS slave_category_id, PA.category AS slave_category_name, element_pathname(EP.element_id) FROM ports_active PA, element_pathname EP WHERE PA.master_port = 'databases/mariadb100-server' AND EP.pathname ilike '/ports/branches/2016Q2/%' AND PA.element_id = EP.element_id UNION SELECT PA.id AS slave_port_id, PA.name AS slave_port_name, PA.category_id AS slave_category_id, PA.category AS slave_category_name, element_pathname(EP.element_id) FROM ports_active PA, element_pathname EP WHERE PA.master_port = 'databases/mariadb100-server' AND EP.pathname ilike '/ports/head/%' AND PA.element_id = EP.element_id ORDER BY slave_category_name, slave_port_name; slave_port_id | slave_port_name | slave_category_id | slave_category_name | element_pathname ---------------+-------------------+-------------------+---------------------+----------------------------------------- 35630 | mariadb100-client | 32 | databases | /ports/head/databases/mariadb100-client (1 row)
Now we have the list we need, and it will be clear which ports do not exist on the branch and we must first create the port instead of fetching it. This point becomes clearer when you try the same query on databases/postgresql94-server
SELECT PA.id AS slave_port_id, PA.name AS slave_port_name, PA.category_id AS slave_category_id, PA.category AS slave_category_name, element_pathname(EP.element_id) FROM ports_active PA, element_pathname EP WHERE PA.master_port = 'databases/postgresql94-server' AND EP.pathname ilike '/ports/branches/%' AND PA.element_id = EP.element_id UNION SELECT PA.id AS slave_port_id, PA.name AS slave_port_name, PA.category_id AS slave_category_id, PA.category AS slave_category_name, element_pathname(EP.element_id) FROM ports_active PA, element_pathname EP WHERE PA.master_port = 'databases/postgresql94-server' AND EP.pathname ilike '/ports/head/%' AND PA.element_id = EP.element_id ORDER BY slave_category_name, slave_port_name, element_pathname; slave_port_id | slave_port_name | slave_category_id | slave_category_name | element_pathname ---------------+-----------------------+-------------------+---------------------+------------------------------------------------------ 40432 | postgresql94-client | 32 | databases | /ports/branches/2015Q2/databases/postgresql94-client 39921 | postgresql94-client | 32 | databases | /ports/branches/2016Q1/databases/postgresql94-client 34655 | postgresql94-client | 32 | databases | /ports/head/databases/postgresql94-client 34657 | postgresql94-contrib | 32 | databases | /ports/head/databases/postgresql94-contrib 34678 | postgresql94-docs | 32 | databases | /ports/head/databases/postgresql94-docs 34677 | postgresql94-plperl | 32 | databases | /ports/head/databases/postgresql94-plperl 34675 | postgresql94-plpython | 32 | databases | /ports/head/databases/postgresql94-plpython 34676 | postgresql94-pltcl | 32 | databases | /ports/head/databases/postgresql94-pltcl (8 rows)
If you look only at slave_port_name and slave_category_name, you can see we have duplicates. The ideal situation takes values from head first, then removes any values found in the branch we are interested in, and for this query, we are interested in just one branch.
I’m positive we can do this with just one query.
I thought about this issue overnight. I think the solution is as follows.
- Get the list of master ports from head
- Look for those same port names on the branch
- If the port exists, confirm it still has the same master port (i.e. the one from step #1)
- If not the same same master port, ignore this ‘slave’ port
- If port exists, refresh it
- If port does not exist on branch, create it, and refresh it
NOTE:
- Unless otherwise mentioned, we are dealing with the branch upon with the commit occurred
- When refreshing, we refer to the commit we are processing now
I’ll have to think about this some more.