build-graph 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 77b51e210994a3c93e59ddebf8b3aead06b84c07
4
- data.tar.gz: 5a9ece86c313dbbf9a0ddd462cd18b10eed49ff5
3
+ metadata.gz: f429cca0a6fccf4d050a393c0a89e319c6eaadea
4
+ data.tar.gz: 5c6430d2aca1fcb6ef21cef6b1cad7bfa8514342
5
5
  SHA512:
6
- metadata.gz: afb78262e92072da8e29dce01898447246e7f718a65b4c5f25a79f049fb9474a0fa21a1685758c11720d0f7cbc1b4c7ee328845da1adaf52a67b860da261c69d
7
- data.tar.gz: 4395c36481c93ada46363d602f34e136d9a8759e1022a3f669e97abe05f957ec7b2cab09fe81b06c38f7b796c5baf3a3261b5cb4ebca9e55d9e134f837479e4d
6
+ metadata.gz: 577cd4e1940d0a819ed599f2ed9950a52db4b7bfcc0031f411cc4f2c40bd9d7624294d33a1ab56f18c6eb73abf1ab59fc6a6ab7c264fcbaecc4c28cb49d77702
7
+ data.tar.gz: a1aba82f3d79dc93a0fe93720208005ece5f89c0a2b194000a225dd1c42536f2b11d4c65f04c63144d9929b3b0cbf2f9b418568f11d7bc2b2d734ccf2bc230a1
data/.travis.yml CHANGED
@@ -2,3 +2,10 @@ language: ruby
2
2
  rvm:
3
3
  - "2.0"
4
4
  - "2.1"
5
+ before_install:
6
+ # libstdc++-4.8-dev
7
+ - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
8
+ # clang++-3.2
9
+ - sudo add-apt-repository --yes ppa:h-rayflood/llvm
10
+ - sudo apt-get -qq update
11
+ - sudo apt-get -qq install libstdc++-4.8-dev clang-3.3
data/README.md CHANGED
@@ -19,10 +19,6 @@ Or install it yourself as:
19
19
 
20
20
  $ gem install build-graph
21
21
 
22
- ### Naming
23
-
24
- I'd like to call this gem, simply, `build`, but this name is not available.
25
-
26
22
  ## Usage
27
23
 
28
24
  TODO: Write usage instructions here
data/Rakefile CHANGED
@@ -1,9 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
- require "rake/testtask"
2
+ require "rspec/core/rake_task"
3
3
 
4
- Rake::TestTask.new do |t|
5
- t.libs << 'test'
6
- end
4
+ RSpec::Core::RakeTask.new(:spec)
7
5
 
8
- desc "Run tests"
9
- task :default => :test
6
+ task :default => :spec
data/build-graph.gemspec CHANGED
@@ -1,11 +1,11 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'build/version'
4
+ require 'build/graph/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "build-graph"
8
- spec.version = Build::VERSION
8
+ spec.version = Build::Graph::VERSION
9
9
  spec.authors = ["Samuel Williams"]
10
10
  spec.email = ["samuel.williams@oriontransfer.co.nz"]
11
11
  spec.summary = %q{Build::Graph is a framework for build systems, with specific functionality for dealing with file based processes.}
@@ -20,11 +20,14 @@ Gem::Specification.new do |spec|
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_dependency "process-group", "~> 0.1.0"
24
-
23
+ spec.add_dependency "process-group", "~> 0.2.1"
24
+ spec.add_dependency "build-files", "~> 0.1.0"
25
+ spec.add_dependency "build-makefile", "~> 0.1.0"
26
+
25
27
  spec.add_dependency "system"
26
- spec.add_dependency "rainbow"
28
+ spec.add_dependency "rainbow", "~> 2.0.0"
27
29
 
28
30
  spec.add_development_dependency "bundler", "~> 1.3"
31
+ spec.add_development_dependency "rspec", "~> 3.0.0.rc1"
29
32
  spec.add_development_dependency "rake"
30
33
  end
data/lib/build/graph.rb CHANGED
@@ -1,74 +1,26 @@
1
+ # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
1
20
 
2
- require 'build/files/monitor'
3
-
4
- require 'build/error'
5
- require 'build/node'
6
- require 'build/walker'
7
- require 'build/edge'
21
+ require_relative 'graph/controller'
8
22
 
9
23
  module Build
