-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcreate-release.py
More file actions
executable file
·141 lines (126 loc) · 5.63 KB
/
Copy pathcreate-release.py
File metadata and controls
executable file
·141 lines (126 loc) · 5.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/env python3
"""
Creates a clean, distributable .zip of the CppMode folder for a release.
Includes everything in CppMode/ EXCEPT the contents of cache/ subfolders
(cache/linux-x64, cache/windows-x64, etc.) -- those are machine-specific
compiled build artifacts (Processing.o and similar), not something that
belongs in a release archive; they get rebuilt fresh on whatever machine
actually uses the release.
Usage:
create-release.py [version]
If no version is given, the zip is named CppMode.zip; otherwise it's
named CppMode-<version>.zip (e.g. CppMode-0.2.0.zip).
"""
import os
import sys
import zipfile
# This script lives in CppMode/scripts/, so CppMode's own root is one
# directory up from wherever this script actually is.
CPPMODE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
OUTPUT_DIR = os.path.dirname(CPPMODE_DIR) # one level above CppMode/ itself
def should_skip_file(path):
"""
Returns True for .o files inside cache/<platform>/, or anything
inside .git/ or .github/. The cache/<platform>/ DIRECTORIES
themselves are kept (so the release has the right folder layout
ready for a fresh rebuild), just not the compiled .o artifacts
sitting inside them -- those are machine-specific and get rebuilt
fresh wherever the release is actually used.
"""
rel = os.path.relpath(path, CPPMODE_DIR)
parts = rel.split(os.sep)
if len(parts) >= 1 and parts[0] in (".git", ".github"):
return True
if len(parts) >= 2 and parts[0] == "cache" and path.endswith(".o"):
return True
return False
def should_prune_dir(path):
"""Directories to not even descend into at all (.git, .github)."""
rel = os.path.relpath(path, CPPMODE_DIR)
parts = rel.split(os.sep)
return len(parts) >= 1 and parts[0] in (".git", ".github")
def bump_version_files(tag):
"""
Updates mode.properties and CppMode.txt to match the given release
tag: sets prettyVersion/prettyversion to the tag exactly as given,
and increments the plain integer "version=" build number by 1 in
both files. Both files get updated together so they never drift out
of sync with each other.
"""
targets = [
(os.path.join(CPPMODE_DIR, "mode.properties"), "prettyVersion"),
(os.path.join(CPPMODE_DIR, "CppMode.txt"), "prettyVersion"),
]
for path, pretty_key in targets:
if not os.path.exists(path):
print(f"WARNING: {path} not found, skipping version bump for it.")
continue
lines = open(path).readlines()
new_lines = []
for line in lines:
if line.startswith("version="):
try:
current = int(line.strip().split("=", 1)[1])
except ValueError:
current = 0
new_lines.append(f"version={current + 1}\n")
elif line.startswith(pretty_key + "="):
new_lines.append(f"{pretty_key}={tag}\n")
else:
new_lines.append(line)
with open(path, "w") as out:
out.writelines(new_lines)
print(f"Updated {path}: {pretty_key}={tag}, version bumped by 1")
def main():
version = sys.argv[1] if len(sys.argv) > 1 else None
if version:
bump_version_files(version)
zip_name = f"CppMode-{version}.zip" if version else "CppMode.zip"
zip_path = os.path.join(OUTPUT_DIR, zip_name)
if os.path.exists(zip_path):
os.remove(zip_path)
included = 0
skipped = 0
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
for root, dirs, files in os.walk(CPPMODE_DIR):
# Prune .git/.github entirely -- never even descend into
# them. cache/<platform> directories are walked normally
# (their FOLDER STRUCTURE is kept), only individual .o
# files inside them get filtered out below.
dirs[:] = [
d for d in dirs
if not should_prune_dir(os.path.join(root, d))
]
# If this directory ends up with no files going into the
# zip -- either because it was ALREADY empty (e.g. a fresh
# cache/windows-x64/ that's never been built into yet) or
# BECAME empty after filtering out its .o files -- add an
# explicit directory entry so the folder still exists after
# extraction. Zip files don't store empty directories
# unless told to, and this needs to cover both cases, not
# just the "had files, now has none" case.
rel_dir = os.path.relpath(root, CPPMODE_DIR)
kept_any_file_here = any(
not should_skip_file(os.path.join(root, f)) for f in files
)
if not kept_any_file_here:
dir_arcname = os.path.join("CppMode", rel_dir) + "/"
zf.write(root, dir_arcname)
for fname in files:
full_path = os.path.join(root, fname)
if should_skip_file(full_path):
skipped += 1
continue
# Store paths inside the zip relative to CppMode's own
# parent, so extracting the zip recreates a top-level
# "CppMode/" folder rather than dumping files loose.
arcname = os.path.join(
"CppMode", os.path.relpath(full_path, CPPMODE_DIR)
)
zf.write(full_path, arcname)
included += 1
size_mb = os.path.getsize(zip_path) / (1024 * 1024)
print(f"Created {zip_path} ({size_mb:.2f} MB)")
print(f" {included} files included, {skipped} cache files skipped")
if __name__ == "__main__":
main()