Utils API
The pkg/utils
package provides utility functions for file operations, path manipulation, and XML processing used throughout the NuGet Config Parser library.
Overview
The Utils API provides:
- File system operations and checks
- Cross-platform path manipulation
- XML processing utilities
- String and data validation helpers
File System Operations
FileExists
func FileExists(filePath string) bool
Checks if a file exists and is not a directory.
Parameters:
filePath
(string): Path to the file to check
Returns:
bool
: True if the file exists and is not a directory, false otherwise
Example:
import "github.com/scagogogo/nuget-config-parser/pkg/utils"
configPath := "/path/to/NuGet.Config"
if utils.FileExists(configPath) {
fmt.Printf("Configuration file exists: %s\n", configPath)
// Proceed with parsing...
} else {
fmt.Printf("Configuration file not found: %s\n", configPath)
// Create default configuration...
}
DirExists
func DirExists(dirPath string) bool
Checks if a directory exists.
Parameters:
dirPath
(string): Path to the directory to check
Returns:
bool
: True if the directory exists, false otherwise
Example:
configDir := "/etc/nuget"
if utils.DirExists(configDir) {
fmt.Printf("Configuration directory exists: %s\n", configDir)
} else {
fmt.Printf("Creating configuration directory: %s\n", configDir)
err := os.MkdirAll(configDir, 0755)
if err != nil {
log.Fatalf("Failed to create directory: %v", err)
}
}
IsReadableFile
func IsReadableFile(filePath string) bool
Checks if a file exists and is readable.
Parameters:
filePath
(string): Path to the file to check
Returns:
bool
: True if the file exists and is readable, false otherwise
Example:
configPath := "/path/to/NuGet.Config"
if utils.IsReadableFile(configPath) {
// Safe to read the file
content, err := os.ReadFile(configPath)
if err != nil {
log.Printf("Error reading file: %v", err)
}
} else {
fmt.Printf("File is not readable: %s\n", configPath)
}
IsWritableFile
func IsWritableFile(filePath string) bool
Checks if a file is writable (or if it doesn't exist, if the directory is writable).
Parameters:
filePath
(string): Path to the file to check
Returns:
bool
: True if the file is writable, false otherwise
Example:
configPath := "/path/to/NuGet.Config"
if utils.IsWritableFile(configPath) {
// Safe to write to the file
err := os.WriteFile(configPath, []byte("content"), 0644)
if err != nil {
log.Printf("Error writing file: %v", err)
}
} else {
fmt.Printf("File is not writable: %s\n", configPath)
}
Path Manipulation
IsAbsolutePath
func IsAbsolutePath(path string) bool
Checks if a path is absolute.
Parameters:
path
(string): Path to check
Returns:
bool
: True if the path is absolute, false if relative
Example:
// Unix/Linux examples
fmt.Println(utils.IsAbsolutePath("/etc/nuget")) // true
fmt.Println(utils.IsAbsolutePath("./config")) // false
fmt.Println(utils.IsAbsolutePath("../config")) // false
// Windows examples
fmt.Println(utils.IsAbsolutePath("C:\\nuget\\config")) // true
fmt.Println(utils.IsAbsolutePath(".\\config")) // false
NormalizePath
func NormalizePath(path string) string
Normalizes a file path by cleaning it and converting to the OS-specific format.
Parameters:
path
(string): Path to normalize
Returns:
string
: Normalized path
Example:
// Clean up redundant path elements
messyPath := "/etc/nuget/../nuget/./config"
cleanPath := utils.NormalizePath(messyPath)
fmt.Printf("Normalized: %s\n", cleanPath)
// Output: /etc/nuget/config
// Handle different separators
mixedPath := "/etc\\nuget/config"
normalizedPath := utils.NormalizePath(mixedPath)
fmt.Printf("Normalized: %s\n", normalizedPath)
JoinPaths
func JoinPaths(basePath string, paths ...string) string
Joins multiple path elements using the OS-specific path separator.
Parameters:
basePath
(string): Base pathpaths
(...string): Additional path elements to join
Returns:
string
: Joined path
Example:
// Join path elements
basePath := "/etc"
configPath := utils.JoinPaths(basePath, "nuget", "NuGet.Config")
fmt.Printf("Joined path: %s\n", configPath)
// Output: /etc/nuget/NuGet.Config
// Windows example
winBase := "C:\\Users"
winPath := utils.JoinPaths(winBase, "username", ".nuget", "packages")
fmt.Printf("Windows path: %s\n", winPath)
// Output: C:\Users\username\.nuget\packages
// Handle trailing slashes
trailingSlash := "/home/user/"
result := utils.JoinPaths(trailingSlash, "nuget", "packages")
fmt.Printf("Result: %s\n", result)
// Output: /home/user/nuget/packages
ResolvePath
func ResolvePath(basePath, path string) string
Resolves a path relative to a base path. If the path is already absolute, returns it normalized.
Parameters:
basePath
(string): Base path for resolving relative pathspath
(string): Path to resolve (can be relative or absolute)
Returns:
string
: Resolved absolute path
Example:
basePath := "/etc/nuget"
// Resolve relative path
relativePath := "../packages/cache"
resolvedRelative := utils.ResolvePath(basePath, relativePath)
fmt.Printf("Relative '%s' resolved to: %s\n", relativePath, resolvedRelative)
// Output: Relative '../packages/cache' resolved to: /etc/packages/cache
// Handle absolute path
absolutePath := "/var/nuget/packages"
resolvedAbsolute := utils.ResolvePath(basePath, absolutePath)
fmt.Printf("Absolute '%s' remains: %s\n", absolutePath, resolvedAbsolute)
// Output: Absolute '/var/nuget/packages' remains: /var/nuget/packages
ExpandEnvVars
func ExpandEnvVars(path string) string
Expands environment variables in a path string.
Parameters:
path
(string): Path containing environment variables
Returns:
string
: Path with environment variables expanded
Supported Formats:
- Unix/Linux/macOS:
$VAR
or${VAR}
- Windows:
%VAR%
Example:
// Unix/Linux/macOS examples
unixPath := "$HOME/.nuget/packages"
expandedUnixPath := utils.ExpandEnvVars(unixPath)
fmt.Printf("Expanded: %s\n", expandedUnixPath)
// Output: Expanded: /home/user/.nuget/packages
bracedPath := "${HOME}/.config/NuGet/NuGet.Config"
expandedBracedPath := utils.ExpandEnvVars(bracedPath)
fmt.Printf("Expanded: %s\n", expandedBracedPath)
// Windows examples
winPath := "%USERPROFILE%\\.nuget\\packages"
expandedWinPath := utils.ExpandEnvVars(winPath)
fmt.Printf("Expanded: %s\n", expandedWinPath)
// Output: Expanded: C:\Users\username\.nuget\packages
XML Processing
ValidateXML
func ValidateXML(content []byte) error
Validates that content is well-formed XML.
Parameters:
content
([]byte): XML content to validate
Returns:
error
: Error if XML is not well-formed, nil if valid
Example:
// Valid XML
validXML := []byte(`<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>`)
err := utils.ValidateXML(validXML)
if err != nil {
fmt.Printf("Invalid XML: %v\n", err)
} else {
fmt.Println("XML is valid")
}
// Invalid XML
invalidXML := []byte(`<configuration><packageSources><add key="test"`)
err = utils.ValidateXML(invalidXML)
if err != nil {
fmt.Printf("Invalid XML: %v\n", err)
}
FormatXML
func FormatXML(content []byte) ([]byte, error)
Formats XML content with proper indentation.
Parameters:
content
([]byte): XML content to format
Returns:
[]byte
: Formatted XML contenterror
: Error if formatting fails
Example:
// Unformatted XML
unformattedXML := []byte(`<configuration><packageSources><add key="nuget.org" value="https://api.nuget.org/v3/index.json" /></packageSources></configuration>`)
formattedXML, err := utils.FormatXML(unformattedXML)
if err != nil {
log.Printf("Failed to format XML: %v", err)
} else {
fmt.Println("Formatted XML:")
fmt.Println(string(formattedXML))
}
// Output:
// <?xml version="1.0" encoding="UTF-8"?>
// <configuration>
// <packageSources>
// <add key="nuget.org" value="https://api.nuget.org/v3/index.json"/>
// </packageSources>
// </configuration>
ExtractXMLElement
func ExtractXMLElement(content []byte, elementName string) ([]byte, error)
Extracts a specific XML element from content.
Parameters:
content
([]byte): XML content to searchelementName
(string): Name of the element to extract
Returns:
[]byte
: Extracted element contenterror
: Error if element not found or extraction fails
Example:
xmlContent := []byte(`<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="local" value="/path/to/local" />
</packageSources>
<config>
<add key="globalPackagesFolder" value="/packages" />
</config>
</configuration>`)
// Extract packageSources element
packageSources, err := utils.ExtractXMLElement(xmlContent, "packageSources")
if err != nil {
log.Printf("Failed to extract element: %v", err)
} else {
fmt.Println("Package sources:")
fmt.Println(string(packageSources))
}
String Utilities
IsEmptyOrWhitespace
func IsEmptyOrWhitespace(s string) bool
Checks if a string is empty or contains only whitespace.
Parameters:
s
(string): String to check
Returns:
bool
: True if string is empty or whitespace-only
Example:
fmt.Println(utils.IsEmptyOrWhitespace("")) // true
fmt.Println(utils.IsEmptyOrWhitespace(" ")) // true
fmt.Println(utils.IsEmptyOrWhitespace("\t\n")) // true
fmt.Println(utils.IsEmptyOrWhitespace("content")) // false
fmt.Println(utils.IsEmptyOrWhitespace(" content ")) // false
TrimWhitespace
func TrimWhitespace(s string) string
Trims leading and trailing whitespace from a string.
Parameters:
s
(string): String to trim
Returns:
string
: Trimmed string
Example:
input := " \t content with spaces \n "
trimmed := utils.TrimWhitespace(input)
fmt.Printf("Trimmed: '%s'\n", trimmed)
// Output: Trimmed: 'content with spaces'
SanitizeXMLValue
func SanitizeXMLValue(value string) string
Sanitizes a string value for safe use in XML attributes or content.
Parameters:
value
(string): Value to sanitize
Returns:
string
: Sanitized value safe for XML
Example:
unsafeValue := `value with "quotes" & <brackets>`
safeValue := utils.SanitizeXMLValue(unsafeValue)
fmt.Printf("Sanitized: %s\n", safeValue)
// Output: Sanitized: value with "quotes" & <brackets>
Validation Utilities
IsValidURL
func IsValidURL(urlStr string) bool
Validates if a string is a valid URL.
Parameters:
urlStr
(string): URL string to validate
Returns:
bool
: True if URL is valid
Example:
validURLs := []string{
"https://api.nuget.org/v3/index.json",
"http://localhost:8080/nuget",
"file:///path/to/packages",
}
invalidURLs := []string{
"not-a-url",
"://missing-scheme",
"https://",
}
for _, url := range validURLs {
if utils.IsValidURL(url) {
fmt.Printf("Valid URL: %s\n", url)
}
}
for _, url := range invalidURLs {
if !utils.IsValidURL(url) {
fmt.Printf("Invalid URL: %s\n", url)
}
}
IsValidPackageSourceKey
func IsValidPackageSourceKey(key string) bool
Validates if a string is a valid package source key.
Parameters:
key
(string): Package source key to validate
Returns:
bool
: True if key is valid
Validation Rules:
- Not empty or whitespace-only
- Contains only alphanumeric characters, hyphens, underscores, and dots
- Does not start or end with special characters
Example:
validKeys := []string{
"nuget.org",
"company-feed",
"local_packages",
"feed123",
}
invalidKeys := []string{
"",
" ",
"invalid key with spaces",
"-starts-with-dash",
"ends-with-dash-",
"has@invalid#chars",
}
for _, key := range validKeys {
if utils.IsValidPackageSourceKey(key) {
fmt.Printf("Valid key: %s\n", key)
}
}
for _, key := range invalidKeys {
if !utils.IsValidPackageSourceKey(key) {
fmt.Printf("Invalid key: '%s'\n", key)
}
}
Complete Usage Example
package main
import (
"fmt"
"log"
"os"
"github.com/scagogogo/nuget-config-parser/pkg/utils"
)
func main() {
// File operations
configPath := "/path/to/NuGet.Config"
if utils.FileExists(configPath) {
fmt.Printf("Configuration file exists: %s\n", configPath)
if utils.IsReadableFile(configPath) {
content, err := os.ReadFile(configPath)
if err != nil {
log.Printf("Error reading file: %v", err)
return
}
// Validate XML
if err := utils.ValidateXML(content); err != nil {
log.Printf("Invalid XML: %v", err)
return
}
// Format XML
formatted, err := utils.FormatXML(content)
if err != nil {
log.Printf("Failed to format XML: %v", err)
} else {
fmt.Println("Formatted XML:")
fmt.Println(string(formatted))
}
}
} else {
fmt.Printf("Configuration file not found: %s\n", configPath)
// Create directory if needed
configDir := utils.JoinPaths("/etc", "nuget")
if !utils.DirExists(configDir) {
fmt.Printf("Creating directory: %s\n", configDir)
err := os.MkdirAll(configDir, 0755)
if err != nil {
log.Fatalf("Failed to create directory: %v", err)
}
}
}
// Path manipulation
basePath := "/etc/nuget"
relativePath := "../packages"
resolvedPath := utils.ResolvePath(basePath, relativePath)
fmt.Printf("Resolved path: %s\n", resolvedPath)
// Environment variable expansion
envPath := "$HOME/.nuget/packages"
expandedPath := utils.ExpandEnvVars(envPath)
fmt.Printf("Expanded path: %s\n", expandedPath)
// Validation
testURL := "https://api.nuget.org/v3/index.json"
if utils.IsValidURL(testURL) {
fmt.Printf("Valid URL: %s\n", testURL)
}
testKey := "nuget.org"
if utils.IsValidPackageSourceKey(testKey) {
fmt.Printf("Valid package source key: %s\n", testKey)
}
}
Best Practices
- Check file existence: Always use
FileExists()
before attempting file operations - Validate inputs: Use validation functions for URLs and keys before processing
- Handle paths correctly: Use path manipulation functions for cross-platform compatibility
- Sanitize XML content: Use
SanitizeXMLValue()
for user-provided content - Validate XML: Use
ValidateXML()
before parsing to catch malformed content early - Normalize paths: Use
NormalizePath()
to clean up path strings - Expand environment variables: Use
ExpandEnvVars()
for flexible path configuration
Thread Safety
All utility functions in this package are thread-safe and can be used concurrently.