Class: Quik::Merger

Inherits:
Object
  • Object
show all
Defined in:
lib/quik/merger.rb

Instance Method Summary collapse

Instance Method Details

#find_files(root_dir) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/quik/merger.rb', line 9

def find_files( root_dir )
  tree = []

  files =  Dir.entries( root_dir )
  files = files.sort
  puts "#{root_dir}:"
  pp files

  files.each do |file|
    if File.directory?( "#{root_dir}/#{file}" )
      ## note: skip directory if it starts with dot e.g. . or .. or .git etc.
      if file.start_with?( '.' )
        puts "skipping directory >#{file}< (#{root_dir})"
        next
      end
      subtree = find_files( "#{root_dir}/#{file}" )
      tree << [ file, subtree ]
    else
      ## just a "regular" file
      tree << file
    end
  end
  tree
end

#merge(root_dir, hash, opts = {}) ⇒ Object



197
198
199
200
201
202
# File 'lib/quik/merger.rb', line 197

def merge( root_dir, hash, opts={} )
  puts "  merge #{root_dir}, #{hash.inspect}"

  merge_filenames( root_dir, hash, opts )
  merge_files( root_dir, hash, opts )
end

#merge_filenames(root_dir, hash, opts = {}) ⇒ Object

flags e.g. noop, verbose, etc. see FileUtils



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/quik/merger.rb', line 35

def merge_filenames( root_dir, hash, opts={} )  ## flags e.g. noop, verbose, etc. see FileUtils
  tree = find_files( root_dir )
  pp tree

  flags = {     ## always use verbose mode for now
    verbose: true
  }

  ## todo/check: move opts={} to initialize e.g. Merger.new( opts={}) why? why not??

  ## check for noop e.g. test mode/dry run
  flags[ :noop ] = true  if opts[:test] || opts[:dry_run] || opts[:noop]

  puts "walk tree:"
  merge_filenames_worker_step1( root_dir, hash, tree, flags )
  merge_filenames_worker_step2( root_dir, hash, tree, flags )
end

#merge_filenames_worker_step1(root_dir, hash, tree, flags) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/quik/merger.rb', line 53

def merge_filenames_worker_step1( root_dir, hash, tree, flags )
  ## note:  step 1 move all files
  ##        step 2 move all dirs

  tree.each do |node|
    if node.is_a? Array ## assume it's a directory
      merge_filenames_worker_step1( "#{root_dir}/#{node[0]}", hash, node[1], flags )
    else  ## assume it's a file
      old_name = node
      new_name = merge_path( old_name, hash )
      if old_name == new_name
         puts "  keep file #{node} (#{root_dir})"
      else
         puts "  *** move file #{old_name} => #{new_name} (#{root_dir})"
         src_path  = "#{root_dir}/#{old_name}"
         dest_path = "#{root_dir}/#{new_name}"
         ## note: make sure subpath exists (e.g. replacement might include new (sub)dirs too)
         FileUtils.mkdir_p( File.dirname( dest_path ), flags )  unless Dir.exist?( File.dirname( dest_path ))
         FileUtils.mv( src_path, dest_path, flags )
      end
    end
  end
end

#merge_filenames_worker_step2(root_dir, hash, tree, flags) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/quik/merger.rb', line 77

def merge_filenames_worker_step2( root_dir, hash, tree, flags )
  ## note:  step 1 move all files
  ##        step 2 move all dirs

  tree.each do |node|
    if node.is_a? Array ## assume it's a directory
      merge_filenames_worker_step2( "#{root_dir}/#{node[0]}", hash, node[1], flags )
      old_name = node[0]
      new_name = merge_path( old_name, hash )
      if old_name == new_name
         puts "  keep dir #{node[0]} (#{root_dir})"
      else
         puts "  *** move dir #{old_name} => #{new_name} (#{root_dir})"
         src_path  = "#{root_dir}/#{old_name}"
         dest_path = "#{root_dir}/#{new_name}"
         ## note: make sure subpath exists (e.g. replacement might include new (sub)dirs too)
         FileUtils.mkdir_p( File.dirname( dest_path ), flags )  unless Dir.exist?( File.dirname( dest_path ))
         FileUtils.mv( src_path, dest_path, flags )
      end
    end
  end
