Class: Rmk

Inherits:
Object
  • Object
show all
Defined in:
lib/rmk/rmk.rb,
lib/rmk/vars.rb,
lib/rmk/version.rb,
lib/rmk/schedule.rb

Defined Under Namespace

Modules: Schedule Classes: Build, MultiVarWriter, Rule, Storage, VDir, VFile, VOutDir, Vars

Constant Summary collapse

VERSION =
"0.3.0"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(srcroot: '', outroot: '', variant: nil) ⇒ Rmk

create Rmk object

Parameters:

  • srcroot (String) (defaults to: '')

    source root dir,can be absolute or relative to output root(start with ..)

  • outroot (String) (defaults to: '')

    output root dir,can be absolute or relative to pwd,default pwd



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rmk/rmk.rb', line 39

def initialize(srcroot:'', outroot:'', variant:nil)
	@files_mutex = Thread::Mutex.new	# files operate mutex
	@stdoe_mutex = Thread::Mutex.new	# stdout and stderr mutex

	srcroot = Rmk.normalize_path srcroot
	@outroot = File.join Rmk.normalize_path(File.absolute_path outroot), ''
	@srcroot = File.join File.absolute_path(srcroot, @outroot), ''
	raise "source path '#{@srcroot}' not exist or not directory" unless ::Dir.exist?(@srcroot)
	warn 'in-source build' if @outroot == @srcroot
	@src_relative = srcroot.match?(/^\.\./) && File.join(srcroot, '')
	Dir.mkdir @outroot unless Dir.exist? @outroot
	Dir.chdir @outroot
	Dir.mkdir '.rmk' unless Dir.exist? '.rmk'
	@mid_storage = Rmk::Storage.new '.rmk/mid', {}
	@dep_storage = Rmk::Storage.new '.rmk/dep', {}
	@cml_storage = Rmk::Storage.new '.rmk/cml', {}	# command line text storage
	@srcfiles = {}
	@outfiles = {}
	@defaultfiles = []
	@vars = {'srcroot'=>@srcroot[0..-2], 'outroot'=>@outroot[0..-2], 'src_rto_root'=>(@src_relative || @srcroot)[0..-2]}
	@vars['variant'] = variant if variant
	@vars.freeze
	@log_prefix = variant ? "Rmk (#{variant}): " : 'Rmk: '
	@virtual_root = Rmk::VDir.new self, nil
end

Instance Attribute Details

#cml_storageObject (readonly)

Returns the value of attribute cml_storage.



65
66
67
# File 'lib/rmk/rmk.rb', line 65

def cml_storage
  @cml_storage
end

#dep_storageObject (readonly)

Returns the value of attribute dep_storage.



65
66
67
# File 'lib/rmk/rmk.rb', line 65

def dep_storage
  @dep_storage
end

#mid_storageObject (readonly)

Returns the value of attribute mid_storage.



65
66
67
# File 'lib/rmk/rmk.rb', line 65

def mid_storage
  @mid_storage
end

#outfilesObject (readonly)

Returns the value of attribute outfiles.



64
65
66
# File 'lib/rmk/rmk.rb', line 64

def outfiles
  @outfiles
end

#outrootObject (readonly)

Returns the value of attribute outroot.



64
65
66
# File 'lib/rmk/rmk.rb', line 64

def outroot
  @outroot
end

#srcfilesObject (readonly)

Returns the value of attribute srcfiles.



64
65
66
# File 'lib/rmk/rmk.rb', line 64

def srcfiles
  @srcfiles
end

#srcrootObject (readonly)

Returns the value of attribute srcroot.



64
65
66
# File 'lib/rmk/rmk.rb', line 64

def srcroot
  @srcroot
end

#varsObject (readonly)

Returns the value of attribute vars.



64
65
66
# File 'lib/rmk/rmk.rb', line 64

def vars
  @vars
end

#virtual_rootObject (readonly)

Returns the value of attribute virtual_root.



64
65
66
# File 'lib/rmk/rmk.rb', line 64

def virtual_root
  @virtual_root
end

Class Method Details

.normalize_path(path) ⇒ String

