-
Notifications
You must be signed in to change notification settings - Fork 11
refactor(platformifier): use fs.FS and return file map #261
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: refactor/abstract-fs
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,8 @@ import ( | |||||||||||||||||||||
| "errors" | ||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||
| "io" | ||||||||||||||||||||||
| "os" | ||||||||||||||||||||||
| "path" | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| "github.com/spf13/cobra" | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
@@ -39,11 +41,7 @@ func Platformify(ctx context.Context, stdout, stderr io.Writer, assets *vendoriz | |||||||||||||||||||||
| answers := models.NewAnswers() | ||||||||||||||||||||||
| answers.Flavor, _ = ctx.Value(FlavorKey).(string) | ||||||||||||||||||||||
| ctx = models.ToContext(ctx, answers) | ||||||||||||||||||||||
| ctx = colors.ToContext( | ||||||||||||||||||||||
| ctx, | ||||||||||||||||||||||
| stdout, | ||||||||||||||||||||||
| stderr, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| ctx = colors.ToContext(ctx, stdout, stderr) | ||||||||||||||||||||||
| q := questionnaire.New( | ||||||||||||||||||||||
| &question.WorkingDirectory{}, | ||||||||||||||||||||||
| &question.FilesOverwrite{}, | ||||||||||||||||||||||
|
|
@@ -76,12 +74,24 @@ func Platformify(ctx context.Context, stdout, stderr io.Writer, assets *vendoriz | |||||||||||||||||||||
| input := answers.ToUserInput() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pfier := platformifier.New(input, assets.ConfigFlavor) | ||||||||||||||||||||||
| err = pfier.Platformify(ctx) | ||||||||||||||||||||||
| configFiles, err := pfier.Platformify(ctx) | ||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||
| fmt.Fprintln(stderr, colors.Colorize(colors.ErrorCode, err.Error())) | ||||||||||||||||||||||
| return fmt.Errorf("could not configure project: %w", err) | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| for file, contents := range configFiles { | ||||||||||||||||||||||
| filePath := path.Join(answers.Cwd, file) | ||||||||||||||||||||||
| if err := os.MkdirAll(path.Dir(filePath), os.ModeDir|os.ModePerm); err != nil { | ||||||||||||||||||||||
| fmt.Fprintf(stderr, "Could not create parent directories of file %s: %s\n", file, err) | ||||||||||||||||||||||
| continue | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| if err := os.WriteFile(filePath, contents, 0o664); err != nil { | ||||||||||||||||||||||
| fmt.Fprintf(stderr, "Could not write file %s: %s\n", file, err) | ||||||||||||||||||||||
| continue | ||||||||||||||||||||||
|
Comment on lines
+87
to
+91
|
||||||||||||||||||||||
| continue | |
| } | |
| if err := os.WriteFile(filePath, contents, 0o664); err != nil { | |
| fmt.Fprintf(stderr, "Could not write file %s: %s\n", file, err) | |
| continue | |
| return fmt.Errorf("could not create parent directories of file %s: %w", file, err) | |
| } | |
| if err := os.WriteFile(filePath, contents, 0o664); err != nil { | |
| fmt.Fprintf(stderr, "Could not write file %s: %s\n", file, err) | |
| return fmt.Errorf("could not write file %s: %w", file, err) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,6 @@ package question | |
| import ( | ||
| "context" | ||
| "fmt" | ||
| "path" | ||
| "path/filepath" | ||
| "slices" | ||
|
|
||
|
|
@@ -74,8 +73,9 @@ func (q *BuildSteps) Ask(ctx context.Context) error { | |
| ) | ||
| } | ||
| if _, ok := utils.GetJSONValue( | ||
| answers.WorkingDirectory, | ||
| []string{"scripts", "build"}, | ||
| path.Join(answers.WorkingDirectory, "package.json"), | ||
| "package.json", | ||
| true, | ||
| ); ok { | ||
| if dm == models.Yarn { | ||
|
|
@@ -100,7 +100,8 @@ func (q *BuildSteps) Ask(ctx context.Context) error { | |
| switch answers.Stack { | ||
| case models.Django: | ||
| if managePyPath := utils.FindFile( | ||
| path.Join(answers.WorkingDirectory, answers.ApplicationRoot), | ||
| answers.WorkingDirectory, | ||
| answers.ApplicationRoot, | ||
| managePyFile, | ||
| ); managePyPath != "" { | ||
| prefix := "" | ||
|
|
@@ -110,7 +111,7 @@ func (q *BuildSteps) Ask(ctx context.Context) error { | |
| prefix = "poetry run " | ||
| } | ||
|
|
||
| managePyPath, _ = filepath.Rel(path.Join(answers.WorkingDirectory, answers.ApplicationRoot), managePyPath) | ||
| managePyPath, _ = filepath.Rel(answers.ApplicationRoot, managePyPath) | ||
|
||
| assets, _ := vendorization.FromContext(ctx) | ||
| answers.BuildSteps = append( | ||
| answers.BuildSteps, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,7 +3,6 @@ package question | |||||||
| import ( | ||||||||
| "context" | ||||||||
| "fmt" | ||||||||
| "path" | ||||||||
| "path/filepath" | ||||||||
| "slices" | ||||||||
|
|
||||||||
|
|
@@ -21,9 +20,9 @@ func (q *DeployCommand) Ask(ctx context.Context) error { | |||||||
|
|
||||||||
| switch answers.Stack { | ||||||||
| case models.Django: | ||||||||
| managePyPath := utils.FindFile(path.Join(answers.WorkingDirectory, answers.ApplicationRoot), managePyFile) | ||||||||
| managePyPath := utils.FindFile(answers.WorkingDirectory, answers.ApplicationRoot, managePyFile) | ||||||||
| if managePyPath != "" { | ||||||||
| managePyPath, _ = filepath.Rel(path.Join(answers.WorkingDirectory, answers.ApplicationRoot), managePyPath) | ||||||||
| managePyPath, _ = filepath.Rel(answers.ApplicationRoot, managePyPath) | ||||||||
|
||||||||
| managePyPath, _ = filepath.Rel(answers.ApplicationRoot, managePyPath) | |
| managePyPath, _ = filepath.Rel(answers.ApplicationRoot, managePyPath) | |
| managePyPath = filepath.ToSlash(managePyPath) |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ package models | |||||||||
|
|
||||||||||
| import ( | ||||||||||
| "encoding/json" | ||||||||||
| "io/fs" | ||||||||||
| "os" | ||||||||||
| "path/filepath" | ||||||||||
| "strings" | ||||||||||
|
|
@@ -10,23 +11,24 @@ import ( | |||||||||
| ) | ||||||||||
|
|
||||||||||
| type Answers struct { | ||||||||||
| Stack Stack `json:"stack"` | ||||||||||
| Flavor string `json:"flavor"` | ||||||||||
| Type RuntimeType `json:"type"` | ||||||||||
| Name string `json:"name"` | ||||||||||
| ApplicationRoot string `json:"application_root"` | ||||||||||
| Environment map[string]string `json:"environment"` | ||||||||||
| BuildSteps []string `json:"build_steps"` | ||||||||||
| WebCommand string `json:"web_command"` | ||||||||||
| SocketFamily SocketFamily `json:"socket_family"` | ||||||||||
| DeployCommand []string `json:"deploy_command"` | ||||||||||
| DependencyManagers []DepManager `json:"dependency_managers"` | ||||||||||
| Dependencies map[string]map[string]string `json:"dependencies"` | ||||||||||
| BuildFlavor string `json:"build_flavor"` | ||||||||||
| Disk string `json:"disk"` | ||||||||||
| Mounts map[string]map[string]string `json:"mounts"` | ||||||||||
| Services []Service `json:"services"` | ||||||||||
| WorkingDirectory string `json:"working_directory"` | ||||||||||
| Stack Stack `json:"stack"` | ||||||||||
| Flavor string `json:"flavor"` | ||||||||||
| Type RuntimeType `json:"type"` | ||||||||||
| Name string `json:"name"` | ||||||||||
| ApplicationRoot string `json:"application_root"` | ||||||||||
| Environment map[string]string `json:"environment"` | ||||||||||
| BuildSteps []string `json:"build_steps"` | ||||||||||
| WebCommand string `json:"web_command"` | ||||||||||
| SocketFamily SocketFamily `json:"socket_family"` | ||||||||||
| DeployCommand []string `json:"deploy_command"` | ||||||||||
| DependencyManagers []DepManager `json:"dependency_managers"` | ||||||||||
| Dependencies map[string]map[string]string `json:"dependencies"` | ||||||||||
| BuildFlavor string `json:"build_flavor"` | ||||||||||
| Disk string `json:"disk"` | ||||||||||
| Mounts map[string]map[string]string `json:"mounts"` | ||||||||||
| Services []Service `json:"services"` | ||||||||||
| WorkingDirectory fs.FS | ||||||||||
| Cwd string | ||||||||||
|
Comment on lines
+30
to
+31
|
||||||||||
| WorkingDirectory fs.FS | |
| Cwd string | |
| WorkingDirectory fs.FS `json:"-"` | |
| Cwd string `json:"cwd"` |
Copilot
AI
Mar 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ToUserInput currently prefixes ApplicationRoot with an OS path separator (e.g., "/app" or "\app"). With the new fs.FS-based file discovery (fs.WalkDir/os.DirFS), leading separators (and Windows backslashes) make paths invalid for fs.FS operations and can prevent stack-specific platformifiers from finding project files. Consider keeping ApplicationRoot as a slash-separated relative path for fs traversal, and only rendering a leading "/" (if needed) at template time.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,7 +30,7 @@ func (q *Name) Ask(ctx context.Context) error { | |
| } | ||
|
|
||
| question := &survey.Input{ | ||
| Message: "Tell us your project's application name:", Default: slugify(path.Base(answers.WorkingDirectory)), | ||
| Message: "Tell us your project's application name:", Default: slugify(path.Base(answers.Cwd)), | ||
| } | ||
|
Comment on lines
+33
to
34
|
||
|
|
||
| var name string | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code uses the path package (slash-based) to build OS file paths (answers.Cwd + template paths). On Windows, path.Join/path.Dir won’t handle volume names or separators correctly. Prefer filepath.Join/filepath.Dir for OS paths, and use a standard dir/file mode (e.g., 0o755 for MkdirAll and 0o644 for WriteFile) rather than os.ModeDir|os.ModePerm.