dep_selector 0.0.8 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -53,6 +53,7 @@ struct VersionProblemPool
53
53
  void DeleteAll();
54
54
  };
55
55
 
56
+ #define DEBUG_PREFIX_LENGTH 40
56
57
 
57
58
  class VersionProblem : public Space
58
59
  {
@@ -62,7 +63,11 @@ public:
62
63
  static const int MAX_TRUST_LEVEL;
63
64
  static const int MAX_PREFERRED_WEIGHT;
64
65
 
65
- VersionProblem(int packageCount, bool dumpStats = true, bool debug = false);
66
+ static int instance_counter;
67
+
68
+ VersionProblem(int packageCount, bool dumpStats = true,
69
+ bool debug = false,
70
+ const char * logId = 0);
66
71
  // Clone constructor; check gecode rules for this...
67
72
  VersionProblem(bool share, VersionProblem & s);
68
73
  virtual ~VersionProblem();
@@ -103,17 +108,20 @@ public:
103
108
  // Debug and utility functions
104
109
  void Print(std::ostream &out);
105
110
  void PrintPackageVar(std::ostream & out, int packageId) ;
111
+ const char * DebugPrefix() const { return debugPrefix; }
106
112
 
107
- static VersionProblem *InnerSolve(VersionProblem * problem, int & itercount);
113
+ static VersionProblem *InnerSolve(VersionProblem * problem, int & itercount);
108
114
  static VersionProblem *Solve(VersionProblem *problem);
109
-
110
115
 
111
116
  protected:
117
+ int instance_id;
112
118
  int size;
113
119
  int version_constraint_count;
114
120
  int cur_package;
115
121
  bool dump_stats;
116
- bool debug_logging;
122
+ bool debugLogging;
123
+ char debugPrefix[DEBUG_PREFIX_LENGTH];
124
+ char outputBuffer[1024];
117
125
  bool finalized;
118
126
 
119
127
  BoolVarArgs version_flags;
@@ -139,7 +147,7 @@ public:
139
147
  void AddPackagesPreferredToBeAtLatestObjectiveFunction(const VersionProblem & best_known_solution);
140
148
  void ConstrainVectorLessThanBest(IntVarArgs & current, IntVarArgs & best);
141
149
  void BuildCostVector(IntVarArgs & costVector) const;
142
-
150
+
143
151
  friend class VersionProblemPool;
144
152
  };
145
153
 
@@ -29,9 +29,10 @@
29
29
  // insure proper memory behaviour
30
30
 
31
31
  // FFI friendly
32
- VersionProblem * VersionProblemCreate(int packageCount, bool dump_stats, bool debug)
32
+ VersionProblem * VersionProblemCreate(int packageCount, bool dump_stats,
33
+ bool debug, const char * logId)
33
34
  {
34
- return new VersionProblem(packageCount, dump_stats, debug);
35
+ return new VersionProblem(packageCount, dump_stats, debug, logId);
35
36
  }
36
37
 
37
38
  void VersionProblemDestroy(VersionProblem * p)
