Skip to content

Commit 8b17476

Browse files
committed
Added git-lfs feature
1 parent 5da5f0a commit 8b17476

File tree

11 files changed

+260
-0
lines changed

11 files changed

+260
-0
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jobs:
1616
matrix:
1717
feature: [
1818
"docker-out",
19+
"git-lfs",
1920
"go",
2021
"zig"
2122
]

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Below is a list with included features, click on the link for more details.
1616
| Name | Description |
1717
| --- | --- |
1818
| [docker-out](./features/src/docker-out/README.md) | A feature which installs the Docker client and re-uses the host socket. |
19+
| [git-lfs](./features/src/git-lfs/README.md) | A feature which installs Git LFS. |
1920
| [go](./features/src/go/README.md) | A feature which installs Go. |
2021
| [zig](./features/src/zig/README.md) | A feature which installs Zig. |
2122

build/build.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
var featureList = []string{
2323
"docker-out",
24+
"git-lfs",
2425
"go",
2526
"zig",
2627
}
@@ -58,6 +59,17 @@ func init() {
5859
return publishFeature("docker-out")
5960
})
6061

62+
////////// git-lfs
63+
gotaskr.Task("Feature:git-lfs:Package", func() error {
64+
return packageFeature("git-lfs")
65+
})
66+
gotaskr.Task("Feature:git-lfs:Test", func() error {
67+
return testFeature("git-lfs")
68+
})
69+
gotaskr.Task("Feature:git-lfs:Publish", func() error {
70+
return publishFeature("git-lfs")
71+
})
72+
6173
////////// go
6274
gotaskr.Task("Feature:go:Package", func() error {
6375
return packageFeature("go")

features/src/git-lfs/NOTES.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## Notes
2+
3+
### System Compatibility
4+
5+
Debian, Ubuntu, Alpine
6+
7+
### Accessed Urls
8+
9+
Needs access to the following URL for downloading and resolving:
10+
* https://github.com

features/src/git-lfs/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Git LFS (git-lfs)
2+
3+
A feature which installs Git LFS.
4+
5+
## Example Usage
6+
7+
```json
8+
"features": {
9+
"ghcr.io/postfinance/devcontainer-features/git-lfs:0.1.0": {
10+
"version": "latest",
11+
"versionResolve": false,
12+
"downloadUrlBase": "",
13+
"downloadUrlPath": ""
14+
}
15+
}
16+
```
17+
18+
## Options
19+
20+
| Option | Description | Type | Default Value | Proposals |
21+
|-----|-----|-----|-----|-----|
22+
| version | The version of Git LFS to install. | string | latest | latest, 3.7.0, 3.6 |
23+
| versionResolve | Whether to resolve the version automatically. | boolean | false | true, false |
24+
| downloadUrlBase | The download URL to use for Git LFS binaries. | string | <empty> | |
25+
| downloadUrlPath | The download URL path to use for Git LFS binaries. | string | <empty> | |
26+
27+
## Notes
28+
29+
### System Compatibility
30+
31+
Debian, Ubuntu, Alpine
32+
33+
### Accessed Urls
34+
35+
Needs access to the following URL for downloading and resolving:
36+
* https://github.com
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"id": "git-lfs",
3+
"version": "0.1.0",
4+
"name": "Git LFS",
5+
"description": "A feature which installs Git LFS.",
6+
"options": {
7+
"version": {
8+
"type": "string",
9+
"proposals": [
10+
"latest",
11+
"3.7.0",
12+
"3.6"
13+
],
14+
"default": "latest",
15+
"description": "The version of Git LFS to install."
16+
},
17+
"versionResolve": {
18+
"type": "boolean",
19+
"default": false,
20+
"description": "Whether to resolve the version automatically."
21+
},
22+
"downloadUrlBase": {
23+
"type": "string",
24+
"default": "",
25+
"description": "The download URL to use for Git LFS binaries."
26+
},
27+
"downloadUrlPath": {
28+
"type": "string",
29+
"default": "",
30+
"description": "The download URL path to use for Git LFS binaries."
31+
}
32+
}
33+
}

features/src/git-lfs/install.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
case $(uname -m | tr '[:upper:]' '[:lower:]') in
2+
x86_64*) ARCH=amd64 ;;
3+
arm*|aarch64*) ARCH=arm64 ;;
4+
*) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
5+
esac
6+
7+
"./installer_$ARCH" \
8+
-version="${VERSION:-"latest"}" \
9+
-versionResolve="${VERSIONRESOLVE:-false}" \
10+
-downloadUrlBase="${DOWNLOADURLBASE:-""}" \
11+
-downloadUrlPath="${DOWNLOADURLPATH:-""}"

