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