4 # Christian Klein (chrikle@berlios.de)
6 # As templete for this file I used the msvs.py
7 # I hope this template will work proper
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions
14 1. Redistributions of source code must retain the above copyright
15 notice, this list of conditions and the following disclaimer.
17 2. Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
21 3. The name of the author may not be used to endorse or promote products
22 derived from this software without specific prior written permission.
24 THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
25 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
28 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
33 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 POSSIBILITY OF SUCH DAMAGE.
40 To add this tool to your project:
44 It can be a good idea to add the sync_exec tool too.
46 To generate solution files:
47 $ waf configure codelite
49 To customize the outputs, provide subclasses in your wscript files:
51 from waflib.extras import codelite
52 class vsnode_target(codelite.vsnode_target):
53 def get_build_command(self, props):
54 # likely to be required
55 return "waf.bat build"
56 def collect_source(self):
57 # likely to be required
59 class codelite_bar(codelite.codelite_generator):
61 codelite.codelite_generator.init(self)
62 self.vsnode_target = vsnode_target
64 The codelite class re-uses the same build() function for reading the targets (task generators),
65 you may therefore specify codelite settings on the context object:
68 bld.codelite_solution_name = 'foo.workspace'
69 bld.waf_command = 'waf.bat'
70 bld.projects_dir = bld.srcnode.make_node('')
71 bld.projects_dir.mkdir()
75 * a project can be either a directory or a target, project files are written only for targets that have source files
76 * each project is a vcxproj file, therefore the project uuid needs only to be a hash of the absolute path
80 import uuid
# requires python 2.5
81 from waflib
.Build
import BuildContext
82 from waflib
import Utils
, TaskGen
, Logs
, Task
, Context
, Node
, Options
84 HEADERS_GLOB
= '**/(*.h|*.hpp|*.H|*.inl)'
86 PROJECT_TEMPLATE
= r
'''<?xml version="1.0" encoding="utf-8"?>
87 <CodeLite_Project Name="${project.name}" InternalType="Library">
90 <![CDATA[00010001N0005Release000000000000]]>
95 <VirtualDirectory Name="src">
96 ${for x in project.source}
97 ${if (project.get_key(x)=="sourcefile")}
98 <File Name="${x.abspath()}"/>
102 <VirtualDirectory Name="include">
103 ${for x in project.source}
104 ${if (project.get_key(x)=="headerfile")}
105 <File Name="${x.abspath()}"/>
109 <Settings Type="Dynamic Library">
111 <Compiler Options="" C_Options="">
112 <IncludePath Value="."/>
115 <LibraryPath Value="."/>
117 <ResourceCompiler Options=""/>
119 <Configuration Name="Release" CompilerType="gnu gcc" ReleasegerType="GNU gdb Releaseger" Type="Dynamic Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
120 <Compiler Options="" C_Options="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
121 <IncludePath Value="."/>
122 <IncludePath Value="."/>
124 <Linker Options="" Required="yes">
125 <LibraryPath Value=""/>
127 <ResourceCompiler Options="" Required="no"/>
128 <General OutputFile="${xml:project.build_properties[0].output_file}" IntermediateDirectory="" Command="" CommandArguments="" PauseExecWhenProcTerminates="yes"/>
129 <Environment EnvVarSetName="<Use Defaults>" DbgSetName="<Use Defaults>">
132 <Releaseger IsRemote="no" RemoteHostName="" RemoteHostPort="" ReleasegerPath="">
133 <PostConnectCommands/>
138 <CustomBuild Enabled="yes">
139 $b = project.build_properties[0]}
140 <RebuildCommand>${xml:project.get_rebuild_command(project.build_properties[0])}</RebuildCommand>
141 <CleanCommand>${xml:project.get_clean_command(project.build_properties[0])}</CleanCommand>
142 <BuildCommand>${xml:project.get_build_command(project.build_properties[0])}</BuildCommand>
143 <Target Name="Install">${xml:project.get_install_command(project.build_properties[0])}</Target>
144 <Target Name="Build and Install">${xml:project.get_build_and_install_command(project.build_properties[0])}</Target>
145 <Target Name="Build All">${xml:project.get_build_all_command(project.build_properties[0])}</Target>
146 <Target Name="Rebuild All">${xml:project.get_rebuild_all_command(project.build_properties[0])}</Target>
147 <Target Name="Clean All">${xml:project.get_clean_all_command(project.build_properties[0])}</Target>
148 <Target Name="Build and Install All">${xml:project.get_build_and_install_all_command(project.build_properties[0])}</Target>
149 <PreprocessFileCommand/>
151 <MakefileGenerationCommand/>
152 <ThirdPartyToolName>None</ThirdPartyToolName>
165 <Configuration Name="Release" CompilerType="gnu gcc" ReleasegerType="GNU gdb Releaseger" Type="" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
166 <Compiler Options="" C_Options="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
167 <IncludePath Value="."/>
169 <Linker Options="" Required="yes"/>
170 <ResourceCompiler Options="" Required="no"/>
171 <General OutputFile="" IntermediateDirectory="./Release" Command="" CommandArguments="" UseSeparateReleaseArgs="no" ReleaseArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/>
172 <Environment EnvVarSetName="<Use Defaults>" DbgSetName="<Use Defaults>">
179 <Releaseger IsRemote="no" RemoteHostName="" RemoteHostPort="" ReleasegerPath="">
180 <PostConnectCommands/>
185 <CustomBuild Enabled="no">
189 <PreprocessFileCommand/>
191 <MakefileGenerationCommand/>
192 <ThirdPartyToolName/>
206 </CodeLite_Project>'''
211 SOLUTION_TEMPLATE
= '''<?xml version="1.0" encoding="utf-8"?>
212 <CodeLite_Workspace Name="${getattr(project, 'codelite_solution_name', None)[:-10]}" Database="./${getattr(project, 'codelite_solution_name', None)[:-10]}.tags">
213 ${for p in project.all_projects}
214 <Project Name = "${p.name}" Path = "${p.title}" Active="No"/>
217 <WorkspaceConfiguration Name="Release" Selected="yes">
218 ${for p in project.all_projects}
219 <Project Name="${p.name}" ConfigName="Release"/>
221 </WorkspaceConfiguration>
223 </CodeLite_Workspace>'''
227 COMPILE_TEMPLATE
= '''def f(project):
229 def xml_escape(value):
230 return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">")
234 #f = open('cmd.txt', 'w')
239 reg_act
= re
.compile(r
"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<code>[^}]*?)\})", re
.M
)
240 def compile_template(line
):
242 Compile a template expression into a python function (like jsps, but way shorter)
252 extr
.append(g('code'))
256 line2
= reg_act
.sub(repl
, line
)
257 params
= line2
.split('<<|@|>>')
266 buf
.append(indent
* '\t' + txt
)
268 for x
in range(len(extr
)):
270 app("lst.append(%r)" % params
[x
])
273 if f
.startswith(('if', 'for')):
276 elif f
.startswith('py:'):
278 elif f
.startswith(('endif', 'endfor')):
280 elif f
.startswith(('else', 'elif')):
284 elif f
.startswith('xml:'):
285 app('lst.append(xml_escape(%s))' % f
[4:])
287 #app('lst.append((%s) or "cannot find %s")' % (f, f))
288 app('lst.append(%s)' % f
)
292 app("lst.append(%r)" % params
[-1])
294 fun
= COMPILE_TEMPLATE
% "\n\t".join(buf
)
296 return Task
.funex(fun
)
299 re_blank
= re
.compile('(\n|\r|\\s)*\n', re
.M
)
300 def rm_blank_lines(txt
):
301 txt
= re_blank
.sub('\r\n', txt
)
306 BOM
= bytes(BOM
, 'latin-1') # python 3
307 except (TypeError, NameError):
310 def stealth_write(self
, data
, flags
='wb'):
314 data
= data
.encode('utf-8') # python 3
316 data
= data
.decode(sys
.getfilesystemencoding(), 'replace')
317 data
= data
.encode('utf-8')
319 if self
.name
.endswith('.project'):
323 txt
= self
.read(flags
='rb')
325 raise ValueError('must write')
326 except (IOError, ValueError):
327 self
.write(data
, flags
=flags
)
329 Logs
.debug('codelite: skipping %r', self
)
330 Node
.Node
.stealth_write
= stealth_write
332 re_quote
= re
.compile("[^a-zA-Z0-9-]")
334 return re_quote
.sub("_", s
)
336 def xml_escape(value
):
337 return value
.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">")
339 def make_uuid(v
, prefix
= None):
341 simple utility function
343 if isinstance(v
, dict):
344 keys
= list(v
.keys())
346 tmp
= str([(k
, v
[k
]) for k
in keys
])
349 d
= Utils
.md5(tmp
.encode()).hexdigest().upper()
351 d
= '%s%s' % (prefix
, d
[8:])
352 gid
= uuid
.UUID(d
, version
= 4)
353 return str(gid
).upper()
355 def diff(node
, fromnode
):
356 # difference between two nodes, but with "(..)" instead of ".."
376 while id(c1
) != id(c2
):
388 class build_property(object):
391 class vsnode(object):
393 Abstract class representing visual studio elements
394 We assume that all visual studio nodes have a uuid and a parent
396 def __init__(self
, ctx
):
397 self
.ctx
= ctx
# codelite context
398 self
.name
= '' # string, mandatory
399 self
.vspath
= '' # path in visual studio (name for dirs, absolute path for projects)
400 self
.uuid
= '' # string, mandatory
401 self
.parent
= None # parent node for visual studio nesting
405 Override in subclasses...
407 return '%s/%s' % (self
.ctx
.srcnode
.abspath(), getattr(self
.ctx
, 'waf_command', 'waf'))
411 Return a special uuid for projects written in the solution file
417 Write the project file, by default, do nothing
421 def make_uuid(self
, val
):
423 Alias for creating uuid values easily (the templates cannot access global variables)
425 return make_uuid(val
)
427 class vsnode_vsdir(vsnode
):
429 Nodes representing visual studio folders (which do not match the filesystem tree!)
431 VS_GUID_SOLUTIONFOLDER
= "2150E333-8FDC-42A3-9474-1A3956D46DE8"
432 def __init__(self
, ctx
, uuid
, name
, vspath
=''):
433 vsnode
.__init
__(self
, ctx
)
434 self
.title
= self
.name
= name
436 self
.vspath
= vspath
or name
439 return self
.VS_GUID_SOLUTIONFOLDER
441 class vsnode_project(vsnode
):
443 Abstract class representing visual studio project elements
444 A project is assumed to be writable, and has a node representing the file to write to
446 VS_GUID_VCPROJ
= "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
448 return self
.VS_GUID_VCPROJ
450 def __init__(self
, ctx
, node
):
451 vsnode
.__init
__(self
, ctx
)
453 self
.uuid
= make_uuid(node
.abspath())
454 self
.name
= node
.name
455 self
.title
= self
.path
.abspath()
456 self
.source
= [] # list of node objects
457 self
.build_properties
= [] # list of properties (nmake commands, output dir, etc)
461 Get the list of parent folders of the source files (header files included)
462 for writing the filters
466 if x
.height() > self
.tg
.path
.height() and x
not in lst
:
469 for x
in self
.source
:
474 Logs
.debug('codelite: creating %r', self
.path
)
475 #print "self.name:",self.name
477 # first write the project file
478 template1
= compile_template(PROJECT_TEMPLATE
)
479 proj_str
= template1(self
)
480 proj_str
= rm_blank_lines(proj_str
)
481 self
.path
.stealth_write(proj_str
)
483 # then write the filter
484 #template2 = compile_template(FILTER_TEMPLATE)
485 #filter_str = template2(self)
486 #filter_str = rm_blank_lines(filter_str)
487 #tmp = self.path.parent.make_node(self.path.name + '.filters')
488 #tmp.stealth_write(filter_str)
490 def get_key(self
, node
):
492 required for writing the source files
495 if name
.endswith(('.cpp', '.c')):
499 def collect_properties(self
):
501 Returns a list of triplet (configuration, platform, output_directory)
504 for c
in self
.ctx
.configurations
:
505 for p
in self
.ctx
.platforms
:
512 x
.preprocessor_definitions
= ''
513 x
.includes_search_path
= ''
515 # can specify "deploy_dir" too
517 self
.build_properties
= ret
519 def get_build_params(self
, props
):
521 return (self
.get_waf(), opt
)
523 def get_build_command(self
, props
):
524 return "%s build %s" % self
.get_build_params(props
)
526 def get_clean_command(self
, props
):
527 return "%s clean %s" % self
.get_build_params(props
)
529 def get_rebuild_command(self
, props
):
530 return "%s clean build %s" % self
.get_build_params(props
)
532 def get_install_command(self
, props
):
533 return "%s install %s" % self
.get_build_params(props
)
534 def get_build_and_install_command(self
, props
):
535 return "%s build install %s" % self
.get_build_params(props
)
537 def get_build_and_install_all_command(self
, props
):
538 return "%s build install" % self
.get_build_params(props
)[0]
540 def get_clean_all_command(self
, props
):
541 return "%s clean" % self
.get_build_params(props
)[0]
543 def get_build_all_command(self
, props
):
544 return "%s build" % self
.get_build_params(props
)[0]
546 def get_rebuild_all_command(self
, props
):
547 return "%s clean build" % self
.get_build_params(props
)[0]
549 def get_filter_name(self
, node
):
550 lst
= diff(node
, self
.tg
.path
)
551 return '\\'.join(lst
) or '.'
553 class vsnode_alias(vsnode_project
):
554 def __init__(self
, ctx
, node
, name
):
555 vsnode_project
.__init
__(self
, ctx
, node
)
557 self
.output_file
= ''
559 class vsnode_build_all(vsnode_alias
):
561 Fake target used to emulate the behaviour of "make all" (starting one process by target is slow)
562 This is the only alias enabled by default
564 def __init__(self
, ctx
, node
, name
='build_all_projects'):
565 vsnode_alias
.__init
__(self
, ctx
, node
, name
)
566 self
.is_active
= True
568 class vsnode_install_all(vsnode_alias
):
570 Fake target used to emulate the behaviour of "make install"
572 def __init__(self
, ctx
, node
, name
='install_all_projects'):
573 vsnode_alias
.__init
__(self
, ctx
, node
, name
)
575 def get_build_command(self
, props
):
576 return "%s build install %s" % self
.get_build_params(props
)
578 def get_clean_command(self
, props
):
579 return "%s clean %s" % self
.get_build_params(props
)
581 def get_rebuild_command(self
, props
):
582 return "%s clean build install %s" % self
.get_build_params(props
)
584 class vsnode_project_view(vsnode_alias
):
586 Fake target used to emulate a file system view
588 def __init__(self
, ctx
, node
, name
='project_view'):
589 vsnode_alias
.__init
__(self
, ctx
, node
, name
)
590 self
.tg
= self
.ctx() # fake one, cannot remove
591 self
.exclude_files
= Node
.exclude_regs
+ '''
600 ''' % Options
.lockfile
602 def collect_source(self
):
603 # this is likely to be slow
604 self
.source
= self
.ctx
.srcnode
.ant_glob('**', excl
=self
.exclude_files
)
606 def get_build_command(self
, props
):
607 params
= self
.get_build_params(props
) + (self
.ctx
.cmd
,)
608 return "%s %s %s" % params
610 def get_clean_command(self
, props
):
613 def get_rebuild_command(self
, props
):
614 return self
.get_build_command(props
)
616 class vsnode_target(vsnode_project
):
618 CodeLite project representing a targets (programs, libraries, etc) and bound
621 def __init__(self
, ctx
, tg
):
623 A project is more or less equivalent to a file/folder
625 base
= getattr(ctx
, 'projects_dir', None) or tg
.path
626 node
= base
.make_node(quote(tg
.name
) + ctx
.project_extension
) # the project file as a Node
627 vsnode_project
.__init
__(self
, ctx
, node
)
628 self
.name
= quote(tg
.name
)
629 self
.tg
= tg
# task generator
631 def get_build_params(self
, props
):
633 Override the default to add the target name
636 if getattr(self
, 'tg', None):
637 opt
+= " --targets=%s" % self
.tg
.name
638 return (self
.get_waf(), opt
)
640 def collect_source(self
):
642 source_files
= tg
.to_nodes(getattr(tg
, 'source', []))
643 include_dirs
= Utils
.to_list(getattr(tg
, 'codelite_includes', []))
645 for x
in include_dirs
:
646 if isinstance(x
, str):
647 x
= tg
.path
.find_node(x
)
649 lst
= [y
for y
in x
.ant_glob(HEADERS_GLOB
, flat
=False)]
650 include_files
.extend(lst
)
653 self
.source
.extend(list(set(source_files
+ include_files
)))
654 self
.source
.sort(key
=lambda x
: x
.abspath())
656 def collect_properties(self
):
658 CodeLite projects are associated with platforms and configurations (for building especially)
660 super(vsnode_target
, self
).collect_properties()
661 for x
in self
.build_properties
:
662 x
.outdir
= self
.path
.parent
.abspath()
663 x
.preprocessor_definitions
= ''
664 x
.includes_search_path
= ''
667 tsk
= self
.tg
.link_task
668 except AttributeError:
671 x
.output_file
= tsk
.outputs
[0].abspath()
672 x
.preprocessor_definitions
= ';'.join(tsk
.env
.DEFINES
)
673 x
.includes_search_path
= ';'.join(self
.tg
.env
.INCPATHS
)
675 class codelite_generator(BuildContext
):
676 '''generates a CodeLite workspace'''
682 Some data that needs to be present
684 if not getattr(self
, 'configurations', None):
685 self
.configurations
= ['Release'] # LocalRelease, RemoteDebug, etc
686 if not getattr(self
, 'platforms', None):
687 self
.platforms
= ['Win32']
688 if not getattr(self
, 'all_projects', None):
689 self
.all_projects
= []
690 if not getattr(self
, 'project_extension', None):
691 self
.project_extension
= '.project'
692 if not getattr(self
, 'projects_dir', None):
693 self
.projects_dir
= self
.srcnode
.make_node('')
694 self
.projects_dir
.mkdir()
696 # bind the classes to the object, so that subclass can provide custom generators
697 if not getattr(self
, 'vsnode_vsdir', None):
698 self
.vsnode_vsdir
= vsnode_vsdir
699 if not getattr(self
, 'vsnode_target', None):
700 self
.vsnode_target
= vsnode_target
701 if not getattr(self
, 'vsnode_build_all', None):
702 self
.vsnode_build_all
= vsnode_build_all
703 if not getattr(self
, 'vsnode_install_all', None):
704 self
.vsnode_install_all
= vsnode_install_all
705 if not getattr(self
, 'vsnode_project_view', None):
706 self
.vsnode_project_view
= vsnode_project_view
708 self
.numver
= '11.00'
716 if not self
.all_envs
:
718 self
.recurse([self
.run_dir
])
720 # user initialization
723 # two phases for creating the solution
724 self
.collect_projects() # add project objects into "self.all_projects"
725 self
.write_files() # write the corresponding project and solution files
727 def collect_projects(self
):
729 Fill the list self.all_projects with project objects
730 Fill the list of build targets
732 self
.collect_targets()
735 default_project
= getattr(self
, 'default_project', None)
737 if x
.name
== default_project
:
739 return getattr(x
, 'path', None) and x
.path
.abspath() or x
.name
740 self
.all_projects
.sort(key
=sortfun
)
742 def write_files(self
):
744 Write the project and solution files from the data collected
745 so far. It is unlikely that you will want to change this
747 for p
in self
.all_projects
:
750 # and finally write the solution file
751 node
= self
.get_solution_node()
753 Logs
.warn('Creating %r', node
)
757 #print self.group_names
758 #print "Hallo2: ",self.root.listdir()
759 #print getattr(self, 'codelite_solution_name', None)
760 template1
= compile_template(SOLUTION_TEMPLATE
)
761 sln_str
= template1(self
)
762 sln_str
= rm_blank_lines(sln_str
)
763 node
.stealth_write(sln_str
)
765 def get_solution_node(self
):
767 The solution filename is required when writing the .vcproj files
768 return self.solution_node and if it does not exist, make one
771 return self
.solution_node
775 codelite_solution_name
= getattr(self
, 'codelite_solution_name', None)
776 if not codelite_solution_name
:
777 codelite_solution_name
= getattr(Context
.g_module
, Context
.APPNAME
, 'project') + '.workspace'
778 setattr(self
, 'codelite_solution_name', codelite_solution_name
)
779 if os
.path
.isabs(codelite_solution_name
):
780 self
.solution_node
= self
.root
.make_node(codelite_solution_name
)
782 self
.solution_node
= self
.srcnode
.make_node(codelite_solution_name
)
783 return self
.solution_node
785 def project_configurations(self
):
787 Helper that returns all the pairs (config,platform)
790 for c
in self
.configurations
:
791 for p
in self
.platforms
:
795 def collect_targets(self
):
797 Process the list of task generators
799 for g
in self
.groups
:
801 if not isinstance(tg
, TaskGen
.task_gen
):
804 if not hasattr(tg
, 'codelite_includes'):
805 tg
.codelite_includes
= tg
.to_list(getattr(tg
, 'includes', [])) + tg
.to_list(getattr(tg
, 'export_includes', []))
807 if not getattr(tg
, 'link_task', None):
810 p
= self
.vsnode_target(self
, tg
)
811 p
.collect_source() # delegate this processing
812 p
.collect_properties()
813 self
.all_projects
.append(p
)
815 def add_aliases(self
):
817 Add a specific target that emulates the "make all" necessary for Visual studio when pressing F7
818 We also add an alias for "make install" (disabled by default)
820 base
= getattr(self
, 'projects_dir', None) or self
.tg
.path
822 node_project
= base
.make_node('build_all_projects' + self
.project_extension
) # Node
823 p_build
= self
.vsnode_build_all(self
, node_project
)
824 p_build
.collect_properties()
825 self
.all_projects
.append(p_build
)
827 node_project
= base
.make_node('install_all_projects' + self
.project_extension
) # Node
828 p_install
= self
.vsnode_install_all(self
, node_project
)
829 p_install
.collect_properties()
830 self
.all_projects
.append(p_install
)
832 node_project
= base
.make_node('project_view' + self
.project_extension
) # Node
833 p_view
= self
.vsnode_project_view(self
, node_project
)
834 p_view
.collect_source()
835 p_view
.collect_properties()
836 self
.all_projects
.append(p_view
)
838 n
= self
.vsnode_vsdir(self
, make_uuid(self
.srcnode
.abspath() + 'build_aliases'), "build_aliases")
839 p_build
.parent
= p_install
.parent
= p_view
.parent
= n
840 self
.all_projects
.append(n
)
842 def collect_dirs(self
):
844 Create the folder structure in the CodeLite project view
847 def make_parents(proj
):
848 # look at a project, try to make a parent
849 if getattr(proj
, 'parent', None):
850 # aliases already have parents
854 proj
.parent
= seen
[x
]
857 # There is not vsnode_vsdir for x.
858 # So create a project representing the folder "x"
859 n
= proj
.parent
= seen
[x
] = self
.vsnode_vsdir(self
, make_uuid(x
.abspath()), x
.name
)
860 n
.iter_path
= x
.parent
861 self
.all_projects
.append(n
)
863 # recurse up to the project directory
864 if x
.height() > self
.srcnode
.height() + 1:
867 for p
in self
.all_projects
[:]: # iterate over a copy of all projects
868 if not getattr(p
, 'tg', None):
869 # but only projects that have a task generator
872 # make a folder for each task generator
873 p
.iter_path
= p
.tg
.path