features/src/git-lfs/installer.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package main
2+
3+
import (
4+
"builder/installer"
5+
"flag"
6+
"fmt"
7+
"os"
8+
"path/filepath"
9+
"regexp"
10+
11+
"github.com/roemer/gotaskr/execr"
12+
"github.com/roemer/gover"
13+
)
14+
15+
//////////
16+
// Configuration
17+
//////////
18+
19+
var gitLfsVersionRegexp *regexp.Regexp = regexp.MustCompile(`(?m)^v(?P<raw>(\d+)\.(\d+)\.(\d+))$`)
20+
21+
//////////
22+
// Main
23+
//////////
24+
25+
func main() {
26+
if err := runMain(); err != nil {
27+
fmt.Printf("Error: %v\n", err)
28+
os.Exit(1)
29+
}
30+
}
31+
32+
func runMain() error {
33+
// Handle the flags
34+
version := flag.String("version", "latest", "")
35+
versionResolve := flag.Bool("versionResolve", false, "")
36+
downloadUrlBase := flag.String("downloadUrlBase", "", "")
37+
downloadUrlPath := flag.String("downloadUrlPath", "", "")
38+
flag.Parse()
39+
40+
// Load settings from an external file
41+
if err := installer.LoadOverrides(); err != nil {
42+
return err
43+
}
44+
45+
installer.HandleGitHubOverride(downloadUrlBase, downloadUrlPath, "git-lfs/git-lfs", "git-lfs-download-url")
46+
47+
// Create and process the feature
48+
feature := installer.NewFeature("Git LFS", false,
49+
&gitLfsComponent{
50+
ComponentBase: installer.NewComponentBase("Git LFS", *version, *versionResolve),
51+
DownloadUrlBase: *downloadUrlBase,
52+
DownloadUrlPath: *downloadUrlPath,
53+
},
54+
)
55+
return feature.Process()
56+
}
57+
58+
//////////
59+
// Implementation
60+
//////////
61+
62+
type gitLfsComponent struct {
63+
*installer.ComponentBase
64+
DownloadUrlBase string
65+
DownloadUrlPath string
66+
}
67+
68+
func (c *gitLfsComponent) GetAllVersions() ([]*gover.Version, error) {
69+
versions := []*gover.Version{}
70+
allTags, err := installer.Tools.GitHub.GetTags("git-lfs", "git-lfs")
71+
if err != nil {
72+
return nil, err
73+
}
74+
for _, tag := range allTags {
75+
if gitLfsVersionRegexp.MatchString(tag.Name) {
76+
version, err := gover.ParseVersionFromRegex(tag.Name, gitLfsVersionRegexp)
77+
if err != nil {
78+
return nil, err
79+
}
80+
versions = append(versions, version)
81+
}
82+
}
83+
return versions, nil
84+
}
85+
86+
func (c *gitLfsComponent) InstallVersion(version *gover.Version) error {
87+
// Download the file
88+
archPart, err := installer.Tools.System.MapArchitecture(map[string]string{
89+
installer.AMD64: "amd64",
90+
installer.ARM64: "arm64",
91+
})
92+
if err != nil {
93+
return err
94+
}
95+
// https://github.com/git-lfs/git-lfs/releases/download/v3.7.0/git-lfs-linux-amd64-v3.7.0.tar.gz
96+
// https://github.com/git-lfs/git-lfs/releases/download/v3.7.0/git-lfs-linux-arm64-v3.7.0.tar.gz
97+
versionPart := fmt.Sprintf("v%s", version.Raw)
98+
fileName := fmt.Sprintf("git-lfs-linux-%s-%s.tar.gz", archPart, versionPart)
99+
downloadUrl, err := installer.Tools.Http.BuildUrl(c.DownloadUrlBase, c.DownloadUrlPath, versionPart, fileName)
100+
if err != nil {
101+
return err
102+
}
103+
if err := installer.Tools.Download.ToFile(downloadUrl, fileName, "Git LFS"); err != nil {
104+
return err
105+
}
106+
// Extract it
107+
tempDir, err := os.MkdirTemp("", "git-lfs-extract")
108+
if err != nil {
109+
return err
110+
}
111+
defer os.RemoveAll(tempDir)
112+
if err := installer.Tools.Compression.ExtractTarGz(fileName, tempDir, true); err != nil {
113+
return err
114+
}
115+
// Move the desired files
116+
if err := installer.Tools.FileSystem.MoveFile(filepath.Join(tempDir, "git-lfs"), "/usr/local/bin/git-lfs"); err != nil {
117+
return err
118+
}
119+
// Apply executable permissions
120+
if err := execr.Run(true, "chmod", "+x", "/usr/local/bin/git-lfs"); err != nil {
121+
return err
122+
}
123+
// Install
124+
if err := execr.Run(true, "git", "lfs", "install"); err != nil {
125+
return err
126+
}
127+
return nil
128+
}

features/test/git-lfs/install.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
set -e
3+
4+
[[ -f "$(dirname "$0")/../functions.sh" ]] && source "$(dirname "$0")/../functions.sh"
5+
[[ -f "$(dirname "$0")/functions.sh" ]] && source "$(dirname "$0")/functions.sh"
6+
7+
check_version "$(git lfs version)" "git-lfs/3.7.0 (GitHub; linux amd64; go 1.24.4; git 92dddf56)"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"install": {
3+
"build": {
4+
"dockerfile": "Dockerfile",
5+
"options": [
6+
"--add-host=host.docker.internal:host-gateway"
7+
]
8+
},
9+
"features": {
10+
"./git-lfs": {
11+
"version": "3.7.0"
12+
}
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)