Mercurial > hg > orthanc-ohif
annotate Resources/EmbedStaticAssets.py @ 17:154cb76a042f
make the build of static assets reproducible
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sat, 05 Aug 2023 11:36:33 +0200 |
parents | 39585ba26f20 |
children | 36049c04ee27 |
rev | line source |
---|---|
0 | 1 #!/usr/bin/python3 |
2 | |
3 # SPDX-FileCopyrightText: 2023 Sebastien Jodogne, UCLouvain, Belgium | |
4 # SPDX-License-Identifier: GPL-3.0-or-later | |
5 | |
6 # OHIF plugin for Orthanc | |
7 # Copyright (C) 2023 Sebastien Jodogne, UCLouvain, Belgium | |
8 # | |
9 # This program is free software: you can redistribute it and/or | |
10 # modify it under the terms of the GNU General Public License as | |
11 # published by the Free Software Foundation, either version 3 of the | |
12 # License, or (at your option) any later version. | |
13 # | |
14 # This program is distributed in the hope that it will be useful, but | |
15 # WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 # General Public License for more details. | |
18 # | |
19 # You should have received a copy of the GNU General Public License | |
20 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
21 | |
22 | |
23 import gzip | |
24 import hashlib | |
25 import io | |
26 import os | |
27 import sys | |
28 | |
29 if len(sys.argv) != 3: | |
30 raise Exception('Usage: %s [source folder] [target C++]' % sys.argv[0]) | |
31 | |
32 SOURCE = sys.argv[1] | |
33 TARGET = sys.argv[2] | |
34 | |
35 if not os.path.isdir(SOURCE): | |
36 raise Exception('Nonexistent source folder: %s' % SOURCE) | |
37 | |
38 | |
39 def EncodeFileAsCString(f, variable, content): | |
40 f.write('static const uint8_t %s[%d] = \n "' % (variable, len(content) + 1)) | |
41 | |
42 column = 0 | |
43 | |
44 for c in content: | |
45 | |
46 if sys.version_info < (3, 0): | |
47 # Python 2.7 | |
48 i = ord(c) | |
49 else: | |
50 # Python 3.x | |
51 i = c | |
52 | |
53 if i < 32 or i >= 127 or i == ord('?'): | |
54 f.write('\\{0:03o}'.format(i)) | |
55 elif i in [ ord('"'), ord('\\') ]: | |
56 f.write('\\' + chr(i)) | |
57 else: | |
58 f.write(chr(i)) | |
59 | |
60 column += 1 | |
61 if column >= 120: | |
62 f.write('"\n "') | |
63 column = 0 | |
64 | |
65 f.write('";\n\n') | |
66 | |
67 | |
68 def WriteChecksum(f, variable, content): | |
69 md5 = hashlib.md5(content).hexdigest() | |
70 g.write('static const char* %s = "%s";\n\n' % (variable, md5)) | |
71 | |
72 | |
73 with open(TARGET, 'w') as g: | |
74 g.write(''' | |
75 #include <stdint.h> | |
76 #include <Compression/GzipCompressor.h> | |
77 #include <OrthancException.h> | |
78 #include <Toolbox.h> | |
79 | |
80 static void Uncompress(std::string& target, const void* data, size_t size, const std::string& md5Expected) | |
81 { | |
82 Orthanc::GzipCompressor compressor; | |
83 compressor.Uncompress(target, data, size); | |
84 std::string md5Actual; | |
85 Orthanc::Toolbox::ComputeMD5(md5Actual, target); | |
86 if (md5Actual != md5Expected) | |
87 { | |
88 throw Orthanc::OrthancException(Orthanc::ErrorCode_CorruptedFile); | |
89 } | |
90 } | |
91 | |
92 ''') | |
93 | |
94 index = {} | |
95 count = 0 | |
96 | |
97 for root, dirs, files in os.walk(SOURCE): | |
17
154cb76a042f
make the build of static assets reproducible
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
98 files.sort() |
154cb76a042f
make the build of static assets reproducible
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
99 dirs.sort() |
154cb76a042f
make the build of static assets reproducible
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
100 |
0 | 101 for f in files: |
102 fullPath = os.path.join(root, f) | |
103 relativePath = os.path.relpath(os.path.join(root, f), SOURCE) | |
104 variable = 'data_%06d' % count | |
105 | |
106 with open(fullPath, 'rb') as source: | |
107 content = source.read() | |
108 | |
109 if sys.version_info < (3, 0): | |
110 # Python 2.7 | |
111 fileobj = io.BytesIO() | |
17
154cb76a042f
make the build of static assets reproducible
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
112 gzip.GzipFile(fileobj=fileobj, mode='w', mtime=0).write(content) |
0 | 113 compressed = fileobj.getvalue() |
114 else: | |
115 # Python 3.x | |
17
154cb76a042f
make the build of static assets reproducible
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
116 compressed = gzip.compress(content, mtime=0) |
0 | 117 |
118 EncodeFileAsCString(g, variable, compressed) | |
119 WriteChecksum(g, variable + '_md5', content) | |
120 | |
121 index[relativePath] = variable | |
122 | |
123 count += 1 | |
124 | |
125 g.write('void ReadStaticAsset(std::string& target, const std::string& path)\n') | |
126 g.write('{\n') | |
17
154cb76a042f
make the build of static assets reproducible
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
127 for (path, variable) in sorted(index.items()): |
0 | 128 g.write(' if (path == "%s")\n' % path) |
129 g.write(' {\n') | |
130 g.write(' Uncompress(target, %s, sizeof(%s) - 1, %s_md5);\n' % (variable, variable, variable)) | |
131 g.write(' return;\n') | |
132 g.write(' }\n\n') | |
133 | |
134 g.write(' throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem, "Unknown OHIF resource: " + path);\n') | |
135 g.write('}\n') |