Skip to content

Commit 75a4397

Browse files
TimoWilkenktf
authored andcommitted
Clone SOURCES repos outside container
This lets us always use speed-up options like --filter, even when we're building inside a container. We can also easily start using sapling for this in future by implementing the new SCM methods. This also helps with some annoying authentication-related issues, if running inside --docker, such as in CI. Fixes <https://its.cern.ch/jira/browse/O2-2439>. When this is merged, we can also get rid of the `GIT_*` environment variables used in CI, and stop installing an especially-new Git version in our containers (since that was needed to understand the `GIT_*` variables).
1 parent 54fdf8d commit 75a4397

File tree

9 files changed

+162
-98
lines changed

9 files changed

+162
-98
lines changed

alibuild_helpers/build.py

+9-31
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
from alibuild_helpers.utilities import Hasher
1414
from alibuild_helpers.utilities import yamlDump
1515
from alibuild_helpers.utilities import resolve_tag, resolve_version
16-
from alibuild_helpers.git import git, clone_speedup_options, Git
16+
from alibuild_helpers.git import Git, git
1717
from alibuild_helpers.sl import Sapling
1818
from alibuild_helpers.scm import SCMError
1919
from alibuild_helpers.sync import remote_from_url
2020
import yaml
21-
from alibuild_helpers.workarea import logged_scm, updateReferenceRepoSpec
21+
from alibuild_helpers.workarea import logged_scm, updateReferenceRepoSpec, checkout_sources
2222
from alibuild_helpers.log import ProgressPrint, log_current_package
2323
from glob import glob
2424
from textwrap import dedent
@@ -69,9 +69,7 @@ def update_repo(package, git_prompt):
6969
if exists(os.path.join(specs[package]["source"], ".sl")):
7070
specs[package]["scm"] = Sapling()
7171
updateReferenceRepoSpec(args.referenceSources, package, specs[package],
72-
fetch=args.fetchRepos,
73-
usePartialClone=not args.docker,
74-
allowGitPrompt=git_prompt)
72+
fetch=args.fetchRepos, allowGitPrompt=git_prompt)
7573

7674
# Retrieve git heads
7775
output = logged_scm(specs[package]["scm"], package, args.referenceSources,
@@ -967,10 +965,6 @@ def doBuild(args, parser):
967965
if spec["cachedTarball"] else "No cache tarballs found")
968966

969967
# The actual build script.
970-
referenceStatement = ""
971-
if "reference" in spec:
972-
referenceStatement = "export GIT_REFERENCE=${GIT_REFERENCE_OVERRIDE:-%s}/%s" % (dirname(spec["reference"]), basename(spec["reference"]))
973-
974968
debug("spec = %r", spec)
975969

976970
cmd_raw = ""
@@ -982,22 +976,14 @@ def doBuild(args, parser):
982976
from pkg_resources import resource_string
983977
cmd_raw = resource_string("alibuild_helpers", 'build_template.sh')
984978

985-
source = spec.get("source", "")
986-
# Shortend the commit hash in case it's a real commit hash and not simply
987-
# the tag.
988-
commit_hash = spec["commit_hash"]
989-
if spec["tag"] != spec["commit_hash"]:
990-
commit_hash = spec["commit_hash"][0:10]
991-
992-
# Split the source in two parts, sourceDir and sourceName. This is done so
993-
# that when we use Docker we can replace sourceDir with the correct
994-
# container path, if required. No changes for what concerns the standard
995-
# bash builds, though.
996979
if args.docker:
997980
cachedTarball = re.sub("^" + workDir, "/sw", spec["cachedTarball"])
998981
else:
999982
cachedTarball = spec["cachedTarball"]
1000983

984+
if not cachedTarball:
985+
checkout_sources(spec, workDir, args.referenceSources, args.docker)
986+
1001987
scriptDir = join(workDir, "SPECS", args.architecture, spec["package"],
1002988
spec["version"] + "-" + spec["revision"])
1003989

