release and custom build in CI
This commit is contained in:
parent
c1d1d49f8a
commit
dc3fcdae9e
7 changed files with 241 additions and 35 deletions
70
.github/workflows/release.yml
vendored
Normal file
70
.github/workflows/release.yml
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
name: Release Font
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
options:
|
||||
description: 'Options for build.py'
|
||||
required: false
|
||||
default: ''
|
||||
cn:
|
||||
description: 'Include Chinese version'
|
||||
required: false
|
||||
default: 'false'
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Checkout branch
|
||||
run: git checkout variable
|
||||
|
||||
- name: Install ftcli
|
||||
run: python -m pip install foundrytools-cli
|
||||
|
||||
- name: Run release script
|
||||
run: |
|
||||
if [ "${{ github..event_name }}" == "push" ]; then
|
||||
python release.py
|
||||
else
|
||||
options="${{ github.event.inputs.options }}"
|
||||
if [ "${{ github.event.inputs.cn }}" == "true" ]; then
|
||||
options="$options --cn"
|
||||
fi
|
||||
python build.py $options
|
||||
fi
|
||||
|
||||
- name: Generate release notes
|
||||
id: release_notes
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" == "push" ]; then
|
||||
echo "notes=$(git log --pretty=%B $(git describe --tags --abbrev=0)..HEAD)" >> $GITHUB_ENV
|
||||
else
|
||||
notes=$(python release.py ${{ github.event.inputs.options }} --dry)
|
||||
echo "notes=### Configuration:\n\n```\n$notes\n```" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate tag name
|
||||
id: generate_timestamp
|
||||
run: echo "::set-output name=tag_name::v$(date +%s)"
|
||||
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.ref_name || steps.generate_timestamp.outputs.tag_name }}
|
||||
draft: ${{ github.event_name == 'push' }}
|
||||
body: ${{ env.notes }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: |
|
||||
release/*
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -5,3 +5,6 @@ dist
|
|||
/fonts
|
||||
/source/cn/static
|
||||
__pycache__
|
||||
.DS_store
|
||||
release
|
||||
source/cn
|
43
build.py
43
build.py
|
@ -13,7 +13,9 @@ from fontTools.ttLib import TTFont, newTable
|
|||
from fontTools.merge import Merger
|
||||
from source.py.utils import (
|
||||
check_font_patcher,
|
||||
download_cn_static_fonts,
|
||||
get_font_forge_bin,
|
||||
is_ci,
|
||||
run,
|
||||
set_font_name,
|
||||
joinPaths,
|
||||
|
@ -341,7 +343,8 @@ class BuildOption:
|
|||
self.output_dir, "TTF-AutoHint" if config.use_hinted else "TTF"
|
||||
)
|
||||
|
||||
self.cn_static_path = f"{self.src_dir}/cn/static"
|
||||
self.cn_variable_dir = f"{self.src_dir}/cn"
|
||||
self.cn_static_dir = f"{self.cn_variable_dir}/static"
|
||||
|
||||
self.cn_base_font_dir = None
|
||||
self.cn_suffix = None
|
||||
|
@ -373,6 +376,22 @@ class BuildOption:
|
|||
self.cn_suffix = self.cn_suffix_compact = "CN"
|
||||
self.output_cn = joinPaths(self.output_dir, self.cn_suffix_compact)
|
||||
|
||||
def should_build_cn(self, config: FontConfig) -> bool:
|
||||
if not config.cn["enable"] and not config.use_cn_both:
|
||||
return False
|
||||
if path.exists(self.cn_static_dir) and listdir(self.cn_static_dir).__len__() == 16:
|
||||
return True
|
||||
if not path.exists(self.cn_variable_dir) and listdir(self.cn_variable_dir).__len__() < 1:
|
||||
if is_ci():
|
||||
return download_cn_static_fonts(
|
||||
tag="cn_static",
|
||||
target_dir=self.cn_static_dir,
|
||||
github_mirror=self.nerd_font["github_mirror"],
|
||||
)
|
||||
print("CN varaible fonts does not exist. Skip CN build.")
|
||||
return False
|
||||
return True
|
||||
|
||||
def has_cache(self) -> bool:
|
||||
return (
|
||||
self.__check_cache_dir(self.output_variable, count=2)
|
||||
|
@ -660,7 +679,7 @@ def build_cn(f: str, font_config: FontConfig, build_option: BuildOption):
|
|||
[
|
||||
joinPaths(build_option.cn_base_font_dir, f),
|
||||
joinPaths(
|
||||
build_option.cn_static_path, f"MapleMonoCN-{style_compact_cn}.ttf"
|
||||
build_option.cn_static_dir, f"MapleMonoCN-{style_compact_cn}.ttf"
|
||||
),
|
||||
]
|
||||
)
|
||||
|
@ -743,6 +762,7 @@ def run_build(pool_size: int, fn: Callable, dir: str):
|
|||
for f in listdir(dir):
|
||||
fn(f)
|
||||
|
||||
|
||||
def main():
|
||||
check_ftcli()
|
||||
parsed_args = parse_args()
|
||||
|
@ -847,20 +867,17 @@ def main():
|
|||
# ==================================== build CN =======================================
|
||||
# =========================================================================================
|
||||
|
||||
if font_config.cn["enable"] and path.exists(f"{build_option.src_dir}/cn"):
|
||||
if (
|
||||
not path.exists(build_option.cn_static_path)
|
||||
or font_config.cn["clean_cache"]
|
||||
):
|
||||
if build_option.should_build_cn(font_config):
|
||||
if not path.exists(build_option.cn_static_dir) or font_config.cn["clean_cache"]:
|
||||
print("=========================================")
|
||||
print("Instantiating CN Base font, be patient...")
|
||||
print("=========================================")
|
||||
run(
|
||||
f"ftcli converter vf2i {build_option.src_dir}/cn -out {build_option.cn_static_path}"
|
||||
f"ftcli converter vf2i {build_option.cn_variable_dir} -out {build_option.cn_static_dir}"
|
||||
)
|
||||
run(f"ftcli ttf fix-contours {build_option.cn_static_path}")
|
||||
run(f"ftcli ttf remove-overlaps {build_option.cn_static_path}")
|
||||
run(f"ftcli utils del-table -t kern -t GPOS {build_option.cn_static_path}")
|
||||
run(f"ftcli ttf fix-contours {build_option.cn_static_dir}")
|
||||
run(f"ftcli ttf remove-overlaps {build_option.cn_static_dir}")
|
||||
run(f"ftcli utils del-table -t kern -t GPOS {build_option.cn_static_dir}")
|
||||
|
||||
def _build_cn():
|
||||
print(
|
||||
|
@ -969,7 +986,9 @@ def main():
|
|||
target_parent_dir_path=archieve_dir,
|
||||
)
|
||||
with open(
|
||||
joinPaths(archieve_dir, f"{font_config.family_name_compact}-{f}.sha256"),
|
||||
joinPaths(
|
||||
archieve_dir, f"{font_config.family_name_compact}-{f}.sha256"
|
||||
),
|
||||
"w",
|
||||
encoding="utf-8",
|
||||
) as hash_file:
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
"extra_args": []
|
||||
},
|
||||
"cn": {
|
||||
"enable": true,
|
||||
"enable": false,
|
||||
"with_nerd_font": true,
|
||||
"fix_meta_table": true,
|
||||
"clean_cache": false,
|
||||
|
|
70
release.py
Normal file
70
release.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
from os import listdir, mkdir, path
|
||||
from shutil import copytree, move, rmtree
|
||||
import subprocess
|
||||
|
||||
from source.py.utils import joinPaths
|
||||
|
||||
output_base = "fonts"
|
||||
output_release = "release"
|
||||
|
||||
|
||||
def move_and_log(file_path: str, target_path: str):
|
||||
print(f"Move {file_path} -> {target_path}")
|
||||
move(file_path, target_path)
|
||||
|
||||
def build(normal: bool, hinted: bool, cache: bool = False):
|
||||
args = [
|
||||
"python",
|
||||
"build.py",
|
||||
"--archieve",
|
||||
"--cn-both",
|
||||
]
|
||||
|
||||
if cache:
|
||||
args.append("--cache")
|
||||
|
||||
if normal:
|
||||
args.append("--normal")
|
||||
|
||||
if hinted:
|
||||
args.append("--hinted")
|
||||
else:
|
||||
args.append("--no-hinted")
|
||||
|
||||
print(" ".join(args))
|
||||
subprocess.run(args)
|
||||
|
||||
build_archieve_dir = f"{output_base}/archieve"
|
||||
|
||||
for file_name in listdir(build_archieve_dir):
|
||||
file_path = joinPaths(build_archieve_dir, file_name)
|
||||
if path.isfile(file_path):
|
||||
if not hinted:
|
||||
name, ext = path.splitext(file_name)
|
||||
file_name = f"{name}-unhinted{ext}"
|
||||
|
||||
move_and_log(file_path, joinPaths(output_release, file_name))
|
||||
|
||||
|
||||
# clear old releases
|
||||
rmtree(output_base, ignore_errors=True)
|
||||
mkdir(output_base)
|
||||
rmtree(output_release, ignore_errors=True)
|
||||
mkdir(output_release)
|
||||
|
||||
# build all formats
|
||||
build(normal=True, hinted=True)
|
||||
build(normal=True, hinted=False, cache=True)
|
||||
build(normal=False, hinted=True)
|
||||
build(normal=False, hinted=False, cache=True)
|
||||
|
||||
# copy woff2 to root
|
||||
rmtree("woff2", ignore_errors=True)
|
||||
copytree(f"{output_base}/woff2", "woff2")
|
||||
print("Copy woff2 to root")
|
||||
|
||||
subprocess.run(f"ftcli converter ft2wf -out woff2/var -f woff2 {output_base}/variable")
|
||||
|
||||
target_dir = "website/public-dev/fonts"
|
||||
rmtree(target_dir, ignore_errors=True)
|
||||
copytree("woff2/var", target_dir)
|
|
@ -38,7 +38,7 @@
|
|||
"extra_args": []
|
||||
},
|
||||
"cn": {
|
||||
"enable": true,
|
||||
"enable": false,
|
||||
"with_nerd_font": true,
|
||||
"fix_meta_table": true,
|
||||
"clean_cache": false,
|
||||
|
|
|
@ -50,9 +50,58 @@ def get_font_forge_bin():
|
|||
return LINUX_FONTFORGE_PATH
|
||||
|
||||
|
||||
def is_ci():
|
||||
ci_envs = [
|
||||
"JENKINS_HOME",
|
||||
"TRAVIS",
|
||||
"CIRCLECI",
|
||||
"GITHUB_ACTIONS",
|
||||
"GITLAB_CI",
|
||||
"TF_BUILD",
|
||||
]
|
||||
|
||||
for env in ci_envs:
|
||||
if environ.get(env):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def parse_github_mirror(github_mirror: str) -> str:
|
||||
github = environ.get("GITHUB") # custom github mirror, for CN users
|
||||
if not github:
|
||||
github = github_mirror
|
||||
return f"https://{github}"
|
||||
|
||||
|
||||
def download_zip_and_extract(
|
||||
name: str, url: str, zip_path: str, output_dir: str, remove_zip: bool = True
|
||||
) -> bool:
|
||||
try:
|
||||
if not path.exists(zip_path):
|
||||
try:
|
||||
print(f"NerdFont Patcher does not exist, download from {url}")
|
||||
with urlopen(url) as response, open(zip_path, "wb") as out_file:
|
||||
shutil.copyfileobj(response, out_file)
|
||||
except Exception as e:
|
||||
print(
|
||||
f"\nFail to download {name}. Please download it manually from {url}, then put downloaded file into project's root and run this script again. \n Error: {e}"
|
||||
)
|
||||
return False
|
||||
with ZipFile(zip_path, "r") as zip_ref:
|
||||
zip_ref.extractall(output_dir)
|
||||
if remove_zip:
|
||||
remove(zip_path)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Download zip and extract failed, error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def check_font_patcher(version: str, github_mirror: str = "github.com") -> bool:
|
||||
if path.exists("FontPatcher"):
|
||||
with open("FontPatcher/font-patcher", "r", encoding="utf-8") as f:
|
||||
target_dir = "FontPatcher"
|
||||
if path.exists(target_dir):
|
||||
with open(f"{target_dir}/font-patcher", "r", encoding="utf-8") as f:
|
||||
if f"# Nerd Fonts Version: {version}" in f.read():
|
||||
return True
|
||||
else:
|
||||
|
@ -60,22 +109,17 @@ def check_font_patcher(version: str, github_mirror: str = "github.com") -> bool:
|
|||
shutil.rmtree("FontPatcher", ignore_errors=True)
|
||||
|
||||
zip_path = "FontPatcher.zip"
|
||||
if not path.exists(zip_path):
|
||||
github = environ.get("GITHUB") # custom github mirror, for CN users
|
||||
if not github:
|
||||
github = github_mirror
|
||||
url = f"https://{github}/ryanoasis/nerd-fonts/releases/download/v{version}/FontPatcher.zip"
|
||||
try:
|
||||
print(f"NerdFont Patcher does not exist, download from {url}")
|
||||
with urlopen(url) as response, open(zip_path, "wb") as out_file:
|
||||
shutil.copyfileobj(response, out_file)
|
||||
except Exception as e:
|
||||
print(
|
||||
f"\nFail to download NerdFont Patcher. Please download it manually from {url}, then put downloaded 'FontPatcher.zip' into project's root and run this script again. \n Error: {e}"
|
||||
url = f"{parse_github_mirror(github_mirror)}/ryanoasis/nerd-fonts/releases/download/v{version}/{zip_path}"
|
||||
return download_zip_and_extract(
|
||||
name="Nerd Font Patcher", url=url, zip_path=zip_path, output_dir=target_dir
|
||||
)
|
||||
exit(1)
|
||||
|
||||
with ZipFile(zip_path, "r") as zip_ref:
|
||||
zip_ref.extractall("FontPatcher")
|
||||
remove(zip_path)
|
||||
return True
|
||||
|
||||
def download_cn_static_fonts(
|
||||
tag: str, target_dir: str, github_mirror: str = "github.com"
|
||||
) -> bool:
|
||||
url = f"{parse_github_mirror(github_mirror)}/subframe7536/maple-font/releases/download/{tag}/cn-base.zip"
|
||||
zip_path = "cn-base-static.zip"
|
||||
return download_zip_and_extract(
|
||||
name="Nerd Font Patcher", url=url, zip_path=zip_path, output_dir=target_dir
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue