548 lines
16 KiB
Shell
Executable file
548 lines
16 KiB
Shell
Executable file
#!/bin/bash
|
|
|
|
# Color definitions
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
# Configuration
|
|
BASE_URL="https://magic-mount.zrlab.org/download"
|
|
UPDATE_JSON_URL="https://magic-mount.zrlab.org/version"
|
|
CHANGELOG_URL="https://magic-mount.zrlab.org/changelog"
|
|
MODULE_ID="org.zrlab.magic_mount"
|
|
SHIM_ID="meta-mm"
|
|
|
|
# Build state
|
|
BUILD_TYPES=()
|
|
VERSION=""
|
|
VERSION_FULL=""
|
|
GIT_COMMIT=""
|
|
TEMP_DIRS=()
|
|
BUILD_SHIM=false
|
|
|
|
# Logging functions
|
|
log_info() { echo -e "${GREEN}$*${NC}" >&2; }
|
|
log_warn() { echo -e "${YELLOW}$*${NC}" >&2; }
|
|
log_error() { echo -e "${RED}$*${NC}" >&2; }
|
|
log_step() { echo -e "\n${YELLOW}[$1/$2] $3${NC}" >&2; }
|
|
|
|
# Cleanup function
|
|
cleanup() {
|
|
local exit_code=$?
|
|
|
|
log_warn "Cleaning up temporary directories..."
|
|
|
|
# Clean up other temp directories
|
|
for dir in "${TEMP_DIRS[@]}"; do
|
|
if [ -d "$dir" ]; then
|
|
rm -rf "$dir"
|
|
log_info " Removed: $dir"
|
|
fi
|
|
done
|
|
|
|
# If script failed, show helpful message
|
|
if [ $exit_code -ne 0 ]; then
|
|
log_error "Build failed with exit code $exit_code"
|
|
log_warn "All temporary files have been cleaned up"
|
|
fi
|
|
|
|
exit $exit_code
|
|
}
|
|
|
|
# Register trap for cleanup
|
|
trap cleanup EXIT INT TERM
|
|
|
|
# Usage
|
|
usage() {
|
|
cat << EOF
|
|
Usage: $0 [OPTIONS]
|
|
|
|
OPTIONS:
|
|
--release Build release version
|
|
--debug Build debug version
|
|
--shim Build shim versions (creates both normal and shim variants)
|
|
-h, --help Show this help message
|
|
(no option) Build both release and debug versions
|
|
|
|
When --shim is combined with --release or --debug, both normal and shim
|
|
versions will be built, sharing binaries for efficiency.
|
|
|
|
Version is automatically obtained from git tags.
|
|
|
|
EXAMPLES:
|
|
$0 # Build release and debug (normal)
|
|
$0 --release # Build release only (normal)
|
|
$0 --release --shim # Build release normal + shim
|
|
$0 --debug --shim # Build debug normal + shim
|
|
$0 --shim # Build both types, each with normal + shim
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
# Parse arguments
|
|
parse_args() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-r|--release) BUILD_TYPES+=("release"); shift ;;
|
|
-d|--debug) BUILD_TYPES+=("debug"); shift ;;
|
|
-s|--shim) BUILD_SHIM=true; shift ;;
|
|
-h|--help) usage ;;
|
|
*) log_error "Unknown parameter: $1"; usage ;;
|
|
esac
|
|
done
|
|
|
|
# Default to both if none specified
|
|
[ ${#BUILD_TYPES[@]} -eq 0 ] && BUILD_TYPES=("release" "debug")
|
|
}
|
|
|
|
# Check prerequisites
|
|
check_prerequisites() {
|
|
# Check git repository
|
|
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
|
log_error "Not in a git repository"
|
|
exit 1
|
|
fi
|
|
|
|
# Check zig
|
|
if ! command -v zig &> /dev/null; then
|
|
log_error "zig is not installed"
|
|
exit 1
|
|
fi
|
|
|
|
# Check required directories
|
|
for dir in template src; do
|
|
if [ ! -d "$dir" ]; then
|
|
log_error "Required directory '$dir' not found"
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Get version information from git
|
|
get_version_info() {
|
|
local describe=$(git describe --tags --long --always --dirty 2>/dev/null)
|
|
|
|
if [ -z "$describe" ]; then
|
|
log_error "Failed to get git information"
|
|
exit 1
|
|
fi
|
|
|
|
# Parse git describe output: v1.0.0-5-gabc1234-dirty
|
|
if [[ "$describe" =~ ^(.+)-([0-9]+)-g([0-9a-f]+)(-dirty)?$ ]]; then
|
|
VERSION="${BASH_REMATCH[1]}"
|
|
local commits="${BASH_REMATCH[2]}"
|
|
GIT_COMMIT="${BASH_REMATCH[3]}"
|
|
local dirty="${BASH_REMATCH[4]}"
|
|
|
|
if [ "$commits" = "0" ]; then
|
|
VERSION_FULL="$VERSION"
|
|
log_info "Building release: $VERSION"
|
|
else
|
|
VERSION_FULL="${VERSION}-${commits}-g${GIT_COMMIT}"
|
|
log_warn "Building from $commits commit(s) after $VERSION"
|
|
fi
|
|
|
|
[ -n "$dirty" ] && VERSION_FULL="${VERSION_FULL}-dirty" && log_warn "Working directory is dirty"
|
|
else
|
|
# No tags found
|
|
VERSION="0.0.0"
|
|
GIT_COMMIT="$describe"
|
|
VERSION_FULL="$describe"
|
|
log_warn "No tags found, using commit: $describe"
|
|
fi
|
|
}
|
|
|
|
# Generate changelog
|
|
generate_changelog() {
|
|
local file="build/changelog.md"
|
|
local prev_tag=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null)
|
|
|
|
cat > "$file" << EOF
|
|
# Changelog
|
|
|
|
## Version $VERSION_FULL ($(date +%Y-%m-%d))
|
|
|
|
### Changes
|
|
|
|
EOF
|
|
|
|
if [ -n "$prev_tag" ]; then
|
|
echo "Changes since $prev_tag:" >> "$file"
|
|
echo "" >> "$file"
|
|
git log --pretty=format:"- %s (%h)" "$prev_tag"..HEAD >> "$file"
|
|
echo -e "\n\n---" >> "$file"
|
|
echo "Full Changelog: https://github.com/7a72/meta-magic_mount/compare/${prev_tag}...${VERSION}" >> "$file"
|
|
else
|
|
echo "Initial release" >> "$file"
|
|
echo "" >> "$file"
|
|
git log --pretty=format:"- %s (%h)" >> "$file"
|
|
fi
|
|
}
|
|
|
|
# Generate version.json for release builds
|
|
generate_update_json() {
|
|
local output_name=$1
|
|
local version_code=$2
|
|
local file="build/version.json"
|
|
|
|
cat > "$file" << EOF
|
|
{
|
|
"versionCode": $version_code,
|
|
"version": "$VERSION",
|
|
"zipUrl": "$BASE_URL/$VERSION/$output_name",
|
|
"changelog": "$CHANGELOG_URL"
|
|
}
|
|
EOF
|
|
}
|
|
|
|
# Build binaries
|
|
build_binaries() {
|
|
local build_type=$1
|
|
|
|
log_step 2 9 "Building binaries ($build_type)"
|
|
|
|
cd src || return 1
|
|
make clean > /dev/null 2>&1
|
|
|
|
if ! make "$build_type" VERSION="$VERSION_FULL" >&2; then
|
|
cd ..
|
|
log_error "Failed to build binaries"
|
|
return 1
|
|
fi
|
|
|
|
cd ..
|
|
log_info "Binaries built successfully"
|
|
}
|
|
|
|
# Configure module files
|
|
configure_module() {
|
|
local build_dir=$1
|
|
local build_type=$2
|
|
local version_code=$3
|
|
local is_shim=${4:-false} # Optional parameter, defaults to false
|
|
|
|
# Determine module ID and metamodule value based on variant type
|
|
local module_id_to_use="$MODULE_ID"
|
|
local metamodule_value="1"
|
|
|
|
if [ "$is_shim" = true ]; then
|
|
module_id_to_use="$SHIM_ID"
|
|
metamodule_value="0"
|
|
log_info " Configuring shim variant (ID: $module_id_to_use, metamodule: $metamodule_value)"
|
|
else
|
|
log_info " Configuring normal variant (ID: $module_id_to_use, metamodule: $metamodule_value)"
|
|
fi
|
|
|
|
# Configure module.prop
|
|
local module_prop="$build_dir/module.prop"
|
|
if [ ! -f "$module_prop" ]; then
|
|
log_error "module.prop not found"
|
|
return 1
|
|
fi
|
|
|
|
local module_version="$VERSION_FULL"
|
|
|
|
sed -i "s|^id=.*|id=$module_id_to_use|" "$module_prop"
|
|
sed -i "s|^version=.*|version=$module_version|" "$module_prop"
|
|
sed -i "s|^versionCode=.*|versionCode=$version_code|" "$module_prop"
|
|
sed -i "s|^updateJson=.*|updateJson=$UPDATE_JSON_URL|" "$module_prop"
|
|
sed -i "s|^metamodule=.*|metamodule=$metamodule_value|" "$module_prop"
|
|
|
|
log_info " module.prop configured ($module_version, code $version_code)"
|
|
}
|
|
|
|
# Generate checksums for all files
|
|
generate_checksums() {
|
|
local build_dir=$1
|
|
|
|
log_info " Generating checksums"
|
|
|
|
local checksum_file="$build_dir/checksums"
|
|
|
|
# Generate checksums (exclude checksums file itself if it exists)
|
|
if ! (cd "$build_dir" && \
|
|
find . -type f ! -name "checksums" -print0 | \
|
|
LC_ALL=C sort -z | \
|
|
xargs -0 sha256sum | \
|
|
sed 's|^\./||' > checksums); then
|
|
log_error "Failed to generate checksums"
|
|
return 1
|
|
fi
|
|
|
|
local count=$(wc -l < "$checksum_file")
|
|
log_info " Generated checksums for $count files"
|
|
}
|
|
|
|
# Normalize timestamps for reproducible builds
|
|
normalize_timestamps() {
|
|
local build_dir=$1
|
|
|
|
log_info " Normalizing timestamps"
|
|
|
|
# Use git commit timestamp for reproducibility
|
|
local git_timestamp=$(git log -1 --format=%ct 2>/dev/null)
|
|
|
|
if [ -n "$git_timestamp" ]; then
|
|
# Try GNU date first, then BSD date (macOS)
|
|
local timestamp=$(date -d "@$git_timestamp" '+%Y%m%d%H%M.%S' 2>/dev/null)
|
|
if [ -z "$timestamp" ]; then
|
|
# macOS compatibility
|
|
timestamp=$(date -r "$git_timestamp" '+%Y%m%d%H%M.%S' 2>/dev/null)
|
|
fi
|
|
|
|
if [ -z "$timestamp" ]; then
|
|
log_error "Failed to convert git timestamp"
|
|
return 1
|
|
fi
|
|
else
|
|
timestamp=$(date '+%Y%m%d%H%M.%S')
|
|
log_warn "Git timestamp not available, using current time"
|
|
fi
|
|
|
|
if ! find "$build_dir" -exec touch -m -t "$timestamp" {} +; then
|
|
log_error "Failed to normalize timestamps"
|
|
return 1
|
|
fi
|
|
|
|
log_info " Timestamps normalized"
|
|
}
|
|
|
|
# Package variant
|
|
package_variant() {
|
|
local base_dir=$1
|
|
local output_name=$2
|
|
local is_shim=$3
|
|
local variant_name=$4
|
|
|
|
log_info " Packaging $variant_name variant"
|
|
|
|
# Create a copy for this variant
|
|
local variant_dir="${base_dir}_${variant_name}"
|
|
if ! cp -r "$base_dir" "$variant_dir"; then
|
|
log_error "Failed to create variant directory"
|
|
return 1
|
|
fi
|
|
|
|
# Determine module ID and metamodule value
|
|
local module_id="$MODULE_ID"
|
|
local metamodule_value="1"
|
|
|
|
if [ "$is_shim" = true ]; then
|
|
module_id="$SHIM_ID"
|
|
metamodule_value="0"
|
|
log_info " Configuring as shim (ID: $module_id, metamodule: $metamodule_value)"
|
|
fi
|
|
|
|
# Configure for this module ID and metamodule setting
|
|
local module_prop="$variant_dir/module.prop"
|
|
sed -i "s|^id=.*|id=$module_id|" "$module_prop"
|
|
sed -i "s|^metamodule=.*|metamodule=$metamodule_value|" "$module_prop"
|
|
|
|
# Regenerate checksums with the new module.prop
|
|
if ! (cd "$variant_dir" && \
|
|
find . -type f ! -name "checksums" -print0 | \
|
|
LC_ALL=C sort -z | \
|
|
xargs -0 sha256sum | \
|
|
sed 's|^\./||' > checksums); then
|
|
log_error "Failed to regenerate checksums"
|
|
return 1
|
|
fi
|
|
|
|
# Re-normalize timestamps
|
|
local git_timestamp=$(git log -1 --format=%ct 2>/dev/null)
|
|
if [ -n "$git_timestamp" ]; then
|
|
local timestamp=$(date -d "@$git_timestamp" '+%Y%m%d%H%M.%S' 2>/dev/null)
|
|
if [ -z "$timestamp" ]; then
|
|
timestamp=$(date -r "$git_timestamp" '+%Y%m%d%H%M.%S' 2>/dev/null)
|
|
fi
|
|
else
|
|
timestamp=$(date '+%Y%m%d%H%M.%S')
|
|
fi
|
|
find "$variant_dir" -exec touch -m -t "$timestamp" {} +
|
|
|
|
# Package
|
|
if ! (cd "$variant_dir" && zip -qr "../../build/$output_name" ./*); then
|
|
log_error "Failed to create package"
|
|
return 1
|
|
fi
|
|
|
|
# Clean up variant directory
|
|
rm -rf "$variant_dir"
|
|
|
|
local size=$(du -h "build/$output_name" | cut -f1)
|
|
log_info " Created: $output_name ($size)"
|
|
}
|
|
|
|
# Build single type with variants
|
|
build_single_type() {
|
|
local build_type=$1
|
|
local build_shim=$2
|
|
|
|
local version_code=$(git rev-list --count HEAD)
|
|
|
|
# Set base directory and register for cleanup
|
|
BASE_DIR="build/${build_type}_base"
|
|
|
|
# Register other directories for cleanup
|
|
TEMP_DIRS+=("src/bin" "$BASE_DIR")
|
|
|
|
log_info ""
|
|
log_info "========================================"
|
|
if [ "$build_shim" = true ]; then
|
|
log_info "Building $build_type (normal + shim variants)"
|
|
else
|
|
log_info "Building $build_type (normal)"
|
|
fi
|
|
log_info "Version: $VERSION_FULL"
|
|
log_info "========================================"
|
|
|
|
# Clean and create build directory
|
|
rm -rf "$BASE_DIR"
|
|
mkdir -p "$BASE_DIR" || {
|
|
log_error "Failed to create build directory: $BASE_DIR"
|
|
return 1
|
|
}
|
|
|
|
# Step 1: Copy template
|
|
log_step 1 9 "Copying template"
|
|
if ! cp -r template/* "$BASE_DIR/"; then
|
|
log_error "Failed to copy template"
|
|
return 1
|
|
fi
|
|
|
|
# Step 2: Build binaries (shared)
|
|
build_binaries "$build_type" || return 1
|
|
|
|
# Step 3: Initial configuration (will be overridden per variant)
|
|
log_step 3 9 "Configuring base module files"
|
|
configure_module "$BASE_DIR" "$build_type" "$version_code" false || return 1
|
|
|
|
# Step 4: Copy binaries (shared)
|
|
log_step 4 9 "Copying binaries"
|
|
if [ ! -d "src/bin" ]; then
|
|
log_error "src/bin not found"
|
|
return 1
|
|
fi
|
|
if ! cp -r src/bin "$BASE_DIR/"; then
|
|
log_error "Failed to copy binaries"
|
|
return 1
|
|
fi
|
|
|
|
# Step 5: Generate checksums (will be regenerated per variant)
|
|
log_step 5 9 "Generating base checksums"
|
|
generate_checksums "$BASE_DIR" || return 1
|
|
|
|
# Step 6: Normalize timestamps (will be reapplied per variant)
|
|
log_step 6 9 "Normalizing timestamps"
|
|
normalize_timestamps "$BASE_DIR" || return 1
|
|
|
|
# Step 7: Package variants
|
|
log_step 7 9 "Packaging variants"
|
|
|
|
local built_artifacts=()
|
|
|
|
# Normal variant
|
|
local normal_output="meta-magic_mount-${VERSION_FULL}-${build_type}.zip"
|
|
if package_variant "$BASE_DIR" "$normal_output" false "normal"; then
|
|
built_artifacts+=("$normal_output")
|
|
else
|
|
log_error "Failed to package normal variant"
|
|
return 1
|
|
fi
|
|
|
|
# Shim variant (if requested)
|
|
if [ "$build_shim" = true ]; then
|
|
local shim_output="meta-magic_mount-${VERSION_FULL}-${build_type}-shim.zip"
|
|
if package_variant "$BASE_DIR" "$shim_output" true "shim"; then
|
|
built_artifacts+=("$shim_output")
|
|
else
|
|
log_error "Failed to package shim variant"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Step 8: Generate misc files
|
|
log_step 8 9 "Generating metadata files"
|
|
if [ "$build_type" = "release" ]; then
|
|
# Generate changelog once (shared between variants)
|
|
generate_changelog
|
|
|
|
# Generate update JSON only for normal variant
|
|
# Shim variant doesn't need separate version.json since it converts to normal module after installation
|
|
generate_update_json "$normal_output" "$version_code"
|
|
log_info " Generated version.json (normal variant only)"
|
|
else
|
|
log_info " Skipped (debug build)"
|
|
fi
|
|
|
|
log_step 9 9 "Done. "
|
|
|
|
log_info ""
|
|
log_info "========================================="
|
|
log_info "Build complete for $build_type:"
|
|
for artifact in "${built_artifacts[@]}"; do
|
|
local size=$(du -h "build/$artifact" | cut -f1)
|
|
log_info " - $artifact ($size)"
|
|
done
|
|
log_info "========================================="
|
|
|
|
# Return artifacts via global variable
|
|
artifacts=("${built_artifacts[@]}")
|
|
}
|
|
|
|
# Main build process
|
|
main() {
|
|
parse_args "$@"
|
|
check_prerequisites
|
|
get_version_info
|
|
|
|
# Setup build directory
|
|
mkdir -p build
|
|
|
|
# Build each type
|
|
local success=0
|
|
local failed=0
|
|
local all_built_files=()
|
|
|
|
for build_type in "${BUILD_TYPES[@]}"; do
|
|
if build_single_type "$build_type" "$BUILD_SHIM"; then
|
|
((success++))
|
|
all_built_files+=("${artifacts[@]}")
|
|
else
|
|
((failed++))
|
|
log_error "Failed to build $build_type"
|
|
fi
|
|
done
|
|
|
|
# Print summary
|
|
log_info ""
|
|
log_info "========================================"
|
|
log_info "Build Summary"
|
|
log_info "========================================"
|
|
log_info "Version: $VERSION_FULL"
|
|
log_info "Commit: $GIT_COMMIT"
|
|
log_info "Build mode: $([ "$BUILD_SHIM" = true ] && echo "NORMAL + SHIM" || echo "NORMAL ONLY")"
|
|
log_info "Module IDs: $MODULE_ID$([ "$BUILD_SHIM" = true ] && echo ", $SHIM_ID" || echo "")"
|
|
log_info "Success: $success | Failed: $failed"
|
|
log_info "----------------------------------------"
|
|
log_info "Generated files:"
|
|
|
|
# Show metadata files
|
|
if [[ " ${BUILD_TYPES[*]} " =~ " release " ]]; then
|
|
log_info " build/changelog.md"
|
|
log_info " build/version.json"
|
|
fi
|
|
|
|
# Show all artifacts
|
|
for file in "${all_built_files[@]}"; do
|
|
local size=$(du -h "build/$file" | cut -f1)
|
|
log_info " build/$file ($size)"
|
|
done
|
|
log_info "========================================"
|
|
|
|
[ $failed -gt 0 ] && exit 1
|
|
exit 0
|
|
}
|
|
|
|
main "$@"
|