'Updating SourceTree's browser.plist with non-existing repositories dynamically

I'd like to traverse some directories containing git repositories with my Bash script and add them to SourceTree's list if they don't exist already. I'd preferably do it with native macOS tools (e.g. plutil) and structure the SourceTree's list in the same way as my (sub)directories are.

If I look at the browser.plist while my SourceTree list is empty, it looks like this:

$ plutil -p /Users/xox/Library/ApplicationSupport/SourceTree/browser.plist

{
  "$archiver" => "NSKeyedArchiver"
  "$objects" => [
    0 => "$null"
    1 => {
      "$class" => <CFKeyedArchiverUID 0x600000936f60 [0x7ff861751d80]>{value = 2}
      "NS.objects" => [
      ]
    }
    2 => {
      "$classes" => [
        0 => "NSMutableArray"
        1 => "NSArray"
        2 => "NSObject"
      ]
      "$classname" => "NSMutableArray"
    }
  ]
  "$top" => {
    "root" => <CFKeyedArchiverUID 0x600000936ec0 [0x7ff861751d80]>{value = 1}
  }
  "$version" => 100000
}

If I add some directories and repositories to SourceTree, like in this example: enter image description here

browser.plist will look like this:

$ plutil -p /Users/xox/Library/ApplicationSupport/SourceTree/browser.plist

