Mailinglist Archive: zypp-commit (171 mails)

< Previous Next >
[zypp-commit] <sat-solver> master : Handle SolutionElement
  • From: Klaus Kämpf <kkaempf@xxxxxxx>
  • Date: Tue, 23 Jun 2009 12:57:27 +0200
  • Message-id: <E1MJ3hw-0005wt-Hy@xxxxxxxxxxxxxxxx>
ref: refs/heads/master
commit 59872542a0e6cd2e02209a6db6157be0958fbd17
Author: Klaus Kämpf <kkaempf@xxxxxxx>
Date: Tue Jun 23 12:57:27 2009 +0200

Handle SolutionElement

This finalizes the transition from a zypp-ish problem/solution
handling to a satsolver-ish one.
---
applayer/problem.c | 45 ++---------------
applayer/solution.c | 103 ++++++++++++++++++++++++++++++++++++--
applayer/solution.h | 23 +++++++--
bindings/ruby/tests/job.rb | 44 ++++++++++++++++
bindings/ruby/tests/solutions.rb | 25 ++++++++-
bindings/solution.i | 54 +++++++++++++++++++-
6 files changed, 241 insertions(+), 53 deletions(-)

diff --git a/applayer/problem.c b/applayer/problem.c
index 514b69a..4fa209f 100644
--- a/applayer/problem.c
+++ b/applayer/problem.c
@@ -87,45 +87,10 @@ problem_solutions_iterate( Problem *problem, int
(*callback)( const Solution *s,

while ((solution = solver_next_solution( problem->solver, problem->id,
solution )) != 0)
{
- Id p, rp, element = 0;
-
-
- /* from src/problems.c:
- *
- * return the next item of the proposed solution
- * here are the possibilities for p / rp and what
- * the solver expects the application to do:
- * p rp
- * -------------------------------------------------------
- * SOLVER_SOLUTION_INFARCH pkgid
- * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
- *
- * SOLVER_SOLUTION_DISTUPGRADE pkgid
- * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
- *
- * SOLVER_SOLUTION_JOB jobidx
- * -> remove job (jobidx - 1, jobidx) from job queue
- *
- * pkgid (> 0) 0
- * -> add (SOLVER_ERASE|SOLVER_SOLVABLE, p) to the job
- *
- * pkgid (> 0) pkgid (> 0)
- * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
- * (this will replace package p)
- *
- * Thus, the solver will either ask the application to remove
- * a specific job from the job queue, or ask to add an install/erase
- * job to it.
- *
- */
-
- while ((element = solver_next_solutionelement( problem->solver,
problem->id, solution, element, &p, &rp)) != 0)
- {
- Solution *s = solution_new( problem, solution, p, rp );
- int result = callback( s, user_data );
- solution_free(s);
- if (result)
- break;
- }
+ Solution *s = solution_new( problem, solution );
+ int result = callback( s, user_data );
+ solution_free(s);
+ if (result)
+ break;
}
}
diff --git a/applayer/solution.c b/applayer/solution.c
index 5b83834..f4b7929 100644
--- a/applayer/solution.c
+++ b/applayer/solution.c
@@ -18,16 +18,14 @@
#include <stdlib.h>

#include "solution.h"
-
+#include "request.h"

Solution *
-solution_new( const Problem *problem, Id s, Id p, Id rp )
+solution_new( const Problem *problem, Id id )
{
Solution *solution = (Solution *)malloc( sizeof( Solution ));
solution->problem = problem;
- solution->s = s;
- solution->p = p;
- solution->rp = rp;
+ solution->id = id;
return solution;
}

@@ -37,3 +35,98 @@ solution_free( Solution *s )
{
free( s );
}
+
+SolutionElement *
+solutionelement_new( const Solution *solution, Id p, Id rp )
+{
+ SolutionElement *element = (SolutionElement *)malloc( sizeof(
SolutionElement ));
+ element->solution = solution;
+ element->p = p;
+ element->rp = rp;
+ return element;
+}
+
+
+void
+solutionelement_free( SolutionElement *se )
+{
+ free( se );
+}
+
+
+void
+solution_elements_iterate( const Solution *solution, int (*callback)( const
SolutionElement *se, void *user_data ), void *user_data )
+{
+ if (!callback) /* no use to iterate without callback */
+ return;
+
+ Id p, rp, element = 0;
+
+ while ((element = solver_next_solutionelement( solution->problem->solver,
solution->problem->id, solution->id, element, &p, &rp)) != 0)
+ {
+
+ /* from src/problems.c:
+ *
+ * return the next item of the proposed solution
+ * here are the possibilities for p / rp and what
+ * the solver expects the application to do:
+ * p rp
+ * -------------------------------------------------------
+ * SOLVER_SOLUTION_INFARCH pkgid
+ * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *
+ * SOLVER_SOLUTION_DISTUPGRADE pkgid
+ * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *
+ * SOLVER_SOLUTION_JOB jobidx
+ * -> remove job (jobidx - 1, jobidx) from job queue
+ *
+ * pkgid (> 0) 0
+ * -> add (SOLVER_ERASE|SOLVER_SOLVABLE, p) to the job
+ *
+ * pkgid (> 0) pkgid (> 0)
+ * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ * (this will replace package p)
+ *
+ * Thus, the solver will either ask the application to remove
+ * a specific job from the job queue, or ask to add an install/erase
+ * job to it.
+ *
+ */
+
+ SolutionElement *se = solutionelement_new( solution, p, rp );
+ int result = callback( se, user_data );
+ solutionelement_free(se);
+ if (result)
+ break;
+ }
+}
+
+
+int
+solutionelement_cause( const SolutionElement *se )
+{
+ if (se->p > 0)
+ return 0;
+ else
+ return se->p - 1;
+}
+
+
+Job *
+solutionelement_job( const SolutionElement *se )
+{
+ const Problem *problem = se->solution->problem;
+ Pool *pool = problem->solver->pool;
+
+ if (se->p == SOLVER_SOLUTION_INFARCH)
+ return job_new( pool, SOLVER_INSTALL|SOLVER_SOLVABLE, se->rp );
+ else if (se->p == SOLVER_SOLUTION_DISTUPGRADE)
+ return job_new( pool, SOLVER_INSTALL|SOLVER_SOLVABLE, se->rp );
+ else if (se->p == SOLVER_SOLUTION_JOB)
+ return request_job_get( problem->request, se->rp);
+ else if (se->rp == 0)
+ return job_new( pool, SOLVER_ERASE|SOLVER_SOLVABLE, se->p );
+ else
+ return job_new( pool, SOLVER_INSTALL|SOLVER_SOLVABLE, se->rp );
+}
diff --git a/applayer/solution.h b/applayer/solution.h
index 98fd943..8114cd1 100644
--- a/applayer/solution.h
+++ b/applayer/solution.h
@@ -23,13 +23,26 @@
#include "problem.h"

typedef struct _Solution {
- const Problem *problem;
- Id s; /* solution set id. */
- Id p;
- Id rp;
+ const Problem *problem; /* take solver and problem id from here */
+ Id id; /* solution set id. */
} Solution;

-Solution *solution_new( const Problem *problem, Id s, Id p, Id rp );
+Solution *solution_new( const Problem *problem, Id id );
void solution_free( Solution *s );
+const Problem *solution_problem( const Solution *s );
+
+
+typedef struct _SolutionElement {
+ const Solution *solution;
+ Id p;
+ Id rp;
+} SolutionElement;
+
+SolutionElement *solutionelement_new( const Solution *solution, Id p, Id rp );
+void solutionelement_free( SolutionElement *se );
+
+void solution_elements_iterate( const Solution *s, int (*callback)( const
SolutionElement *se, void *user_data ), void *user_data );
+int solutionelement_cause( const SolutionElement *se );
+Job *solutionelement_job( const SolutionElement *se );

#endif /* SATSOLVER_SOLUTION_H */
diff --git a/bindings/ruby/tests/job.rb b/bindings/ruby/tests/job.rb
new file mode 100644
index 0000000..57404f7
--- /dev/null
+++ b/bindings/ruby/tests/job.rb
@@ -0,0 +1,44 @@
+#
+# job.rb
+#
+
+module Satsolver
+ class Job
+ def to_s
+ case cmd
+ when INSTALL_SOLVABLE
+ "Install %s" % solvable
+ when UPDATE_SOLVABLE
+ "Update %s" % solvable
+ when REMOVE_SOLVABLE
+ "Remove %s" % solvable
+ when WEAKEN_SOLVABLE
+ "Weaken %s" % solvable
+ when LOCK_SOLVABLE
+ "Lock %s" % solvable
+ when INSTALL_SOLVABLE_NAME
+ "Install %s" % name
+ when UPDATE_SOLVABLE_NAME
+ "Update %s" % name
+ when REMOVE_SOLVABLE_NAME
+ "Remove %s" % name
+ when WEAKEN_SOLVABLE_NAME
+ "Weaken %s" % name
+ when LOCK_SOLVABLE_NAME
+ "Lock %s" % name
+ when INSTALL_SOLVABLE_PROVIDES
+ "Install %s" % relation
+ when UPDATE_SOLVABLE_PROVIDES
+ "Update %s" % relation
+ when REMOVE_SOLVABLE_PROVIDES
+ "Remove %s" % relation
+ when WEAKEN_SOLVABLE_PROVIDES
+ "Weaken %s" % relation
+ when LOCK_SOLVABLE_PROVIDES
+ "Lock %s" % relation
+ else
+ "Job cmd %s" % cmd
+ end
+ end
+ end
+end
diff --git a/bindings/ruby/tests/solutions.rb b/bindings/ruby/tests/solutions.rb
index 7c3f68a..0dbead3 100644
--- a/bindings/ruby/tests/solutions.rb
+++ b/bindings/ruby/tests/solutions.rb
@@ -11,6 +11,8 @@ require 'pathname'
# test Solutions
require 'test/unit'
require 'satsolver'
+require 'ruleinfo'
+require 'job'

class SolutionTest < Test::Unit::TestCase
def test_solutions
@@ -37,7 +39,7 @@ class SolutionTest < Test::Unit::TestCase
assert solv2

solv3 = repo.create_solvable( 'CC', '3.3-0' )
-# solv3.requires << Satsolver::Relation.new( pool, "Z" )
+ solv3.requires << Satsolver::Relation.new( pool, "Z" )
repo.create_solvable( 'DD', '4.4-0' )


@@ -52,6 +54,25 @@ class SolutionTest < Test::Unit::TestCase
solver.solve( request )
assert solver.problems?
puts "Problems found"
- i = 0
+ solver.each_problem(request) do |problem|
+ puts "Problem"
+ problem.each_solution do |solution|
+ puts " Solution"
+ solution.each_element do |element|
+ case element.cause
+ when Satsolver::SOLUTION_SOLVABLE
+ puts " Solvable : #{element.job}"
+ when Satsolver::SOLUTION_JOB
+ puts " Bad job : #{element.job}"
+ when Satsolver::SOLUTION_DISTUPGRADE
+ puts " Upgrade : #{element.job}"
+ when Satsolver::SOLUTION_INFARCH
+ puts " Architecture : #{element.job}"
+ else
+ puts " Unknown : #{element.job}"
+ end
+ end
+ end
+ end
end
end
diff --git a/bindings/solution.i b/bindings/solution.i
index 508b23a..25df3cd 100644
--- a/bindings/solution.i
+++ b/bindings/solution.i
@@ -15,14 +15,66 @@
*
*/

+%{
+/*
+ * iterating over solution elements ('yield' in Ruby)
+ */
+
+static int
+solutionelement_iterate_callback(const SolutionElement *se, void *user_data)
+{
+#if defined(SWIGRUBY)
+ /* FIXME: how to pass 'break' back to the caller ? */
+ rb_yield( SWIG_NewPointerObj((void*)se, SWIGTYPE_p__SolutionElement, 0) );
+#endif
+ return 0;
+}
+
+%}
+
+
%nodefault _Solution;
%rename(Solution) _Solution;
typedef struct _Solution {} Solution;

+%nodefault _SolutionElement;
+%rename(SolutionElement) _SolutionElement;
+typedef struct _SolutionElement {} SolutionElement;
+

%extend Solution {
+ /* No explicit constructor, use Problem#each_solution */
~Solution()
{ solution_free ($self); }
-}
+ /*
+ * An iterator providing elements of the Solution
+ *
+ * call-seq:
+ * solution.each_element { |solution_element| ... }
+ *
+ */
+ void each_element()
+ { solution_elements_iterate( $self, solutionelement_iterate_callback, NULL
); }

+}

+%extend SolutionElement {
+ /* caused by missing/dispensable solvable */
+ %constant int SOLUTION_SOLVABLE = 0;
+ /* caused by bad job */
+ %constant int SOLUTION_JOB = SOLVER_SOLUTION_JOB-1;
+ /* caused by upgrade */
+ %constant int SOLUTION_DISTUPGRADE = SOLVER_SOLUTION_DISTUPGRADE-1;
+ /* caused by wrong/inferior architecture */
+ %constant int SOLUTION_INFARCH = SOLVER_SOLUTION_INFARCH-1;
+
+ /* No explicit constructor, use Soltion#each_element */
+ ~SolutionElement()
+ { solutionelement_free ($self); }
+
+ int cause()
+ { return solutionelement_cause( $self ); }
+
+ Job *job()
+ { return solutionelement_job( $self ); }
+}
--
To unsubscribe, e-mail: zypp-commit+unsubscribe@xxxxxxxxxxxx
For additional commands, e-mail: zypp-commit+help@xxxxxxxxxxxx

< Previous Next >
This Thread
  • No further messages