From a5726bd2bf8c05b8a73e1e674295895f4b9a82ef Mon Sep 17 00:00:00 2001 From: Aaron Pham Date: Tue, 3 Sep 2024 06:20:53 -0400 Subject: [PATCH] feat(crates): prebuilt binaries (#473) * feat(crates): prebuilt binaries Signed-off-by: Aaron Pham * chore: update name Signed-off-by: Aaron Pham * chore: build on PR Signed-off-by: Aaron Pham * chore: only build for lua51 and luajit Signed-off-by: Aaron Pham * feat: build stuff Signed-off-by: Aaron Pham * chore: only build if changes in Rust Signed-off-by: Aaron Pham * fix: remove deadcode Signed-off-by: Aaron Pham --------- Signed-off-by: Aaron Pham --- .github/workflows/build.yaml | 61 ++++++++++++++++++++++++++++++++++++ .github/workflows/ci.yaml | 14 ++++++++- Makefile | 39 ++++++++++++++++------- README.md | 7 +++-- autoload/avante.vim | 5 +-- build.sh | 47 +++++++++++++++++++++++++++ lua/avante/api.lua | 53 ++++++++++++++++++++++++++++++- lua/avante/init.lua | 59 +++++++++------------------------- 8 files changed, 223 insertions(+), 62 deletions(-) create mode 100644 .github/workflows/build.yaml create mode 100644 build.sh diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..180eeae --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,61 @@ +name: Nightly Build + +on: + schedule: + - cron: '0 2 * * *' # Runs at 2 AM UTC every day + push: + branches: + - main + pull_request: + branches: + - main + paths: + - 'crates/**' + - '**/Cargo.toml' + workflow_dispatch: # Allows manual triggering + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + feature: [lua51, luajit] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.80.0 + - name: Build all crates + run: cargo build --release --features ${{ matrix.feature }} + - name: handle binaries + shell: bash + run: | + mkdir -p results + if [ "${{ matrix.os }}" == "ubuntu-latest" ]; then + OS="linux" + EXT="so" + elif [ "${{ matrix.os }}" == "macos-latest" ]; then + OS="macOS" + EXT="dylib" + else + OS="windows" + EXT="dll" + fi + + if [ "${{ matrix.os }}" == "windows-latest" ]; then + cp target/release/avante_templates.$EXT results/avante_templates.$EXT + cp target/release/avante_tokenizers.$EXT results/avante_tokenizers.$EXT + else + cp target/release/libavante_templates.$EXT results/avante_templates.$EXT + cp target/release/libavante_tokenizers.$EXT results/avante_tokenizers.$EXT + fi + - name: Upload binaries + uses: actions/upload-artifact@v4 + with: + name: avante_lib-${{ matrix.os }}-${{ matrix.feature }} + path: results/ diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e48f3db..8d02a9e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,7 +18,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} version: latest - args: --check ./lua/ + args: --check ./lua/ ./plugin/ luacheck: name: Lint Lua runs-on: ubuntu-latest @@ -29,3 +29,15 @@ jobs: uses: lunarmodules/luacheck@v1 with: args: ./lua/ + rust: + name: Check Rust style + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + components: clippy, rustfmt + - name: Run rustfmt + run: make ruststylecheck diff --git a/Makefile b/Makefile index 3f5d423..87b3c5f 100644 --- a/Makefile +++ b/Makefile @@ -11,14 +11,16 @@ else $(error Unsupported operating system: $(UNAME)) endif -LUA_VERSIONS := luajit lua51 lua52 lua53 lua54 +LUA_VERSIONS := luajit lua51 BUILD_DIR := build +BUILD_FROM_SOURCE ?= false TARGET_LIBRARY ?= all all: luajit define make_definitions +ifeq ($(BUILD_FROM_SOURCE),true) ifeq ($(TARGET_LIBRARY), all) $1: $(BUILD_DIR)/libAvanteTokenizers-$1.$(EXT) $(BUILD_DIR)/libAvanteTemplates-$1.$(EXT) else ifeq ($(TARGET_LIBRARY), tokenizers) @@ -28,35 +30,50 @@ $1: $(BUILD_DIR)/libAvanteTemplates-$1.$(EXT) else $$(error TARGET_LIBRARY must be one of all, tokenizers, templates) endif +else +$1: + LUA_VERSION=$1 sh ./build.sh +endif endef $(foreach lua_version,$(LUA_VERSIONS),$(eval $(call make_definitions,$(lua_version)))) -define build_from_source +define build_package +$1-$2: cargo build --release --features=$1 -p avante-$2 cp target/release/libavante_$2.$(EXT) $(BUILD_DIR)/avante_$2.$(EXT) endef define build_targets -$(BUILD_DIR)/libAvanteTokenizers-$1.$(EXT): $(BUILD_DIR) - $$(call build_from_source,$1,tokenizers) -$(BUILD_DIR)/libAvanteTemplates-$1.$(EXT): $(BUILD_DIR) - $$(call build_from_source,$1,templates) +$(BUILD_DIR)/libAvanteTokenizers-$1.$(EXT): $(BUILD_DIR) $1-tokenizers +$(BUILD_DIR)/libAvanteTemplates-$1.$(EXT): $(BUILD_DIR) $1-templates endef +$(foreach lua_version,$(LUA_VERSIONS),$(eval $(call build_package,$(lua_version),tokenizers))) +$(foreach lua_version,$(LUA_VERSIONS),$(eval $(call build_package,$(lua_version),templates))) $(foreach lua_version,$(LUA_VERSIONS),$(eval $(call build_targets,$(lua_version)))) $(BUILD_DIR): - mkdir -p $(BUILD_DIR) + @mkdir -p $(BUILD_DIR) clean: - rm -rf $(BUILD_DIR) + @rm -rf $(BUILD_DIR) luacheck: - luacheck `find -name "*.lua"` --codes + @luacheck `find -name "*.lua"` --codes stylecheck: - stylua --check lua/ + @stylua --check lua/ plugin/ stylefix: - stylua lua/ plugin/ + @stylua lua/ plugin/ + +.PHONY: ruststylecheck +ruststylecheck: + @rustup component add rustfmt 2> /dev/null + @cargo fmt --all -- --check + +.PHONY: rustlint +rustlint: + @rustup component add clippy 2> /dev/null + @cargo clippy -F luajit --all -- -F clippy::dbg-macro -D warnings diff --git a/README.md b/README.md index 67a8918..41d50be 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,10 @@ https://github.com/user-attachments/assets/86140bfd-08b4-483d-a887-1b701d9e37dd opts = { -- add any opts here }, - build = ":AvanteBuild", -- Also note that this will block the startup for a bit since we are compiling bindings in Rust. + -- if you want to build from source, then pass source=true (requires cargo). + -- Also note that building from source will block startuptime since + -- we are compiling bindings in Rust. + build = ":AvanteBuild", dependencies = { "stevearc/dressing.nvim", "nvim-lua/plenary.nvim", @@ -87,7 +90,7 @@ Plug 'nvim-tree/nvim-web-devicons' "or Plug 'echasnovski/mini.icons' Plug 'HakonHarnes/img-clip.nvim' Plug 'zbirenbaum/copilot.lua' -" Yay +" Yay, pass source=true if you want to build from source Plug 'yetone/avante.nvim', { 'branch': 'main', 'do': { -> avante#build() }, 'on': 'AvanteAsk' } ``` diff --git a/autoload/avante.vim b/autoload/avante.vim index 2e7025e..6006e98 100644 --- a/autoload/avante.vim +++ b/autoload/avante.vim @@ -1,3 +1,4 @@ -function avante#build() abort - return join(luaeval("require('avante').build()"), "\n") +function avante#build(...) abort + let l:source = get(a:, 1, v:false) + return join(luaeval("require('avante').build(_A)", l:source), "\n") endfunction diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..d14ad48 --- /dev/null +++ b/build.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +set -eo pipefail + +REPO_OWNER="yetone" +REPO_NAME="avante.nvim" + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" + +# Set the target directory to clone the artifact +TARGET_DIR="${SCRIPT_DIR}/build" + +# Get the latest successful run ID of the workflow +RUN_ID=$(curl -s -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/actions/workflows/build.yaml/runs?status=success&branch=main" | + \grep -oP '(?<="id": )\d+' | head -1) + +# Get the artifact download URL based on the platform and Lua version +case "$(uname -s)" in +Linux*) + PLATFORM="linux" + ;; +Darwin*) + PLATFORM="macos" + ;; +CYGWIN* | MINGW* | MSYS*) + PLATFORM="windows" + ;; +*) + echo "Unsupported platform" + exit 1 + ;; +esac + +# Set the Lua version (lua54 or luajit) +LUA_VERSION="${LUA_VERSION:-luajit}" + +# Set the artifact name pattern +ARTIFACT_NAME_PATTERN="avante_lib-$PLATFORM-latest-$LUA_VERSION" + +# Get the artifact download URL +ARTIFACT_URL=$(curl -s -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/actions/runs/$RUN_ID/artifacts" | + \grep -oP "(?<=\"archive_download_url\": \")https://[^\"]+/$ARTIFACT_NAME_PATTERN[^\"]+") + +mkdir -p "$TARGET_DIR" +curl -L "$ARTIFACT_URL" | tar -xz -C "$TARGET_DIR" --strip-components=1 diff --git a/lua/avante/api.lua b/lua/avante/api.lua index ac70dfe..3eae50e 100644 --- a/lua/avante/api.lua +++ b/lua/avante/api.lua @@ -10,7 +10,7 @@ local Utils = require("avante.utils") ---@field ask fun(question:string?): boolean ---@field edit fun(question:string?): nil ---@field refresh fun(): nil ----@field build fun(): boolean +---@field build fun(opts: {source: boolean}): boolean ---@field switch_provider fun(target: string): nil ---@field toggle avante.ApiToggle ---@field get_suggestion fun(): avante.Suggestion | nil @@ -20,6 +20,57 @@ local M = {} ---@param target Provider M.switch_provider = function(target) require("avante.providers").refresh(target) end +---@param path string +local function to_windows_path(path) + local winpath = path:gsub("/", "\\") + + if winpath:match("^%a:") then winpath = winpath:sub(1, 2):upper() .. winpath:sub(3) end + + winpath = winpath:gsub("\\$", "") + + return winpath +end + +---@param opts {source: boolean} +M.build = function(opts) + local dirname = Utils.trim(string.sub(debug.getinfo(1).source, 2, #"/init.lua" * -1), { suffix = "/" }) + local git_root = vim.fs.find(".git", { path = dirname, upward = true })[1] + local build_directory = git_root and vim.fn.fnamemodify(git_root, ":h") or (dirname .. "/../../") + + if opts.source and not vim.fn.executable("cargo") then + error("Building avante.nvim requires cargo to be installed.", 2) + end + + ---@type string[] + local cmd + local os_name = Utils.get_os_name() + + if vim.tbl_contains({ "linux", "darwin" }, os_name) then + cmd = { + "sh", + "-c", + string.format("make BUILD_FROM_SOURCE=%s -C %s", opts.source == true and "true" or "false", build_directory), + } + elseif os_name == "windows" then + build_directory = to_windows_path(build_directory) + cmd = { + "powershell", + "-ExecutionPolicy", + "Bypass", + "-File", + string.format("%s\\Build.ps1", build_directory), + "-WorkingDirectory", + build_directory, + } + else + error("Unsupported operating system: " .. os_name, 2) + end + + local job = vim.system(cmd, { text = true }):wait() + + return vim.tbl_contains({ 0 }, job.code) and true or false +end + ---@param question? string M.ask = function(question) if not require("avante").toggle() then return false end diff --git a/lua/avante/init.lua b/lua/avante/init.lua index 3488d75..883ac32 100644 --- a/lua/avante/init.lua +++ b/lua/avante/init.lua @@ -44,7 +44,20 @@ H.commands = function() { desc = "avante: edit selected block", nargs = "*" } ) cmd("Refresh", function() require("avante.api").refresh() end, { desc = "avante: refresh windows" }) - cmd("Build", function() M.build() end, { desc = "avante: build dependencies" }) + cmd("Build", function(opts) + local args = {} + for _, arg in ipairs(opts.fargs) do + local key, value = arg:match("(%w+)=(%w+)") + if key and value then args[key] = value == "true" end + end + if args.source == nil then args.source = Config.debug and true or false end + + require("avante.api").build(args) + end, { + desc = "avante: build dependencies", + nargs = "*", + complete = function(_, _, _) return { "source=true", "source=false" } end, + }) cmd("SwitchProvider", function(opts) require("avante.api").switch_provider(vim.trim(opts.args or "")) end, { nargs = 1, desc = "avante: switch provider", @@ -269,50 +282,6 @@ setmetatable(M.toggle, { end, }) ----@param path string -local function to_windows_path(path) - local winpath = path:gsub("/", "\\") - - if winpath:match("^%a:") then winpath = winpath:sub(1, 2):upper() .. winpath:sub(3) end - - winpath = winpath:gsub("\\$", "") - - return winpath -end - -M.build = H.api(function() - local dirname = Utils.trim(string.sub(debug.getinfo(1).source, 2, #"/init.lua" * -1), { suffix = "/" }) - local git_root = vim.fs.find(".git", { path = dirname, upward = true })[1] - local build_directory = git_root and vim.fn.fnamemodify(git_root, ":h") or (dirname .. "/../../") - - if not vim.fn.executable("cargo") then error("Building avante.nvim requires cargo to be installed.", 2) end - - ---@type string[] - local cmd - local os_name = Utils.get_os_name() - - if vim.tbl_contains({ "linux", "darwin" }, os_name) then - cmd = { "sh", "-c", string.format("make -C %s", build_directory) } - elseif os_name == "windows" then - build_directory = to_windows_path(build_directory) - cmd = { - "powershell", - "-ExecutionPolicy", - "Bypass", - "-File", - string.format("%s\\Build.ps1", build_directory), - "-WorkingDirectory", - build_directory, - } - else - error("Unsupported operating system: " .. os_name, 2) - end - - local job = vim.system(cmd, { text = true }):wait() - - return vim.tbl_contains({ 0 }, job.code) and true or false -end) - ---@param opts? avante.Config function M.setup(opts) ---PERF: we can still allow running require("avante").setup() multiple times to override config if users wish to