name: 编译dufs

on:
  #每天北京时间11点 4点自动检测更新
  schedule:
   - cron: "0 3,20 * * *"
  #设置手动触发运行，并且设置几个输入参数变量
  workflow_dispatch:
    inputs:
      branch:
        description: '指定编译的版本号'
        required: false
        default: ''
      info:
        description: '发布Release的补充说明'
        required: false
        default: ''
      bj:
        description: '强制使用手动编译'
        required: true
        default: false
        type: boolean

#设置全局权限
permissions:
  #允许仓库的写入权限，用来发布release
  contents: write
  #允许操作工作流程，用来删除工作流的记录
  actions: write

#设置全局变量
env:
  #TZ时区设为上海
  TZ: Asia/Shanghai
  #编译rust程序时 显示彩色字体
  CARGO_TERM_COLOR: always
  #设置输入的变量是否强制编译（因为使用了对比当前仓库的版本和官方版本是否一致，不一致才会执行编译，勾选这个 哪怕一致也重新编译）
  BJ: ${{ github.event.inputs.bj }}
  #设置输入的版本号，用来指定编译某个版本
  BRANCH: ${{ github.event.inputs.branch }}

jobs:
  #第一个作业check 我用来检测当前仓库版本和官方最新版本号 进行比较
  check:
   #使用Ubuntu linux系统
   runs-on: ubuntu-latest
	 #输出版本号的值 供后续作业使用
   outputs:
     ver: ${{ steps.getversion.outputs.ver }}
     tag: ${{ steps.getversion.outputs.tag }}
   steps:
   - name: 检查更新
	   #设置当前作业的步骤id名 供后缀引用
     id: getversion
     run: |
      #执行获取版本号命令
      ver=`curl https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/latest | jq -r '.tag_name'`
      tag=`curl https://api.github.com/repos/sigoden/dufs/releases/latest | jq -r '.tag_name'`
      echo "ver=${ver}" >> $GITHUB_OUTPUT
      echo "tag=${tag}" >> $GITHUB_OUTPUT

      #这里引用别人写好的流程快速删除之前的记录（需要用到前面的权限 工作流写入）
   -  name: 删除工作流
      uses: Mattraks/delete-workflow-runs@main
      #这里的with下面的参数是传递给这个第三方写好的流程里使用的
      with:
        #这里就是之前设置的权限自动生成的token 也可以自己创建token 权限更高 
        token: ${{ secrets.GITHUB_TOKEN }}
        #保留的天数 我设置0 
        retain_days: 0
        #保留的最少个数 我设置0 一个不要 全删除
        keep_minimum_runs: 0

  #第二个作业 构建这个程序的自定义前端页面
  build-assets:
    # 设置条件  nedds需要前面 check 作业执行完成才能执行这个作业
    needs: check
    # 增加判断 如果手动输入的参数 是 强制编译 或 获取的 版本号不一致 才执行这个作业后续命令 避免频繁操作
    if: ${{ github.event.inputs.bj == 'true' || (github.event.inputs.bj != 'true' && needs.check.outputs.ver != needs.check.outputs.tag) }}
    runs-on: ubuntu-latest
    steps:
      # 检出代码 这里使用官方流程 快速 克隆 别人的项目 
      - uses: actions/checkout@v4
        with:
          #这里传递的值是  指定用户和仓库 
          repository: TransparentLC/dufs-material-assets
          #这里指定分支号  我使用他仓库的主分支
          ref: master

        #这个步骤同样使用别人写好的流程 快速安装pnpm环境
      - name: Setup pnpm
        uses: pnpm/action-setup@v3
        with:
          version: latest

        # 快速安装node环境
      - name: Setup node
        uses: actions/setup-node@v4
        with:
          node-version: latest
          check-latest: true
          cache: pnpm
          cache-dependency-path: "**/package.json"

        #这里开始构建 前面克隆 别人的项目的自定义页面了
      - name: Build assets
        run: |
          pnpm install
          DUFS_EMBED_FILENAME=1 pnpm run build

        #这里是上传构建的文件 可以在流程页面下载  也可以供后续其他作业下载调用
      - name: Upload assets
        uses: actions/upload-artifact@v4
        with:
          name: dufs-自定义页面
          path: dist

  #第三个作业
  build-dufs:
    # 我设置 需要在前面的 构建自定义页面 和 检测版本号 完成后才能执行
    needs: 
     - build-assets
     - check
    # 这是矩阵构建 参考GitHub的说明  多个系统同时并发构建 
    strategy:
      #设置如果某个任务失败 不能终止其他任务 
      fail-fast: false
      # 设置并发任务 同时运行  
      matrix:
        include:
        
        - target: aarch64-apple-darwin
          os: macos-latest
          NAME: dufs-aarch64-apple-darwin
          
        - target: aarch64-pc-windows-msvc
          os: windows-latest
          NAME: dufs-aarch64-pc-windows-msvc.exe
          
        - target: x86_64-apple-darwin
          os: macos-latest
          NAME: dufs-x86_64-apple-darwin
          
        - target: x86_64-pc-windows-msvc
          os: windows-latest
          NAME: dufs-x86_64-pc-windows-msvc.exe
          
        - target: i686-pc-windows-msvc
          os: windows-latest
          NAME: dufs-i686-pc-windows-msvc.exe
          
        - target: aarch64-unknown-linux-musl
          os: ubuntu-latest
          URL: aarch64-linux-musl
          NAME: dufs-aarch64-linux-musl
          
        - target: x86_64-unknown-linux-musl
          os: ubuntu-latest
          URL: x86_64-linux-musl
          NAME: dufs-x86_64-linux-musl
            
        - target: i686-unknown-linux-musl
          os: ubuntu-latest
          URL: i686-linux-musl
          NAME: dufs-i686-linux-musl
        
        - target: armv7-unknown-linux-musleabihf
          os: ubuntu-latest
          URL: armv7l-linux-musleabihf
          NAME: dufs-armv7-linux-musleabihf

        - target: armv7-unknown-linux-musleabi
          os: ubuntu-latest
          URL: armv7m-linux-musleabi
          NAME: dufs-armv7-linux-musleabi
          
        - target: arm-unknown-linux-musleabihf
          os: ubuntu-latest
          URL: arm-linux-musleabihf
          NAME: dufs-arm-linux-musleabihf

        - target: arm-unknown-linux-musleabi
          os: ubuntu-latest
          URL: arm-linux-musleabi
          NAME: dufs-arm-linux-musleabi

        - target: mipsel-unknown-linux-musl
          os: ubuntu-latest
          URL: mipsel-linux-muslsf
          NAME: dufs-mipsel-linux-muslsf

        - target: mips-unknown-linux-musl
          os: ubuntu-latest
          URL: mips-linux-muslsf
          NAME: dufs-mips-linux-muslsf

        - target: x86_64-unknown-freebsd
          os: ubuntu-latest
          NAME: dufs-x86_64-freebsd

    #设置运行的系统  从并发任务的变量里读取       
    runs-on: ${{ matrix.os }}
    #设置环境变量 从并发任务里读取
    env:
      TARGET: ${{ matrix.target }}
      URL: ${{ matrix.URL }}
      NAME: ${{ matrix.NAME }}
    steps:
      # 由于我设置 自动定时执行 和 手动执行 ，如果是自动执行 那么手动输入的参数就会默认为空 ，这里做个判断，统一都是shell语法
      - name: 确定版本号
        shell: bash
        run: |
          if [[ "${{ env.BJ }}" == "true" ]]; then
            echo "强制进行编译..."
            if [[ -n "${{ github.event.inputs.branch }}" ]]; then
                echo "使用手动指定的版本：${{ github.event.inputs.branch }}"
                TAG=${{ github.event.inputs.branch }}
                echo "TAG=$TAG" >> $GITHUB_ENV
            else
                echo "使用自动获取的版本：${{ needs.check.outputs.tag }}"
                TAG=${{ needs.check.outputs.tag }}
                echo "TAG=$TAG" >> $GITHUB_ENV
            fi
          else
            echo "使用自动获取的版本：${{ needs.check.outputs.tag }}"
            TAG=${{ needs.check.outputs.tag }}
            echo "TAG=$TAG" >> $GITHUB_ENV
          fi

      #这里继续使用官方的检出流程 不使用git clone命令了 这个的好处就是 默认在当前目录 而不用cd了 你可以通过 pwd 显示当前的路径测试
      - uses: actions/checkout@v4
        with:
          # 这里指定程序的官方仓库
          repository: sigoden/dufs
          #这里的分支 由上面那个步骤确定了 是手动执行输入的版本还是 自动检测版本获取的版本号
          ref: ${{ env.TAG }}

        #这个步骤做了判断 如果并发任务中某个值等于 指定值的情况下 才执行这个步骤 
      - name: 下载apple-windows工具链
        if: ${{ matrix.TARGET == 'aarch64-apple-darwin' || matrix.TARGET == 'aarch64-pc-windows-msvc' || matrix.TARGET == 'x86_64-apple-darwin' || matrix.TARGET == 'x86_64-pc-windows-msvc' || matrix.TARGET == 'i686-pc-windows-msvc' || matrix.TARGET == 'x86_64-unknown-freebsd' }}
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

        #这个步骤也是做了判断 如果并发任务中某个值等于 指定值的情况下 才执行这个步骤
      - name: 下载apple-windows编译工具
        if: ${{ matrix.TARGET == 'aarch64-apple-darwin' || matrix.TARGET == 'aarch64-pc-windows-msvc' || matrix.TARGET == 'i686-pc-windows-msvc' || matrix.TARGET == 'x86_64-unknown-freebsd' }}
        uses: taiki-e/install-action@v2
        with:
          tool: cross

        #这个步骤也是做了判断 如果并发任务中某个值等于 指定值的情况下 才执行这个步骤 
      - name: 下载linux编译工具
        if: ${{ matrix.TARGET != 'aarch64-apple-darwin' && matrix.TARGET != 'aarch64-pc-windows-msvc' && matrix.TARGET != 'x86_64-apple-darwin' && matrix.TARGET != 'x86_64-pc-windows-msvc' && matrix.TARGET != 'i686-pc-windows-msvc' && matrix.TARGET != 'x86_64-unknown-freebsd' }}
        run: |
          mkdir -p /opt/musl_gcc
          rustup set auto-self-update disable
          echo "下载https://musl.cc/${{ env.URL }}-cross.tgz"
          wget -q -c https://musl.cc/${{ env.URL }}-cross.tgz -P /opt/musl_gcc/
          tar zxf /opt/musl_gcc/${{ env.URL }}-cross.tgz -C /opt/musl_gcc/
          sudo ln -s /opt/musl_gcc/${{ env.URL }}-cross/bin/*gcc /usr/bin/
          #sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools
          if [[ $TARGET =~ ^mips.*$ ]]; then
            echo "指定 $TARGET 架构 使用rust 1.74版本，若编译失败 请修改此处升级版本 "
            rustup install 1.74
            rustup default 1.74
          else
            echo "指定 $TARGET 架构 使用rust 1.77版本，若编译失败 请修改此处升级版本 "
            rustup install 1.77
            rustup default 1.77
          fi
          rustup target add ${{ env.TARGET }}
          #添加交叉编译配置
          cat >>~/.cargo/config <<EOF
          [target.x86_64-unknown-linux-musl]
          linker = "x86_64-linux-musl-gcc"
          rustflags = ["-C", "target-feature=+crt-static"]
          
          [target.i686-unknown-linux-musl]
          linker = "i686-linux-musl-gcc"
          rustflags = ["-C", "target-feature=+crt-static"] 
          
          [target.aarch64-unknown-linux-musl]
          linker = "aarch64-linux-musl-gcc"
          rustflags = ["-C", "target-feature=+crt-static"]
          
          [target.armv7-unknown-linux-musleabi]
          linker = "armv7m-linux-musleabi-gcc"
          rustflags = ["-C", "target-feature=+crt-static"]

          [target.armv7-unknown-linux-musleabihf]
          linker = "armv7l-linux-musleabihf-gcc"
          rustflags = ["-C", "target-feature=+crt-static"]
          
          [target.arm-unknown-linux-musleabi]
          linker = "arm-linux-musleabi-gcc"
          rustflags = ["-C", "target-feature=+crt-static"]

          [target.arm-unknown-linux-musleabihf]
          linker = "arm-linux-musleabihf-gcc"
          rustflags = ["-C", "target-feature=+crt-static"]
          
          [target.mipsel-unknown-linux-musl]
          linker = "mipsel-linux-muslsf-gcc"
          rustflags = ["-C", "target-feature=+crt-static"]
          
          [target.mips-unknown-linux-musl]
          linker = "mips-linux-muslsf-gcc"
          rustflags = ["-C", "target-feature=+crt-static"]      
          EOF

        #这个只是输出一下版本信息  可有可无  完全是linux的shell 语法
      - name: 打印版本信息 (Rust, cargo, GCC)
        shell: bash
        run: |
          rustup -V
          rustup toolchain list
          rustup default
          cargo -V
          rustc -V

        # 这里是下载上个作业里上传的文件  作业之间 文件是不共享的  所以需要这样上传下载配合
      - name: 下载 assets 页面
        uses: actions/download-artifact@v4
        with:
          name: dufs-自定义页面
          path: dufs-material-assets-embed

        #下载好后 替换程序的页面 
      - name: 替换自定义 assets 页面
        shell: bash
        run: |
          cp dufs-material-assets-embed/index.css assets/index.css
          cp dufs-material-assets-embed/index.html assets/index.html
          cp dufs-material-assets-embed/index.js assets/index.js

        #正式开始编译程序了
      - name: 编译dufs
        shell: bash
        run: |
          if [[ $TARGET == 'aarch64-apple-darwin' || $TARGET == 'aarch64-pc-windows-msvc' || $TARGET == 'i686-pc-windows-msvc' || $TARGET == 'x86_64-unknown-freebsd' ]]; then
            echo "编译： cross build --locked --release --target=${{ matrix.target }}"
            cross build --locked --release --target=${{ matrix.target }}
          else
            echo "编译： cargo build --locked --release --target=${{ matrix.target }}"
            cargo build --locked --release --target=${{ matrix.target }}
          fi
            
          cd target/${{ matrix.target }}/release
          mkdir -p ./out
          if [[ "$RUNNER_OS" == "Windows" ]]; then
            mv ./dufs.exe ./out/${{ matrix.NAME }}
          else
            mv ./dufs ./out/${{ matrix.NAME }}
          fi
          
          ls -alh ./out/
          #这个命令是把当前时间 写入到 GitHub的全局环境变量里 因为每个作业每个步骤的变量只在当前有效 这样写入才能在所有步骤里使用 这里因为是国外的  所以开头我使用全局环境变量设置了时区TZ 为上海时区
          echo "build_time=$(date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV

        #这里做了判断 通过并发任务的指定值 才执行 
      - name: 安装 UPX
        if: ${{ matrix.TARGET != 'aarch64-apple-darwin' && matrix.TARGET != 'aarch64-pc-windows-msvc' && matrix.TARGET != 'x86_64-apple-darwin' && matrix.TARGET != 'x86_64-pc-windows-msvc' && matrix.TARGET != 'i686-pc-windows-msvc' && matrix.TARGET != 'x86_64-unknown-freebsd' }}
        uses: crazy-max/ghaction-upx@v3
        with:
          version: latest
          install-only: true

        #这里做了判断 通过并发任务的指定值 才执行 
      - name: 压缩程序
        if: ${{ matrix.TARGET != 'aarch64-apple-darwin' && matrix.TARGET != 'aarch64-pc-windows-msvc' && matrix.TARGET != 'x86_64-apple-darwin' && matrix.TARGET != 'x86_64-pc-windows-msvc' && matrix.TARGET != 'i686-pc-windows-msvc' && matrix.TARGET != 'x86_64-unknown-freebsd' }}
        run: |
          cd target/${{ matrix.target }}/release/out
          cp ${{ matrix.NAME }} ${{ matrix.NAME }}-upx
          upx --lzma --best ${{ matrix.NAME }}-upx

        #这里是把编译好的程序 上传到流程里 方便下载
      - name: 上传程序
        uses: actions/upload-artifact@v4
        with:
          name: dufs-${{ matrix.target }}
          path: target/${{ matrix.target }}/release/out/*

       # 这里是发布到release里  需要开始设置的权限  contents: write 
      - name: 发布
        uses: softprops/action-gh-release@v2
        with:
            token: ${{ github.token }}
            body: |
             > ### 编译时间 ：${{ env.build_time }}

              **-upx** 后缀的 为upx压缩文件
              
              **[官方更新说明](https://github.com/sigoden/dufs/releases)**

              ${{ github.event.inputs.info }}
              
            tag_name: ${{ env.TAG }}
            files: target/${{ matrix.target }}/release/out/*

  #这里是新的作业   用来自动化执行保活的 60天的任务 GitHub会自动暂停 
  keepalive-workflow:
    name: 工作流保活
    runs-on: ubuntu-latest
    permissions:
      actions: write
      contents: write
    steps:
      - uses: actions/checkout@v4
      - uses: gautamkrishnar/keepalive-workflow@v2
        #with:
          #use_api: true
