annotate scripts/vsutil.py @ 3:949c4f536f26

Add `None` file items to source solution files.
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 24 Oct 2019 11:14:39 -0700
parents 5d2c0db51914
children ae0fb567f459
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
1 import copy
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
2 import logging
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
3 import os.path
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
4 import pickle
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
5 import re
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
6 import xml.etree.ElementTree as etree
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
7
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
8
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
9 # Known VS project types.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
10 PROJ_TYPE_FOLDER = '2150E333-8FDC-42A3-9474-1A3956D46DE8'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
11 PROJ_TYPE_NMAKE = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
12 PROJ_TYPE_CSHARP = 'FAE04EC0-301F-11D3-BF4B-00C04F79EFBC'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
13
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
14 PROJ_TYPE_NAMES = {
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
15 PROJ_TYPE_FOLDER: 'folder',
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
16 PROJ_TYPE_NMAKE: 'nmake',
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
17 PROJ_TYPE_CSHARP: 'csharp'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
18 }
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
19
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
20 # Known VS item types.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
21 ITEM_TYPE_CPP_SRC = 'ClCompile'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
22 ITEM_TYPE_CPP_HDR = 'ClInclude'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
23
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
24 ITEM_TYPE_CS_REF = 'Reference'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
25 ITEM_TYPE_CS_PROJREF = 'ProjectReference'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
26 ITEM_TYPE_CS_SRC = 'Compile'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
27
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
28 ITEM_TYPE_NONE = 'None'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
29
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
30 ITEM_TYPE_SOURCE_FILES = (ITEM_TYPE_CPP_SRC, ITEM_TYPE_CPP_HDR,
3
949c4f536f26 Add `None` file items to source solution files.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
31 ITEM_TYPE_CS_SRC, ITEM_TYPE_NONE)
0
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
32
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
33
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
34 # Known VS properties.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
35 PROP_CONFIGURATION_TYPE = 'ConfigurationType'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
36 PROP_NMAKE_PREPROCESSOR_DEFINITIONS = 'NMakePreprocessorDefinitions'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
37 PROP_NMAKE_INCLUDE_SEARCH_PATH = 'NMakeIncludeSearchPath'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
38
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
39
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
40 logger = logging.getLogger(__name__)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
41
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
42
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
43 def _strip_ns(tag):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
44 """ Remove the XML namespace from a tag name. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
45 if tag[0] == '{':
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
46 i = tag.index('}')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
47 return tag[i+1:]
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
48 return tag
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
49
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
50
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
51 re_msbuild_var = re.compile(r'\$\((?P<var>[\w\d_]+)\)')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
52
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
53
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
54 def _resolve_value(val, env):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
55 """ Expands MSBuild property values given a build environment. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
56 def _repl_vars(m):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
57 varname = m.group('var')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
58 varval = env.get(varname, '')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
59 return varval
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
60
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
61 if not val:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
62 return val
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
63 return re_msbuild_var.sub(_repl_vars, val)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
64
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
65
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
66 def _evaluate_condition(cond, env):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
67 """ Expands MSBuild property values in a condition and evaluates it. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
68 left, right = _resolve_value(cond, env).split('==')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
69 return left == right
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
70
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
71
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
72 class VSBaseGroup:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
73 """ Base class for VS project stuff that has conditional stuff inside.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
74
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
75 For instance, a property group called 'Blah' might have some common
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
76 (always valid) stuff, but a bunch of other stuff that should only
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
77 be considered when the solution configuration is Debug, Release, or
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
78 whatever else. In that case, each 'conditional' (i.e. values for Debug,
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
79 values for Release, etc.) is listed and tracked separately until
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
80 we are asked to 'resolve' ourselves based on a given build environment.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
81 """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
82 def __init__(self, label):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
83 self.label = label
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
84 self.conditionals = {}
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
85
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
86 def get_conditional(self, condition):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
87 """ Adds a conditional sub-group. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
88 return self.conditionals.get(condition)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
89
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
90 def get_or_create_conditional(self, condition):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
91 """ Gets or creates a new conditional sub-group. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
92 c = self.get_conditional(condition)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
93 if not c:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
94 c = self.__class__(self.label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
95 self.conditionals[condition] = c
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
96 return c
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
97
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
98 def resolve(self, env):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
99 """ Resolves this group by evaluating each conditional sub-group
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
100 based on the given build environment. Returns a 'flattened'
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
101 version of ourselves.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
102 """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
103 c = self.__class__(self.label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
104 c._collapse_child(self, env)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
105
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
106 for cond, child in self.conditionals.items():
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
107 if _evaluate_condition(cond, env):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
108 c._collapse_child(child, env)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
109
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
110 return c
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
111
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
112
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
113 class VSProjectItem:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
114 """ A VS project item, like a source code file. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
115 def __init__(self, include, itemtype=None):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
116 self.include = include
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
117 self.itemtype = itemtype
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
118 self.metadata = {}
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
119
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
120 def resolve(self, env):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
121 c = VSProjectItem(_resolve_value(self.include), self.itemtype)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
122 c.metadata = {k: _resolve_value(v, env)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
123 for k, v in self.metadata.items()}
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
124 return c
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
125
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
126 def __str__(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
127 return "(%s)%s" % (self.itemtype, self.include)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
128
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
129
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
130 class VSProjectItemGroup(VSBaseGroup):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
131 """ A VS project item group, like a list of source code files,
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
132 or a list of resources.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
133 """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
134 def __init__(self, label):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
135 super().__init__(label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
136 self.items = []
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
137
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
138 def get_source_items(self):
3
949c4f536f26 Add `None` file items to source solution files.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
139 return self.get_items_of_types(ITEM_TYPE_SOURCE_FILES)
949c4f536f26 Add `None` file items to source solution files.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
140
949c4f536f26 Add `None` file items to source solution files.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
141 def get_items_of_types(self, *itemtypes):
949c4f536f26 Add `None` file items to source solution files.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
142 typeset = set(*itemtypes)
0
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
143 for i in self.items:
3
949c4f536f26 Add `None` file items to source solution files.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
144 if i.itemtype in typeset:
0
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
145 yield i
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
146
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
147 def _collapse_child(self, child, env):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
148 self.items += [i.resolve(env) for i in child.items]
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
149
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
150
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
151 class VSProjectProperty:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
152 """ A VS project property, like an include path or compiler flag. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
153 def __init__(self, name, value):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
154 self.name = name
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
155 self.value = value
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
156
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
157 def resolve(self, env):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
158 c = VSProjectProperty(self.name, _resolve_value(self.value, env))
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
159 return c
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
160
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
161 def __str__(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
162 return "%s=%s" % (self.name, self.value)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
163
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
164
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
165 class VSProjectPropertyGroup(VSBaseGroup):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
166 """ A VS project property group, such as compiler macros or flags. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
167 def __init__(self, label):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
168 super().__init__(label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
169 self.properties = []
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
170
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
171 def get(self, propname):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
172 try:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
173 return self[propname]
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
174 except IndexError:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
175 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
176
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
177 def __getitem__(self, propname):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
178 for p in self.properties:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
179 if p.name == propname:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
180 return p.value
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
181 raise IndexError()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
182
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
183 def _collapse_child(self, child, env):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
184 self.properties += [p.resolve(env) for p in child.properties]
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
185
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
186
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
187 class VSProject:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
188 """ A VS project. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
189 def __init__(self, projtype, name, path, guid):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
190 self.type = projtype
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
191 self.name = name
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
192 self.path = path
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
193 self.guid = guid
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
194 self._itemgroups = None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
195 self._propgroups = None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
196 self._sln = None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
197
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
198 @property
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
199 def is_folder(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
200 """ Returns whether this project is actually just a solution
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
201 folder, used as a container for other projects.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
202 """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
203 return self.type == PROJ_TYPE_FOLDER
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
204
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
205 @property
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
206 def abspath(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
207 abspath = self.path
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
208 if self._sln and self._sln.path:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
209 abspath = os.path.join(self._sln.dirpath, self.path)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
210 return abspath
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
211
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
212 @property
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
213 def absdirpath(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
214 return os.path.dirname(self.abspath)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
215
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
216 @property
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
217 def itemgroups(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
218 self._ensure_loaded()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
219 return self._itemgroups.values()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
220
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
221 @property
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
222 def propertygroups(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
223 self._ensure_loaded()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
224 return self._propgroups.values()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
225
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
226 def itemgroup(self, label, resolved_with=None):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
227 self._ensure_loaded()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
228 ig = self._itemgroups.get(label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
229 if resolved_with is not None and ig is not None:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
230 logger.debug("Resolving item group '%s'." % ig.label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
231 ig = ig.resolve(resolved_with)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
232 return ig
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
233
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
234 def defaultitemgroup(self, resolved_with=None):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
235 return self.itemgroup(None, resolved_with=resolved_with)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
236
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
237 def propertygroup(self, label, resolved_with=None):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
238 self._ensure_loaded()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
239 pg = self._propgroups.get(label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
240 if resolved_with is not None and pg is not None:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
241 logger.debug("Resolving property group '%s'." % pg.label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
242 pg = pg.resolve(resolved_with)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
243 return pg
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
244
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
245 def defaultpropertygroup(self, resolved_with=None):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
246 return self.propertygroup(None, resolved_with=resolved_with)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
247
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
248 def get_abs_item_include(self, item):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
249 return os.path.abspath(os.path.join(self.absdirpath, item.include))
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
250
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
251 def resolve(self, env):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
252 self._ensure_loaded()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
253
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
254 propgroups = list(self._propgroups)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
255 itemgroups = list(self._itemgroups)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
256 self._propgroups[:] = []
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
257 self._itemgroups[:] = []
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
258
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
259 for pg in propgroups:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
260 rpg = pg.resolve(env)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
261 self._propgroups.append(rpg)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
262
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
263 for ig in itemgroups:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
264 rig = ig.resolve(env)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
265 self._itemgroups.append(rig)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
266
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
267 def _ensure_loaded(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
268 if self._itemgroups is None or self._propgroups is None:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
269 self._load()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
270
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
271 def _load(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
272 if not self.path:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
273 raise Exception("The current project has no path.")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
274 if self.is_folder:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
275 logger.debug(f"Skipping folder project {self.name}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
276 self._itemgroups = {}
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
277 self._propgroups = {}
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
278 return
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
279
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
280 ns = {'ms': 'http://schemas.microsoft.com/developer/msbuild/2003'}
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
281
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
282 abspath = self.abspath
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
283 logger.debug(f"Loading project {self.name} ({self.path}) from: {abspath}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
284 tree = etree.parse(abspath)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
285 root = tree.getroot()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
286 if _strip_ns(root.tag) != 'Project':
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
287 raise Exception(f"Expected root node 'Project', got '{root.tag}'")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
288
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
289 self._itemgroups = {}
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
290 for itemgroupnode in root.iterfind('ms:ItemGroup', ns):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
291 label = itemgroupnode.attrib.get('Label')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
292 itemgroup = self._itemgroups.get(label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
293 if not itemgroup:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
294 itemgroup = VSProjectItemGroup(label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
295 self._itemgroups[label] = itemgroup
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
296 logger.debug(f"Adding itemgroup '{label}'")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
297
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
298 condition = itemgroupnode.attrib.get('Condition')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
299 if condition:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
300 itemgroup = itemgroup.get_or_create_conditional(condition)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
301
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
302 for itemnode in itemgroupnode:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
303 incval = itemnode.attrib.get('Include')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
304 item = VSProjectItem(incval, _strip_ns(itemnode.tag))
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
305 itemgroup.items.append(item)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
306 for metanode in itemnode:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
307 item.metadata[_strip_ns(metanode.tag)] = metanode.text
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
308
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
309 self._propgroups = {}
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
310 for propgroupnode in root.iterfind('ms:PropertyGroup', ns):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
311 label = propgroupnode.attrib.get('Label')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
312 propgroup = self._propgroups.get(label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
313 if not propgroup:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
314 propgroup = VSProjectPropertyGroup(label)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
315 self._propgroups[label] = propgroup
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
316 logger.debug(f"Adding propertygroup '{label}'")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
317
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
318 condition = propgroupnode.attrib.get('Condition')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
319 if condition:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
320 propgroup = propgroup.get_or_create_conditional(condition)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
321
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
322 for propnode in propgroupnode:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
323 propgroup.properties.append(VSProjectProperty(
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
324 _strip_ns(propnode.tag),
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
325 propnode.text))
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
326
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
327
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
328 class MissingVSProjectError(Exception):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
329 pass
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
330
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
331
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
332 class VSGlobalSectionEntry:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
333 """ An entry in a VS solution's global section. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
334 def __init__(self, name, value):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
335 self.name = name
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
336 self.value = value
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
337
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
338
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
339 class VSGlobalSection:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
340 """ A global section in a VS solution. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
341 def __init__(self, name):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
342 self.name = name
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
343 self.entries = []
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
344
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
345
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
346 class VSSolution:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
347 """ A VS solution. """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
348 def __init__(self, path=None):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
349 self.path = path
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
350 self.projects = []
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
351 self.sections = []
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
352
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
353 @property
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
354 def dirpath(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
355 return os.path.dirname(self.path)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
356
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
357 def find_project_by_name(self, name, missing_ok=True):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
358 for p in self.projects:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
359 if p.name == name:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
360 return p
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
361 if missing_ok:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
362 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
363 return MissingVSProjectError(f"Can't find project with name: {name}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
364
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
365 def find_project_by_path(self, path, missing_ok=True):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
366 for p in self.projects:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
367 if p.abspath == path:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
368 return p
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
369 if missing_ok:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
370 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
371 raise MissingVSProjectError(f"Can't find project with path: {path}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
372
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
373 def find_project_by_guid(self, guid, missing_ok=True):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
374 for p in self.projects:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
375 if p.guid == guid:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
376 return p
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
377 if missing_ok:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
378 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
379 raise MissingVSProjectError(f"Can't find project for guid: {guid}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
380
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
381 def globalsection(self, name):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
382 for sec in self.sections:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
383 if sec.name == name:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
384 return sec
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
385 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
386
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
387 def find_project_configuration(self, proj_guid, sln_config):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
388 configs = self.globalsection('ProjectConfigurationPlatforms')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
389 if not configs:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
390 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
391
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
392 entry_name = '{%s}.%s.Build.0' % (proj_guid, sln_config)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
393 for entry in configs.entries:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
394 if entry.name == entry_name:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
395 return entry.value
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
396 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
397
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
398
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
399 _re_sln_project_decl_start = re.compile(
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
400 r'^Project\("\{(?P<type>[A-Z0-9\-]+)\}"\) \= '
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
401 r'"(?P<name>[^"]+)", "(?P<path>[^"]+)", "\{(?P<guid>[A-Z0-9\-]+)\}"$')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
402 _re_sln_project_decl_end = re.compile(
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
403 r'^EndProject$')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
404
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
405 _re_sln_global_start = re.compile(r'^Global$')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
406 _re_sln_global_end = re.compile(r'^EndGlobal$')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
407 _re_sln_global_section_start = re.compile(
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
408 r'^\s*GlobalSection\((?P<name>\w+)\) \= (?P<step>\w+)$')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
409 _re_sln_global_section_end = re.compile(r'^\s*EndGlobalSection$')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
410
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
411
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
412 def parse_sln_file(slnpath):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
413 """ Parses a solution file, returns a solution object.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
414 The projects are not loaded (they will be lazily loaded upon
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
415 first access to their items/properties/etc.).
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
416 """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
417 logging.debug(f"Reading {slnpath}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
418 slnobj = VSSolution(slnpath)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
419 with open(slnpath, 'r') as fp:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
420 lines = fp.readlines()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
421 _parse_sln_file_text(slnobj, lines)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
422 return slnobj
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
423
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
424
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
425 def _parse_sln_file_text(slnobj, lines):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
426 until = None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
427 in_global = False
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
428 in_global_section = None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
429
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
430 for i, line in enumerate(lines):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
431 if until:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
432 # We need to parse something until a given token, so let's
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
433 # do that and ignore everything else.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
434 m = until.search(line)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
435 if m:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
436 until = None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
437 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
438
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
439 if in_global:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
440 # We're in the 'global' part of the solution. It should contain
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
441 # a bunch of 'global sections' that we need to parse individually.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
442 if in_global_section:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
443 # Keep parsing the current section until we reach the end.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
444 m = _re_sln_global_section_end.search(line)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
445 if m:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
446 in_global_section = None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
447 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
448
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
449 ename, evalue = line.strip().split('=')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
450 in_global_section.entries.append(VSGlobalSectionEntry(
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
451 ename.strip(),
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
452 evalue.strip()))
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
453 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
454
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
455 m = _re_sln_global_section_start.search(line)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
456 if m:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
457 # Found the start of a new section.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
458 in_global_section = VSGlobalSection(m.group('name'))
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
459 logging.debug(f" Adding global section {in_global_section.name}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
460 slnobj.sections.append(in_global_section)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
461 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
462
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
463 m = _re_sln_global_end.search(line)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
464 if m:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
465 # Found the end of the 'global' part.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
466 in_global = False
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
467 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
468
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
469 # We're not in a specific part of the solution, so do high-level
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
470 # parsing. First, ignore root-level comments.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
471 if not line or line[0] == '#':
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
472 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
473
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
474 m = _re_sln_project_decl_start.search(line)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
475 if m:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
476 # Found the start of a project declaration.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
477 try:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
478 p = VSProject(
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
479 m.group('type'), m.group('name'), m.group('path'),
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
480 m.group('guid'))
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
481 except:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
482 raise Exception(f"Error line {i}: unexpected project syntax.")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
483 logging.debug(f" Adding project {p.name}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
484 slnobj.projects.append(p)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
485 p._sln = slnobj
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
486
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
487 until = _re_sln_project_decl_end
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
488 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
489
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
490 m = _re_sln_global_start.search(line)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
491 if m:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
492 # Reached the start of the 'global' part, where global sections
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
493 # are defined.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
494 in_global = True
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
495 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
496
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
497 # Ignore the rest (like visual studio version flags).
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
498 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
499
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
500
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
501 class SolutionCache:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
502 """ A class that contains a VS solution object, along with pre-indexed
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
503 lists of items. It's meant to be saved on disk.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
504 """
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
505 VERSION = 3
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
506
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
507 def __init__(self, slnobj):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
508 self.slnobj = slnobj
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
509 self.index = None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
510
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
511 def build_cache(self):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
512 self.index = {}
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
513 for proj in self.slnobj.projects:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
514 if proj.is_folder:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
515 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
516 itemgroup = proj.defaultitemgroup()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
517 if not itemgroup:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
518 continue
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
519
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
520 item_cache = set()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
521 self.index[proj.abspath] = item_cache
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
522
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
523 for item in itemgroup.get_source_items():
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
524 item_path = proj.get_abs_item_include(item).lower()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
525 item_cache.add(item_path)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
526
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
527 def save(self, path):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
528 pathdir = os.path.dirname(path)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
529 if not os.path.exists(pathdir):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
530 os.makedirs(pathdir)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
531 with open(path, 'wb') as fp:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
532 pickle.dump(self, fp)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
533
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
534 @staticmethod
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
535 def load_or_rebuild(slnpath, cachepath):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
536 if cachepath:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
537 res = _try_load_from_cache(slnpath, cachepath)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
538 if res is not None:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
539 return res
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
540
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
541 slnobj = parse_sln_file(slnpath)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
542 cache = SolutionCache(slnobj)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
543
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
544 if cachepath:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
545 logger.debug(f"Regenerating cache: {cachepath}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
546 cache.build_cache()
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
547 cache.save(cachepath)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
548
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
549 return (cache, False)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
550
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
551
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
552 def _try_load_from_cache(slnpath, cachepath):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
553 try:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
554 sln_dt = os.path.getmtime(slnpath)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
555 cache_dt = os.path.getmtime(cachepath)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
556 except OSError:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
557 logger.debug("Can't read solution or cache files.")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
558 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
559
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
560 # If the solution file is newer, bail out.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
561 if sln_dt >= cache_dt:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
562 logger.debug("Solution is newer than cache.")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
563 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
564
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
565 # Our cache is at least valid for the solution stuff. Some of our
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
566 # projects might be out of date, but at least there can't be any
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
567 # added or removed projects from the solution (otherwise the solution
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
568 # file would have been touched). Let's load the cache.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
569 with open(cachepath, 'rb') as fp:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
570 cache = pickle.load(fp)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
571
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
572 # Check that the cache version is up-to-date with this code.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
573 loaded_ver = getattr(cache, 'VERSION')
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
574 if loaded_ver != SolutionCache.VERSION:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
575 logger.debug(f"Cache was saved with older format: {cachepath}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
576 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
577
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
578 slnobj = cache.slnobj
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
579
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
580 # Check that none of the project files in the solution are newer
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
581 # than this cache.
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
582 proj_dts = []
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
583 for p in slnobj.projects:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
584 if not p.is_folder:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
585 try:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
586 proj_dts.append(os.path.getmtime(p.abspath))
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
587 except OSError:
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
588 logger.debug(f"Found missing project: {p.abspath}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
589 return None
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
590
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
591 if all([cache_dt > pdt for pdt in proj_dts]):
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
592 logger.debug(f"Cache is up to date: {cachepath}")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
593 return (cache, True)
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
594
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
595 logger.debug("Cache has outdated projects.")
5d2c0db51914 Initial commit
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
596 return None