packaging system

classic Classic list List threaded Threaded
52 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Re: packaging system

Stéfan van der Walt
On Wed, Jun 22, 2005 at 10:47:46AM +0200, David Bateman wrote:

> I think a bit more complete dependency checking code might be good idea
> to get into place early to save us some pain later. At the moment you
> have a line "Depends:" in the DESCRIPTION file, that contains a list of
> all packages that the current package depends on. May I suggest that
> each package dependency has a seperate "Depends:" line of the form
>
> Depends: PACKAGE [<|=|>] VERSION
>
> to take into account the possible need for a particular version of a
> package or newer than, or range of versions.. For example you might have
>
> Depends: Signal >= 1.0.0
> Depends: Signal < 2.0.0

I think Søren implemented something like this already, since his
sample package contains the following line:

Depends: octave (>= 2.1.64)

Regards
Stéfan

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

David Bateman-3
Stefan van der Walt wrote:

>On Wed, Jun 22, 2005 at 10:47:46AM +0200, David Bateman wrote:
>  
>
>>I think a bit more complete dependency checking code might be good idea
>>to get into place early to save us some pain later. At the moment you
>>have a line "Depends:" in the DESCRIPTION file, that contains a list of
>>all packages that the current package depends on. May I suggest that
>>each package dependency has a seperate "Depends:" line of the form
>>
>>Depends: PACKAGE [<|=|>] VERSION
>>
>>to take into account the possible need for a particular version of a
>>package or newer than, or range of versions.. For example you might have
>>
>>Depends: Signal >= 1.0.0
>>Depends: Signal < 2.0.0
>>    
>>
>
>I think Søren implemented something like this already, since his
>sample package contains the following line:
>
>Depends: octave (>= 2.1.64)
>
>Regards
>Stéfan
>
>  
>
Yes, he has I see that now. However, the syntax is

Depends: octave (>= 2.1.64), signal ( >= 1.0.0), signal (< 2.0.0)

all on a single depends line. Multiple Depends lines would be nice to
have.. with a function like

function deps = desc_get_deps (desc)
    first = true;
    deps = "";
    for i = 1:length(desc.keywords)
        if (strcmp(desc.keywords{i}, "DEPENDS"))
          if (first)
             deps = desc.values{i};
          else
             deps = [deps, ",", desc.values{i}];
          endif
        endif
    endfor
endfunction

Also, only checks against the installed packages are performed.. What I
see as an extention is to create a complete dependency table of all of
the installed packages, with a function like

function dependency_table = installed_dependencies (prefix,
installed_packages)
  count = 0;
  for i = 1:length(installed_packages.name)
    desc = get_description ([prefix, installed_packages.name{i}]);
    verify_description (desc);
    for j = 1:length(desc.keywords)
      if (strcmp(desc.keywords{j}, "DEPENDS"))
         deps = parse_dependencies ( desc.values{i});
         if (iscell (deps))
           for k = 1:length(deps)
              count++;
              dependency_table.name{count} = installed_packages.name{i};
              dependency_table.version{count} =
installed_packages.version{i};
              dependency_table.package{count} = deps.package{k};
              dependency_table.operator{count} = deps.operator{k};
              dependency_table.dversion{count} = deps.version{k};
         endif
      endif
    endfor
  endfor
endfunction

function pdep = parse_dependencies (deps)
    deps = split_by(tolower(deps), ",");

    if (length(deps) < 1)
       pdeps = false;
       return;
    endif

    ## For each dependency
    for i = 1:length(deps)
        dep = deps{i};
        lpar = find(dep == "(");
        rpar = find(dep == ")");
        ## Does the dependency specify a version
        ## Example: package(>= version)
        if (length(lpar) == 1 && length(rpar) == 1)
            package = tolower(strip(dep(1:lpar-1)));
            sub = dep( lpar(1)+1:rpar(1)-1 );
            parts = split_by(sub, " ");
            idx = [];
            for r = 1:size(parts,1)
                if (length(parts{r}) > 0)
                    idx(end+1) = r;
                endif
            endfor
           
            if (length(idx) != 2)
                error(["There's something wrong with the DESCRIPTION
file. " ...
                       "The dependency %s has the wrong syntax.\n"], dep);
            endif
            operator = parts{idx(1)};
            version  = fix_version(parts{idx(2)});
           
        ## If no version is specified for the dependcy
        ## we say that the version should be greater than
        ## or equal to 0.0.0
        else
            pdep.package{i} = tolower(strip(dep));
            pdep.operator{i} = ">=";
            pdep.version{i}  = "0.0.0";
        endif
     endfor
