Jul 022016
 

In my previous post, I wrote about the need to copy a port from head to a branch in some circumstances, specifically when a master-port is updated and the slave ports do not already exist in the FreshPorts database on that branch. This is a side-effect of FreshPorts only taking action for commits, and not repo-copies.

Get new pathnames

Expanding upon the recursive query from that post, I think I have a starting point for a copy-port function. Let me illustrate with this query. Assume we need to duplicate sysutils/bacula-client from head to branch 2016Q2.

WITH RECURSIVE all_descendents AS (
  SELECT id, name, parent_id, directory_file_flag, status
    FROM element
    WHERE id = (select pathname_id('/ports/head/sysutils/bacula-client/'))
  UNION
  SELECT E.id, E.name, E.parent_id, E.directory_file_flag, E.status
    FROM element E
    JOIN all_descendents AD
      ON (E.parent_id = AD.id)
)
   SELECT directory_file_flag, element_pathname(id) AS pathname, replace(element_pathname(id), '/ports/head/', '/ports/branches/2016Q2/')
      FROM all_descendents
     WHERE status = 'A'
 ORDER BY pathname;

 directory_file_flag |                  pathname                   |                        replace                         
---------------------+---------------------------------------------+--------------------------------------------------------
 D                   | /ports/head/sysutils/bacula-client          | /ports/branches/2016Q2/sysutils/bacula-client
 F                   | /ports/head/sysutils/bacula-client/Makefile | /ports/branches/2016Q2/sysutils/bacula-client/Makefile
(2 rows)

The first column indicates file or directory. The second column is the name of the existing element in head. The third column is the name of the element to be created in the branch.

Add new pathnames to the database

Next, how do use that information to create the new elements?

We use the existing function: element_add($in_element_pathname, $element_directory_file_flag)

Let’s incorporate that into the query above and get:

WITH RECURSIVE all_descendents AS (
  SELECT id, name, parent_id, directory_file_flag, status
    FROM element
    WHERE id = (select pathname_id('/ports/head/sysutils/bacula-client/'))
  UNION
  SELECT E.id, E.name, E.parent_id, E.directory_file_flag, E.status
    FROM element E
    JOIN all_descendents AD
      ON (E.parent_id = AD.id)
)
   SELECT element_add(replace(element_pathname(id), '/ports/head/', '/ports/branches/2016Q2/'), directory_file_flag), replace(element_pathname(id), '/ports/head/', '/ports/branches/2016Q2/'), directory_file_flag
      FROM all_descendents
     WHERE status = 'A';

 element_add |                        replace                         | directory_file_flag 
-------------+--------------------------------------------------------+---------------------
      739280 | /ports/branches/2016Q2/sysutils/bacula-client          | D
      739281 | /ports/branches/2016Q2/sysutils/bacula-client/Makefile | F

-- Let's confirm the new elements:

WITH RECURSIVE all_descendents AS (
  SELECT id, name, parent_id, directory_file_flag, status
    FROM element
    WHERE id = (select pathname_id('/ports/branches/2016Q2/sysutils/bacula-client/'))
  UNION
  SELECT E.id, E.name, E.parent_id, E.directory_file_flag, E.status
    FROM element E
    JOIN all_descendents AD
      ON (E.parent_id = AD.id)
)
   SELECT id, name, parent_id, directory_file_flag, status, element_pathname(id) AS pathname
      FROM all_descendents
     WHERE status = 'A'
 ORDER BY pathname;

   id   |     name      | parent_id | directory_file_flag | status |                        pathname                        
--------+---------------+-----------+---------------------+--------+--------------------------------------------------------
 739280 | bacula-client |    732848 | D                   | A      | /ports/branches/2016Q2/sysutils/bacula-client
 739281 | Makefile      |    739280 | F                   | A      | /ports/branches/2016Q2/sysutils/bacula-client/Makefile
(2 rows)

There they are!

Create the port

This creates the directory structure (i.e. pathnames) but it does not create the port. We can do that next with createport($port_element_id, $port_category_id). Let’s try this:

select createport(pathname_id(‘/ports/branches/2016Q2/sysutils/bacula-client’), getcategory(‘sysutils’));

Before we run that, let’s break down the individual components, because I found an error and I want to demonstrate it.

select pathname_id('/ports/branches/2016Q2/sysutils/bacula-client');
 pathname_id 
-------------
      739280
(1 row)

You will see 739280 mentioned above in the output from creating the elements on the branch.

Next we grab the category details:

select getcategory('sysutils');
 getcategory 
-------------
            
(1 row)

Eh? Woah, that’s not good.

Fix the category code

Let’s look at that code:

CREATE OR REPLACE FUNCTION GetCategory (text ) RETURNS int4 AS $$
   DECLARE
      category_name ALIAS for $1;
      pathname             text;   
      category_element_id  int4;
      category_id          int4;
   BEGIN
      pathname            := 'ports/' || category_name;
      category_element_id := Pathname_ID(pathname);
      if NOT category_element_id IS NULL THEN
         select id
           into category_id
           from categories
          where element_id = category_element_id;
      END IF;
      return category_id;
   END;
$$ LANGUAGE 'plpgsql';

Ahh, look at line 8. That pathname needs to be prefixed with ‘ports/head/’. This change is related to Full pathnames, which was work carried out a few years ago. This function was used only by some one-off maintenance scripts.

After making that change, the results are as expected:

# select getcategory('sysutils');
 getcategory 
-------------
          20
(1 row)

Back to creating the port

Let’s create that port:

# select createport(pathname_id('/ports/branches/2016Q2/sysutils/bacula-client'), getcategory('sysutils'));
 createport 
------------
      41761
(1 row)

 select element_pathname(element_id) from ports where id = 41761;
               element_pathname                
-----------------------------------------------
 /ports/branches/2016Q2/sysutils/bacula-client
(1 row)

We have a port on the branch. It needs to be refreshed from the Makefile (via make -V), but that is for a later stage.

I think we are well on our way to copying a port upon demand.

Website Pin Facebook Twitter Myspace Friendfeed Technorati del.icio.us Digg Google StumbleUpon Premium Responsive