Skip to content

Commit 8997bd1

Browse files
dschovdye
authored andcommitted
Merge pull request #371 from dscho/run-scalar-functional-tests-and-fix-built-in-fsmonitor
Fix the built-in FSMonitor, and run Scalar's Functional Tests as part of the automated builds
2 parents 0604897 + bd8bbc3 commit 8997bd1

File tree

23 files changed

+1774
-84
lines changed

23 files changed

+1774
-84
lines changed
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
name: Scalar Functional Tests
2+
3+
env:
4+
SCALAR_REPOSITORY: microsoft/scalar
5+
SCALAR_REF: main
6+
DEBUG_WITH_TMATE: false
7+
SCALAR_TEST_SKIP_VSTS_INFO: true
8+
9+
on:
10+
push:
11+
branches: [ vfs-*, tentative/vfs-* ]
12+
pull_request:
13+
branches: [ vfs-*, features/* ]
14+
15+
jobs:
16+
scalar:
17+
name: "Scalar Functional Tests"
18+
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
# Order by runtime (in descending order)
23+
os: [windows-2019, macos-11, ubuntu-20.04, ubuntu-22.04]
24+
# Scalar.NET used to be tested using `features: [false, experimental]`
25+
# But currently, Scalar/C ignores `feature.scalar` altogether, so let's
26+
# save some electrons and run only one of them...
27+
features: [ignored]
28+
exclude:
29+
# The built-in FSMonitor is not (yet) supported on Linux
30+
- os: ubuntu-20.04
31+
features: experimental
32+
- os: ubuntu-22.04
33+
features: experimental
34+
runs-on: ${{ matrix.os }}
35+
36+
env:
37+
BUILD_FRAGMENT: bin/Release/netcoreapp3.1
38+
GIT_FORCE_UNTRACKED_CACHE: 1
39+
40+
steps:
41+
- name: Check out Git's source code
42+
uses: actions/checkout@v3
43+
44+
- name: Setup build tools on Windows
45+
if: runner.os == 'Windows'
46+
uses: git-for-windows/setup-git-for-windows-sdk@v1
47+
48+
- name: Provide a minimal `install` on Windows
49+
if: runner.os == 'Windows'
50+
shell: bash
51+
run: |
52+
test -x /usr/bin/install ||
53+
tr % '\t' >/usr/bin/install <<-\EOF
54+
#!/bin/sh
55+
56+
cmd=cp
57+
while test $# != 0
58+
do
59+
%case "$1" in
60+
%-d) cmd="mkdir -p";;
61+
%-m) shift;; # ignore mode
62+
%*) break;;
63+
%esac
64+
%shift
65+
done
66+
67+
exec $cmd "$@"
68+
EOF
69+
70+
- name: Install build dependencies for Git (Linux)
71+
if: runner.os == 'Linux'
72+
run: |
73+
sudo apt-get update
74+
sudo apt-get -q -y install libssl-dev libcurl4-openssl-dev gettext
75+
76+
- name: Build and install Git
77+
shell: bash
78+
env:
79+
NO_TCLTK: Yup
80+
run: |
81+
# We do require a VFS version
82+
def_ver="$(sed -n 's/DEF_VER=\(.*vfs.*\)/\1/p' GIT-VERSION-GEN)"
83+
test -n "$def_ver"
84+
85+
# Ensure that `git version` reflects DEF_VER
86+
case "$(git describe --match "v[0-9]*vfs*" HEAD)" in
87+
${def_ver%%.vfs.*}.vfs.*) ;; # okay, we can use this
88+
*) git -c user.name=ci -c user.email=ci@github tag -m for-testing ${def_ver}.NNN.g$(git rev-parse --short HEAD);;
89+
esac
90+
91+
SUDO=
92+
extra=
93+
case "${{ runner.os }}" in
94+
Windows)
95+
extra=DESTDIR=/c/Progra~1/Git
96+
cygpath -aw "/c/Program Files/Git/cmd" >>$GITHUB_PATH
97+
;;
98+
Linux)
99+
SUDO=sudo
100+
extra=prefix=/usr
101+
;;
102+
macOS)
103+
SUDO=sudo
104+
extra=prefix=/usr/local
105+
;;
106+
esac
107+
108+
$SUDO make -j5 $extra install
109+
110+
- name: Ensure that we use the built Git and Scalar
111+
shell: bash
112+
run: |
113+
type -p git
114+
git version
115+
case "$(git version)" in *.vfs.*) echo Good;; *) exit 1;; esac
116+
type -p scalar
117+
scalar version
118+
case "$(scalar version 2>&1)" in *.vfs.*) echo Good;; *) exit 1;; esac
119+
120+
- name: Check out Scalar's source code
121+
uses: actions/checkout@v3
122+
with:
123+
fetch-depth: 0 # Indicate full history so Nerdbank.GitVersioning works.
124+
path: scalar
125+
repository: ${{ env.SCALAR_REPOSITORY }}
126+
ref: ${{ env.SCALAR_REF }}
127+
128+
- name: Setup .NET Core
129+
uses: actions/setup-dotnet@v3
130+
with:
131+
dotnet-version: '3.1.x'
132+
133+
- name: Install dependencies
134+
run: dotnet restore
135+
working-directory: scalar
136+
env:
137+
DOTNET_NOLOGO: 1
138+
139+
- name: Build
140+
working-directory: scalar
141+
run: dotnet build --configuration Release --no-restore -p:UseAppHost=true # Force generation of executable on macOS.
142+
143+
- name: Setup platform (Linux)
144+
if: runner.os == 'Linux'
145+
run: |
146+
echo "BUILD_PLATFORM=${{ runner.os }}" >>$GITHUB_ENV
147+
echo "TRACE2_BASENAME=Trace2.${{ github.run_id }}__${{ github.run_number }}__${{ matrix.os }}__${{ matrix.features }}" >>$GITHUB_ENV
148+
149+
- name: Setup platform (Mac)
150+
if: runner.os == 'macOS'
151+
run: |
152+
echo 'BUILD_PLATFORM=Mac' >>$GITHUB_ENV
153+
echo "TRACE2_BASENAME=Trace2.${{ github.run_id }}__${{ github.run_number }}__${{ matrix.os }}__${{ matrix.features }}" >>$GITHUB_ENV
154+
155+
- name: Setup platform (Windows)
156+
if: runner.os == 'Windows'
157+
run: |
158+
echo "BUILD_PLATFORM=${{ runner.os }}" >>$env:GITHUB_ENV
159+
echo 'BUILD_FILE_EXT=.exe' >>$env:GITHUB_ENV
160+
echo "TRACE2_BASENAME=Trace2.${{ github.run_id }}__${{ github.run_number }}__${{ matrix.os }}__${{ matrix.features }}" >>$env:GITHUB_ENV
161+
162+
- name: Configure feature.scalar
163+
run: git config --global feature.scalar ${{ matrix.features }}
164+
165+
- id: functional_test
166+
name: Functional test
167+
timeout-minutes: 60
168+
working-directory: scalar
169+
shell: bash
170+
run: |
171+
export GIT_TRACE2_EVENT="$PWD/$TRACE2_BASENAME/Event"
172+
export GIT_TRACE2_PERF="$PWD/$TRACE2_BASENAME/Perf"
173+
export GIT_TRACE2_EVENT_BRIEF=true
174+
export GIT_TRACE2_PERF_BRIEF=true
175+
mkdir -p "$TRACE2_BASENAME"
176+
mkdir -p "$TRACE2_BASENAME/Event"
177+
mkdir -p "$TRACE2_BASENAME/Perf"
178+
git version --build-options
179+
cd ../out
180+
Scalar.FunctionalTests/$BUILD_FRAGMENT/Scalar.FunctionalTests$BUILD_FILE_EXT --test-scalar-on-path --test-git-on-path --timeout=300000 --full-suite
181+
182+
- name: Force-stop FSMonitor daemons and Git processes (Windows)
183+
if: runner.os == 'Windows' && (success() || failure())
184+
shell: bash
185+
run: |
186+
set -x
187+
wmic process get CommandLine,ExecutablePath,HandleCount,Name,ParentProcessID,ProcessID
188+
wmic process where "CommandLine Like '%fsmonitor--daemon %run'" delete
189+
wmic process where "ExecutablePath Like '%git.exe'" delete
190+
191+
- id: trace2_zip_unix
192+
if: runner.os != 'Windows' && ( success() || failure() ) && ( steps.functional_test.conclusion == 'success' || steps.functional_test.conclusion == 'failure' )
193+
name: Zip Trace2 Logs (Unix)
194+
shell: bash
195+
working-directory: scalar
196+
run: zip -q -r $TRACE2_BASENAME.zip $TRACE2_BASENAME/
197+
198+
- id: trace2_zip_windows
199+
if: runner.os == 'Windows' && ( success() || failure() ) && ( steps.functional_test.conclusion == 'success' || steps.functional_test.conclusion == 'failure' )
200+
name: Zip Trace2 Logs (Windows)
201+
working-directory: scalar
202+
run: Compress-Archive -DestinationPath ${{ env.TRACE2_BASENAME }}.zip -Path ${{ env.TRACE2_BASENAME }}
203+
204+
- name: Archive Trace2 Logs
205+
if: ( success() || failure() ) && ( steps.trace2_zip_unix.conclusion == 'success' || steps.trace2_zip_windows.conclusion == 'success' )
206+
uses: actions/upload-artifact@v3
207+
with:
208+
name: ${{ env.TRACE2_BASENAME }}.zip
209+
path: scalar/${{ env.TRACE2_BASENAME }}.zip
210+
retention-days: 3
211+
212+
# The GitHub Action `action-tmate` allows developers to connect to the running agent
213+
# using SSH (it will be a `tmux` session; on Windows agents it will be inside the MSYS2
214+
# environment in `C:\msys64`, therefore it can be slightly tricky to interact with
215+
# Git for Windows, which runs a slightly incompatible MSYS2 runtime).
216+
- name: action-tmate
217+
if: env.DEBUG_WITH_TMATE == 'true' && failure()
218+
uses: mxschmitt/action-tmate@v3
219+
with:
220+
limit-access-to-actor: true

Documentation/config/core.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,3 +806,12 @@ core.abbrev::
806806
If set to "no", no abbreviation is made and the object names
807807
are shown in their full length.
808808
The minimum length is 4.
809+
810+
core.configWriteLockTimeoutMS::
811+
When processes try to write to the config concurrently, it is likely
812+
that one process "wins" and the other process(es) fail to lock the
813+
config file. By configuring a timeout larger than zero, Git can be
814+
told to try to lock the config again a couple times within the
815+
specified timeout. If the timeout is configure to zero (which is the
816+
default), Git will fail immediately when the config is already
817+
locked.

Documentation/scalar.txt

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@ scalar - A tool for managing large Git repositories
88
SYNOPSIS
99
--------
1010
[verse]
11-
scalar clone [--single-branch] [--branch <main-branch>] [--full-clone] <url> [<enlistment>]
11+
scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]
12+
[--local-cache-path <path>] [--cache-server-url <url>] [--[no-]src]
13+
<url> [<enlistment>]
1214
scalar list
1315
scalar register [<enlistment>]
1416
scalar unregister [<enlistment>]
1517
scalar run ( all | config | commit-graph | fetch | loose-objects | pack-files ) [<enlistment>]
1618
scalar reconfigure [ --all | <enlistment> ]
1719
scalar diagnose [<enlistment>]
1820
scalar delete <enlistment>
21+
scalar cache-server ( --get | --set <url> | --list [<remote>] ) [<enlistment>]
1922

2023
DESCRIPTION
2124
-----------
@@ -80,10 +83,24 @@ remote-tracking branch for the branch this option was used for the initial
8083
cloning. If the HEAD at the remote did not point at any branch when
8184
`--single-branch` clone was made, no remote-tracking branch is created.
8285

86+
--no-src::
87+
Skip adding a `src` directory within the target enlistment.
88+
8389
--[no-]full-clone::
8490
A sparse-checkout is initialized by default. This behavior can be
8591
turned off via `--full-clone`.
8692

93+
--local-cache-path <path>::
94+
Override the path to the local cache root directory; Pre-fetched objects
95+
are stored into a repository-dependent subdirectory of that path.
96+
+
97+
The default is `<drive>:\.scalarCache` on Windows (on the same drive as the
98+
clone), and `~/.scalarCache` on macOS.
99+
100+
--cache-server-url <url>::
101+
Retrieve missing objects from the specified remote, which is expected to
102+
understand the GVFS protocol.
103+
87104
List
88105
~~~~
89106

@@ -157,6 +174,27 @@ delete <enlistment>::
157174
This subcommand lets you delete an existing Scalar enlistment from your
158175
local file system, unregistering the repository.
159176

177+
Cache-server
178+
~~~~~~~~~~~~
179+
180+
cache-server ( --get | --set <url> | --list [<remote>] ) [<enlistment>]::
181+
This command lets you query or set the GVFS-enabled cache server used
182+
to fetch missing objects.
183+
184+
--get::
185+
This is the default command mode: query the currently-configured cache
186+
server URL, if any.
187+
188+
--list::
189+
Access the `gvfs/info` endpoint of the specified remote (default:
190+
`origin`) to figure out which cache servers are available, if any.
191+
+
192+
In contrast to the `--get` command mode (which only accesses the local
193+
repository), this command mode triggers a request via the network that
194+
potentially requires authentication. If authentication is required, the
195+
configured credential helper is employed (see linkgit:git-credential[1]
196+
for details).
197+
160198
SEE ALSO
161199
--------
162200
linkgit:git-clone[1], linkgit:git-maintenance[1].

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2736,6 +2736,7 @@ GIT_OBJS += git.o
27362736
.PHONY: git-objs
27372737
git-objs: $(GIT_OBJS)
27382738

2739+
SCALAR_OBJS := json-parser.o
27392740
SCALAR_OBJS += scalar.o
27402741
.PHONY: scalar-objs
27412742
scalar-objs: $(SCALAR_OBJS)
@@ -2884,7 +2885,7 @@ $(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o $(LAZYLOAD_LIBCURL_OB
28842885
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
28852886
$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
28862887

2887-
scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
2888+
scalar$X: $(SCALAR_OBJS) GIT-LDFLAGS $(GITLIBS)
28882889
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
28892890
$(filter %.o,$^) $(LIBS)
28902891

abspath.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ int is_directory(const char *path)
1414
}
1515

1616
/* removes the last path component from 'path' except if 'path' is root */
17-
static void strip_last_component(struct strbuf *path)
17+
void strip_last_path_component(struct strbuf *path)
1818
{
1919
size_t offset = offset_1st_component(path->buf);
2020
size_t len = path->len;
@@ -119,7 +119,7 @@ static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
119119
continue; /* '.' component */
120120
} else if (next.len == 2 && !strcmp(next.buf, "..")) {
121121
/* '..' component; strip the last path component */
122-
strip_last_component(resolved);
122+
strip_last_path_component(resolved);
123123
continue;
124124
}
125125

@@ -171,7 +171,7 @@ static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
171171
* strip off the last component since it will
172172
* be replaced with the contents of the symlink
173173
*/
174-
strip_last_component(resolved);
174+
strip_last_path_component(resolved);
175175
}
176176