endfunction

then have three other function, one to remove a package, one to add a
package to the table and another to validate the dependency table, like

function new_table = delete_dependency (table, name)
   count = 0;
   for i = 1:length(table.name)
      if (table.name{i} != name)
         count++;
         new_table.name{count} = table.name{i};
         new_table.version{count} = table.version{i};
         new_table.package{count} = table.package{i};
         new_table.operator{count} = table.operator{i};
         new_table.dversion{count} = table.dversion{i};
       endif
    endfor

    if (count == 0)
      new_table = false;
    endif
endfunction

function table = add_dependency (table, name, version, desc)
    count = length (table.name);
    for j = 1:length(desc.keywords)
      if (strcmp(desc.keywords{j}, "DEPENDS"))
         deps = parse_dependencies ( desc.values{i});
         if (iscell (deps))
           for k = 1:length(deps)
             count++;
             table.name{count} = name;
             table.version{count} = version;
             table.package{count} = deps.package{k};
             table.operator{count} = deps.operator{k};
             table.dversion{count} = deps.version{k};
           endfor
         endif
      endif
   endfor
endfunction

function ret = check_dependency_table (table, packages)
   for i = 1:length(table.name)
      name = table.name{i};
      version = table.version{i};
      package = table.package{i};
      operator = table.operator{i};
      dversion = table.dversion{i};
      found = false;
      for j = 1:length(packages.name)
         if (strcmp (packages.name{j}, package) &&
             (compare_versions(packages.version{j}, dversion, operator)))
           found = true;
           break;  
         endif
      endfor
      if (! found)
         error ("missing dependency");
      endif
   endfor
endfunction

where packages in the function check_dependency_table is the list of
packages that will be installed after the current operation is finished,
and has the same form as installed_packages in the existing code.

Ok, none of the above code is checked as I wrote it straight into my
e-mail client, but at least it gives an idea of what I'm thinking
about.. Including allowing cell-arrays to install/uninstall, it
addresses the issues of circular dependencies and dependencies on
uninstalling...

Cheers
D.

--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

Stéfan van der Walt
On Wed, Jun 22, 2005 at 12:30:49PM +0200, David Bateman wrote:

>
> Also, only checks against the installed packages are performed.. What I
> see as an extention is to create a complete dependency table of all of
> the installed packages, with a function like
>
> function dependency_table = installed_dependencies (prefix,
> installed_packages)
>  count = 0;
>  for i = 1:length(installed_packages.name)
>    desc = get_description ([prefix, installed_packages.name{i}]);
>    verify_description (desc);
>    for j = 1:length(desc.keywords)
>      if (strcmp(desc.keywords{j}, "DEPENDS"))
>         deps = parse_dependencies ( desc.values{i});
>         if (iscell (deps))
>           for k = 1:length(deps)
>              count++;
>              dependency_table.name{count} = installed_packages.name{i};
>              dependency_table.version{count} =
> installed_packages.version{i};
>              dependency_table.package{count} = deps.package{k};
>              dependency_table.operator{count} = deps.operator{k};
>              dependency_table.dversion{count} = deps.version{k};
>         endif
>      endif
>    endfor
>  endfor
> endfunction

I like your idea.  Wouldn't it be easier to implement it as some sort
of tree structure, instead of a flat one?  Unfortunately, we don't
have python's dictionaries, but maybe we can do something similar in
Octave like

function [value, idx] = search(dict, key)
    value = [];
    for idx = 1:rows(dict)
        if strcmp(dict(idx,1), key)
            value = dict{idx,2};
            return;
        endif
    endfor
    idx = 0;
endfunction

