Skip to content

aurc/plist

Repository files navigation

plist

GoDoc example workflow codecov GitHub license

Convert Apple's plist file format to JSON or YAML (natural & high fidelity modes) effortlessly. Often complex bundles and other files are very hard to read or seamlessly port to other applications.

This Package Provides:

  • A CLI tool for reading and converting PLIST that can be fully intgrated with shell scripting.
  • A golang module that can be imported directly into golang projects with an easy to use API.
  • A native bundle (coming soon) that can be imported to any C-compatible applications (e.g. Swift, C, C++, Python, etc).

Installation

Homebrew For the Inpatient

Consider using homebrew to install the utility from there:

brew install aurc/tap/plist

More information here: plist homebrew tap

Golang

# As CLI Tool
go install github.com/aurc/plist@latest
# Then (assumung $GOPATH/bin set in the path)
plist --help

OR

# For working only with parser lib on your go code
go get github.com/aurc/plist/pkg/plistparser
# For entire package with CLI tool on your local (more below)
go get github.com/aurc/plist

Basic Usage

CLI Tool

To get started:

go install github.com/aurc/plist@latest

Assuming your $GOPATH/bin is in your path, then:

plist -h

Output:

This tool converts Apple's Property List (.plist) inputs into several useful
formats, such as JSON and YAML.

It supports both a file name as input and a piped ('|') input which might be useful
on more involved shell scripts.

For example:
    plist json -i myfile.plist
    cat myfile.plist | plist json

For individual commands instructions run:
        plist [command] -h
        plist json -h

Usage:
  plist [command]

Available Commands:
  completion  generate the autocompletion script for the specified shell
  help        Help about any command
  json        Converts plist into JSON
  yaml        Converts plist into YAML

Flags:
  -h, --help            help for plist
  -x, --high-fidelity   Specifies whether the output should be a one-to-one translation of the plist. 
                        Set to true, it's one-to-one. The default is false as it produces a more readable file.
  -i, --input string    Specifies a input file, e.g. --input myFile.plist

Use "plist [command] --help" for more information about a command.

Given the input

<?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>idle_wakeups</key><integer>103</integer>
        <key>idle_wakeups_per_s</key><real>20.533</real>
        <key>timer_wakeups</key>
        <array>
            <dict>
                <key>interval_ns</key><integer>2000000</integer>
                <key>wakeups</key><integer>270</integer>
                <key>wakeups_per_s</key><real>53.8244</real>
            </dict>
            <dict>
                <key>interval_ns</key><integer>1500000</integer>
                <key>wakeups</key><integer>170</integer>
                <key>wakeups_per_s</key><real>22.44</real>
            </dict>
        </array>
    </dict>
</plist>

Output as JSON (Natural conversion)

plist json -i docs/demo/demo.plist -p true

OR

cat docs/demo/demo.plist | plist json -p true

The natural conversion will hide the verbosity of datatypes, having types to be easily inferred, for example a <real>1.1</real> becomes just 1.1 without quotes whereas a <dict> will look more like a JSON objects, with the key entries listed as fields.

{
  "idle_wakeups": 103,
  "idle_wakeups_per_s": 20.533,
  "timer_wakeups": [
    {
      "interval_ns": 2000000,
      "wakeups": 270,
      "wakeups_per_s": 53.8244
    },
    {
      "interval_ns": 1500000,
      "wakeups": 170,
      "wakeups_per_s": 22.44
    }
  ]
}

Output as YAML (Natural conversion)

plist yaml -i docs/demo/demo.plist

OR

cat docs/demo/demo.plist | plist yaml

Gives...

idle_wakeups: 103
idle_wakeups_per_s: 20.533
timer_wakeups:
- interval_ns: 2000000
  wakeups: 270
  wakeups_per_s: 53.8244
- interval_ns: 1500000
  wakeups: 170
  wakeups_per_s: 22.44

Output as JSON (High fidelity)

plist json -i docs/demo/demo.plist -p true -x true

OR

cat docs/demo/demo.plist | plist json -p true -x true

Depending on your application, you might want a full, high fidelity translation, defining each entry and explicitly exposing the data types. For that, given the same input above, you'll have the following output:

{
  "type": "dict",
  "value": [
    {
      "k": "idle_wakeups",
      "v": {
        "type": "integer",
        "value": "103"
      }
    },
    {
      "k": "idle_wakeups_per_s",
      "v": {
        "type": "real",
        "value": "20.533"
      }
    },
    {
      "k": "timer_wakeups",
      "v": {
        "type": "array",
        "value": [
          {
            "type": "dict",
            "value": [
              {
                "k": "interval_ns",
                "v": {
                  "type": "integer",
                  "value": "2000000"
                }
              },
              {
                "k": "wakeups",
                "v": {
                  "type": "integer",
                  "value": "270"
                }
              },
              {
                "k": "wakeups_per_s",
                "v": {
                  "type": "real",
                  "value": "53.8244"
                }
              }
            ]
          },
          {
            "type": "dict",
            "value": [
              {
                "k": "interval_ns",
                "v": {
                  "type": "integer",
                  "value": "1500000"
                }
              },
              {
                "k": "wakeups",
                "v": {
                  "type": "integer",
                  "value": "170"
                }
              },
              {
                "k": "wakeups_per_s",
                "v": {
                  "type": "real",
                  "value": "22.44"
                }
              }
            ]
          }
        ]
      }
    }
  ]
}

Output as YAML (High fidelity)

plist yaml -i docs/demo/demo.plist -x true

OR

cat docs/demo/demo.plist | plist yaml -x true
type: dict
value:
- k: idle_wakeups
  v:
    type: integer
    value: "103"
- k: idle_wakeups_per_s
  v:
    type: real
    value: "20.533"
- k: timer_wakeups
  v:
    type: array
    value:
    - type: dict
      value:
      - k: interval_ns
        v:
          type: integer
          value: "2000000"
      - k: wakeups
        v:
          type: integer
          value: "270"
      - k: wakeups_per_s
        v:
          type: real
          value: "53.8244"
    - type: dict
      value:
      - k: interval_ns
        v:
          type: integer
          value: "1500000"
      - k: wakeups
        v:
          type: integer
          value: "170"
      - k: wakeups_per_s
        v:
          type: real
          value: "22.44"

As a Package

$ go get github.com/aurc/plist/pkg/plistparser
package main

import (
    "fmt"
	
    "github.com/aurc/plist/pkg/plistparser"
)

func main() {
  plistFile := `<?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">
  <array>
      <string>String</string>
  </array>
  </plist>`

  out, _ := plistparser.Convert([]byte(plistFile), &plistparser.Config{
    Target:       plistparser.Json,
    HighFidelity: false,
    Beatify:      true,
  })
  
  fmt.Println(string(out))
}

License

plist is released under the Apache 2.0 license. See LICENSE