github.com/AiRISTAFlowInc/fs-cli@v0.2.6/api/create.go (about)

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