1#!/usr/bin/env python3
2#
3# Copyright (c) 2017 Nordic Semiconductor
4#
5# SPDX-License-Identifier: Apache-2.0
6
7"""Write subfolder list to a file
8
9This script will walk the specified directory and write the file specified with
10the list of all sub-directories found. If the output file already exists, the
11file will only be updated in case sub-directories have been added or removed
12since the previous invocation.
13
14"""
15
16import argparse
17import os
18
19
20def parse_args():
21    """Parse command line arguments and options"""
22    parser = argparse.ArgumentParser(
23        description=__doc__,
24        formatter_class=argparse.RawDescriptionHelpFormatter,
25        allow_abbrev=False,
26    )
27
28    parser.add_argument(
29        '-d', '--directory', required=True, help='Directory to walk for sub-directory discovery'
30    )
31    parser.add_argument(
32        '-c',
33        '--create-links',
34        required=False,
35        help='Create links for each directory found in directory given',
36    )
37    parser.add_argument(
38        '-o',
39        '--out-file',
40        required=True,
41        help='File to write containing a list of all directories found',
42    )
43    parser.add_argument(
44        '-t', '--trigger-file', required=False, help='Trigger file to be touched to re-run CMake'
45    )
46
47    args = parser.parse_args()
48
49    return args
50
51
52def get_subfolder_list(directory, create_links=None):
53    """Return subfolder list of a directory"""
54    dirlist = []
55
56    if create_links is not None:
57        if not os.path.exists(create_links):
58            os.makedirs(create_links)
59        symbase = os.path.basename(directory)
60        symlink = create_links + os.path.sep + symbase
61        if not os.path.exists(symlink):
62            os.symlink(directory, symlink)
63        dirlist.append(symlink)
64    else:
65        dirlist.append(directory)
66
67    for root, dirs, _ in os.walk(directory, topdown=True):
68        dirs.sort()
69        for subdir in dirs:
70            if create_links is not None:
71                targetdirectory = os.path.join(root, subdir)
72                reldir = os.path.relpath(targetdirectory, directory)
73                linkname = symbase + '_' + reldir.replace(os.path.sep, '_')
74                symlink = create_links + os.path.sep + linkname
75                if not os.path.exists(symlink):
76                    os.symlink(targetdirectory, symlink)
77                dirlist.append(symlink)
78            else:
79                dirlist.append(os.path.join(root, subdir))
80
81    return dirlist
82
83
84def gen_out_file(out_file, dirs):
85    """Generate file with the list of directories
86
87    File won't be updated if it already exists and has the same content
88
89    """
90    dirs_nl = "\n".join(dirs) + "\n"
91
92    if os.path.exists(out_file):
93        with open(out_file, encoding="utf-8") as out_file_fo:
94            out_file_dirs = out_file_fo.read()
95
96        if out_file_dirs == dirs_nl:
97            return
98
99    with open(out_file, 'w', encoding="utf-8") as out_file_fo:
100        out_file_fo.writelines(dirs_nl)
101
102
103def touch(trigger):
104    """Touch the trigger file
105
106    If no trigger file is provided then do a return.
107
108    """
109    if trigger is None:
110        return
111
112    if os.path.exists(trigger):
113        os.utime(trigger, None)
114    else:
115        with open(trigger, 'w') as trigger_fo:
116            trigger_fo.write("")
117
118
119def main():
120    """Parse command line arguments and take respective actions"""
121    args = parse_args()
122
123    dirs = get_subfolder_list(args.directory, args.create_links)
124    gen_out_file(args.out_file, dirs)
125
126    # Always touch trigger file to ensure json files are updated
127    touch(args.trigger_file)
128
129
130if __name__ == "__main__":
131    main()
132