Skip to content

Commit

Permalink
build: add support for Git repos
Browse files Browse the repository at this point in the history
  • Loading branch information
aksiksi committed Sep 29, 2024
1 parent 7c905c2 commit a055b4b
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 45 deletions.
30 changes: 20 additions & 10 deletions compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -720,20 +720,30 @@ func (g *Generator) buildNixContainer(service types.ServiceConfig, networkMap ma

func (g *Generator) parseServiceBuild(service types.ServiceConfig, c *NixContainer) (*NixBuild, error) {
cx := service.Build.Context
isGitRepo := false

if strings.HasPrefix(cx, "http") {
return nil, fmt.Errorf("Git repo build context is not yet supported")
}
if !path.IsAbs(cx) {
// Process this as a Git repo.
isGitRepo = true
} else if !path.IsAbs(cx) {
cx = path.Join(g.rootPath, cx)
}

// Always prepend the image name to the list of specified tags.
tags := service.Build.Tags
if service.Image != "" {
tags = slices.Insert(tags, 0, service.Image)
}

b := &NixBuild{
Runtime: g.Runtime,
Context: cx,
Args: service.Build.Args,
Tags: service.Build.Tags,
Dockerfile: service.Build.Dockerfile,
ServiceName: service.Name,
Runtime: g.Runtime,
Context: cx,
PullPolicy: NewServicePullPolicy(service.PullPolicy),
IsGitRepo: isGitRepo,
Args: service.Build.Args,
Tags: tags,
Dockerfile: service.Build.Dockerfile,
ContainerName: c.Name,
}

if g.IncludeBuild {
Expand Down Expand Up @@ -774,7 +784,7 @@ func (g *Generator) buildNixContainers(composeProject *types.Project, networkMap
return cmp.Compare(c1.Name, c2.Name)
})
slices.SortFunc(builds, func(c1, c2 *NixBuild) int {
return cmp.Compare(c1.ServiceName, c2.ServiceName)
return cmp.Compare(c1.ContainerName, c2.ContainerName)
})
return containers, builds, nil
}
Expand Down
47 changes: 40 additions & 7 deletions nix.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,19 +196,52 @@ func (c *NixContainer) Unit() string {
return fmt.Sprintf("%s-%s.service", c.Runtime, c.Name)
}

// https://docs.docker.com/reference/compose-file/services/#pull_policy
type ServicePullPolicy int

const (
ServicePullPolicyInvalid ServicePullPolicy = iota
ServicePullPolicyAlways
ServicePullPolicyNever
ServicePullPolicyMissing
ServicePullPolicyBuild
ServicePullPolicyUnset
)

func NewServicePullPolicy(s string) ServicePullPolicy {
switch strings.TrimSpace(s) {
case "always":
return ServicePullPolicyAlways
case "never":
return ServicePullPolicyNever
case "missing", "if_not_present":
return ServicePullPolicyMissing
case "build":
return ServicePullPolicyBuild
default:
return ServicePullPolicyUnset
}
}

// https://docs.docker.com/reference/compose-file/build/
// https://docs.docker.com/reference/cli/docker/buildx/build/
type NixBuild struct {
Runtime ContainerRuntime
Context string
Args map[string]*string
Tags []string
Dockerfile string // Relative to context path.
ServiceName string
Runtime ContainerRuntime
Context string
PullPolicy ServicePullPolicy
IsGitRepo bool
Args map[string]*string
Tags []string
Dockerfile string // Relative to context path.
ContainerName string // Name of the resolved Nix container.
}

func (b *NixBuild) UnitName() string {
return fmt.Sprintf("%s-build-%s", b.Runtime, b.ContainerName)
}

func (b *NixBuild) Unit() string {
return fmt.Sprintf("podman-build-%s.service", b.ServiceName)
return b.UnitName() + ".service"
}

func (b *NixBuild) Command() string {
Expand Down
13 changes: 10 additions & 3 deletions templates/build.nix.tmpl
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
systemd.services."{{.Runtime}}-build-{{.ServiceName}}" = {
systemd.services."{{.UnitName}}" = {
{{- /* TODO: Support Git repo as a build source. */}}
path = [ pkgs.{{.Runtime}} pkgs.git ];
serviceConfig = {
Type = "oneshot";
{{- if cfg.IncludeBuild}}
RuntimeDirectory = "{{.UnitName}}";
{{- if cfg.IncludeBuild}}
RemainAfterExit = true;
{{- end}}
{{- end}}
};
script = ''
{{- if .IsGitRepo}}
cd /var/run/{{.UnitName}}
rm -rf *
git clone {{.Context}} .
{{- else}}
cd {{.Context}}
{{- end}}
{{escapeIndentedNixString .Command}}
'';
{{- if and cfg.IncludeBuild rootTarget}}
Expand Down
3 changes: 0 additions & 3 deletions templates/main.nix.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@
{{- if .Builds}}

# Builds
#
# NOTE: These must be run manually before running any containers that require
# them to be present in the image store.
{{- range .Builds}}
{{execTemplate "build.nix.tmpl" . | indent 2}}
{{- end}}
Expand Down
7 changes: 7 additions & 0 deletions testdata/TestBuildSpec.compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ services:
- ./data:/data:ro
networks:
- internal
prefetcharr:
image: prefetcharr
build: https://github.com/p-hueber/prefetcharr.git
environment:
- JELLYFIN_URL=http://example.com/jellyfin
volumes:
- /path/to/log/dir:/log

volumes:
custom-logs:
Expand Down
58 changes: 54 additions & 4 deletions testdata/TestBuildSpec.docker.nix
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,47 @@
"docker-volume-test_custom-logs.service"
];
};
virtualisation.oci-containers.containers."test-prefetcharr" = {
image = "prefetcharr";
environment = {
"JELLYFIN_URL" = "http://example.com/jellyfin";
};
volumes = [
"/path/to/log/dir:/log:rw"
];
log-driver = "journald";
autoStart = false;
extraOptions = [
"--network-alias=prefetcharr"
"--network=test_default"
];
};
systemd.services."docker-test-prefetcharr" = {
serviceConfig = {
Restart = lib.mkOverride 90 "no";
};
after = [
"docker-network-test_default.service"
];
requires = [
"docker-network-test_default.service"
];
};

# Networks
systemd.services."docker-network-test_default" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "docker network rm -f test_default";
};
script = ''
docker network inspect test_default || docker network create test_default
'';
partOf = [ "docker-compose-test-root.target" ];
wantedBy = [ "docker-compose-test-root.target" ];
};
systemd.services."docker-network-test_internal" = {
path = [ pkgs.docker ];
serviceConfig = {
Expand Down Expand Up @@ -75,19 +114,30 @@
};

# Builds
#
# NOTE: These must be run manually before running any containers that require
# them to be present in the image store.
systemd.services."docker-build-museum" = {
systemd.services."docker-build-test-museum" = {
path = [ pkgs.docker pkgs.git ];
serviceConfig = {
Type = "oneshot";
RuntimeDirectory = "docker-build-test-museum";
};
script = ''
cd /some/path
docker build -t latest -t non-latest --build-arg GIT_COMMIT=development-cluster .
'';
};
systemd.services."docker-build-test-prefetcharr" = {
path = [ pkgs.docker pkgs.git ];
serviceConfig = {
Type = "oneshot";
RuntimeDirectory = "docker-build-test-prefetcharr";
};
script = ''
cd /var/run/docker-build-test-prefetcharr
rm -rf *
git clone https://github.com/p-hueber/prefetcharr.git .
docker build -t prefetcharr .
'';
};

# Root service
# When started, this will automatically create all resources and start
Expand Down
58 changes: 54 additions & 4 deletions testdata/TestBuildSpec.podman.nix
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,47 @@
"podman-volume-test_custom-logs.service"
];
};
virtualisation.oci-containers.containers."test-prefetcharr" = {
image = "prefetcharr";
environment = {
"JELLYFIN_URL" = "http://example.com/jellyfin";
};
volumes = [
"/path/to/log/dir:/log:rw"
];
log-driver = "journald";
autoStart = false;
extraOptions = [
"--network-alias=prefetcharr"
"--network=test_default"
];
};
systemd.services."podman-test-prefetcharr" = {
serviceConfig = {
Restart = lib.mkOverride 90 "no";
};
after = [
"podman-network-test_default.service"
];
requires = [
"podman-network-test_default.service"
];
};

