github.com/torresashjian/cli@v0.10.1-0.20210916231452-89080fe7069c/api/build.go (about)

     1  package api
     2  
     3  import (
     4  	"fmt"
     5  	"go/parser"
     6  	"go/printer"
     7  	"go/token"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/torresashjian/cli/common"
    14  	"github.com/torresashjian/cli/util"
    15  )
    16  
    17  const (
    18  	fileEmbeddedAppGo string = "embeddedapp.go"
    19  )
    20  
    21  func BuildProject(project common.AppProject, options common.BuildOptions) error {
    22  
    23  	err := project.DepManager().AddReplacedContribForBuild()
    24  	if err != nil {
    25  		return err
    26  	}
    27  
    28  	buildPreProcessors := common.BuildPreProcessors()
    29  
    30  	if len(buildPreProcessors) > 0 {
    31  		for _, processor := range buildPreProcessors {
    32  			err = processor.DoPreProcessing(project,options)
    33  			if err != nil {
    34  				return err
    35  			}
    36  		}
    37  	}
    38  
    39  	var builder common.Builder
    40  	embedConfig := options.EmbedConfig
    41  
    42  	if options.Shim != "" {
    43  		builder = &ShimBuilder{shim:options.Shim}
    44  		embedConfig = true
    45  	} else {
    46  		builder = &AppBuilder{}
    47  	}
    48  
    49  	if embedConfig {
    50  		err = createEmbeddedAppGoFile(project)
    51  		if err != nil {
    52  			return err
    53  		}
    54  	} else {
    55  		err = cleanupEmbeddedAppGoFile(project)
    56  		if err != nil {
    57  			return err
    58  		}
    59  	}
    60  
    61  	if options.OptimizeImports {
    62  		if Verbose() {
    63  			fmt.Println("Optimizing imports...")
    64  		}
    65  		err := optimizeImports(project)
    66  		defer restoreImports(project)
    67  
    68  		if err != nil {
    69  			return err
    70  		}
    71  	}
    72  
    73  	err = builder.Build(project)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	buildPostProcessors := common.BuildPostProcessors()
    79  
    80  	if len(buildPostProcessors) > 0 {
    81  		for _, processor := range buildPostProcessors {
    82  			err = processor.DoPostProcessing(project)
    83  			if err != nil {
    84  				return err
    85  			}
    86  		}
    87  	}
    88  
    89  	return nil
    90  }
    91  
    92  func cleanupEmbeddedAppGoFile(project common.AppProject) error {
    93  	embedSrcPath := filepath.Join(project.SrcDir(), fileEmbeddedAppGo)
    94  
    95  		if _, err := os.Stat(embedSrcPath); err == nil {
    96  			if Verbose() {
    97  				fmt.Println("Removing embed configuration")
    98  			}
    99  			err = os.Remove(embedSrcPath)
   100  			if err != nil {
   101  				return err
   102  			}
   103  		}
   104  		return nil
   105  }
   106  
   107  func createEmbeddedAppGoFile(project common.AppProject) error {
   108  
   109  	embedSrcPath := filepath.Join(project.SrcDir(), fileEmbeddedAppGo)
   110  
   111  	if Verbose() {
   112  		fmt.Println("Embedding configuration in application...")
   113  	}
   114  
   115  	buf, err := ioutil.ReadFile(filepath.Join(project.Dir(), fileFlogoJson))
   116  	if err != nil {
   117  		return err
   118  	}
   119  	flogoJSON := string(buf)
   120  
   121  	tplFile := tplEmbeddedAppGoFile
   122  	if !isNewMain(project) {
   123  		tplFile = tplEmbeddedAppOldGoFile
   124  	}
   125  
   126  	engineJSON := ""
   127  
   128  	if util.FileExists(filepath.Join(project.Dir(), fileEngineJson)) {
   129  		buf, err = ioutil.ReadFile(filepath.Join(project.Dir(), fileEngineJson))
   130  		if err != nil {
   131  			return err
   132  		}
   133  
   134  		engineJSON = string(buf)
   135  	}
   136  
   137  	data := struct {
   138  		FlogoJSON string
   139  		EngineJSON string
   140  	}{
   141  		flogoJSON,
   142  		engineJSON,
   143  	}
   144  
   145  	f, err := os.Create(embedSrcPath)
   146  	if err != nil {
   147  		return err
   148  	}
   149  	RenderTemplate(f, tplFile, &data)
   150  	_ = f.Close()
   151  
   152  	return nil
   153  }
   154  
   155  func isNewMain(project common.AppProject) bool {
   156  	mainGo := filepath.Join(project.SrcDir(), fileMainGo)
   157  	buf, err := ioutil.ReadFile(mainGo)
   158  	if err == nil {
   159  		mainCode := string(buf)
   160  		return strings.Contains(mainCode, "cfgEngine")
   161  
   162  	}
   163  
   164  	return false
   165  }
   166  
   167  
   168  var tplEmbeddedAppGoFile = `// Do not change this file, it has been generated using flogo-cli
   169  // If you change it and rebuild the application your changes might get lost
   170  package main
   171  
   172  // embedded flogo app descriptor file
   173  const flogoJSON string = ` + "`{{.FlogoJSON}}`" + `
   174  const engineJSON string = ` + "`{{.EngineJSON}}`" + `
   175  
   176  func init () {
   177  	cfgJson = flogoJSON
   178  	cfgEngine = engineJSON
   179  }
   180  `
   181  
   182  var tplEmbeddedAppOldGoFile = `// Do not change this file, it has been generated using flogo-cli
   183  // If you change it and rebuild the application your changes might get lost
   184  package main
   185  
   186  // embedded flogo app descriptor file
   187  const flogoJSON string = ` + "`{{.FlogoJSON}}`" + `
   188  
   189  func init () {
   190  	cfgJson = flogoJSON
   191  }
   192  `
   193  
   194  func initMain(project common.AppProject, backupMain bool) error {
   195  
   196  	//backup main if it exists
   197  	mainGo := filepath.Join(project.SrcDir(), fileMainGo)
   198  	mainGoBak := filepath.Join(project.SrcDir(), fileMainGo+".bak")
   199  
   200  	if backupMain {
   201  		if _, err := os.Stat(mainGo); err == nil {
   202  			err = os.Rename(mainGo, mainGoBak)
   203  			if err != nil {
   204  				return err
   205  			}
   206  		} else if _, err := os.Stat(mainGoBak); err != nil {
   207  			return fmt.Errorf("project corrupt, main missing")
   208  		}
   209  	} else {
   210  		if _, err := os.Stat(mainGoBak); err == nil {
   211  			err = os.Rename(mainGoBak, mainGo)
   212  			if err != nil {
   213  				return err
   214  			}
   215  		} else if _, err := os.Stat(mainGo); err != nil {
   216  			return fmt.Errorf("project corrupt, main missing")
   217  		}
   218  	}
   219  
   220  	return nil
   221  }
   222  
   223  func optimizeImports(project common.AppProject) error {
   224  
   225  	appImports, err := util.GetAppImports(filepath.Join(project.Dir(), fileFlogoJson), project.DepManager(), true)
   226  	if err != nil {
   227  		return err
   228  	}
   229  
   230  	var unused []util.Import
   231  	appImports.GetAllImports()
   232  	for _, impDetails := range appImports.GetAllImportDetails() {
   233  		if !impDetails.Referenced() && impDetails.IsCoreContrib() {
   234  			unused = append(unused, impDetails.Imp)
   235  		}
   236  	}
   237  
   238  	importsFile := filepath.Join(project.SrcDir(), fileImportsGo)
   239  	importsFileOrig := filepath.Join(project.SrcDir(), fileImportsGo+".orig")
   240  
   241  	err = util.CopyFile(importsFile, importsFileOrig)
   242  	if err != nil {
   243  		return err
   244  	}
   245  
   246  	fset := token.NewFileSet()
   247  	file, err := parser.ParseFile(fset, importsFile, nil, parser.ImportsOnly)
   248  	if err != nil {
   249  		return err
   250  	}
   251  
   252  	for _, i := range unused {
   253  		if Verbose() {
   254  			fmt.Printf("  Removing Import: %s\n", i.GoImportPath())
   255  		}
   256  		util.DeleteImport(fset, file, i.GoImportPath())
   257  	}
   258  
   259  	f, err := os.Create(importsFile)
   260  	defer f.Close()
   261  	if err := printer.Fprint(f, fset, file); err != nil {
   262  		return err
   263  	}
   264  
   265  	return nil
   266  }
   267  
   268  func restoreImports(project common.AppProject) {
   269  
   270  	importsFile := filepath.Join(project.SrcDir(), fileImportsGo)
   271  	importsFileOrig := filepath.Join(project.SrcDir(), fileImportsGo+".orig")
   272  
   273  	if _, err := os.Stat(importsFileOrig); err == nil {
   274  		err = util.CopyFile(importsFileOrig, importsFile)
   275  		if err != nil {
   276  			fmt.Fprintf(os.Stderr, "Error restoring imports file '%s': %v\n", importsFile, err)
   277  			return
   278  		}
   279  
   280  		var err = os.Remove(importsFileOrig)
   281  		if err != nil {
   282  			fmt.Fprintf(os.Stderr, "Error removing backup imports file '%s': %v\n", importsFileOrig, err)
   283  			fmt.Fprintf(os.Stderr, "Manually remove backup imports file '%s'\n", importsFileOrig)
   284  		}
   285  	}
   286  }