### Initialize and Start Lexer Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/parsing-and-internals.md Creates and starts a new lexer instance. The lexer begins emitting items on a channel, typically starting in the `lexKeyword` state. ```go lexer := lex("network", configContent) ``` -------------------------------- ### Get Function Example Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/convenience-functions.md Retrieves all values for a fully qualified option from the default tree. Returns the values and a boolean indicating success. ```go values, ok := uci.Get("network", "lan", "ifname") if ok { fmt.Println("Interfaces:", values) } ``` -------------------------------- ### LoadConfig Function Example Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/convenience-functions.md Loads a specified configuration file into memory. Use forceReload to reload even if already loaded. ```go err := uci.LoadConfig("network", false) ``` -------------------------------- ### Example Scanner Output Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/parsing-and-internals.md Illustrates the output of the scanner, showing how sequences of items are grouped into meaningful tokens like sections and options. ```go token{typ: tokSection, items: [config, interface, lan]} token{typ: tokOption, items: [option, ifname, eth0.1]} ``` -------------------------------- ### Initialize and Start Scanner Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/parsing-and-internals.md Creates a scanner instance from raw input, internally initializing a lexer and setting the initial scanning state to `scanStart`. ```go scanner := scan("network", configContent) ``` -------------------------------- ### Example of Handling ParseError Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/types.md Demonstrates how to parse UCI configuration content and specifically catch and print a ParseError if one occurs during parsing. ```go cfg, err := parse("network", configContent) if err != nil { if _, isParse := err.(ParseError); isParse { fmt.Println("Parse error:", err) } } ``` -------------------------------- ### GetSections Function Example Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/convenience-functions.md Returns all sections of a specific type within a configuration file. Handles potential errors during retrieval. ```go sections, err := uci.GetSections("network", "interface") if err == nil { for _, section := range sections { fmt.Println("Section:", section) } } ``` -------------------------------- ### Get Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/convenience-functions.md Retrieves all values for a fully qualified option from the default tree. ```APIDOC ## Get ### Description Delegates to the default tree. Retrieves all values for a fully qualified option. ### Signature ```go func Get(config, section, option string) ([]string, bool) ``` ### Parameters #### Path Parameters - **config** (string) - Required - Config file name - **section** (string) - Required - Section name - **option** (string) - Required - Option name ### Returns - **([]string, bool)** - Values and success indicator ### Example ```go values, ok := uci.Get("network", "lan", "ifname") if ok { fmt.Println("Interfaces:", values) } ``` ``` -------------------------------- ### Manage Custom Configuration Directory Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/README.md Demonstrates using a custom directory for UCI configuration instead of the default /etc/config. Includes creating a tree, getting a value, setting a value, and committing changes. ```go tree := uci.NewTree("/path/to/config") value, ok := tree.Get("network", "lan", "ifname") _ = tree.SetType("network", "lan", "ifname", uci.TypeOption, "eth0.1") _ = tree.Commit() ``` -------------------------------- ### AddSection Function Example Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/convenience-functions.md Adds a new section with a specified name and type to a configuration file. Returns an error if the addition fails. ```go err := uci.AddSection("network", "guest", "interface") ``` -------------------------------- ### Get and Set UCI Configuration Values Source: https://github.com/digineo/go-uci/blob/v2/README.md Demonstrates how to retrieve configuration values using the default UCI tree and a custom tree. Also shows how to set a value, add a section if it doesn't exist, and commit changes. ```go import "github.com/digineo/go-uci" func main() { // use the default tree (/etc/config) if values, ok := uci.Get("system", "@system[0]", "hostname"); ok { fmt.Println("hostanme", values) //=> hostname [OpenWrt] } // use a custom tree u := uci.NewTree("/path/to/config") if values, ok := u.Get("network", "lan", "ifname"); ok { fmt.Println("network.lan.ifname", values) //=> network.lan.ifname [eth0.2] } if sectionExists := u.Set("network", "lan", "ipaddr", "192.168.7.1"); !sectionExists { _ = u.AddSection("network", "lan", "interface") _ = u.Set("network", "lan", "ipaddr", "192.168.7.1") } u.Commit() // or uci.Revert() } ``` -------------------------------- ### Provision a New Router Configuration Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Provisions a new router by setting system and network configurations, including static and DHCP interfaces, and NTP servers. This example uses a temporary directory for configuration. ```go package main import ( "fmt" "log" uci "github.com/digineo/go-uci" ) func provisionRouter(configDir string) error { tree := uci.NewTree(configDir) // Configure system _ = tree.AddSection("system", "system", "system") _ = tree.SetType("system", "system", "hostname", uci.TypeOption, "OpenWrt") _ = tree.SetType("system", "system", "timezone", uci.TypeOption, "UTC") // Configure LAN _ = tree.AddSection("network", "lan", "interface") _ = tree.SetType("network", "lan", "ifname", uci.TypeOption, "eth0.1") _ = tree.SetType("network", "lan", "proto", uci.TypeOption, "static") _ = tree.SetType("network", "lan", "ipaddr", uci.TypeOption, "192.168.1.1") _ = tree.SetType("network", "lan", "netmask", uci.TypeOption, "255.255.255.0") // Configure WAN _ = tree.AddSection("network", "wan", "interface") _ = tree.SetType("network", "wan", "ifname", uci.TypeOption, "eth0.2") _ = tree.SetType("network", "wan", "proto", uci.TypeOption, "dhcp") // Add NTP servers _ = tree.AddSection("system", "ntp", "ntp") _ = tree.SetType("system", "ntp", "enabled", uci.TypeOption, "1") _ = tree.SetType("system", "ntp", "server", uci.TypeList, "0.pool.ntp.org", "1.pool.ntp.org") return tree.Commit() } func main() { if err := provisionRouter("/tmp/new_router_config"); err != nil { log.Fatal("Provisioning failed:", err) } fmt.Println("Router provisioned successfully") } ``` -------------------------------- ### Del Function Example Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/convenience-functions.md Removes a specified option from a configuration. Returns an error if the deletion fails. ```go err := uci.Del("network", "lan", "ipaddr") ``` -------------------------------- ### GetLast Function Example Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/convenience-functions.md Retrieves the last value for a specified option. Returns the value and a boolean indicating success. ```go hostname, ok := uci.GetLast("system", "system", "hostname") if ok { fmt.Println("Hostname:", hostname) } ``` -------------------------------- ### Handling ErrSectionNotFound Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/errors.md This example shows how to handle errors when a specified section does not exist. It uses errors.As to check for ErrSectionNotFound and demonstrates creating the section before retrying the operation. ```go tree := uci.NewTree("/etc/config") // Try to set an option in a non-existent section err := tree.SetType("network", "guest", "ipaddr", uci.TypeOption, "10.0.0.1") if err != nil { var notFound ErrSectionNotFound if errors.As(err, ¬Found) { fmt.Printf("Section '%s' not found. Create it first.\n", notFound.Section) // Create the section _ = tree.AddSection("network", "guest", "interface") // Try again _ = tree.SetType("network", "guest", "ipaddr", uci.TypeOption, "10.0.0.1") } } ``` -------------------------------- ### Lexer State Transitions Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/parsing-and-internals.md Illustrates the state transitions within the lexer, showing how it moves from the start state through keyword recognition to value or identifier parsing, and handling comments. ```plaintext start -> lexKeyword -> [keyword] -> lexValue/lexIdent -> lexComment (for # lines) ``` -------------------------------- ### Anonymous Section Syntax Examples Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/INDEX.md Demonstrates the array-like notation used to access anonymous sections within UCI configuration files. This includes accessing the first, last, and other indexed sections. ```go tree.Get("firewall", "@rule[0]", "name") // First rule tree.Get("firewall", "@rule[-1]", "target") // Last rule ``` -------------------------------- ### Set UCI Option Types Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/types.md Examples of setting single-valued and list-type UCI options using the Tree.SetType method. ```go // Set a single-valued option err := tree.SetType("network", "lan", "ipaddr", uci.TypeOption, "192.168.1.1") // Set a list-type option with multiple values err := tree.SetType("network", "lan", "dns", uci.TypeList, "8.8.8.8", "8.8.4.4") ``` -------------------------------- ### Add a List Option to a Section Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Sets multiple values for a list-type option within an existing section. This example adds multiple DNS servers to the 'wan' interface configuration. ```go package main import ( "log" uci "github.com/digineo/go-uci" ) func main() { // Create a section first uci.AddSection("network", "wan", "interface") // Add multiple DNS servers using list type err := uci.SetType("network", "wan", "dns", uci.TypeList, "8.8.8.8", "8.8.4.4", "1.1.1.1", ) if err != nil { log.Fatal("Failed to set DNS list:", err) } if err := uci.Commit(); err != nil { log.Fatal("Commit failed:", err) } } ``` -------------------------------- ### GetBool Function Example Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/convenience-functions.md Retrieves and interprets the last value of an option as a boolean. Returns the boolean value and a success indicator. ```go enabled, ok := uci.GetBool("system", "system", "enable_dhcp") if ok { fmt.Println("DHCP enabled:", enabled) } ``` -------------------------------- ### Get Method Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/Tree.md Retrieves all values for a fully qualified option. Returns the values and a boolean indicating success. Automatically loads the config file if not already loaded. Supports anonymous section notation like @type[index]. ```APIDOC ## Get Method ### Description Retrieves all values for a fully qualified option. Returns the values and a boolean indicating success. Automatically loads the config file if not already loaded. ### Parameters #### Path Parameters - **config** (string) - Required - Config file name - **section** (string) - Required - Section name (supports @type[index] syntax for anonymous sections) - **option** (string) - Required - Option name ### Returns - **([]string, bool)** - Values and success indicator ### Example ```go values, ok := tree.Get("network", "lan", "ifname") if ok { fmt.Println("Interface:", values) // ["eth0.1"] } // Using anonymous section notation values, ok := tree.Get("system", "@system[0]", "hostname") if ok { fmt.Println("Hostname:", values) } ``` ``` -------------------------------- ### Get Default Tree Convenience Functions Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/README.md Utilize package-level convenience functions for simple scripts, which operate on the default UCI tree located at /etc/config. ```go uci.Get("system", "system", "hostname") uci.Commit() ``` -------------------------------- ### Get Sections by Type Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/Tree.md Retrieves names of sections matching a specific type from a configuration file. Handles anonymous sections by returning synthetic names. ```go sections, err := tree.GetSections("network", "interface") if err == nil { for _, sec := range sections { fmt.Println("Section:", sec) // lan, wan, @interface[0], etc. } } ``` -------------------------------- ### Setting UCI Options Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/OVERVIEW.md Demonstrates how to set single-valued, multi-valued (list), and boolean options within UCI configuration sections. Use `SetType` for setting values and `Get` or `GetBool` for retrieval. ```go // Single value _ = tree.SetType("network", "lan", "ipaddr", uci.TypeOption, "192.168.1.1") // Multiple values (list) _ = tree.SetType("network", "lan", "dns", uci.TypeList, "8.8.8.8", "8.8.4.4") // Read all values (returned as []string even for single-valued options) values, _ := tree.Get("network", "lan", "dns") // Read last value for convenience lastDns, _ := tree.GetLast("network", "lan", "dns") // Read as boolean enabled, _ := tree.GetBool("system", "system", "enable_dhcp") ``` -------------------------------- ### Handle Missing Sections Gracefully Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Shows how to safely retrieve values from potentially non-existent sections using `Get`, which returns (nil, false) without error. It also demonstrates handling errors when attempting to modify non-existent sections. ```go package main import ( "fmt" "log" uci "github.com/digineo/go-uci" ) func main() { // Get returns (nil, false) for missing sections // This doesn't trigger an error value, exists := uci.Get("network", "nonexistent", "option") if !exists { fmt.Println("Section or option doesn't exist") } // But SetType fails if section doesn't exist err := uci.SetType("network", "nonexistent", "option", uci.TypeOption, "value") if err != nil { var notFound uci.ErrSectionNotFound if err == notFound || fmt.Sprintf("%T", err) == "uci.ErrSectionNotFound" { fmt.Println("Section not found. Create it first:") uci.AddSection("network", "nonexistent", "interface") uci.SetType("network", "nonexistent", "option", uci.TypeOption, "value") } } } ``` -------------------------------- ### Read Hostname from System Configuration Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/INDEX.md Retrieves the last set hostname value from the system configuration. This is useful for getting the current system hostname. ```go hostname, ok := uci.GetLast("system", "system", "hostname") ``` -------------------------------- ### Get All Values for an Option Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/Tree.md Retrieve all string values associated with a specific configuration option. Supports anonymous sections using @type[index] syntax. Automatically loads the config if not already in memory. ```go values, ok := tree.Get("network", "lan", "ifname") if ok { fmt.Println("Interface:", values) // ["eth0.1"] } // Using anonymous section notation values, ok := tree.Get("system", "@system[0]", "hostname") if ok { fmt.Println("Hostname:", values) } ``` -------------------------------- ### SetType Function Example Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/convenience-functions.md Sets or replaces an option with a specific type (OptionType or TypeList) and provided values. Returns an error if the operation fails. ```go err := uci.SetType("network", "lan", "ipaddr", uci.TypeOption, "192.168.1.1") if err != nil { log.Println("Failed to set IP:", err) } ``` -------------------------------- ### Reading Configuration Functions Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/README.md Provides functions to retrieve configuration values from UCI files. Supports getting all values for an option, the last value, boolean values, and listing sections. ```APIDOC ## Reading Configuration ### Functions - **`Get(sectionType, sectionName, optionName)`** - Returns: `[]string, bool` - Purpose: Get all values for an option. - **`GetLast(sectionType, sectionName, optionName)`** - Returns: `string, bool` - Purpose: Get the last value for an option. - **`GetBool(sectionType, sectionName, optionName)`** - Returns: `bool, bool` - Purpose: Get an option's value as a boolean. - **`GetSections(sectionType)`** - Returns: `[]string, error` - Purpose: List all sections of a given type. ``` -------------------------------- ### LoadConfig Method Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/Tree.md Reads a configuration file into memory. If the config is already loaded and forceReload is false, it returns ErrConfigAlreadyLoaded. Accessing configs via Get, Set, Add, or Delete methods automatically loads missing files, making explicit calls to LoadConfig optional. ```APIDOC ## LoadConfig Method ### Description Reads a configuration file into memory. If the config is already loaded and `forceReload` is false, returns `ErrConfigAlreadyLoaded`. Accessing configs via Get, Set, Add, or Delete methods automatically loads missing files, so explicit calls to LoadConfig are optional. ### Parameters #### Path Parameters - **name** (string) - Required - Name of the config file (without directory path) - **forceReload** (bool) - Required - If true, reload even if already in memory ### Returns - **error** - nil on success, error otherwise ### Throws/Errors - `ErrConfigAlreadyLoaded` — Config is already loaded and forceReload is false - File I/O errors — Reading the config file fails - Parse errors — Config file contains invalid UCI syntax ### Example ```go tree := uci.NewTree("/etc/config") err := tree.LoadConfig("network", false) if err != nil { log.Fatal(err) } ``` ``` -------------------------------- ### Work with Multiple Config Trees Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Demonstrates creating and interacting with a UCI configuration tree located in a custom directory. Useful for testing or specific provisioning scenarios. ```go package main import ( "fmt" "log" uci "github.com/digineo/go-uci" ) func main() { // Create tree pointing to custom directory (useful for testing/provisioning) tree := uci.NewTree("/tmp/config") // Read from custom tree value, ok := tree.Get("network", "lan", "ifname") if ok { fmt.Println("LAN interface:", value) } // Modify custom tree _ = tree.AddSection("network", "test", "interface") _ = tree.SetType("network", "test", "ifname", uci.TypeOption, "eth0.4") // Commit changes to custom directory if err := tree.Commit(); err != nil { log.Fatal("Commit failed:", err) } } ``` -------------------------------- ### Configure Multiple Interfaces in Batch Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Demonstrates configuring multiple network interfaces with different settings (static or DHCP) within a single batch operation. All changes are committed at once. ```go package main import ( "fmt" "log" uci "github.com/digineo/go-uci" ) func configureInterface(name, ifname, proto, ipaddr, netmask string) error { if err := uci.AddSection("network", name, "interface"); err != nil { return err } uci.SetType("network", name, "ifname", uci.TypeOption, ifname) uci.SetType("network", name, "proto", uci.TypeOption, proto) if proto == "static" { uci.SetType("network", name, "ipaddr", uci.TypeOption, ipaddr) uci.SetType("network", name, "netmask", uci.TypeOption, netmask) } return nil } func main() { // Configure multiple interfaces interfaces := []struct { name, ifname, proto, ipaddr, netmask string }{ {"lan", "eth0.1", "static", "192.168.1.1", "255.255.255.0"}, {"wan", "eth0.2", "dhcp", "", ""}, {"guest", "eth0.3", "static", "10.0.0.1", "255.255.255.0"}, } for _, iface := range interfaces { if err := configureInterface(iface.name, iface.ifname, iface.proto, iface.ipaddr, iface.netmask); err != nil { log.Fatal("Configuration failed:", err) } } // Commit all changes at once if err := uci.Commit(); err != nil { log.Fatal("Commit failed:", err) } fmt.Println("Configuration complete") } ``` -------------------------------- ### Get Next Scanner Token Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/parsing-and-internals.md Retrieves the next token from the scanner. This operation blocks until a token is available or the end of the input is reached. ```go tok := s.nextToken() ``` -------------------------------- ### Initialize a UCI Tree Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/OVERVIEW.md Demonstrates how to create a new UCI Tree instance for a specific configuration directory. ```go tree := uci.NewTree("/etc/config") ``` -------------------------------- ### Complete Router Provisioning Script Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md A comprehensive script to provision a router by configuring system, network (WAN/LAN), DHCP server, and firewall rules, then committing all changes. ```go package main import ( "fmt" "log" uci "github.com/digineo/go-uci" ) func main() { tree := uci.NewTree("/etc/config") // Step 1: Configure system settings if err := tree.AddSection("system", "system", "system"); err != nil { log.Println("System section exists, that's fine") } tree.SetType("system", "system", "hostname", uci.TypeOption, "MyRouter") // Step 2: Configure WAN interface with DHCP tree.AddSection("network", "wan", "interface") tree.SetType("network", "wan", "ifname", uci.TypeOption, "eth0.2") tree.SetType("network", "wan", "proto", uci.TypeOption, "dhcp") // Step 3: Configure LAN interface with static IP tree.AddSection("network", "lan", "interface") tree.SetType("network", "lan", "ifname", uci.TypeOption, "eth0.1") tree.SetType("network", "lan", "proto", uci.TypeOption, "static") tree.SetType("network", "lan", "ipaddr", uci.TypeOption, "192.168.1.1") tree.SetType("network", "lan", "netmask", uci.TypeOption, "255.255.255.0") // Step 4: Configure WAN6 interface for IPv6 tree.AddSection("network", "wan6", "interface") tree.SetType("network", "wan6", "ifname", uci.TypeOption, "eth0.2") tree.SetType("network", "wan6", "proto", uci.TypeOption, "dhcpv6") // Step 5: Configure DHCP server on LAN tree.AddSection("dhcp", "lan", "dhcp") tree.SetType("dhcp", "lan", "interface", uci.TypeOption, "lan") tree.SetType("dhcp", "lan", "start", uci.TypeOption, "100") tree.SetType("dhcp", "lan", "limit", uci.TypeOption, "150") tree.SetType("dhcp", "lan", "leasetime", uci.TypeOption, "12h") // Step 6: Add default firewall rule tree.AddAnonymousSection("firewall", "rule") tree.SetType("firewall", "@rule[-1]", "name", uci.TypeOption, "Allow SSH") tree.SetType("firewall", "@rule[-1]", "src", uci.TypeOption, "wan") tree.SetType("firewall", "@rule[-1]", "dest_port", uci.TypeOption, "22") tree.SetType("firewall", "@rule[-1]", "target", uci.TypeOption, "ACCEPT") // Commit all changes if err := tree.Commit(); err != nil { log.Fatal("Failed to commit configuration:", err) } fmt.Println("Router configuration completed successfully!") } ``` -------------------------------- ### Basic UCI Configuration Script Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/convenience-functions.md Demonstrates a typical usage pattern for the convenience functions in a Go script. This includes reading a value, adding and modifying sections, and committing the changes. ```go package main import ( "fmt" "log" uci "github.com/digineo/go-uci" ) func main() { // Read a value hostname, ok := uci.GetLast("system", "system", "hostname") if !ok { log.Fatal("Hostname not found") } // Modify configuration _ = uci.AddSection("network", "guest", "interface") _ = uci.SetType("network", "guest", "ifname", uci.TypeOption, "eth0.3") _ = uci.SetType("network", "guest", "proto", uci.TypeOption, "static") // Commit changes if err := uci.Commit(); err != nil { log.Fatal("Commit failed:", err) } fmt.Println("New hostname:", hostname) } ``` -------------------------------- ### Read and Write UCI Configuration (Custom Tree) Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/OVERVIEW.md Shows how to use a custom UCI tree for managing configurations in a specific directory. Includes reading, writing, and committing changes. ```go tree := uci.NewTree("/path/to/config") // Read values, ok := tree.Get("network", "lan", "ifname") // Write _ = tree.AddSection("network", "lan", "interface") _ = tree.SetType("network", "lan", "ifname", uci.TypeOption, "eth0.1") // Commit if err := tree.Commit(); err != nil { log.Fatal(err) } ``` -------------------------------- ### Load UCI Configuration (Implicit and Explicit) Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/OVERVIEW.md Illustrates implicit configuration loading on first access and explicit loading using LoadConfig. ```go // Implicit load on first access values, ok := tree.Get("network", "lan", "ifname") // Explicit load _ = tree.LoadConfig("network", false) ``` -------------------------------- ### Handle Config Load Errors Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Shows how to explicitly load a configuration file and handle potential errors, such as the configuration already being loaded, using `errors.As` for specific error types. ```go package main import ( "fmt" "log" uci "github.com/digineo/go-uci" ) func main() { tree := uci.NewTree("/etc/config") // Explicitly load with error handling err := tree.LoadConfig("network", false) if err != nil { var alreadyLoaded uci.ErrConfigAlreadyLoaded if errors.As(err, &alreadyLoaded) { fmt.Printf("%s already in memory\n", alreadyLoaded.Name) } else { log.Fatal("Failed to load config:", err) } } } ``` -------------------------------- ### Create and Configure a New Network Interface Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/INDEX.md Adds a new network interface section and sets its associated options, such as the interface name. This is a multi-step process involving adding the section and then setting its properties. ```go uci.AddSection("network", "guest", "interface") uci.SetType("network", "guest", "ifname", uci.TypeOption, "eth0.3") uci.Commit() ``` -------------------------------- ### Using the Default UCI Tree Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/INDEX.md Illustrates the convenience functions that operate on the default UCI configuration path, typically '/etc/config'. This is suitable for standard OpenWrt system configurations. ```go // Uses /etc/config uci.Get("system", "system", "hostname") uci.Commit() ``` -------------------------------- ### Handling ErrUnknownOptionType Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/errors.md This example illustrates how to detect and handle invalid option types during JSON unmarshaling. It checks for ErrUnknownOptionType, which is raised when an unknown string is encountered for an OptionType field. ```go var optType uci.OptionType err := json.Unmarshal([]byte(`"invalid"`), &optType) if err != nil { var unknownType ErrUnknownOptionType if errors.As(err, &unknownType) { fmt.Printf("Unknown option type: %s\n", unknownType.Type) } } ``` -------------------------------- ### Read Configuration Values Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/README.md Demonstrates how to read configuration values, including single values, lists of values, and boolean interpretations, from the UCI configuration. ```go package main import ( "fmt" uci "github.com/digineo/go-uci" ) func main() { // Get value hostname, ok := uci.GetLast("system", "system", "hostname") if ok { fmt.Println("Hostname:", hostname) } // Get list of values dnsServers, ok := uci.Get("network", "wan", "dns") if ok { fmt.Println("DNS servers:", dnsServers) } // Get boolean value enabled, ok := uci.GetBool("system", "system", "enable_dhcp") if ok { fmt.Println("DHCP enabled:", enabled) } } ``` -------------------------------- ### Get Next Lexer Item Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/parsing-and-internals.md Retrieves the next lexical item from the lexer. This method blocks until an item is available or the end of the file is reached. It's the primary interface for the scanner. ```go item := l.nextItem() ``` -------------------------------- ### Revert Configuration Changes Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Demonstrates how to revert uncommitted changes to a specific configuration section or all configurations before committing. ```go package main import ( "fmt" uci "github.com/digineo/go-uci" ) func main() { // Make changes uci.AddSection("network", "test", "interface") uci.SetType("network", "test", "ifname", uci.TypeOption, "eth1") // Decide to revert (before commit) uci.Revert("network") // Revert just the network config // or uci.Revert() // Revert all configs fmt.Println("Changes reverted") } ``` -------------------------------- ### Read and Modify UCI Configuration (Default Tree) Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/OVERVIEW.md Demonstrates reading a hostname and modifying network interface settings using the default UCI tree. Changes are committed to disk. ```go package main import ( "fmt" "log" uci "github.com/digineo/go-uci" ) func main() { // Read configuration hostname, ok := uci.GetLast("system", "system", "hostname") if !ok { log.Fatal("hostname not found") } fmt.Println("Hostname:", hostname) // Modify configuration _ = uci.AddSection("network", "guest", "interface") _ = uci.SetType("network", "guest", "ifname", uci.TypeOption, "eth0.3") _ = uci.SetType("network", "guest", "proto", uci.TypeOption, "static") _ = uci.SetType("network", "guest", "ipaddr", uci.TypeOption, "10.0.0.1") // Commit changes if err := uci.Commit(); err != nil { log.Fatal("Commit failed:", err) } } ``` -------------------------------- ### Get Boolean Value for an Option Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/Tree.md Retrieve and interpret the last value of an option as a boolean. Recognizes common true/false string representations. Returns false and false if the value cannot be interpreted as a boolean. ```go enabled, ok := tree.GetBool("system", "system", "enable_dhcp") if ok && enabled { fmt.Println("DHCP is enabled") } ``` -------------------------------- ### Get Last Value for an Option Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/Tree.md Retrieve the most recent string value for a configuration option. Useful for options expected to have a single value. Returns false if the config, section, or option is not found. ```go hostname, ok := tree.GetLast("system", "system", "hostname") if ok { fmt.Println("Hostname:", hostname) } ``` -------------------------------- ### Create a New Named Interface Section Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Adds a new section with a specific name to a configuration file and sets its options. Changes are committed to disk afterwards. ```go package main import ( "log" uci "github.com/digineo/go-uci" ) func main() { // Add a new named section if err := uci.AddSection("network", "guest", "interface"); err != nil { log.Fatal("Failed to add section:", err) } // Set single-valued options uci.SetType("network", "guest", "ifname", uci.TypeOption, "eth0.3") uci.SetType("network", "guest", "proto", uci.TypeOption, "static") uci.SetType("network", "guest", "ipaddr", uci.TypeOption, "10.0.0.1") uci.SetType("network", "guest", "netmask", uci.TypeOption, "255.255.255.0") // Commit changes to disk if err := uci.Commit(); err != nil { log.Fatal("Commit failed:", err) } } ``` -------------------------------- ### Scanner State Transitions Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/parsing-and-internals.md Describes the state transitions of the scanner, which progresses from an initial state by parsing keywords to identify token types like sections, options, or lists, and then returns to the start state. ```plaintext scanStart -> [parse keyword] -> tokSection/tokOption/tokList -> scanStart (repeat) ``` -------------------------------- ### Write Configuration Changes Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/README.md Illustrates how to modify UCI configuration by adding sections and setting options, followed by committing the changes to disk. Error handling for the commit operation is included. ```go package main import ( "log" uci "github.com/digineo/go-uci" ) func main() { // Create section uci.AddSection("network", "guest", "interface") // Set options uci.SetType("network", "guest", "ifname", uci.TypeOption, "eth0.3") uci.SetType("network", "guest", "proto", uci.TypeOption, "static") uci.SetType("network", "guest", "ipaddr", uci.TypeOption, "10.0.0.1") // Commit changes if err := uci.Commit(); err != nil { log.Fatal("Commit failed:", err) } } ``` -------------------------------- ### Read Multiple Configuration Values (List) Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Retrieves all values associated with a list-type option. Iterates through the list to print each DNS server. ```go package main import ( "fmt" uci "github.com/digineo/go-uci" ) func main() { // Get all DNS servers (list option) dnsServers, ok := uci.Get("network", "wan", "dns") if ok { for i, dns := range dnsServers { fmt.Printf("DNS %d: %s\n", i+1, dns) } } } ``` -------------------------------- ### Handle UCI Errors, Specifically Section Not Found Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/INDEX.md Demonstrates how to check for and handle specific UCI errors, such as when a requested section does not exist. This pattern is crucial for robust configuration management. ```go if err != nil { var notFound uci.ErrSectionNotFound if errors.As(err, ¬Found) { // Handle missing section } } ``` -------------------------------- ### Create New UCI Tree Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/Tree.md Instantiate a new Tree object pointing to a specific configuration directory. This is the entry point for managing UCI configurations. ```go tree := uci.NewTree("/path/to/config") ``` -------------------------------- ### Run UCI Tests Source: https://github.com/digineo/go-uci/blob/v2/README.md Command to execute the test suite for the go-uci library. Ensure all tests pass before submitting changes. ```console $ go test github.com/digineo/go-uci/... ``` -------------------------------- ### Enumerate All Sections of a Specific Type Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Retrieves all section names of a given type within a configuration file. It then iterates through these sections to extract specific interface names. ```go package main import ( "fmt" uci "github.com/digineo/go-uci" ) func main() { // Get all interface sections sections, err := uci.GetSections("network", "interface") if err != nil { fmt.Println("Error:", err) return } for _, section := range sections { ifname, ok := uci.GetLast("network", section, "ifname") if ok { fmt.Printf("Section %s uses interface %s\n", section, ifname) } } } ``` -------------------------------- ### Access Anonymous Firewall Rules Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Demonstrates accessing and enumerating anonymous sections, specifically firewall rules, using index-based access and section enumeration. ```go package main import ( "fmt" uci "github.com/digineo/go-uci" ) func main() { // Assume firewall config has multiple rule sections // Access first rule val, ok := uci.Get("firewall", "@rule[0]", "name") if ok { fmt.Println("First rule:", val) } // Access last rule val, ok = uci.Get("firewall", "@rule[-1]", "target") if ok { fmt.Println("Last rule target:", val) } // Enumerate all rules sections, _ := uci.GetSections("firewall", "rule") for i, sec := range sections { fmt.Printf("Rule %d: %s\n", i, sec) } } ``` -------------------------------- ### Tree Interface Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/README.md Represents a single configuration directory and manages its files. Provides methods for interacting with the configuration, including reading, writing, and committing changes. ```APIDOC ## Tree Interface ### Methods - **`NewTree(configDir string)`** - Returns: `*Tree` - Purpose: Creates a new Tree instance for the specified configuration directory. - **`Get(sectionType, sectionName, optionName)`** (on Tree instance) - Returns: `[]string, bool` - Purpose: Get all values for an option within the tree. - **`SetType(sectionType, sectionName, optionName, valueType, ...values)`** (on Tree instance) - Returns: `error` - Purpose: Set an option with a specific type and value(s) within the tree. - **`Commit()`** (on Tree instance) - Returns: `error` - Purpose: Write all pending changes for this tree to disk. ``` -------------------------------- ### Set Single-Valued and List-Type Options Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/README.md Configure options within a section. Options can be set as single values or as a list of values, specifying the desired type. ```go // Single value tree.SetType("network", "lan", "ipaddr", uci.TypeOption, "192.168.1.1") // Multiple values (list) tree.SetType("network", "lan", "dns", uci.TypeList, "8.8.8.8", "8.8.4.4") ``` -------------------------------- ### JSON Marshaling/Unmarshaling for OptionType Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/types.md Demonstrates how OptionType marshals to and unmarshals from JSON strings like "option" or "list". ```go // Marshaling data, _ := json.Marshal(uci.TypeOption) // => "option" data, _ := json.Marshal(uci.TypeList) // => "list" // Unmarshaling var t uci.OptionType json.Unmarshal([]byte(`"list"`), &t) // t = TypeList ``` -------------------------------- ### Access and Add Anonymous Firewall Rules Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/INDEX.md Shows how to access anonymous sections like firewall rules using array-like notation and how to add a new anonymous rule. This is useful for managing dynamic or numerous similar sections. ```go // Access first rule uci.Get("firewall", "@rule[0]", "name") // Access last rule uci.Get("firewall", "@rule[-1]", "target") // Add new rule uci.AddAnonymousSection("firewall", "rule") ``` -------------------------------- ### UCI Configuration Access Functions Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/INDEX.md Provides a summary of common functions for retrieving configuration values. These functions offer different ways to access data based on whether the last value, a boolean, or all values are needed. ```go uci.Get(config, section, option) // Get all values uci.GetLast(config, section, option) // Get last value uci.GetBool(config, section, option) // Get as boolean uci.GetSections(config, secType) // List sections ``` -------------------------------- ### Concurrent Tree Operations Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/INDEX.md Demonstrates safe concurrent access to the Tree structure from multiple goroutines. Ensure the Tree is initialized before use. ```go go tree.Get("network", "lan", "ipaddr") go tree.Set("network", "wan", "proto", uci.TypeOption, "dhcp") ``` -------------------------------- ### Accessing Named and Anonymous Sections Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/OVERVIEW.md Shows how to retrieve values from both named sections and anonymous sections using their respective notations. ```go tree.Get("network", "lan", "ifname") // Named section "lan" tree.Get("system", "@system[0]", "hostname") // First @system section tree.Get("rules", "@rule[-1]", "name") // Last @rule section ``` -------------------------------- ### NewTree Constructor Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/api-reference/Tree.md Creates a new Tree instance that manages configurations in the specified directory. The root parameter specifies the base directory path containing UCI config files. ```APIDOC ## NewTree Constructor ### Description Creates a new Tree instance pointing to the specified root directory. ### Parameters #### Path Parameters - **root** (string) - Required - Base directory path containing UCI config files ### Returns - **Tree** - A new Tree instance that manages configurations in the specified directory. ### Example ```go tree := uci.NewTree("/path/to/config") ``` ``` -------------------------------- ### Convenience Functions Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/COMPLETION_SUMMARY.txt Documentation for convenience functions that operate on the default Tree instance. ```APIDOC ## Convenience Functions ### Description These functions provide a simplified interface for common operations by utilizing the default `Tree` instance. They are suitable for straightforward configuration management tasks. ### Methods - **LoadConfig(path string) error**: Loads the UCI configuration from the specified file path using the default tree. - **Get(section, option string) (string, error)**: Retrieves the value of a specific option within a section using the default tree. - **GetLast(section, option string) (string, error)**: Retrieves the last value of a specific option within a section using the default tree. - **GetBool(section, option string) (bool, error)**: Retrieves the boolean value of a specific option within a section using the default tree. - **GetSections(sectionType string) ([]string, error)**: Retrieves all section names of a given type using the default tree. - **SetType(section, sectionType string) error**: Sets the type of a given section using the default tree. - **Del(section, option string) error**: Deletes a specific option from a section using the default tree. - **AddSection(sectionType string) (string, error)**: Adds a new section of the specified type and returns its name using the default tree. - **DelSection(section string) error**: Deletes an entire section using the default tree. - **Commit() error**: Saves the current configuration changes to the underlying storage using the default tree. - **Revert() error**: Discards any uncommitted changes and reverts to the last committed state using the default tree. ``` -------------------------------- ### Create a Firewall Rule (Anonymous Section) Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/examples.md Adds an anonymous section to the firewall configuration to define a new rule. Options are set using a special selector for the last added anonymous section. ```go package main import ( "log" uci "github.com/digineo/go-uci" ) func main() { // Add an anonymous section (auto-numbered) if err := uci.AddAnonymousSection("firewall", "rule"); err != nil { log.Fatal("Failed to add rule:", err) } // Set rule options uci.SetType("firewall", "@rule[-1]", "name", uci.TypeOption, "Allow HTTP") uci.SetType("firewall", "@rule[-1]", "src", uci.TypeOption, "wan") uci.SetType("firewall", "@rule[-1]", "dest", uci.TypeOption, "lan") uci.SetType("firewall", "@rule[-1]", "dest_port", uci.TypeOption, "80") uci.SetType("firewall", "@rule[-1]", "target", uci.TypeOption, "ACCEPT") if err := uci.Commit(); err != nil { log.Fatal("Commit failed:", err) } } ``` -------------------------------- ### ErrConfigAlreadyLoaded Struct Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/types.md Error indicating that a configuration has already been loaded. ```APIDOC ## ErrConfigAlreadyLoaded ### Description See [errors.md](errors.md) ``` -------------------------------- ### Default Tree vs Custom Trees Source: https://github.com/digineo/go-uci/blob/v2/_autodocs/INDEX.md Differentiates between using the default UCI configuration tree (convenience functions) and managing custom trees with specific file paths. ```APIDOC ## Default Tree vs Custom Trees ### Description Differentiates between using the default UCI configuration tree (convenience functions) and managing custom trees with specific file paths. ### Default Tree (convenience functions) - **Usage**: Uses the default configuration path (e.g., `/etc/config`). - **Example**: `uci.Get("system", "system", "hostname")` - **Best for**: Simple scripts and standard OpenWrt systems. ### Custom Trees - **Usage**: Allows specifying a custom path for configuration files. - **Example**: `tree := uci.NewTree("/path/to/config"); value, ok := tree.Get("system", "system", "hostname")` - **Best for**: Testing, provisioning, managing multiple configurations, or custom directory structures. ```