Skip to content

Commit

Permalink
Added backup/restore to CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
RhetTbull committed Mar 1, 2020
1 parent 6149d21 commit cd9b52e
Show file tree
Hide file tree
Showing 10 changed files with 404 additions and 85 deletions.
41 changes: 29 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ Options:
--update ATTRIBUTE VALUE Update ATTRIBUTE with VALUE; for multi-valued
attributes, this adds VALUE to the attribute if
not already in the list
--backup Backup FILE attributes. Backup file
'.osxmetadata.json' will be created in same folder
as FILE
--restore Restore FILE attributes from backup file. Restore
will look for backup file '.osxmetadata.json' in
same folder as FILE
-V, --verbose Print verbose output
--help Show this message and exit.
Valid attributes for ATTRIBUTE: Each attribute has a short name, a constant
Expand All @@ -67,44 +74,44 @@ set keywords to ['foo', 'bar']
Short Name Description
authors kMDItemAuthors, com.apple.metadata:kMDItemAuthors; The
author, or authors, of the contents of the file. A list of
author, or authors, of the contents of the file. A list of
strings.
comment kMDItemComment, com.apple.metadata:kMDItemComment; A comment
related to the file. This differs from the Finder comment,
kMDItemFinderComment. A string.
related to the file. This differs from the Finder comment,
kMDItemFinderComment. A string.
copyright kMDItemCopyright, com.apple.metadata:kMDItemCopyright; The
copyright owner of the file contents. A string.
copyright owner of the file contents. A string.
creator kMDItemCreator, com.apple.metadata:kMDItemCreator;
Application used to create the document content (for example
“Word”, “Pages”, and so on). A string.
“Word”, “Pages”, and so on). A string.
description kMDItemDescription, com.apple.metadata:kMDItemDescription; A
description of the content of the resource. The description
description of the content of the resource. The description
may include an abstract, table of contents, reference to a
graphical representation of content or a free-text account
of the content. A string.
of the content. A string.
downloadeddate kMDItemDownloadedDate,
com.apple.metadata:kMDItemDownloadedDate; The date the item
was downloaded. A date in ISO 8601 format: e.g.
2000-01-12T12:00:00 or 2000-12-31 (ISO 8601 w/o time zone)
findercomment kMDItemFinderComment,
com.apple.metadata:kMDItemFinderComment; Finder comments for
this file. A string.
this file. A string.
headline kMDItemHeadline, com.apple.metadata:kMDItemHeadline; A
publishable entry providing a synopsis of the contents of
the file. A string.
the file. A string.
keywords kMDItemKeywords, com.apple.metadata:kMDItemKeywords;
Keywords associated with this file. For example, “Birthday”,
“Important”, etc. This differs from Finder tags
(_kMDItemUserTags) which are keywords/tags shown in the
Finder and searchable in Spotlight using "tag:tag_name"A
Finder and searchable in Spotlight using "tag:tag_name". A
list of strings.
tags _kMDItemUserTags, com.apple.metadata:_kMDItemUserTags;
Finder tags; searchable in Spotlight using "tag:tag_name".
If you want tags/keywords visible in the Finder, use this
instead of kMDItemKeywords. A list of strings.
instead of kMDItemKeywords. A list of strings.
wherefroms kMDItemWhereFroms, com.apple.metadata:kMDItemWhereFroms;
Describes where the file was obtained from (e.g. URL
downloaded from). A list of strings.
downloaded from). A list of strings.
```


Expand Down Expand Up @@ -259,6 +266,11 @@ meta.clear_attribute("tags")

## Programmatic Interface:

### name
`name()`

Returns POSIX path of the file OSXMetaData is operating on.

### get_attribute
`get_attribute(attribute_name)`

Expand Down Expand Up @@ -326,6 +338,11 @@ Clear anttribute (remove it from the file).

List the Apple metadata attributes set on the file. e.g. those in com.apple.metadata namespace.

### to_json
`to_json()`

Return dict in JSON format with all attributes for this file. Format is the same as used by the command line --backup/--restore functions.

## Usage Notes

Changes are immediately written to the file. For example, OSXMetaData.tags.append("Foo") immediately writes the tag 'Foo' to the file.
Expand Down
50 changes: 50 additions & 0 deletions osxmetadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# the same MIT license. See: https://github.com/scooby/osx-tags

import datetime
import json
import logging
import pathlib
import plistlib
Expand Down Expand Up @@ -119,6 +120,55 @@ def name(self):
""" POSIX path of the file OSXMetaData is operating on """
return self._fname.resolve().as_posix()

def _to_dict(self):
""" Return dict with all attributes for this file
key of dict is filename and value is another dict with attributes """

attribute_list = self.list_metadata()
json_data = {}
json_data["_version"] = __version__
json_data["_filepath"] = self._posix_name
json_data["_filename"] = self._fname.name
for attr in attribute_list:
try:
attribute = ATTRIBUTES[attr]
if attribute.type_ == datetime.datetime:
# need to convert datetime.datetime to string to serialize
value = self.get_attribute(attribute.name)
if type(value) == list:
value = [v.isoformat() for v in value]
else:
value = value.isoformat()
json_data[attribute.constant] = value
else:
# get raw value
json_data[attribute.constant] = self.get_attribute(attribute.name)
except KeyError:
# unknown attribute, ignore it
pass
return json_data

def to_json(self):
""" Returns a string in JSON format for all attributes in this file """
json_data = self._to_dict()
json_str = json.dumps(json_data)
return json_str

def _restore_attributes(self, attr_dict):
""" restore attributes from attr_dict
for each attribute in attr_dict, will set the attribute
will not clear/erase any attributes on file that are not in attr_dict
attr_dict: an attribute dict as produced by OSXMetaData._to_dict() """

for key, val in attr_dict.items():
if key.startswith("_"):
# skip private keys like _version and _filepath
continue
try:
self.set_attribute(key, val)
except:
logging.warning(f"Unable to restore attribute {attr} for {self._fname}")

def get_attribute(self, attribute_name):
""" load attribute and return value or None if attribute was not set
attribute_name: name of attribute
Expand Down

0 comments on commit cd9b52e

Please sign in to comment.