10
- class Graph < Files::Monitor
11
- def initialize
12
- super
13
-
14
- @nodes = {}
15
-
16
- build_graph!
17
- end
18
-
19
- attr :nodes
20
-
21
- # You need to override this to traverse the top nodes as required:
22
- def traverse!(walker)
23
- #Array(top).each do |node|
24
- # node.update!(walker)
25
- #end
26
- end
27
-
28
- def walk(&block)
29
- Walker.new(self, &block)
30
- end
31
-
32
- def build_graph!
33
- # We build the graph without doing any actual execution:
34
- nodes = []
35
-
36
- walker = walk do |walker, node|
37
- nodes << node
38
-
39
- yield walker, node
40
- end
41
-
42
- traverse! walker
43
-
44
- # We should update the status of all nodes in the graph once we've traversed the graph.
45
- nodes.each do |node|
46
- node.update_status!
47
- end
48
- end
49
-
50
- def update_with_log
51
- puts Rainbow("*** Graph update traversal ***").green
52
-
53
- start_time = Time.now
54
-
55
- walker = update!
56
- ensure
57
- end_time = Time.now
58
- elapsed_time = end_time - start_time
59
-
60
- $stdout.flush
61
- $stderr.puts Rainbow("Graph Update Time: %0.3fs" % elapsed_time).magenta
62
- end
63
-
64
- def update!
65
- walker = walk do |walker, node|
66
- yield walker, node
67
- end
68
-
69
- traverse! walker
70
-
71
- return walker
72
- end
24
+ module Graph
73
25
  end
74
26
  end