# Networks
systemd.services."podman-network-test_default" = {
path = [ pkgs.podman ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "podman network rm -f test_default";
};
script = ''
podman network inspect test_default || podman network create test_default
'';
partOf = [ "podman-compose-test-root.target" ];
wantedBy = [ "podman-compose-test-root.target" ];
};
systemd.services."podman-network-test_internal" = {
path = [ pkgs.podman ];
serviceConfig = {
Expand Down Expand Up @@ -85,19 +124,30 @@
};

# Builds
#
# NOTE: These must be run manually before running any containers that require
# them to be present in the image store.
systemd.services."podman-build-museum" = {
systemd.services."podman-build-test-museum" = {
path = [ pkgs.podman pkgs.git ];
serviceConfig = {
Type = "oneshot";
RuntimeDirectory = "podman-build-test-museum";
};
script = ''
cd /some/path
podman build -t latest -t non-latest --build-arg GIT_COMMIT=development-cluster .
'';
};
systemd.services."podman-build-test-prefetcharr" = {
path = [ pkgs.podman pkgs.git ];
serviceConfig = {
Type = "oneshot";
RuntimeDirectory = "podman-build-test-prefetcharr";
};
script = ''
cd /var/run/podman-build-test-prefetcharr
rm -rf *
git clone https://github.com/p-hueber/prefetcharr.git .
podman build -t prefetcharr .
'';
};

# Root service
# When started, this will automatically create all resources and start
Expand Down
12 changes: 5 additions & 7 deletions testdata/TestBuildSpec_BuildEnabled.docker.nix
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@
Restart = lib.mkOverride 90 "no";
};
after = [
"docker-build-test-museum.service"
"docker-network-test_internal.service"
"docker-volume-test_custom-logs.service"
"podman-build-museum.service"
];
requires = [
"docker-build-test-museum.service"
"docker-network-test_internal.service"
"docker-volume-test_custom-logs.service"
"podman-build-museum.service"
];
upheldBy = [
"podman-build-museum.service"
"docker-build-test-museum.service"
];
};

