From 11fd2ce35a5d67c93a75f85d0d0967e1e7551ae8 Mon Sep 17 00:00:00 2001 From: Paul Hilt Date: Mon, 24 Jul 2023 20:53:50 +0200 Subject: [PATCH] add installer script --- .github/workflows/build_installers.yaml | 91 ++++++++++++++++++++++++ deployment/construct.yaml | 15 ++++ deployment/env.yaml | 9 +++ deployment/version_getter.py | 15 ++++ deployment/windows_menu.json | 14 ++++ deployment/windows_menu_setup.py | 10 +++ doc/images/micro-sam-logo.ico | Bin 0 -> 217598 bytes 7 files changed, 154 insertions(+) create mode 100644 .github/workflows/build_installers.yaml create mode 100644 deployment/construct.yaml create mode 100644 deployment/env.yaml create mode 100644 deployment/version_getter.py create mode 100644 deployment/windows_menu.json create mode 100644 deployment/windows_menu_setup.py create mode 100644 doc/images/micro-sam-logo.ico diff --git a/.github/workflows/build_installers.yaml b/.github/workflows/build_installers.yaml new file mode 100644 index 00000000..9dc900c4 --- /dev/null +++ b/.github/workflows/build_installers.yaml @@ -0,0 +1,91 @@ +name: build_installers + +on: + push: + tags: + - '**' + branches: + - '*' + +jobs: + build_intaller: + name: ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + + env: + PREPARE_SCRIPT: | + cd deployment + conda install -y -c conda-forge constructor + conda install -y -c conda-forge ruamel.yaml + conda install -y -c conda-forge mamba + mamba env create --file=env.yaml + RUN_SCRIPT: | + python version_getter.py + mkdir ./${{ matrix.os }}_x86_64 + constructor --output-dir ./${{ matrix.os }}_x86_64 . + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: setup conda + if: matrix.os == 'windows-latest' || matrix.os == 'ubuntu-latest' + uses: conda-incubator/setup-miniconda@v2 + with: + miniconda-version: "latest" + auto-activate-base: true + activate-environment: "" + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + + - name: build ${{ matrix.os }}_x86_64 + if: matrix.os == 'windows-latest' + shell: pwsh + run: | + ${{ env.PREPARE_SCRIPT }} + conda activate __MICROSAM_BUILD_ENV__ + conda install -c anaconda menuinst + python windows_menu_setup.py + conda activate base + ${{ env.RUN_SCRIPT }} + + - name: build ${{ matrix.os }}_x86_64 + if: matrix.os == 'ubuntu-latest' + shell: bash -el {0} + run: | + ${{ env.PREPARE_SCRIPT }} + ${{ env.RUN_SCRIPT }} + + - name: build ${{ matrix.os }}_x86_64_step1 + if: matrix.os == 'macos-latest' + shell: bash -el {0} + run: | + brew install micromamba + /usr/local/opt/micromamba/bin/micromamba shell init -s bash -p ~/micromamba + + - name: build ${{ matrix.os }}_x86_64_step2 + if: matrix.os == 'macos-latest' + shell: bash -el {0} + run: | + cd deployment + micromamba activate base + micromamba install -y -c conda-forge python=3.10 + micromamba install -y -c conda-forge constructor + micromamba install -y -c conda-forge ruamel.yaml + micromamba install -y -c conda-forge mamba + mamba env create --file=env.yaml + python version_getter.py + mkdir ./${{ matrix.os }}_x86_64 + constructor --conda-exe=$(which mamba) --output-dir ./${{ matrix.os }}_x86_64 . + + - name: upload installer + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.os }}_x86_64 + path: ./deployment/${{ matrix.os }}_x86_64 + retention-days: 5 diff --git a/deployment/construct.yaml b/deployment/construct.yaml new file mode 100644 index 00000000..3cb7ad9b --- /dev/null +++ b/deployment/construct.yaml @@ -0,0 +1,15 @@ +name: micro_sam +version: 0.1.0 +license_file: ../LICENSE +installer_type: pkg #[osx] # This will trigger pkg build on Mac Os. On windows and linux, native build will be done and this has no effect. +environment: __MICROSAM_BUILD_ENV__ +welcome_image: ../doc/images/micro-sam-logo.png +header_image: ../doc/images/micro-sam-logo.png +icon_image: ../doc/images/micro-sam-logo.png +channels: +- conda-forge +welcome_text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. +conclusion_text: Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris + nisi ut aliquip ex ea commodo consequat. +initialize_by_default: true \ No newline at end of file diff --git a/deployment/env.yaml b/deployment/env.yaml new file mode 100644 index 00000000..dc5d317a --- /dev/null +++ b/deployment/env.yaml @@ -0,0 +1,9 @@ +name: __MICROSAM_BUILD_ENV__ +channels: + - conda-forge +dependencies: + - napari + - pyqt + - pytorch::pytorch + - pytorch::torchvision + - micro_sam diff --git a/deployment/version_getter.py b/deployment/version_getter.py new file mode 100644 index 00000000..fef7eec0 --- /dev/null +++ b/deployment/version_getter.py @@ -0,0 +1,15 @@ +import runpy +import ruamel.yaml +import os + +yaml = ruamel.yaml.YAML() +yaml.preserve_quotes = True +ctor_fname = os.path.join("construct.yaml") + +with open(ctor_fname, 'r') as stream: + ctor_conf = yaml.load(stream) + +ctor_conf["version"] = runpy.run_path(os.path.join("..", "micro_sam", "__version__.py"))["__version__"] + +with open(ctor_fname, 'w') as outfile: + yaml.dump(ctor_conf, outfile) diff --git a/deployment/windows_menu.json b/deployment/windows_menu.json new file mode 100644 index 00000000..cf409eb2 --- /dev/null +++ b/deployment/windows_menu.json @@ -0,0 +1,14 @@ +{ + "menu_name": "micro_sam", + "menu_items": + [ + { + "script": "${PREFIX}/Scripts/micro_sam.annotator.exe", + "name": "micro_sam", + "icon": "${PREFIX}/Menu/micro-sam-logo.ico", + "workdir": "${PREFIX}", + "desktop": true, + "quicklaunch": true + } + ] +} \ No newline at end of file diff --git a/deployment/windows_menu_setup.py b/deployment/windows_menu_setup.py new file mode 100644 index 00000000..182a5123 --- /dev/null +++ b/deployment/windows_menu_setup.py @@ -0,0 +1,10 @@ +import menuinst +import shutil +import os + +conda_dir = os.environ["CONDA_PREFIX"] +menu_dir = os.path.join(conda_dir, "Menu") +os.makedirs(menu_dir, exist_ok = True) +shutil.copy("../doc/images/micro-sam-logo.ico", menu_dir) +shutil.copy("./windows_menu.json", menu_dir) +menuinst.install(os.path.join(menu_dir, 'windows_menu.json'), prefix=conda_dir) diff --git a/doc/images/micro-sam-logo.ico b/doc/images/micro-sam-logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..3c8d968766892571c14691c6d5dc9e5710a7d3db GIT binary patch literal 217598 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 Z^lSY8T2+m1s`0XtryooC)Bgwh{|Doa;u8P> literal 0 HcmV?d00001