module embedfs import os import strings import net.http.mime pub struct CodeGenerator { pub: // Path to file or directory to embed path string @[required] // Path prefix if you want to add extra prefix for file paths prefix string // Glob patterns to match files the must be ignored when generating the code ignore_patterns []string // If true set the default MIME-type for files if no MIME-type detected force_mimetype bool // Default MIME-type for files. See https://www.iana.org/assignments/media-types/media-types.xhtml default_mimetype string = 'application/octet-stream' // Name of generated module module_name string = 'main' // Name of constant which will contain embedded files const_name string = 'embedfs' // If true make constant public make_const_pub bool // If true make all symbols in generated module public make_pub bool // Generate map[string]EmbedFile instead of EmbedFileSystem instance bare_map bool } struct EmbedFileSpec { key string path string name string ext string mimetype string } pub fn (g CodeGenerator) generate() string { visible := if g.make_pub == true { 'pub ' } else { '' } const_visible := if g.make_pub == true || g.make_const_pub == true { 'pub ' } else { '' } mut b := strings.new_builder(1024 * 4) b.writeln('// !WARNING! This file is generated by embedfs module, do not edit it.') b.writeln('') b.writeln('module ${g.module_name}') b.writeln('') b.writeln('import v.embed_file { EmbedFileData }') b.writeln('') b.writeln('${visible}struct EmbedFileMetadata {') b.writeln('\tkey string') b.writeln('\tname string') b.writeln('\text string') b.writeln('\tmimetype string') b.writeln('}') b.writeln('') b.writeln('${visible}struct EmbedFile {') b.writeln('\tdata EmbedFileData') b.writeln('\tmeta EmbedFileMetadata') b.writeln('}') b.writeln('') b.writeln('${visible}struct EmbedFileSystem {') b.writeln('\tfiles map[string]EmbedFile') b.writeln('}') b.writeln('') if g.bare_map { b.writeln('${const_visible}const ${g.const_name} = {') g.write_embed_file_map_item(mut b) b.writeln('}') } else { b.writeln('${const_visible}const ${g.const_name} = EmbedFileSystem{') b.writeln('\tfiles: {') g.write_embed_file_map_item(mut b) b.writeln('\t}') b.writeln('}') } return b.str() } fn (g CodeGenerator) get_files() []EmbedFileSpec { mut file_list := &[]string{} os.walk(g.path, fn [mut file_list] (file string) { file_list << file }) mut files := []EmbedFileSpec{} outer: for file in file_list { for glob in g.ignore_patterns { if file.match_glob(glob) { continue outer } } file_key := os.join_path_single(g.prefix, file) file_path := file // the actual path used in $embed_file() statement file_name := os.file_name(file_path) file_ext := os.file_ext(file_name).replace_once('.', '') mut mimetype := mime.get_mime_type(file_ext) if g.force_mimetype && mimetype == '' { mimetype = g.default_mimetype } files << EmbedFileSpec{ key: file_key path: file_path name: file_name ext: file_ext mimetype: mimetype } } return files } fn (g CodeGenerator) write_embed_file_map_item(mut b strings.Builder) { for filespec in g.get_files() { b.writeln("\t\t'${filespec.key}': EmbedFile{") b.writeln("\t\t\tdata: \$embed_file('${filespec.path}')") b.writeln('\t\t\tmeta: EmbedFileMetadata{') b.writeln("\t\t\t\tkey: '${filespec.key}'") b.writeln("\t\t\t\tname: '${filespec.name}'") b.writeln("\t\t\t\text: '${filespec.ext}'") b.writeln("\t\t\t\tmimetype: '${filespec.mimetype}'") b.writeln('\t\t\t}') b.writeln('\t\t},') } }