Returns:

  • (String)


9
# File 'lib/rmk/rmk.rb', line 9

def self.normalize_path(path) path.gsub(?\\, ?/).sub(/^[a-z](?=:)/){|ch|ch.upcase} end

Instance Method Details

#add_default(*files) ⇒ Object

add default target



172
# File 'lib/rmk/rmk.rb', line 172

def add_default(*files) @files_mutex.synchronize{@defaultfiles.concat files} end

#add_out_file(path:, vpath: nil) ⇒ Rmk::VFile

register a out file

Parameters:

  • path (String)
  • vpath (String) (defaults to: nil)

Returns:



153
154
155
156
157
158
159
# File 'lib/rmk/rmk.rb', line 153

def add_out_file(path:, vpath:nil)
	@files_mutex.synchronize do
		raise "file '#{path}' has been defined" if @outfiles.include? path
		file = @srcfiles.delete(path).change_to_out! file if @srcfiles.include? path
		@outfiles[path] = VFile.new rmk:self, path:path, vpath:vpath
	end
end

#add_src_file(path:, vpath: nil) ⇒ Rmk::VFile

register a src file

Parameters:

  • path (String)
  • vpath (String) (defaults to: nil)

Returns:



165
166
167
168
169
# File 'lib/rmk/rmk.rb', line 165

def add_src_file(path:, vpath:nil)
	@files_mutex.synchronize do
		@outfiles[path] || (@srcfiles[path] ||= VFile.new(rmk:self, path:path, vpath:vpath, is_src:true))
	end
end

#build(*tgts) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/rmk/rmk.rb', line 186

def build(*tgts)
	std_puts 'build start'
	if tgts.empty?
		files = @defaultfiles
	else
		files = tgts.map do |name|
			file = Rmk.normalize_path name
			file = @outfiles[File.absolute_path file, @outroot] || @srcfiles[File.absolute_path file, @srcroot]
			raise "build target '#{name}' not found" unless file
			file = file.input_ref_builds[0].outfiles[0] if file.src? && file.input_ref_builds.size == 1
			file
		end
	end
	if files.empty?
		@srcfiles.each_value{|file| file.check_for_build}
	else
		checklist = []
		checkproc = proc do |fi|
			next checklist << fi if fi.src?
			fi.output_ref_build.infiles.each &checkproc
			fi.output_ref_build.depfiles.each &checkproc
			fi.output_ref_build.orderfiles.each &checkproc
		end
		files.each &checkproc
		exit std_puts('','found nothing to build') || 0 if checklist.empty?
		checklist.each {|file| file.check_for_build}
	end
	while Thread.list.size > 1
		thr = Thread.list[-1]
		thr.join unless thr == Thread.current
	end
	std_puts 'build end'
	@mid_storage.save
	@dep_storage.data!.each_key {|key| @dep_storage.data!.delete key unless @outfiles.include? key}
	@dep_storage.save
	@cml_storage.data!.each_key {|key| @cml_storage.data!.delete key unless @outfiles.include? key}
	@cml_storage.save
end

#err_puts(mark, *parms) ⇒ Object



22
# File 'lib/rmk/rmk.rb', line 22

def err_puts(mark, *parms) @stdoe_mutex.synchronize{log $stderr, mark, *parms} end

#find_inputfiles(pattern, ffile: false) ⇒ Array<VFile, FFile>

find files which can be build’s imput file

Parameters:

  • pattern (String)

    absolute path to find src and out files which can include ‘*’ to match any char at last no dir part

  • ffile (Boolean) (defaults to: false)

    return FFile struct or not

Returns:

  • (Array<VFile, FFile>)

    return array of FFile when ffile, otherwise array of VFile



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/rmk/rmk.rb', line 88

