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