From 2f39582916632a876890bb0c88786be462a9f28b Mon Sep 17 00:00:00 2001 From: Jasim Kannancherry Date: Sun, 22 Sep 2019 08:47:46 +0400 Subject: [PATCH 1/5] Sub folder template; initial commit --- pkg/boilr/configuration.go | 9 +++++++ pkg/cmd/download.go | 48 ++++++++++++++++++++++++++++++++++++-- pkg/cmd/root.go | 1 + pkg/util/osutil/fs.go | 5 ++++ 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/pkg/boilr/configuration.go b/pkg/boilr/configuration.go index 8dde458..3d3ff60 100644 --- a/pkg/boilr/configuration.go +++ b/pkg/boilr/configuration.go @@ -27,6 +27,9 @@ const ( // TemplateDir is the directory that contains the template registry TemplateDir = "templates" + // TemplateTempDir is the directory that is used for temporary storage + TemplateTempDir = "tmp" + // ContextFileName is the name of the file that contains the context values for the template ContextFileName = "project.json" @@ -57,6 +60,12 @@ func TemplatePath(name string) (string, error) { return filepath.Join(Configuration.TemplateDirPath, name), nil } +// TemplateTempPath returns absolute path of template temporary directory given name of template. +func TemplateTempPath(name string) (string, error) { + return filepath.Join(Configuration.TemplateDirPath, TemplateTempDir, name), nil +} + +// IsTemplateDirInitialized Checks if template directory is initialized func IsTemplateDirInitialized() (bool, error) { return osutil.DirExists(Configuration.TemplateDirPath) } diff --git a/pkg/cmd/download.go b/pkg/cmd/download.go index d642d73..2358bff 100644 --- a/pkg/cmd/download.go +++ b/pkg/cmd/download.go @@ -27,13 +27,15 @@ var Download = &cli.Command{ MustValidateTemplateDir() - templateURL, templateName := args[0], args[1] + templateURL, templateName, templateSubFolder := args[0], args[1], GetStringFlag(c, "sub-path") targetDir, err := boilr.TemplatePath(templateName) if err != nil { exit.Error(fmt.Errorf("download: %s", err)) } + targetTmpDir := targetDir + switch exists, err := osutil.DirExists(targetDir); { case err != nil: exit.Error(fmt.Errorf("download: %s", err)) @@ -47,14 +49,56 @@ var Download = &cli.Command{ exit.Error(fmt.Errorf("download: %s", err)) } } + // In case if we are copying template from repository sub-folder, clone repo to temp folder + if templateSubFolder != "" { + targetTmpDir, err = boilr.TemplateTempPath(templateName) + if err != nil { + exit.Error(fmt.Errorf("download: %s", err)) + } + exists, err := osutil.DirExists(targetTmpDir) + if exists || (!exists && err != nil) { + if err := os.RemoveAll(targetTmpDir); err != nil { + exit.Error(fmt.Errorf("download: %s", err)) + } + } + } // TODO(tmrts): allow fetching other branches than 'master' - if err := git.Clone(targetDir, git.CloneOptions{ + if err := git.Clone(targetTmpDir, git.CloneOptions{ URL: host.URL(templateURL), }); err != nil { exit.Error(fmt.Errorf("download: %s", err)) } + // Copy content from sub-folder to target folder + if templateSubFolder != "" { + // Ensure sub-folder exists + templateTmpDir := osutil.JoinPaths(targetTmpDir, templateSubFolder) + exists, err := osutil.DirExists(templateTmpDir) + if err != nil { + exit.Error(fmt.Errorf("download: %s", err)) + } + if !exists { + exit.Error(fmt.Errorf("download: sub-folder doesn't exist")) + } + // Check target folder exists, and copy contents + if exists, err = osutil.DirExists(targetDir); err != nil { + exit.Error(fmt.Errorf("download: %s", err)) + } + if !exists { + if err = osutil.CreateDirs(targetDir); err != nil { + exit.Error(fmt.Errorf("download: %s", err)) + + } + } + if err = osutil.CopyRecursively(templateTmpDir, targetDir); err != nil { + exit.Error(fmt.Errorf("download: Error copying files from temp %s", err)) + } + // Delete all temp files + if err := os.RemoveAll(targetTmpDir); err != nil { + exit.Error(fmt.Errorf("download: Error deleting temp files %s", err)) + } + } // TODO(tmrts): use git-notes as metadata storage or boltdb if err := serializeMetadata(templateName, templateURL, targetDir); err != nil { exit.Error(fmt.Errorf("download: %s", err)) diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index ed42596..27ceaa5 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -23,6 +23,7 @@ func Run() { Download.PersistentFlags().BoolP("force", "f", false, "Overwrite existing template with the same name") Download.PersistentFlags().StringP("log-level", "l", "error", "log-level for output") + Download.PersistentFlags().StringP("sub-path", "p", "", "Path inside the git repo where 'template' folder.") Template.AddCommand(Download) List.PersistentFlags().BoolP("dont-prettify", "", false, "Print only the template names without fancy formatting") diff --git a/pkg/util/osutil/fs.go b/pkg/util/osutil/fs.go index ca8a9e1..5f57e48 100644 --- a/pkg/util/osutil/fs.go +++ b/pkg/util/osutil/fs.go @@ -7,6 +7,11 @@ import ( "path/filepath" ) +// JoinPaths joins multiple paths together +func JoinPaths(paths ...string) string { + return filepath.Join(paths...) +} + // FileExists checks whether the given path exists and belongs to a file. func FileExists(path string) (bool, error) { info, err := os.Stat(path) From 64a60f6d37f4ec534be8173c1c79b31ea3ad4440 Mon Sep 17 00:00:00 2001 From: Jasim Kannancherry Date: Sun, 22 Sep 2019 08:50:30 +0400 Subject: [PATCH 2/5] Added a make file --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d3f2ee1 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +test: + go test ./... +build: + go build \ No newline at end of file From 4db107075e0ddb3dfdbe6f3c6fe35ac4ec3a80d6 Mon Sep 17 00:00:00 2001 From: Jasim Kannancherry Date: Sun, 22 Sep 2019 09:10:26 +0400 Subject: [PATCH 3/5] Fixing failing tests --- pkg/prompt/prompt_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/prompt/prompt_test.go b/pkg/prompt/prompt_test.go index 3e3b93c..28deb18 100644 --- a/pkg/prompt/prompt_test.go +++ b/pkg/prompt/prompt_test.go @@ -49,7 +49,7 @@ func TestNewBooleanPromptFunc(t *testing.T) { expectedPromptMsg := "Please choose a value for \"fieldName\"" if msg != expectedPromptMsg { - t.Errorf("boolPrompt(%q).PromptMessage(%q) expected %q got %q", defval, name, expectedPromptMsg, msg) + t.Errorf("boolPrompt((%v).PromptMessage(%q) expected %q got %q", defval, name, expectedPromptMsg, msg) } choiceCases := []struct { @@ -73,7 +73,7 @@ func TestNewBooleanPromptFunc(t *testing.T) { for _, c := range choiceCases { val, err := boolPrompt.EvaluateChoice(c.choice) if err != nil { - t.Errorf("boolPrompt(%q).EvaluateChoice(%q) got error %q", defval, c.choice, err) + t.Errorf("boolPrompt(%v).EvaluateChoice(%q) got error %q", defval, c.choice, err) continue } From 338fd0563dcb083c654f3344a08bfc1b85e949e8 Mon Sep 17 00:00:00 2001 From: Jasim Kannancherry Date: Mon, 23 Sep 2019 12:19:24 +0400 Subject: [PATCH 4/5] Allow cloning from a branch in boiler --- pkg/cmd/download.go | 19 ++++++++++++++----- pkg/cmd/root.go | 1 + 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/pkg/cmd/download.go b/pkg/cmd/download.go index 2358bff..6eae9c0 100644 --- a/pkg/cmd/download.go +++ b/pkg/cmd/download.go @@ -4,6 +4,8 @@ import ( "fmt" "os" + "gopkg.in/src-d/go-git.v4/plumbing" + cli "github.com/spf13/cobra" "github.com/tmrts/boilr/pkg/boilr" @@ -27,9 +29,11 @@ var Download = &cli.Command{ MustValidateTemplateDir() - templateURL, templateName, templateSubFolder := args[0], args[1], GetStringFlag(c, "sub-path") - + templateURL, templateName := args[0], args[1] + templateSubFolder := GetStringFlag(c, "sub-path") + templateRemoteBranch := GetStringFlag(c, "branch") targetDir, err := boilr.TemplatePath(templateName) + if err != nil { exit.Error(fmt.Errorf("download: %s", err)) } @@ -64,10 +68,15 @@ var Download = &cli.Command{ } // TODO(tmrts): allow fetching other branches than 'master' - if err := git.Clone(targetTmpDir, git.CloneOptions{ + gitCloneOptions := git.CloneOptions{ URL: host.URL(templateURL), - }); err != nil { - exit.Error(fmt.Errorf("download: %s", err)) + } + if templateRemoteBranch != "" { + gitCloneOptions.ReferenceName = plumbing.NewBranchReferenceName(templateRemoteBranch) + } + fmt.Println(gitCloneOptions) + if err := git.Clone(targetTmpDir, gitCloneOptions); err != nil { + exit.Error(fmt.Errorf("download: Cloning repo - %s", err)) } // Copy content from sub-folder to target folder diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 27ceaa5..fe3be09 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -23,6 +23,7 @@ func Run() { Download.PersistentFlags().BoolP("force", "f", false, "Overwrite existing template with the same name") Download.PersistentFlags().StringP("log-level", "l", "error", "log-level for output") + Download.PersistentFlags().StringP("branch", "b", "", "Branch, Commit Id, Tag or other reference to checkout") Download.PersistentFlags().StringP("sub-path", "p", "", "Path inside the git repo where 'template' folder.") Template.AddCommand(Download) From 20870ae62a07550795194368681f380d9233234c Mon Sep 17 00:00:00 2001 From: Jasim Kannancherry Date: Mon, 23 Sep 2019 13:14:16 +0400 Subject: [PATCH 5/5] Completing implementation of downloading template from multi branch, multitemplate repo --- README.md | 6 ++++++ pkg/boilr/configuration.go | 2 +- pkg/cmd/download.go | 15 +++++++++++---- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e4dbe4e..835b470 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,12 @@ boilr template download boilr template download tmrts/boilr-license license ``` +An example for multi template, multi branch forced repo clone + +``` +boilr template download -p template2/templates/sample -b multi-branch -f https://github.com/jasimmk/boilr-test.git sample +``` + The downloaded template will be saved to local `boilr` registry. ## Save a Local Template diff --git a/pkg/boilr/configuration.go b/pkg/boilr/configuration.go index 3d3ff60..db85de0 100644 --- a/pkg/boilr/configuration.go +++ b/pkg/boilr/configuration.go @@ -28,7 +28,7 @@ const ( TemplateDir = "templates" // TemplateTempDir is the directory that is used for temporary storage - TemplateTempDir = "tmp" + TemplateTempDir = "../tmp" // ContextFileName is the name of the file that contains the context values for the template ContextFileName = "project.json" diff --git a/pkg/cmd/download.go b/pkg/cmd/download.go index 6eae9c0..e4cd358 100644 --- a/pkg/cmd/download.go +++ b/pkg/cmd/download.go @@ -29,17 +29,16 @@ var Download = &cli.Command{ MustValidateTemplateDir() - templateURL, templateName := args[0], args[1] templateSubFolder := GetStringFlag(c, "sub-path") templateRemoteBranch := GetStringFlag(c, "branch") + templateURL, templateName := args[0], args[1] targetDir, err := boilr.TemplatePath(templateName) + targetTmpDir := targetDir if err != nil { exit.Error(fmt.Errorf("download: %s", err)) } - targetTmpDir := targetDir - switch exists, err := osutil.DirExists(targetDir); { case err != nil: exit.Error(fmt.Errorf("download: %s", err)) @@ -73,8 +72,8 @@ var Download = &cli.Command{ } if templateRemoteBranch != "" { gitCloneOptions.ReferenceName = plumbing.NewBranchReferenceName(templateRemoteBranch) + gitCloneOptions.SingleBranch = true } - fmt.Println(gitCloneOptions) if err := git.Clone(targetTmpDir, gitCloneOptions); err != nil { exit.Error(fmt.Errorf("download: Cloning repo - %s", err)) } @@ -108,6 +107,14 @@ var Download = &cli.Command{ exit.Error(fmt.Errorf("download: Error deleting temp files %s", err)) } } + // Ensure that a 'template' folder exists inside the repo before registering template + exists, err := osutil.DirExists(osutil.JoinPaths(targetDir, boilr.TemplateDirName)) + if err != nil { + exit.Error(fmt.Errorf("download: Template error - %s", err)) + } + if !exists { + exit.Error(fmt.Errorf("download: Invalid template. Folder '%s' - doesn't exist at %s", boilr.TemplateDirName, targetDir)) + } // TODO(tmrts): use git-notes as metadata storage or boltdb if err := serializeMetadata(templateName, templateURL, targetDir); err != nil { exit.Error(fmt.Errorf("download: %s", err))