Skip to content

[Fix] MacOS build when xcode is not installed #574

[Fix] MacOS build when xcode is not installed

[Fix] MacOS build when xcode is not installed #574

Workflow file for this run

name: CI
env:
PROJECT_NAME: unison
PROJECT_DESC: "`unison` file synchronizer"
PROJECT_EXES: "unison unison-fsmonitor"
on:
- pull_request
- push
jobs:
docs:
runs-on: ubuntu-20.04
steps:
- run: sudo apt-get update
- name: Checkout code
uses: actions/checkout@v4
- name: Use OCaml
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: 4.14.x
opam-depext: false
- run: sudo apt-get install hevea lynx texlive-latex-base
- run: opam exec -- make docs
- name: Store user manual for the build jobs
uses: actions/upload-artifact@v4
with:
name: unison-docs
path: |
doc/unison-manual.txt
doc/unison-manual.html
doc/unison-manual.pdf
man/unison.1
- name: Store user manual for the build jobs (legacy, for build_compat)
uses: actions/upload-artifact@v3
with:
name: unison-docs
path: |
doc/unison-manual.txt
doc/unison-manual.html
doc/unison-manual.pdf
man/unison.1
build:
if: ${{ !cancelled() }} # Don't fail if 'docs' failed
needs: docs
strategy:
fail-fast: false
matrix:
job:
- { os: macos-14 , ocaml-version: 5.2.0 }
- { os: macos-14 , ocaml-version: 4.14.2 , publish: true , fnsuffix: -macos-arm64 }
- { os: macos-12 , ocaml-version: 4.14.2 , publish: true , fnsuffix: -macos-x86_64 }
- { os: ubuntu-22.04 , ocaml-version: 5.2.0 }
- { os: ubuntu-22.04 , ocaml-version: 4.14.2 }
- { os: ubuntu-20.04 , ocaml-version: 4.14.2 }
- { os: windows-2022 , ocaml-version: 4.14.0+mingw64c , publish: true , fnsuffix: -windows-x86_64 }
- { os: windows-2019 , ocaml-version: 4.14.0+mingw32c , publish: true , fnsuffix: -windows-i386 }
runs-on: ${{ matrix.job.os }}
steps:
- if: contains(matrix.job.os, 'ubuntu')
run: sudo apt-get update
- if: runner.os == 'Windows'
name: "Windows: Stash away the default MSYS installation"
continue-on-error: true
shell: cmd
# This conflicts with Cygwin installed by setup-ocaml
# Adjusting PATH alone does not seem to work
run: rename C:\msys64 dmsys64
- name: Checkout code
uses: actions/checkout@v4
- name: Initialize workflow variables
id: vars
shell: bash
run: |
outputs() { for var in "$@" ; do echo steps.vars.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT ; done; }
# normalize to pre-compiled ocaml compiler variants for windows/Cygwin (decreases OCaml install time by 50%)
case '${{ matrix.job.ocaml-version }}' in
*+*) OCAML_COMPILER='ocaml-variants.${{ matrix.job.ocaml-version }}' ;;
*) OCAML_COMPILER='ocaml-base-compiler.${{ matrix.job.ocaml-version }}' ;;
esac
OCAML_VARIANT='${{ matrix.job.ocaml-version }}'
OCAML_VARIANT="${OCAML_VARIANT/+options/}"
outputs OCAML_VARIANT OCAML_COMPILER
# architecture/platform vars
EXE_suffix='' ; case '${{ matrix.job.os }}' in windows-*) EXE_suffix=".exe" ;; esac
MinGW_ARCH='x86_64' ; case '${{ matrix.job.ocaml-version }}' in *+mingw32*) MinGW_ARCH='i686' ;; *+mingw64*) MinGW_ARCH='x86_64' ;; esac
MSVC_ARCH='' ; case '${{ matrix.job.ocaml-version }}' in *+msvc32*) MSVC_ARCH='x86' ;; *+msvc64*) MSVC_ARCH='x64' ;; esac
outputs EXE_suffix MinGW_ARCH MSVC_ARCH
case '${{ matrix.job.os }}','${{ matrix.job.ocaml-version }}' in
macos-*,4*) MACOSX_DEPLOYMENT_TARGET=10.6 ;; macos-*,5*) MACOSX_DEPLOYMENT_TARGET=10.7 ;;
macos-14*,*) MACOSX_DEPLOYMENT_TARGET=10.13 ;;
esac
case '${{ matrix.job.os }}' in
macos-*) echo "MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET}" >> $GITHUB_ENV ;
echo "XCODEFLAGS=-arch $(uname -m) -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET}" >> $GITHUB_ENV ;
echo "CFLAGS=${CFLAGS} -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET}" >> $GITHUB_ENV ;;
esac
# staging environment
STAGING_DIR='_staging'
outputs STAGING_DIR
# parse commit reference info
echo GITHUB_REF=${GITHUB_REF}
echo GITHUB_SHA=${GITHUB_SHA}
REF_NAME="${GITHUB_REF#refs/*/}"
unset REF_BRANCH ; case "${GITHUB_REF}" in refs/heads/*) REF_BRANCH="${GITHUB_REF#refs/heads/}" ;; esac;
unset REF_TAG ; case "${GITHUB_REF}" in refs/tags/*) REF_TAG="${GITHUB_REF#refs/tags/}" ;; esac;
REF_SHAS="${GITHUB_SHA:0:8}"
outputs REF_BRANCH REF_NAME REF_SHAS REF_TAG
# deployable tag? (ie, leading "vM" or "M"; M == version number)
unset DEPLOY ; if [[ $REF_TAG =~ ^[vV]?[0-9].* ]]; then DEPLOY='true' ; fi
outputs DEPLOY
# package name
PKG_suffix='.tar.gz' ; case '${{ matrix.job.os }}' in windows-*) PKG_suffix='.zip' ;; esac;
PKG_VER="${REF_TAG:-git_$REF_SHAS}"
PKG_VER="${PKG_VER#v}"
PKG_BASENAME="${PROJECT_NAME}-${PKG_VER}${{ matrix.job.fnsuffix }}"
PKG_NAME="${PKG_BASENAME}${PKG_suffix}"
PKG_DIR="${STAGING_DIR}/${PKG_BASENAME}"
outputs PKG_VER PKG_BASENAME PKG_DIR PKG_NAME PKG_suffix
COMPRESS_CMD='tar czf'; case '${{ matrix.job.os }}' in windows-*) COMPRESS_CMD='7z -y a' ;; esac;
outputs COMPRESS_CMD
- name: Create/configure any needed build/workspace
shell: bash
run: |
# create build/work space
mkdir -p '${{ steps.vars.outputs.STAGING_DIR }}'
mkdir -p '${{ steps.vars.outputs.PKG_DIR }}'
mkdir -p '${{ steps.vars.outputs.PKG_DIR }}'/bin
- name: Enable/config MSVC environment (if/when needed)
uses: ilammy/msvc-dev-cmd@v1
with:
arch: "${{ steps.vars.outputs.MSVC_ARCH }}"
if: contains(matrix.job.ocaml-version, '+msvc')
- name: Use OCaml ${{ matrix.job.ocaml-version }}
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: "${{ steps.vars.outputs.OCAML_COMPILER }}"
opam-pin: false
opam-depext: false
# setup-ocaml can prepare the build environment from unison.opam
# We're not relying on that capability here, to make sure the builds
# also work without using unison.opam
## note: at this point, after OCaml installation, windows platforms will use Cygwin bash as the default
## ... Cygwin bash cannot handle shell scripts containing CRLF EOLs (which are what is generated by GHA on windows platforms)
## ... so, "igncr" must be added to SHELLOPTS
- name: Prepare Cygwin environment (Windows)
if: runner.os == 'Windows'
shell: cmd
run: |
echo %CYGWIN_ROOT_BIN%>> %GITHUB_PATH%
echo %CYGWIN_ROOT_WRAPPERBIN%>> %GITHUB_PATH%
echo "/usr/${{ steps.vars.outputs.MinGW_ARCH }}-w64-mingw32/sys-root/mingw/bin">> %GITHUB_PATH%
echo SHELLOPTS=igncr>> %GITHUB_ENV%
- shell: bash
env:
LDFLAGS: ${{ matrix.job.static }}
run: |
opam exec -- make tui
opam exec -- make fsmonitor
# stage
# * notes: darwin/macos doesn't build `unison-fsmonitor`
for file in ${PROJECT_EXES} ; do
if [ -f "src/${file}${{ steps.vars.outputs.EXE_suffix }}" ]; then
cp "src/${file}${{ steps.vars.outputs.EXE_suffix }}" '${{ steps.vars.outputs.PKG_DIR }}/bin'
echo "'src/${file}${{ steps.vars.outputs.EXE_suffix }}' copied to '${{ steps.vars.outputs.PKG_DIR }}/bin'"
fi
done
- run: opam exec -- make test
## There is still code to run tests with old ocaml on Windows.
## That remains intentionally so that someone could turn it on if
## desired.
- name: Run self-tests over RPC
if: runner.os == 'Windows' && !contains(matrix.job.ocaml-version, '4.14')
shell: bash
run: |
# Separate backup dir must be set for server instance so that the central
# backup location of both instances doesn't overlap
UNISONBACKUPDIR=./src/testbak2 ./src/unison -socket 55443 &
sleep 1 # Wait for the server to be fully started
./src/unison -ui text -selftest testr1 socket://127.0.0.1:55443/testr2 -killserver
- name: Run self-tests over local socket
# Recent Windows versions do support Unix domain sockets
# but at least OCaml 4.14 is required to use that support
if: runner.os != 'Windows' || contains(matrix.job.ocaml-version, '4.14')
shell: bash
run: |
mkdir localsocket
chmod 700 localsocket
# Separate backup dir must be set for server instance so that the central
# backup location of both instances doesn't overlap
UNISONBACKUPDIR=./src/testbak4 ./src/unison -socket ./localsocket/test.sock &
sleep 1 # Wait for the server to be fully started
${{ runner.os == 'Windows' }} || test -S ./localsocket/test.sock
./src/unison -ui text -selftest testr3 socket://{./localsocket/test.sock}/testr4 -killserver
- name: Prepare lablgtk install (Windows)
if: ${{ runner.os == 'Windows' && contains(matrix.job.ocaml-version, '+mingw') }}
shell: bash
run: |
opam install opam-depext depext-cygwinports
setup-x86_64.exe --quiet-mode --root "${CYGWIN_ROOT}" --site http://cygwin.mirror.constant.com --symlink-type=sys --packages hicolor-icon-theme,adwaita-icon-theme
# [2022-11] This terrible (terrible) hack is here to forcibly skip
# building the fontconfig cache because it can take 30-45 minutes
# on GHA runners and is never needed anyway.
setup-x86_64.exe --quiet-mode --root "${CYGWIN_ROOT}" --site http://cygwin.mirror.constant.com --symlink-type=sys --local-package-dir D:/a --download --packages mingw64-${{ steps.vars.outputs.MinGW_ARCH }}-fontconfig
cd 'D:/a/https%3a%2f%2fcygwin.mirror.constant.com%2f/noarch/release/'mingw64-${{ steps.vars.outputs.MinGW_ARCH }}-fontconfig
CNAMEXZ=$(ls mingw64-${{ steps.vars.outputs.MinGW_ARCH }}-fontconfig*.tar.xz)
CNAME=${CNAMEXZ%.xz}
unxz ${CNAMEXZ}
tar --delete --file ${CNAME} etc/postinstall/zp_mingw64-${{ steps.vars.outputs.MinGW_ARCH }}-fontconfig_cache.sh
xz ${CNAME}
sha512sum > sha512.sum
CSZ=$(stat -c %s ${CNAMEXZ})
SHASUM=$(sha512sum ${CNAMEXZ})
cd 'D:/a/https%3a%2f%2fcygwin.mirror.constant.com%2f/x86_64'
mv setup.ini tsetup.ini
rm -f setup*
sed -E -e "\|install: noarch/release/mingw64-${{ steps.vars.outputs.MinGW_ARCH }}-fontconfig/${CNAMEXZ}|s/xz .+/xz ${CSZ} ${SHASUM%% *}/" tsetup.ini > setup.ini
rm tsetup.ini
sha512sum > sha512.sum
setup-x86_64.exe --quiet-mode --root "${CYGWIN_ROOT}" --symlink-type=sys --local-install --local-package-dir 'D:/a/https%3a%2f%2fcygwin.mirror.constant.com%2f' --mirror-mode --no-verify --packages mingw64-${{ steps.vars.outputs.MinGW_ARCH }}-fontconfig
- name: lablgtk install
## [2020-09] non-working/unavailable for MSVC or musl OCaml variants ; also, non-working for 32bit OCaml variant (see [GH:garrigue/lablgtk#64](https://github.com/garrigue/lablgtk/issues/64))
if: ${{ ! ( contains(matrix.job.ocaml-version, '+msvc') || contains(matrix.job.ocaml-version, '-musl') || contains(matrix.job.ocaml-version, '-32bit') ) }}
run: opam depext --install --verbose --yes lablgtk3 && opam install ocamlfind
- if: ${{ !matrix.job.static }} ## unable to build static gtk/gui
shell: bash
run: |
opam exec -- make gui
# stage
# * copy only main/first project binary
project_exe_stem=${PROJECT_EXES%% *}
cp "src/${project_exe_stem}-gui${{ steps.vars.outputs.EXE_suffix }}" "${{ steps.vars.outputs.PKG_DIR }}/bin/"
- name: "Build WinOS text+gui hybrid"
if: ${{ runner.os == 'Windows' && !matrix.job.static }} ## WinOS, non-static (unable to build static gtk/gui)
shell: bash
run: |
# create and stage text+gui hybrid for Windows
# * copy only main/first project binary
project_exe_stem=${PROJECT_EXES%% *}
# * clean/remove build artifact(s)
rm "src/${project_exe_stem}-gui${{ steps.vars.outputs.EXE_suffix }}" ##.or.# opam exec -- make -C src clean #.or.# opam exec -- make clean
# * re-create (with hybrid text+gui UI)
opam exec -- make gui UI_WINOS=hybrid
cp "src/${project_exe_stem}-gui${{ steps.vars.outputs.EXE_suffix }}" "${{ steps.vars.outputs.PKG_DIR }}/bin/${project_exe_stem}-text+gui${{ steps.vars.outputs.EXE_suffix }}"
- uses: actions/upload-artifact@v4
if: false ## disable by default; only useful for debugging GHA
with:
name: unison-${{ steps.vars.outputs.REF_SHAS }}.ocaml-${{ matrix.job.ocaml-version }}.${{ matrix.job.os }}
path: ${{ steps.vars.outputs.PKG_DIR }}/bin/*
- name: Copy user manual
continue-on-error: ${{ !(steps.vars.outputs.DEPLOY && matrix.job.publish) }}
uses: actions/download-artifact@v4
with:
name: unison-docs
path: '${{ steps.vars.outputs.PKG_DIR }}'
- name: Prepare package
# if: steps.vars.outputs.DEPLOY
shell: bash
run: |
## package artifact(s)
PKG_DIR='${{ steps.vars.outputs.PKG_DIR }}'
# `strip` binaries
strip "${PKG_DIR}/bin"/*'${{ steps.vars.outputs.EXE_suffix }}'
# README and LICENSE
(shopt -s nullglob; for f in [R]'EADME'{,.*}; do cp $f "${PKG_DIR}"/ ; done)
(shopt -s nullglob; for f in [L]'ICENSE'{-*,}{,.*}; do cp $f "${PKG_DIR}"/ ; done)
cp INSTALL.md "${PKG_DIR}"/
cp CONTRIBUTING.md "${PKG_DIR}"/
cp NEWS.md "${PKG_DIR}"/
- if: runner.os == 'Windows'
name: "Windows: Package gtk"
shell: bash
run: |
# [2023-03] Setting this PATH here (and it has to be right here) is
# a workaround for an unknown issue (most likely something with GHA)
# causing MinGW binutils not to be found (while other binutils
# pre-installed in the GHA images may be found instead), which in turn
# causes the DLL extracting functions to silently fail.
export PATH="/usr/${{ steps.vars.outputs.MinGW_ARCH }}-w64-mingw32/bin":${PATH}
## package artifact(s)
PKG_DIR='${{ steps.vars.outputs.PKG_DIR }}'
# collect any needed dlls/libraries
# dlls
dll_refs() { eval "$(opam env)" ; eval "$(ocaml-env cygwin)" ; objdump -x "$@" | grep -Po "\S+[.]dll$" | xargs -I{} 2>/dev/null which "{}" | sort -u ; }
filtered_dll_refs() { list="$(dll_refs "$@" | grep -vF "$(cygpath ${WINDIR})" | perl -lape '$_ = qq/@{[sort @F]}/')" ; echo "$list" ; }
recursive_filtered_dll_refs() { list="$(filtered_dll_refs "$@")" ; n=0 ; while [ $n -lt $(echo "$list" | wc -l) ]; do n=$(echo "$list" | wc -l) ; list="$(filtered_dll_refs $list)" ; done ; echo "$list" ; }
IFS=$'\n' DLL_list=( "$(recursive_filtered_dll_refs "${PKG_DIR}"/bin/*)" )
for dll in ${DLL_list[@]} ; do cp "${dll}" "${PKG_DIR}"/bin ; done
TARGET_ARCH_ID='x86_64'; case '${{ matrix.job.ocaml-version }}' in *+mingw32*|*+msvc32*) TARGET_ARCH_ID='i686' ;; esac
# required gdk support files
mkdir "${PKG_DIR}"/lib
cp -r /usr/${TARGET_ARCH_ID}-w64-mingw32/sys-root/mingw/lib/gdk-pixbuf-2.0 "${PKG_DIR}"/lib/
# update loader.cache to point to local relative installation
mv "${PKG_DIR}"/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache "${PKG_DIR}"/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache.original
cat "${PKG_DIR}"/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache.original | sed -E 's#([^"]*)(lib/gdk-pixbuf-2.0/2.10.0/loaders/[^"]*[.]dll)#../\2#' > "${PKG_DIR}"/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
rm "${PKG_DIR}"/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache.original
# required icons
mkdir "${PKG_DIR}"/share
cp -rL /usr/share/icons "${PKG_DIR}"/share
# compile glib settings schema
mkdir -p "${PKG_DIR}"/share/glib-2.0
cp -r /usr/${TARGET_ARCH_ID}-w64-mingw32/sys-root/mingw/share/glib-2.0/schemas "${PKG_DIR}"/share/glib-2.0
glib-compile-schemas "${PKG_DIR}"/share/glib-2.0/schemas
# add gtk configuration
mkdir -p "${PKG_DIR}"/etc/gtk-3.0
printf "[Settings]\ngtk-button-images=true\ngtk-font-name=Segoe UI 9\n" > "${PKG_DIR}"/etc/gtk-3.0/settings.ini
- name: Package
shell: bash
run: cd '${{ steps.vars.outputs.PKG_DIR }}/' && ${{ steps.vars.outputs.COMPRESS_CMD }} '../${{ steps.vars.outputs.PKG_NAME }}' *
- uses: actions/upload-artifact@v4
if: matrix.job.publish
with:
name: ${{ steps.vars.outputs.PKG_NAME }}___ocaml-${{ matrix.job.ocaml-version }}.${{ matrix.job.os }}-publish
path: ${{ steps.vars.outputs.STAGING_DIR }}/${{ steps.vars.outputs.PKG_NAME }}
- name: Publish
if: steps.vars.outputs.DEPLOY && matrix.job.publish
uses: softprops/action-gh-release@v1
with:
files: |
${{ steps.vars.outputs.STAGING_DIR }}/${{ steps.vars.outputs.PKG_NAME }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: runner.os == 'macOS'
name: "macOS: Build and package Unison.app"
id: macapp
run: |
opam exec -- make macui
# package
APP_NAME=Unison-${{ steps.vars.outputs.PKG_VER }}${{ matrix.job.fnsuffix }}.app.tar.gz
echo APP_NAME=${APP_NAME} >> $GITHUB_OUTPUT
tar czf ${APP_NAME} -C src/uimac/build/Default Unison.app
- if: runner.os == 'macOS' && matrix.job.publish
name: "macOS: Upload Unison.app artifact"
uses: actions/upload-artifact@v4
with:
name: ${{ steps.macapp.outputs.APP_NAME }}___ocaml-${{ matrix.job.ocaml-version }}.${{ matrix.job.os }}-publish
path: ${{ steps.macapp.outputs.APP_NAME }}
- if: runner.os == 'macOS' && steps.vars.outputs.DEPLOY && matrix.job.publish
name: "macOS: Publish Unison.app"
uses: softprops/action-gh-release@v1
with:
files: ${{ steps.macapp.outputs.APP_NAME }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
rpc_abicheck:
needs: build
strategy:
fail-fast: false
matrix:
# This list is intended to balance good enough coverage and
# limited resource usage.
job:
- { os: ubuntu-22.04 , ocaml-version: 5.2.x , ref: v2.53.5 }
- { os: ubuntu-22.04 , ocaml-version: 4.14.x , ref: v2.53.5 }
- { os: ubuntu-22.04 , ocaml-version: 4.14.x , ref: v2.52.1 , oldmake: true }
- { os: ubuntu-22.04 , ocaml-version: 4.14.x , ref: v2.51.5 , oldmake: true }
- { os: ubuntu-22.04 , ocaml-version: 4.08.x , ref: v2.51.5 , oldmake: true }
- { os: ubuntu-22.04 , ocaml-version: 4.08.x , ref: v2.51.2 , oldmake: true }
- { os: windows-2019 , ocaml-version: ocaml-variants.4.14.0+mingw64c , ref: v2.53.5 }
- { os: windows-2019 , ocaml-version: ocaml-variants.4.14.0+mingw64c , ref: v2.52.1 , oldmake: true }
- { os: windows-2019 , ocaml-version: ocaml-variants.4.08.1+mingw32c , ref: v2.51.5 , oldmake: true }
- { os: macos-12 , ocaml-version: 4.14.x , ref: v2.53.5 }
- { os: macos-12 , ocaml-version: 4.14.x , ref: v2.52.1 , oldmake: true }
- { os: macos-12 , ocaml-version: 4.08.x , ref: v2.51.2 , oldmake: true }
runs-on: ${{ matrix.job.os }}
steps:
- if: contains(matrix.job.os, 'ubuntu')
run: sudo apt-get update
- name: Use OCaml ${{ matrix.job.ocaml-version }}
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: "${{ matrix.job.ocaml-version }}"
opam-pin: false
opam-depext: false
# setup-ocaml can prepare the build environment from unison.opam
# We're not relying on that capability here, to make sure the builds
# also work without using unison.opam
- name: Prepare Cygwin environment (Windows)
if: runner.os == 'Windows'
shell: cmd
run: |
echo %CYGWIN_ROOT_BIN%>> %GITHUB_PATH%
echo %CYGWIN_ROOT_WRAPPERBIN%>> %GITHUB_PATH%
echo SHELLOPTS=igncr>> %GITHUB_ENV%
- name: Checkout HEAD to _new
uses: actions/checkout@v4
with:
path: _new
- run: cd _new && opam exec -- make tui
shell: bash
- name: Checkout ${{ matrix.job.ref }} to _prev
uses: actions/checkout@v4
with:
ref: "${{ matrix.job.ref }}"
path: _prev
- name: "2.51.0: Patch connection header in _prev"
if: contains(matrix.job.ref, '2.51.0')
shell: bash
run: |
# Connection header string was broken in 2.51.0
cd _prev && git apply - <<"EOF"
diff --git a/src/remote.ml b/src/remote.ml
index ddca0d77..7f819eab 100644
--- a/src/remote.ml
+++ b/src/remote.ml
@@ -920,7 +920,7 @@ let connectionHeader =
Scanf.sscanf Sys.ocaml_version "%d.%d.%d" (fun x y z -> (x,y,z)) in
let compiler =
if major < 4
- || major = 4 && minor <= 2
+ || major = 4 && minor < 2
|| major = 4 && minor = 2 && patchlevel <= 1
then "<= 4.01.1"
else ">= 4.01.2"
EOF
- name: "2.51.{2,3}: Patch bugs in _prev"
if: contains(matrix.job.ref, '2.51.2') || contains(matrix.job.ref, '2.51.3')
shell: bash
run: |
cd _prev && git apply - <<"EOF"
diff --git a/src/bytearray_stubs.c b/src/bytearray_stubs.c
index 2b29421a..2850f2d8 100644
--- a/src/bytearray_stubs.c
+++ b/src/bytearray_stubs.c
@@ -10,7 +10,7 @@
CAMLprim value ml_marshal_to_bigarray(value v, value flags)
{
char *buf;
- long len;
+ intnat len;
output_value_to_malloc(v, flags, &buf, &len);
return alloc_bigarray(BIGARRAY_UINT8 | BIGARRAY_C_LAYOUT | BIGARRAY_MANAGED,
1, buf, &len);
diff --git a/src/uicommon.ml b/src/uicommon.ml
index 9fa94cf5..65fc37a5 100644
--- a/src/uicommon.ml
+++ b/src/uicommon.ml
@@ -494,10 +494,11 @@ let promptForRoots getFirstRoot getSecondRoot =
(* ---- *)
let makeTempDir pattern =
- let ic = Unix.open_process_in (Printf.sprintf "(mktemp --tmpdir -d %s.XXXXXX || mktemp -d -t %s) 2>/dev/null" pattern pattern) in
- let path = input_line ic in
- ignore (Unix.close_process_in ic);
- path
+ let path = Filename.temp_file pattern "" in
+ let fspath = System.fspathFromString path in
+ System.unlink fspath; (* Remove file created by [temp_file]... *)
+ System.mkdir fspath 0o755; (* ... and create a dir instead. *)
+ path ^ Filename.dir_sep
(* The first time we load preferences, we also read the command line
arguments; if we re-load prefs (because the user selected a new profile)
EOF
- name: "2.51.2: Patch _prev for mingw compilers"
if: contains(matrix.job.ref, '2.51.2')
shell: bash
run: |
cd _prev && git apply - <<"EOF"
diff --git a/src/Makefile.OCaml b/src/Makefile.OCaml
index 7cefa2ec..95b1bec4 100644
--- a/src/Makefile.OCaml
+++ b/src/Makefile.OCaml
@@ -107,8 +107,8 @@ CAMLFLAGS+=-I system/$(SYSTEM) -I lwt/$(SYSTEM)
ifeq ($(OSARCH),win32)
# Win32 system
EXEC_EXT=.exe
- OBJ_EXT=.obj
- OUTPUT_SEL=/Fo
+ OBJ_EXT=.o
+ OUTPUT_SEL=-o
CWD=.
# Fix suggested by Karl M, Jan 2009:
# "The new flexlink wrapper that OCaml 3.11 uses was gagging on the res
@@ -120,8 +120,6 @@ ifeq ($(OSARCH),win32)
COBJS+=system/system_win_stubs$(OBJ_EXT) lwt/lwt_unix_stubs$(OBJ_EXT)
WINOBJS=system/system_win.cmo
SYSTEM=win
- CLIBS+=-cclib "-link win32rc/unison.res" shell32.lib
- STATICLIBS+=-cclib "-link win32rc/unison.res" shell32.lib
buildexecutable::
@echo Building for Windows
else
EOF
- name: "2.51.2: Patch _prev for newer compilers/OS"
if: contains(matrix.job.ref, '2.51.2')
shell: bash
run: |
cd _prev && git apply - <<"EOF"
diff --git a/src/Makefile.OCaml b/src/Makefile.OCaml
index 7cefa2ec..ffc3ab9e 100644
--- a/src/Makefile.OCaml
+++ b/src/Makefile.OCaml
@@ -180,7 +180,7 @@ else
buildexecutable:: $(NAME)$(EXEC_EXT)
endif
-MINOSXVERSION=10.5
+MINOSXVERSION=10.7
# XCODEFLAGS=-sdk macosx$(MINOSXVERSION)
ifeq ($(OSARCH),osx)
CAMLFLAGS+=-ccopt -mmacosx-version-min=$(MINOSXVERSION)
diff --git a/src/files.ml b/src/files.ml
index 5ff18810..1d1fbcc6 100644
--- a/src/files.ml
+++ b/src/files.ml
@@ -734,7 +734,7 @@ let get_files_in_directory dir =
with End_of_file ->
dirh.System.closedir ()
end;
- Sort.list (<) !files
+ List.sort String.compare !files
let ls dir pattern =
Util.convertUnixErrorsToTransient
diff --git a/src/recon.ml b/src/recon.ml
index 2c619bb8..2412c18e 100644
--- a/src/recon.ml
+++ b/src/recon.ml
@@ -661,8 +661,8 @@ let rec reconcile
(* Sorts the paths so that they will be displayed in order *)
let sortPaths pathUpdatesList =
- Sort.list
- (fun (p1, _) (p2, _) -> Path.compare p1 p2 <= 0)
+ List.sort
+ Path.compare
pathUpdatesList
let rec enterPath p1 p2 t =
diff --git a/src/system/system_generic.ml b/src/system/system_generic.ml
index 453027d0..290851e1 100755
--- a/src/system/system_generic.ml
+++ b/src/system/system_generic.ml
@@ -47,7 +47,7 @@ let open_out_gen = open_out_gen
let chmod = Unix.chmod
let chown = Unix.chown
let utimes = Unix.utimes
-let link = Unix.link
+let link x y = Unix.link x y
let openfile = Unix.openfile
let opendir f =
let h = Unix.opendir f in
EOF
- name: "2.51.0 - 2.52.1: Patch tests in _prev"
if: contains(matrix.job.ref, '2.51') || matrix.job.ref == 'v2.52.0' || matrix.job.ref == 'v2.52.1'
shell: bash
run: |
cd _prev && git apply - <<"EOF"
diff --git a/src/test.ml b/src/test.ml
index 3d480409..60ed014d 100644
--- a/src/test.ml
+++ b/src/test.ml
@@ -542,6 +542,77 @@ let test() =
*)
end;
+ if not bothRootsLocal then
+ begin
+ let localR, remoteR, localRaw =
+ match r1 with
+ | Common.Local, _ -> R1, R2, r1
+ | _ -> R2, R1, r2
+ in
+
+ (* Test RPC function "fingerprintSubfile" *)
+ runtest "RPC: transfer append" [] (fun () ->
+ let prefixLen = 1024 * 1024 + 1 in
+ let len = prefixLen + 31 in
+ let contents = String.make len '.' in
+ let fileName = "bigfile" in
+ let prefixPath = Path.fromString fileName in
+ let (workingDir, _) = Fspath.findWorkingDir (snd localRaw) prefixPath in
+ let prefixName = Path.toString (Os.tempPath ~fresh:false workingDir prefixPath) in
+ put remoteR (Dir [(fileName, File contents)]);
+ put localR (Dir [(prefixName, File (String.sub contents 0 prefixLen))]);
+ sync ();
+ check "1" localR (Dir [(fileName, File contents)]);
+ );
+
+ (* Test RPC function "updateProps" *)
+ runtest "RPC: update props" ["times = true"] (fun () ->
+ let state = [("a", File "x")] in
+ put remoteR (Dir state);
+ put localR (Dir []);
+ sync ();
+ (* Having to sleep here is an unfortunate side-effect of the current
+ Windows limitations-inspired time comparison algorithm which is
+ designed to work on FAT filesystems (2-second granularity). *)
+ Unix.sleep 2;
+ put remoteR (Dir state);
+ sync ();
+ check "1" localR (Dir state);
+ );
+
+ (* Test RPC function "replaceArchive" *)
+ runtest "RPC: replaceArchive" [] (fun () ->
+ put localR (Dir [("n", File "to delete")]);
+ put remoteR (Dir []);
+ sync ();
+ put remoteR (Dir []);
+ sync ();
+ check "1" localR (Dir []);
+ );
+
+ (* Test RPC functions "mkdir" and "setDirProp" *)
+ runtest "RPC: mkdir, setDirProp" [] (fun () ->
+ let state = [("subd", Dir [])] in
+ put localR (Dir state);
+ put remoteR (Dir []);
+ sync ();
+ check "1" remoteR (Dir state);
+ );
+
+ (* Test RPC function "setupTargetPaths" *)
+ runtest "RPC: merge" ["merge = Name ma -> echo x> NEW"; "backupcurr = Name ma"] (fun () ->
+ let result = match Sys.os_type with
+ | "Win32" -> ("ma", File "x\r\n")
+ | _ -> ("ma", File "x\n")
+ in
+ put localR (Dir [("ma", File "a")]);
+ put remoteR (Dir [("ma", File "b")]);
+ sync ();
+ check "1" localR (Dir [result]);
+ check "2" remoteR (Dir [result]);
+ );
+ end;
+
if !failures = 0 then
Util.msg "Success :-)\n"
else
EOF
- name: "2.52.0: Patch _prev for newer compilers"
if: contains(matrix.job.ref, '2.52.0')
shell: bash
run: |
cd _prev && git apply - <<"EOF"
diff --git a/src/system/system_win_stubs.c b/src/system/system_win_stubs.c
index 50ea663f..57940d98 100644
--- a/src/system/system_win_stubs.c
+++ b/src/system/system_win_stubs.c
@@ -373,7 +373,7 @@ typedef enum _FILE_INFORMATION_CLASS {
#include <caml/version.h> /* Available since OCaml 4.02 */
#endif
-#if !defined(OCAML_VERSION) || OCAML_VERSION < 40300
+#if !defined(OCAML_VERSION) || OCAML_VERSION < 40300 || OCAML_VERSION >= 41400
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
EOF
- run: cd _prev && opam exec -- make src UISTYLE=text OSTYPE=$OSTYPE
shell: bash
if: matrix.job.oldmake
- run: cd _prev && opam exec -- make tui
shell: bash
if: ${{ !matrix.job.oldmake }}
# IMPORTANT! These tests do not exercise the entire RPC API. Yet, they
# should work fine as a smoke test.
- name: Run self-tests over RPC - new client to prev server
env:
UNISON: test1
shell: bash
run: |
# Separate backup dir must be set for server instance so that the central
# backup location of both instances doesn't overlap
UNISONBACKUPDIR=./_prev/src/testbak_s _prev/src/unison -socket 55443 &
sleep 1 # Wait for the server to be fully started
_new/src/unison -ui text -selftest testr_c socket://127.0.0.1:55443/testr_s -killserver
- name: Run self-tests over RPC - prev client to new server
env:
UNISON: test2
shell: bash
run: |
# Separate backup dir must be set for server instance so that the central
# backup location of both instances doesn't overlap
UNISONBACKUPDIR=./_new/src/testbak_s _new/src/unison -socket 55443 &
sleep 1 # Wait for the server to be fully started
_prev/src/unison -ui text -selftest testr_c socket://127.0.0.1:55443/testr_s -killserver
## We know the code is ok with various ocaml versions, so this is
## just checking the dune build process. Therefore build each OS
## family just once. Pick a different ocaml version because that's
## better coverage without adding a build.
opam_dune_build:
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-22.04 , ocaml-compiler: 4.12.x }
- { os: macos-14 , ocaml-compiler: 4.14.x }
runs-on: ${{ matrix.job.os }}
steps:
- if: contains(matrix.job.os, 'ubuntu')
run: sudo apt-get update
- name: Checkout code
uses: actions/checkout@v4
- name: Use OCaml ${{ matrix.job.ocaml-compiler }}
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: "${{ matrix.job.ocaml-compiler }}"
- run: opam install . --deps-only
- run: opam exec -- dune build && cp -L ./_build/install/default/bin/unison* ./src/
# - run: opam exec -- make test
bytecode_build:
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-22.04 , ocaml-compiler: 4.14.x }
runs-on: ${{ matrix.job.os }}
steps:
- if: contains(matrix.job.os, 'ubuntu')
run: sudo apt-get update
- name: Checkout code
uses: actions/checkout@v4
- name: Use OCaml ${{ matrix.job.ocaml-compiler }}
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: "${{ matrix.job.ocaml-compiler }}"
opam-pin: false
opam-depext: false
- run: opam exec -- make tui NATIVE=false
- run: opam exec -- make test
build_compat:
if: ${{ !cancelled() }} # Don't fail if 'docs' failed
needs: docs
strategy:
fail-fast: false
matrix:
job:
- { ocaml-version: 4.14.x, publish: true, fnsuffix: -ubuntu-x86_64 }
- { ocaml-version: "ocaml-variants.4.14.2+options,ocaml-option-musl,ocaml-option-static,ocaml-option-flambda", publish: true, fnsuffix: -ubuntu-x86_64-static, static: -static }
- { ocaml-version: 4.12.x }
- { ocaml-version: 4.08.x }
runs-on: ubuntu-latest
container: ubuntu:16.04
steps:
- name: Set up the OS
run: |
apt-get update
apt-get install --assume-yes git make gcc patch wget bzip2 unzip musl-tools
- name: Checkout code
uses: actions/checkout@v3
- name: Use OCaml ${{ matrix.job.ocaml-version }}
uses: ocaml/setup-ocaml@v2.0.19
with:
ocaml-compiler: ${{ matrix.job.ocaml-version }}
opam-disable-sandboxing: true
opam-pin: false
opam-depext: false
- name: Build text UI
env:
LDFLAGS: ${{ matrix.job.static }}
run: |
opam exec -- make
mkdir -p pkg/bin
cp src/unison pkg/bin/
cp src/unison-fsmonitor pkg/bin/
- name: Run local tests
run: opam exec -- make test
- name: Run remote tests
run: |
mkdir localsocket
chmod 700 localsocket
# Separate backup dir must be set for server instance so that the central
# backup location of both instances doesn't overlap
UNISONBACKUPDIR=./src/testbak4 ./src/unison -socket ./localsocket/test.sock &
sleep 1 # Wait for the server to be fully started
test -S ./localsocket/test.sock
./src/unison -ui text -selftest testr3 socket://{./localsocket/test.sock}/testr4 -killserver
- name: Build GUI
if: ${{ !contains(matrix.job.ocaml-version, '-musl') }}
run: |
opam depext --install --verbose --yes lablgtk3 && opam install ocamlfind
opam exec -- make gui
cp src/unison-gui pkg/bin/
- name: Initialize packaging variables
id: vars
run: |
REF_SHAS=$(echo '${{ github.sha }}' | awk '{ print substr($0, 1, 8) }')
unset REF_TAG ; case "${GITHUB_REF}" in refs/tags/*) REF_TAG="${GITHUB_REF#refs/tags/}" ;; esac;
PKG_VER="${REF_TAG:-git_$REF_SHAS}"
PKG_VER="${PKG_VER#v}"
echo PKG_NAME="${PROJECT_NAME}-${PKG_VER}${{ matrix.job.fnsuffix }}.tar.gz" >> $GITHUB_OUTPUT
echo REF_SHAS=${REF_SHAS} >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v3
if: false ## disable by default; only useful for debugging GHA
with:
name: unison-${{ steps.vars.outputs.REF_SHAS }}.ocaml-${{ matrix.job.ocaml-version }}.ubuntu.x86_64
path: pkg/bin/*
- name: Copy user manual
if: matrix.job.publish
continue-on-error: ${{ !(github.ref_type == 'tag' && startsWith(github.ref_name, 'v') && matrix.job.publish) }}
uses: actions/download-artifact@v3
with:
name: unison-docs
path: pkg
- name: Prepare package
if: matrix.job.publish
run: |
strip pkg/bin/*
cp README* pkg/
cp LICENSE* pkg/
cp INSTALL.md pkg/
cp CONTRIBUTING.md pkg/
cp NEWS.md pkg/
- name: Package
if: matrix.job.publish
run: cd pkg && tar czf '${{ steps.vars.outputs.PKG_NAME }}' *
- uses: actions/upload-artifact@v3
if: matrix.job.publish
with:
name: ${{ steps.vars.outputs.PKG_NAME }}___ocaml-${{ matrix.job.ocaml-version }}.ubuntu_compat-publish
path: pkg/${{ steps.vars.outputs.PKG_NAME }}
- name: Publish
if: github.ref_type == 'tag' && startsWith(github.ref_name, 'v') && matrix.job.publish
uses: softprops/action-gh-release@v1
with:
files: pkg/${{ steps.vars.outputs.PKG_NAME }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}