GIT_LFS_SHA ?= $(shell env -u GIT_TRACE git rev-parse --short HEAD)
VERSION ?= $(shell env -u GIT_TRACE git describe HEAD)
PREFIX ?= $(patsubst v%,git-lfs-%,$(VERSION))
GO ?= go
export GOTOOLCHAIN = local
GO_TEST_EXTRA_ARGS =
BUILTIN_LD_FLAGS =
ifneq ("$(VENDOR)","")
BUILTIN_LD_FLAGS += -X 'github.com/git-lfs/git-lfs/v3/config.Vendor=$(VENDOR)'
endif
BUILTIN_LD_FLAGS += -X github.com/git-lfs/git-lfs/v3/config.GitCommit=$(GIT_LFS_SHA)
ifneq ("$(DWARF)","YesPlease")
BUILTIN_LD_FLAGS += -s
BUILTIN_LD_FLAGS += -w
endif
ifdef LDFLAGS
EXTRA_LD_FLAGS ?= -extldflags ${LDFLAGS}
endif
LD_FLAGS = $(BUILTIN_LD_FLAGS) $(EXTRA_LD_FLAGS)
BUILTIN_GC_FLAGS =
EXTRA_GC_FLAGS =
GC_FLAGS = $(BUILTIN_GC_FLAGS) $(EXTRA_GC_FLAGS)
RONN ?= ronn
RONN_EXTRA_ARGS ?=
ASCIIDOCTOR ?= asciidoctor
ASCIIDOCTOR_EXTRA_ARGS ?= -a reproducible
GREP ?= grep
XARGS ?= xargs
GOIMPORTS ?= goimports
GOIMPORTS_EXTRA_OPTS ?= -w -l
TAR ?= tar
TAR_XFORM_ARG ?= $(shell $(TAR) --version | grep -q 'GNU tar' && echo '--xform' || echo '-s')
TAR_XFORM_CMD ?= $(shell $(TAR) --version | grep -q 'GNU tar' && echo 's')
CERT_SHA1 ?= 30a531ed3a246d3d07a4273adaef31552bf6473a
CERT_FILE ?=
CERT_PASS ?=
ifneq ("$(CERT_FILE)$(CERT_PASS)","")
CERT_ARGS ?= -f "$(CERT_FILE)" -p "$(CERT_PASS)"
else
CERT_ARGS ?= -sha1 $(CERT_SHA1)
endif
DARWIN_CERT_ID ?=
DARWIN_KEYCHAIN_ID ?= CI.keychain
export DARWIN_DEV_USER DARWIN_DEV_PASS DARWIN_DEV_TEAM
SOURCES = $(shell find . -type f -name '*.go' | grep -v vendor)
MSGFMT ?= msgfmt
PO = $(wildcard po/*.po)
MO = $(patsubst po/%.po,po/build/%.mo,$(PO))
XGOTEXT ?= xgotext
CODESIGN ?= codesign
SIGNTOOL ?= signtool.exe
FORCE_LOCALIZE ?=
ifndef PKGS
PKGS =
PKGS += commands
PKGS += config
PKGS += creds
PKGS += errors
PKGS += filepathfilter
PKGS += fs
PKGS += git
PKGS += git/gitattr
PKGS += git/githistory
PKGS += git
PKGS += lfs
PKGS += lfsapi
PKGS += lfshttp
PKGS += locking
PKGS += ssh
PKGS += subprocess
PKGS += tasklog
PKGS += tools
PKGS += tools/humanize
PKGS += tools/kv
PKGS += tr
PKGS += tq
endif
ifeq ($(OS),Windows_NT)
X ?= .exe
BUILD_MAIN ?=
BSDTAR ?= C:/Windows/system32/tar.exe
else
X ?=
BUILD_MAIN ?= ./git-lfs.go
BSDTAR ?= $(shell $(TAR) --version | grep -q 'GNU tar' && echo bsdtar || echo $(TAR))
endif
BUILD = GOOS=$(1) GOARCH=$(2) \
$(GO) build \
-ldflags="$(LD_FLAGS)" \
-gcflags="$(GC_FLAGS)" \
-trimpath \
-o ./bin/git-lfs$(3) $(BUILD_MAIN)
BUILD_TARGETS = \
bin/git-lfs-darwin-amd64 \
bin/git-lfs-darwin-arm64 \
bin/git-lfs-linux-arm \
bin/git-lfs-linux-arm64 \
bin/git-lfs-linux-amd64 \
bin/git-lfs-linux-ppc64le \
bin/git-lfs-linux-riscv64 \
bin/git-lfs-linux-s390x \
bin/git-lfs-linux-loong64 \
bin/git-lfs-linux-386 \
bin/git-lfs-freebsd-amd64 \
bin/git-lfs-freebsd-386 \
bin/git-lfs-windows-amd64.exe \
bin/git-lfs-windows-386.exe \
bin/git-lfs-windows-arm64.exe
.PHONY : mangen
mangen : commands/mancontent_gen.go
commands/mancontent_gen.go : $(wildcard docs/man/*.adoc)
GOOS= GOARCH= $(GO) generate github.com/git-lfs/git-lfs/v3/commands
.PHONY : trgen
trgen : tr/tr_gen.go
tr/tr_gen.go : $(MO)
GOOS= GOARCH= $(GO) generate github.com/git-lfs/git-lfs/v3/tr
po/build:
mkdir -p po/build
po/build/%.mo: po/%.po po/build
ifeq ($(FORCE_LOCALIZE),)
if command -v $(MSGFMT) >/dev/null 2>&1; \
then \
$(MSGFMT) -o $@ $<; \
fi
else
$(MSGFMT) -o $@ $<
endif
po/i-reverse.po: po/default.pot
script/gen-i-reverse $< $@
po/default.pot:
if command -v $(XGOTEXT) >/dev/null 2>&1; \
then \
$(XGOTEXT) -in . -exclude .git,.github,vendor -out po -v; \
fi
.PHONY : all build
all build : $(BUILD_TARGETS)
bin/git-lfs-darwin-amd64 : $(SOURCES) mangen trgen
$(call BUILD,darwin,amd64,-darwin-amd64)
bin/git-lfs-darwin-arm64 : $(SOURCES) mangen trgen
$(call BUILD,darwin,arm64,-darwin-arm64)
bin/git-lfs-linux-arm : $(SOURCES) mangen trgen
GOARM=5 $(call BUILD,linux,arm,-linux-arm)
bin/git-lfs-linux-arm64 : $(SOURCES) mangen trgen
$(call BUILD,linux,arm64,-linux-arm64)
bin/git-lfs-linux-amd64 : $(SOURCES) mangen trgen
$(call BUILD,linux,amd64,-linux-amd64)
bin/git-lfs-linux-ppc64le : $(SOURCES) mangen trgen
$(call BUILD,linux,ppc64le,-linux-ppc64le)
bin/git-lfs-linux-riscv64 : $(SOURCES) mangen trgen
$(call BUILD,linux,riscv64,-linux-riscv64)
bin/git-lfs-linux-loong64 : $(SOURCES) mangen trgen
$(call BUILD,linux,loong64,-linux-loong64)
bin/git-lfs-linux-s390x : $(SOURCES) mangen trgen
$(call BUILD,linux,s390x,-linux-s390x)
bin/git-lfs-linux-386 : $(SOURCES) mangen trgen
$(call BUILD,linux,386,-linux-386)
bin/git-lfs-freebsd-amd64 : $(SOURCES) mangen trgen
$(call BUILD,freebsd,amd64,-freebsd-amd64)
bin/git-lfs-freebsd-386 : $(SOURCES) mangen trgen
$(call BUILD,freebsd,386,-freebsd-386)
bin/git-lfs-windows-amd64.exe : resource.syso $(SOURCES) mangen trgen
$(call BUILD,windows,amd64,-windows-amd64.exe)
bin/git-lfs-windows-386.exe : resource.syso $(SOURCES) mangen trgen
$(call BUILD,windows,386,-windows-386.exe)
bin/git-lfs-windows-arm64.exe : resource.syso $(SOURCES) mangen trgen
$(call BUILD,windows,arm64,-windows-arm64.exe)
.DEFAULT_GOAL := bin/git-lfs$(X)
bin/git-lfs : $(SOURCES) fmt mangen trgen
$(call BUILD,$(GOOS),$(GOARCH),)
bin/git-lfs.exe : $(SOURCES) resource.syso mangen trgen
$(call BUILD,$(GOOS),$(GOARCH),.exe)
resource.syso : \
versioninfo.json script/windows-installer/git-lfs-logo.bmp \
script/windows-installer/git-lfs-logo.ico \
script/windows-installer/git-lfs-wizard-image.bmp
$(GO) generate
RELEASE_TARGETS = \
bin/releases/git-lfs-darwin-amd64-$(VERSION).zip \
bin/releases/git-lfs-darwin-arm64-$(VERSION).zip \
bin/releases/git-lfs-linux-arm-$(VERSION).tar.gz \
bin/releases/git-lfs-linux-arm64-$(VERSION).tar.gz \
bin/releases/git-lfs-linux-amd64-$(VERSION).tar.gz \
bin/releases/git-lfs-linux-ppc64le-$(VERSION).tar.gz \
bin/releases/git-lfs-linux-riscv64-$(VERSION).tar.gz \
bin/releases/git-lfs-linux-s390x-$(VERSION).tar.gz \
bin/releases/git-lfs-linux-loong64-$(VERSION).tar.gz \
bin/releases/git-lfs-linux-386-$(VERSION).tar.gz \
bin/releases/git-lfs-freebsd-amd64-$(VERSION).tar.gz \
bin/releases/git-lfs-freebsd-386-$(VERSION).tar.gz \
bin/releases/git-lfs-windows-amd64-$(VERSION).zip \
bin/releases/git-lfs-windows-386-$(VERSION).zip \
bin/releases/git-lfs-windows-arm64-$(VERSION).zip \
bin/releases/git-lfs-$(VERSION).tar.gz
RELEASE_INCLUDES = README.md CHANGELOG.md man
.PHONY : release
release : $(RELEASE_TARGETS)
shasum -a 256 $(RELEASE_TARGETS)
bin/releases/git-lfs-%-$(VERSION).tar.gz : \
$(RELEASE_INCLUDES) bin/git-lfs-% script/install.sh
@mkdir -p bin/releases
$(TAR) $(TAR_XFORM_ARG) '$(TAR_XFORM_CMD)!bin/git-lfs-.*!$(PREFIX)/git-lfs!' \
$(TAR_XFORM_ARG) '$(TAR_XFORM_CMD)!script/!$(PREFIX)/!' \
$(TAR_XFORM_ARG) '$(TAR_XFORM_CMD)!\(.*\)\.md!$(PREFIX)/\1.md!' \
$(TAR_XFORM_ARG) '$(TAR_XFORM_CMD)!man!$(PREFIX)/man!' \
--posix -czf $@ $^
bin/releases/git-lfs-darwin-%-$(VERSION).zip : \
$(RELEASE_INCLUDES) bin/git-lfs-darwin-% script/install.sh
@mkdir -p bin/releases
$(BSDTAR) --format zip \
-s '!bin/git-lfs-.*!$(PREFIX)/git-lfs!' \
-s '!script/!$(PREFIX)/!' \
-s '!\(.*\)\.md!$(PREFIX)/\1.md!' \
-s '!man!$(PREFIX)/man!' \
-cf $@ $^
bin/releases/git-lfs-windows-%-$(VERSION).zip : $(RELEASE_INCLUDES) bin/git-lfs-windows-%.exe
@mkdir -p bin/releases
temp=$$(mktemp -d); \
file="$$PWD/$@" && \
mkdir -p "$$temp/$(PREFIX)/man" && \
cp -r $^ "$$temp/$(PREFIX)" && \
(cd "$$temp" && $(BSDTAR) --format zip -cf "$$file" $(PREFIX)) && \
$(RM) -r "$$temp"
bin/releases/git-lfs-$(VERSION).tar.gz :
git archive -o $@ --prefix=$(PREFIX)/ --format tar.gz $(VERSION)
.PHONY : release-linux
release-linux:
./docker/run_dockers.bsh
.PHONY : release-windows-stage-1
release-windows-stage-1: tmp/stage1
tmp/stage1:
$(RM) -r tmp/stage1
@mkdir -p tmp/stage1
@
@
$(MAKE) -B GOOS=windows X=.exe GOARCH=amd64 && cp ./bin/git-lfs.exe ./git-lfs-x64.exe
$(MAKE) -B GOOS=windows X=.exe GOARCH=386 && cp ./bin/git-lfs.exe ./git-lfs-x86.exe
$(MAKE) -B GOOS=windows X=.exe GOARCH=arm64 && cp ./bin/git-lfs.exe ./git-lfs-arm64.exe
mv git-lfs-x64.exe git-lfs-x86.exe git-lfs-arm64.exe tmp/stage1
.PHONY : release-windows-stage-2
release-windows-stage-2: tmp/stage2
tmp/stage2: tmp/stage1
cp tmp/stage1/*.exe .
@
@
iscc.exe script/windows-installer/inno-setup-git-lfs-installer.iss
mv git-lfs-windows-*.exe git-lfs-windows.exe
$(RM) -r tmp/stage2
@mkdir -p tmp/stage2
cp git-lfs-windows.exe tmp/stage2
.PHONY : release-windows-stage-3
release-windows-stage-3: bin/releases/git-lfs-windows-assets-$(VERSION).tar.gz
bin/releases/git-lfs-windows-assets-$(VERSION).tar.gz : tmp/stage1 tmp/stage2
mv tmp/stage1/git-lfs-x64.exe git-lfs-windows-amd64.exe
mv tmp/stage1/git-lfs-x86.exe git-lfs-windows-386.exe
mv tmp/stage1/git-lfs-arm64.exe git-lfs-windows-arm64.exe
mv tmp/stage2/git-lfs-windows.exe git-lfs-windows.exe
@
$(TAR) -czf $@ git-lfs-windows-amd64.exe git-lfs-windows-386.exe git-lfs-windows-arm64.exe git-lfs-windows.exe
$(RM) git-lfs-windows-amd64.exe git-lfs-windows-386.exe git-lfs-windows-arm64.exe git-lfs-windows.exe
.PHONY : release-windows-rebuild
release-windows-rebuild: bin/releases/git-lfs-windows-assets-$(VERSION).tar.gz
temp=$$(mktemp -d); \
file="$$PWD/$^"; \
root="$$PWD" && \
( \
tar -C "$$temp" -xzf "$$file" && \
for i in 386 amd64 arm64; do \
temp2="$$(mktemp -d)" && \
$(BSDTAR) -C "$$temp2" -xf "$$root/bin/releases/git-lfs-windows-$$i-$(VERSION).zip" && \
rm -f "$$temp2/$(PREFIX)/"git-lfs*.exe && \
cp "$$temp/git-lfs-windows-$$i.exe" "$$temp2/$(PREFIX)/git-lfs.exe" && \
(cd "$$temp2" && $(BSDTAR) --format=zip -cf "$$root/bin/releases/git-lfs-windows-$$i-$(VERSION).zip" $(PREFIX)) && \
rm -fr "$$temp2"; \
done && \
cp "$$temp/git-lfs-windows.exe" bin/releases/git-lfs-windows-$(VERSION).exe \
); \
status="$$?"; [ -n "$$temp" ] && $(RM) -r "$$temp"; exit "$$status"
.PHONY : release-darwin
release-darwin: bin/releases/git-lfs-darwin-amd64-$(VERSION).zip bin/releases/git-lfs-darwin-arm64-$(VERSION).zip
for i in $^; do \
temp=$$(mktemp -d) && \
root=$$(pwd -P) && \
( \
$(BSDTAR) -C "$$temp" -xf "$$i" && \
$(CODESIGN) --keychain $(DARWIN_KEYCHAIN_ID) -s "$(DARWIN_CERT_ID)" --force --timestamp -vvvv --options runtime "$$temp/$(PREFIX)/git-lfs" && \
$(CODESIGN) -dvvv "$$temp/$(PREFIX)/git-lfs" && \
(cd "$$temp" && $(BSDTAR) --format zip -cf "$$root/$$i" "$(PREFIX)") && \
$(CODESIGN) --keychain $(DARWIN_KEYCHAIN_ID) -s "$(DARWIN_CERT_ID)" --force --timestamp -vvvv --options runtime "$$i" && \
$(CODESIGN) -dvvv "$$i" && \
jq -e ".notarize.path = \"$$i\" | .apple_id.username = \"$(DARWIN_DEV_USER)\"" script/macos/manifest.json > "$$temp/manifest.json"; \
for j in 1 2 3; \
do \
script/notarize "$$i" && break; \
done; \
); \
status="$$?"; [ -n "$$temp" ] && $(RM) -r "$$temp"; [ "$$status" -eq 0 ] || exit "$$status"; \
done
.PHONY : release-write-certificate
release-write-certificate:
@echo "Writing certificate to $(CERT_FILE)"
@echo "$$CERT_CONTENTS" | base64 --decode >"$$CERT_FILE"
@printf 'Wrote %d bytes (SHA256 %s) to certificate file\n' $$(wc -c <"$$CERT_FILE") $$(shasum -ba 256 "$$CERT_FILE" | cut -d' ' -f1)
.PHONY : release-import-certificate
release-import-certificate:
@[ -n "$(CI)" ] || { echo "Don't run this target by hand." >&2; false; }
@echo "Creating CI keychain"
security create-keychain -p default CI.keychain
security set-keychain-settings CI.keychain
security unlock-keychain -p default CI.keychain
@echo "Importing certificate from $(CERT_FILE)"
@security import "$$CERT_FILE" -f pkcs12 -k CI.keychain -P "$$CERT_PASS" -A
@echo "Verifying import and setting permissions"
security list-keychains -s CI.keychain
security default-keychain -s CI.keychain
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k default CI.keychain
security find-identity -vp codesigning CI.keychain
TEST_TARGETS := test-bench test-verbose test-race
.PHONY : $(TEST_TARGETS) test
$(TEST_TARGETS) : test
test-bench : GO_TEST_EXTRA_ARGS=-run=__nothing__ -bench=.
test-verbose : GO_TEST_EXTRA_ARGS=-v
test-race : GO_TEST_EXTRA_ARGS=-race
test : fmt $(.DEFAULT_GOAL)
( \
unset GIT_DIR; unset GIT_WORK_TREE; unset XDG_CONFIG_HOME; unset XDG_RUNTIME_DIR; \
tempdir="$$(mktemp -d)"; \
export HOME="$$tempdir"; \
export GIT_CONFIG_NOSYSTEM=1; \
$(GO) test -count=1 $(GO_TEST_EXTRA_ARGS) $(addprefix ./,$(PKGS)); \
RET=$$?; \
chmod -R u+w "$$tempdir"; \
rm -fr "$$tempdir"; \
exit $$RET; \
)
.PHONY : integration
integration : bin/git-lfs$(X)
make -C t test
go.sum : go.mod
$(GO) mod verify >/dev/null
.PHONY : vendor
vendor : go.mod
$(GO) mod vendor -v
.PHONY : fmt
ifeq ($(shell test -x "`command -v $(GOIMPORTS)`"; echo $$?),0)
fmt : $(SOURCES) | lint
@$(GOIMPORTS) $(GOIMPORTS_EXTRA_OPTS) $?;
else
fmt : $(SOURCES) | lint
@echo "git-lfs: skipping fmt, no goimports found at \`$(GOIMPORTS)\` ..."
endif
.PHONY : lint
lint : $(SOURCES)
@! $(GO) list -f '{{ join .Deps "\n" }}' . \
| $(XARGS) $(GO) list -f \
'{{ if and (not .Standard) (not .Module) }} \
{{ .ImportPath }} \
{{ end }}' \
| $(GREP) -v "github.com/git-lfs/git-lfs" \
| $(GREP) "."
MAN_ROFF_TARGETS = man/man1/git-lfs-checkout.1 \
man/man1/git-lfs-clean.1 \
man/man1/git-lfs-clone.1 \
man/man1/git-lfs-completion.1 \
man/man5/git-lfs-config.5 \
man/man1/git-lfs-dedup.1 \
man/man1/git-lfs-env.1 \
man/man1/git-lfs-ext.1 \
man/man7/git-lfs-faq.7 \
man/man1/git-lfs-fetch.1 \
man/man1/git-lfs-filter-process.1 \
man/man1/git-lfs-fsck.1 \
man/man1/git-lfs-install.1 \
man/man1/git-lfs-lock.1 \
man/man1/git-lfs-locks.1 \
man/man1/git-lfs-logs.1 \
man/man1/git-lfs-ls-files.1 \
man/man1/git-lfs-merge-driver.1 \
man/man1/git-lfs-migrate.1 \
man/man1/git-lfs-pointer.1 \
man/man1/git-lfs-post-checkout.1 \
man/man1/git-lfs-post-commit.1 \
man/man1/git-lfs-post-merge.1 \
man/man1/git-lfs-pre-push.1 \
man/man1/git-lfs-prune.1 \
man/man1/git-lfs-pull.1 \
man/man1/git-lfs-push.1 \
man/man1/git-lfs-smudge.1 \
man/man1/git-lfs-standalone-file.1 \
man/man1/git-lfs-status.1 \
man/man1/git-lfs-track.1 \
man/man1/git-lfs-uninstall.1 \
man/man1/git-lfs-unlock.1 \
man/man1/git-lfs-untrack.1 \
man/man1/git-lfs-update.1 \
man/man1/git-lfs.1
MAN_HTML_TARGETS = man/html/git-lfs-checkout.1.html \
man/html/git-lfs-clean.1.html \
man/html/git-lfs-clone.1.html \
man/html/git-lfs-completion.1.html \
man/html/git-lfs-config.5.html \
man/html/git-lfs-dedup.1.html \
man/html/git-lfs-env.1.html \
man/html/git-lfs-ext.1.html \
man/html/git-lfs-faq.7.html \
man/html/git-lfs-fetch.1.html \
man/html/git-lfs-filter-process.1.html \
man/html/git-lfs-fsck.1.html \
man/html/git-lfs-install.1.html \
man/html/git-lfs-lock.1.html \
man/html/git-lfs-locks.1.html \
man/html/git-lfs-logs.1.html \
man/html/git-lfs-ls-files.1.html \
man/html/git-lfs-merge-driver.1.html \
man/html/git-lfs-migrate.1.html \
man/html/git-lfs-pointer.1.html \
man/html/git-lfs-post-checkout.1.html \
man/html/git-lfs-post-commit.1.html \
man/html/git-lfs-post-merge.1.html \
man/html/git-lfs-pre-push.1.html \
man/html/git-lfs-prune.1.html \
man/html/git-lfs-pull.1.html \
man/html/git-lfs-push.1.html \
man/html/git-lfs-smudge.1.html \
man/html/git-lfs-standalone-file.1.html \
man/html/git-lfs-status.1.html \
man/html/git-lfs-track.1.html \
man/html/git-lfs-uninstall.1.html \
man/html/git-lfs-unlock.1.html \
man/html/git-lfs-untrack.1.html \
man/html/git-lfs-update.1.html \
man/html/git-lfs.1.html
.PHONY : man
man : $(MAN_ROFF_TARGETS) $(MAN_HTML_TARGETS)
man/man1/%.1 man/man5/%.5 man/man7/%.7 : docs/man/%.adoc
@mkdir -p man/man1 man/man5
$(ASCIIDOCTOR) $(ASCIIDOCTOR_EXTRA_ARGS) -b manpage -o $@ $^
man/html/%.1.html man/html/%.5.html man/html/%.7.html : docs/man/%.adoc
@mkdir -p man/html
$(ASCIIDOCTOR) $(ASCIIDOCTOR_EXTRA_ARGS) -b html5 -o $@ $^