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

     1  package api
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  	"os/exec"
    11  
    12  	"github.com/project-flogo/cli/common"
    13  	"github.com/project-flogo/cli/util"
    14  )
    15  
    16  var fileSampleEngineMain = filepath.Join("examples", "engine", "main.go")
    17  
    18  func CreateProject(basePath, appName, appCfgPath, coreVersion string) (common.AppProject, error) {
    19  
    20  	var err error
    21  	var appJson string
    22  
    23  	if appCfgPath != "" {
    24  
    25  		if util.IsRemote(appCfgPath) {
    26  
    27  			appJson, err = util.LoadRemoteFile(appCfgPath)
    28  			if err != nil {
    29  				return nil, fmt.Errorf("unable to load remote app file '%s' - %s", appCfgPath, err.Error())
    30  			}
    31  		} else {
    32  			appJson, err = util.LoadLocalFile(appCfgPath)
    33  			if err != nil {
    34  				return nil, fmt.Errorf("unable to load app file '%s' - %s", appCfgPath, err.Error())
    35  			}
    36  		}
    37  	} else {
    38  		if len(appName) == 0 {
    39  			return nil, fmt.Errorf("app name not specified")
    40  		}
    41  	}
    42  
    43  	appName, err = getAppName(appName, appJson)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	fmt.Printf("Creating Flogo App: %s\n", appName)
    49  
    50  	appDir, err := createAppDirectory(basePath, appName)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	srcDir := filepath.Join(appDir, "src")
    56  	dm := util.NewDepManager(srcDir)
    57  
    58  	if Verbose() {
    59  		fmt.Printf("Setting up app directory: %s\n", appDir)
    60  	}
    61  
    62  	err = setupAppDirectory(dm, appDir, coreVersion)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	if Verbose() {
    68  		if appJson == "" {
    69  			fmt.Println("Adding sample flogo.json")
    70  		}
    71  	}
    72  	err = createAppJson(dm, appDir, appName, appJson)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	err = createMain(dm, appDir)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	project := NewAppProject(appDir)
    83  
    84  	if Verbose() {
    85  		fmt.Println("Importing Dependencies...")
    86  	}
    87  
    88  	err = importDependencies(project)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	if Verbose() {
    94  		fmt.Printf("Created App: %s\n", appName)
    95  	}
    96  
    97  	return project, nil
    98  }
    99  
   100  // createAppDirectory creates the flogo app directory
   101  func createAppDirectory(basePath, appName string) (string, error) {
   102  
   103  	var err error
   104  
   105  	if basePath == "." {
   106  		basePath, err = os.Getwd()
   107  		if err != nil {
   108  			return "", err
   109  		}
   110  	}
   111  
   112  	appPath := filepath.Join(basePath, appName)
   113  	err = os.Mkdir(appPath, os.ModePerm)
   114  	if err != nil {
   115  		return "", err
   116  	}
   117  
   118  	return appPath, nil
   119  }
   120  
   121  //setupAppDirectory sets up the flogo app directory
   122  func setupAppDirectory(dm util.DepManager, appPath, coreVersion string) error {
   123  
   124  	err := os.Mkdir(filepath.Join(appPath, dirBin), os.ModePerm)
   125  	if err != nil {
   126  		return err
   127  	}
   128  
   129  	srcDir := filepath.Join(appPath, dirSrc)
   130  	err = os.Mkdir(srcDir, os.ModePerm)
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  	_, err = os.Create(filepath.Join(srcDir, fileImportsGo))
   136  	if err != nil {
   137  		return err
   138  	}
   139  	err = ioutil.WriteFile(filepath.Join(srcDir, fileImportsGo), []byte("package main\n"), 0644)
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	err = dm.Init()
   145  	if err != nil {
   146  		return err
   147  	}
   148  
   149  	flogoCoreImport := util.NewFlogoImport(flogoCoreRepo, "", coreVersion, "")
   150  
   151  	//todo get the actual version installed from the go.mod file
   152  	if coreVersion == "" {
   153  		fmt.Printf("Installing: %s@latest\n", flogoCoreImport.CanonicalImport())
   154  	} else {
   155  		fmt.Printf("Installing: %s\n", flogoCoreImport.CanonicalImport())
   156  	}
   157  
   158  	// add & fetch the core library
   159  	err = dm.AddDependency(flogoCoreImport)
   160  	if err != nil {
   161  		return err
   162  	}
   163  
   164  	return nil
   165  }
   166  
   167  // createAppJson create the flogo app json
   168  func createAppJson(dm util.DepManager, appDir, appName, appJson string) error {
   169  
   170  	updatedJson, err := getAndUpdateAppJson(dm, appName, appJson)
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	err = ioutil.WriteFile(filepath.Join(appDir, fileFlogoJson), []byte(updatedJson), 0644)
   176  	if err != nil {
   177  		return err
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  // importDependencies import all dependencies
   184  func importDependencies(project common.AppProject) error {
   185  
   186  	ai, err := util.GetAppImports(filepath.Join(project.Dir(), fileFlogoJson), project.DepManager(), true)
   187  	if err != nil {
   188  		return err
   189  	}
   190  
   191  	imports := ai.GetAllImports()
   192  
   193  	if len(imports) == 0 {
   194  		return nil
   195  	}
   196  
   197  	err = project.AddImports(true, false, imports...)
   198  	if err != nil {
   199  		return err
   200  	}
   201  
   202  	legacySupportRequired := false
   203  
   204  	for _, details := range ai.GetAllImportDetails() {
   205  
   206  		path, err := project.GetPath(details.Imp)
   207  		if err != nil {
   208  			return err
   209  		}
   210  
   211  		desc, err := util.GetContribDescriptor(path)
   212  
   213  		if err != nil {
   214  			return err
   215  		}
   216  
   217  		if desc != nil {
   218  
   219  			cType := desc.GetContribType()
   220  			if desc.IsLegacy {
   221  				legacySupportRequired = true
   222  				cType = "legacy " + desc.GetContribType()
   223  				err := CreateLegacyMetadata(path, desc.GetContribType(), details.Imp.GoImportPath())
   224  				if err != nil {
   225  					return err
   226  				}
   227  			}
   228  
   229  			fmt.Printf("Installed %s: %s\n", cType, details.Imp)
   230  			//instStr := fmt.Sprintf("Installed %s:", cType)
   231  			//fmt.Printf("%-20s %s\n", instStr, imp)
   232  		}
   233  	}
   234  	
   235  	if Verbose() {
   236  		fmt.Printf("Tidying go mod...")
   237  	}
   238  	
   239  	err = util.ExecCmd(exec.Command("go", "mod", "tidy"), project.SrcDir())
   240  	if err != nil {
   241  		fmt.Printf("Failed to clean deps: %s\n", err)
   242  	}
   243  
   244  	if legacySupportRequired {
   245  		err := InstallLegacySupport(project)
   246  		return err
   247  	}
   248  
   249  	return nil
   250  }
   251  
   252  func createMain(dm util.DepManager, appDir string) error {
   253  
   254  	flogoCoreImport, err := util.NewFlogoImportFromPath(flogoCoreRepo)
   255  	if err != nil {
   256  		return err
   257  	}
   258  
   259  	corePath, err := dm.GetPath(flogoCoreImport)
   260  	if err != nil {
   261  		return err
   262  	}
   263  
   264  	bytes, err := ioutil.ReadFile(filepath.Join(corePath, fileSampleEngineMain))
   265  	if err != nil {
   266  		return err
   267  	}
   268  
   269  	err = ioutil.WriteFile(filepath.Join(appDir, dirSrc, fileMainGo), bytes, 0644)
   270  	if err != nil {
   271  		return err
   272  	}
   273  
   274  	return nil
   275  }
   276  
   277  func getAndUpdateAppJson(dm util.DepManager, appName, appJson string) (string, error) {
   278  
   279  	if len(appJson) == 0 {
   280  		appJson = emptyFlogoJson
   281  	}
   282  
   283  	descriptor, err := util.ParseAppDescriptor(appJson)
   284  	if err != nil {
   285  		return "", err
   286  	}
   287  
   288  	if appName != "" {
   289  		// override the application name
   290  
   291  		altJson := strings.Replace(appJson, `"`+descriptor.Name+`"`, `"`+appName+`"`, 1)
   292  		altDescriptor, err := util.ParseAppDescriptor(altJson)
   293  
   294  		//see if we can get away with simple replace so we don't reorder the existing json
   295  		if err == nil && altDescriptor.Name == appName {
   296  			appJson = altJson
   297  		} else {
   298  			//simple replace didn't work so we have to unmarshal & re-marshal the supplied json
   299  			var appObj map[string]interface{}
   300  			err := json.Unmarshal([]byte(appJson), &appObj)
   301  			if err != nil {
   302  				return "", err
   303  			}
   304  
   305  			appObj["name"] = appName
   306  
   307  			updApp, err := json.MarshalIndent(appObj, "", "  ")
   308  			if err != nil {
   309  				return "", err
   310  			}
   311  			appJson = string(updApp)
   312  		}
   313  
   314  		descriptor.Name = appName
   315  	} else {
   316  		appName = descriptor.Name
   317  	}
   318  
   319  	return appJson, nil
   320  }
   321  
   322  func getAppName(appName, appJson string) (string, error) {
   323  
   324  	if appJson != "" && appName == "" {
   325  		descriptor, err := util.ParseAppDescriptor(appJson)
   326  		if err != nil {
   327  			return "", err
   328  		}
   329  
   330  		return descriptor.Name, nil
   331  	}
   332  
   333  	return appName, nil
   334  }
   335  func GetTempDir() (string, error) {
   336  
   337  	tempDir, err := ioutil.TempDir("", "flogo")
   338  	if err != nil {
   339  		return "", err
   340  	}
   341  	return tempDir, nil
   342  }
   343  
   344  var emptyFlogoJson = `
   345  {
   346  	"name": "{{.AppName}}",
   347  	"type": "flogo:app",
   348  	"version": "0.0.1",
   349  	"description": "My Flogo Application Description",
   350  	"appModel": "1.1.0",
   351  	"imports": [],
   352  	"triggers": [],
   353  	"resources":[]
   354    }
   355    `