|
16 | 16 | import argparse |
17 | 17 | import os |
18 | 18 | import os.path as osp |
19 | | -import uuid |
20 | | -import xml.etree.ElementTree as ET |
21 | 19 |
|
22 | 20 | COUNT = 0 |
23 | 21 |
|
@@ -48,93 +46,39 @@ def insert_text_after(text: str, containing: str, content: str) -> str: |
48 | 46 | def make_wxs(product_name: str, version: str) -> None: |
49 | 47 | """Make a .wxs file for the DataLab Windows installer.""" |
50 | 48 | wix_dir = osp.abspath(osp.dirname(__file__)) |
51 | | - proj_dir = osp.join(wix_dir, os.pardir) |
| 49 | + proj_dir = osp.abspath(osp.join(wix_dir, os.pardir)) |
52 | 50 | dist_dir = osp.join(proj_dir, "dist", product_name) |
| 51 | + archive_path = osp.join(proj_dir, "dist", f"{product_name}-files.zip") |
53 | 52 | wxs_path = osp.join(wix_dir, f"generic-{product_name}.wxs") |
54 | 53 | output_path = osp.join(wix_dir, f"{product_name}-{version}.wxs") |
55 | 54 |
|
56 | | - dir_ids: dict[str, str] = {} |
57 | | - file_ids: dict[str, str] = {} |
58 | | - |
59 | | - files_dict: dict[str, list[str]] = {} |
60 | | - |
61 | | - dir_str_list: list[str] = [] |
62 | | - comp_str_list: list[str] = [] |
63 | | - |
64 | | - for pth in os.listdir(dist_dir): |
65 | | - root_dir = osp.join(dist_dir, pth) |
66 | | - |
67 | | - if not osp.isdir(root_dir): |
68 | | - continue |
69 | | - |
70 | | - dpath_list : list[str] = [] |
71 | | - for root, dirs, filenames in os.walk(root_dir): |
72 | | - for dpath in dirs: |
73 | | - relpath = osp.relpath(osp.join(root, dpath), proj_dir) |
74 | | - dpath_list.append(relpath) |
75 | | - dir_ids[relpath] = generate_id() |
76 | | - files_dict.setdefault(osp.dirname(relpath), []) |
77 | | - for filename in filenames: |
78 | | - relpath = osp.relpath(osp.join(root, filename), proj_dir) |
79 | | - file_ids[relpath] = generate_id() |
80 | | - files_dict.setdefault(osp.dirname(relpath), []).append(relpath) |
81 | | - |
82 | | - # Create the base directory structure in XML: |
83 | | - base_name = osp.basename(root_dir) |
84 | | - base_path = osp.relpath(root_dir, proj_dir) |
85 | | - base_id = dir_ids[base_path] = generate_id() |
86 | | - dir_xml = ET.Element("Directory", Id=base_id, Name=base_name) |
87 | | - |
88 | | - # Nesting directories, recursively, in XML: |
89 | | - for dpath in sorted(dpath_list): |
90 | | - dname = osp.basename(dpath) |
91 | | - parent = dir_xml |
92 | | - for element in parent.iter(): |
93 | | - if element.get("Id") == dir_ids[osp.dirname(dpath)]: |
94 | | - parent = element |
95 | | - break |
96 | | - else: |
97 | | - raise ValueError(f"Parent directory not found for {dpath}") |
98 | | - ET.SubElement(parent, "Directory", Id=dir_ids[dpath], Name=dname) |
99 | | - space = " " * 4 |
100 | | - ET.indent(dir_xml, space=space, level=4) |
101 | | - dir_str_list.append(space * 4 + ET.tostring(dir_xml, encoding="unicode")) |
102 | | - |
103 | | - # Create additionnal components for each file in the directory structure: |
104 | | - for dpath in sorted([base_path] + dpath_list): |
105 | | - did = dir_ids[dpath] |
106 | | - files = files_dict.get(dpath, []) |
107 | | - if files: |
108 | | - # This is a directory with files, so we need to create components: |
109 | | - for path in files: |
110 | | - fid = file_ids[path] |
111 | | - guid = str(uuid.uuid4()) |
112 | | - comp_xml = ET.Element("Component", Id=fid, Directory=did, Guid=guid) |
113 | | - ET.SubElement(comp_xml, "File", Source=path, KeyPath="yes") |
114 | | - ET.indent(comp_xml, space=space, level=3) |
115 | | - comp_str = space * 3 + ET.tostring(comp_xml, encoding="unicode") |
116 | | - comp_str_list.append(comp_str) |
117 | | - elif dpath != base_path: |
118 | | - # This is an empty directory, so we need to create a folder: |
119 | | - guid = str(uuid.uuid4()) |
120 | | - cdid = f"CreateFolder_{did}" |
121 | | - comp_xml = ET.Element("Component", Id=cdid, Directory=did, Guid=guid) |
122 | | - ET.SubElement(comp_xml, "CreateFolder") |
123 | | - ET.indent(comp_xml, space=space, level=3) |
124 | | - comp_str = space * 3 + ET.tostring(comp_xml, encoding="unicode") |
125 | | - comp_str_list.append(comp_str) |
126 | | - |
127 | | - dir_str = "\n".join(dir_str_list).replace("><", ">\n<") |
128 | | - # print("Directory structure:\n", dir_str) |
129 | | - comp_str = "\n".join(comp_str_list).replace("><", ">\n<") |
130 | | - # print("Component structure:\n", comp_str) |
| 55 | + # Check if archive exists |
| 56 | + if not osp.exists(archive_path): |
| 57 | + print(f"ERROR: Archive not found at: {archive_path}") |
| 58 | + print(f"Working directory: {os.getcwd()}") |
| 59 | + print(f"Project directory: {proj_dir}") |
| 60 | + raise FileNotFoundError(f"Archive not found: {archive_path}") |
| 61 | + |
| 62 | + # Get archive size for statistics |
| 63 | + archive_size_mb = osp.getsize(archive_path) / (1024 * 1024) |
| 64 | + |
| 65 | + # Count files in dist directory for statistics |
| 66 | + total_files = sum(len(files) for _, _, files in os.walk(dist_dir)) |
| 67 | + |
| 68 | + print("Archive-based installer mode:") |
| 69 | + print(f" Archive: {osp.basename(archive_path)}") |
| 70 | + print(f" Archive size: {archive_size_mb:.1f} MB") |
| 71 | + print(f" Total files archived: {total_files}") |
| 72 | + print(" Components in MSI: ~15 (executables + archive + cleanup)") |
131 | 73 |
|
132 | 74 | # Create the .wxs file: |
133 | 75 | with open(wxs_path, "r", encoding="utf-8") as fd: |
134 | 76 | wxs = fd.read() |
135 | | - wxs = insert_text_after(dir_str, "<!-- Automatically inserted directories -->", wxs) |
136 | | - wxs = insert_text_after(comp_str, "<!-- Automatically inserted components -->", wxs) |
| 77 | + |
| 78 | + # Replace version placeholder |
137 | 79 | wxs = wxs.replace("{version}", version) |
| 80 | + wxs = wxs.replace("{archive_path}", f"dist\\{product_name}-files.zip") |
| 81 | + |
138 | 82 | with open(output_path, "w", encoding="utf-8") as fd: |
139 | 83 | fd.write(wxs) |
140 | 84 | print("Successfully created:", output_path) |
|
0 commit comments