def find_inputfiles(pattern, ffile:false)
	pattern = Rmk.normalize_path pattern
	path, regex, postpath = split_path_pattern pattern
	files = []
	if regex
		@files_mutex.synchronize do
			find_outfiles_imp files, path, regex, postpath, ffile:ffile
			range = postpath ? path.size..-1-postpath.size : path.size..-1
			Dir[pattern].each do |fn|
				next if @outfiles.include? fn
				next files << (ffile ? FFile.new(@srcfiles[fn], nil, fn[range][regex, 1]) : @srcfiles[fn]) if @srcfiles.include? fn
				file = (@srcfiles[fn] = VFile.new rmk:self, path:fn, is_src:true,
					vpath:fn.start_with?(@srcroot) && fn[@srcroot.size .. -1])
				files << (ffile ? FFile.new(file, nil, fn[range][regex, 1]) : file)
			end
		end
	else
		@files_mutex.synchronize do
			next files << (ffile ? FFile.new(@outfiles[path]) : @outfiles[path]) if @outfiles.include? path
			next files << (ffile ? FFile.new(@srcfiles[path]) : @srcfiles[path]) if @srcfiles.include? path
			next unless File.exist? path
			file = @srcfiles[path] = VFile.new rmk:self, path:path, is_src:true,
					vpath:path.start_with?(@srcroot) && path[@srcroot.size .. -1]
			files << (ffile ? FFile.new(file) : file)
		end
	end
	files
end

#find_outfiles(pattern) ⇒ Array<Hash>

find files which must be build’s output

Parameters:

  • pattern (String)

    absolute path to find out files which can include ‘*’ to match any char at last no dir part

Returns:

  • (Array<Hash>)

    return Array of file, and Regex when has ‘*’ pattern



120
121
122
123
124
125
126
127
128
# File 'lib/rmk/rmk.rb', line 120

def find_outfiles(pattern)
	path, regex, postpath = split_path_pattern Rmk.normalize_path pattern
	files = []
	@files_mutex.synchronize do
		next (files << @outfiles[path] if @outfiles.include? path) unless regex
		find_outfiles_imp files, path, regex, postpath
	end
	files
end

#join_abs_src_path(path) ⇒ Object



67
# File 'lib/rmk/rmk.rb', line 67

def join_abs_src_path(path) File.join @srcroot, path end

#join_rto_src_path(path) ⇒ Object

join src file path relative to out root, or absolute src path when not relative src



70
# File 'lib/rmk/rmk.rb', line 70

def join_rto_src_path(path) ::File.join @src_relative ? @src_relative : @srcroot, path end

#log_cmd_out(mark, out, err) ⇒ Object



29
30
31
32
33
34
# File 'lib/rmk/rmk.rb', line 29

def log_cmd_out(mark, out, err)
	@stdoe_mutex.synchronize do
		split_log $stdout, mark, out
		split_log $stderr, nil, err unless err.empty?
	end
end

#parseself

parse project

Returns:

  • (self)


176
177
178
179
180
181
182
183
184
# File 'lib/rmk/rmk.rb', line 176

def parse
	std_puts 'parse start'
	@mid_storage.wait_ready
	@dep_storage.wait_ready
	@cml_storage.wait_ready
	@virtual_root.parse
	std_puts 'parse done'
	self
end

#split_path_pattern(pattern) ⇒ Object

split path pattern to dir part and file match regex part when pattern include ‘*’, return [dir part, file(or dir) match regex, post dir part, post file part] ;otherwise return [origin pattern, nil, nil, nil]

Parameters:

  • pattern (String)

    absolute path, can include ‘*’ to match any char at last no dir part



76
77
78
79
80
81
82
# File 'lib/rmk/rmk.rb', line 76

def split_path_pattern(pattern)
	match = /^([a-zA-Z]:\/(?:[^\/*]+\/)*+)([^\/*]*+)(?:\*([^\/*]*+))?(?(3)(\/(?:[^\/*]+\/)*+[^\/*]++)?)$/.match pattern
	raise "file syntax '#{pattern}' error" unless match
	dir, prefix, postfix, postpath = *match[1..5]
	regex = postfix && /#{Regexp.escape prefix}(.*)#{Regexp.escape postfix}$/
	[regex ? dir : pattern, regex, postpath]
end

#std_puts(mark, *parms) ⇒ Object



20
# File 'lib/rmk/rmk.rb', line 20

def std_puts(mark, *parms) @stdoe_mutex.synchronize{log $stdout, mark, *parms} end