app API

app

package

API reference for the app package.

S
struct

App

App represents a Vanilla OS application

pkg/v1/app/app.go:26-50
type App struct

Methods

WithCLI
Method

WithCLI assigns a command created from a struct (declarative model) to the application CLI.

Parameters

root any

Returns

error
func (*App) WithCLI(root any) error
{
	cmd, err := cli.NewCommandFromStruct(root)
	if err != nil {
		return err
	}
	app.CLI = cmd
	return nil
}
Example
root := &RootCmd{
	Poll: PollCmd{},
	Man:  ManCmd{},
}
app.WithCLI(root)
app.CLI.Execute()

checkMissingStrings is a hook used when the "check_missing_strings" build tag is set. It scans the project for missing translation keys and exists with a non-zero status if any are found.

func (*App) checkMissingStrings()
{
	rootDir, err := os.Getwd()
	if err != nil {
		fmt.Printf("Error getting current directory: %v\n", err)
		os.Exit(1)
	}

	// Try to locate the English locale file in common paths.
	var localeFile string
	possiblePaths := []string{
		"cmd/locales/en/LC_MESSAGES",
		"cmd/locales/en",
		"locales/en/LC_MESSAGES",
		"locales/en",
		"assets/locales/en/LC_MESSAGES",
		"assets/locales/en",
	}

	for _, p := range possiblePaths {
		path := filepath.Join(rootDir, p)
		matches, _ := filepath.Glob(filepath.Join(path, "*.po"))
		if len(matches) > 0 {
			localeFile = matches[0]
			break
		}
	}

	if localeFile == "" {
		fmt.Println("Error: Could not find any .po file in standard locations")
		os.Exit(1)
	}

	fmt.Printf("Checking missing strings in %s using locale %s\n", rootDir, localeFile)

	missing, err := i18n.CheckMissingStrings(rootDir, localeFile)
	if err != nil {
		fmt.Printf("Error checking strings: %v\n", err)
		os.Exit(1)
	}

	if len(missing) > 0 {
		fmt.Println("Oops, there are missing translation strings:")
		for file, keys := range missing {
			for _, key := range keys {
				fmt.Printf("- %s: Missing '%s'\n", file, key)
			}
		}

		f, _ := os.Create("missing_strings.json")
		defer f.Close()
		enc := json.NewEncoder(f)
		enc.SetIndent("", "  ")
		enc.Encode(missing)

		os.Exit(1)
	}

	fmt.Println("No missing translation strings. Good job!")
	os.Exit(0)
}

checkMissingStrings is a no-op when the "check_missing_strings" build tag is not set.

func (*App) checkMissingStrings()
{
	// No-op
}

Fields

Name Type Description
Sign types.Sign
RDNN string
Name string
Version string
Log *logs.Logger
LC spreak.Localizer
LocalesFS fs.FS
CLI *cli.Command
F
function

NewApp

NewApp creates a new Vanilla OS application, which can be used to
interact with the system. The application is created with the
default configuration if no options are provided.

Parameters

Returns

error
pkg/v1/app/app.go:86-133
func NewApp(options types.AppOptions) (*App, error)

{
	app := App{
		RDNN:      options.RDNN,
		Name:      options.Name,
		Version:   options.Version,
		LocalesFS: options.LocalesFS,
	}
	app.Sign = generateAppSign(&app)

	// here we prepare a logger for the application
	logger, err := logs.NewLogger(string(app.Sign))
	if err != nil {
		return &app, err // logger is mandatory for each application
	}
	app.Log = &logger

	// here we prepare a localizer for the application
	locale := os.Getenv("LANGUAGE")
	if locale == "" {
		locale = os.Getenv("LC_ALL")
	}
	if locale == "" {
		locale = os.Getenv("LC_MESSAGES")
	}
	if locale == "" {
		locale = os.Getenv("LANG")
	}
	if locale == "" {
		locale = options.DefaultLocale
	}

	var localizer *spreak.Localizer
	if options.LocalesFS != nil {
		var err error
		localizer, err = i18n.NewLocalizer(options.LocalesFS, app.RDNN, locale)
		if err != nil {
			return &app, err
		}
	}

	if localizer != nil {
		app.LC = *localizer
	}

	app.checkMissingStrings()

	return &app, nil
}

Example

app, err := app.NewApp({
	RDNN: "com.vanilla-os.batsignal",
	Name: "BatSignal",
	Version: "1.0.0",
	LocalesFS: localesFS,
	DefaultLocale: "en",
	CLIOptions: &cli.CLIOptions{
		Use: "batsignal",
		Short: "A simple CLI to call Batman",
		Long: "A simple CLI to call Batman using the BatSignal",
	},
})
if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}
fmt.Printf("App Sign: %s\n", app.Sign)

Notes

If the project does not provide a FS for the locales, the
localizer will not be created. If the localizer fails to be created
in any way, the application will continue to work without it but
translation keys will be returned as they are (in English).

The logger, instead, is mandatory for each application. So if the
logger fails to be created, the application will return an error and
will not work.

F
function

generateAppSign

generateAppSign generates a unique signature for the application
based on the RDNN, name and version. The signature is used to
identify the application.

Parameters

app

Returns

pkg/v1/app/app.go:157-163
func generateAppSign(app *App) types.Sign

{
	sign := fmt.Sprintf("%s-%s-%s", app.RDNN, app.Name, app.Version)

	h := sha1.New()
	h.Write([]byte(sign))
	return types.Sign(base64.URLEncoding.EncodeToString(h.Sum(nil)))
}