function d = dict(d, key, new_value)
    if (nargin == 0)
        d = cell(0,2);
        return
    endif

    [value, idx] = search(d, key);
    if (idx == 0)
        idx = rows(d)+1;
    endif
   
    d(idx, 1) = key;
    d(idx, 2) = new_value;
   
endfunction


> then have three other function, one to remove a package, one to add a
> package to the table and another to validate the dependency table,
> like

...

> Ok, none of the above code is checked as I wrote it straight into my
> e-mail client, but at least it gives an idea of what I'm thinking
> about.. Including allowing cell-arrays to install/uninstall, it
> addresses the issues of circular dependencies and dependencies on
> uninstalling...

Fortunately, the inmind-Octave-parser is pretty flexible :)

Regards
Stéfan

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

Søren Hauberg
In reply to this post by David Bateman-3
David Bateman wrote:
[snip]

>> I think Søren implemented something like this already, since his
>> sample package contains the following line:
>>
>> Depends: octave (>= 2.1.64)
>>
> Yes, he has I see that now. However, the syntax is
>
> Depends: octave (>= 2.1.64), signal ( >= 1.0.0), signal (< 2.0.0)
>
> all on a single depends line. Multiple Depends lines would be nice to
> have.. with a function like
You should be able to create a continuation line (I don't think this
word exist), that is if a line starts with a blank char (as defined by
isspace) it is appended to the previous line. So

Depends: octave (>= 2.1.64), signal ( >= 1.0.0), signal (< 2.0.0)

should be the same as

Depends: octave (>= 2.1.64),
          signal ( >= 1.0.0),
          signal (< 2.0.0)

Is that good enough?

/Søren

P.S. I'm about to take a couple of days off, so I don't have time to
read/comment your code, but I will next week. Thanks

>
> function deps = desc_get_deps (desc)
>    first = true;
>    deps = "";
>    for i = 1:length(desc.keywords)
>        if (strcmp(desc.keywords{i}, "DEPENDS"))
>          if (first)
>             deps = desc.values{i};
>          else
>             deps = [deps, ",", desc.values{i}];
>          endif
>        endif
>    endfor
> endfunction
>
> Also, only checks against the installed packages are performed.. What I
> see as an extention is to create a complete dependency table of all of
> the installed packages, with a function like
>
> function dependency_table = installed_dependencies (prefix,
> installed_packages)
>  count = 0;
>  for i = 1:length(installed_packages.name)
>    desc = get_description ([prefix, installed_packages.name{i}]);
>    verify_description (desc);
>    for j = 1:length(desc.keywords)
>      if (strcmp(desc.keywords{j}, "DEPENDS"))
>         deps = parse_dependencies ( desc.values{i});
>         if (iscell (deps))
>           for k = 1:length(deps)
>              count++;
>              dependency_table.name{count} = installed_packages.name{i};
>              dependency_table.version{count} =
> installed_packages.version{i};
>              dependency_table.package{count} = deps.package{k};
>              dependency_table.operator{count} = deps.operator{k};
>              dependency_table.dversion{count} = deps.version{k};
>         endif
>      endif
>    endfor
>  endfor
> endfunction
>
> function pdep = parse_dependencies (deps)
>    deps = split_by(tolower(deps), ",");
>
>    if (length(deps) < 1)
>       pdeps = false;
>       return;
>    endif
>
>    ## For each dependency
>    for i = 1:length(deps)
>        dep = deps{i};
>        lpar = find(dep == "(");
>        rpar = find(dep == ")");
>        ## Does the dependency specify a version
>        ## Example: package(>= version)
>        if (length(lpar) == 1 && length(rpar) == 1)
>            package = tolower(strip(dep(1:lpar-1)));
>            sub = dep( lpar(1)+1:rpar(1)-1 );
>            parts = split_by(sub, " ");
>            idx = [];
>            for r = 1:size(parts,1)
>                if (length(parts{r}) > 0)
>                    idx(end+1) = r;
>                endif
>            endfor
>                       if (length(idx) != 2)
>                error(["There's something wrong with the DESCRIPTION
> file. " ...
>                       "The dependency %s has the wrong syntax.\n"], dep);
>            endif
>            operator = parts{idx(1)};
>            version  = fix_version(parts{idx(2)});
>                   ## If no version is specified for the dependcy
>        ## we say that the version should be greater than
>        ## or equal to 0.0.0
>        else
>            pdep.package{i} = tolower(strip(dep));
>            pdep.operator{i} = ">=";
>            pdep.version{i}  = "0.0.0";
>        endif
>     endfor
> endfunction
>
> then have three other function, one to remove a package, one to add a
> package to the table and another to validate the dependency table, like
>
> function new_table = delete_dependency (table, name)
>   count = 0;
>   for i = 1:length(table.name)
>      if (table.name{i} != name)
>         count++;
>         new_table.name{count} = table.name{i};
>         new_table.version{count} = table.version{i};
>         new_table.package{count} = table.package{i};
>         new_table.operator{count} = table.operator{i};
>         new_table.dversion{count} = table.dversion{i};
>       endif
>    endfor
>
>    if (count == 0)
>      new_table = false;
>    endif
> endfunction
>
> function table = add_dependency (table, name, version, desc)
>    count = length (table.name);
>    for j = 1:length(desc.keywords)
>      if (strcmp(desc.keywords{j}, "DEPENDS"))
>         deps = parse_dependencies ( desc.values{i});
>         if (iscell (deps))
>           for k = 1:length(deps)
>             count++;
>             table.name{count} = name;
>             table.version{count} = version;
>             table.package{count} = deps.package{k};
>             table.operator{count} = deps.operator{k};
>             table.dversion{count} = deps.version{k};
>           endfor
>         endif
>      endif
>   endfor
> endfunction
>
> function ret = check_dependency_table (table, packages)
>   for i = 1:length(table.name)
>      name = table.name{i};
>      version = table.version{i};
>      package = table.package{i};
>      operator = table.operator{i};
>      dversion = table.dversion{i};
>      found = false;
>      for j = 1:length(packages.name)
>         if (strcmp (packages.name{j}, package) &&
>             (compare_versions(packages.version{j}, dversion, operator)))
>           found = true;
>           break;           endif
>      endfor
>      if (! found)
>         error ("missing dependency");
>      endif
>   endfor
> endfunction
>
> where packages in the function check_dependency_table is the list of
> packages that will be installed after the current operation is finished,
> and has the same form as installed_packages in the existing code.
>
> Ok, none of the above code is checked as I wrote it straight into my
> e-mail client, but at least it gives an idea of what I'm thinking
> about.. Including allowing cell-arrays to install/uninstall, it
> addresses the issues of circular dependencies and dependencies on
> uninstalling...
>
> Cheers
> D.
>

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

David Bateman-3
Søren Hauberg wrote:

> David Bateman wrote:
> [snip]
>
>>> I think Søren implemented something like this already, since his
>>> sample package contains the following line:
>>>
>>> Depends: octave (>= 2.1.64)
>>>
>> Yes, he has I see that now. However, the syntax is
>>
>> Depends: octave (>= 2.1.64), signal ( >= 1.0.0), signal (< 2.0.0)
>>
>> all on a single depends line. Multiple Depends lines would be nice to
>> have.. with a function like
>
> You should be able to create a continuation line (I don't think this
> word exist), that is if a line starts with a blank char (as defined by
> isspace) it is appended to the previous line. So
>
> Depends: octave (>= 2.1.64), signal ( >= 1.0.0), signal (< 2.0.0)
>
> should be the same as
>
> Depends: octave (>= 2.1.64),
>          signal ( >= 1.0.0),
>          signal (< 2.0.0)


Ok, I see. I'd though desc_get took the file line by line, but
get_descriptions parsing the description including continuation lines...
That is fine..

D.

--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

David Bateman-3
In reply to this post by Stéfan van der Walt
Stefan van der Walt wrote:

>I like your idea.  Wouldn't it be easier to implement it as some sort
>of tree structure, instead of a flat one?  Unfortunately, we don't
>have python's dictionaries, but maybe we can do something similar in
>Octave like
>
>function [value, idx] = search(dict, key)
>    value = [];
>    for idx = 1:rows(dict)
> if strcmp(dict(idx,1), key)
>    value = dict{idx,2};
>    return;
> endif
>    endfor
>    idx = 0;
>endfunction
>
>function d = dict(d, key, new_value)
>    if (nargin == 0)
> d = cell(0,2);
> return
>    endif
>
>    [value, idx] = search(d, key);
>    if (idx == 0)
> idx = rows(d)+1;
>    endif
>    
>    d(idx, 1) = key;
>    d(idx, 2) = new_value;
>    
>endfunction
>
>  
>
Which dict is which? You use dict as a function and a variable.... Do we
need the complexity of a tree structure for dependency check. I thought
the interest of that was to reduce the amount of work required in
checking the dependencies. This makes sense in a linux distribution with
a large number of installed packages, but will octave really ever have
more than a 100 or so packages installed at any time. So the flat
structure might be easier to get running and maintained initially.

In any case, its an internal implementation issue of how the full
dependency table is kept. If we run into performance problems, we can
always switch to a dependency tree in the future with no visible effect
on the user as long as the DESCRIPTION file format supports it..

Cheers
David

>  
>
>>then have three other function, one to remove a package, one to add a
>>package to the table and another to validate the dependency table,
>>like
>>    
>>
>
>...
>
>  
>
>>Ok, none of the above code is checked as I wrote it straight into my
>>e-mail client, but at least it gives an idea of what I'm thinking
>>about.. Including allowing cell-arrays to install/uninstall, it
>>addresses the issues of circular dependencies and dependencies on
>>uninstalling...
>>    
>>
>
>Fortunately, the inmind-Octave-parser is pretty flexible :)
>
>Regards
>Stéfan
>
>  
>


--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

Bill Denney
On Wed, 22 Jun 2005, David Bateman wrote:

> Do we need the complexity of a tree structure for dependency check. I
> thought the interest of that was to reduce the amount of work required
> in checking the dependencies. This makes sense in a linux distribution
> with a large number of installed packages, but will octave really ever
> have more than a 100 or so packages installed at any time. So the flat
> structure might be easier to get running and maintained initially.

I'm wary of any statement that would limit the numbers of anything.
Initially, I'd say that anything that can handle up to about 10k packages
within 3-5 seconds would be OK, but I'd want to be certain that the system
could handle lots of packages.

> In any case, its an internal implementation issue of how the full
> dependency table is kept. If we run into performance problems, we can
> always switch to a dependency tree in the future with no visible effect
> on the user as long as the DESCRIPTION file format supports it..

As long as there's not a user visible (including package maintainers)
change if it is necessary to change to a different dependency checking
routine, I think it'd be fine to do it any way that works.  This seems
like something that's been solved many times before, though.  Can we not
just grab apt-get (or some other program) and use their dependency
checking routines?

Bill

--
"I usually read the obituaries first as there is always the happy chance
that one of them will make my day."
   -- Dr. Richard Ames, _The Cat Who Walks Through Walls_

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

Stéfan van der Walt
In reply to this post by David Bateman-3
On Wed, Jun 22, 2005 at 02:15:24PM +0200, David Bateman wrote:

> Stefan van der Walt wrote:
>
> >I like your idea.  Wouldn't it be easier to implement it as some sort
> >of tree structure, instead of a flat one?  Unfortunately, we don't
> >have python's dictionaries, but maybe we can do something similar in
> >Octave like
> >
> >function [value, idx] = search(dict, key)
> >   value = [];
> >   for idx = 1:rows(dict)
> > if strcmp(dict(idx,1), key)
> >    value = dict{idx,2};
> >    return;
> > endif
> >   endfor
> >   idx = 0;
> >endfunction
> >
> >function d = dict(d, key, new_value)
> >   if (nargin == 0)
> > d = cell(0,2);
> > return
> >   endif
> >
> >   [value, idx] = search(d, key);
> >   if (idx == 0)
> > idx = rows(d)+1;
> >   endif
> >  
> >   d(idx, 1) = key;
> >   d(idx, 2) = new_value;
> >  
> >endfunction
> >
> >
> >
> Which dict is which? You use dict as a function and a variable.... Do we

