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        allow_abbrev=False)
23
24    parser.add_argument('-d', '--directory', required=True,
25                        help='Directory to walk for sub-directory discovery')
26    parser.add_argument('-c', '--create-links', required=False,
27                        help='Create links for each directory found in \
28                              directory given')
29    parser.add_argument('-o', '--out-file', required=True,
30                        help='File to write containing a list of all \
31                              directories found')
32    parser.add_argument('-t', '--trigger-file', required=False,
33                        help='Trigger file to be touched to re-run CMake')
34
35    args = parser.parse_args()
36
37    return args
38
39
40def get_subfolder_list(directory, create_links=None):
41    """Return subfolder list of a directory"""
42    dirlist = []
43
44    if create_links is not None:
45        if not os.path.exists(create_links):
46            os.makedirs(create_links)
47        symbase = os.path.basename(directory)
48        symlink = create_links + os.path.sep + symbase
49        if not os.path.exists(symlink):
50            os.symlink(directory, symlink)
51        dirlist.append(symlink)
52    else:
53        dirlist.append(directory)
54
55    for root, dirs, _ in os.walk(directory, topdown=True):
56        dirs.sort()
57        for subdir in dirs:
58            if create_links is not None:
59                targetdirectory = os.path.join(root, subdir)
60                reldir = os.path.relpath(targetdirectory, directory)
61                linkname = symbase + '_' + reldir.replace(os.path.sep, '_')
62                symlink = create_links + os.path.sep + linkname
63                if not os.path.exists(symlink):
64                    os.symlink(targetdirectory, symlink)
65                dirlist.append(symlink)
66            else:
67                dirlist.append(os.path.join(root, subdir))
68
69    return dirlist
70
71
72def gen_out_file(out_file, dirs):
73    """Generate file with the list of directories
74
75    File won't be updated if it already exists and has the same content
76
77    """
78    dirs_nl = "\n".join(dirs) + "\n"
79
80    if os.path.exists(out_file):
81        with open(out_file, 'r', encoding="utf-8") as out_file_fo:
82            out_file_dirs = out_file_fo.read()
83
84        if out_file_dirs == dirs_nl:
85            return
86
87    with open(out_file, 'w', encoding="utf-8") as out_file_fo:
88        out_file_fo.writelines(dirs_nl)
89
90
91def touch(trigger):
92    """Touch the trigger file
93
94    If no trigger file is provided then do a return.
95
96    """
97    if trigger is None:
98        return
99
100    if os.path.exists(trigger):
101        os.utime(trigger, None)
102    else:
103        with open(trigger, 'w') as trigger_fo:
104            trigger_fo.write("")
105
106
107def main():
108    """Parse command line arguments and take respective actions"""
109    args = parse_args()
110
111    dirs = get_subfolder_list(args.directory, args.create_links)
112    gen_out_file(args.out_file, dirs)
113
114    # Always touch trigger file to ensure json files are updated
115    touch(args.trigger_file)
116
117
118if __name__ == "__main__":
119    main()
120