new implementation

This commit is contained in:
ge
2026-05-05 23:02:06 +03:00
parent 171ec8fe4b
commit 95ceb5aeac
9 changed files with 179 additions and 217 deletions
+46 -106
View File
@@ -1,122 +1,62 @@
module embedfs
import os
import strings
import net.http.mime
pub struct CodeGenerator {
@[params]
pub struct EmbedFsParams {
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
module_name string = 'main' // name of the generated V module.
const_name string = 'embed_files' // name of the constant that will store the embedded data.
const_public bool // if true make the const public.
key_path_prefix string // path prefix for all embedded files, will be added to data map key.
file_path_prefix string // path prefix for files used in $embed_file() call in generated file.
compression bool // add zlib compression flag to $embed_file() call in generated file.
notice string = 'This file is generated by embedfs module, DO NOT EDIT!'
}
struct EmbedFileSpec {
key string
path string
name string
ext string
mimetype string
@[params]
pub struct GenerateParams {
EmbedFsParams
pub:
ignore []string // glob expressions for files that should not be embedded.
}
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('}')
// generate generates the V code that embeds the contents of directory `dir`.
pub fn generate(dir string, params GenerateParams) !string {
files := collect_files(dir, params.ignore)
return generate_with(files, params.EmbedFsParams)!
}
// generate_with generates the V code that embeds the files listed in `paths`.
pub fn generate_with(paths []string, params EmbedFsParams) !string {
module_name := params.module_name
const_name := params.const_name
const_public := params.const_public
compression := params.compression
notice := params.notice
skip_notice := params.notice == ''
mut files := map[string]string{}
for file in paths {
file_path := if params.file_path_prefix == '' {
file
} else {
os.join_path_single(params.file_path_prefix, file)
}
files[os.join_path_single(params.key_path_prefix, file)] = file_path
}
return b.str()
result := $tmpl('embedfs.template')
return result
}
fn (g CodeGenerator) get_files() []EmbedFileSpec {
fn collect_files(path string, ignore []string) []string {
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
os.walk(path, fn [mut file_list, ignore] (file string) {
for globexpr in ignore {
if file.match_glob(globexpr) {
return
}
}
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},')
}
file_list << file
})
return *file_list
}