177177
/*

abspath.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ char *real_pathdup(const char *path, int die_on_error);
1010
const char *absolute_path(const char *path);
1111
char *absolute_pathdup(const char *path);
1212

13+
/**
14+
* Remove the last path component from 'path' except if 'path' is root.
15+
*/
16+
void strip_last_path_component(struct strbuf *path);
17+
1318
/*
1419
* Concatenate "prefix" (if len is non-zero) and "path", with no
1520
* connecting characters (so "prefix" should end with a "/").

config.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3465,6 +3465,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
34653465
const char *value_pattern,
34663466
unsigned flags)
34673467
{
3468+
static unsigned long timeout_ms = ULONG_MAX;
34683469
int fd = -1, in_fd = -1;
34693470
int ret;
34703471
struct lock_file lock = LOCK_INIT;
@@ -3485,11 +3486,16 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
34853486
if (!config_filename)
34863487
config_filename = filename_buf = git_pathdup("config");
34873488

3489+
if ((long)timeout_ms < 0 &&
3490+
git_config_get_ulong("core.configWriteLockTimeoutMS", &timeout_ms))
3491+
timeout_ms = 0;
3492+
34883493
/*
34893494
* The lock serves a purpose in addition to locking: the new
34903495
* contents of .git/config will be written into it.
34913496
*/
3492-
fd = hold_lock_file_for_update(&lock, config_filename, 0);
3497+
fd = hold_lock_file_for_update_timeout(&lock, config_filename, 0,
3498+
timeout_ms);
34933499
if (fd < 0) {
34943500
error_errno(_("could not lock config file %s"), config_filename);
34953501
ret = CONFIG_NO_LOCK;

contrib/buildsystems/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,7 @@ target_link_libraries(git-sh-i18n--envsubst common-main)
797797
add_executable(git-shell ${CMAKE_SOURCE_DIR}/shell.c)
798798
target_link_libraries(git-shell common-main)
799799

800-
add_executable(scalar ${CMAKE_SOURCE_DIR}/scalar.c)
800+
add_executable(scalar ${CMAKE_SOURCE_DIR}/scalar.c ${CMAKE_SOURCE_DIR}/json-parser.c)
801801
target_link_libraries(scalar common-main)
802802

803803
if(CURL_FOUND)

0 commit comments

Comments
 (0)