1#!/usr/bin/env python3
2# -*- Coding: UTF-8 -*-
3
4# ---------------------------------------------------------------------------
5# Open Asset Import Library (ASSIMP)
6# ---------------------------------------------------------------------------
7#
8# Copyright (c) 2006-2020, ASSIMP Development Team
9#
10# All rights reserved.
11#
12# Redistribution and use of this software in source and binary forms,
13# with or without modification, are permitted provided that the following
14# conditions are met:
15#
16# * Redistributions of source code must retain the above
17#   copyright notice, this list of conditions and the
18#   following disclaimer.
19#
20# * Redistributions in binary form must reproduce the above
21#   copyright notice, this list of conditions and the
22#   following disclaimer in the documentation and/or other
23#   materials provided with the distribution.
24#
25# * Neither the name of the ASSIMP team, nor the names of its
26#   contributors may be used to endorse or promote products
27#   derived from this software without specific prior
28#   written permission of the ASSIMP Development Team.
29#
30# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41# ---------------------------------------------------------------------------
42
43"""
44Generate the regression database db.zip from the files in the <root>/test/models
45directory. Older databases are overwritten with no prompt but can be restored
46using Git as needed.
47
48Use --help for usage.
49
50On Windows, use ``py run.py <arguments>`` to make sure command line parameters
51are forwarded to the script.
52"""
53
54import sys
55import os
56import subprocess
57import zipfile
58
59import settings
60import utils
61
62usage = """gen_db [assimp_binary] [-i=...] [-e=...] [-p] [-n]
63
64The assimp_cmd (or assimp) binary to use is specified by the first
65command line argument and defaults to ``assimp``.
66
67To build, set ``ASSIMP_BUILD_ASSIMP_TOOLS=ON`` in CMake. If generating
68configs for an IDE, make sure to build the assimp_cmd project.
69
70-i,--include: List of file extensions to update dumps for. If omitted,
71         all file extensions are updated except those in `exclude`.
72         Example: -ixyz,abc
73                  -i.xyz,.abc
74                  --include=xyz,abc
75
76-e,--exclude: Merged with settings.exclude_extensions to produce a
77         list of all file extensions to ignore. If dumps exist,
78         they are not altered. If not, theu are not created.
79
80-p,--preview: Preview list of file extensions touched by the update.
81         Dont' change anything.
82
83-n,--nozip: Don't pack to ZIP archive. Keep all dumps in individual files.
84"""
85
86# -------------------------------------------------------------------------------
87def process_dir(d, outfile, file_filter):
88    """ Generate small dump records for all files in 'd' """
89    print("Processing directory " + d)
90
91    num = 0
92    for f in os.listdir(d):
93        fullp = os.path.join(d, f)
94        if os.path.isdir(fullp) and not f == ".svn":
95            num += process_dir(fullp, outfile, file_filter)
96            continue
97
98        if file_filter(f):
99            for pp in settings.pp_configs_to_test:
100                num += 1
101                print("DUMP " + fullp + "\n post-processing: " + pp)
102                outf = os.path.join(os.getcwd(), settings.database_name,
103                    utils.hashing(fullp, pp))
104
105                cmd = [ assimp_bin_path, "dump", fullp, outf, "-b", "-s", "-l" ] + pp.split()
106                outfile.write("assimp dump "+"-"*80+"\n")
107                outfile.flush()
108                if subprocess.call(cmd, stdout=outfile, stderr=outfile, shell=False):
109                    print("Failure processing " + fullp)
110
111                    # spit out an empty file to indicate that this failure is expected
112                    with open(outf,'wb') as f:
113                        pass
114    return num
115
116
117# -------------------------------------------------------------------------------
118def make_zip():
119    """Zip the contents of ./<settings.database_name>
120    to <settings.database_name>.zip using DEFLATE
121    compression to minimize the file size. """
122
123    num = 0
124    zipout = zipfile.ZipFile(settings.database_name + ".zip", "w", zipfile.ZIP_DEFLATED)
125    for f in os.listdir(settings.database_name):
126        p = os.path.join(settings.database_name, f)
127        zipout.write(p, f)
128        if settings.remove_old:
129            os.remove(p)
130
131        num += 1
132
133    if settings.remove_old:
134        os.rmdir(settings.database_name)
135
136    bad = zipout.testzip()
137    assert bad is None
138
139    print("="*60)
140    print("Database contains {0} entries".format(num))
141
142
143# -------------------------------------------------------------------------------
144def extract_zip():
145    """Unzip <settings.database_name>.zip to
146    ./<settings.database_name>"""
147    try:
148        zipout = zipfile.ZipFile(settings.database_name + ".zip", "r", 0)
149        zipout.extractall(path=settings.database_name)
150    except (RuntimeError,IOError) as r:
151        print(r)
152        print("failed to extract previous ZIP contents. "\
153              "DB is generated from scratch.")
154
155
156# -------------------------------------------------------------------------------
157def gen_db(ext_list,outfile):
158    """Generate the crash dump database in
159    ./<settings.database_name>"""
160    try:
161        os.mkdir(settings.database_name)
162    except OSError:
163        pass
164
165    num = 0
166    for tp in settings.model_directories:
167        num += process_dir(tp, outfile,
168            lambda x: os.path.splitext(x)[1].lower() in ext_list and not x in settings.files_to_ignore)
169
170    print("="*60)
171    print("Updated {0} entries".format(num))
172
173
174# -------------------------------------------------------------------------------
175if __name__ == "__main__":
176    def clean(f):
177        f = f.strip("* \'")
178        return "."+f if f[:1] != '.' else f
179
180    if len(sys.argv) <= 1 or sys.argv[1] == "--help" or sys.argv[1] == "-h":
181        print(usage)
182        sys.exit(0)
183
184    assimp_bin_path = sys.argv[1]
185    ext_list, preview, nozip = None, False, False
186    for m in sys.argv[2:]:
187        if m[:10]=="--exclude=":
188            settings.exclude_extensions += map(clean, m[10:].split(","))
189        elif m[:2]=="-e":
190            settings.exclude_extensions += map(clean, m[2:].split(","))
191        elif m[:10]=="--include=":
192            ext_list = m[10:].split(",")
193        elif m[:2]=="-i":
194            ext_list = m[2:].split(",")
195        elif m=="-p" or m == "--preview":
196            preview = True
197        elif m=="-n" or m == "--nozip":
198            nozip = True
199        else:
200            print("Unrecognized parameter: " + m)
201            sys.exit(-1)
202
203    outfile = open(os.path.join("..", "results", "gen_regression_db_output.txt"), "w")
204    if ext_list is None:
205        (ext_list, err) = subprocess.Popen([assimp_bin_path, "listext"],
206            stdout=subprocess.PIPE).communicate()
207        ext_list = str(ext_list.strip()).lower().split(";")
208
209    # todo: Fix for multi dot extensions like .skeleton.xml
210    ext_list = list(filter(lambda f: not f in settings.exclude_extensions,
211        map(clean, ext_list)))
212    print('File extensions processed: ' + ', '.join(ext_list))
213    if preview:
214        sys.exit(1)
215
216    extract_zip()
217    gen_db(ext_list,outfile)
218    make_zip()
219
220    print("="*60)
221    input("Press any key to continue")
222    sys.exit(0)
223
224# vim: ai ts=4 sts=4 et sw=4
225
226