Skip to content

Instantly share code, notes, and snippets.

@mikeschinkel
Last active January 29, 2025 05:40
Show Gist options
  • Save mikeschinkel/d745132837361264f884e6c2de3d2900 to your computer and use it in GitHub Desktop.
Save mikeschinkel/d745132837361264f884e6c2de3d2900 to your computer and use it in GitHub Desktop.
Example use-case for github.com/micromdm/plist where `UnmarshalPlist()` needs access to `pval`
package main
import (
"bytes"
"fmt"
"os"
"github.com/micromdm/plist"
)
// Value is key to my use-case
type Value struct {
Value any
}
// UnmarshalPlist only captures the value if the type of `value` matches the type
// of `v`, the reflect.Value. Otherwise value is equal to `nil`. If I change the
// type of `value` to any specific type, it captures all values for that type but
// sets all `*Value` objects to `nil`. I guess I could literally create a slice
// of reflect types and create a zero instance of each and loop through them
// until f() no longer returns an error but that would probably cur performance
// in half, if not 1/10th or worse.
func (v *Value) UnmarshalPlist(f func(interface{}) error) (err error) {
var value any
err = f(&value)
v.Value = value
return nil
}
type ManifestKey struct {
Name string `plist:"pfm_name"`
Default Value `plist:"pfm_default,omitempty"`
Subkeys []ManifestKey `plist:"pfm_subkeys,omitempty"`
}
type ProfileManifest struct {
Domain string `plist:"pfm_domain"`
Subkeys []ManifestKey `plist:"pfm_subkeys"`
}
func main() {
r := bytes.NewBuffer([]byte(dockYAML))
decoder := plist.NewXMLDecoder(r)
pm := ProfileManifest{}
err := decoder.Decode(&pm)
if err != nil {
fmt.Printf("Failed to decode profile manifest: %s", err.Error())
os.Exit(1)
}
fmt.Println(pm)
}
// dockYAML is a subset of https://github.com/ProfileManifests/ProfileManifests/tree/master/Manifests/ManifestsApple/com.apple.dock.plist
const dockYAML = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>pfm_domain</key>
<string>com.apple.dock</string>
<key>pfm_subkeys</key>
<array>
<dict>
<key>pfm_name</key>
<string>static-apps</string>
<key>pfm_subkeys</key>
<array>
<dict>
<key>pfm_name</key>
<string>StaticItem</string>
<key>pfm_subkeys</key>
<array>
<dict>
<key>pfm_default</key>
<string>file-tile</string>
<key>pfm_name</key>
<string>tile-type</string>
</dict>
<dict>
<key>pfm_name</key>
<string>tile-data</string>
<key>pfm_subkeys</key>
<array>
<dict>
<key>pfm_name</key>
<string>label</string>
</dict>
<dict>
<key>pfm_name</key>
<string>file-label</string>
</dict>
<dict>
<key>pfm_name</key>
<string>file-type</string>
</dict>
<dict>
<key>pfm_name</key>
<string>file-data</string>
<key>pfm_subkeys</key>
<array>
<dict>
<key>pfm_name</key>
<string>_CFURLString</string>
</dict>
<dict>
<key>pfm_name</key>
<string>_CFURLStringType</string>
</dict>
</array>
</dict>
<dict>
<key>pfm_name</key>
<string>url</string>
</dict>
</array>
</dict>
</array>
</dict>
</array>
</dict>
</array>
</dict>
</plist>`
@mikeschinkel
Copy link
Author

Here is the ultimate resolution: micromdm/plist#46

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment