-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add basic attempt at local module handling
The idea here is to support a new formatting section, `module`, which is the module we're currently running in as a replacement for `prefix(module/we/are/running/in)`. This attempt is very basic: if the `module` section is requested it: * Looks for a `go.mod` in the current directory or any parent directory, or errors if we can't find or read it (this is to make it clear when something goes wrong, compared to seeing a confusing "No section found for Import" error later * Stores the module path from `go.mod` * Looks for imports that have that path as a prefix when specifying ordering This attempt intentionally simple and does not try to handle workspaces
- Loading branch information
1 parent
19d84f7
commit 112d948
Showing
8 changed files
with
190 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package section | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"golang.org/x/mod/modfile" | ||
|
||
"github.com/daixiang0/gci/pkg/parse" | ||
"github.com/daixiang0/gci/pkg/specificity" | ||
) | ||
|
||
const moduleType = "module" | ||
|
||
type Module struct { | ||
ModulePaths []string | ||
} | ||
|
||
func (m *Module) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecificity { | ||
for _, modPath := range m.ModulePaths { | ||
if strings.HasPrefix(spec.Path, modPath) { | ||
return specificity.Module{} | ||
} | ||
} | ||
|
||
return specificity.MisMatch{} | ||
} | ||
|
||
func (m *Module) String() string { | ||
return moduleType | ||
} | ||
|
||
func (m *Module) Type() string { | ||
return moduleType | ||
} | ||
|
||
func (m *Module) Populate() error { | ||
dir, err := os.Getwd() | ||
if err != nil { | ||
// TODO: warn | ||
return nil | ||
} | ||
modFile := findModule(dir) | ||
if modFile == "" { | ||
return fmt.Errorf("local module lookup was requested, but could not find module file") | ||
} | ||
|
||
modContent, err := os.ReadFile(modFile) | ||
if err != nil { | ||
return fmt.Errorf("failed to read %s: %v", modFile, err) | ||
} | ||
|
||
modPath := modfile.ModulePath(modContent) | ||
if modPath == "" { | ||
return fmt.Errorf("could not read module path from %s", modFile) | ||
} | ||
|
||
m.ModulePaths = []string{modPath} | ||
return nil | ||
} | ||
|
||
func findModule(dir string) string { | ||
// Look for enclosing go.mod. | ||
for { | ||
target := filepath.Join(dir, "go.mod") | ||
if fi, err := os.Stat(target); err == nil && !fi.IsDir() { | ||
return target | ||
} | ||
d := filepath.Dir(dir) | ||
if d == dir { | ||
break | ||
} | ||
dir = d | ||
} | ||
return "" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package section | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/daixiang0/gci/pkg/log" | ||
) | ||
|
||
func init() { | ||
log.InitLogger() | ||
defer log.L().Sync() | ||
} | ||
|
||
func runWithDir(t *testing.T, dir string) { | ||
oldWd, err := os.Getwd() | ||
require.NoError(t, err) | ||
t.Cleanup(func() { require.NoError(t, os.Chdir(oldWd)) }) | ||
|
||
require.NoError(t, os.Chdir(dir)) | ||
} | ||
|
||
func TestPopulateFailsIfNoGoMod(t *testing.T) { | ||
dir := t.TempDir() | ||
runWithDir(t, dir) | ||
|
||
m := &Module{} | ||
assert.ErrorContains(t, m.Populate(), "local module lookup was requested, but could not find module file") | ||
} | ||
|
||
func TestPopulateFailsIfUnreadableGoMod(t *testing.T) { | ||
dir := t.TempDir() | ||
runWithDir(t, dir) | ||
modPath := filepath.Join(dir, "go.mod") | ||
|
||
_, err := os.Create(modPath) | ||
require.NoError(t, err) | ||
require.NoError(t, os.Chmod(modPath, 0o002)) | ||
|
||
m := &Module{} | ||
assert.ErrorContains(t, m.Populate(), "failed to read ") | ||
} | ||
|
||
func TestPopulateFailsIfInvalidGoMod(t *testing.T) { | ||
dir := t.TempDir() | ||
runWithDir(t, dir) | ||
modPath := filepath.Join(dir, "go.mod") | ||
|
||
modContents := "not a valid go.mod" | ||
require.NoError(t, os.WriteFile(modPath, []byte(modContents), 0o644)) | ||
|
||
m := &Module{} | ||
assert.ErrorContains(t, m.Populate(), "could not read module path from ") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package specificity | ||
|
||
type Module struct{} | ||
|
||
func (m Module) IsMoreSpecific(than MatchSpecificity) bool { | ||
return isMoreSpecific(m, than) | ||
} | ||
|
||
func (m Module) Equal(to MatchSpecificity) bool { | ||
return equalSpecificity(m, to) | ||
} | ||
|
||
func (Module) class() specificityClass { | ||
return ModuleClass | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters