From 0e199faad2b3e71a4ddb25a1890389e02c7fc2d0 Mon Sep 17 00:00:00 2001 From: Maxime Corbin Date: Wed, 1 Dec 2021 22:07:59 +0100 Subject: [PATCH] Fix dependency handling (#81) * Fix dependency handling, boost now working * Fix CI --- adapter/defaultadapter/defaultadapter.go | 21 ++++ cmd/list.go | 12 ++- ctpm/add.go | 9 ++ ctpm/build.go | 43 ++++++-- ctpm/install.go | 7 +- ctpm/list.go | 132 ++++++++++++++++++++++- main.go | 2 +- 7 files changed, 205 insertions(+), 21 deletions(-) diff --git a/adapter/defaultadapter/defaultadapter.go b/adapter/defaultadapter/defaultadapter.go index b020ac9..90261e8 100644 --- a/adapter/defaultadapter/defaultadapter.go +++ b/adapter/defaultadapter/defaultadapter.go @@ -7,7 +7,9 @@ import ( "github.com/c3pm-labs/c3pm/cmake" "github.com/c3pm-labs/c3pm/config" "github.com/c3pm-labs/c3pm/config/manifest" + "os" "path/filepath" + "strings" ) // DefaultAdapter is the builtin adapter used by default in c3pm @@ -22,6 +24,20 @@ func New(adapterGetter adapter_interface.AdapterGetter) *DefaultAdapter { var CurrentVersion, _ = manifest.VersionFromString("0.0.1") +func isInCache(pc *config.ProjectConfig) bool { + root, _ := filepath.Abs(pc.ProjectRoot) + c3pmDir, _ := filepath.Abs(config.GlobalC3PMDirPath()) + if !strings.Contains(root, filepath.Join(c3pmDir, "cache")) { + // Project dir not in cache directory, skipping + return false + } + if _, err := os.Stat(filepath.Join(root, fmt.Sprintf("lib%s.a", pc.Manifest.Name))); err != nil { + // Lib file does not exist yet + return false + } + return true +} + func (a *DefaultAdapter) Build(pc *config.ProjectConfig) error { cmakeVariables := map[string]string{ "CMAKE_LIBRARY_OUTPUT_DIRECTORY": pc.ProjectRoot, @@ -48,6 +64,11 @@ func (a *DefaultAdapter) Build(pc *config.ProjectConfig) error { return nil } + // dont rebuild if already in cache + if pc.Manifest.Type == manifest.Library && isInCache(pc) { + return nil + } + err = generateCMakeScripts(cmakeDirFromPc(pc), pc, a.adapterGetter) if err != nil { return fmt.Errorf("error generating config files: %w", err) diff --git a/cmd/list.go b/cmd/list.go index 2f822f8..6ab67bc 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -7,6 +7,12 @@ import ( "github.com/spf13/cobra" ) +type ListCmdFlags struct { + ctpm.ListOptions +} + +var listCmdFlags = ListCmdFlags{} + var listCmd = &cobra.Command{ Use: "list", Short: "list all project dependencies", @@ -16,10 +22,14 @@ var listCmd = &cobra.Command{ if err != nil { return fmt.Errorf("failed to read c3pm.yml: %w", err) } - err = ctpm.List(pc) + err = ctpm.List(pc, listCmdFlags.ListOptions) if err != nil { return fmt.Errorf("failed to add dependencies: %w", err) } return nil }, } + +func init() { + listCmd.Flags().BoolVar(&listCmdFlags.Tree, "tree", ctpm.ListDefaultOptions.Tree, "List dependencies in indented tree form") +} diff --git a/ctpm/add.go b/ctpm/add.go index ed259ce..c81cabb 100644 --- a/ctpm/add.go +++ b/ctpm/add.go @@ -23,6 +23,15 @@ func Add(pc *config.ProjectConfig, opts AddOptions) error { if err != nil { return fmt.Errorf("error adding %s: %w", dep, err) } + libPath := config.LibCachePath(name, version.String()) + libPc, err := config.Load(libPath) + if err != nil { + return fmt.Errorf("failed to read c3pm.yml: %w", err) + } + err = Build(libPc) + if err != nil { + return err + } if pc.Manifest.Dependencies == nil { pc.Manifest.Dependencies = make(manifest.Dependencies) } diff --git a/ctpm/build.go b/ctpm/build.go index dddc7ea..0d71148 100644 --- a/ctpm/build.go +++ b/ctpm/build.go @@ -4,14 +4,20 @@ import ( "fmt" "github.com/Masterminds/semver/v3" "github.com/c3pm-labs/c3pm/adapter" + "github.com/c3pm-labs/c3pm/adapter_interface" "github.com/c3pm-labs/c3pm/config" "github.com/c3pm-labs/c3pm/config/manifest" "github.com/c3pm-labs/c3pm/dependencies" ) -type DependencyFetcher struct{} +type DependencyBuilder struct { + Done manifest.Dependencies +} -func (d DependencyFetcher) FetchDeps(request dependencies.PackageRequest) (dependencies.Dependencies, error) { +func (d DependencyBuilder) FetchDeps(request dependencies.PackageRequest) (dependencies.Dependencies, error) { + if _, ok := d.Done[request.Name]; ok { + return dependencies.Dependencies{}, nil + } libPath := config.LibCachePath(request.Name, request.Version) pc, err := config.Load(libPath) if err != nil { @@ -24,22 +30,39 @@ func (d DependencyFetcher) FetchDeps(request dependencies.PackageRequest) (depen return ret, nil } -func (d DependencyFetcher) PreAct(_ dependencies.PackageRequest) error { return nil } -func (d DependencyFetcher) PostAct(_ dependencies.PackageRequest) error { return nil } +func (d DependencyBuilder) PreAct(_ dependencies.PackageRequest) error { return nil } +func (d DependencyBuilder) PostAct(request dependencies.PackageRequest) error { + fmt.Printf("Building %s:%s\n", request.Name, request.Version) + + libPath := config.LibCachePath(request.Name, request.Version) + pc, err := config.Load(libPath) + if err != nil { + return fmt.Errorf("failed to read c3pm.yml: %w", err) + } + getter := adapter.AdapterGetterImp{} + var adp adapter_interface.Adapter + adp, err = getter.FromPC(pc.Manifest.Build.Adapter) + if err != nil { + return err + } + err = adp.Build(pc) + if err != nil { + return fmt.Errorf("error building: %w", err) + } + d.Done[fmt.Sprintf(request.Name)] = request.Version + return nil +} func getAllDependencies(pc *config.ProjectConfig) error { allDeps := make(manifest.Dependencies) + allDeps[pc.Manifest.Name] = pc.Manifest.Version.String() for name, version := range pc.Manifest.Dependencies { - deps, err := dependencies.Install(dependencies.PackageRequest{Name: name, Version: version}, DependencyFetcher{}) + _, err := dependencies.Install(dependencies.PackageRequest{Name: name, Version: version}, DependencyBuilder{Done: allDeps}) if err != nil { return err } - for dname, dversions := range deps { - for dversion := range dversions { - allDeps[dname] = dversion - } - } } + delete(allDeps, pc.Manifest.Name) pc.Manifest.Dependencies = allDeps return nil } diff --git a/ctpm/install.go b/ctpm/install.go index 6a47abe..25be51c 100644 --- a/ctpm/install.go +++ b/ctpm/install.go @@ -33,14 +33,13 @@ func (i InstallHandler) PreAct(request dependencies.PackageRequest) error { } func (i InstallHandler) PostAct(request dependencies.PackageRequest) error { - fmt.Printf("Building %s:%s\n", request.Name, request.Version) - // Build the lib + // Check that the lib has correctly been installed libPath := config.LibCachePath(request.Name, request.Version) - pc, err := config.Load(libPath) + _, err := config.Load(libPath) if err != nil { return fmt.Errorf("failed to read c3pm.yml: %w", err) } - return Build(pc) + return nil } // Install fetches the package, unpacks it in the c3pm cache and builds it. If the lib already is diff --git a/ctpm/list.go b/ctpm/list.go index 1d3901f..de443e2 100644 --- a/ctpm/list.go +++ b/ctpm/list.go @@ -3,16 +3,138 @@ package ctpm import ( "fmt" "github.com/c3pm-labs/c3pm/config" + "github.com/c3pm-labs/c3pm/config/manifest" + "github.com/c3pm-labs/c3pm/dependencies" + "strings" ) -func List(pc *config.ProjectConfig) error { - err := getAllDependencies(pc) +type ListOptions struct { + Tree bool +} + +var ListDefaultOptions = ListOptions{ + Tree: false, +} + +type DependencyNode struct { + Children []*DependencyNode + Name string +} + +func (d DependencyNode) String() string { + sb := strings.Builder{} + sb.WriteString(d.Name) + sb.WriteString(": ") + sb.WriteString("[") + for i := 0; i < len(d.Children); i++ { + sb.WriteString(d.Children[i].Name) + if i < len(d.Children)-1 { + sb.WriteString(", ") + } + } + sb.WriteString("]") + return sb.String() +} + +type DependencyBranch []*DependencyNode + +func (d DependencyBranch) String() string { + sb := strings.Builder{} + sb.WriteString("[") + for i := 0; i < len(d); i++ { + sb.WriteString(d[i].Name) + if i < len(d)-1 { + sb.WriteString(", ") + } + } + sb.WriteString("]") + return sb.String() +} + +type DependencyFetcher struct { + Done manifest.Dependencies + CurrentNode *DependencyNode + CurrentBranch DependencyBranch +} + +func (d *DependencyFetcher) FetchDeps(request dependencies.PackageRequest) (dependencies.Dependencies, error) { + if _, ok := d.Done[request.Name]; ok { + return dependencies.Dependencies{}, nil + } + // Find new current node + var currentNode *DependencyNode = nil + found := false + for !found { + for _, node := range d.CurrentNode.Children { + if node.Name == fmt.Sprintf("%s@%s", request.Name, request.Version) { + found = true + d.CurrentBranch = append(d.CurrentBranch, node) + currentNode = node + } + } + if !found { + // Move up one level + d.CurrentBranch = d.CurrentBranch[:len(d.CurrentBranch)-1] + d.CurrentNode = d.CurrentBranch[len(d.CurrentBranch)-1] + } + } + d.Done[request.Name] = request.Version + libPath := config.LibCachePath(request.Name, request.Version) + pc, err := config.Load(libPath) if err != nil { - return err + return nil, fmt.Errorf("failed to read c3pm.yml: %w", err) + } + ret := make(dependencies.Dependencies) + for k, v := range pc.Manifest.Dependencies { + ret[k] = v + currentNode.Children = append(currentNode.Children, &DependencyNode{Name: fmt.Sprintf("%s@%s", k, v), Children: []*DependencyNode{}}) + } + d.CurrentNode = currentNode + return ret, nil +} + +func (d *DependencyFetcher) PreAct(_ dependencies.PackageRequest) error { + return nil +} + +func (d *DependencyFetcher) PostAct(_ dependencies.PackageRequest) error { + return nil +} + +func displayTree(root *DependencyNode, under string) { + fmt.Printf("───%s\n", root.Name) + for i := 0; i < len(root.Children); i++ { + if i < len(root.Children)-1 { + fmt.Printf("%s├", under) + displayTree(root.Children[i], fmt.Sprintf("%s%s", under, "│ ")) + } else { + fmt.Printf("%s└", under) + displayTree(root.Children[i], fmt.Sprintf("%s%s", under, " ")) + } + } +} + +func List(pc *config.ProjectConfig, opt ListOptions) error { + var topLevelDeps []*DependencyNode + for name, version := range pc.Manifest.Dependencies { + topLevelDeps = append(topLevelDeps, &DependencyNode{Name: fmt.Sprintf("%s@%s", name, version), Children: []*DependencyNode{}}) + } + treeRoot := &DependencyNode{Name: fmt.Sprintf("%s@%s", pc.Manifest.Name, pc.Manifest.Version), Children: topLevelDeps} + + allDeps := make(manifest.Dependencies) + for name, version := range pc.Manifest.Dependencies { + _, err := dependencies.Install(dependencies.PackageRequest{Name: name, Version: version}, &DependencyFetcher{Done: allDeps, CurrentNode: treeRoot, CurrentBranch: []*DependencyNode{treeRoot}}) + if err != nil { + return err + } } - for key, val := range pc.Manifest.Dependencies { - fmt.Printf("%s@%s\n", key, val) + if !opt.Tree { + for key, val := range allDeps { + fmt.Printf("%s@%s\n", key, val) + } + } else { + displayTree(treeRoot, " ") } return nil diff --git a/main.go b/main.go index aaec844..72f51ce 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,7 @@ import ( "github.com/c3pm-labs/c3pm/cmd" ) -var version = "dev" +var version = "1.0.0" func main() { cmd.RootCmd.Version = version