dake 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/dake.gemspec +1 -0
- data/examples/Dakefile +40 -0
- data/exe/dake +39 -13
- data/lib/dake/analyzer.rb +3 -15
- data/lib/dake/executor.rb +9 -7
- data/lib/dake/resolver.rb +120 -30
- data/lib/dake/scheme.rb +2 -1
- data/lib/dake/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 480b83fa04055fcf5d393da94b870bafdb901c5a39788d52dbee7d89244f5f1f
|
4
|
+
data.tar.gz: a10e599b85562d3302997cd2500117357fbbacd2bae85cf7232452246afe5613
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c849058294a6c5daf084d19ba34d6cbecc53736863958cd064f1ab5f2f5d1cbe1a83c903fc137622ce02d2fa6547285a07882643b84d01c42b6a35b809bacb4
|
7
|
+
data.tar.gz: c665db3ce2bafab077723497299735e5c9d455654385b8c1845e944454ec0140c5410bbf5b4b67410224eb27b39ac97d7798a284b47c9d3e6d77ff2ce4394cd4
|
data/.gitignore
CHANGED
data/dake.gemspec
CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.summary = %q{Dake is a data workflow tool inspired by Drake.}
|
13
13
|
spec.description = %q{Dake is a data workflow tool inspired by Drake.}
|
14
14
|
spec.homepage = "https://github.com/minor6th/dake"
|
15
|
+
spec.license = "MIT"
|
15
16
|
|
16
17
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
18
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
data/examples/Dakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# This is an example
|
2
|
+
|
3
|
+
imdb/dataset_urls <- [ruby]
|
4
|
+
require 'net/http'
|
5
|
+
html = Net::HTTP.get(URI('https://datasets.imdbws.com/index.html'))
|
6
|
+
urls = html.each_line.grep(/href=.+tsv.gz/) { |line| line.sub(/.*<a href=(https:\/\/.+tsv.gz)>.*\n/, '\1') }
|
7
|
+
FileUtils.mkdir('imdb') unless Dir.exist? 'imdb'
|
8
|
+
file = File.open('$[OUTPUT]', 'w')
|
9
|
+
file.write(urls.join("\n"))
|
10
|
+
file.close
|
11
|
+
|
12
|
+
^"imdb/.+\.tsv.gz" <- imdb/dataset_urls
|
13
|
+
FILE=`basename $[OUTPUT]`
|
14
|
+
URL=`grep $FILE $[INPUT]`
|
15
|
+
wget -O $[OUTPUT] $URL
|
16
|
+
touch $[OUTPUT]
|
17
|
+
|
18
|
+
^"imdb/(?<file>.+\.tsv)" <- imdb/$[file].gz
|
19
|
+
gunzip -k $[INPUT]
|
20
|
+
touch $[OUTPUT]
|
21
|
+
|
22
|
+
imdb/title_type_rating_dist.pdf <- imdb/title.ratings.tsv, imdb/title.basics.tsv [r]
|
23
|
+
require(tidyverse)
|
24
|
+
title_ratings <- read_tsv("$[INPUT0]")
|
25
|
+
title_basics <- read_tsv("$[INPUT1]")
|
26
|
+
pd <- title_basics %>% left_join(title_ratings, by='tconst') %>%
|
27
|
+
group_by(titleType) %>%
|
28
|
+
summarise(averageRating = mean(averageRating, na.rm = T))
|
29
|
+
pdf("$[OUTPUT]", width = 5, height = 4)
|
30
|
+
ggplot(pd, aes(x = reorder(titleType, averageRating), y = averageRating)) +
|
31
|
+
geom_col() +
|
32
|
+
coord_flip() +
|
33
|
+
xlab("titleType")
|
34
|
+
|
35
|
+
imdb/rating_dist.pdf <- imdb/title.ratings.tsv [r]
|
36
|
+
require(tidyverse)
|
37
|
+
title_ratings <- read_tsv("$[INPUT0]")
|
38
|
+
pdf("$[OUTPUT]", width = 5, height = 4)
|
39
|
+
ggplot(title_ratings, aes(x = averageRating)) + geom_histogram()
|
40
|
+
|
data/exe/dake
CHANGED
@@ -28,7 +28,7 @@ def target_opts(target)
|
|
28
28
|
opts = Dake::TargetOption.new(false, false, :check, :up_tree)
|
29
29
|
mdata = /(?<build_mode>[+-]?)(?<tree_mode>[=^]?)(?<tag>@?)(?<regex>%?)(?<target_name>.+)/.match(target)
|
30
30
|
opts.build_mode = (mdata[:build_mode] == '+' ? :forced : :exclusion) unless mdata[:build_mode].empty?
|
31
|
-
opts.tree_mode = (mdata[:tree_mode] == '=' ?
|
31
|
+
opts.tree_mode = (mdata[:tree_mode] == '=' ? :target_only : :down_tree) unless mdata[:tree_mode].empty?
|
32
32
|
opts.tag = true unless mdata[:tag].empty?
|
33
33
|
opts.regex = true unless mdata[:regex].empty?
|
34
34
|
[mdata[:target_name], opts]
|
@@ -77,18 +77,42 @@ command :build do |c|
|
|
77
77
|
env = global_options[:var].reduce({}, :merge!)
|
78
78
|
env.merge! 'BASE' => File.dirname(path)
|
79
79
|
begin
|
80
|
-
target_dict = {}
|
81
|
-
args.each do |arg|
|
82
|
-
target, opts = target_opts(arg)
|
83
|
-
target_dict[target] = opts
|
84
|
-
end
|
85
80
|
tree = DakeParser.new.parse(workflow_file.read)
|
86
81
|
workflow = DakeTransform.new.apply(tree, src_file: workflow_file.to_path)
|
87
82
|
analyzer = DakeAnalyzer.new(workflow, [path], env).analyze
|
83
|
+
target_pairs = []
|
84
|
+
args.each do |arg|
|
85
|
+
target, opts = target_opts(arg)
|
86
|
+
if target == '...'
|
87
|
+
tag_list = analyzer.tag_target_dict.keys.map { |tag| [tag, Dake::TargetOption.new(true, false, :check, :up_tree)] }
|
88
|
+
file_list = analyzer.file_target_dict.keys.map { |file| [file, Dake::TargetOption.new(false, false, :check, :up_tree)] }
|
89
|
+
target_pairs += (tag_list + file_list)
|
90
|
+
else
|
91
|
+
if opts.regex
|
92
|
+
matched_targets =
|
93
|
+
if opts.tag
|
94
|
+
analyzer.tag_target_dict.keys.find_all { |tag_name| tag_name.match target }
|
95
|
+
else
|
96
|
+
analyzer.file_target_dict.keys.find_all { |file_name| file_name.match target }
|
97
|
+
end
|
98
|
+
matched_targets.each { |matched_target| target_pairs << [matched_target, opts] }
|
99
|
+
else
|
100
|
+
target_pairs << [target, opts]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
if target_pairs.any? { |_, opts| opts.tree_mode == :down_tree }
|
105
|
+
tag_list = analyzer.tag_target_dict.keys.map { |tag| [tag, Dake::TargetOption.new(true, false, :check, :up_tree)] }
|
106
|
+
file_list = analyzer.file_target_dict.keys.map { |file| [file, Dake::TargetOption.new(false, false, :check, :up_tree)] }
|
107
|
+
resolve_pairs = (tag_list + file_list)
|
108
|
+
else
|
109
|
+
resolve_pairs = target_pairs
|
110
|
+
end
|
88
111
|
resolver = DakeResolver.new(analyzer)
|
89
|
-
dep_graph = resolver.resolve(
|
112
|
+
dep_graph = resolver.resolve(resolve_pairs)
|
113
|
+
rebuild_set = resolver.target_rebuild_set(target_pairs, dep_graph)
|
90
114
|
dake_db = DakeDB.new(workflow_file.to_path)
|
91
|
-
DakeExecutor.new(analyzer, dake_db, dep_graph, options[:jobs]).execute(options[:'dry-run'], options[:log])
|
115
|
+
DakeExecutor.new(analyzer, dake_db, dep_graph, options[:jobs]).execute(rebuild_set, options[:'dry-run'], options[:log])
|
92
116
|
rescue Parslet::ParseFailed => failure
|
93
117
|
puts failure.cause
|
94
118
|
exit(1)
|
@@ -116,11 +140,13 @@ command :list do |c|
|
|
116
140
|
workflow = DakeTransform.new.apply(tree, src_file: workflow_file.to_path)
|
117
141
|
analyzer = DakeAnalyzer.new(workflow, [path], env).analyze
|
118
142
|
resolver = DakeResolver.new(analyzer)
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
143
|
+
dep_graph = nil
|
144
|
+
if options['dep']
|
145
|
+
tag_list = analyzer.tag_target_dict.keys.map { |tag| [tag, Dake::TargetOption.new(true, false, :check, :up_tree)] }
|
146
|
+
file_list = analyzer.file_target_dict.keys.map { |file| [file, Dake::TargetOption.new(false, false, :check, :up_tree)] }
|
147
|
+
target_pairs = (tag_list + file_list)
|
148
|
+
dep_graph = resolver.resolve(target_pairs)
|
149
|
+
end
|
124
150
|
analyzer.tag_target_dict.each do |tag, steps|
|
125
151
|
steps.each do |step|
|
126
152
|
next if options['dep'] and not dep_graph.root_step.include? step
|
data/lib/dake/analyzer.rb
CHANGED
@@ -1,18 +1,6 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'open3'
|
3
3
|
|
4
|
-
# the data struct needed by the executor
|
5
|
-
# note that this is not nessesarily the complete graph,
|
6
|
-
# the graph is only used to produce the given targets
|
7
|
-
DepGraph = Struct.new(
|
8
|
-
:succ_step, # a dict maps each step in the DepGraph to the steps depend on it
|
9
|
-
:dep_step, # a dict maps each step in the DepGraph to the steps it depends on
|
10
|
-
:step_list, # a list of steps represents one sequential execution order
|
11
|
-
:root_step, # a set of steps that hos no dependant
|
12
|
-
:leaf_step, # a set of steps that has no prerequisite
|
13
|
-
:need_rebuild # a set of steps in step_list which should be executed to update their targets
|
14
|
-
)
|
15
|
-
|
16
4
|
class DakeAnalyzer
|
17
5
|
attr_reader :workflow, :variable_dict, :method_dict, :included_files
|
18
6
|
attr_reader :tag_target_dict, :file_target_dict
|
@@ -138,9 +126,9 @@ class DakeAnalyzer
|
|
138
126
|
end
|
139
127
|
else
|
140
128
|
# Generated file list should not be used in targets
|
141
|
-
if type == :targets
|
142
|
-
|
143
|
-
end
|
129
|
+
# if type == :targets
|
130
|
+
# raise "File list `#{file_name}' in #{step.src_file} at #{line}:#{column} cannot be used as targets."
|
131
|
+
# end
|
144
132
|
end
|
145
133
|
newfile = file.dup
|
146
134
|
newfile.scheme = scheme
|
data/lib/dake/executor.rb
CHANGED
@@ -15,16 +15,17 @@ class DakeExecutor
|
|
15
15
|
) if @async
|
16
16
|
end
|
17
17
|
|
18
|
-
def execute(dry_run=false, log=false)
|
19
|
-
if
|
18
|
+
def execute(rebuild_set, dry_run=false, log=false)
|
19
|
+
if rebuild_set.empty?
|
20
20
|
STDERR.puts "Nothing to be done.".colorize(:green)
|
21
21
|
return
|
22
22
|
end
|
23
23
|
if @async
|
24
24
|
dep_map = Hash.new
|
25
|
-
|
25
|
+
rebuild_set.each do |step|
|
26
|
+
dep_set = @dep_graph.dep_step[step]
|
26
27
|
next if dep_set.empty?
|
27
|
-
dep_map[step] = dep_set
|
28
|
+
dep_map[step] = dep_set & rebuild_set
|
28
29
|
end
|
29
30
|
|
30
31
|
queue = Queue.new
|
@@ -42,7 +43,7 @@ class DakeExecutor
|
|
42
43
|
end
|
43
44
|
|
44
45
|
lock = Concurrent::ReadWriteLock.new
|
45
|
-
@dep_graph.leaf_step.each { |step| queue << step }
|
46
|
+
@dep_graph.leaf_step.each { |step| queue << step if rebuild_set.include? step }
|
46
47
|
|
47
48
|
while next_step = queue.deq
|
48
49
|
@pool.post(next_step) do |step|
|
@@ -55,7 +56,7 @@ class DakeExecutor
|
|
55
56
|
"skipped due to prerequisite step(s) error."
|
56
57
|
error_queue << Exception.new(msg)
|
57
58
|
else
|
58
|
-
execute_step(step, dry_run, log)
|
59
|
+
execute_step(step, dry_run, log)
|
59
60
|
end
|
60
61
|
lock.acquire_write_lock
|
61
62
|
dep_map.delete step
|
@@ -63,6 +64,7 @@ class DakeExecutor
|
|
63
64
|
queue.close
|
64
65
|
else
|
65
66
|
@dep_graph.succ_step[step].each do |succ|
|
67
|
+
next unless dep_map[succ]
|
66
68
|
dep_map[succ].delete step
|
67
69
|
if dep_map[succ].empty?
|
68
70
|
queue << succ
|
@@ -99,7 +101,7 @@ class DakeExecutor
|
|
99
101
|
raise "Failed to execute some step(s)" unless error_steps.empty?
|
100
102
|
else
|
101
103
|
@dep_graph.step_list.each do |step|
|
102
|
-
execute_step(step, dry_run, log) if
|
104
|
+
execute_step(step, dry_run, log) if rebuild_set.include? step
|
103
105
|
end
|
104
106
|
end
|
105
107
|
end
|
data/lib/dake/resolver.rb
CHANGED
@@ -1,8 +1,115 @@
|
|
1
|
+
# the data struct needed by the executor
|
2
|
+
# note that this is not nessesarily the complete graph,
|
3
|
+
# the graph is only used to produce the given targets
|
4
|
+
DepGraph = Struct.new(
|
5
|
+
:succ_step, # a dict maps each step in the DepGraph to the steps depend on it
|
6
|
+
:dep_step, # a dict maps each step in the DepGraph to the steps it depends on
|
7
|
+
:step_list, # a list of steps represents one sequential execution order
|
8
|
+
:root_step, # a set of steps that hos no dependant
|
9
|
+
:leaf_step, # a set of steps that has no prerequisite
|
10
|
+
:step_target # a dict maps each step in the DepGraph to its output files used while resolving targets
|
11
|
+
)
|
12
|
+
|
1
13
|
class DakeResolver
|
2
14
|
def initialize(analyzer)
|
3
15
|
@analyzer = analyzer
|
4
16
|
end
|
5
17
|
|
18
|
+
def target_rebuild_set(target_pairs, dep_graph)
|
19
|
+
rebuild_set = Set.new
|
20
|
+
target_pairs.each do |target_name, target_opts|
|
21
|
+
if target_opts.tag
|
22
|
+
dummy_step = Step.new([], [], [], {}, nil, nil, @analyzer.variable_dict, nil, nil)
|
23
|
+
scheme = DakeScheme::Tag.new('@', target_name, dummy_step)
|
24
|
+
else
|
25
|
+
scheme = @analyzer.analyze_scheme(target_name, nil, nil, nil)
|
26
|
+
end
|
27
|
+
target_steps = find_steps(scheme, target_opts.tag).to_set
|
28
|
+
if target_steps.empty? and not scheme.exist?
|
29
|
+
raise "No step found for building file `#{target_name}'."
|
30
|
+
end
|
31
|
+
|
32
|
+
visited = Set.new
|
33
|
+
path_visited = Set.new
|
34
|
+
down_tree_steps = Set.new
|
35
|
+
up_tree_steps = Set.new
|
36
|
+
need_rebuild = Set.new
|
37
|
+
up_tree = 0
|
38
|
+
dep_step_list = {}
|
39
|
+
|
40
|
+
init_steps = (target_opts.tree_mode == :down_tree ? dep_graph.root_step : target_steps)
|
41
|
+
init_steps.each do |init_step|
|
42
|
+
stack = [init_step]
|
43
|
+
|
44
|
+
until stack.empty?
|
45
|
+
step = stack.last
|
46
|
+
visited << step
|
47
|
+
path_visited << step
|
48
|
+
up_tree_steps << step if up_tree > 0 or target_steps.include? step
|
49
|
+
|
50
|
+
dep_step_list[step] ||= dep_graph.dep_step[step].to_a
|
51
|
+
while next_step = dep_step_list[step].pop
|
52
|
+
break unless visited.include? next_step
|
53
|
+
end
|
54
|
+
if next_step
|
55
|
+
stack.push next_step
|
56
|
+
up_tree += 1 if target_steps.include? step
|
57
|
+
else
|
58
|
+
stack.pop
|
59
|
+
|
60
|
+
if dep_graph.leaf_step.include? step
|
61
|
+
step.prerequisites.each do |prereq|
|
62
|
+
if prereq.flag != '?' and not prereq.scheme.exist?
|
63
|
+
raise "No step found for building file `#{prereq.scheme.path}'."
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if target_steps.include? step or dep_graph.dep_step[step].any? { |s| down_tree_steps.include? s }
|
69
|
+
down_tree_steps << step
|
70
|
+
end
|
71
|
+
|
72
|
+
if target_opts.build_mode == :check and (up_tree_steps.include? step or down_tree_steps.include? step)
|
73
|
+
if dep_graph.leaf_step.include? step
|
74
|
+
need_rebuild << step if need_execute?(dep_graph.step_target[step], step)
|
75
|
+
else
|
76
|
+
if dep_graph.dep_step[step].any? { |dep_step| need_rebuild.include? dep_step }
|
77
|
+
need_rebuild << step
|
78
|
+
else
|
79
|
+
need_rebuild << step if need_execute?(dep_graph.step_target[step], step)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
up_tree -= 1 if target_steps.include? step
|
85
|
+
path_visited.delete step
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
case target_opts.build_mode
|
90
|
+
when :forced
|
91
|
+
case target_opts.tree_mode
|
92
|
+
when :up_tree then rebuild_set |= up_tree_steps
|
93
|
+
when :down_tree then rebuild_set |= down_tree_steps
|
94
|
+
when :target_only then rebuild_set |= target_steps
|
95
|
+
end
|
96
|
+
when :exclusion
|
97
|
+
case target_opts.tree_mode
|
98
|
+
when :up_tree then rebuild_set -= up_tree_steps
|
99
|
+
when :down_tree then rebuild_set -= down_tree_steps
|
100
|
+
when :target_only then rebuild_set -= target_steps
|
101
|
+
end
|
102
|
+
when :check
|
103
|
+
case target_opts.tree_mode
|
104
|
+
when :up_tree then rebuild_set |= (up_tree_steps & need_rebuild)
|
105
|
+
when :down_tree then rebuild_set |= (down_tree_steps & need_rebuild)
|
106
|
+
when :target_only then rebuild_set |= (target_steps & need_rebuild)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
rebuild_set
|
111
|
+
end
|
112
|
+
|
6
113
|
# check if a step needs to be executed to produce the given targets
|
7
114
|
def need_execute?(targets, step)
|
8
115
|
max_mtime = nil
|
@@ -43,7 +150,7 @@ class DakeResolver
|
|
43
150
|
false
|
44
151
|
end
|
45
152
|
|
46
|
-
def find_steps(target_scheme, tag
|
153
|
+
def find_steps(target_scheme, tag)
|
47
154
|
target_name = target_scheme.path
|
48
155
|
target_src = target_scheme.src
|
49
156
|
if tag
|
@@ -58,8 +165,8 @@ class DakeResolver
|
|
58
165
|
steps = []
|
59
166
|
template_steps.each do |template_step|
|
60
167
|
if @analyzer.step_template_dict[template_step] and
|
61
|
-
@analyzer.step_template_dict[template_step][mdata
|
62
|
-
step = @analyzer.step_template_dict[template_step][mdata
|
168
|
+
@analyzer.step_template_dict[template_step][mdata]
|
169
|
+
step = @analyzer.step_template_dict[template_step][mdata]
|
63
170
|
else
|
64
171
|
step = template_step.dup
|
65
172
|
step.targets = template_step.targets.dup
|
@@ -67,7 +174,7 @@ class DakeResolver
|
|
67
174
|
step.context = template_step.context.dup
|
68
175
|
step.context.merge! mdata.named_captures
|
69
176
|
@analyzer.step_template_dict[template_step] ||= {}
|
70
|
-
@analyzer.step_template_dict[template_step][mdata
|
177
|
+
@analyzer.step_template_dict[template_step][mdata] = step
|
71
178
|
end
|
72
179
|
step.targets.map! do |file|
|
73
180
|
if file.scheme.is_a? DakeScheme::Regex and file.scheme.path.match target_name
|
@@ -96,8 +203,8 @@ class DakeResolver
|
|
96
203
|
end
|
97
204
|
if template_step
|
98
205
|
if @analyzer.step_template_dict[template_step] and
|
99
|
-
@analyzer.step_template_dict[template_step][mdata
|
100
|
-
step = @step_template_dict[template_step][mdata
|
206
|
+
@analyzer.step_template_dict[template_step][mdata]
|
207
|
+
step = @analyzer.step_template_dict[template_step][mdata]
|
101
208
|
else
|
102
209
|
step = template_step.dup
|
103
210
|
step.targets = template_step.targets.dup
|
@@ -105,7 +212,7 @@ class DakeResolver
|
|
105
212
|
step.context = template_step.context.dup
|
106
213
|
step.context.merge! mdata.named_captures
|
107
214
|
@analyzer.step_template_dict[template_step] ||= {}
|
108
|
-
@analyzer.step_template_dict[template_step][mdata
|
215
|
+
@analyzer.step_template_dict[template_step][mdata] = step
|
109
216
|
end
|
110
217
|
step.targets.map! do |file|
|
111
218
|
if file.scheme.is_a? DakeScheme::Regex and file.scheme.path.match target_src
|
@@ -120,12 +227,7 @@ class DakeResolver
|
|
120
227
|
@analyzer.file_target_dict[target_name] = step
|
121
228
|
steps = [step]
|
122
229
|
else
|
123
|
-
|
124
|
-
if optional or scheme.exist?
|
125
|
-
steps = []
|
126
|
-
else
|
127
|
-
raise "No step found for building file `#{target_name}'."
|
128
|
-
end
|
230
|
+
steps = []
|
129
231
|
end
|
130
232
|
end
|
131
233
|
end
|
@@ -133,26 +235,25 @@ class DakeResolver
|
|
133
235
|
end
|
134
236
|
|
135
237
|
# resolve the dependency graph and generate step list for sequential execution
|
136
|
-
def resolve(
|
238
|
+
def resolve(target_pairs)
|
137
239
|
step_list = []
|
138
240
|
visited = Set.new
|
139
241
|
path_visited = Set.new
|
140
242
|
leaf_steps = Set.new
|
141
243
|
target_steps = Set.new
|
142
|
-
need_rebuild = Set.new
|
143
244
|
succ_step_dict = {}
|
144
245
|
dep_step_dict = {}
|
145
246
|
dep_step_list = {}
|
146
247
|
succ_target_dict = {}
|
147
248
|
|
148
|
-
|
249
|
+
target_pairs.each do |target_name, target_opts|
|
149
250
|
if target_opts.tag
|
150
251
|
dummy_step = Step.new([], [], [], {}, nil, nil, @analyzer.variable_dict, nil, nil)
|
151
252
|
scheme = DakeScheme::Tag.new('@', target_name, dummy_step)
|
152
253
|
else
|
153
254
|
scheme = @analyzer.analyze_scheme(target_name, nil, nil, nil)
|
154
255
|
end
|
155
|
-
dep_steps = find_steps(scheme, target_opts.tag
|
256
|
+
dep_steps = find_steps(scheme, target_opts.tag)
|
156
257
|
dep_steps.each do |dep_step|
|
157
258
|
target = dep_step.targets.find { |target| target.scheme.path == scheme.path }
|
158
259
|
succ_target_dict[dep_step] ||= Set.new
|
@@ -173,7 +274,7 @@ class DakeResolver
|
|
173
274
|
dep_step_dict[step] = Set.new
|
174
275
|
step.prerequisites.map! { |file| @analyzer.analyze_file(file, :prerequisites, step) }.flatten!
|
175
276
|
step.prerequisites.each do |dep|
|
176
|
-
dep_steps = find_steps(dep.scheme, dep.tag
|
277
|
+
dep_steps = find_steps(dep.scheme, dep.tag)
|
177
278
|
dep_steps.each do |dep_step|
|
178
279
|
dep_step_dict[step] << dep_step
|
179
280
|
succ_step_dict[dep_step] ||= Set.new
|
@@ -205,18 +306,7 @@ class DakeResolver
|
|
205
306
|
end
|
206
307
|
end
|
207
308
|
end
|
208
|
-
step_list.each do |step|
|
209
|
-
if leaf_steps.include? step
|
210
|
-
need_rebuild << step if no_check or need_execute?(succ_target_dict[step], step)
|
211
|
-
else
|
212
|
-
if dep_step_dict[step].any? { |dep_step| need_rebuild.include? dep_step }
|
213
|
-
need_rebuild << step
|
214
|
-
else
|
215
|
-
need_rebuild << step if no_check or need_execute?(succ_target_dict[step], step)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
309
|
root_steps = target_steps.select { |step| succ_step_dict[step].empty? }.to_set
|
220
|
-
DepGraph.new(succ_step_dict, dep_step_dict, step_list, root_steps, leaf_steps,
|
310
|
+
DepGraph.new(succ_step_dict, dep_step_dict, step_list, root_steps, leaf_steps, succ_target_dict)
|
221
311
|
end
|
222
312
|
end
|
data/lib/dake/scheme.rb
CHANGED
@@ -34,11 +34,12 @@ module DakeScheme
|
|
34
34
|
class Local < Scheme
|
35
35
|
PATTERN = ['local:']
|
36
36
|
def initialize(scheme_part, path_part, step)
|
37
|
-
@src = path_part
|
38
37
|
if path_part.start_with? '/'
|
39
38
|
@path = path_part
|
39
|
+
@src = Pathname.new(path_part).relative_path_from(step.context['BASE'])
|
40
40
|
else
|
41
41
|
@path = File.expand_path(path_part, step.context['BASE'])
|
42
|
+
@src = path_part
|
42
43
|
end
|
43
44
|
@step = step
|
44
45
|
end
|
data/lib/dake/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- minor6th
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -180,6 +180,7 @@ files:
|
|
180
180
|
- bin/console
|
181
181
|
- bin/setup
|
182
182
|
- dake.gemspec
|
183
|
+
- examples/Dakefile
|
183
184
|
- exe/dake
|
184
185
|
- lib/dake.rb
|
185
186
|
- lib/dake/analyzer.rb
|
@@ -193,7 +194,8 @@ files:
|
|
193
194
|
- vim/ftdetect/dake.vim
|
194
195
|
- vim/syntax/dake.vim
|
195
196
|
homepage: https://github.com/minor6th/dake
|
196
|
-
licenses:
|
197
|
+
licenses:
|
198
|
+
- MIT
|
197
199
|
metadata: {}
|
198
200
|
post_install_message:
|
199
201
|
rdoc_options: []
|