github.com/bosssauce/ponzu@v0.11.1-0.20200102001432-9bc41b703131/cmd/ponzu/new.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/spf13/cobra"
    11  )
    12  
    13  var newCmd = &cobra.Command{
    14  	Use:   "new [flags] <project name>",
    15  	Short: "creates a project directory of the name supplied as a parameter",
    16  	Long: `Creates a project directory of the name supplied as a parameter
    17  immediately following the 'new' option in the $GOPATH/src directory. Note:
    18  'new' depends on the program 'git' and possibly a network connection. If
    19  there is no local repository to clone from at the local machine's $GOPATH,
    20  'new' will attempt to clone the 'github.com/ponzu-cms/ponzu' package from
    21  over the network.`,
    22  	Example: `$ ponzu new github.com/nilslice/proj
    23  > New ponzu project created at $GOPATH/src/github.com/nilslice/proj`,
    24  	RunE: func(cmd *cobra.Command, args []string) error {
    25  		projectName := "ponzu"
    26  		if len(args) > 0 {
    27  			projectName = args[0]
    28  		} else {
    29  			msg := "Please provide a project name."
    30  			msg += "\nThis will create a directory within your $GOPATH/src."
    31  			return fmt.Errorf("%s", msg)
    32  		}
    33  		return newProjectInDir(projectName)
    34  	},
    35  }
    36  
    37  // name2path transforns a project name to an absolute path
    38  func name2path(projectName string) (string, error) {
    39  	gopath, err := getGOPATH()
    40  	if err != nil {
    41  		return "", err
    42  	}
    43  	gosrc := filepath.Join(gopath, "src")
    44  
    45  	path := projectName
    46  	// support current directory
    47  	if path == "." {
    48  		path, err = os.Getwd()
    49  		if err != nil {
    50  			return "", err
    51  		}
    52  	} else {
    53  		path = filepath.Join(gosrc, path)
    54  	}
    55  
    56  	// make sure path is inside $GOPATH/src
    57  	srcrel, err := filepath.Rel(gosrc, path)
    58  	if err != nil {
    59  		return "", err
    60  	}
    61  	if len(srcrel) >= 2 && srcrel[:2] == ".." {
    62  		return "", fmt.Errorf("path '%s' must be inside '%s'", projectName, gosrc)
    63  	}
    64  	if srcrel == "." {
    65  		return "", fmt.Errorf("path '%s' must not be %s", path, filepath.Join("GOPATH", "src"))
    66  	}
    67  
    68  	_, err = os.Stat(path)
    69  	if err != nil && !os.IsNotExist(err) {
    70  		return "", err
    71  	}
    72  	if err == nil {
    73  		err = os.ErrExist
    74  	} else if os.IsNotExist(err) {
    75  		err = nil
    76  	}
    77  
    78  	return path, err
    79  }
    80  
    81  func newProjectInDir(path string) error {
    82  	path, err := name2path(path)
    83  	if err != nil && !os.IsNotExist(err) {
    84  		return err
    85  	}
    86  
    87  	// path exists, ask if it should be overwritten
    88  	if os.IsNotExist(err) {
    89  		fmt.Printf("Using '%s' as project directory\n", path)
    90  		fmt.Println("Path exists, overwrite contents? (y/N):")
    91  
    92  		answer, err := getAnswer()
    93  		if err != nil {
    94  			return err
    95  		}
    96  
    97  		switch answer {
    98  		case "n", "no", "\r\n", "\n", "":
    99  			fmt.Println("")
   100  
   101  		case "y", "yes":
   102  			err := os.RemoveAll(path)
   103  			if err != nil {
   104  				return fmt.Errorf("Failed to overwrite %s. \n%s", path, err)
   105  			}
   106  
   107  			return createProjectInDir(path)
   108  
   109  		default:
   110  			fmt.Println("Input not recognized. No files overwritten. Answer as 'y' or 'n' only.")
   111  		}
   112  
   113  		return nil
   114  	}
   115  
   116  	return createProjectInDir(path)
   117  }
   118  
   119  func createProjectInDir(path string) error {
   120  	gopath, err := getGOPATH()
   121  	if err != nil {
   122  		return err
   123  	}
   124  	repo := ponzuRepo
   125  	local := filepath.Join(gopath, "src", filepath.Join(repo...))
   126  	network := "https://" + strings.Join(repo, "/") + ".git"
   127  	if !strings.HasPrefix(path, gopath) {
   128  		path = filepath.Join(gopath, path)
   129  	}
   130  
   131  	// create the directory or overwrite it
   132  	err = os.MkdirAll(path, os.ModeDir|os.ModePerm)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	if dev {
   138  		if fork != "" {
   139  			local = filepath.Join(gopath, "src", fork)
   140  		}
   141  
   142  		err = execAndWait("git", "clone", local, "--branch", "ponzu-dev", "--single-branch", path)
   143  		if err != nil {
   144  			return err
   145  		}
   146  
   147  		err = vendorCorePackages(path)
   148  		if err != nil {
   149  			return err
   150  		}
   151  
   152  		fmt.Println("Dev build cloned from " + local + ":ponzu-dev")
   153  		return nil
   154  	}
   155  
   156  	// try to git clone the repository from the local machine's $GOPATH
   157  	err = execAndWait("git", "clone", local, path)
   158  	if err != nil {
   159  		fmt.Println("Couldn't clone from", local, "- trying network...")
   160  
   161  		// try to git clone the repository over the network
   162  		networkClone := exec.Command("git", "clone", network, path)
   163  		networkClone.Stdout = os.Stdout
   164  		networkClone.Stderr = os.Stderr
   165  
   166  		err = networkClone.Start()
   167  		if err != nil {
   168  			fmt.Println("Network clone failed to start. Try again and make sure you have a network connection.")
   169  			return err
   170  		}
   171  		err = networkClone.Wait()
   172  		if err != nil {
   173  			fmt.Println("Network clone failure.")
   174  			// failed
   175  			return fmt.Errorf("Failed to clone files from local machine [%s] and over the network [%s].\n%s", local, network, err)
   176  		}
   177  	}
   178  
   179  	// create an internal vendor directory in ./cmd/ponzu and move content,
   180  	// management and system packages into it
   181  	err = vendorCorePackages(path)
   182  	if err != nil {
   183  		return err
   184  	}
   185  
   186  	// remove non-project files and directories
   187  	rmPaths := []string{".git", ".circleci"}
   188  	for _, rm := range rmPaths {
   189  		dir := filepath.Join(path, rm)
   190  		err = os.RemoveAll(dir)
   191  		if err != nil {
   192  			fmt.Println("Failed to remove directory from your project path. Consider removing it manually:", dir)
   193  		}
   194  	}
   195  
   196  	fmt.Println("New ponzu project created at", path)
   197  	return nil
   198  }
   199  
   200  func init() {
   201  	newCmd.Flags().StringVar(&fork, "fork", "", "modify repo source for Ponzu core development")
   202  	newCmd.Flags().BoolVar(&dev, "dev", false, "modify environment for Ponzu core development")
   203  
   204  	RegisterCmdlineCommand(newCmd)
   205  }