{
  "$archiver" => "NSKeyedArchiver"
  "$objects" => [
    0 => "$null"
    1 => {
      "$class" => <CFKeyedArchiverUID 0x60000167efa0 [0x7ff861751d80]>{value = 16}
      "NS.objects" => [
        0 => <CFKeyedArchiverUID 0x60000167ef60 [0x7ff861751d80]>{value = 2}
        1 => <CFKeyedArchiverUID 0x60000167ef80 [0x7ff861751d80]>{value = 20}
      ]
    }
    2 => {
      "$class" => <CFKeyedArchiverUID 0x60000167f060 [0x7ff861751d80]>{value = 15}
      "children" => <CFKeyedArchiverUID 0x60000167f080 [0x7ff861751d80]>{value = 5}
      "hashValue" => <CFKeyedArchiverUID 0x60000167f0c0 [0x7ff861751d80]>{value = 19}
      "isLeaf" => <CFKeyedArchiverUID 0x60000167f020 [0x7ff861751d80]>{value = 4}
      "name" => <CFKeyedArchiverUID 0x60000167f0e0 [0x7ff861751d80]>{value = 3}
      "parent" => <CFKeyedArchiverUID 0x60000167f040 [0x7ff861751d80]>{value = 0}
      "path" => <CFKeyedArchiverUID 0x60000167f040 [0x7ff861751d80]>{value = 0}
      "repositoryType" => <CFKeyedArchiverUID 0x60000167f0a0 [0x7ff861751d80]>{value = 17}
    }
    3 => "test_directory_1"
    4 => 0
    5 => {
      "$class" => <CFKeyedArchiverUID 0x60000167efa0 [0x7ff861751d80]>{value = 16}
      "NS.objects" => [
        0 => <CFKeyedArchiverUID 0x60000167f100 [0x7ff861751d80]>{value = 6}
      ]
    }
    6 => {
      "$class" => <CFKeyedArchiverUID 0x60000167f060 [0x7ff861751d80]>{value = 15}
      "children" => <CFKeyedArchiverUID 0x60000167f120 [0x7ff861751d80]>{value = 8}
      "hashValue" => <CFKeyedArchiverUID 0x60000167f140 [0x7ff861751d80]>{value = 18}
      "isLeaf" => <CFKeyedArchiverUID 0x60000167f020 [0x7ff861751d80]>{value = 4}
      "name" => <CFKeyedArchiverUID 0x60000167f160 [0x7ff861751d80]>{value = 7}
      "parent" => <CFKeyedArchiverUID 0x60000167ef60 [0x7ff861751d80]>{value = 2}
      "path" => <CFKeyedArchiverUID 0x60000167f040 [0x7ff861751d80]>{value = 0}
      "repositoryType" => <CFKeyedArchiverUID 0x60000167f0a0 [0x7ff861751d80]>{value = 17}
    }
    7 => "test_subdirectory_1"
    8 => {
      "$class" => <CFKeyedArchiverUID 0x60000167efa0 [0x7ff861751d80]>{value = 16}
      "NS.objects" => [
        0 => <CFKeyedArchiverUID 0x60000167f180 [0x7ff861751d80]>{value = 9}
      ]
    }
    9 => {
      "$class" => <CFKeyedArchiverUID 0x60000167f060 [0x7ff861751d80]>{value = 15}
      "children" => <CFKeyedArchiverUID 0x60000167f040 [0x7ff861751d80]>{value = 0}
      "hashValue" => <CFKeyedArchiverUID 0x60000167f200 [0x7ff861751d80]>{value = 14}
      "isLeaf" => <CFKeyedArchiverUID 0x60000167f1a0 [0x7ff861751d80]>{value = 11}
      "name" => <CFKeyedArchiverUID 0x60000167f220 [0x7ff861751d80]>{value = 10}
      "parent" => <CFKeyedArchiverUID 0x60000167f100 [0x7ff861751d80]>{value = 6}
      "path" => <CFKeyedArchiverUID 0x60000167f1c0 [0x7ff861751d80]>{value = 12}
      "repositoryType" => <CFKeyedArchiverUID 0x60000167f1e0 [0x7ff861751d80]>{value = 13}
    }
    10 => "test_repo_1"
    11 => 1
    12 => "/Users/xox/werk/test_repo_1"
    13 => 1
    14 => 16224097462203018508
    15 => {
      "$classes" => [
        0 => "STBrowserNode"
        1 => "STTreeNode"
        2 => "NSObject"
      ]
      "$classname" => "STBrowserNode"
    }
    16 => {
      "$classes" => [
        0 => "NSMutableArray"
        1 => "NSArray"
        2 => "NSObject"
      ]
      "$classname" => "NSMutableArray"
    }
    17 => 255
    18 => 84843717759646174
    19 => 11241636783512070445
    20 => {
      "$class" => <CFKeyedArchiverUID 0x60000167f060 [0x7ff861751d80]>{value = 15}
      "children" => <CFKeyedArchiverUID 0x60000167f360 [0x7ff861751d80]>{value = 22}
      "hashValue" => <CFKeyedArchiverUID 0x60000167f380 [0x7ff861751d80]>{value = 27}
      "isLeaf" => <CFKeyedArchiverUID 0x60000167f020 [0x7ff861751d80]>{value = 4}
      "name" => <CFKeyedArchiverUID 0x60000167f3a0 [0x7ff861751d80]>{value = 21}
      "parent" => <CFKeyedArchiverUID 0x60000167f040 [0x7ff861751d80]>{value = 0}
      "path" => <CFKeyedArchiverUID 0x60000167f040 [0x7ff861751d80]>{value = 0}
      "repositoryType" => <CFKeyedArchiverUID 0x60000167f0a0 [0x7ff861751d80]>{value = 17}
    }
    21 => "test_directory_2"
    22 => {
      "$class" => <CFKeyedArchiverUID 0x60000167efa0 [0x7ff861751d80]>{value = 16}
      "NS.objects" => [
        0 => <CFKeyedArchiverUID 0x60000167f3c0 [0x7ff861751d80]>{value = 23}
      ]
    }
    23 => {
      "$class" => <CFKeyedArchiverUID 0x60000167f060 [0x7ff861751d80]>{value = 15}
      "children" => <CFKeyedArchiverUID 0x60000167f040 [0x7ff861751d80]>{value = 0}
      "hashValue" => <CFKeyedArchiverUID 0x60000167f400 [0x7ff861751d80]>{value = 26}
      "isLeaf" => <CFKeyedArchiverUID 0x60000167f1a0 [0x7ff861751d80]>{value = 11}
      "name" => <CFKeyedArchiverUID 0x60000167f420 [0x7ff861751d80]>{value = 24}
      "parent" => <CFKeyedArchiverUID 0x60000167ef80 [0x7ff861751d80]>{value = 20}
      "path" => <CFKeyedArchiverUID 0x60000167f3e0 [0x7ff861751d80]>{value = 25}
      "repositoryType" => <CFKeyedArchiverUID 0x60000167f1e0 [0x7ff861751d80]>{value = 13}
    }
    24 => "test_repo_2"
    25 => "/Users/xox/werk/test_repo_2"
    26 => 13314943410316335170
    27 => 2273844435150619926
  ]
  "$top" => {
    "root" => <CFKeyedArchiverUID 0x60000167eec0 [0x7ff861751d80]>{value = 1}
  }
  "$version" => 100000
}

Is there some simple way to modify my plist in a desired way given that each directory/repository is not a simple entry but an object with a bit more complex structure?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source