@@ -31,7 +31,8 @@ extern "C" {
31
31
  typedef struct VersionProblem VersionProblem;
32
32
  #endif // __cplusplus
33
33
 
34
- VersionProblem * VersionProblemCreate(int packageCount, bool dumpStats, bool debug);
34
+ VersionProblem * VersionProblemCreate(int packageCount, bool dumpStats,
35
+ bool debug, const char * logId);
35
36
  void VersionProblemDestroy(VersionProblem * vp);
36
37
 
37
38
 
@@ -23,16 +23,34 @@
23
23
  # to work properly here.
24
24
  require 'mkmf'
25
25
 
26
- $LIBS << " -lstdc++"
27
-
28
26
  # $CFLAGS << "-g"
29
27
 
30
28
  gecode_installed =
31
- have_library('gecodesearch') &&
32
- have_library('gecodeint') &&
33
- have_library('gecodekernel') &&
29
+ # Gecode documentation notes:
30
+ # "Some linkers require the list of libraries to be sorted such that
31
+ # libraries appear before all libraries they depend on."
32
+ # http://www.gecode.org/doc-latest/MPG.pdf
33
+ #
34
+ # This appears to be true of the version of mingw that ships with Ruby 1.9.3.
35
+ # The correct order of `-l` flags according to the docs is:
36
+ #
37
+ # 1. -lgecodeflatzinc
38
+ # 2. -lgecodedriver
39
+ # 3. -lgecodegist
40
+ # 4. -lgecodesearch,
41
+ # 5. -lgecodeminimodel
42
+ # 6. -lgecodeset
43
+ # 7. -lgecodefloat
44
+ # 8. -lgecodeint
45
+ # 9. -lgecodekernel
46
+ # 10. -lgecodesupport
47
+ #
48
+ # Ruby `mkmf` will add `-l` flags in the _REVERSE_ order that they appear here.
34
49
  have_library('gecodesupport') &&
35
- have_library('gecodeminimodel')
50
+ have_library('gecodekernel') &&
51
+ have_library('gecodeint') &&
52
+ have_library('gecodeminimodel') &&
53
+ have_library('gecodesearch')
36
54
 
37
55
  unless gecode_installed
38
56
  STDERR.puts <<EOS
@@ -1,3 +1,3 @@
1
1
  module DepSelector
2
- VERSION = "0.0.8"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -26,6 +26,8 @@ require 'dep_selector/gecode_wrapper'
26
26
  module DepSelector
27
27
  class DependencyGraph
28
28
 
29
+ DebugOptionFile = "/tmp/DepSelectorDebugOn"
30
+
29
31
  attr_reader :packages
30
32
 
31
33
  def initialize
@@ -58,10 +60,11 @@ module DepSelector
58
60
  packages.map{ |name, pkg| pkg }
59
61
  end
60
62
 
63
+ debugFlag = DebugOptionFile && File::exists?(DebugOptionFile)
61
64
  # In addition to all the packages that the user specified,
62
65
  # there is a "ghost" package that contains the solution
63
66
  # constraints. See Selector#solve for more information.
64
- @gecode_wrapper = GecodeWrapper.new(packages_in_solve.size + 1)
67
+ @gecode_wrapper = GecodeWrapper.new(packages_in_solve.size + 1, debugFlag)
65
68
  packages_in_solve.each{ |pkg| pkg.generate_gecode_wrapper_constraints }
66
69
  end
67
70
  end
@@ -78,11 +78,15 @@ module DepSelector
78
78
 
79
79
  # determine all versions of curr_pkg that match
80
80
  # version_constraint and recurse into them
81
+ seen_dep_trees = {}
81
82
  curr_pkg[version_constraint].each do |curr_pkg_ver|
83
+ next if seen_dep_trees.has_key?(curr_pkg_ver.dependencies.to_s)
82
84
  curr_path.push(curr_pkg_ver)
83
85
  curr_pkg_ver.dependencies.each do |dep|
86
+ next if curr_pkg.name == dep.package.name
84
87
  paths_to_pkg(dep_graph, dep.package, dep.constraint, target_pkg, curr_path, all_paths)
85
88
  end
89
+ seen_dep_trees[curr_pkg_ver.dependencies.to_s] = true
86
90
  curr_path.pop
87
91
  end
88
92
  end
@@ -38,6 +38,11 @@ module DepSelector
38
38
  end
39
39
  end
40
40
 
41
+ class TimeBoundExceeded < StandardError
42
+ end
43
+ class TimeBoundExceededNoSolution < StandardError
44
+ end
45
+
41
46
  # This exception is thrown by gecode_wrapper and only used
42
47
  # internally
43
48
  class NoSolutionFound < StandardError
@@ -17,22 +17,25 @@
17
17
  # limitations under the License.
18
18
  #
19
19
 
20
+ require "uuidtools"
20
21
  require "dep_gecode"
21
22
  require 'dep_selector/exceptions'
22
23
 
23
24
  module DepSelector
24
25
  class GecodeWrapper
25
26
  attr_reader :gecode_problem
27
+ attr_reader :debug_logs_on
26
28
  DontCareConstraint = -1
27
29
  NoMatchConstraint = -2
28
30
  DumpStatistics = true
29
- DebugLogsOn = false
30
31
 
31
32
  # This insures that we properly deallocate the c++ class at the heart of dep_gecode.
32
33
  # modeled after http://www.mikeperham.com/2010/02/24/the-trouble-with-ruby-finalizers/
33
- def initialize(problem_or_package_count)
34
+ def initialize(problem_or_package_count, debug=false)
34
35
  if (problem_or_package_count.is_a?(Numeric))
35
- @gecode_problem = Dep_gecode.VersionProblemCreate(problem_or_package_count, DumpStatistics, DebugLogsOn)
36
+ logId = UUIDTools::UUID.random_create().to_str()
37
+ @debug_logs_on = debug
38
+ @gecode_problem = Dep_gecode.VersionProblemCreate(problem_or_package_count, DumpStatistics, debug, logId)
36
39
  else
37
40
  @gecode_problem = problem_or_package_count
38
41
  end
@@ -142,7 +145,7 @@ module DepSelector
142
145
 
143
146
  def solve()
144
147
  raise "Gecode internal failure (solve)" if gecode_problem.nil?
145
- solution = GecodeWrapper.new(Dep_gecode.Solve(gecode_problem))
148
+ solution = GecodeWrapper.new(Dep_gecode.Solve(gecode_problem), debug_logs_on)
146
149
  raise "Gecode internal failure (no solution found)" if (solution.nil?)
147
150
 
148
151
  raise Exceptions::NoSolutionFound.new(solution) if solution.package_disabled_count > 0
@@ -17,6 +17,7 @@
17
17
  # limitations under the License.
18
18
  #
19
19
 
20
+ require 'timeout'
20
21
  require 'dep_selector/dependency_graph'
21
22
  require 'dep_selector/exceptions'
22
23
  require 'dep_selector/error_reporter'
@@ -29,12 +30,13 @@ require 'dep_selector/error_reporter/simple_tree_traverser'
29
30
  # constraint that makes a solution impossible.
30
31
  module DepSelector
31
32
  class Selector
32
- attr_accessor :dep_graph, :error_reporter
33
+ attr_accessor :dep_graph, :error_reporter, :time_bound
33
34
 
34
35
  DEFAULT_ERROR_REPORTER = ErrorReporter::SimpleTreeTraverser.new
35
36
 
36
- def initialize(dep_graph, error_reporter = DEFAULT_ERROR_REPORTER)
37
+ def initialize(dep_graph, time_bound = 5, error_reporter = DEFAULT_ERROR_REPORTER)
37
38
  @dep_graph = dep_graph
39
+ @time_bound = time_bound
38
40
  @error_reporter = error_reporter
39
41
  end
40
42
 
@@ -65,8 +67,10 @@ module DepSelector
65
67
  packages_to_include_in_solve = trim_unreachable_packages(dep_graph, solution_constraints)
66
68
 
67
69
  begin
68
- # first, try to solve the whole set of constraints
69
- solve(dep_graph.clone, solution_constraints, valid_packages, packages_to_include_in_solve)
70
+ Timeout::timeout(@time_bound, Exceptions::TimeBoundExceeded) do
71
+ # first, try to solve the whole set of constraints
72
+ solve(dep_graph.clone, solution_constraints, valid_packages, packages_to_include_in_solve)
73
+ end
70
74
  rescue Exceptions::NoSolutionFound
71
75
  # since we're here, solving the whole system failed, so add
72
76
  # the solution_constraints one-by-one and try to solve in
@@ -79,48 +83,50 @@ module DepSelector
79
83
  # iteratively add and solve in order to re-use
80
84
  # propagations. This will require separating setting up the
81
85
  # constraints from searching for the solution.
82
- solution_constraints.each_index do |idx|
83
- workspace = dep_graph.clone
84
- begin
85
- solve(workspace, solution_constraints[0..idx], valid_packages, packages_to_include_in_solve)
86
- rescue Exceptions::NoSolutionFound => nsf
87
- disabled_packages =
88
- packages_to_include_in_solve.inject([]) do |acc, elt|
86
+ Timeout::timeout(@time_bound, Exceptions::TimeBoundExceededNoSolution) do
87
+ solution_constraints.each_index do |idx|
88
+ workspace = dep_graph.clone
89
+ begin
90
+ solve(workspace, solution_constraints[0..idx], valid_packages, packages_to_include_in_solve)
91
+ rescue Exceptions::NoSolutionFound => nsf
92
+ disabled_packages =
93
+ packages_to_include_in_solve.inject([]) do |acc, elt|
89
94
  pkg = workspace.package(elt.name)
90
95
  acc << pkg if nsf.unsatisfiable_problem.is_package_disabled?(pkg.gecode_package_id)
91
96
  acc
92
97
  end
93
- # disambiguate between packages disabled becuase they
98
+ # disambiguate between packages disabled becuase they
94
99
  # don't exist and those that have otherwise problematic
95
- # constraints
96
- disabled_non_existent_packages = []
97
- disabled_most_constrained_packages = []
98
- disabled_packages.each do |disabled_pkg|
99
- disabled_collection =
100
- if disabled_pkg.valid? || (valid_packages && valid_packages.include?(disabled_pkg))
101
- disabled_most_constrained_packages
102
- else
103
- disabled_non_existent_packages
104
- end
105
- disabled_collection << disabled_pkg
100
+ # constraints
101
+ disabled_non_existent_packages = []
102
+ disabled_most_constrained_packages = []
103
+ disabled_packages.each do |disabled_pkg|
104
+ disabled_collection =
105
+ if disabled_pkg.valid? || (valid_packages && valid_packages.include?(disabled_pkg))
106
+ disabled_most_constrained_packages
107
+ else
108
+ disabled_non_existent_packages
109
+ end
110
+ disabled_collection << disabled_pkg
111
+ end
112
+
113
+ # Pick the first non-existent or most-constrained package
114
+ # that was required or the package whose constraints had
115
+ # to be disabled in order to find a solution and generate
116
+ # feedback for it. We only report feedback for one
117
+ # package, because it is in fact actionable and dispalying
118
+ # feedback for every disabled package would probably be
119
+ # too long. The full set of disabled packages is
120
+ # accessible in the NoSolutionExists exception.
121
+ disabled_package_to_report_on = disabled_non_existent_packages.first ||
122
+ disabled_most_constrained_packages.first
123
+ feedback = error_reporter.give_feedback(dep_graph, solution_constraints, idx,
124
+ disabled_package_to_report_on)
125
+
126
+ raise Exceptions::NoSolutionExists.new(feedback, solution_constraints[idx],
127
+ disabled_non_existent_packages,
128
+ disabled_most_constrained_packages)
106
129
  end
107
-
108
- # Pick the first non-existent or most-constrained package
109
- # that was required or the package whose constraints had
110
- # to be disabled in order to find a solution and generate
111
- # feedback for it. We only report feedback for one
112
- # package, because it is in fact actionable and dispalying
113
- # feedback for every disabled package would probably be
114
- # too long. The full set of disabled packages is
115
- # accessible in the NoSolutionExists exception.
116
- disabled_package_to_report_on = disabled_non_existent_packages.first ||
117
- disabled_most_constrained_packages.first
118
- feedback = error_reporter.give_feedback(dep_graph, solution_constraints, idx,
119
- disabled_package_to_report_on)
120
-
121
- raise Exceptions::NoSolutionExists.new(feedback, solution_constraints[idx],
122
- disabled_non_existent_packages,
123
- disabled_most_constrained_packages)
124
130
  end
125
131
  end
126
132
  end
metadata CHANGED
@@ -1,35 +1,68 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: dep_selector
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 8
9
- version: 0.0.8
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
10
5
  platform: ruby
11
- authors:
6
+ authors:
12
7
  - Christopher Walters
13
8
  - Mark Anderson
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-05-06 00:00:00 -07:00
19
- default_executable:
20
- dependencies: []
21
-
22
- description: Given packages, versions, and a dependency graph, find a valid assignment of package versions
23
- email:
12
+ date: 2014-03-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: uuidtools
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: '2.1'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: '2.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: '2.14'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: '2.14'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake-compiler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: 0.9.2
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 0.9.2
56
+ description: Given packages, versions, and a dependency graph, find a valid assignment
57
+ of package versions
58
+ email:
24
59
  - cw@opscode.com
25
60
  - mark@opscode.com
26
61
  executables: []
27
-
28
- extensions:
62
+ extensions:
29
63
  - ext/dep_gecode/extconf.rb
30
64
  extra_rdoc_files: []
31
-
32
- files:
65
+ files:
33
66
  - lib/dep_selector/densely_packed_set.rb
34
67
  - lib/dep_selector/dep_selector_version.rb
35
68
  - lib/dep_selector/dependency.rb
@@ -53,36 +86,31 @@ files:
53
86
  - ext/dep_gecode/dep_selector_to_gecode_interface.cpp
54
87
  - ext/dep_gecode/extconf.rb
55
88
  - ext/dep_gecode/lib/dep_selector_to_gecode.rb
56
- has_rdoc: false
57
89
  homepage: http://github.com/algorist/dep_selector
58
- licenses:
90
+ licenses:
59
91
  - Apache v2
92
+ metadata: {}
60
93
  post_install_message:
61
94
  rdoc_options: []
62
-
63
- require_paths:
95
+ require_paths:
64
96
  - lib
65
- required_ruby_version: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- segments:
70
- - 0
71
- version: "0"
72
- required_rubygems_version: !ruby/object:Gem::Requirement
73
- requirements:
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- segments:
77
- - 0
78
- version: "0"
79
- requirements:
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements:
80
108
  - gecode, version 3.5 or greater
81
109
  - g++
82
110
  rubyforge_project:
83
- rubygems_version: 1.3.6
111
+ rubygems_version: 2.0.3
84
112
  signing_key:
85
- specification_version: 3
86
- summary: Given packages, versions, and a dependency graph, find a valid assignment of package versions
113
+ specification_version: 4
114
+ summary: Given packages, versions, and a dependency graph, find a valid assignment
115
+ of package versions
87
116
  test_files: []
88
-