267 lines
9.2 KiB
Go
267 lines
9.2 KiB
Go
package devContainer
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"path"
|
|
"strconv"
|
|
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
"code.gitea.io/gitea/modules/templates"
|
|
"code.gitea.io/gitea/services/context"
|
|
devcontainer_service "code.gitea.io/gitea/services/devcontainer"
|
|
)
|
|
|
|
const (
|
|
tplGetDevContainerDetails templates.TplName = "repo/devcontainer/details"
|
|
)
|
|
|
|
// 获取仓库 Dev Container 详细信息
|
|
// GET /{username}/{reponame}/devcontainer
|
|
func GetDevContainerDetails(ctx *context.Context) {
|
|
var err error
|
|
ctx.Data["canRead"], err = devcontainer_service.CanReadDevcontainer(ctx.Req.Context(), ctx.Doer, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
}
|
|
ctx.Data["isAdmin"], err = devcontainer_service.IsAdmin(ctx, ctx.Doer, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
}
|
|
ctx.Data["HasDevContainer"], err = devcontainer_service.HasDevContainer(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
}
|
|
ctx.Data["ValidateDevContainerConfiguration"] = true
|
|
ctx.Data["HasDevContainerConfiguration"], err = devcontainer_service.HasDevContainerConfiguration(ctx, ctx.Repo)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Data["ValidateDevContainerConfiguration"] = false
|
|
ctx.Flash.Error(err.Error(), true)
|
|
}
|
|
if ctx.Data["HasDevContainerConfiguration"] == false {
|
|
ctx.Data["ValidateDevContainerConfiguration"] = false
|
|
}
|
|
|
|
ctx.Data["HasDevContainerDockerfile"], err = devcontainer_service.HasDevContainerDockerFile(ctx, ctx.Repo)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
}
|
|
if ctx.Data["HasDevContainer"] == true {
|
|
configurationString, _ := devcontainer_service.GetDevcontainerConfigurationString(ctx, ctx.Repo.Repository)
|
|
configurationModel, _ := devcontainer_service.UnmarshalDevcontainerConfigContent(configurationString)
|
|
imageName := configurationModel.Image
|
|
registry, namespace, repo, tag := devcontainer_service.ParseImageName(imageName)
|
|
log.Info("%v %v", repo, tag)
|
|
ctx.Data["RepositoryAddress"] = registry
|
|
ctx.Data["RepositoryUsername"] = namespace
|
|
ctx.Data["ImageName"] = "dev-" + ctx.Repo.Repository.Name + ":latest"
|
|
|
|
if setting.K8sConfig.Enable {
|
|
// 获取WebSSH服务端口
|
|
webTerminalURL, err := devcontainer_service.GetWebTerminalURL(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
} else {
|
|
ctx.Data["WebSSHUrl"] = webTerminalURL
|
|
}
|
|
} else {
|
|
terminalParams := "user=" + ctx.Doer.Name + "&repo=" + ctx.Repo.Repository.Name + "&repoid=" + strconv.FormatInt(ctx.Repo.Repository.ID, 10) + "&userid=" + strconv.FormatInt(ctx.Doer.ID, 10) + "&domain=" + setting.Domain + "&port=" + setting.HTTPPort
|
|
webTerminalURL, err := devcontainer_service.ReplacePortOfUrl(setting.AppURL, "7681")
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
}
|
|
ctx.Data["WebSSHUrl"] = webTerminalURL + "?type=docker&" + terminalParams
|
|
}
|
|
|
|
}
|
|
|
|
// 3. 携带数据渲染页面,返回
|
|
ctx.Data["Title"] = ctx.Locale.Tr("repo.dev_container")
|
|
ctx.Data["PageIsDevContainer"] = true
|
|
ctx.Data["Repository"] = ctx.Repo.Repository
|
|
ctx.Data["CreateDevcontainerSettingUrl"] = "/" + ctx.ContextUser.Name + "/" + ctx.Repo.Repository.Name + "/devcontainer/createConfiguration"
|
|
ctx.Data["EditDevcontainerConfigurationUrl"] = ctx.Repo.RepoLink + "/_edit/" + ctx.Repo.Repository.DefaultBranch + "/.devcontainer/devcontainer.json"
|
|
ctx.Data["TreeNames"] = []string{".devcontainer", "devcontainer.json"}
|
|
ctx.Data["TreePaths"] = []string{".devcontainer", ".devcontainer/devcontainer.json"}
|
|
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src"
|
|
ctx.Data["SaveMethods"] = []string{"Container", "DockerFile"}
|
|
ctx.Data["SaveMethod"] = "Container"
|
|
ctx.HTML(http.StatusOK, tplGetDevContainerDetails)
|
|
}
|
|
func GetDevContainerStatus(ctx *context.Context) {
|
|
// 设置 CORS 响应头
|
|
ctx.Resp.Header().Set("Access-Control-Allow-Origin", "*")
|
|
ctx.Resp.Header().Set("Access-Control-Allow-Methods", "*")
|
|
ctx.Resp.Header().Set("Access-Control-Allow-Headers", "*")
|
|
var userID string
|
|
if ctx.Doer != nil {
|
|
userID = fmt.Sprintf("%d", ctx.Doer.ID)
|
|
} else {
|
|
query := ctx.Req.URL.Query()
|
|
userID = query.Get("user")
|
|
}
|
|
realTimeStatus, err := devcontainer_service.GetDevContainerStatus(ctx, userID, fmt.Sprintf("%d", ctx.Repo.Repository.ID))
|
|
if err != nil {
|
|
log.Info("%v\n", err)
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, map[string]string{"status": realTimeStatus})
|
|
}
|
|
func CreateDevContainerConfiguration(ctx *context.Context) {
|
|
hasDevContainerConfiguration, err := devcontainer_service.HasDevContainerConfiguration(ctx, ctx.Repo)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
return
|
|
}
|
|
if hasDevContainerConfiguration {
|
|
ctx.Flash.Error("Already exist", true)
|
|
return
|
|
}
|
|
isAdmin, err := devcontainer_service.IsAdmin(ctx, ctx.Doer, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
ctx.Flash.Error(err.Error(), true)
|
|
return
|
|
}
|
|
if !isAdmin {
|
|
ctx.Flash.Error("permisson denied", true)
|
|
return
|
|
}
|
|
err = devcontainer_service.CreateDevcontainerConfiguration(ctx.Repo.Repository, ctx.Doer)
|
|
if err != nil {
|
|
ctx.Flash.Error(err.Error(), true)
|
|
return
|
|
}
|
|
ctx.Redirect(path.Join(ctx.Repo.RepoLink, "/devcontainer"))
|
|
}
|
|
func CreateDevContainer(ctx *context.Context) {
|
|
hasDevContainer, err := devcontainer_service.HasDevContainer(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
return
|
|
}
|
|
if hasDevContainer {
|
|
ctx.Flash.Error("Already exist", true)
|
|
return
|
|
}
|
|
err = devcontainer_service.CreateDevContainer(ctx, ctx.Repo.Repository, ctx.Doer)
|
|
if err != nil {
|
|
ctx.Flash.Error(err.Error(), true)
|
|
}
|
|
ctx.Redirect(path.Join(ctx.Repo.RepoLink, "/devcontainer"))
|
|
}
|
|
func DeleteDevContainer(ctx *context.Context) {
|
|
hasDevContainer, err := devcontainer_service.HasDevContainer(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
return
|
|
}
|
|
if !hasDevContainer {
|
|
ctx.Flash.Error("Already Deleted.", true)
|
|
return
|
|
}
|
|
err = devcontainer_service.DeleteDevContainer(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
ctx.Flash.Error(err.Error(), true)
|
|
}
|
|
ctx.Redirect(path.Join(ctx.Repo.RepoLink, "/devcontainer"))
|
|
}
|
|
func RestartDevContainer(ctx *context.Context) {
|
|
hasDevContainer, err := devcontainer_service.HasDevContainer(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
return
|
|
}
|
|
if !hasDevContainer {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error("Already delete", true)
|
|
return
|
|
}
|
|
err = devcontainer_service.RestartDevContainer(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
ctx.Flash.Error(err.Error(), true)
|
|
}
|
|
ctx.JSON(http.StatusOK, "")
|
|
}
|
|
func StopDevContainer(ctx *context.Context) {
|
|
hasDevContainer, err := devcontainer_service.HasDevContainer(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.Flash.Error(err.Error(), true)
|
|
return
|
|
}
|
|
if !hasDevContainer {
|
|
ctx.Flash.Error("Already delete", true)
|
|
return
|
|
}
|
|
err = devcontainer_service.StopDevContainer(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
ctx.Flash.Error(err.Error(), true)
|
|
}
|
|
ctx.JSON(http.StatusOK, "")
|
|
}
|
|
func UpdateDevContainer(ctx *context.Context) {
|
|
hasDevContainer, err := devcontainer_service.HasDevContainer(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
ctx.JSON(http.StatusOK, map[string]string{"message": err.Error()})
|
|
return
|
|
}
|
|
if !hasDevContainer {
|
|
ctx.JSON(http.StatusOK, map[string]string{"message": "Already delete"})
|
|
return
|
|
}
|
|
// 取得参数
|
|
body, _ := io.ReadAll(ctx.Req.Body)
|
|
var updateInfo devcontainer_service.UpdateInfo
|
|
err = json.Unmarshal(body, &updateInfo)
|
|
if err != nil {
|
|
ctx.JSON(http.StatusOK, map[string]string{"message": err.Error()})
|
|
return
|
|
}
|
|
err = devcontainer_service.UpdateDevContainer(ctx, ctx.Doer, ctx.Repo.Repository, &updateInfo)
|
|
if err != nil {
|
|
ctx.JSON(http.StatusOK, map[string]string{"message": err.Error()})
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusOK, map[string]string{"redirect": ctx.Repo.RepoLink + "/devcontainer", "message": "成功"})
|
|
}
|
|
func GetTerminalCommand(ctx *context.Context) {
|
|
// 设置 CORS 响应头
|
|
ctx.Resp.Header().Set("Access-Control-Allow-Origin", "*")
|
|
ctx.Resp.Header().Set("Access-Control-Allow-Methods", "*")
|
|
ctx.Resp.Header().Set("Access-Control-Allow-Headers", "*")
|
|
query := ctx.Req.URL.Query()
|
|
cmd, status, err := devcontainer_service.GetTerminalCommand(ctx, query.Get("user"), ctx.Repo.Repository)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
status = "error"
|
|
}
|
|
ctx.JSON(http.StatusOK, map[string]string{"command": cmd, "status": status})
|
|
}
|
|
|
|
func GetDevContainerOutput(ctx *context.Context) {
|
|
// 设置 CORS 响应头
|
|
ctx.Resp.Header().Set("Access-Control-Allow-Origin", "*")
|
|
ctx.Resp.Header().Set("Access-Control-Allow-Methods", "*")
|
|
ctx.Resp.Header().Set("Access-Control-Allow-Headers", "*")
|
|
output, err := devcontainer_service.GetDevContainerOutput(ctx, ctx.Doer, ctx.Repo.Repository)
|
|
if err != nil {
|
|
log.Info(err.Error())
|
|
}
|
|
ctx.JSON(http.StatusOK, output)
|
|
}
|