dep_selector 0.0.8 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
-