github.com/project-flogo/cli@v0.12.0/api/project.go (about)

     1  package api
     2  
     3  import (
     4  	"fmt"
     5  	"go/parser"
     6  	"go/printer"
     7  	"go/token"
     8  	"os"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strings"
    12  
    13  	"github.com/project-flogo/cli/common"
    14  	"github.com/project-flogo/cli/util"
    15  )
    16  
    17  const (
    18  	flogoCoreRepo  = "github.com/project-flogo/core"
    19  	fileFlogoJson  = "flogo.json"
    20  	fileEngineJson = "engine.json"
    21  	fileMainGo     = "main.go"
    22  	fileImportsGo  = "imports.go"
    23  	dirSrc         = "src"
    24  	dirBin         = "bin"
    25  )
    26  
    27  var GOOSENV = os.Getenv("GOOS")
    28  
    29  type appProjectImpl struct {
    30  	appDir  string
    31  	appName string
    32  	srcDir  string
    33  	binDir  string
    34  	dm      util.DepManager
    35  }
    36  
    37  func NewAppProject(appDir string) common.AppProject {
    38  	project := &appProjectImpl{appDir: appDir}
    39  	project.srcDir = filepath.Join(appDir, dirSrc)
    40  	project.binDir = filepath.Join(appDir, dirBin)
    41  	project.dm = util.NewDepManager(project.srcDir)
    42  	project.appName = filepath.Base(appDir)
    43  	return project
    44  }
    45  
    46  func (p *appProjectImpl) Validate() error {
    47  	_, err := os.Stat(filepath.Join(p.appDir, fileFlogoJson))
    48  	if os.IsNotExist(err) {
    49  		return fmt.Errorf("not a valid flogo app project directory, missing flogo.json")
    50  	}
    51  
    52  	_, err = os.Stat(p.srcDir)
    53  	if os.IsNotExist(err) {
    54  		return fmt.Errorf("not a valid flogo app project directory, missing 'src' diretory")
    55  	}
    56  
    57  	_, err = os.Stat(filepath.Join(p.srcDir, fileImportsGo))
    58  	if os.IsNotExist(err) {
    59  		return fmt.Errorf("flogo app directory corrupt, missing 'src/imports.go' file")
    60  	}
    61  
    62  	_, err = os.Stat(filepath.Join(p.srcDir, "go.mod"))
    63  	if os.IsNotExist(err) {
    64  		return fmt.Errorf("flogo app directory corrupt, missing 'src/go.mod' file")
    65  	}
    66  
    67  	return nil
    68  }
    69  
    70  func (p *appProjectImpl) Name() string {
    71  	return p.appName
    72  }
    73  
    74  func (p *appProjectImpl) Dir() string {
    75  	return p.appDir
    76  }
    77  
    78  func (p *appProjectImpl) BinDir() string {
    79  	return p.binDir
    80  }
    81  
    82  func (p *appProjectImpl) SrcDir() string {
    83  	return p.srcDir
    84  }
    85  
    86  func (p *appProjectImpl) DepManager() util.DepManager {
    87  	return p.dm
    88  }
    89  
    90  func (p *appProjectImpl) Executable() string {
    91  
    92  	var execPath string
    93  
    94  	execPath = filepath.Join(p.binDir, p.appName)
    95  
    96  	if GOOSENV == "windows" || (runtime.GOOS == "windows" && GOOSENV == "") {
    97  		// env or cross platform is windows
    98  		execPath = filepath.Join(p.binDir, p.appName+".exe")
    99  	}
   100  
   101  	return execPath
   102  }
   103  
   104  func (p *appProjectImpl) GetPath(flogoImport util.Import) (string, error) {
   105  	return p.dm.GetPath(flogoImport)
   106  }
   107  
   108  func (p *appProjectImpl) GetGoImports(withVersion bool) ([]util.Import, error) {
   109  	importsFile := filepath.Join(p.SrcDir(), fileImportsGo)
   110  
   111  	fset := token.NewFileSet()
   112  	file, err := parser.ParseFile(fset, importsFile, nil, parser.ImportsOnly)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  
   117  	//if withVersion, parse go.mod file for version information
   118  	//goModImports, err := p.dm.GetAllImports()
   119  	//if err != nil {
   120  	//	return nil, err
   121  	//}
   122  
   123  	var imports []util.Import
   124  	for _, is := range file.Imports {
   125  
   126  		imp, err := util.ParseImport(is.Path.Value)
   127  		if err != nil {
   128  			return nil, err
   129  		}
   130  
   131  		imports = append(imports, imp)
   132  	}
   133  
   134  	return imports, nil
   135  }
   136  
   137  func (p *appProjectImpl) addImportsInGo(ignoreError bool, imports ...util.Import) error {
   138  	importsFile := filepath.Join(p.SrcDir(), fileImportsGo)
   139  
   140  	fset := token.NewFileSet()
   141  	file, err := parser.ParseFile(fset, importsFile, nil, parser.ImportsOnly)
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	for _, i := range imports {
   147  		err := p.DepManager().AddDependency(i)
   148  		if err != nil {
   149  			if ignoreError {
   150  				fmt.Printf("Warning: unable to install '%s'\n", i)
   151  				continue
   152  			}
   153  
   154  			fmt.Fprintf(os.Stderr, "Error in installing '%s'\n", i)
   155  
   156  			return err
   157  		}
   158  		util.AddImport(fset, file, i.GoImportPath())
   159  	}
   160  
   161  	f, err := os.Create(importsFile)
   162  	defer f.Close()
   163  	if err := printer.Fprint(f, fset, file); err != nil {
   164  		return err
   165  	}
   166  
   167  	//p.dm.Finalize()
   168  
   169  	return nil
   170  }
   171  
   172  func (p *appProjectImpl) addImportsInJson(ignoreError bool, imports ...util.Import) error {
   173  
   174  	appDescriptor, err := readAppDescriptor(p)
   175  	if err != nil {
   176  		return err
   177  	}
   178  
   179  	// list existing imports in JSON to avoid duplicates
   180  	existingImports := make(map[string]util.Import)
   181  	jsonImports, _ := util.ParseImports(appDescriptor.Imports)
   182  	for _, e := range jsonImports {
   183  		existingImports[e.GoImportPath()] = e
   184  	}
   185  
   186  	for _, i := range imports {
   187  		val, ok := existingImports[i.GoImportPath()]
   188  		if !ok {
   189  			//appDescriptor.Imports = append(appDescriptor.Imports, i.CanonicalImport())
   190  			existingImports[i.GoImportPath()] = i
   191  		} else {
   192  			if i.CanonicalImport() != val.CanonicalImport() {
   193  				delete(existingImports, val.GoImportPath())
   194  				alias := i.Alias()
   195  				if val.Alias() != "" && i.Alias() == "" {
   196  					alias = val.Alias()
   197  				}
   198  				existingImports[i.GoImportPath()] = util.NewFlogoImport(i.ModulePath(), i.RelativeImportPath(), i.Version(), alias)
   199  			}
   200  		}
   201  
   202  	}
   203  	var newImport []string
   204  	for _, val := range existingImports {
   205  		newImport = append(newImport, val.CanonicalImport())
   206  	}
   207  	appDescriptor.Imports = newImport
   208  
   209  	err = writeAppDescriptor(p, appDescriptor)
   210  	if err != nil {
   211  		return err
   212  	}
   213  
   214  	return nil
   215  }
   216  
   217  func (p *appProjectImpl) AddImports(ignoreError bool, addToJson bool, imports ...util.Import) error {
   218  	err := p.addImportsInGo(ignoreError, imports...) // begin with Go imports as they are more likely to fail
   219  	if err != nil {
   220  		return err
   221  	}
   222  
   223  	if addToJson {
   224  		err = p.addImportsInJson(ignoreError, imports...) // adding imports in JSON after Go imports ensure the flogo.json is self-sufficient
   225  	}
   226  
   227  	return err
   228  }
   229  
   230  func (p *appProjectImpl) RemoveImports(imports ...string) error {
   231  
   232  	importsFile := filepath.Join(p.SrcDir(), fileImportsGo)
   233  
   234  	fset := token.NewFileSet()
   235  	file, err := parser.ParseFile(fset, importsFile, nil, parser.ImportsOnly)
   236  	if err != nil {
   237  		return err
   238  	}
   239  
   240  	for _, impPath := range imports {
   241  		util.DeleteImport(fset, file, strings.Trim(impPath, "\""))
   242  	}
   243  
   244  	f, err := os.Create(importsFile)
   245  	defer f.Close()
   246  	if err := printer.Fprint(f, fset, file); err != nil {
   247  		return err
   248  	}
   249  
   250  	return nil
   251  }