Skip to content

Instantly share code, notes, and snippets.

@OlyDLG
Last active January 18, 2017 07:42
Show Gist options
  • Select an option

  • Save OlyDLG/8fa46739193b56305f6f86fd12b9d936 to your computer and use it in GitHub Desktop.

Select an option

Save OlyDLG/8fa46739193b56305f6f86fd12b9d936 to your computer and use it in GitHub Desktop.
Function to write the contents, suitably encoded, of a text file, e.g., a Python source file, into an extended attribute of a target file
# ArchiveSourceWithOutput.py
#
# Copyright 2017 by David Lawrence Goldsmith
# License: BSD
# Use at own risk; no warranty expressed or implied
#
# Two functions--encode_and_write and read_and_decode--to assist in,
# among other potential uses, matching source code with output files,
# (on platforms that support extended attributes via the xattr shell
# command, e.g., Mac and some posix flavors):
#
# encode_and_write(source_file, target_file, xattr_name='source')
# converts (the ascii content of) <source_file> (a valid path, as a
# str) into a valid shell command line argument value, (i.e., a double-
# quoted string free of other double-quotes, standard parentheses, and
# newline characters), and "attaches" the result to <target_file> as
# extended attribute <xattr_name> (default value 'source').
#
# Example use-case: storage of the exact code that produces some output
# file(s) as part of those output file(s), regardless of output format,
# i.e., text source can be "pinned" to image files, pdf's, even directories
# and sym. links, etc.
#
# read_and_decode(target_file, xattr_name='source')
# encode_and_write's "inverse": reads in <target_file>'s extended attribute
# <xattr_name> value, and converts it back into the original text file,
# writing it out to a file with the same full path as the original, but with a '_'
# preceding any '.' (TODO: add support for alternate output name in read_and_decode)
#
# Example usage:
#
# from ArchiveSourceWithOutput import *
# :
# msg = encode_and_write(__file__, targetfilepath)
# if msg: print(msg) # msg is empty string unless something goes wrong
# else:
# msg = read_and_decode(targetfilepath) # Ditto
# print(msg)
from os import system, linesep
from subprocess import getoutput
def encode_and_write(source_file, target_file, xattr_name='source'):
fail = getoutput('xattr')
if fail:
pass
else:
src = open(source_file)
temp = src.readlines()
src.close()
cnts = source_file + ' _fn_ '
for line in temp:
cnts += line[:-1] + ' _nl_ '
cnts = cnts.replace('(', '_lparen_')
cnts = cnts.replace(')', '_rparen_')
cnts = cnts.replace('"', '_dblquote_')
fail = getoutput('chmod 660 ' + target_file)
if fail:
pass
else:
fail = getoutput('xattr -w ' + xattr_name + ' "' + cnts + '" ' + target_file)
return fail
def read_and_decode(target_file, xattr_name='source'):
fail = system('xattr -p ' + xattr_name + ' ' + target_file)
if fail:
return fail
else:
fail = getoutput('xattr -p ' + xattr_name + ' ' + target_file)
filename, fail = fail.split(' _fn_ ', 1)
filename = filename.replace('.', '_.')
fail = fail.replace('_dblquote_', '"')
fail = fail.replace('_rparen_', ')')
fail = fail.replace('_lparen_', '(')
fail = fail.replace(' _nl_ ', linesep)
fl = open(filename, 'w')
fl.write(fail)
fl.close()
return ''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment