github.com/secoba/wails/v2@v2.6.4/internal/project/project.go (about)

     1  package project
     2  
     3  import (
     4  	"encoding/json"
     5  	"os"
     6  	"path/filepath"
     7  	"runtime"
     8  	"strings"
     9  
    10  	"github.com/samber/lo"
    11  )
    12  
    13  // Project holds the data related to a Wails project
    14  type Project struct {
    15  	/*** Application Data ***/
    16  	Name           string `json:"name"`
    17  	AssetDirectory string `json:"assetdir,omitempty"`
    18  
    19  	ReloadDirectories string `json:"reloaddirs,omitempty"`
    20  
    21  	BuildCommand   string `json:"frontend:build"`
    22  	InstallCommand string `json:"frontend:install"`
    23  
    24  	// Commands used in `wails dev`
    25  	DevCommand        string `json:"frontend:dev"`
    26  	DevBuildCommand   string `json:"frontend:dev:build"`
    27  	DevInstallCommand string `json:"frontend:dev:install"`
    28  	DevWatcherCommand string `json:"frontend:dev:watcher"`
    29  	// The url of the external wails dev server. If this is set, this server is used for the frontend. Default ""
    30  	FrontendDevServerURL string `json:"frontend:dev:serverUrl"`
    31  
    32  	// Directory to generate the API Module
    33  	WailsJSDir string `json:"wailsjsdir"`
    34  
    35  	Version string `json:"version"`
    36  
    37  	/*** Internal Data ***/
    38  
    39  	// The path to the project directory
    40  	Path string `json:"projectdir"`
    41  
    42  	// Build directory
    43  	BuildDir string `json:"build:dir"`
    44  
    45  	// The output filename
    46  	OutputFilename string `json:"outputfilename"`
    47  
    48  	// The type of application. EG: Desktop, Server, etc
    49  	OutputType string
    50  
    51  	// The platform to target
    52  	Platform string
    53  
    54  	// RunNonNativeBuildHooks will run build hooks though they are defined for a GOOS which is not equal to the host os
    55  	RunNonNativeBuildHooks bool `json:"runNonNativeBuildHooks"`
    56  
    57  	// Build hooks for different targets, the hooks are executed in the following order
    58  	// Key: GOOS/GOARCH - Executed at build level before/after a build of the specific platform and arch
    59  	// Key: GOOS/*      - Executed at build level before/after a build of the specific platform
    60  	// Key: */*         - Executed at build level before/after a build
    61  	// The following keys are not yet supported.
    62  	// Key: GOOS        - Executed at platform level before/after all builds of the specific platform
    63  	// Key: *           - Executed at platform level before/after all builds of a platform
    64  	// Key: [empty]     - Executed at global level before/after all builds of all platforms
    65  	PostBuildHooks map[string]string `json:"postBuildHooks"`
    66  	PreBuildHooks  map[string]string `json:"preBuildHooks"`
    67  
    68  	// The application author
    69  	Author Author
    70  
    71  	// The application information
    72  	Info Info
    73  
    74  	// Fully qualified filename
    75  	filename string
    76  
    77  	// The debounce time for hot-reload of the built-in dev server. Default 100
    78  	DebounceMS int `json:"debounceMS"`
    79  
    80  	// The address to bind the wails dev server to. Default "localhost:34115"
    81  	DevServer string `json:"devServer"`
    82  
    83  	// Arguments that are forwared to the application in dev mode
    84  	AppArgs string `json:"appargs"`
    85  
    86  	// NSISType to be build
    87  	NSISType string `json:"nsisType"`
    88  
    89  	// Garble
    90  	Obfuscated bool   `json:"obfuscated"`
    91  	GarbleArgs string `json:"garbleargs"`
    92  
    93  	// Frontend directory
    94  	FrontendDir string `json:"frontend:dir"`
    95  
    96  	Bindings Bindings `json:"bindings"`
    97  }
    98  
    99  func (p *Project) GetFrontendDir() string {
   100  	if filepath.IsAbs(p.FrontendDir) {
   101  		return p.FrontendDir
   102  	}
   103  	return filepath.Join(p.Path, p.FrontendDir)
   104  }
   105  
   106  func (p *Project) GetWailsJSDir() string {
   107  	if filepath.IsAbs(p.WailsJSDir) {
   108  		return p.WailsJSDir
   109  	}
   110  	return filepath.Join(p.Path, p.WailsJSDir)
   111  }
   112  
   113  func (p *Project) GetBuildDir() string {
   114  	if filepath.IsAbs(p.BuildDir) {
   115  		return p.BuildDir
   116  	}
   117  	return filepath.Join(p.Path, p.BuildDir)
   118  }
   119  
   120  func (p *Project) GetDevBuildCommand() string {
   121  	if p.DevBuildCommand != "" {
   122  		return p.DevBuildCommand
   123  	}
   124  	if p.DevCommand != "" {
   125  		return p.DevCommand
   126  	}
   127  	return p.BuildCommand
   128  }
   129  
   130  func (p *Project) GetDevInstallerCommand() string {
   131  	if p.DevInstallCommand != "" {
   132  		return p.DevInstallCommand
   133  	}
   134  	return p.InstallCommand
   135  }
   136  
   137  func (p *Project) IsFrontendDevServerURLAutoDiscovery() bool {
   138  	return p.FrontendDevServerURL == "auto"
   139  }
   140  
   141  func (p *Project) Save() error {
   142  	data, err := json.MarshalIndent(p, "", "  ")
   143  	if err != nil {
   144  		return err
   145  	}
   146  	return os.WriteFile(p.filename, data, 0o755)
   147  }
   148  
   149  func (p *Project) setDefaults() {
   150  	if p.Path == "" {
   151  		p.Path = lo.Must(os.Getwd())
   152  	}
   153  	if p.Version == "" {
   154  		p.Version = "2"
   155  	}
   156  	// Create default name if not given
   157  	if p.Name == "" {
   158  		p.Name = "wailsapp"
   159  	}
   160  	if p.OutputFilename == "" {
   161  		p.OutputFilename = p.Name
   162  	}
   163  	if p.FrontendDir == "" {
   164  		p.FrontendDir = "frontend"
   165  	}
   166  	if p.WailsJSDir == "" {
   167  		p.WailsJSDir = p.FrontendDir
   168  	}
   169  	if p.BuildDir == "" {
   170  		p.BuildDir = "build"
   171  	}
   172  	if p.DebounceMS == 0 {
   173  		p.DebounceMS = 100
   174  	}
   175  	if p.DevServer == "" {
   176  		p.DevServer = "localhost:34115"
   177  	}
   178  	if p.NSISType == "" {
   179  		p.NSISType = "multiple"
   180  	}
   181  	if p.Info.CompanyName == "" {
   182  		p.Info.CompanyName = p.Name
   183  	}
   184  	if p.Info.ProductName == "" {
   185  		p.Info.ProductName = p.Name
   186  	}
   187  	if p.Info.ProductVersion == "" {
   188  		p.Info.ProductVersion = "1.0.0"
   189  	}
   190  	if p.Info.Copyright == nil {
   191  		v := "Copyright........."
   192  		p.Info.Copyright = &v
   193  	}
   194  	if p.Info.Comments == nil {
   195  		v := "Built using Wails (https://wails.io)"
   196  		p.Info.Comments = &v
   197  	}
   198  
   199  	// Fix up OutputFilename
   200  	switch runtime.GOOS {
   201  	case "windows":
   202  		if !strings.HasSuffix(p.OutputFilename, ".exe") {
   203  			p.OutputFilename += ".exe"
   204  		}
   205  	case "darwin", "linux":
   206  		p.OutputFilename = strings.TrimSuffix(p.OutputFilename, ".exe")
   207  	}
   208  }
   209  
   210  // Author stores details about the application author
   211  type Author struct {
   212  	Name  string `json:"name"`
   213  	Email string `json:"email"`
   214  }
   215  
   216  type Info struct {
   217  	CompanyName      string            `json:"companyName"`
   218  	ProductName      string            `json:"productName"`
   219  	ProductVersion   string            `json:"productVersion"`
   220  	Copyright        *string           `json:"copyright"`
   221  	Comments         *string           `json:"comments"`
   222  	FileAssociations []FileAssociation `json:"fileAssociations"`
   223  	Protocols        []Protocol        `json:"protocols"`
   224  }
   225  
   226  type FileAssociation struct {
   227  	Ext         string `json:"ext"`
   228  	Name        string `json:"name"`
   229  	Description string `json:"description"`
   230  	IconName    string `json:"iconName"`
   231  	Role        string `json:"role"`
   232  }
   233  
   234  type Protocol struct {
   235  	Scheme      string `json:"scheme"`
   236  	Description string `json:"description"`
   237  	Role        string `json:"role"`
   238  }
   239  
   240  type Bindings struct {
   241  	TsGeneration TsGeneration `json:"ts_generation"`
   242  }
   243  
   244  type TsGeneration struct {
   245  	Prefix string `json:"prefix"`
   246  	Suffix string `json:"suffix"`
   247  }
   248  
   249  // Parse the given JSON data into a Project struct
   250  func Parse(projectData []byte) (*Project, error) {
   251  	project := &Project{}
   252  	err := json.Unmarshal(projectData, project)
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  	project.setDefaults()
   257  	return project, nil
   258  }
   259  
   260  // Load the project from the current working directory
   261  func Load(projectPath string) (*Project, error) {
   262  	projectFile := filepath.Join(projectPath, "wails.json")
   263  	rawBytes, err := os.ReadFile(projectFile)
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  	result, err := Parse(rawBytes)
   268  	if err != nil {
   269  		return nil, err
   270  	}
   271  	result.filename = projectFile
   272  	return result, nil
   273  }