You can just rename `Dict: The Function' to set_dict or whatever.
Hey, it parses :)

> need the complexity of a tree structure for dependency check. I thought
> the interest of that was to reduce the amount of work required in

I think Bill is right -- we don't need to reinvent the wheel twice.
Finding an efficient transportable C++ implementation might not be so
easy though -- I'll take a look.  As you say, anything that gets the
job done is good for now.

Cheers
Stéfan

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

Stéfan van der Walt
In reply to this post by Bill Denney
On Wed, Jun 22, 2005 at 12:09:24PM -0400, Bill Denney wrote:
> routine, I think it'd be fine to do it any way that works.  This seems
> like something that's been solved many times before, though.  Can we not
> just grab apt-get (or some other program) and use their dependency
> checking routines?

Here is a link to the Boost C++ Graph-library:

http://www.boost.org/libs/graph/doc/table_of_contents.html

It is probably overkill though...

Regards
Stéfan

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

Søren Hauberg
In reply to this post by David Bateman-3
David Bateman wrote:
Hi,
I'm back from my short vacation and I've had a look at your code. I've
altered a bit in the way descriptions are represented (the change was
from a struct containing cells to a cell containing structs) and I've
adapted your code to this change (although I've made a dirty hack
because I was lazy).

The current code supports
*) the installation of multible packages with one function call (i.e.
the package files are given as a cell array).
*) Dependency checking at uninstall time
*) Circular dependecies (I think)

It does have one problem. If multible packages are installed with one
function call the order of the installation is sortof random. So if
package A depends on package B at install time, package A might be
installed before package B, which would yield an error. Am I making sense?

As always the source is at http://hauberg.org/octave-package/package.tgz

/Søren

> Also, only checks against the installed packages are performed.. What I
> see as an extention is to create a complete dependency table of all of
> the installed packages, with a function like
>
> function dependency_table = installed_dependencies (prefix,
> installed_packages)
>  count = 0;
>  for i = 1:length(installed_packages.name)
>    desc = get_description ([prefix, installed_packages.name{i}]);
>    verify_description (desc);
>    for j = 1:length(desc.keywords)
>      if (strcmp(desc.keywords{j}, "DEPENDS"))
>         deps = parse_dependencies ( desc.values{i});
>         if (iscell (deps))
>           for k = 1:length(deps)
>              count++;
>              dependency_table.name{count} = installed_packages.name{i};
>              dependency_table.version{count} =
> installed_packages.version{i};
>              dependency_table.package{count} = deps.package{k};
>              dependency_table.operator{count} = deps.operator{k};
>              dependency_table.dversion{count} = deps.version{k};
>         endif
>      endif
>    endfor
>  endfor
> endfunction
>
> function pdep = parse_dependencies (deps)
>    deps = split_by(tolower(deps), ",");
>
>    if (length(deps) < 1)
>       pdeps = false;
>       return;
>    endif
>
>    ## For each dependency
>    for i = 1:length(deps)
>        dep = deps{i};
>        lpar = find(dep == "(");
>        rpar = find(dep == ")");
>        ## Does the dependency specify a version
>        ## Example: package(>= version)
>        if (length(lpar) == 1 && length(rpar) == 1)
>            package = tolower(strip(dep(1:lpar-1)));
>            sub = dep( lpar(1)+1:rpar(1)-1 );
>            parts = split_by(sub, " ");
>            idx = [];
>            for r = 1:size(parts,1)
>                if (length(parts{r}) > 0)
>                    idx(end+1) = r;
>                endif
>            endfor
>                       if (length(idx) != 2)
>                error(["There's something wrong with the DESCRIPTION
> file. " ...
>                       "The dependency %s has the wrong syntax.\n"], dep);
>            endif
>            operator = parts{idx(1)};
>            version  = fix_version(parts{idx(2)});
>                   ## If no version is specified for the dependcy
>        ## we say that the version should be greater than
>        ## or equal to 0.0.0
>        else
>            pdep.package{i} = tolower(strip(dep));
>            pdep.operator{i} = ">=";
>            pdep.version{i}  = "0.0.0";
>        endif
>     endfor
> endfunction
>
> then have three other function, one to remove a package, one to add a
> package to the table and another to validate the dependency table, like
>
> function new_table = delete_dependency (table, name)
>   count = 0;
>   for i = 1:length(table.name)
>      if (table.name{i} != name)
>         count++;
>         new_table.name{count} = table.name{i};
>         new_table.version{count} = table.version{i};
>         new_table.package{count} = table.package{i};
>         new_table.operator{count} = table.operator{i};
>         new_table.dversion{count} = table.dversion{i};
>       endif
>    endfor
>
>    if (count == 0)
>      new_table = false;
>    endif
> endfunction
>
> function table = add_dependency (table, name, version, desc)
>    count = length (table.name);
>    for j = 1:length(desc.keywords)
>      if (strcmp(desc.keywords{j}, "DEPENDS"))
>         deps = parse_dependencies ( desc.values{i});
>         if (iscell (deps))
>           for k = 1:length(deps)
>             count++;
>             table.name{count} = name;
>             table.version{count} = version;
>             table.package{count} = deps.package{k};
>             table.operator{count} = deps.operator{k};
>             table.dversion{count} = deps.version{k};
>           endfor
>         endif
>      endif
>   endfor
> endfunction
>
> function ret = check_dependency_table (table, packages)
>   for i = 1:length(table.name)
>      name = table.name{i};
>      version = table.version{i};
>      package = table.package{i};
>      operator = table.operator{i};
>      dversion = table.dversion{i};
>      found = false;
>      for j = 1:length(packages.name)
>         if (strcmp (packages.name{j}, package) &&
>             (compare_versions(packages.version{j}, dversion, operator)))
>           found = true;
>           break;           endif
>      endfor
>      if (! found)
>         error ("missing dependency");
>      endif
>   endfor
> endfunction
>
> where packages in the function check_dependency_table is the list of
> packages that will be installed after the current operation is finished,
> and has the same form as installed_packages in the existing code.
>
> Ok, none of the above code is checked as I wrote it straight into my
> e-mail client, but at least it gives an idea of what I'm thinking
> about.. Including allowing cell-arrays to install/uninstall, it
> addresses the issues of circular dependencies and dependencies on
> uninstalling...
>
> Cheers
> D.
>

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

David Bateman-3
Søren Hauberg wrote:

> David Bateman wrote:
> Hi,
> I'm back from my short vacation and I've had a look at your code. I've
> altered a bit in the way descriptions are represented (the change was
> from a struct containing cells to a cell containing structs) and I've
> adapted your code to this change (although I've made a dirty hack
> because I was lazy).
>
> The current code supports
> *) the installation of multible packages with one function call (i.e.
> the package files are given as a cell array).
> *) Dependency checking at uninstall time
> *) Circular dependecies (I think)
>
> It does have one problem. If multible packages are installed with one
> function call the order of the installation is sortof random. So if
> package A depends on package B at install time, package A might be
> installed before package B, which would yield an error. Am I making
> sense?
>
> As always the source is at http://hauberg.org/octave-package/package.tgz
>
> /Søren

A couple of comments..

* uninstall.m doesn't take cell arrays and so you can have the problem
of circular dependencies on removal... Given the install code, in
shouldn't be too hard to get the same functionality there.
* I see no reason that you can't install over an existing package, as in
this case it is an upgrade. I'd first remove the existing version and
replace with the new version after the dependencies have been checked..

Cheers
David

--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary

Reply | Threaded
Open this post in threaded view
|

Re: packaging system

Søren Hauberg
Hi

David Bateman wrote:
> A couple of comments..
>
> * uninstall.m doesn't take cell arrays and so you can have the problem
> of circular dependencies on removal... Given the install code, in
> shouldn't be too hard to get the same functionality there.
Done. I simply forgot :-)

> * I see no reason that you can't install over an existing package, as in
> this case it is an upgrade. I'd first remove the existing version and
> replace with the new version after the dependencies have been checked..
Done (I think, I haven't tested things that much). A package will be
removed after it has been verified that the dependencies of the new
version is satisfied. If the installation of the new package fails, the
user will however not have the old or the new version installed.

> Cheers
> David
Thanks,
Søren

123