Expand Down Expand Up @@ -80,13 +80,11 @@
};

# Builds
#
# NOTE: These must be run manually before running any containers that require
# them to be present in the image store.
systemd.services."docker-build-museum" = {
systemd.services."docker-build-test-museum" = {
path = [ pkgs.docker pkgs.git ];
serviceConfig = {
Type = "oneshot";
RuntimeDirectory = "docker-build-test-museum";
RemainAfterExit = true;
};
script = ''
Expand Down
12 changes: 5 additions & 7 deletions testdata/TestBuildSpec_BuildEnabled.podman.nix
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,17 @@
Restart = lib.mkOverride 90 "no";
};
after = [
"podman-build-museum.service"
"podman-build-test-museum.service"
"podman-network-test_internal.service"
"podman-volume-test_custom-logs.service"
];
requires = [
"podman-build-museum.service"
"podman-build-test-museum.service"
"podman-network-test_internal.service"
"podman-volume-test_custom-logs.service"
];
upheldBy = [
"podman-build-museum.service"
"podman-build-test-museum.service"
];
};

Expand Down Expand Up @@ -90,13 +90,11 @@
};

# Builds
#
# NOTE: These must be run manually before running any containers that require
# them to be present in the image store.
systemd.services."podman-build-museum" = {
systemd.services."podman-build-test-museum" = {
path = [ pkgs.podman pkgs.git ];
serviceConfig = {
Type = "oneshot";
RuntimeDirectory = "podman-build-test-museum";
RemainAfterExit = true;
};
script = ''
Expand Down

0 comments on commit a055b4b

Please sign in to comment.