diff --git a/xmake/actions/build/xmake.lua b/xmake/actions/build/xmake.lua index 61174105c0c..5fdfe4522fb 100644 --- a/xmake/actions/build/xmake.lua +++ b/xmake/actions/build/xmake.lua @@ -47,7 +47,7 @@ task("build") "e.g. ", " - xmake --files=src/main.c", " - xmake --files='src/*.c' [target]", - " - xmake --files='src/**c|excluded_file.c'", + " - xmake --files='src/**.c|excluded_file.c'", " - xmake --files='src/main.c" .. path.envsep() .. "src/test.c'" } , {} diff --git a/xmake/plugins/format/main.lua b/xmake/plugins/format/main.lua index 297e0a851f3..85c5e00f986 100644 --- a/xmake/plugins/format/main.lua +++ b/xmake/plugins/format/main.lua @@ -20,12 +20,102 @@ -- imports import("core.base.option") +import("core.base.hashset") import("core.project.config") import("core.project.project") import("lib.detect.find_tool") import("private.action.require.impl.packagenv") import("private.action.require.impl.install_packages") +-- match source files +function _match_sourcefiles(sourcefile, filepatterns) + for _, filepattern in ipairs(filepatterns) do + if sourcefile:match(filepattern.pattern) == sourcefile then + if filepattern.excludes then + if filepattern.rootdir and sourcefile:startswith(filepattern.rootdir) then + sourcefile = sourcefile:sub(#filepattern.rootdir + 2) + end + for _, exclude in ipairs(filepattern.excludes) do + if sourcefile:match(exclude) == sourcefile then + return false + end + end + end + return true + end + end +end + +-- convert all sourcefiles to lua pattern +function _get_file_patterns(sourcefiles) + local patterns = {} + for _, sourcefile in ipairs(path.splitenv(sourcefiles)) do + + -- get the excludes + local pattern = sourcefile:trim() + local excludes = pattern:match("|.*$") + if excludes then excludes = excludes:split("|", {plain = true}) end + + -- translate excludes + if excludes then + local _excludes = {} + for _, exclude in ipairs(excludes) do + exclude = path.translate(exclude) + exclude = path.pattern(exclude) + table.insert(_excludes, exclude) + end + excludes = _excludes + end + + -- translate path and remove some repeat separators + pattern = path.translate(pattern:gsub("|.*$", "")) + + -- remove "./" or '.\\' prefix + if pattern:sub(1, 2):find('%.[/\\]') then + pattern = pattern:sub(3) + end + + -- get the root directory + local rootdir = pattern + local startpos = pattern:find("*", 1, true) + if startpos then + rootdir = rootdir:sub(1, startpos - 1) + end + rootdir = path.directory(rootdir) + + -- convert to lua path pattern + pattern = path.pattern(pattern) + table.insert(patterns, {pattern = pattern, excludes = excludes, rootdir = rootdir}) + end + return patterns +end + +-- get all the targets that match the group or targetname +function _get_targets(targetname, group_pattern) + local targets_root = {} + if targetname then + table.insert(targets_root, project.target(targetname)) + else + local depset = hashset.new() + local targets = {} + for _, target in pairs(project.targets()) do + local group = target:get("group") + if (target:is_default() and not group_pattern) or option.get("all") or (group_pattern and group and group:match(group_pattern)) then + for _, depname in ipairs(target:get("deps")) do + depset:insert(depname) + end + table.insert(targets, target) + end + end + for _, target in pairs(targets) do + if not depset:has(target:name()) then + table.insert(targets_root, target) + end + end + end + return targets_root +end + -- main function main() @@ -71,23 +161,34 @@ function main() -- inplace flag table.insert(argv, "-i") - -- set file to format + local targetname + local group_pattern = option.get("group") + if group_pattern then + group_pattern = "^" .. path.pattern(group_pattern) .. "$" + else + targetname = option.get("target") + end + + local targets = _get_targets(targetname, group_pattern) if option.get("files") then - local files = path.splitenv(option.get("files")) - for _, f in ipairs(files) do - local p = path.join(projectdir, f) - for _, filepath in ipairs(os.files(p)) do - table.insert(argv, filepath) + local filepatterns = _get_file_patterns(option.get("files")) + for _, target in ipairs(targets) do + for _, source in ipairs(target:sourcefiles()) do + if _match_sourcefiles(source, filepatterns) then + table.insert(argv, path.join(projectdir, source)) + end + end + for _, header in ipairs(target:headerfiles()) do + if _match_sourcefiles(header, filepatterns) then + table.insert(argv, path.join(projectdir, header)) + end end end else - -- format all source files of all targets - for targetname, target in pairs(project.targets()) do - -- source files + for _, target in ipairs(targets) do for _, source in ipairs(target:sourcefiles()) do table.insert(argv, path.join(projectdir, source)) end - -- header files for _, header in ipairs(target:headerfiles()) do table.insert(argv, path.join(projectdir, header)) end diff --git a/xmake/plugins/format/xmake.lua b/xmake/plugins/format/xmake.lua index ed2bf3d654b..7979bb21132 100644 --- a/xmake/plugins/format/xmake.lua +++ b/xmake/plugins/format/xmake.lua @@ -28,10 +28,20 @@ task("format") {'s', "style", "kv", nil, "Set the path of .clang-format file, a coding style", values = {"LLVM", "Google", "Chromium", "Mozilla", "WebKit"}}, {nil, "create", "k", nil, "Create a .clang-format file from a coding style"}, - {'f', "files", "v", nil, "Set files path with pattern", + {'g', "group", "kv", nil, "Format all targets of the given group. It support path pattern matching.", + "e.g.", + " xmake format -g test", + " xmake format -g test_*", + " xmake format --group=benchmark/*"}, + {'f', "files", "kv", nil, "Build the given source files.", "e.g.", - " - xmake format -f src/main.c", - " - xmake format -f 'src/*.c" .. path.envsep() .. "src/**.cpp'"} + " - xmake format --files=src/main.c", + " - xmake format --files='src/*.c' [target]", + " - xmake format --files='src/**.c|excluded_file.c", + " - xmake format --files='src/main.c" .. path.envsep() .. "src/test.c'" }, + {}, + {nil, "target", "v", nil, "The target name. It will format all default targets if this parameter is not specified." + , values = function (complete, opt) return import("private.utils.complete_helper.targets")(complete, opt) end } } }