Files
rph/cmd/template/template.go

217 lines
6.3 KiB
Go

package template
import (
"context"
"encoding/json"
"fmt"
"io/fs"
"log/slog"
"os"
"path/filepath"
"regexp"
"rph/state"
"rph/utils"
"strings"
)
type TemplateOptions struct {
Lang string
ProjectType string
Dir string
Team uint64
DesktopSupport *bool
}
type WpilibPreferences struct {
CppIntellisense bool `json:"enableCppIntellisense"`
Lang string `json:"currentLanguage"`
Year string `json:"projectYear"`
Team int `json:"teamNumber"`
}
// Fetch fetch the latest template zip that's distributed by vscode-wpilib
func Fetch(force bool, version string) {
os.MkdirAll(filepath.Join(state.CachePath), 0755)
getTemplateArchive(zipFile, force, version);
}
func GenerateProject(opts TemplateOptions) {
opts, err := openConfigUi(opts)
if err != nil {
slog.Error("Failed to run interactive ui", "error", err)
return
}
err = os.Mkdir(opts.Dir, 0755)
if err != nil {
slog.Error("Failed to create directory", "path", opts.Dir, "error", err)
// TODO: how should we handle if the directory already exists?
}
fsys, err := OpenArchive(context.Background())
if err != nil {
slog.Error("Failed to open archive", "err", err)
return
}
subFS, err := fs.Sub(fsys, path.Join(opts.Lang, opts.ProjectType))
if err != nil {
slog.Error("Unable to find project template", "template", opts.ProjectType, "error", err)
}
err = os.CopyFS(opts.Dir, subFS)
if err != nil {
slog.Error("Failed to copy template to destination", "template",
opts.ProjectType, "destination", opts.Dir, "error", err)
os.Exit(1)
}
// Configure the project
err = os.Chmod(filepath.Join(opts.Dir, "gradlew"), 0755)
if err != nil {
slog.Error("Unable to make gradlew executable", "error", err)
}
{
jsonFile := filepath.Join(opts.Dir, ".wpilib", "wpilib_preferences.json")
file, err := os.Open(jsonFile)
if err != nil {
slog.Error(
"Failed to open wpilib preferences file\n\nYou need to put your team number into " +
opts.Dir + "/.wpilib/wpilib_preferences.json",
"error",
err,
)
goto PostJson
}
defer file.Close()
{ // scope it so I can jump over it
var p WpilibPreferences
decoder := json.NewDecoder(file)
err = decoder.Decode(&p)
if err != nil {
slog.Error("Failed to decode json", "error", err)
goto PostJson
}
p.Team = int(opts.Team)
jsonData, err := json.MarshalIndent(p, "", " ")
if err != nil {
slog.Error("Error marshaling JSON:", "error", err)
goto PostJson
}
err = os.WriteFile(jsonFile, jsonData, 0644)
if err != nil {
slog.Error("Error writing to file:", "error", err)
goto PostJson
}
}
PostJson:
}
// Enable desktop support
{
buildGradleFile := filepath.Join(opts.Dir, "build.gradle")
in, err := os.ReadFile(buildGradleFile)
if err != nil {
slog.Error("Failed to open gradle build file", "error", err)
goto PostGradle
}
{ // scope it so I can jump over it
value := "false"
if *opts.DesktopSupport {
value = "true"
}
// this regex was translated from:
// https://github.com/wpilibsuite/vscode-wpilib/blob/df7fc8bb9db453cbc9ccc32d3c5f81ef53f5e93a/vscode-wpilib/src/shared/generator.ts#L390
re := regexp.MustCompile(`(?m)^(\s*def\s+includeDesktopSupport\s*=\s*)(true|false)\b`)
out := re.ReplaceAllString(string(in), "${1}" + value)
err = os.WriteFile(buildGradleFile, []byte(out), 0644)
if err != nil {
slog.Error("failed to write to gradle build file", "error", err)
goto PostGradle
}
}
PostGradle:
}
// Generate example deploy file
{
deployPath := filepath.Join(opts.Dir, "src", "main", "deploy")
err := os.Mkdir(deployPath, 0755)
if err != nil {
slog.Error("Failed to make deploy directory", "error", err)
goto PostExampleDeploy
}
{ // Scope it so we can jump over it
var exampleTxt string
switch (opts.Lang) {
case "cpp":
exampleTxt = `Files placed in this directory will be deployed to the RoboRIO into the
'deploy' directory in the home folder. Use the 'frc::filesystem::GetDeployDirectory'
function from the 'frc/Filesystem.h' header to get a proper path relative to the deploy
directory.`
case "java":
exampleTxt = `Files placed in this directory will be deployed to the RoboRIO into the
'deploy' directory in the home folder. Use the 'Filesystem.getDeployDirectory' wpilib function
to get a proper path relative to the deploy directory.`
default:
exampleTxt = `Files placed in this directory will be deployed to the RoboRIO into the
'deploy' directory in the home folder.`
}
os.WriteFile(deployPath, []byte(exampleTxt), 0644)
}
PostExampleDeploy:
}
// Download the wpilib non-maven project specific vendor deps
// FIXME: these should all be cached with the deleted vendor deps, but I don't
// have time to do that right now so this will do for now.
{
projType := strings.ToLower(opts.ProjectType)
vendordepDir := filepath.Join(opts.Dir, "vendordeps")
os.Mkdir(vendordepDir, 0755)
version, err := LoadArchiveVersion()
if err != nil {
slog.Error("Unable to get arhive version", "error", err)
return
}
if strings.HasPrefix(projType, "xrp") {
url := fmt.Sprintf("https://raw.githubusercontent.com/wpilibsuite/allwpilib/%s/xrpVendordep/XRPVendordep.json", version)
err = utils.DownloadFile(url, filepath.Join(vendordepDir, "XRPVendordep.json"))
if err != nil {
slog.Error("Failed to download required vendor dep you should download it yourself", "url", url, "error", err)
return
}
} else if strings.HasPrefix(projType, "romi") {
url := fmt.Sprintf("https://raw.githubusercontent.com/wpilibsuite/allwpilib/%s/romiVendordep/RomiVendordep.json", version)
err = utils.DownloadFile(url, filepath.Join(vendordepDir, "RomiVendordep.json"))
if err != nil {
slog.Error("Failed to download required vendor dep you should download it yourself", "url", url, "error", err)
return
}
} else if strings.HasPrefix(projType, "command") {
// TODO: make sure there's no other project types this has to work with
url := fmt.Sprintf("https://raw.githubusercontent.com/wpilibsuite/allwpilib/%s/wpilibNewCommands/WPILibNewCommands.json", version)
err = utils.DownloadFile(url, filepath.Join(vendordepDir, "WPILibNewCommands.json"))
if err != nil {
slog.Error("Failed to download required vendor dep you should download it yourself", "url", url, "error", err)
return
}
}
}
}