DodoApp: support Hugo static websites

Change-Id: Ie01f12443e81f3bfc9f7500d443a0399a1fe01ef
diff --git a/apps/app-runner/Dockerfile.hugo b/apps/app-runner/Dockerfile.hugo
new file mode 100644
index 0000000..490d5c5
--- /dev/null
+++ b/apps/app-runner/Dockerfile.hugo
@@ -0,0 +1,5 @@
+FROM giolekva/hugo:latest
+
+ARG TARGETARCH
+
+COPY app-runner_${TARGETARCH} /usr/bin/app-runner
diff --git a/apps/app-runner/Makefile b/apps/app-runner/Makefile
index 4c2424e..8a8936a 100644
--- a/apps/app-runner/Makefile
+++ b/apps/app-runner/Makefile
@@ -33,3 +33,18 @@
 	$(podman) manifest create $(repo_name)/app-runner:golang-1.22.0 $(repo_name)/app-runner:golang-1.22.0-arm64 $(repo_name)/app-runner:golang-1.22.0-amd64
 	$(podman) manifest push $(repo_name)/app-runner:golang-1.22.0 $(manifest_dest)
 	$(podman) manifest rm $(repo_name)/app-runner:golang-1.22.0
+
+# Hugo
+
+push_hugo_arm64: clean build_arm64
+	$(podman) build --platform linux/arm64 --tag=$(repo_name)/app-runner:hugo-latest-arm64 -f Dockerfile.hugo .
+	$(podman) push $(repo_name)/app-runner:hugo-latest-arm64
+
+push_hugo_amd64: clean build_amd64
+	$(podman) build --platform linux/amd64 --tag=$(repo_name)/app-runner:hugo-latest-amd64 -f Dockerfile.hugo .
+	$(podman) push $(repo_name)/app-runner:hugo-latest-amd64
+
+push_hugo: push_hugo_arm64 push_hugo_amd64
+	$(podman) manifest create $(repo_name)/app-runner:hugo-latest $(repo_name)/app-runner:hugo-latest-arm64 $(repo_name)/app-runner:hugo-latest-amd64
+	$(podman) manifest push $(repo_name)/app-runner:hugo-latest $(manifest_dest)
+	$(podman) manifest rm $(repo_name)/app-runner:hugo-latest
diff --git a/apps/app-runner/main.go b/apps/app-runner/main.go
index fb17415..ee2476a 100644
--- a/apps/app-runner/main.go
+++ b/apps/app-runner/main.go
@@ -41,10 +41,12 @@
 				},
 			},
 		},
-		RemoteName:      "origin",
-		ReferenceName:   "refs/heads/master",
-		Depth:           1,
-		InsecureSkipTLS: true,
+		RemoteName:        "origin",
+		ReferenceName:     "refs/heads/master",
+		Depth:             1,
+		RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
+		ShallowSubmodules: true,
+		InsecureSkipTLS:   true,
 	})
 	return err
 }
diff --git a/core/installer/app_configs/dodo_app.cue b/core/installer/app_configs/dodo_app.cue
index 409b5d4..39788a7 100644
--- a/core/installer/app_configs/dodo_app.cue
+++ b/core/installer/app_configs/dodo_app.cue
@@ -15,6 +15,20 @@
 	auth: #Auth
 }
 
+#AppTmpl: {
+	type: string
+	ingress: #AppIngress
+	runConfiguration: [...#Command]
+	...
+}
+
+#Command: {
+	bin: string
+	args: [...string] | *[]
+}
+
+// Go app
+
 _goVer1220: "golang:1.22.0"
 _goVer1200: "golang:1.20.0"
 
@@ -45,7 +59,28 @@
 
 #GoApp: #GoApp1200 | #GoApp1220
 
-app: #GoApp
+// Hugo app
+
+_hugoLatest: "hugo:latest"
+
+#HugoAppTmpl: {
+	type: _hugoLatest
+	ingress: #AppIngress
+
+	runConfiguration: [{
+		bin: "/usr/bin/hugo",
+		args: []
+	}, {
+		bin: "/usr/bin/hugo",
+		args: ["server", "--port=\(_appPort)", "--bind=0.0.0.0"]
+	}]
+}
+
+#HugoApp: #HugoAppTmpl
+
+#App: #GoApp | #HugoApp
+
+app: #App
 
 // output
 
@@ -89,8 +124,8 @@
 				tag: images.app.tag
 				pullPolicy: images.app.pullPolicy
 			}
-			appPort: 8080
-			appDir: "/dodo-app"
+			appPort: _appPort
+			appDir: _appDir
 			repoAddr: input.repoAddr
 			sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
 			runCfg: base64.Encode(null, json.Marshal(_app.runConfiguration))
@@ -98,3 +133,6 @@
 		}
 	}
 }
+
+_appDir: "/dodo-app"
+_appPort: 8080
diff --git a/core/installer/soft/repoio.go b/core/installer/soft/repoio.go
index b50bcaa..6df9dcd 100644
--- a/core/installer/soft/repoio.go
+++ b/core/installer/soft/repoio.go
@@ -188,6 +188,13 @@
 	if err := wt.AddGlob("*"); err != nil {
 		return err
 	}
+	st, err := wt.Status()
+	if err != nil {
+		return err
+	}
+	if len(st) == 0 {
+		return nil // TODO(gio): maybe return ErrorNothingToCommit
+	}
 	if _, err := wt.Commit(message, &git.CommitOptions{
 		Author: &object.Signature{
 			Name: "pcloud-installer",