@@ -1011,11 +997,6 @@ def doBuild(args, parser):
1011997
"workDir": workDir,
1012998
"configDir": abspath(args.configDir),
1013999
"incremental_recipe": spec.get("incremental_recipe", ":"),
1014-
"sourceDir": (dirname(source) + "/") if source else "",
1015-
"sourceName": basename(source) if source else "",
1016-
"referenceStatement": referenceStatement,
1017-
"gitOptionsStatement": "" if args.docker else
1018-
"export GIT_CLONE_SPEEDUP=" + quote(" ".join(clone_speedup_options())),
10191000
"requires": " ".join(spec["requires"]),
10201001
"build_requires": " ".join(spec["build_requires"]),
10211002
"runtime_requires": " ".join(spec["runtime_requires"]),
@@ -1028,14 +1009,14 @@ def doBuild(args, parser):
10281009
("BUILD_REQUIRES", " ".join(spec["build_requires"])),
10291010
("CACHED_TARBALL", cachedTarball),
10301011
("CAN_DELETE", args.aggressiveCleanup and "1" or ""),
1031-
("COMMIT_HASH", commit_hash),
1012+
# Shorten the commit hash if it's a real commit hash and not simply the tag.
1013+
("COMMIT_HASH", spec["tag"] if spec["tag"] == spec["commit_hash"] else spec["commit_hash"][:10]),
10321014
("DEPS_HASH", spec.get("deps_hash", "")),
10331015
("DEVEL_HASH", spec.get("devel_hash", "")),
10341016
("DEVEL_PREFIX", develPrefix),
10351017
("BUILD_FAMILY", spec["build_family"]),
10361018
("GIT_COMMITTER_NAME", "unknown"),
10371019
("GIT_COMMITTER_EMAIL", "unknown"),
1038-
("GIT_TAG", spec["tag"]),
10391020
("INCREMENTAL_BUILD_HASH", spec.get("incremental_hash", "0")),
10401021
("JOBS", str(args.jobs)),
10411022
("PKGHASH", spec["hash"]),
@@ -1048,7 +1029,6 @@ def doBuild(args, parser):
10481029
("FULL_RUNTIME_REQUIRES", " ".join(spec["full_runtime_requires"])),
10491030
("FULL_BUILD_REQUIRES", " ".join(spec["full_build_requires"])),
10501031
("FULL_REQUIRES", " ".join(spec["full_requires"])),
1051-
("WRITE_REPO", spec.get("write_repo", source)),
10521032
]
10531033
# Add the extra environment as passed from the command line.
10541034
buildEnvironment += [e.partition('=')[::2] for e in args.environment]
@@ -1059,15 +1039,13 @@ def doBuild(args, parser):
10591039
build_command = (
10601040
"docker run --rm --entrypoint= --user $(id -u):$(id -g) "
10611041
"-v {workdir}:/sw -v {scriptDir}/build.sh:/build.sh:ro "
1062-
"-e GIT_REFERENCE_OVERRIDE=/mirror -e WORK_DIR_OVERRIDE=/sw "
10631042
"{mirrorVolume} {develVolumes} {additionalEnv} {additionalVolumes} "
1064-
"{overrideSource} {extraArgs} {image} bash -ex /build.sh"
1043+
"-e WORK_DIR_OVERRIDE=/sw {extraArgs} {image} bash -ex /build.sh"
10651044
).format(
10661045
image=quote(args.dockerImage),
10671046
workdir=quote(abspath(args.workDir)),
10681047
scriptDir=quote(scriptDir),
10691048
extraArgs=" ".join(map(quote, args.docker_extra_args)),
1070-
overrideSource="-e SOURCE0_DIR_OVERRIDE=/" if source.startswith("/") else "",
10711049
additionalEnv=" ".join(
10721050
"-e {}={}".format(var, quote(value)) for var, value in buildEnvironment),
10731051
# Used e.g. by O2DPG-sim-tests to find the O2DPG repository.

alibuild_helpers/build_template.sh

+4-43
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ export PATH=$WORK_DIR/wrapper-scripts:$PATH
2727
# - DEPS_HASH
2828
# - DEVEL_HASH
2929
# - DEVEL_PREFIX
30-
# - GIT_TAG
3130
# - INCREMENTAL_BUILD_HASH
3231
# - JOBS
3332
# - PKGHASH
@@ -36,36 +35,27 @@ export PATH=$WORK_DIR/wrapper-scripts:$PATH
3635
# - PKGVERSION
3736
# - REQUIRES
3837
# - RUNTIME_REQUIRES
39-
# - WRITE_REPO
4038

4139
export PKG_NAME="$PKGNAME"
4240
export PKG_VERSION="$PKGVERSION"
4341
export PKG_BUILDNUM="$PKGREVISION"
4442

45-
export SOURCE0="${SOURCE0_DIR_OVERRIDE:-%(sourceDir)s}%(sourceName)s"
4643
export PKGPATH=${ARCHITECTURE}/${PKGNAME}/${PKGVERSION}-${PKGREVISION}
4744
mkdir -p "$WORK_DIR/BUILD" "$WORK_DIR/SOURCES" "$WORK_DIR/TARS" \
4845
"$WORK_DIR/SPECS" "$WORK_DIR/INSTALLROOT"
4946
export BUILDROOT="$WORK_DIR/BUILD/$PKGHASH"
5047

51-
# In case the repository is local, it means we are in development mode, so we
52-
# install directly in $WORK_DIR/$PKGPATH so that we can do make install
53-
# directly into BUILD/$PKGPATH and have changes being propagated.
54-
if [ "${SOURCE0:0:1}" == "/" ]; then
48+
# If we are in development mode, then install directly in $WORK_DIR/$PKGPATH,
49+
# so that we can do "make install" directly into BUILD/$PKGPATH and have
50+
# changes being propagated.
51+
if [ -n "$DEVEL_HASH" ]; then
5552
export INSTALLROOT="$WORK_DIR/$PKGPATH"
5653
else
5754
export INSTALLROOT="$WORK_DIR/INSTALLROOT/$PKGHASH/$PKGPATH"
5855
fi
5956
export SOURCEDIR="$WORK_DIR/SOURCES/$PKGNAME/$PKGVERSION/$COMMIT_HASH"
6057
export BUILDDIR="$BUILDROOT/$PKGNAME"
6158

62-
SHORT_TAG=${GIT_TAG:0:10}
63-
mkdir -p $(dirname $SOURCEDIR)
64-
if [[ ${COMMIT_HASH} != ${GIT_TAG} && "${SHORT_TAG:-0}" != ${COMMIT_HASH} ]]; then
65-
GIT_TAG_DIR=${GIT_TAG:-0}
66-
GIT_TAG_DIR=${GIT_TAG_DIR//\//_}
67-
ln -snf ${COMMIT_HASH} "$WORK_DIR/SOURCES/$PKGNAME/$PKGVERSION/${GIT_TAG_DIR}"
68-
fi
6959
rm -fr "$WORK_DIR/INSTALLROOT/$PKGHASH"
7060
# We remove the build directory only if we are not in incremental mode.
7161
if [[ "$INCREMENTAL_BUILD_HASH" == 0 ]] && ! rm -rf "$BUILDROOT"; then
@@ -114,35 +104,6 @@ if [[ $DEVEL_PREFIX ]]; then
114104
ln -snf $PKGHASH $WORK_DIR/BUILD/$PKGNAME-latest-$DEVEL_PREFIX
115105
fi
116106

117-
# Reference statements
118-
%(referenceStatement)s
119-
%(gitOptionsStatement)s
120-
121-
if [ -z "$CACHED_TARBALL" ]; then
122-
case "$SOURCE0" in
123-
'') # SOURCE0 is empty, so just create an empty SOURCEDIR.
124-
mkdir -p "$SOURCEDIR" ;;
125-
/*) # SOURCE0 is an absolute path, so just make a symlink there.
126-
ln -snf "$SOURCE0" "$SOURCEDIR" ;;
127-
*) # SOURCE0 is a relative path or URL, so clone/checkout the git repo from there.
128-
if cd "$SOURCEDIR" 2>/dev/null; then
129-
# Folder is already present, but check that it is the right tag
130-
if ! git checkout -f "$GIT_TAG"; then
131-
# If we can't find the tag, it might be new. Fetch tags and try again.
132-
git fetch -f "$SOURCE0" "refs/tags/$GIT_TAG:refs/tags/$GIT_TAG"
133-
git checkout -f "$GIT_TAG"
134-
fi
135-
else
136-
# In case there is a stale link / file, for whatever reason.
137-
rm -rf "$SOURCEDIR"
138-
git clone -n $GIT_CLONE_SPEEDUP ${GIT_REFERENCE:+--reference "$GIT_REFERENCE"} "$SOURCE0" "$SOURCEDIR"
139-
cd "$SOURCEDIR"
140-
git remote set-url --push origin "$WRITE_REPO"
141-
git checkout -f "$GIT_TAG"
142-
fi ;;
143-
esac
144-
fi
145-
146107
cd "$BUILDDIR"
147108

148109
# Actual build script, as defined in the recipe

alibuild_helpers/git.py

+27-3
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,58 @@ def clone_speedup_options():
1818

1919
class Git(SCM):
2020
name = "Git"
21+
2122
def checkedOutCommitName(self, directory):
2223
return git(("rev-parse", "HEAD"), directory)
24+
2325
def branchOrRef(self, directory):
2426
out = git(("rev-parse", "--abbrev-ref", "HEAD"), directory=directory)
2527
if out == "HEAD":
2628
out = git(("rev-parse", "HEAD"), directory)[:10]
2729
return out
30+
2831
def exec(self, *args, **kwargs):
2932
return git(*args, **kwargs)
33+
3034
def parseRefs(self, output):
3135
return {
3236
git_ref: git_hash for git_hash, sep, git_ref
3337
in (line.partition("\t") for line in output.splitlines()) if sep
3438
}
39+
3540
def listRefsCmd(self, repository):
3641
return ["ls-remote", "--heads", "--tags", repository]
37-
def cloneCmd(self, source, referenceRepo, usePartialClone):
42+
43+
def cloneReferenceCmd(self, source, referenceRepo, usePartialClone):
3844
cmd = ["clone", "--bare", source, referenceRepo]
3945
if usePartialClone:
4046
cmd.extend(clone_speedup_options())
4147
return cmd
42-
def fetchCmd(self, source):
43-
return ["fetch", "-f", "--tags", source, "+refs/heads/*:refs/heads/*"]
48+
49+
def cloneSourceCmd(self, source, destination, referenceRepo, usePartialClone):
50+
cmd = ["clone", "-n", source, destination]
51+
if referenceRepo:
52+
cmd.extend(["--reference", referenceRepo])
53+
if usePartialClone:
54+
cmd.extend(clone_speedup_options())
55+
return cmd
56+
57+
def checkoutCmd(self, ref):
58+
return ["checkout", "-f", ref]
59+
60+
def fetchCmd(self, source, *refs):
61+
return ["fetch", "-f", source, *refs]
62+
63+
def setWriteUrlCmd(self, url):
64+
return ["remote", "set-url", "--push", "origin", url]
65+
4466
def diffCmd(self, directory):
4567
return "cd %s && git diff -r HEAD && git status --porcelain" % directory
68+
4669
def checkUntracked(self, line):
4770
return line.startswith("?? ")
4871

72+
4973
def git(args, directory=".", check=True, prompt=True):
5074
debug("Executing git %s (in directory %s)", " ".join(args), directory)
5175
# We can't use git --git-dir=%s/.git or git -C %s here as the former requires

alibuild_helpers/init.py

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def doInit(args):
6666

6767
for p in pkgs:
6868
spec = specs.get(p["name"])
69+
spec["is_devel_pkg"] = False
6970
spec["scm"] = Git()
7071
dieOnError(spec is None, "cannot find recipe for package %s" % p["name"])
7172
dest = join(args.develPrefix, spec["package"])

alibuild_helpers/scm.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ def parseRefs(self, output):
1515
raise NotImplementedError
1616
def exec(self, *args, **kwargs):
1717
raise NotImplementedError
18-
def cloneCmd(self, spec, referenceRepo, usePartialClone):
18+
def checkoutCmd(self, tag):
19+
raise NotImplementedError
20+
def fetchCmd(self, remote, *refs):
21+
raise NotImplementedError
22+
def cloneReferenceCmd(self, spec, referenceRepo, usePartialClone):
23+
raise NotImplementedError
24+
def cloneSourceCmd(self, spec, referenceRepo, usePartialClone):
25+
raise NotImplementedError
26+
def setWriteUrlCmd(self, url):
1927
raise NotImplementedError
2028
def diffCmd(self, directory):
2129
raise NotImplementedError

alibuild_helpers/sl.py

+9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
SL_COMMAND_TIMEOUT_SEC = 120
77
"""How many seconds to let any sl command execute before being terminated."""
88

9+
910
# Sapling is a novel SCM by Meta (i.e. Facebook) that is fully compatible with
1011
# git, but has a different command line interface. Among the reasons why it's
1112
# worth suporting it is the ability to handle unnamed branches, the ability to
@@ -14,26 +15,34 @@
1415
# command line from each commit of a branch.
1516
class Sapling(SCM):
1617
name = "Sapling"
18+
1719
def checkedOutCommitName(self, directory):
1820
return sapling(("whereami", ), directory)
21+
1922
def branchOrRef(self, directory):
2023
# Format is <hash>[+] <branch>
2124
identity = sapling(("identify", ), directory)
2225
return identity.split(" ")[-1]
26+
2327
def exec(self, *args, **kwargs):
2428
return sapling(*args, **kwargs)
29+
2530
def parseRefs(self, output):
2631
return {
2732
sl_ref: sl_hash for sl_ref, sep, sl_hash
2833
in (line.partition("\t") for line in output.splitlines()) if sep
2934
}
35+
3036
def listRefsCmd(self, repository):
3137
return ["bookmark", "--list", "--remote", "-R", repository]
38+
3239
def diffCmd(self, directory):
3340
return "cd %s && sl diff && sl status" % directory
41+
3442
def checkUntracked(self, line):
3543
return line.startswith("? ")
3644

45+
3746
def sapling(args, directory=".", check=True, prompt=True):
3847
debug("Executing sl %s (in directory %s)", " ".join(args), directory)
3948
# We can't use git --git-dir=%s/.git or git -C %s here as the former requires

0 commit comments

Comments
 (0)