MPV (clang) #607
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: MPV | |
run-name: "${{ inputs.run_name != '' && format('{0} ({1})', inputs.run_name, inputs.compiler) || inputs.prs != '' && format('{0}[{2}] ({1})', github.workflow, inputs.compiler, inputs.prs) || format('{0} ({1})', github.workflow, inputs.compiler) }}" | |
on: | |
workflow_dispatch: | |
inputs: | |
build_target: | |
description: "Build target" | |
required: false | |
default: "all-64bit" | |
type: choice | |
options: | |
- 64bit | |
- 64bit-v3 | |
- aarch64 | |
- all-64bit | |
- all | |
lgpl: | |
description: "Also build lgpl libmpv" | |
required: false | |
default: false | |
type: boolean | |
compiler: | |
required: false | |
default: "clang" | |
type: choice | |
options: | |
- clang | |
needclean: | |
description: 'Build without cache' | |
required: false | |
default: false | |
type: boolean | |
no_save_cache: | |
description: "Don't save caches after success build" | |
required: false | |
default: false | |
type: boolean | |
release: | |
description: "Publish a release" | |
required: false | |
default: true | |
type: boolean | |
command: | |
description: 'input command you want to run before build' | |
required: false | |
prs: | |
description: "Input the pr numbers of mpv,split items by comma(',')" | |
required: false | |
run_name: | |
description: 'The name displayed in the list of workflow runs' | |
required: false | |
jobs: | |
params: | |
runs-on: ubuntu-latest | |
outputs: | |
sha: ${{ steps.script.outputs.sha }} | |
matrix: ${{ steps.script.outputs.matrix }} | |
patch_note: ${{ steps.script.outputs.patch_note }} | |
steps: | |
- id: script | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const commit = await github.rest.repos.getCommit({ | |
owner: 'mpv-player', | |
repo: 'mpv', | |
ref: `master` | |
}) | |
core.setOutput('sha', String(commit.data.sha)) | |
let matrix = {}; | |
let build_target = "${{ inputs.build_target }}" | |
switch ( build_target ) { | |
case "32bit": | |
matrix.bit = ["32"]; | |
break; | |
case "64bit": | |
matrix.bit = ["64"]; | |
break; | |
case "64bit-v3": | |
matrix.bit = ["64-v3"]; | |
break; | |
case "aarch64": | |
matrix.bit = ["aarch64"]; | |
break; | |
case "all-64bit": | |
matrix.bit = ["64-v3","aarch64"]; | |
break; | |
case "all": | |
matrix.bit = ["64-v3","aarch64"]; | |
break; | |
default: | |
matrix.bit = ["64-v3","aarch64"]; | |
break; | |
} | |
matrix.lgpl=[false]; | |
if ("${{ inputs.lgpl}}" == "true") { | |
matrix.lgpl.push(true) | |
} | |
core.setOutput("matrix",JSON.stringify(matrix)); | |
const fs = require('fs/promises'); | |
const sleep = ms => new Promise(res => setTimeout(res, ms)); | |
const waitingMergeability = async(o)=>{ | |
let count = 0; | |
while (count<5) { | |
count = count + 1; | |
const res = await github.rest.pulls.get(o); | |
// If the 'mergeable' is 'null', waiting for GitHub to compute the mergeability | |
if (res.data.merged || res.data.mergeable != null) return res; | |
if (count<5) await sleep(300*2**count); | |
} | |
}; | |
let prs = "${{ inputs.prs }}".split(',').map(e=>e.trim()); | |
let i = 1; | |
let patch_note = ""; | |
for (const pr of prs) { | |
let pr_number = parseInt(pr); | |
if (isNaN(pr_number)) { | |
console.warn(`'${pr}' is not a number.`); | |
continue; | |
} | |
try { | |
const res = await waitingMergeability({ | |
owner: "mpv-player", | |
repo: "mpv", | |
pull_number: pr_number, | |
}); | |
if( res === undefined || res.data.merged || !res.data.mergeable ) { | |
console.warn(`Pr#${pr_number} can't merged because it has been merged or has conflicts with the base branch.`); | |
continue; | |
} | |
const {status,data:content} = await github.request(res.data.patch_url); | |
const name = res.data.title.replace(/[/\\?%*:|`'"<> ]/g,'-').replace(/--+/g,'-'); | |
await fs.writeFile(`mpv-${String(i).padStart(4,'0')}-#${pr_number}-${name}.patch`, content) | |
.then( ()=>{ i++; patch_note+=`- [#${pr_number}](${res.data.html_url}): ${res.data.title.replace(/`/g, '\\`')}\n`; }) | |
.catch(err => console.log(err)); | |
console.log(`Download patch of #${pr_number}: ${res.data.title}.`) | |
} catch(error) { | |
if (error?.response) { | |
console.warn(`Get pr#${pr_number} failed: ${error.response.data.message}.`); | |
} else { | |
console.warn(error); | |
} | |
continue; | |
}; | |
} | |
core.setOutput("patch_note",patch_note.trim()); | |
- name: upload patch | |
uses: actions/upload-artifact@v4 | |
if: ${{ steps.script.outputs.patch_note }} | |
with: | |
name: mpv-patch | |
path: "*.patch" | |
build_mpv: | |
name: Build MPV | |
needs: params | |
runs-on: ubuntu-latest | |
container: | |
image: cachyos/cachyos-v3:latest | |
continue-on-error: true | |
strategy: | |
matrix: ${{ fromJson(needs.params.outputs.matrix) }} | |
steps: | |
- name: Install Dependencies | |
run: | | |
sudo bash -c 'yes y|pacman -Syu' | |
sudo bash -c 'yes y|pacman -Sy --needed base-devel dash zlib-ng-compat git ninja cmake meson unzip ragel yasm nasm gperf rst2pdf python-cairo curl wget mimalloc go ccache wine' | |
mkdir -p /home/opt/7zip | |
wget -qO - https://www.7-zip.org/a/7z2408-linux-x64.tar.xz | tar -xJf - -C /home/opt/7zip 7zzs | |
sudo ln -s /home/opt/7zip/7zzs /usr/bin/7z | |
git config --global user.name "github-actions[bot]" | |
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
git config --global pull.rebase true | |
git config --global rebase.autoStash true | |
git config --global fetch.prune true | |
sudo GOBIN=/usr/bin go install go.chromium.org/luci/cipd/client/cmd/...@latest | |
sudo cipd install fuchsia/third_party/clang/linux-amd64 latest -root /usr/local/fuchsia-clang | |
sudo rm /usr/bin/sh | |
sudo ln -s dash /usr/bin/sh | |
echo "PATH=/usr/local/fuchsia-clang/bin:$PATH" >> $GITHUB_ENV | |
- uses: actions/checkout@v4 | |
- name: Checkout toolchain | |
uses: actions/checkout@v4 | |
with: | |
repository: Andarwinux/mpv-winbuild-cmake | |
path: mpv-winbuild-cmake | |
fetch-depth: 0 | |
- name: Prepare | |
run: | | |
echo "sha=${{ needs.params.outputs.sha }}" >> $GITHUB_ENV | |
echo "short_time=$(date "+%Y-%m-%d")" >> $GITHUB_ENV | |
echo "cache_suffix=$(date "+%Y-%m-%d")-${{ github.run_id }}-${{ github.run_attempt }}" >> $GITHUB_ENV | |
sed -i '/ccache_conf.in/d' mpv-winbuild-cmake/CMakeLists.txt | |
sed -i '/ccache/d' mpv-winbuild-cmake/exec.in | |
- name: Lookup Toolchain Cache | |
id: lookup_toolchain | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/build${{ matrix.bit }} | |
key: toolchain-${{ inputs.compiler }}-build${{ matrix.bit }}-${{ env.cache_suffix }} | |
restore-keys: | | |
toolchain-${{ inputs.compiler }}-build${{ matrix.bit }}- | |
lookup-only: true | |
- name: Lookup Build Cache | |
id: lookup_build | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/build${{ matrix.bit }} | |
key: ${{ inputs.compiler }}-build${{ matrix.bit }}-${{ env.cache_suffix }} | |
restore-keys: | | |
${{ inputs.compiler }}-build${{ matrix.bit }}- | |
lookup-only: true | |
- name: Generate cache key | |
id: generate_key | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
let toolchain_restore_key="${{ steps.lookup_toolchain.outputs.cache-matched-key }}"; | |
let build_restore_key="${{ steps.lookup_build.outputs.cache-matched-key }}"; | |
let build_save_key="${{ inputs.compiler }}-build${{ matrix.bit }}-${{ env.cache_suffix }}"; | |
let key_suffix= "${{ env.cache_suffix }}" | |
let restore_suffix= ""; // if only want to match primaryKey, set a value which make restore-keys can't hit | |
// If toolchain cache exist, compare version of toolchain and build | |
if (toolchain_restore_key) { | |
const toolchain_version = toolchain_restore_key.split("-build${{ matrix.bit }}-").at(-1); | |
core.exportVariable( `toolchain_version`, toolchain_version ); | |
build_save_key += `(${toolchain_version})`; | |
// If build cache version is not same as toolchain or needclean=true, don't restore build cache. | |
// Else, don't restore toolchain cache and use build cache. | |
if ( !build_restore_key.includes(toolchain_version) || ${{ inputs.needclean }} ) { | |
build_restore_key=""; | |
key_suffix=toolchain_version; // only use same version cache as toolchain-version | |
restore_suffix="-only-use-primaryKey-"; // make restore-keys can't hit | |
} else { | |
toolchain_restore_key=""; | |
} | |
} | |
core.exportVariable( `toolchain_restore_key`, toolchain_restore_key ); | |
core.exportVariable( `build_restore_key`, build_restore_key ); | |
core.exportVariable( `build_save_key`, build_save_key ); | |
core.exportVariable( `key_suffix`, key_suffix ); | |
core.exportVariable( `restore_suffix`, restore_suffix ); | |
- name: Keep inital clang sysroot cache alive | |
if: ${{ inputs.compiler =='clang' && env.toolchain_version }} | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/clang_root | |
key: ${{ matrix.bit }}-clang_root-${{ env.toolchain_version }} | |
restore-keys: | | |
${{ matrix.bit }}-clang_root-${{ env.toolchain_version }} | |
lookup-only: true | |
- name: Keep llvm cache alive | |
if: ${{ inputs.compiler =='clang' }} | |
uses: actions/cache/[email protected] | |
with: | |
path: mpv-winbuild-cmake/clang_root | |
key: llvm-${{ env.toolchain_version }} | |
restore-keys: | | |
llvm- | |
lookup-only: true | |
- name: Restore clang sysroot cache | |
if: ${{ inputs.compiler =='clang' }} | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/clang_root | |
key: ${{ matrix.bit }}-clang_root-${{ env.key_suffix }} | |
restore-keys: | | |
${{ matrix.bit }}-clang_root-${{ env.restore_suffix }} | |
- name: Restore Rust Cache | |
uses: actions/cache/[email protected] | |
id: cache_rust | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/install_rustup | |
key: rust-${{ env.key_suffix }} | |
restore-keys: | | |
rust-${{ env.restore_suffix }} | |
- name: Restore Source Cache | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/src_packages | |
key: source-${{ env.key_suffix }} | |
restore-keys: | | |
source-${{ env.restore_suffix }} | |
- name: Restore Toolchain Cache | |
if: ${{ env.toolchain_restore_key != '' }} | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/build${{ matrix.bit }} | |
key: ${{ env.toolchain_restore_key }} | |
- name: Restore Build Cache | |
if: ${{ inputs.needclean != true && env.build_restore_key != '' }} | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/build${{ matrix.bit }} | |
key: ${{ env.build_restore_key }} | |
- name: Set up ccache | |
uses: zhongfly/setup-ccache-action@dist | |
with: | |
update_packager_index: false | |
install_ccache: false | |
prepend_symlinks_to_path: false | |
store_cache: ${{ matrix.lgpl != true && inputs.no_save_cache != true }} | |
override_cache_key: ccache-build${{ matrix.bit }}-${{ inputs.compiler }} | |
ccache_options: | | |
cache_dir=$GITHUB_WORKSPACE/.ccache | |
max_size=2G | |
sloppiness=locale,time_macros,pch_defines | |
compression=false | |
compiler_check=none | |
- name: Download mpv patch | |
if: ${{ needs.params.outputs.patch_note }} | |
uses: actions/download-artifact@v4 | |
with: | |
name: mpv-patch | |
path: mpv-patch | |
- name: Apply mpv pr releated patch | |
if: ${{ needs.params.outputs.patch_note }} | |
continue-on-error: true | |
run: | | |
shopt -s globstar | |
cp mpv-patch/*.patch mpv-winbuild-cmake/packages | |
ls mpv-winbuild-cmake/packages/mpv-*.patch | |
cd mpv-winbuild-cmake | |
if [[ "$(ls -A ../patch_pr/0000-*.patch)" ]]; then | |
for patch in ../patch_pr/0000-*.patch ; do | |
git am --3way "$patch" || git am --abort | |
done | |
fi | |
for patch in packages/mpv-*.patch ; do | |
pr="$(echo ${patch#*#} | cut -d- -f1)" | |
if [[ "$(ls -A ../patch_pr/#${pr}-*.patch)" ]]; then | |
for p in ../patch_pr/#${pr}-*.patch ; do | |
git am --3way "$p" || git am --abort | |
done | |
fi | |
done | |
- name: Running custom command | |
if: ${{ inputs.command != '' }} | |
shell: bash | |
continue-on-error: true | |
run: | | |
cd mpv-winbuild-cmake | |
bit="${{ matrix.bit }}" | |
compiler="${{ inputs.compiler }}" | |
gitdir=$(pwd) | |
clang_root=$(pwd)/clang_root | |
buildroot=$(pwd) | |
srcdir=$(pwd)/src_packages | |
builddir=$buildroot/build$bit | |
if [ $bit == "32" ]; then | |
arch="i686" | |
elif [ $bit == "64" ]; then | |
arch="x86_64" | |
elif [ $bit == "64-v3" ]; then | |
arch="x86_64" | |
gcc_arch=-DGCC_ARCH=x86-64-v3 | |
x86_64_level=-v3 | |
elif [ $bit == "aarch64" ]; then | |
arch="aarch64" | |
fi | |
retry-tool() { | |
local RETRY_COUNTER=0 | |
local MAX_RETRY=3 | |
while [[ $RETRY_COUNTER -lt $MAX_RETRY ]]; do | |
$@ && break || sleep 2 | |
RETRY_COUNTER=$(( $RETRY_COUNTER + 1 )) | |
echo "Retry $RETRY_COUNTER..." | |
done | |
if [[ $RETRY_COUNTER -ge $MAX_RETRY ]]; then | |
echo "Max retry count exceeded." | |
fi | |
} | |
set -x | |
${{ inputs.command }} | |
- name: Build | |
id: build | |
shell: bash | |
run: | | |
chmod +x build.sh | |
cd mpv-winbuild-cmake | |
if [[ "$(ls -A ../patch/*.patch)" ]]; then | |
for patch in ../patch/*.patch ; do | |
git am --3way "$patch" || git am --abort | |
done | |
fi | |
if [ "${{ matrix.lgpl }}" = "true" ]; then | |
git am --3way ../compile-lgpl-libmpv.patch | |
fi | |
bash ../build.sh -t '${{ matrix.bit }}' -c '${{ inputs.compiler }}' -s "${{ matrix.lgpl == true && 'true' || 'false' }}" | |
- name: Collect logs | |
if: ${{ always() }} | |
run: | | |
sudo 7z a logs.7z $(find mpv-winbuild-cmake/build${{ matrix.bit }} -type f -iname "*-*.log" -or -wholename "*/ffbuild/config.log") | |
- name: upload logs | |
uses: actions/upload-artifact@v4 | |
if: ${{ always() }} | |
with: | |
name: ${{ matrix.bit }}${{ matrix.lgpl == true && '-lgpl' || '' }}_logs | |
path: logs.7z | |
- name: "Get artifacts' name and path" | |
id: get_files | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const path = require('path'); | |
const types = ["mpv-debug", "mpv-dev", "mpv"]; | |
const lgpl = ${{ matrix.lgpl }} ? "-lgpl" : ""; | |
let arch=""; | |
switch ( "${{ matrix.bit }}" ) { | |
case "32": | |
arch = "i686"; | |
break; | |
case "64": | |
arch = "x86_64"; | |
break; | |
case "64-v3": | |
arch = "x86_64-v3"; | |
break; | |
case "aarch64": | |
arch = "aarch64"; | |
break; | |
} | |
for (let type of types) { | |
const globber = await glob.create(`mpv-winbuild-cmake/release/${type}${lgpl}-${arch}-*.7z`); | |
const files = await globber.glob(); | |
if ( files.length > 0 ) { | |
const file = files[0]; | |
core.exportVariable( `${type}_name`, path.basename(file) ); | |
core.exportVariable( `${type}_path`, file ); | |
} | |
} | |
let mimalloc_r_path = ""; | |
let mimalloc_o_path = ""; | |
if ( arch != "aarch64" ){ | |
const globber_mimalloc_r = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/mimalloc-redirect.dll`); | |
mimalloc_r_path = (await globber_mimalloc_r.glob())[0]; | |
const globber_mimalloc_o = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/mimalloc-override.dll`); | |
mimalloc_o_path = (await globber_mimalloc_o.glob())[0]; | |
} | |
let { stdout: ffmpeg_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/ffmpeg rev-parse --short HEAD"); | |
ffmpeg_hash = ffmpeg_hash.trim(); | |
const ffmpeg_name = `ffmpeg${lgpl}-${arch}-git-${ffmpeg_hash}`; | |
core.exportVariable('ffmpeg_name', ffmpeg_name); | |
const globber_ffmpeg = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/ffmpeg.exe`); | |
const ffmpeg_path = (await globber_ffmpeg.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${ffmpeg_name}.7z ${ffmpeg_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: ffprobe_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/ffmpeg rev-parse --short HEAD"); | |
ffprobe_hash = ffprobe_hash.trim(); | |
const ffprobe_name = `ffprobe${lgpl}-${arch}-git-${ffprobe_hash}`; | |
core.exportVariable('ffprobe_name', ffprobe_name); | |
const globber_ffprobe = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/ffprobe.exe`); | |
const ffprobe_path = (await globber_ffprobe.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${ffprobe_name}.7z ${ffprobe_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: ffplay_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/ffmpeg rev-parse --short HEAD"); | |
ffplay_hash = ffplay_hash.trim(); | |
const ffplay_name = `ffplay${lgpl}-${arch}-git-${ffplay_hash}`; | |
core.exportVariable('ffplay_name', ffplay_name); | |
const globber_ffplay = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/ffplay.exe`); | |
const ffplay_path = (await globber_ffplay.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${ffplay_name}.7z ${ffplay_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: x265_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/x265 rev-parse --short HEAD"); | |
x265_hash = x265_hash.trim(); | |
const x265_name = `x265-${arch}-git-${x265_hash}`; | |
core.exportVariable('x265_name', x265_name); | |
const globber_x265 = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/x265.exe`); | |
const x265_path = (await globber_x265.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${x265_name}.7z ${x265_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: libmediainfo_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/libmediainfo rev-parse --short HEAD"); | |
libmediainfo_hash = libmediainfo_hash.trim(); | |
const libmediainfo_name = `libmediainfo-${arch}-git-${libmediainfo_hash}`; | |
core.exportVariable('libmediainfo_name', libmediainfo_name); | |
const globber_libmediainfo = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/libmediainfo.dll`); | |
const libmediainfo_path = (await globber_libmediainfo.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${libmediainfo_name}.7z ${libmediainfo_path}`); | |
let { stdout: mediainfo_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/mediainfo rev-parse --short HEAD"); | |
mediainfo_hash = mediainfo_hash.trim(); | |
const mediainfo_name = `mediainfo-${arch}-git-${mediainfo_hash}`; | |
core.exportVariable('mediainfo_name', mediainfo_name); | |
const globber_mediainfo = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/mediainfo.exe`); | |
const mediainfo_path = (await globber_mediainfo.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${mediainfo_name}.7z ${mediainfo_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: mpv_debug_plugin_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/mpv-debug-plugin rev-parse --short HEAD"); | |
mpv_debug_plugin_hash = mpv_debug_plugin_hash.trim(); | |
const mpv_debug_plugin_name = `mpv-debug-plugin-${arch}-git-${mpv_debug_plugin_hash}`; | |
core.exportVariable('mpv-debug-plugin_name', mpv_debug_plugin_name); | |
const globber_mpv_debug_plugin = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/debug.dll`); | |
const mpv_debug_plugin_path = (await globber_mpv_debug_plugin.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${mpv_debug_plugin_name}.7z ${mpv_debug_plugin_path}`); | |
let { stdout: mpv_menu_plugin_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/mpv-menu-plugin rev-parse --short HEAD"); | |
mpv_menu_plugin_hash = mpv_menu_plugin_hash.trim(); | |
const mpv_menu_plugin_name = `mpv-menu-plugin-${arch}-git-${mpv_menu_plugin_hash}`; | |
core.exportVariable('mpv-menu-plugin_name', mpv_menu_plugin_name); | |
const globber_mpv_menu_plugin = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/menu.dll`); | |
const mpv_menu_plugin_path = (await globber_mpv_menu_plugin.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${mpv_menu_plugin_name}.7z ${mpv_menu_plugin_path}`); | |
let { stdout: curl_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/curl rev-parse --short HEAD"); | |
curl_hash = curl_hash.trim(); | |
const curl_name = `curl-${arch}-git-${curl_hash}`; | |
core.exportVariable('curl_name', curl_name); | |
const globber_curl = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/curl.exe`); | |
const curl_path = (await globber_curl.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${curl_name}.7z ${curl_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: aria2_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/aria2 rev-parse --short HEAD"); | |
aria2_hash = aria2_hash.trim(); | |
const aria2_name = `aria2-${arch}-git-${aria2_hash}`; | |
core.exportVariable('aria2_name', aria2_name); | |
const globber_aria2 = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/aria2c.exe`); | |
const aria2_path = (await globber_aria2.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${aria2_name}.7z ${aria2_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: qbittorrent_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/qbittorrent rev-parse --short HEAD"); | |
qbittorrent_hash = qbittorrent_hash.trim(); | |
const qbittorrent_name = `qbittorrent-${arch}-git-${qbittorrent_hash}`; | |
core.exportVariable('qbittorrent_name', qbittorrent_name); | |
const globber_qbittorrent = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/qbittorrent.exe`); | |
const qbittorrent_path = (await globber_qbittorrent.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${qbittorrent_name}.7z ${qbittorrent_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: openssl_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/openssl rev-parse --short HEAD"); | |
openssl_hash = openssl_hash.trim(); | |
const openssl_name = `openssl-${arch}-git-${openssl_hash}`; | |
core.exportVariable('openssl_name', openssl_name); | |
const globber_openssl = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/openssl.exe`); | |
const openssl_path = (await globber_openssl.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${openssl_name}.7z ${openssl_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: zstd_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/zstd rev-parse --short HEAD"); | |
zstd_hash = zstd_hash.trim(); | |
const zstd_name = `zstd-${arch}-git-${zstd_hash}`; | |
core.exportVariable('zstd_name', zstd_name); | |
const globber_zstd = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/zstd.exe`); | |
const zstd_path = (await globber_zstd.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${zstd_name}.7z ${zstd_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: svtav1_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/svtav1 rev-parse --short HEAD"); | |
svtav1_hash = svtav1_hash.trim(); | |
const svtav1_name = `svtav1-${arch}-git-${svtav1_hash}`; | |
core.exportVariable('svtav1_name', svtav1_name); | |
const globber_svtav1 = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/SvtAv1EncApp.exe`); | |
const svtav1_path = (await globber_svtav1.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${svtav1_name}.7z ${svtav1_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
let { stdout: telegram_bot_api_hash } = await exec.getExecOutput("git -C mpv-winbuild-cmake/src_packages/telegram-bot-api rev-parse --short HEAD"); | |
telegram_bot_api_hash = telegram_bot_api_hash.trim(); | |
const telegram_bot_api_name = `telegram-bot-api-${arch}-git-${telegram_bot_api_hash}`; | |
core.exportVariable('telegram_bot_api_name', telegram_bot_api_name); | |
const globber_telegram_bot_api = await glob.create(`./mpv-winbuild-cmake/build${{ matrix.bit }}/**/telegram-bot-api.exe`); | |
const telegram_bot_api_path = (await globber_telegram_bot_api.glob())[0]; | |
await exec.exec(`7z a -m0=lzma2 -mx=9 -ms=on mpv-winbuild-cmake/release/${telegram_bot_api_name}.7z ${telegram_bot_api_path} ${mimalloc_r_path} ${mimalloc_o_path}`); | |
- name: upload mpv-debug | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.mpv-debug_name && env.mpv-debug_path }} | |
with: | |
name: ${{ env.mpv-debug_name }} | |
path: ${{ env.mpv-debug_path }} | |
- name: upload mpv-dev | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.mpv-dev_name && env.mpv-dev_path }} | |
with: | |
name: ${{ env.mpv-dev_name }} | |
path: ${{ env.mpv-dev_path }} | |
- name: upload mpv | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.mpv_name && env.mpv_path }} | |
with: | |
name: ${{ env.mpv_name }} | |
path: ${{ env.mpv_path }} | |
- name: upload ffmpeg | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.ffmpeg_name }} | |
with: | |
name: ${{ env.ffmpeg_name }} | |
path: mpv-winbuild-cmake/release/${{ env.ffmpeg_name }}.7z | |
- name: upload ffprobe | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.ffprobe_name }} | |
with: | |
name: ${{ env.ffprobe_name }} | |
path: mpv-winbuild-cmake/release/${{ env.ffprobe_name }}.7z | |
- name: upload ffplay | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.ffplay_name }} | |
with: | |
name: ${{ env.ffplay_name }} | |
path: mpv-winbuild-cmake/release/${{ env.ffplay_name }}.7z | |
- name: upload x265 | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.x265_name }} | |
with: | |
name: ${{ env.x265_name }} | |
path: mpv-winbuild-cmake/release/${{ env.x265_name }}.7z | |
- name: upload libmediainfo | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.libmediainfo_name }} | |
with: | |
name: ${{ env.libmediainfo_name }} | |
path: mpv-winbuild-cmake/release/${{ env.libmediainfo_name }}.7z | |
- name: upload mediainfo | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.mediainfo_name }} | |
with: | |
name: ${{ env.mediainfo_name }} | |
path: mpv-winbuild-cmake/release/${{ env.mediainfo_name }}.7z | |
- name: upload curl | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.curl_name }} | |
with: | |
name: ${{ env.curl_name }} | |
path: mpv-winbuild-cmake/release/${{ env.curl_name }}.7z | |
- name: upload aria2 | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.aria2_name }} | |
with: | |
name: ${{ env.aria2_name }} | |
path: mpv-winbuild-cmake/release/${{ env.aria2_name }}.7z | |
- name: upload qbittorrent | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.qbittorrent_name }} | |
with: | |
name: ${{ env.qbittorrent_name }} | |
path: mpv-winbuild-cmake/release/${{ env.qbittorrent_name }}.7z | |
- name: upload openssl | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.openssl_name }} | |
with: | |
name: ${{ env.openssl_name }} | |
path: mpv-winbuild-cmake/release/${{ env.openssl_name }}.7z | |
- name: upload zstd | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.zstd_name }} | |
with: | |
name: ${{ env.zstd_name }} | |
path: mpv-winbuild-cmake/release/${{ env.zstd_name }}.7z | |
- name: upload svtav1 | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.svtav1_name }} | |
with: | |
name: ${{ env.svtav1_name }} | |
path: mpv-winbuild-cmake/release/${{ env.svtav1_name }}.7z | |
- name: upload telegram-bot-api | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.telegram_bot_api_name }} | |
with: | |
name: ${{ env.telegram_bot_api_name }} | |
path: mpv-winbuild-cmake/release/${{ env.telegram_bot_api_name }}.7z | |
- name: upload mpv-debug-plugin | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.mpv-debug-plugin_name }} | |
with: | |
name: ${{ env.mpv-debug-plugin_name }} | |
path: mpv-winbuild-cmake/release/${{ env.mpv-debug-plugin_name }}.7z | |
- name: upload mpv-menu-plugin | |
uses: actions/upload-artifact@v4 | |
if: ${{ env.mpv-menu-plugin_name }} | |
with: | |
name: ${{ env.mpv-menu-plugin_name }} | |
path: mpv-winbuild-cmake/release/${{ env.mpv-menu-plugin_name }}.7z | |
- name: Save clang sysroot cache | |
if: ${{ inputs.compiler =='clang' && inputs.no_save_cache != true && matrix.lgpl != true }} | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/clang_root | |
key: ${{ matrix.bit }}-clang_root-${{ env.cache_suffix }} | |
- name: Save Sources Cache | |
if: ${{ inputs.no_save_cache != true && matrix.lgpl != true }} | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/src_packages | |
key: source-${{ env.cache_suffix }} | |
- name: Save Rust Cache | |
if: ${{ inputs.no_save_cache != true && matrix.lgpl != true }} | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/install_rustup | |
key: rust-${{ env.cache_suffix }} | |
- name: Save Build Cache | |
if: ${{ inputs.no_save_cache != true && matrix.lgpl != true }} | |
uses: actions/cache/[email protected] | |
with: | |
path: ${{ github.workspace }}/mpv-winbuild-cmake/build${{ matrix.bit }} | |
key: ${{ env.build_save_key }} | |
- name: "Job summary" | |
uses: actions/github-script@v7 | |
continue-on-error: true | |
if: ${{ always() }} | |
with: | |
script: | | |
const path = require('path'); | |
const { readdirSync,existsSync } = require('fs'); | |
const myExec = async (command, args = null) => await exec.getExecOutput(command,args,{silent: true}).then(result => result.stdout.trim()).catch(err => ''); | |
const upstreamDir = path.resolve("mpv-winbuild-cmake"); | |
const workdir = path.resolve(upstreamDir,"src_packages"); | |
const isGitSync = dirname => existsSync(path.join(workdir, dirname, '.git')); | |
const getGithubUrl = (hash,remote) => remote.replace(/\.git$/,"") + `/commit/${hash}`; | |
const getGitlabUrl = (hash,remote) => remote.replace(/\.git$/,"") + `/-/commit/${hash}`; | |
const getBitbucketUrl = (hash,remote) => remote.replace(/\.git$/,"") + `/commits/${hash}`; | |
const getGoogleSourceUrl = (hash,remote) => remote + `/+/${hash}`; | |
const gethGitVideolanUrl = (hash,remote) => remote.replace(/\/git\//,"/?p=") + `;a=commit;h=${hash}`; | |
const getCgitUrl = (hash,remote) => remote + `/commit/?id=${hash}`; | |
function getCommitUrl(hash,remote) { | |
let url = ""; | |
switch (true) { | |
case /github\.com/.test(remote): | |
url = getGithubUrl(hash,remote); | |
break; | |
case /(gitlab\.com|code\.videolan\.org|gitlab\.(gnome|freedesktop)\.org)/.test(remote): | |
url = getGitlabUrl(hash,remote); | |
break; | |
case /bitbucket\.org/.test(remote): | |
url = getBitbucketUrl(hash,remote); | |
break; | |
case /googlesource\.com/.test(remote): | |
url = getGoogleSourceUrl(hash,remote); | |
break; | |
case /git\.videolan\.org/.test(remote): | |
url = gethGitVideolanUrl(hash,remote); | |
break; | |
case /git\.libssh\.org/.test(remote): | |
url = getCgitUrl(hash,remote); | |
break; | |
default: | |
url = remote; | |
break; | |
} | |
return url; | |
} | |
async function repo_info(dir){ | |
let local_hash = await myExec(`git -C ${dir} rev-parse --short=7 HEAD`); | |
let remote_branch = await myExec(`git -C ${dir} rev-parse --abbrev-ref HEAD@{upstream}`); | |
let remote_hash = await myExec(`git -C ${dir} rev-parse ${remote_branch}`); | |
let status = await myExec(`git -C ${dir} status -sb`).then(s => s.split("\n",1)[0].replace(/^## */,"")); | |
let remote = await myExec(`git -C ${dir} config --get remote.origin.url`); | |
return [local_hash, remote_hash, status, remote] | |
} | |
async function generateGitInfoTable(targetDir){ | |
const dirs = readdirSync(targetDir, { withFileTypes: true }) | |
.filter(dirent => dirent.isDirectory() && isGitSync(dirent.name) ) | |
.map(dirent => path.join(targetDir, dirent.name)); | |
let info_table = [[{data: 'Package', header: true}, {data: 'Local commit', header: true}, {data: 'Status', header: true}, {data: 'Remote commit', header: true}]]; | |
for (let dir of dirs) { | |
[local_hash, remote_hash, status, remote] = await repo_info(dir) | |
let url = getCommitUrl(remote_hash, remote); | |
let package_name = path.basename(dir); | |
info_table.push([package_name, local_hash, status, `<a href="${url}">${remote_hash.slice(0,7)}</a>`]); | |
} | |
return info_table; | |
} | |
await core.summary.clear(); | |
let packages_table = await generateGitInfoTable(workdir); | |
packages_table = core.summary.addTable(packages_table).stringify(); | |
await core.summary.clear(); | |
[upstream_local_hash, upstream_remote_hash, upstream_status, upstream_remote] = await repo_info(upstreamDir) | |
const upstream_url = getCommitUrl(upstream_remote_hash, upstream_remote); | |
const exec_path = path.join(upstreamDir,'build${{ matrix.bit }}','exec'); | |
const compiler_version = (await myExec(`${exec_path}`,["cross-gcc","--version","||","clang","--version"])).split('\n')[0]; | |
core.summary | |
.addRaw(`mpv-winbuild-cmake: ${upstream_status} (remote:<a href="${upstream_url}">${upstream_remote_hash.slice(0,7)}</a>)`,true) | |
.addRaw(`Compiler: ${compiler_version}`,true); | |
const patch_note = `${{ needs.params.outputs.patch_note }}`; | |
if (patch_note) { | |
core.summary.addHeading('Merged Prs'); | |
core.summary.addList(patch_note.replace(/- \[(?<pr>#\d+)\]\((?<url>.*)\)/g,"<a href='$<url>'>$<pr></a>").replace(/`(?<code>[^`]+)`/g, '<code>$<code></code>').split('\n')); | |
} | |
await core.summary.addDetails('Packages Version',packages_table).write(); | |
publish_release: | |
name: Publish release | |
needs: [build_mpv,params] | |
if: ${{ inputs.release == true }} | |
runs-on: ubuntu-latest | |
permissions: | |
id-token: write | |
attestations: write | |
contents: write | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Download artifacts | |
uses: actions/download-artifact@v4 | |
with: | |
path: artifacts | |
pattern: '{mpv,ffmpeg,ffprobe,ffplay,x265,libmediainfo,mediainfo,curl,aria2,qbittorrent,zstd,openssl,svtav1,telegram-bot-api}*' | |
merge-multiple: true | |
- name: "Check artifacts" | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const globber = await glob.create(`artifacts/mpv*.7z`); | |
const files = await globber.glob(); | |
if ( files.length == 0 ) { | |
core.setFailed("Artifact does not exist!"); | |
} | |
- name: Get current time | |
run: | | |
echo "long_time=$(date "+%Y-%m-%d %H:%M")" >> $GITHUB_ENV | |
echo "short_time=$(date "+%Y-%m-%d")" >> $GITHUB_ENV | |
echo "tag_name=$(date "+%Y-%m-%d")-$(head -c 7 <<< "${{needs.params.outputs.sha}}")" >> $GITHUB_ENV | |
- name: Commit version & remove existing tag | |
env: | |
tag_name: ${{ env.tag_name }} | |
GH_TOKEN: ${{ github.token }} | |
shell: bash | |
run: | | |
git fetch --tags | |
git checkout version || git checkout -b version origin/version || ( git checkout --orphan version && git rm -rf . ) | |
echo -e "${tag_name}" > version | |
git config --global user.name "github-actions[bot]" | |
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
git add version | |
git diff-index --quiet HEAD || ( git commit -m "${tag_name}" && git push origin version ) | |
if [ $(git tag -l "${tag_name}") ] ;then | |
gh release delete "${tag_name}" || true | |
git push --delete origin "${tag_name}" || true | |
git tag -d "${tag_name}" || true | |
fi | |
git checkout main | |
- name: "Generate release note & sha256" | |
id: note | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const sha = `${{ needs.params.outputs.sha }}`; | |
let note = `**MPV Git commit**: https://github.com/mpv-player/mpv/commit/${sha}\n`; | |
note+="**Build Time**: ${{ env.long_time }}\n"; | |
note+="**Compiler**: ${{ inputs.compiler }}\n"; | |
note+="**Build Details**: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}\n"; | |
const patch_note = `${{ needs.params.outputs.patch_note }}` ; | |
if (patch_note) { | |
note+=`Merged Prs:\n${patch_note}\n`; | |
} | |
note+="**Download Tips:**\n"; | |
const path = require('path'); | |
const tips = { | |
"i686": "for 32 bit system", | |
"x86_64": "for 64 bit system", | |
"x86_64-v3": "for 64 bit system with cpu not older than Intel Haswell or AMD Excavator", | |
"aarch64": "for ARM64(aarch64)" | |
} | |
async function getTips(arch){ | |
const globber = await glob.create(`artifacts/mpv-${arch}-[0-9]*.7z`); | |
const files = await globber.glob(); | |
if ( files.length > 0 ) { | |
const name = path.basename(files[0]); | |
return `[${name}](https://github.com/${{github.repository}}/releases/download/${{ env.tag_name }}/${name}): ${tips[arch]}\n` | |
} else { | |
return "" | |
} | |
} | |
for(const arch of Object.keys(tips)){ | |
note += await getTips(arch); | |
} | |
note+="**Downloads**: ![downloads](https://badgen.net/github/assets-dl/${{github.repository}}/${{ env.tag_name }}?cache=300)"; | |
core.setOutput("note",note); | |
const os = require('os'); | |
const { basename } = require('path'); | |
const { createHash } = require('crypto'); | |
const { readFileSync,writeFileSync } = require('fs'); | |
const globber = await glob.create([`artifacts/mpv*.7z`,`artifacts/ffmpeg*.7z`,`artifacts/ffprobe*.7z`,`artifacts/ffplay*.7z`,`artifacts/x265*.7z`,`artifacts/libmediainfo*.7z`,`artifacts/mediainfo*.7z`,`artifacts/curl*.7z`,`artifacts/aria2*.7z`,`artifacts/qbittorrent*.7z`,`artifacts/openssl*.7z`,`artifacts/zstd*.7z`,`artifacts/svtav1*.7z`,`artifacts/telegram-bot-api*.7z`].join('\n')); | |
const files = await globber.glob(); | |
if ( files.length > 0 ) { | |
let sha256=""; | |
for (let file of files) { | |
const buff = readFileSync(file); | |
const hash = createHash("sha256").update(buff).digest("hex"); | |
sha256+=`${hash} ${basename(file)}${os.EOL}`; | |
} | |
writeFileSync('sha256.txt', sha256.trim(), { flag: 'w+' }); | |
} | |
- name: Create release | |
uses: ncipollo/release-action@v1 | |
with: | |
artifacts: "artifacts/mpv*.7z,artifacts/ffmpeg*.7z,artifacts/ffprobe*.7z,artifacts/ffplay*.7z,artifacts/x265*.7z,artifacts/libmediainfo*.7z,artifacts/mediainfo*.7z,artifacts/curl*.7z,artifacts/aria2*.7z,artifacts/qbittorrent*.7z,artifacts/openssl*.7z,artifacts/zstd*.7z,artifacts/svtav1*.7z,artifacts/telegram-bot-api*.7z,sha256.txt" | |
commit: version | |
name: "${{ env.long_time }}" | |
body: "${{ steps.note.outputs.note }}" | |
tag: "${{ env.tag_name }}" | |
allowUpdates: true | |
artifactErrorsFailBuild: true | |
prerelease: false | |
makeLatest: true | |
- name: Attest | |
uses: actions/attest-build-provenance@v1 | |
continue-on-error: true | |
with: | |
subject-path: 'artifacts/*.7z' | |
- name: Prune old releases | |
shell: bash | |
env: | |
GH_TOKEN: ${{ github.token }} | |
run: | | |
git checkout main | |
bash prunetags.sh |