@@ -0,0 +1,95 @@
1
+ # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'build/files/monitor'
22
+
23
+ require_relative 'error'
24
+ require_relative 'node'
25
+ require_relative 'walker'
26
+ require_relative 'edge'
27
+
28
+ module Build
29
+ module Graph
30
+ class Controller < Files::Monitor
31
+ def initialize
32
+ super
33
+
34
+ @nodes = {}
35
+
36
+ build_graph!
37
+ end
38
+
39
+ attr :nodes
40
+
41
+ # You need to override this to traverse the top nodes as required:
42
+ def traverse!(walker)
43
+ #Array(top).each do |node|
44
+ # node.update!(walker)
45
+ #end
46
+ end
47
+
48
+ def walk(&block)
49
+ Walker.new(self, &block)
50
+ end
51
+
52
+ def build_graph!
53
+ # We build the graph without doing any actual execution:
54
+ nodes = []
55
+
56
+ walker = walk do |walker, node|
57
+ nodes << node
58
+
59
+ yield walker, node
60
+ end
61
+
62
+ traverse! walker
63
+
64
+ # We should update the status of all nodes in the graph once we've traversed the graph.
65
+ nodes.each do |node|
66
+ node.update_status!
67
+ end
68
+ end
69
+
70
+ def update_with_log
71
+ puts Rainbow("*** Graph update traversal ***").green
72
+
73
+ start_time = Time.now
74
+
75
+ walker = update!
76
+ ensure
77
+ end_time = Time.now
78
+ elapsed_time = end_time - start_time
79
+
80
+ $stdout.flush
81
+ $stderr.puts Rainbow("Graph Update Time: %0.3fs" % elapsed_time).magenta
82
+ end
83
+
84
+ def update!
85
+ walker = walk do |walker, node|
86
+ yield walker, node
87
+ end
88
+
89
+ traverse! walker
90
+
91
+ return walker
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,70 @@
1
+ # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'error'
22
+
23
+ module Build
24
+ module Graph
25
+ # Represents an input to a graph node, with count inputs.
26
+ class Edge
27
+ def initialize(count = 0)
28
+ @fiber = Fiber.current
29
+ @count = count
30
+
31
+ @failed = []
32
+ end
33
+
34
+ attr :failed
35
+
36
+ attr :fiber
37
+ attr :count
38
+
39
+ def wait
40
+ if @count > 0
41
+ Fiber.yield
42
+ end
43
+
44
+ failed?
45
+ end
46
+
47
+ attr :failed
48
+
49
+ def failed?
50
+ @failed.size != 0
51
+ end
52
+
53
+ def traverse(node)
54
+ @count -= 1
55
+
56
+ if node.failed?
57
+ @failed << node
58
+ end
59
+
60
+ if @count == 0
61
+ @fiber.resume
62
+ end
63
+ end
64
+
65
+ def increment!
66
+ @count += 1
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Build
22
+ class TransientError < StandardError
23
+ end
24
+
25
+ class CommandFailure < TransientError
26
+ def initialize(command, status)
27
+ super "Command #{command.inspect} failed with exit status #{status}!"
28
+
29
+ @command = command
30
+ @status = status
31
+ end
32
+
33
+ attr :command
34
+ attr :status
35
+ end
36
+ end
@@ -0,0 +1,156 @@
1
+ # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'build/files/state'
22
+
23
+ module Build
24
+ module Graph
25
+ class Node
26
+ def initialize(controller, inputs, outputs)
27
+ @controller = controller
28
+
29
+ @state = Files::IOState.new(inputs, outputs)
30
+
31
+ @status = :unknown
32
+ @fiber = nil
33
+
34
+ # These are immutable - rather than change them, create a new node:
35
+ @inputs = inputs
36
+ @outputs = outputs
37
+
38
+ @controller.add(self)
39
+ end
40
+
41
+ def eql?(other)
42
+ other.kind_of?(self.class) and @inputs.eql?(other.inputs) and @outputs.eql?(other.outputs)
43
+ end
44
+
45
+ def hash
46
+ [@inputs, @outputs].hash
47
+ end
48
+
49
+ def directories
50
+ @state.files.roots
51
+ end
52
+
53
+ def remove!
54
+ @controller.delete(self)
55
+ end
56
+
57
+ # It is possible this function is called unnecessarily. The state check confirms whether a change occurred or not.
58
+ def changed!(outputs = [])
59
+ # Don't do anything if we are already dirty.
60
+ return if dirty?
61
+
62
+ if @state.intersects?(outputs) || @state.update!
63
+ # puts "** Dirty: #{@inputs.to_a.inspect} -> #{@outputs.to_a.inspect}"
64
+
65
+ # Could possibly use unknown status here.
66
+ @status = :dirty
67
+
68
+ # If this node changes, we force all other nodes which depend on this node to be dirty.
69
+ @controller.update(directories, @outputs)
70
+ end
71
+ end
72
+
73
+ attr :inputs
74
+ attr :outputs
75
+
76
+ attr :state
77
+ attr :status
78
+
79
+ def unknown?
80
+ @status == :unknown
81
+ end
82
+
83
+ def dirty?
84
+ @status == :dirty
85
+ end
86
+
87
+ def clean?
88
+ @status == :clean
89
+ end
90
+
91
+ def clean!
92
+ @status = :clean
93
+ end
94
+
95
+ def fail!
96
+ @status = :failed
97
+ end
98
+
99
+ def failed?
100
+ @status == :failed
101
+ end
102
+
103
+ def updating?
104
+ @fiber != nil
105
+ end
106
+
107
+ # If we are in the initial state, we need to check if the outputs are fresh.
108
+ def update_status!
109
+ #puts "Update status: #{@inputs.inspect} -> #{@outputs.inspect} (status=#{@status} @fiber=#{@fiber.inspect}) @status=#{@status} @state.fresh?=#{@state.fresh?}"
110
+
111
+ if @status == :unknown
112
+ # This could be improved - only stale files should be reported, instead we report all.
113
+ unless @state.fresh?
114
+ changed!(self.inputs)
115
+ else
116
+ @status = :clean
117
+ end
118
+ end
119
+ end
120
+
121
+ def inspect
122
+ "<#{dirty? ? '*' : ''}inputs=#{inputs.inspect} outputs=#{outputs.inspect} fiber=#{@fiber.inspect} fresh=#{@state.fresh?}>"
123
+ end
124
+
125
+ def requires_update?
126
+ not clean?
127
+ end
128
+
129
+ # Perform some actions to update this node, returns when completed, and the node is no longer dirty.
130
+ def update!(walker)
131
+ #puts "Walking #{@inputs.to_a.inspect} -> #{@outputs.to_a.inspect} (dirty=#{dirty?} @fiber=#{@fiber.inspect})"
132
+
133
+ # If a fiber already exists, this node is in the process of updating.
134
+ if requires_update? and @fiber == nil
135
+ # puts "Beginning: #{@inputs.to_a.inspect} -> #{@outputs.to_a.inspect}"
136
+
137
+ @fiber = Fiber.new do
138
+ task = walker.task(self)
139
+
140
+ task.visit
141
+
142
+ # Commit changes:
143
+ # puts "** Committing: #{@inputs.to_a.inspect} -> #{@outputs.to_a.inspect}"
144
+
145
+ @state.update!
146
+ @fiber = nil
147
+
148
+ task.exit
149
+ end
150
+
151
+ @fiber.resume
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end