app
packageAPI reference for the app
package.
Imports
(12)App
App represents a Vanilla OS application
type App struct
Methods
WithCLI assigns a command created from a struct (declarative model) to the application CLI.
Parameters
Returns
func (*App) WithCLI(root any) error
{
cmd, err := cli.NewCommandFromStruct(root)
if err != nil {
return err
}
app.CLI = cmd
return nil
}
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 |
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
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.
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
Returns
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)))
}