dake 0.1.0 → 0.2.0
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.
- 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: []
|