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