github.com/c3pm-labs/c3pm@v0.3.0/ctpm/init.go (about)

     1  package ctpm
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  	"text/template"
    11  
    12  	"github.com/mitchellh/go-spdx"
    13  
    14  	"github.com/c3pm-labs/c3pm/config"
    15  )
    16  
    17  type InitOptions struct {
    18  	NoTemplate bool
    19  }
    20  
    21  var InitDefaultOptions = InitOptions{
    22  	NoTemplate: false,
    23  }
    24  
    25  func Init(pc *config.ProjectConfig, opt InitOptions) error {
    26  	err := os.MkdirAll(pc.ProjectRoot, os.ModePerm) // umask will take care of permissions
    27  	if err != nil {
    28  		return err
    29  	}
    30  	if pc.Manifest.License != "UNLICENSED" {
    31  		err = generateLicenseFile(pc)
    32  		if err != nil {
    33  			return err
    34  		}
    35  	}
    36  	if !opt.NoTemplate {
    37  		err = generateReadMe(pc)
    38  		if err != nil {
    39  			return err
    40  		}
    41  		if pc.Manifest.Type == "executable" {
    42  			err := saveExecutableTemplate(pc)
    43  			if err != nil {
    44  				return err
    45  			}
    46  		} else {
    47  			err := saveLibraryTemplate(pc)
    48  			if err != nil {
    49  				return err
    50  			}
    51  		}
    52  	}
    53  
    54  	return pc.Save()
    55  }
    56  
    57  const execTemplate = `#include <iostream>
    58  
    59  int main() {
    60  	std::cout << "Hello c3pm!" << std::endl;
    61  	return 0;
    62  }`
    63  const includeTemplate = `#pragma once
    64  
    65  void hello();`
    66  const libTemplate = `#include <iostream>
    67  #include "{{.Name}}.hpp"
    68  
    69  void hello() {
    70  	std::cout << "Hello c3pm!" << std::endl;
    71  }`
    72  const readMeTemplate = `# {{.Name}}
    73  
    74  A new C++ project.
    75  
    76  ## Getting Started
    77  
    78  This project is a starting point for a C++ project.
    79  
    80  A few helpful commands to get you started if this is your first time using c3pm:
    81  
    82  ### Building your project
    83  ` + "```" + `shell
    84  $ ctpm build
    85  ` + "```" + `
    86  
    87  ### Add a package
    88  ` + "```" + `shell
    89  $ ctpm add <package>
    90  ` + "```" + `
    91  
    92  ### Publishing your project
    93  ` + "```" + `shell
    94  $ ctpm publish
    95  ` + "```" + `
    96  
    97  For help getting started with c3pm, view our
    98  [online documentation](https://docs.c3pm.io/), which offers tutorials, samples and
    99  a list of all available commands.
   100  `
   101  
   102  func generateReadMe(pc *config.ProjectConfig) error {
   103  	t := template.Must(template.New("readMeTemplate").Parse(readMeTemplate))
   104  	f, err := os.Create(filepath.Join(pc.ProjectRoot, "README.md"))
   105  	if err != nil {
   106  		return err
   107  	}
   108  	return t.ExecuteTemplate(f, "readMeTemplate", pc.Manifest)
   109  }
   110  
   111  func generateLicenseFile(pc *config.ProjectConfig) error {
   112  	lic, err := spdx.License(pc.Manifest.License)
   113  	if err != nil {
   114  		return err
   115  	}
   116  	if len(lic.Text) == 0 {
   117  		return fmt.Errorf("generate %s", lic.Name)
   118  	}
   119  	return ioutil.WriteFile(filepath.Join(pc.ProjectRoot, "LICENSE"), []byte(lic.Text), 0644)
   120  }
   121  
   122  func yesOrNo(label string) string {
   123  	choices := "y/n"
   124  
   125  	r := bufio.NewReader(os.Stdin)
   126  	var s string
   127  
   128  	_, err := fmt.Fprintf(os.Stderr, "%s (%s) ", label, choices)
   129  	if err != nil {
   130  		return ""
   131  	}
   132  	s, _ = r.ReadString('\n')
   133  	s = strings.TrimSpace(s)
   134  	if s == "" {
   135  		return "n"
   136  	}
   137  	s = strings.ToLower(s)
   138  	return s
   139  }
   140  
   141  func overrideDirectory(label string, path string) bool {
   142  	answer := ""
   143  	if _, err := os.Stat(path); !os.IsNotExist(err) {
   144  		answer = yesOrNo(label)
   145  	}
   146  	if answer == "n" || answer == "no" {
   147  		return false
   148  	}
   149  	if answer == "y" || answer == "yes" {
   150  		if err := os.RemoveAll(path); err != nil {
   151  			return false
   152  		}
   153  	}
   154  	if err := os.Mkdir(path, os.ModePerm); err != nil {
   155  		return false
   156  	}
   157  	return true
   158  }
   159  
   160  func saveExecutableTemplate(pc *config.ProjectConfig) error {
   161  	if status := overrideDirectory(
   162  		"You already have a src directory, do you want to override it?",
   163  		filepath.Join(pc.ProjectRoot, "src")); status {
   164  		return ioutil.WriteFile(filepath.Join(pc.ProjectRoot, "src", "main.cpp"), []byte(execTemplate), 0644)
   165  	}
   166  	return nil
   167  }
   168  
   169  func saveLibraryTemplate(pc *config.ProjectConfig) error {
   170  	t := template.Must(template.New("libTemplate").Parse(libTemplate))
   171  	var f *os.File = nil
   172  	var err error = nil
   173  	if status := overrideDirectory(
   174  		"You already have a src directory, do you want to override it?",
   175  		filepath.Join(pc.ProjectRoot, "src")); status {
   176  		f, err = os.Create(filepath.Join(pc.ProjectRoot, "src", pc.Manifest.Name+".cpp"))
   177  		if err != nil {
   178  			return err
   179  		}
   180  		defer f.Close()
   181  
   182  		if err := t.ExecuteTemplate(f, "libTemplate", pc.Manifest); err != nil {
   183  			return err
   184  		}
   185  	}
   186  
   187  	if status := overrideDirectory(
   188  		"You already have a include directory, do you want to override it?",
   189  		filepath.Join(pc.ProjectRoot, "include")); status {
   190  		f, err = os.Create(filepath.Join(pc.ProjectRoot, "include", pc.Manifest.Name+".hpp"))
   191  		if err != nil {
   192  			return err
   193  		}
   194  		defer f.Close()
   195  
   196  		_, err = f.Write([]byte(includeTemplate))
   197  	}
   198  	return err
   199  }