feat(vendordep): add vendordep management

- Add vendordep add
- Add vendordep remove
- Add vendordep list
- Refactor downloading
This commit is contained in:
2025-10-17 14:15:37 -04:00
parent e073c0d391
commit 2a22f41fac
18 changed files with 1099 additions and 184 deletions

147
cmd/vendordepadd.go Normal file
View File

@@ -0,0 +1,147 @@
package cmd
import (
"encoding/json"
"log/slog"
"net/http"
"os"
"path/filepath"
"rph/cmd/template"
"rph/cmd/vendordep"
"rph/cmd/vendordep/artifactory"
"rph/utils"
"strings"
"github.com/spf13/cobra"
)
// vendordepaddCmd represents the vendordep add command
var vendordepaddCmd = &cobra.Command{
Use: "add",
Short: "Add a new vendordep",
Long: `Add a new vendordep. You may pass in as many urls or vendordep names
as you wish. The vendordep names are determined by what's found at
https://frcmaven.wpi.edu/ui/native/vendordeps/`,
Args: cobra.MinimumNArgs(1),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
year, err := cmd.Flags().GetString("year")
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
if year == "" {
file, err := os.Open(filepath.Join(projectDir, ".wpilib", "wpilib_preferences.json"))
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
defer file.Close()
var wpilibPrefs template.WpilibPreferences
if err := json.NewDecoder(file).Decode(&wpilibPrefs); err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
year = wpilibPrefs.Year
}
// TODO: refactor this into it's own func, cache it and then we can make
// less api calls
validVendordeps, err := vendordep.ListAvailableOnlineDeps(year)
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
var completions []string
for k, deps := range validVendordeps {
for _, dep := range deps {
comp := k + "-" + dep.Version
if strings.HasPrefix(comp, toComplete) {
completions = append(completions, comp)
}
}
}
return completions, cobra.ShellCompDirectiveNoFileComp
},
RunE: func(cmd *cobra.Command, args []string) error {
if !inProjectDir() { return nil }
year, err := cmd.Flags().GetString("year")
if err != nil { return err }
if year == "" {
file, err := os.Open(filepath.Join(projectDir, ".wpilib", "wpilib_preferences.json"))
if err != nil {
slog.Error("Failed to open wpilib_preferences.json", "error", err)
return err
}
defer file.Close()
var wpilibPrefs template.WpilibPreferences
if err := json.NewDecoder(file).Decode(&wpilibPrefs); err != nil {
slog.Error("Failed to decode wpilib_preferences.json", "error", err)
return err
}
year = wpilibPrefs.Year
}
fsys := artifactory.New(artifactory.DefaultVendorDepArtifactoryUrl)
path := "vendordeps/vendordep-marketplace/" + year
// make sure the vendordep directory exists in the current project
os.MkdirAll(filepath.Join(projectDir, "vendordeps"), 0755);
for _, arg := range args {
if strings.HasPrefix(arg, "http") {
resp, err := http.Get(arg)
if err != nil {
slog.Error("Failed to download file", "url", arg, "error", err)
return err
}
defer resp.Body.Close()
dep, err := vendordep.Parse(resp.Body)
if err != nil {
slog.Error("Failed to parse vendor dep", "error", err)
return err
}
err = utils.DownloadFile(arg, filepath.Join(projectDir, "vendordeps", dep.FileName))
if err != nil {
slog.Error("Failed to download vendordep", "error", err)
}
} else {
vendordeps, err := vendordep.ListAvailableOnlineDeps(year)
if err != nil {
return err
}
for k, deps := range vendordeps {
for _, dep := range deps {
d := k + "-" + dep.Version
if d == arg {
url := fsys.GetUrl(path + "/" + dep.FileName)
err := utils.DownloadFile(url, filepath.Join(projectDir, "vendordeps", dep.FileName))
if err != nil {
slog.Error("Failed to copy the file to the filesystem", "error", err)
return err
}
break
}
}
}
}
}
// TODO: tell the user to gradle build
return nil
},
}
func init() {
vendordepCmd.AddCommand(vendordepaddCmd)
vendordepaddCmd.Flags().StringP("year", "y", "", "override the year to search for dependencies in frcmaven.")
}