end

#merge_files(root_dir, hash, opts = {}) ⇒ Object



102
103
104
105
106
107
108
109
# File 'lib/quik/merger.rb', line 102

def merge_files( root_dir, hash, opts={} )
  ## note: rescan files (after renames)
  tree = find_files( root_dir )
  pp tree

  puts "walk tree:"
  merge_files_worker( root_dir, '', hash, tree, opts )
end

#merge_files_worker(root_dir, relative_dir, hash, tree, opts) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/quik/merger.rb', line 111

def merge_files_worker( root_dir, relative_dir, hash, tree, opts )
  tree.each do |node|
    if node.is_a? Array ## assume it's a directory
      if relative_dir.empty?   # e.g. just add w/o leading slash e.g. 'lib' and not '/lib'
        new_relative_dir = node[0].dup  # note: create a new string; just in case
      else
        new_relative_dir = "#{relative_dir}/#{node[0]}"
      end
      merge_files_worker( root_dir, new_relative_dir, hash, node[1], opts )
    else  ## assume it's a file
      if relative_dir.empty?
        relative_path = node
      else
        relative_path = "#{relative_dir}/#{node}"
      end

      src_path = "#{root_dir}/#{relative_path}"

      ## note: for now assume always assume text files/utf8
      old_text = File.open( src_path, 'r:utf-8' ) { |f| f.read }
      new_text = merge_text( old_text, hash )

      if opts[:o]
        dest_root = opts[:o]
        dest_path = "#{dest_root}/#{relative_path}"
        ## make sure dest_path exists
        dest_dir = File.dirname( dest_path )
        FileUtils.mkdir_p( dest_dir ) unless Dir.exist?( dest_dir )
      else
        dest_root = root_dir
        dest_path = "#{dest_root}/#{relative_path}"
      end

      if old_text == new_text
         if opts[:o]  ## for testing copy file 1:1
           puts "  copy file 1:1 #{node} (#{relative_dir}) in (#{dest_root})"
           FileUtils.cp( src_path, dest_path, verbose: true )
         else
           puts "  skip file #{node} (#{relative_dir})"
         end
      else
         puts "  *** update file #{node} (#{relative_dir}) in (#{dest_root})"
         File.open( dest_path, 'w:utf-8' ) do |f|
           f.write( new_text )
         end
      end
    end
  end
end

#merge_path(path, hash) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/quik/merger.rb', line 163

def merge_path( path, hash )
  ## e.g. allow
  ##  __filename__  or
  ##  $filename$   for now
  ##   note: allow underline too  e.g $file_name$ etc.
  path.gsub( /(__|\$)([a-z_]+)\1/i ) do |_|
    key   = $2.to_s
    value = hash[ key ]
    puts "   [path] replacing #{key} w/ >#{value}< in (#{path})"
    value
  end
end

#merge_text(text, hash) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/quik/merger.rb', line 176

def merge_text( text, hash )
  ## e.g. allow
  ##  $filename$  for now only in text
  ##  note: must include leading and trailing word boundry (/B)
  ##   e.g. hello$test$ will not match only "free-standing $test
  ##  or in quote e.g. "$test$"
  ##  e.g. no letters or digits allowed before or after $ to match
  ##  note: allow underline too e.g. $test_klass$ etc.

  ## pp text

  text.gsub( /\B\$([a-z_]+)\$\B/i ) do |_|
    key   = $1.to_s
    value = hash[ key ]
    puts "   [text] replacing #{key} w/ >#{value}<"
    value
  end
end