-
-
Notifications
You must be signed in to change notification settings - Fork 424
Expand file tree
/
Copy pathpackage_plugin.py
More file actions
118 lines (96 loc) · 3.49 KB
/
package_plugin.py
File metadata and controls
118 lines (96 loc) · 3.49 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
#!/usr/bin/env python3
"""Package a QGIS plugin directory for upload to the official QGIS plugin repository."""
from __future__ import annotations
import argparse
import os
import re
import zipfile
from pathlib import Path
EXCLUDE_PATTERNS = [
r"^ui_.*\.py$",
r"^resources_rc\.py$",
r"^.*_rc\.py$",
r"^.*\.pyc$",
r"^.*\.pyo$",
r"^.*\.bak$",
r"^.*~$",
r"^\..*\.swp$",
r"^.*\.orig$",
r"^package_plugin\.py$",
]
EXCLUDE_DIRS = {
"__pycache__",
"__MACOSX",
".git",
".svn",
".hg",
".github",
".idea",
".vscode",
".pytest_cache",
".mypy_cache",
".tox",
".eggs",
"build",
"dist",
"node_modules",
"scripts",
"help",
}
def should_exclude_file(filename: str) -> bool:
return any(re.match(pattern, filename) for pattern in EXCLUDE_PATTERNS)
def should_exclude_dir(dirname: str) -> bool:
return dirname.startswith(".") or dirname in EXCLUDE_DIRS or dirname.endswith(".egg-info")
def get_version_from_metadata(plugin_dir: Path) -> str:
metadata_file = plugin_dir / "metadata.txt"
if metadata_file.exists():
with metadata_file.open("r", encoding="utf-8") as f:
for line in f:
if line.startswith("version="):
return line.split("=", 1)[1].strip()
return "unknown"
def package_plugin(source_dir: Path, output_path: Path | None, target_name: str) -> Path:
if not source_dir.exists():
raise FileNotFoundError(f"Source directory not found: {source_dir}")
if not source_dir.is_dir():
raise ValueError(f"Source path is not a directory: {source_dir}")
version = get_version_from_metadata(source_dir)
if output_path is None:
output_path = source_dir.parent / f"{target_name}-{version}.zip"
output_path.parent.mkdir(parents=True, exist_ok=True)
if output_path.exists():
output_path.unlink()
print(f"Packaging plugin from: {source_dir}")
print(f"Output zip file: {output_path}")
print(f"Root folder name in zip: {target_name}")
print(f"Plugin version: {version}")
files_added = 0
files_excluded = 0
with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as zipf:
for root, dirs, files in os.walk(source_dir):
dirs[:] = [d for d in dirs if not should_exclude_dir(d)]
for file in files:
file_path = Path(root) / file
if should_exclude_file(file) or file.startswith("."):
files_excluded += 1
continue
rel_path = file_path.relative_to(source_dir)
archive_name = Path(target_name) / rel_path
zipf.write(file_path, archive_name)
files_added += 1
print(f"Package created successfully: {output_path}")
print(f"Files added: {files_added}")
print(f"Files excluded: {files_excluded}")
return output_path
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--output", "-o", type=Path, default=None, help="Output path for the zip file")
parser.add_argument("--source", "-s", type=Path, default=Path("."), help="Source plugin directory")
parser.add_argument("--name", "-n", default=None, help="Target plugin folder name in the zip")
args = parser.parse_args()
source_dir = args.source.resolve()
target_name = args.name or source_dir.name
package_plugin(source_dir, args.output, target_name)
return 0
if __name__ == "__main__":
raise SystemExit(main())