action.yml 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. name: 'Download Kernel Repository'
  2. description: 'Initialize and sync Android kernel source repository'
  3. inputs:
  4. android_version:
  5. description: 'Android version (e.g., android14)'
  6. required: true
  7. kernel_version:
  8. description: 'Kernel version (e.g., 5.15, 6.1)'
  9. required: true
  10. os_patch_level:
  11. description: 'OS patch level (e.g., 2024-01)'
  12. required: true
  13. outputs:
  14. deprecated_branch:
  15. description: 'Whether the branch is deprecated'
  16. value: ${{ steps.sync.outputs.deprecated }}
  17. runs:
  18. using: composite
  19. steps:
  20. # - name: Initialize and Sync Kernel Repository
  21. # id: sync
  22. # shell: bash
  23. # working-directory: ${{ github.workspace }}/kernel
  24. # run: |
  25. # FORMATTED_BRANCH="${{ inputs.android_version }}-${{ inputs.kernel_version }}-${{ inputs.os_patch_level }}"
  26. # repo init -u https://android.googlesource.com/kernel/manifest -b common-${FORMATTED_BRANCH} --depth=1 --partial-clone --clone-filter=blob:limit=10M
  27. # REMOTE_BRANCH=$(git ls-remote https://android.googlesource.com/kernel/common ${FORMATTED_BRANCH})
  28. # DEFAULT_MANIFEST_PATH=.repo/manifests/default.xml
  29. # DEPRECATED=false
  30. # if grep -q deprecated <<< $REMOTE_BRANCH; then
  31. # sed -i "s/\"${FORMATTED_BRANCH}\"/\"deprecated\/${FORMATTED_BRANCH}\"/g" $DEFAULT_MANIFEST_PATH
  32. # echo "⚠ Note: Branch ${FORMATTED_BRANCH} is considered deprecated."
  33. # DEPRECATED=true
  34. # fi
  35. # echo "deprecated=$DEPRECATED" >> $GITHUB_OUTPUT
  36. # repo sync -c -j$(nproc --all) --fail-fast --no-tags --force-sync --no-clone-bundle
  37. - name: Download manifest.xml for branch
  38. shell: bash
  39. working-directory: ${{ github.workspace }}/kernel
  40. run: |
  41. FORMATTED_BRANCH="${{ inputs.android_version }}-${{ inputs.kernel_version }}-${{ inputs.os_patch_level }}"
  42. MANIFEST_URL="https://android.googlesource.com/kernel/manifest/+/refs/heads/common-${FORMATTED_BRANCH}/default.xml?format=TEXT"
  43. echo "Fetching manifest from $MANIFEST_URL"
  44. curl -fsSL "$MANIFEST_URL" | base64 -d > manifest.xml
  45. - name: Fast Parallel Archive Download
  46. shell: python
  47. working-directory: ${{ github.workspace }}/kernel
  48. run: |
  49. import xml.etree.ElementTree as ET
  50. import subprocess
  51. import os, glob, shutil
  52. from concurrent.futures import ThreadPoolExecutor
  53. MAX_WORKERS = (os.cpu_count() or 2) * 4
  54. NPROC = int(subprocess.check_output("nproc", shell=True).strip())
  55. def sync_project(task):
  56. name, path, url, strip, rev, linkfiles, copyfiles = task
  57. if path not in ["./", "."]:
  58. os.makedirs(path, exist_ok=True)
  59. print(f"Syncing: {name} -> {path}")
  60. try:
  61. aria_cmd = f"aria2c -x16 -s16 -k1M -j5 --file-allocation=none -o {name}.tar.gz '{url}'"
  62. subprocess.run(aria_cmd, shell=True, check=True)
  63. tar_cmd = f"tar -I 'pigz -p {NPROC} -b 256' -x --record-size=1M -C {path} {strip} -f {name}.tar.gz"
  64. subprocess.run(tar_cmd, shell=True, check=True)
  65. os.remove(f"{name}.tar.gz")
  66. # Handle linkfiles and copyfiles
  67. top_dir = os.getcwd()
  68. for src_rel, dest_rel in linkfiles:
  69. src_path = os.path.join(top_dir, path, src_rel)
  70. dest_path = os.path.join(top_dir, dest_rel)
  71. os.makedirs(os.path.dirname(dest_path), exist_ok=True)
  72. if os.path.lexists(dest_path): os.remove(dest_path)
  73. rel_target = os.path.relpath(src_path, os.path.dirname(dest_path))
  74. os.symlink(rel_target, dest_path)
  75. print(f" [Link] {dest_rel} -> {src_rel}")
  76. for src_rel, dest_rel in copyfiles:
  77. src_path = os.path.join(top_dir, path, src_rel)
  78. dest_path = os.path.join(top_dir, dest_rel)
  79. os.makedirs(os.path.dirname(dest_path), exist_ok=True)
  80. shutil.copy2(src_path, dest_path)
  81. print(f" [Copy] {dest_rel} from {src_rel}")
  82. print(f"Synced {name} successfully!")
  83. return True
  84. except Exception as e:
  85. print(f"Failed to sync {name}: {e}")
  86. return False
  87. with open('manifest.xml', 'r') as f:
  88. manifest_content = f.read()
  89. root = ET.fromstring(manifest_content)
  90. remotes = {r.get('name'): r.get('fetch').rstrip('/') for r in root.findall('remote')}
  91. default = root.find('default')
  92. def_remote = default.get('remote') if default is not None else None
  93. def_rev = default.get('revision') if default is not None else None
  94. sync_tasks = []
  95. for project in root.findall('project'):
  96. name = project.get('name')
  97. path = project.get('path', name)
  98. remote_name = project.get('remote', def_remote)
  99. rev = project.get('revision', def_rev)
  100. base_url = remotes.get(remote_name)
  101. if not base_url: continue
  102. if "github.com" in base_url:
  103. url = f"{base_url}/{name}/archive/{rev}.tar.gz"
  104. strip = "--strip-components=1"
  105. elif "googlesource.com" in base_url:
  106. url = f"{base_url}/{name}/+archive/{rev}.tar.gz"
  107. strip = ""
  108. elif "git.codelinaro.org" in base_url:
  109. url = f"{base_url}/{name}/-/archive/{rev}.tar.gz"
  110. strip = "--strip-components=1"
  111. else:
  112. continue
  113. linkfiles = [(lf.get('src'), lf.get('dest')) for lf in project.findall('linkfile')]
  114. copyfiles = [(cf.get('src'), cf.get('dest')) for cf in project.findall('copyfile')]
  115. sync_tasks.append((name, path, url, strip, rev, linkfiles, copyfiles))
  116. with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
  117. results = list(executor.map(sync_project, sync_tasks))
  118. if not all(results):
  119. print("One or more projects failed to sync!")
  120. exit(1)