package commands import ( "fmt" "os" "path/filepath" "slices" "strings" "gitea.codeblob.work/pk/hoster/internals/conf" "gitea.codeblob.work/pk/hoster/internals/helpers" "gitea.codeblob.work/pk/hoster/internals/templates" "gitea.codeblob.work/pk/hoster/internals/types" "github.com/gookit/goutil/fsutil" "github.com/gookit/goutil/sysutil/cmdr" "github.com/kataras/golog" "github.com/urfave/cli/v2" ) func CmdNew(c *cli.Context) error { if os.Getuid() != 0 { golog.Fatalf("You need to run this command as root.") } name := strings.TrimSpace(c.String("name")) domain := strings.TrimSpace(c.String("domain")) customProjectPath := strings.TrimSpace(c.String("custom-path")) projectRoot := conf.App.MustString("projects.root") sitesAvail := conf.App.MustString("nginx.sitesAvailable") sitesEnabled := conf.App.MustString("nginx.sitesEnabled") nginxFile := filepath.Join(sitesAvail, name) projectFolder := filepath.Join(projectRoot, name) if customProjectPath != "" { projectFolder = customProjectPath } existingProjects, err := helpers.FindHostConfigs(sitesAvail) if err != nil { return err } usedPorts := []int{} for _, project := range existingProjects { usedPorts = append(usedPorts, project.InternalPort) } port := conf.App.Int("nginx.portRangeStart") freePort := 0 for port <= conf.App.Int("nginx.portRangeEnd") { if !slices.Contains(usedPorts, port) && helpers.IsFreePort(port) { freePort = port break } port++ } if freePort == 0 { return fmt.Errorf("no free port available") } if !fsutil.IsDir(projectFolder) { golog.Infof("Creating project folder '%s'", projectFolder) err := os.MkdirAll(projectFolder, 0755) if err != nil { return err } } if fsutil.IsFile(nginxFile) { return fmt.Errorf("the nginx config file '%s' already exists", nginxFile) } // Set owner and group of project folder err = os.Chown(projectFolder, conf.App.Int("projects.owner"), conf.App.Int("projects.group")) if err != nil { return err } project := types.Project{ Name: name, Domain: domain, InternalPort: freePort, } // Create nginx config file err = templates.Execute("nginx", nginxFile, project) if err != nil { return err } // Symlink nginx config file err = os.Symlink(nginxFile, filepath.Join(sitesEnabled, name)) if err != nil { return err } // Execute certbot command: "systemctl stop nginx && sudo certbot certonly --standalone --preferred-challenges http -d {domain} && sudo systemctl start nginx" com := cmdr.NewCmd("systemctl"). WithArgs([]string{"stop", "nginx"}) _, err = com.Output() if err != nil { return err } com = cmdr.NewCmd("certbot"). WithArgs([]string{"certonly", "--standalone", "--preferred-challenges", "http", "-d", domain}) _, err = com.Output() if err != nil { return err } com = cmdr.NewCmd("systemctl"). WithArgs([]string{"start", "nginx"}) _, err = com.Output() if err != nil { return err } golog.Infof("Project successfully '%s' created. Uses port %d.", name, freePort) return nil }