65 lines
2.5 KiB
Ruby
65 lines
2.5 KiB
Ruby
# Builds tonalmine/images/icons.svg from tools/icon_map.yml.
|
|
# Usage (from repo root): ruby tools/build_icons.rb
|
|
# Ruby stdlib only. Downloads are cached in tools/.cache/.
|
|
require 'yaml'
|
|
require 'net/http'
|
|
require 'uri'
|
|
require 'fileutils'
|
|
|
|
CORE_ICONS = 'https://raw.githubusercontent.com/redmine/redmine/7.0-stable/config/icon_source.yml'
|
|
SYMBOLS = 'https://raw.githubusercontent.com/google/material-design-icons/master/symbols/web'
|
|
ROOT = File.expand_path('..', __dir__)
|
|
CACHE = File.join(ROOT, 'tools/.cache')
|
|
OUT = File.join(ROOT, 'tonalmine/images/icons.svg')
|
|
|
|
def fetch(url)
|
|
res = Net::HTTP.get_response(URI(url))
|
|
res.is_a?(Net::HTTPSuccess) ? res.body : nil
|
|
end
|
|
|
|
def fail_with(message, items)
|
|
warn "#{message}:\n #{items.join("\n ")}"
|
|
exit 1
|
|
end
|
|
|
|
# 1. Map must cover exactly the core icon names.
|
|
core_yml = fetch(CORE_ICONS) or fail_with('Could not fetch', [CORE_ICONS])
|
|
core = YAML.safe_load(core_yml).map { |e| e['name'] }.uniq
|
|
map = YAML.load_file(File.join(ROOT, 'tools/icon_map.yml'))
|
|
names = map.map { |e| e['name'] }
|
|
dupes = names.select { |n| names.count(n) > 1 }.uniq
|
|
fail_with('Duplicate names in icon_map.yml', dupes) if dupes.any?
|
|
missing = core - names
|
|
extra = names - core
|
|
fail_with('Missing from icon_map.yml', missing) if missing.any?
|
|
fail_with('Not in Redmine icon_source.yml (extra)', extra) if extra.any?
|
|
|
|
# 2. Download (or read cached) SVGs.
|
|
FileUtils.mkdir_p(CACHE)
|
|
not_found = []
|
|
symbols = map.sort_by { |e| e['name'] }.map do |e|
|
|
file = "#{e['symbol']}#{e['fill'] ? '_fill1' : ''}_24px.svg"
|
|
cached = File.join(CACHE, file)
|
|
unless File.exist?(cached)
|
|
svg = fetch("#{SYMBOLS}/#{e['symbol']}/materialsymbolsoutlined/#{file}")
|
|
next not_found << "#{e['name']} -> #{file}" unless svg
|
|
File.write(cached, svg)
|
|
end
|
|
paths = File.read(cached).scan(/<path\b[^>]*\bd="([^"]+)"/).flatten
|
|
fail_with('No <path> found in', [cached]) if paths.empty?
|
|
body = paths.map { |d| %(<path d="#{d}" fill="currentColor" stroke="none"/>) }.join
|
|
%(<symbol id="icon--#{e['name']}" viewBox="0 -960 960 960">#{body}</symbol>)
|
|
end
|
|
fail_with('Material Symbol not found', not_found) if not_found.any?
|
|
|
|
# 3. Write the sprite.
|
|
File.write(OUT, <<~SVG)
|
|
<svg xmlns="http://www.w3.org/2000/svg">
|
|
<!-- Generated by tools/build_icons.rb from tools/icon_map.yml. Do not edit by hand.
|
|
Icons: Material Symbols Outlined by Google (github.com/google/material-design-icons),
|
|
Apache License 2.0, see LICENSE-material-symbols.txt. -->
|
|
#{symbols.join("\n")}
|
|
</svg>
|
|
SVG
|
|
puts "Wrote #{symbols.size} icons to #{OUT.sub("#{ROOT}/", '')}"
|