File: init_yaml.py

package info (click to toggle)
python-project-generator 0.9.13-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 676 kB
  • sloc: python: 3,817; makefile: 15; sh: 6
file content (153 lines) | stat: -rw-r--r-- 6,390 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# Copyright 2015 0xc0170
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import yaml
import logging
import bisect
from collections import defaultdict

from .project import FILES_EXTENSIONS

logger = logging.getLogger('progen.yaml')

def _determine_tool(files):
    """Yields tuples in the form of (linker file, tool the file links for"""
    for file in files:
        linker_ext = file.split('.')[-1]
        if "sct" in linker_ext or "lin" in linker_ext:
            yield (str(file),"uvision")
        elif "ld" in linker_ext:
            yield (str(file),"make_gcc_arm")
        elif "icf" in linker_ext:
            yield (str(file),"iar_arm")


def _scan(section, directory, extensions):
    if section == "sources":
        data_dict = defaultdict(list)  # sources can have group names, making them a dict
    else:
        data_dict = []
    for dirpath, dirnames, files in os.walk(directory):
        for filename in files:
            ext = filename.split('.')[-1]
            relpath = os.path.relpath(dirpath, directory)
            if ext in extensions: # Check if the files extension is an acceptable one for this section of yaml
                if section == "sources":
                    #get the directory one below root
                    dir = directory.split(os.path.sep)[-1] if dirpath == directory else dirpath.replace(directory,'').split(os.path.sep)[1]
                    if relpath not in data_dict[dir]:
                        # Add the path to the file to this dictionary, with dir as group name
                        bisect.insort(data_dict[dir], os.path.normpath(relpath))
                elif section == 'includes':
                    #get all the folders along the path
                    dirs = relpath.split(os.path.sep)
                    for i in range(1, len(dirs)+1):
                        """ add all combinations of them, because we don't know how they will be referenced in program files
                            Example - there is a .h file in the path Here\is\include\include.h
                            We want to catch any possible combo, so add Here, Here\is, and Here\is\include

                        """
                        data_dict.append(os.path.normpath(os.path.sep.join(dirs[:i])))
                else:
                    data_dict.append(os.path.normpath(os.path.join(relpath, filename)))
    if section == "sources":
        return dict(data_dict)
    l = list(set(data_dict))
    l.sort()
    return l

def _generate_file(filename,data):
    logger.debug('Writing the following to %s:\n%s' % (filename, yaml.dump(data)))
    file = os.path.join(os.getcwd(), filename)
    if os.path.isfile(file):
        os.remove(file)
    try:
        with open(file, 'w+') as f:
            f.write(yaml.dump(data, default_flow_style=False))
    except:
        logger.error("Unable to open %s for writing!" % file)
        return -1
    logger.info("Wrote to file %s" % file)

    return 0


def create_yaml(directory, project_name, board,output_dir):
    # lay out what the common section a project yaml file will look like
    # The value mapped to by each key are the file extensions that will help us get valid files for each section
    logger.debug("Project name: %s, Target: %s"%(project_name,board))
    common_section = {
        'linker_file': FILES_EXTENSIONS['linker_file'],
        'sources': FILES_EXTENSIONS['source_files_c'] + FILES_EXTENSIONS['source_files_cpp'] +
                   FILES_EXTENSIONS['source_files_s'] + FILES_EXTENSIONS['source_files_obj'],
        'includes': FILES_EXTENSIONS['include_files']
    }

    # will be written to projects.yaml
    root = os.path.relpath(directory)
    projects_yaml = {
        'projects': {
            project_name:
                ['project.yaml']
        },
        'settings': {'export_dir': os.path.relpath(output_dir)}
    }

    # will be written to project.yaml
    project_yaml = {
        'common': {},
        'tool_specific': {}
    }
    # iterate over the common section defined above
    for section, extensions in common_section.items():
        # look for files in this directory that have the defined extensions, and add them to our project file
        project_yaml['common'][section] = _scan(section, directory,extensions)

    project_yaml['common']['target'] = [board] # user passes target in command line

    """Find what tool the linker works for - if multiple linkers in this dir, project_yaml['common']['linker_file']
        is a list. Tools is an iterator"""
    tools = _determine_tool(project_yaml['common']['linker_file'])

    linkers = {}   # dictionary containing all linker files in the project directory

    # exhaust the iterator and add its yielded values to linkers
    for (file,tool) in tools:
        if tool in linkers:
            linkers[tool].append(file)
        else:
            linkers[tool] = [file]

    for tool, linker in linkers.items():
        if len(linker) > 1:
            # The project directory defined more than one linker for a tool
            print("\nMultipe linkers found for " + tool + "\n")
            for i, file in enumerate(linker):
                print(str(i) + ": " + file)
            answer = raw_input('\nWhich file do you want? ')
            while int(answer) not in range(0,len(linker)):
                answer = raw_input('Answer not in list. Which file do you want? ')
            project_yaml['tool_specific'][tool] = {'linker_file': [linkers[tool][int(answer)]]}
        else:
            project_yaml['tool_specific'][tool] = {'linker_file': linker}

    # linker file is now in tool_specific section
    del project_yaml['common']['linker_file']

    ret = _generate_file("projects.yaml", projects_yaml)
    if ret < 0: # make sure the first file generated correctly
        return -1
    ret = _generate_file("project.yaml", project_yaml)
    return ret