diff --git a/.github/workflows/fuzzy-ci.yml b/.github/workflows/fuzzy-ci.yml index d1f10cac00..cffc02a327 100644 --- a/.github/workflows/fuzzy-ci.yml +++ b/.github/workflows/fuzzy-ci.yml @@ -2,19 +2,19 @@ name: Fuzzy CI on: pull_request: - branches: [ master ] - types: [ opened, synchronize, reopened, unlabeled, labeled ] + branches: [master] + types: [opened, synchronize, reopened, unlabeled, labeled] paths-ignore: - - '**.md' - - '**.txt' - - '.git*' - - 'doc/**' - - 'emacs/**' - - 'vim/**' - - '**/emacs-lint.yml' - - 'bench/**' - - 'upstream/**' - - 'tests/**' + - "**.md" + - "**.txt" + - ".git*" + - "doc/**" + - "emacs/**" + - "vim/**" + - "**/emacs-lint.yml" + - "bench/**" + - "upstream/**" + - "tests/**" env: # Artifact names need to be consistent across jobs: @@ -41,7 +41,7 @@ env: # Irmin version and merl-an version need to be consistent for reproducibility (Irmin is used as the test code base to test `ocamlmerlin` on) IRMIN_VERSION: 3.9.0 # TODO: Release merl-an and install a certain version instead of pinning it to a certain commit - MERL_AN_SHA: 1643fb7a9958379fb4ed8d7c5169146aaa88f5b7 + MERL_AN_SHA: 6411f0d3847e8b7e66362bcb1f9345a5d3e851ca # The compiler version used on the respective branches. It also needs to form part of Irmin's build cache key. # Bump either of these whenever the compiler version is bumped on either of the two branches. @@ -66,163 +66,161 @@ jobs: matrix: commit: ["merge_branch", "base_branch"] steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Checking out ${{ matrix.commit }} - env: - base_branch_sha: ${{ github.event.pull_request.base.sha }} - merge_branch_sha: ${{ github.sha }} - run: | - sha=$${{ matrix.commit }}_sha - echo "Check out $sha" - git checkout $sha - - - name: Get desired compiler version - id: compiler - run: | - v=$${{ matrix.commit }}_COMPILER_VERSION - echo "version=$v" | tee -a $GITHUB_OUTPUT - - - name: Install OCaml - uses: ocaml/setup-ocaml@v2 - with: - ocaml-compiler: ${{ steps.compiler.outputs.version }} - dune-cache: true - - - name: Install merlin dependencies - run: | - opam pin menhirLib 20201216 --no-action - opam install . --deps-only --yes - - - name: Install merlin - run: | - # Running `subst` to have the current commit in the data produced by `merl-an` - opam exec -- dune subst - opam exec -- dune build -p merlin-lib,dot-merlin-reader,merlin - opam exec -- dune install -p merlin-lib,dot-merlin-reader,merlin - - - name: Pull irmin and its deps from cache if possible - uses: actions/cache@v3 - id: irmin-cache - with: - path: irmin/ - key: os${{ runner.os }}+arch${{ runner.arch }}+${{ hashFiles('fuzzy-ci-helpers/irmin.3.9.0.opam.locked') }}+${{ env.IRMIN_VERSION }}+${{ steps.compiler.outputs.version }} - - - name: Download Irmin tarball - if: steps.irmin-cache.outputs.cache-hit != 'true' - run: | - wget https://github.com/mirage/irmin/releases/download/$IRMIN_VERSION/irmin-$IRMIN_VERSION.tbz - - - name: Create irmin dir - if: steps.irmin-cache.outputs.cache-hit != 'true' - run: mkdir -p irmin - - - name: Decompress Irmin tarball - if: steps.irmin-cache.outputs.cache-hit != 'true' - run: tar xvf irmin-$IRMIN_VERSION.tbz -C irmin --strip-components=1 - - - name: Get Irmin's lock files - if: steps.irmin-cache.outputs.cache-hit != 'true' - run: | - cp .github/fuzzy-ci-helpers/irmin.3.9.0.opam.locked irmin/irmin.opam.locked - - - name: Install opam monorepo - if: steps.irmin-cache.outputs.cache-hit != 'true' - run: opam install opam-monorepo --yes - - - name: Pull in Irmin's dependencies - if: steps.irmin-cache.outputs.cache-hit != 'true' - run: | - git checkout ${{ github.sha }} - opam monorepo pull --lockfile=irmin.opam.locked --yes - working-directory: irmin - - - name: Prune Irmin - if: steps.irmin-cache.outputs.cache-hit != 'true' - run: | - rm -r examples/ bench/ - find test/ -mindepth 1 -maxdepth 1 -type d -not -name 'irmin-pack' -exec rm -r {} \; - find src/ -mindepth 1 -maxdepth 1 -type d \ - -not -name 'irmin-pack' \ - -not -name 'irmin' \ - -not -name 'irmin-tezos' \ - -not -name ppx_irmin \ - -not -name irmin_test \ - -not -name irmin-test \ - -exec rm -r {} \; - working-directory: irmin - - - name: Build Irmin - run: | - opam exec -- dune build @check - working-directory: irmin - - - name: Pull merl-an from cache if possible - uses: actions/cache@v3 - id: merl-an-cache - with: - path: /usr/local/bin/merl-an - key: os${{ runner.os }}+arch${{ runner.arch }}+merl-an-sha$MERL_AN_SHA - - - name: Install merl-an - if: steps.merl-an-cache.outputs.cache-hit != 'true' - run: opam pin -y merl-an https://github.com/pitag-ha/merl-an.git#$MERL_AN_SHA - - - name: Add merl-an to /usr/local/bin/ - if: steps.merl-an-cache.outputs.cache-hit != 'true' - run: opam exec -- cp $GITHUB_WORKSPACE/_opam/bin/merl-an /usr/local/bin/merl-an - - - name: Create data set of Merlin responses - run: | - # Note: The parameters with most influence on the execution time are - # `--sample-size`: Number of samples per file defined by `--project` (and per local query). - # `--project`: List of dirs/files to create samples on. In the case of a dirs, all ml(i) files recursively in the dir are used. - # `--queries`: The `ocamlmerlin` queries that are being run. - opam exec -- merl-an behavior \ - --queries=type-enclosing,occurrences,locate,complete-prefix,errors \ - --sample-size=30 \ - --data=${{ env.data_dir }} \ - --merlin=ocamlmerlin \ - --project=irmin/src/irmin,irmin/src/irmin-pack,irmin/test/irmin-pack - - - name: Remove varying components from data - run: | - # TODO: This could be done on the `merl-an` side - jq '.responses |= map(del(.heap_mbytes, .timings, .cache))' \ - ${{ env.data_dir }}/$FULL_DATA_FILE > temp.json && \ - mv temp.json ${{ env.data_dir }}/$FULL_DATA_FILE - - - name: Create name for data artifact - id: artifact_name - env: - base_branch_artifact_name: ${{ env.BASE_BRANCH_ARTIFACT_NAME }} - merge_branch_artifact_name: ${{ env. MERGE_BRANCH_ARTIFACT_NAME }} - run: echo "name=$${{ matrix.commit }}_artifact_name" >> $GITHUB_OUTPUT - - - name: Upload data - uses: actions/upload-artifact@v3 - with: - name: ${{ steps.artifact_name.outputs.name }} - path: ${{ env.data_dir }} - - - name: Compile diff tool - if: ${{ matrix.commit == 'merge_branch' }} - run: | - # Taking advantage that ocamlopt is installed on this runner: compile the diff tool here and share it with the next job where it's needed. - # All GH runners are hosted on x86 machines and all jobs in this workflow declare the same OS, so this should workTM. - opam exec -- ocamlopt -o create_diff .github/fuzzy-ci-helpers/create_diff.ml - - - name: Upload diff tool - if: ${{ matrix.commit == 'merge_branch' }} - uses: actions/upload-artifact@v3 - with: - name: diff_tool - path: create_diff + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Checking out ${{ matrix.commit }} + env: + base_branch_sha: ${{ github.event.pull_request.base.sha }} + merge_branch_sha: ${{ github.sha }} + run: | + sha=$${{ matrix.commit }}_sha + echo "Check out $sha" + git checkout $sha + + - name: Get desired compiler version + id: compiler + run: | + v=$${{ matrix.commit }}_COMPILER_VERSION + echo "version=$v" | tee -a $GITHUB_OUTPUT + + - name: Install OCaml + uses: ocaml/setup-ocaml@v2 + with: + ocaml-compiler: ${{ steps.compiler.outputs.version }} + dune-cache: true + + - name: Install merlin dependencies + run: | + opam pin menhirLib 20201216 --no-action + opam install . --deps-only --yes + + - name: Install merlin + run: | + # Running `subst` to have the current commit in the data produced by `merl-an` + opam exec -- dune subst + opam exec -- dune build -p merlin-lib,dot-merlin-reader,merlin + opam exec -- dune install -p merlin-lib,dot-merlin-reader,merlin + + - name: Pull irmin and its deps from cache if possible + uses: actions/cache@v3 + id: irmin-cache + with: + path: irmin/ + key: os${{ runner.os }}+arch${{ runner.arch }}+${{ hashFiles('fuzzy-ci-helpers/irmin.3.9.0.opam.locked') }}+${{ env.IRMIN_VERSION }}+${{ steps.compiler.outputs.version }} + + - name: Download Irmin tarball + if: steps.irmin-cache.outputs.cache-hit != 'true' + run: | + wget https://github.com/mirage/irmin/releases/download/$IRMIN_VERSION/irmin-$IRMIN_VERSION.tbz + + - name: Create irmin dir + if: steps.irmin-cache.outputs.cache-hit != 'true' + run: mkdir -p irmin + + - name: Decompress Irmin tarball + if: steps.irmin-cache.outputs.cache-hit != 'true' + run: tar xvf irmin-$IRMIN_VERSION.tbz -C irmin --strip-components=1 + + - name: Get Irmin's lock files + if: steps.irmin-cache.outputs.cache-hit != 'true' + run: | + cp .github/fuzzy-ci-helpers/irmin.3.9.0.opam.locked irmin/irmin.opam.locked + + - name: Install opam monorepo + if: steps.irmin-cache.outputs.cache-hit != 'true' + run: opam install opam-monorepo --yes + + - name: Pull in Irmin's dependencies + if: steps.irmin-cache.outputs.cache-hit != 'true' + run: | + git checkout ${{ github.sha }} + opam monorepo pull --lockfile=irmin.opam.locked --yes + working-directory: irmin + + - name: Prune Irmin + if: steps.irmin-cache.outputs.cache-hit != 'true' + run: | + rm -r examples/ bench/ + find test/ -mindepth 1 -maxdepth 1 -type d -not -name 'irmin-pack' -exec rm -r {} \; + find src/ -mindepth 1 -maxdepth 1 -type d \ + -not -name 'irmin-pack' \ + -not -name 'irmin' \ + -not -name 'irmin-tezos' \ + -not -name ppx_irmin \ + -not -name irmin_test \ + -not -name irmin-test \ + -exec rm -r {} \; + working-directory: irmin + + - name: Build Irmin + run: | + opam exec -- dune build @check + working-directory: irmin + + - name: Pull merl-an from cache if possible + uses: actions/cache@v3 + id: merl-an-cache + with: + path: /usr/local/bin/merl-an + key: os${{ runner.os }}+arch${{ runner.arch }}+merl-an-sha$MERL_AN_SHA + - name: Install merl-an + if: steps.merl-an-cache.outputs.cache-hit != 'true' + run: opam pin -y merl-an https://github.com/pitag-ha/merl-an.git#$MERL_AN_SHA + - name: Add merl-an to /usr/local/bin/ + if: steps.merl-an-cache.outputs.cache-hit != 'true' + run: opam exec -- cp $GITHUB_WORKSPACE/_opam/bin/merl-an /usr/local/bin/merl-an + + - name: Create data set of Merlin responses + run: | + # Note: The parameters with most influence on the execution time are + # `--sample-size`: Number of samples per file defined by `--project` (and per local query). + # `--project`: List of dirs/files to create samples on. In the case of a dirs, all ml(i) files recursively in the dir are used. + # `--queries`: The `ocamlmerlin` queries that are being run. + opam exec -- merl-an behavior \ + --queries=type-enclosing,occurrences,locate,complete-prefix,errors \ + --sample-size=30 \ + --data=${{ env.data_dir }} \ + --merlin=ocamlmerlin \ + --project=irmin/src/irmin,irmin/src/irmin-pack,irmin/test/irmin-pack + + - name: Remove varying components from data + run: | + # TODO: This could be done on the `merl-an` side + jq '.responses |= map(del(.heap_mbytes, .timings, .cache))' \ + ${{ env.data_dir }}/$FULL_DATA_FILE > temp.json && \ + mv temp.json ${{ env.data_dir }}/$FULL_DATA_FILE + + - name: Create name for data artifact + id: artifact_name + env: + base_branch_artifact_name: ${{ env.BASE_BRANCH_ARTIFACT_NAME }} + merge_branch_artifact_name: ${{ env. MERGE_BRANCH_ARTIFACT_NAME }} + run: echo "name=$${{ matrix.commit }}_artifact_name" >> $GITHUB_OUTPUT + + - name: Upload data + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.artifact_name.outputs.name }} + path: ${{ env.data_dir }} + + - name: Compile diff tool + if: ${{ matrix.commit == 'merge_branch' }} + run: | + # Taking advantage that ocamlopt is installed on this runner: compile the diff tool here and share it with the next job where it's needed. + # All GH runners are hosted on x86 machines and all jobs in this workflow declare the same OS, so this should workTM. + opam exec -- ocamlopt -o create_diff .github/fuzzy-ci-helpers/create_diff.ml + + - name: Upload diff tool + if: ${{ matrix.commit == 'merge_branch' }} + uses: actions/upload-artifact@v3 + with: + name: diff_tool + path: create_diff diff: name: Generate diffs @@ -300,8 +298,6 @@ jobs: name: ${{ env.DIFF_ARTIFACT_NAME }} path: ${{ env.diff_dir }} - - output: name: Evaluate diffs runs-on: ubuntu-22.04 @@ -420,7 +416,6 @@ jobs: fi fi - approve: name: Approve diff if: > @@ -473,8 +468,8 @@ jobs: env: id: ${{ steps.diff_metadata.outputs.id }} run: | - # Doing this manually, since actions/download-artifact only works on the same workflow run on which the artifact was uploaded - curl -sSLO -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "$GH_API_ARTIFACTS/$id/zip" -D headers.txt + # Doing this manually, since actions/download-artifact only works on the same workflow run on which the artifact was uploaded + curl -sSLO -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "$GH_API_ARTIFACTS/$id/zip" -D headers.txt - name: Unzip downloaded diff run: | diff --git a/CHANGES.md b/CHANGES.md index 2e5045ce0b..da12d591fe 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,9 @@ merlin NEXT_VERSION - Ignore SIGPIPE in the Merlin server process (#1746) - Fix lexing of quoted strings in comments (#1754, fixes #1753) - Improve cursor position detection in longidents (#1756) + - Addition of a `merlin-lib.commands` library which disassociates the + execution of commands from the `new_protocol`, from the binary, allowing + it to be invoked from other projects (#1758) merlin 4.14 =========== diff --git a/src/commands/dune b/src/commands/dune new file mode 100644 index 0000000000..016727ba05 --- /dev/null +++ b/src/commands/dune @@ -0,0 +1,14 @@ +(library + (name merlin_commands) + (public_name merlin-lib.commands) + (flags + :standard + -open Ocaml_parsing + -open Merlin_utils + -open Merlin_kernel) + (libraries + merlin-lib.ocaml_parsing + merlin-lib.utils + merlin-lib.kernel + merlin-lib.query_protocol + merlin-lib.query_commands)) diff --git a/src/frontend/ocamlmerlin/new/new_commands.ml b/src/commands/new_commands.ml similarity index 94% rename from src/frontend/ocamlmerlin/new/new_commands.ml rename to src/commands/new_commands.ml index a1b753dd7d..81e5ff1bc5 100644 --- a/src/frontend/ocamlmerlin/new/new_commands.ml +++ b/src/commands/new_commands.ml @@ -1,3 +1,32 @@ +(* {{{ COPYING *( + + This file is part of Merlin, an helper for ocaml editors + + Copyright (C) 2013 - 2015 Frédéric Bour + Thomas Refis + Simon Castellan + Tomasz Kołodziejski + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + The Software is provided "as is", without warranty of any kind, express or + implied, including but not limited to the warranties of merchantability, + fitness for a particular purpose and noninfringement. In no event shall + the authors or copyright holders be liable for any claim, damages or other + liability, whether in an action of contract, tort or otherwise, arising + from, out of or in connection with the software or the use or other dealings + in the Software. + +)* }}} *) + open Std type command = diff --git a/src/commands/new_commands.mli b/src/commands/new_commands.mli new file mode 100644 index 0000000000..e8f766f822 --- /dev/null +++ b/src/commands/new_commands.mli @@ -0,0 +1,38 @@ +(* {{{ COPYING *( + + This file is part of Merlin, an helper for ocaml editors + + Copyright (C) 2013 - 2015 Frédéric Bour + Thomas Refis + Simon Castellan + Tomasz Kołodziejski + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + The Software is provided "as is", without warranty of any kind, express or + implied, including but not limited to the warranties of merchantability, + fitness for a particular purpose and noninfringement. In no event shall + the authors or copyright holders be liable for any claim, damages or other + liability, whether in an action of contract, tort or otherwise, arising + from, out of or in connection with the software or the use or other dealings + in the Software. + +)* }}} *) + +open Std + +type command = + Command : string * Marg.docstring * ([`Mandatory|`Optional|`Many] * 'args Marg.spec) list * 'args * + (Mpipeline.t -> 'args -> json) -> command + +val all_commands : command list + +val find_command : string -> command list -> command diff --git a/src/frontend/ocamlmerlin/query_json.ml b/src/commands/query_json.ml similarity index 100% rename from src/frontend/ocamlmerlin/query_json.ml rename to src/commands/query_json.ml diff --git a/src/frontend/ocamlmerlin/dune b/src/frontend/ocamlmerlin/dune index 629faa6e4b..8b17d252da 100644 --- a/src/frontend/ocamlmerlin/dune +++ b/src/frontend/ocamlmerlin/dune @@ -12,12 +12,15 @@ -open Merlin_kernel -open Merlin_utils -open Merlin_analysis - -open Merlin_kernel) + -open Merlin_kernel + -open Merlin_commands) (modules (:standard \ gen_ccflags)) (libraries merlin-lib.config yojson merlin-lib.analysis merlin-lib.kernel merlin-lib.utils merlin-lib.os_ipc merlin-lib.ocaml_parsing merlin-lib.query_protocol merlin-lib.query_commands - merlin-lib.ocaml_typing merlin-lib.ocaml_utils unix str)) + merlin-lib.ocaml_typing merlin-lib.ocaml_utils + merlin-lib.commands + unix str)) (executable (name gen_ccflags) diff --git a/src/frontend/ocamlmerlin/new/new_commands.mli b/src/frontend/ocamlmerlin/new/new_commands.mli deleted file mode 100644 index 2c6498aa25..0000000000 --- a/src/frontend/ocamlmerlin/new/new_commands.mli +++ /dev/null @@ -1,9 +0,0 @@ -open Std - -type command = - Command : string * Marg.docstring * ([`Mandatory|`Optional|`Many] * 'args Marg.spec) list * 'args * - (Mpipeline.t -> 'args -> json) -> command - -val all_commands : command list - -val find_command : string -> command list -> command