-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathvpaths.lua
149 lines (122 loc) · 3.95 KB
/
vpaths.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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
---
-- Battle.net package management extension
-- Copyright (c) 2014-2016 Blizzard Entertainment
---
--
-- Given a source file path, return a corresponding virtual path based on
-- the vpath entries in the project. If no matching vpath entry is found,
-- the original path is returned.
--
local function blizzard_getvpath(prj, abspath)
-- if the vpaths table is empty, return the original filename.
if next(prj.vpaths) == nil then
return abspath
end
-- If there is no match, the result is the original filename
local vpath = abspath
-- The file's name must be maintained in the resulting path; use these
-- to make sure I don't cut off too much
local fname = path.getname(abspath)
local max = abspath:len() - fname:len()
-- Look for matching patterns. Virtual paths are stored as an array
-- for tables, each table continuing the path key, which looks up the
-- array of paths with should match against that path.
local function sort_by_length(a, b)
local lena = string.len(a)
local lenb = string.len(b)
if (lena == lenb) then
return a > b
end
return lena > lenb
end
-- cache patterns.
local keys = prj.cached_vpath_keys
local vpaths = prj.cached_vpaths
local wildcards = prj.cached_wildcards
local exacts = prj.cached_exacts
if not vpaths then
vpaths = {}
keys = {}
wildcards = {}
exacts = {}
-- flatten vpaths.
for _, v in ipairs(prj.vpaths) do
for replacement, patterns in pairs(v) do
for _, pattern in ipairs(patterns) do
if pattern:find("*", 1, true) == nil then
exacts[pattern] = replacement
else
vpaths[pattern] = replacement
end
end
end
end
-- sort keys by length, we want the longest most unique vpaths first.
for pattern, _ in pairs(vpaths) do
table.insert(keys, pattern)
end
table.sort(keys, sort_by_length)
-- cache wildcard results, path.wildcards is expensive!!!
for index, pattern in ipairs(keys) do
wildcards[index] = '^' .. path.wildcards(pattern) .. '$'
end
-- store result.
prj.cached_vpath_keys = keys
prj.cached_vpaths = vpaths
prj.cached_wildcards = wildcards
prj.cached_exacts = exacts
end
local function replace(pattern, abspath, replacement)
-- Trim out the part of the name that matched the pattern; what's
-- left is the part that gets appended to the replacement to make
-- the virtual path. So a pattern like "src/**.h" matching the
-- file src/include/hello.h, I want to trim out the src/ part,
-- leaving include/hello.h.
-- Find out where the wildcard appears in the match. If there is
-- no wildcard, the match includes the entire pattern
local i = pattern:find("*", 1, true) or (pattern:len() + 1)
-- Trim, taking care to keep the actual file name intact.
local leaf
if i < max then
leaf = abspath:sub(i)
else
leaf = fname
end
if leaf:startswith("/") then
leaf = leaf:sub(2)
end
-- check for (and remove) stars in the replacement pattern.
-- If there are none, then trim all path info from the leaf
-- and use just the filename in the replacement (stars should
-- really only appear at the end; I'm cheating here)
local stem = ""
if replacement:len() > 0 then
stem, stars = replacement:gsub("%*", "")
if stars == 0 then
leaf = path.getname(leaf)
end
else
leaf = path.getname(leaf)
end
return path.join(stem, leaf)
end
-- find exact matches.
local replacement = exacts[abspath]
if (replacement ~= nil) then
return replace(abspath, abspath, replacement)
end
-- enumerate wildcards matches.
for index, pattern in ipairs(keys) do
local i = abspath:find(wildcards[index])
if i == 1 then
return replace(pattern, abspath, vpaths[pattern])
end
end
return vpath
end
--
-- register the override.
--
premake.override(premake.project, "getvpath", function (base, prj, abspath)
return blizzard_getvpath(prj, abspath)
end)