├── .gitignore
├── README.md
├── getMostFrequentUser
├── getMostFrequentUser.sh
└── README.txt
├── tccmanager
├── tcc_services.plist
└── tccmanager.py
├── icnsToWp
├── README.md
└── icnsToWp.py
├── make_adobe_encorecs6_content_pkg
└── make_adobe_encorecs6_content_pkg.sh
├── GenerateSibeliusContentPkg
├── README.md
└── GenerateSibeliusContentPkg.py
└── repo_sync_and_mail
└── repo_sync_and_mail.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Collection of scripts for Mac sysadmin work.
2 |
--------------------------------------------------------------------------------
/getMostFrequentUser/getMostFrequentUser.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | ac -p | sort -nrk 2 | awk 'NR == 2 { print $1; exit }'
4 |
--------------------------------------------------------------------------------
/getMostFrequentUser/README.txt:
--------------------------------------------------------------------------------
1 | This one-liner retrieves the username of the user with longest time logged in, using the
2 | UNIX ac command.
--------------------------------------------------------------------------------
/tccmanager/tcc_services.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | kTCCServiceAddressBook
6 |
7 | com.adiumX.adiumX
8 |
9 | client_type
10 | 0
11 | allowed
12 | 1
13 | prompt_count
14 | 0
15 |
16 | com.macromates.TextMate.preview
17 |
18 | client_type
19 | 0
20 | allowed
21 | 0
22 | prompt_count
23 | 0
24 |
25 | com.apple.FinalCutPro
26 |
27 | client_type
28 | 0
29 | allowed
30 | 1
31 | prompt_count
32 | 0
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/icnsToWp/README.md:
--------------------------------------------------------------------------------
1 | # icnsToWp
2 |
3 | ## overview
4 |
5 | A very simple utility that takes one or more icns files as input and optimizes, compress and uploads select sizes to a Wordpress instance using its XMLRPC API. This API is enabled by default in Wordpress 3.5.
6 |
7 | There is no proper error handling in this script.
8 |
9 | Edit the config options at the top of the script to set options for the Wordpress URL and optimization tools if you plan to use these options.
10 |
11 | ## example usage
12 |
13 | icnsToWp.py --size 128 --wordpress-upload --include-retina /Applications/TextEdit.app/Contents/Resources/Edit.icns
14 |
15 | For detailed usage and options:
16 |
17 | icnsToWp.py -h
18 |
19 | ## optimizing
20 |
21 | For the `--optimize` option, this script was only tested with optimizer tool `optipng` and compress tool `convert` (ImageMagick/GraphicsMagick) in mind, but others should work fine if the compress tool takes the following argument structure:
22 |
23 | `tool [options here] infile outfile`
24 |
25 | `optipng` and `convert` are installed easily with [Homebrew](http://mxcl.github.com/homebrew).
26 |
--------------------------------------------------------------------------------
/make_adobe_encorecs6_content_pkg/make_adobe_encorecs6_content_pkg.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Packaging script for Adobe Encore CS6 "Functional Content".
4 | #
5 | # Thanks, Adobe, for making three different versions of the "functional content"
6 | # available all in different locations. The ESD download, which is actually in a "standard"
7 | # AAMEE-packageable format, contains only a fraction of the content, and we must resort
8 | # to looking for .zip or .7z archives on forums and blog posts.
9 | #
10 | # Define your own ID_PREFIX, NAME and VERSION. Package identifier will be $ID_PREFIX.$NAME.
11 | #
12 | # Requires fpm:
13 | #
14 | # gem install fpm
15 |
16 | NAME=AdobeEncoreCS6_Content
17 | ID_PREFIX=org.great.my
18 | VERSION=6.0.2013.03.01
19 | URL=https://blogs.adobe.com/premiereprotrainingfiles/EncoreContent_en-US.zip
20 | ARK=EncoreContent_en-US.zip
21 | MD5=f42ef6070cd29c8fcb0478fe7c71bf22
22 |
23 | # download
24 | if [ ! -e "$ARK" ]; then
25 | curl -k -L -o "$ARK" "$URL"
26 | fi
27 | VERIFY=$(md5 -q $ARK)
28 | if [ "$VERIFY" != "$MD5" ]; then
29 | echo "md5 don't match. try wiping it and letting it re-download."
30 | exit
31 | else
32 | echo "md5 matches."
33 | fi
34 |
35 | fpm --verbose \
36 | -s tar \
37 | -t osxpkg \
38 | --osxpkg-identifier-prefix $ID_PREFIX \
39 | -n $NAME \
40 | -v $VERSION \
41 | -C en-US \
42 | --prefix /Applications/Adobe\ Encore\ CS6 \
43 | "$ARK"
44 |
--------------------------------------------------------------------------------
/GenerateSibeliusContentPkg/README.md:
--------------------------------------------------------------------------------
1 | GenerateSibeliusContentPkg
2 | ==========================
3 |
4 | Overview
5 | --------
6 |
7 | Sibelius 7 has a lot of content to optionally install. This script's purpose is to automate the process of repacking this content (or a subset thereof) into an OS X installer package using The Luggage. It takes advantage of Python's multiprocessing module to greatly speed up the bzip2 decompression of the audio sample files to stage them for packaging.
8 |
9 | Sibelius ships with 3 content discs, but there is also additional content on the main application disc, as well as content update DMGs available for download. These are all valid input to the script, so it's possible to combine them in multiple packages if desired.
10 |
11 |
12 | Requirements
13 | ------------
14 |
15 | * The Luggage
16 | * Python 2.6 or greater
17 | * A _lot_ of disk space (100GB or greater for all content discs, due to space required to stage the package, archive, and wrap in a disk image)
18 |
19 |
20 | Caveats
21 | -------
22 |
23 | There's very little error handling. It also assumes the shell the script is run from will be able to run the 'make' command to process Luggage Makefiles.
24 |
25 |
26 | Usage
27 | -----
28 |
29 | 1. Create DMGs of the content discs you want to repackage.
30 | 2. Run the script using the -f argument to specify each of these DMGs whose content you want to add to the package. You can use the -f argument multiple times to combine multiple packages.
31 | 3. The script will ask a couple questions, the package title, version string, etc.
32 | 4. For each disk image, the content will be decompressed to a staging area, a Luggage Makefile will be generated and 'make dmg' will be run against it. There is an optional argument '-p' that will just run 'make pkg' instead.
33 | 5. Due to the amount of space required to stage, package and compress the data, you may want to manually run a 'make clean' from this script's working folder to clean up the Luggage temporary files.
--------------------------------------------------------------------------------
/repo_sync_and_mail/repo_sync_and_mail.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # Simple wrapper for repo_sync. Saves a datestamped log to LOGDIR, and e-mails the log if
4 | # the log contains the string '.pkg'. (ie. if a new product was replicated). The log will
5 | # also contain the contents of English.dist for any new products.
6 | #
7 | # Additional requirements:
8 | # - 'psutil' module, available from PyPi - version currently tested with this script is
9 | # 2.1.1, provided by the Debian Jessie 'python-psutil' apt package
10 |
11 | import os
12 | import sys
13 | import subprocess
14 | import plistlib
15 | from time import strftime, localtime
16 | import re
17 | import psutil # psutil is used to more easily detect whether repo_sync is already running
18 |
19 | import smtplib
20 | from email.MIMEMultipart import MIMEMultipart
21 | from email.MIMEBase import MIMEBase
22 | from email.MIMEText import MIMEText
23 | from email.Utils import formatdate
24 | from email import Encoders
25 |
26 | LOGDIR = '/var/log/reposado'
27 | REPO_SYNC = '/home/reposado/git/reposado/code/repo_sync'
28 | REPO_PREFS = '/home/reposado/git/reposado/code/preferences.plist'
29 | prefs = plistlib.readPlist(REPO_PREFS)
30 |
31 |
32 |
33 | mail_from = "reposado@my.org"
34 | mail_to = ["admin@my.org"]
35 | smtpserver = "smtp.my.org"
36 |
37 | def reposync_is_running():
38 | proclist = psutil.get_process_list()
39 | for p in proclist:
40 | for arg in p.cmdline():
41 | if os.path.basename(arg) == 'repo_sync':
42 | return True
43 | return False
44 |
45 | # E-mail code largely based on http://code.google.com/p/munki/wiki/PreflightAndPostflightScripts
46 | def send_mail(send_from, send_to, subject, text, files=[], server="localhost"):
47 | assert type(send_to) == list
48 | assert type(files) == list
49 |
50 | msg = MIMEMultipart()
51 | msg['From'] = send_from
52 | msg['To'] = ", ".join(send_to)
53 | msg['Date'] = formatdate(localtime=True)
54 | msg['Subject'] = subject
55 |
56 | msg.attach(MIMEText(text))
57 |
58 | for f in files:
59 | part = MIMEBase('application', "octet-stream")
60 | part.set_payload(open(f, "rb").read())
61 | Encoders.encode_base64(part)
62 | part.add_header('Content-Disposition',
63 | 'attachment; filename="%s"' % os.path.basename(f))
64 | msg.attach(part)
65 |
66 | smtp = smtplib.SMTP(server)
67 | smtp.sendmail(send_from, send_to, msg.as_string())
68 | smtp.close()
69 |
70 | if reposync_is_running():
71 | print "repo_sync is already running. Exiting.."
72 | sys.exit(1)
73 |
74 | if not os.path.exists(LOGDIR):
75 | os.mkdir(LOGDIR)
76 |
77 | logfile = os.path.join(LOGDIR, strftime('%Y-%m-%d_%H%M.log', localtime()))
78 |
79 | # do the repo_sync
80 | cmd = [REPO_SYNC, '--log=%s' % logfile]
81 | subprocess.call(cmd)
82 |
83 | try:
84 | lfb = open(logfile)
85 | logfile_contents = lfb.read()
86 | lfb.close()
87 | except:
88 | print "Can't read the logfile"
89 | sys.exit(1)
90 |
91 | if logfile_contents.find('pkg') != -1:
92 | meta = plistlib.readPlist(os.path.join(prefs['UpdatesMetadataDir'], 'ProductInfo.plist'))
93 | distpaths = re.findall("content/.*English.dist", logfile_contents)
94 | localdists = [os.path.join(prefs['UpdatesRootDir'], p) for p in distpaths]
95 | subject = "Reposado log"
96 | body = logfile_contents
97 | body += "\n\n"
98 | for dist in localdists:
99 | distcontent = open(dist, 'r')
100 | body += distcontent.read()
101 | distcontent.close()
102 | body += "\n\n\n"
103 | send_mail(mail_from, mail_to, subject, body, files=[], server=smtpserver)
104 |
--------------------------------------------------------------------------------
/icnsToWp/icnsToWp.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #
3 | # icnsToWp - Tim Sutton, December 2012
4 |
5 | import os
6 | import sys
7 | import xmlrpclib
8 | import optparse
9 | from subprocess import call
10 | from tempfile import mkdtemp
11 | import shutil
12 | from getpass import getpass
13 |
14 | WORDPRESS_URL = 'http://macops.ca/xmlrpc.php'
15 | OPTI_TOOL = '/usr/local/bin/optipng' # optipng's defaults are good enough, no options
16 | COMPRESS_TOOL = '/usr/local/bin/convert' # using imagemagick
17 | # imagemagick options.. IM docs are poor, use at your own risk
18 | COMPRESS_ARGS = ['-quality', '95', '-depth', '7', '-dither', 'Riemersma']
19 | ICONUTIL = '/usr/bin/iconutil'
20 |
21 | def upload(path, proxy, user, password):
22 | with open(path, 'rb') as fd:
23 | imgdata = fd.read()
24 | # wp.uploadFile endpoint: blogid, username, password, data struct {name, type, bits, overwrite}
25 | # from API docs:
26 | # blogid: Not applicable for WordPress, can be any value and will be ignored.
27 | results = proxy.wp.uploadFile(1, user, password,
28 | {'name': os.path.basename(path),
29 | 'type': 'image/%s' % (os.path.splitext(path)[1]),
30 | 'bits': xmlrpclib.Binary(imgdata)})
31 | return results
32 |
33 |
34 | def main():
35 | usage = """%prog [options] /path/to/file.icns
36 | Convert a .icns file to one or more png files, optimize and optionally upload to Wordpress"""
37 | o = optparse.OptionParser(usage=usage)
38 | o.add_option('-s', '--size', action='append',
39 | help="Icon size to use - can be specified multiple \
40 | times, should be multiple of 2.")
41 | o.add_option('-n', '--name',
42 | help="Name to prepend to file - defaults to name of input .icns file.")
43 | o.add_option('-w', '--wordpress-upload', action='store_true',
44 | help="Upload files to Wordpress. Set WORDPRESS_URL in this script to \
45 | http://my-wordpress-site-root/xmlrpc.php and ensure XMLRPC access is enabled.")
46 | o.add_option('-o', '--optimize', action='store_true',
47 | help="Optimize file using tools: %s and %s. Modify OPTI_TOOL and \
48 | COMPRESS_TOOL at top of this script edit paths and options." % (OPTI_TOOL, COMPRESS_TOOL))
49 | o.add_option('-r', '--include-retina', action='store_true',
50 | help="Include retina (ie. 'file@2x.png') versions")
51 | opts, args = o.parse_args()
52 |
53 | if len(args) < 1:
54 | sys.stderr << "Required argument: one or more .icns files to convert!"
55 | sys.exit
56 |
57 | if opts.wordpress_upload:
58 | user = raw_input("Wordpress user: ")
59 | password = getpass("Wordpress password: ")
60 | proxy = xmlrpclib.ServerProxy(WORDPRESS_URL)
61 |
62 | versions = ['']
63 | if opts.include_retina:
64 | versions.append('@2x')
65 |
66 | for icnsfile in args:
67 | icons_out = mkdtemp() + ".iconset"
68 | call([ICONUTIL, '-c', 'iconset', icnsfile, '-o', icons_out])
69 | for size in opts.size:
70 | for version in versions:
71 | if opts.name:
72 | name = opts.name
73 | else:
74 | name = os.path.splitext(os.path.basename(icnsfile))[0]
75 |
76 | iconpath = os.path.join(icons_out, 'icon_%sx%s%s.png' % (size, size, version))
77 | renamed_iconpath = os.path.join(os.path.dirname(iconpath), os.path.basename(iconpath).replace('icon', name))
78 | os.rename(iconpath, renamed_iconpath)
79 | outfile = os.path.join(os.getcwd(), "%s_%s%s.png" % (name, size, version))
80 | if opts.optimize:
81 | # optimize (optipng is in-place)
82 | call([OPTI_TOOL, renamed_iconpath])
83 | compress_cmd = [COMPRESS_TOOL] + COMPRESS_ARGS
84 | # outfile = os.path.join(os.getcwd(), "%s_%s%s.png" % (name, size, version))
85 | compress_cmd += [renamed_iconpath, outfile]
86 | # compress
87 | call(compress_cmd)
88 | else:
89 | # outfile =
90 | shutil.copyfile(renamed_iconpath, outfile)
91 | if opts.wordpress_upload:
92 | results = upload(outfile, proxy, user, password)
93 | print "Upload results:"
94 | print results
95 | # clean up
96 | shutil.rmtree(icons_out)
97 |
98 | if __name__ == '__main__':
99 | main()
100 |
--------------------------------------------------------------------------------
/tccmanager/tccmanager.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #
3 | # Make arbitrary changes to the TCC sqlite3 database, which stores the
4 | # applications that are allowed to access a user's contacts.
5 | #
6 | # Accepted input is in the form of a plist - see the 'tcc_services.plist' example.
7 | # It will add entries that don't already exist and update existing ones. It does not remove
8 | # entries that are present in the DB but not in the input plist.
9 | #
10 | # Ideally we could pass app bundle names or .app paths directly at the command line so that changes can
11 | # be made more atomically or run as one-off commands in a LaunchAgent script, for example.
12 |
13 | import sqlite3
14 | import os
15 | import sys
16 | import plistlib
17 | import optparse
18 |
19 | TCC_DIR = os.path.expanduser('~/Library/Application Support/com.apple.TCC')
20 | DBPATH = os.path.join(TCC_DIR, 'TCC.db')
21 |
22 | def createDB(path):
23 | conn = sqlite3.connect(path)
24 | c = conn.cursor()
25 |
26 | c.execute('''CREATE TABLE admin
27 | (key TEXT PRIMARY KEY NOT NULL, value INTEGER NOT NULL)''')
28 | c.execute("INSERT INTO admin VALUES ('version', 4)")
29 | c.execute('''CREATE TABLE access
30 | (service TEXT NOT NULL,
31 | client TEXT NOT NULL,
32 | client_type INTEGER NOT NULL,
33 | allowed INTEGER NOT NULL,
34 | prompt_count INTEGER NOT NULL,
35 | CONSTRAINT key PRIMARY KEY (service, client, client_type))''')
36 | c.execute('''CREATE TABLE access_times
37 | (service TEXT NOT NULL,
38 | client TEXT NOT NULL,
39 | client_type INTEGER NOT NULL,
40 | last_used_time INTEGER NOT NULL,
41 | CONSTRAINT key PRIMARY KEY (service, client, client_type))''')
42 | c.execute('''CREATE TABLE access_overrides
43 | (service TEXT PRIMARY KEY NOT NULL)''')
44 | conn.commit()
45 | conn.close()
46 |
47 | def main():
48 | usage = "usage: %prog --plist db_entries.plist | (--allow | --disallow) app.bundle.id"
49 | o = optparse.OptionParser(usage=usage)
50 | o.add_option('-p', '--plist', action="store",
51 | help='Path to a plist to be synced to the TCC db.')
52 | o.add_option('-a', '--allow', metavar="bundle-id", action="append",
53 | help='Name of an application bundle ID to allow access to contacts. \
54 | Can be specified multiple times.')
55 | o.add_option('-d', '--disallow', metavar="bundle-id", action="append",
56 | help='Name of an application bundle ID to disallow access to contacts. \
57 | Can be specified multiple times.')
58 | opts, args = o.parse_args()
59 |
60 | if (opts.plist and opts.allow) or (opts.plist and opts.disallow):
61 | print "--plist option is mutually exclusive to using --allow or --disallow."
62 | sys.exit(1)
63 |
64 | db_exists = False
65 | if not os.path.exists(TCC_DIR):
66 | os.mkdir(TCC_DIR, int('700', 8))
67 | else:
68 | db_exists = True
69 |
70 | conn = sqlite3.connect(DBPATH)
71 | c = conn.cursor()
72 |
73 | # Setup the database if it doesn't already exist
74 | if not db_exists:
75 | createDB(DBPATH)
76 |
77 | if opts.plist:
78 | try:
79 | apps = plistlib.readPlist(opts.plist)
80 | except:
81 | print "Error reading plist!"
82 | print sys.exc_info()
83 | print sys.exit(2)
84 |
85 | # add or modify any kTCCServiceAddressBook items we might have defined in the plist
86 | if 'kTCCServiceAddressBook' in apps.keys():
87 | for app, attrs in apps['kTCCServiceAddressBook'].items():
88 | data = ('kTCCServiceAddressBook',
89 | app,
90 | attrs['client_type'],
91 | attrs['allowed'],
92 | attrs['prompt_count'])
93 | c.execute('''INSERT or REPLACE INTO access values
94 | (?, ?, ?, ?, ?)''', data)
95 | conn.commit()
96 |
97 | else:
98 | if opts.allow:
99 | for bundle_id in opts.allow:
100 | c.execute('''INSERT or REPLACE INTO access values
101 | ('kTCCServiceAddressBook', ?, 0, 1, 0)''', (bundle_id,))
102 | conn.commit()
103 |
104 | if opts.disallow:
105 | for bundle_id in opts.disallow:
106 | c.execute('''INSERT or REPLACE INTO access values
107 | ('kTCCServiceAddressBook', ?, 0, 0, 0)''', (bundle_id,))
108 | conn.commit()
109 |
110 | conn.close()
111 |
112 | if __name__ == '__main__':
113 | main()
114 |
--------------------------------------------------------------------------------
/GenerateSibeliusContentPkg/GenerateSibeliusContentPkg.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import os
4 | import subprocess
5 | import sys
6 | import time
7 | import tarfile
8 | import optparse
9 | import tempfile
10 |
11 | REVERSE_DOMAIN = 'org.awesome.my'
12 |
13 |
14 | def generateLuggageMakefile(pkgTitle, pkgVersion, sourcePath, destPath):
15 | """Generate a Luggage Makefile for the project with a single new
16 | 'pack-sibelius-library' rule"""
17 | makefilePath = os.path.join(destPath, 'Makefile')
18 | fb = open(makefilePath, 'w')
19 | fb.write("""
20 | include /usr/local/share/luggage/luggage.make
21 |
22 | TITLE=%s
23 | REVERSE_DOMAIN=%s
24 | PACKAGE_VERSION=%s
25 | PAYLOAD=pack-sibelius-library
26 | SOUNDS_DEST_PATH="${WORK_D}/Library/Application Support/Avid/Sibelius Sounds"
27 |
28 | pack-sibelius-library:
29 | sudo mkdir -p ${SOUNDS_DEST_PATH}
30 | sudo mv "%s" ${SOUNDS_DEST_PATH}/
31 | sudo chown -R root:admin ${SOUNDS_DEST_PATH}
32 | sudo chmod -R 755 ${SOUNDS_DEST_PATH}
33 | """ % (pkgTitle, REVERSE_DOMAIN, pkgVersion, sourcePath))
34 | fb.close()
35 |
36 |
37 | def getPackageInfo():
38 | """Prompt the user for the name and version of the new package"""
39 | pkgTitle = raw_input("Enter a name for this package: ")
40 | rightNow = time.localtime()
41 | versionDate = "%s.%02d.%02d" % (rightNow.tm_year, rightNow.tm_mon, rightNow.tm_mday)
42 | pkgVersion = raw_input("Enter a package version: [%s] " % versionDate)
43 | if not pkgVersion:
44 | pkgVersion = versionDate
45 | return (pkgTitle, pkgVersion)
46 |
47 |
48 | def mountDMGs(files):
49 | """Given a list of DMGs, mount them one by one, returning a list of tempfile mountpoints"""
50 | mountPoints = []
51 | if options.file:
52 | for item in options.file:
53 | if os.path.exists(item):
54 | tmpMount = tempfile.mkdtemp()
55 | # Mount
56 | print "Mounting %s..." % os.path.basename(item)
57 | retcode = subprocess.call(['hdiutil', 'attach', '-nobrowse', '-mountpoint', tmpMount, item])
58 | if retcode:
59 | print "There was an issue mounting the specified image"
60 | sys.exit(1)
61 | else:
62 | print "Mounted at %s." % tmpMount
63 | # Check if it's a valid content disc
64 | if not os.path.exists(os.path.join(tmpMount, 'InstallerData')):
65 | print "Not a valid content disc!"
66 | sys.exit(1)
67 | else:
68 | mountPoints.append(tmpMount)
69 |
70 | else:
71 | print "ERROR: No file at path %s!" % item
72 | return mountPoints
73 |
74 |
75 | def unmountDMGs(mountPoints):
76 | """Given a list of DMGs, unmount them one by one"""
77 | for mountPoint in mountPoints:
78 | print "Unmounting %s..." % mountPoint
79 | subprocess.call(['hdiutil', 'detach', mountPoint])
80 |
81 |
82 | #
83 | # MAIN
84 | #
85 |
86 | usage = """usage: %prog -f [/path/to/dmg] [-f /path/to/another/dmg...]
87 | %prog --help for more information."""
88 |
89 | p = optparse.OptionParser(usage=usage)
90 | p.add_option('--file', '-f', action="append",
91 | help='''Path to a content dmg. Can be specified multiple times and they will be
92 | combined into a single package.''')
93 | p.add_option('--make-pkg', '-p', action="store_true",
94 | help="""Build a pkg with Luggage instead of the default DMG.""")
95 |
96 | if os.geteuid() != 0:
97 | print "ERROR: This script should be run as root, in order for Luggage to run successfully. Exiting..."
98 | sys.exit(1)
99 |
100 | options, arguments = p.parse_args()
101 |
102 | if options.file:
103 | mountPoints = mountDMGs(options.file)
104 | else:
105 | print "You need to specify at least one content DMG!"
106 | sys.exit(1)
107 |
108 | if mountPoints == []:
109 | print "No valid DMGs to mount. Exiting..."
110 | sys.exit(1)
111 |
112 | else:
113 | # Get package info from user interactively
114 | (pkgTitle, pkgVersion) = getPackageInfo()
115 | #(pkgTitle, pkgVersion) = ('SibeliusContentTest', '2012.01.15')
116 |
117 | # Set up build dirs
118 | # buildDirName = 'build' + '.' + pkgTitle
119 | buildDirPath = os.path.join(os.getcwd(), "build.%s" % pkgTitle)
120 | libraryExtractPath = os.path.join(buildDirPath, 'Sibelius 7 Sounds')
121 | if not os.path.exists(buildDirPath):
122 | os.mkdir(buildDirPath)
123 | os.mkdir(libraryExtractPath)
124 |
125 | def unbz2File(path):
126 | tar = tarfile.open(name=path, mode='r:bz2')
127 | tar.extractall(path=libraryExtractPath)
128 | tar.close()
129 | print "%s done" % os.path.basename(path)
130 |
131 | from multiprocessing import Pool
132 | pool = Pool()
133 |
134 | archivesToProcess = []
135 | for mountPoint in mountPoints:
136 | installerDataPath = os.path.join(mountPoint, 'InstallerData')
137 | for archive in os.listdir(installerDataPath):
138 | if archive.endswith('.tbz'):
139 | archivesToProcess.append(os.path.join(installerDataPath, archive))
140 | print "Added archive %s" % (os.path.join(installerDataPath, archive))
141 | # print "Extracting %s..." % archive
142 | # subprocess.call(['tar', '-xjvf', os.path.join(installerDataPath, archive), '-C', libraryExtractPath])
143 | # unbz2File(os.path.join(installerDataPath, archive), installerDataPath)
144 |
145 | imap_it = pool.imap(unbz2File, archivesToProcess)
146 |
147 | print "Beginning extraction..."
148 | for item in imap_it:
149 | pass
150 |
151 | # print "Extracting %s" % os.path.basename(item)
152 |
153 | unmountDMGs(mountPoints)
154 |
155 | # Make the Luggage Makefile
156 | generateLuggageMakefile(pkgTitle, pkgVersion, libraryExtractPath, buildDirPath)
157 |
158 | # Set up Luggage run
159 | luggageCmd = ['make']
160 | if options.make_pkg:
161 | luggageTarget = 'pkg'
162 | else:
163 | luggageTarget = 'dmg'
164 | luggageCmd.append(luggageTarget)
165 |
166 | # Do Luggage
167 | print "Building a %s with Luggage..." % luggageTarget
168 | subprocess.call(luggageCmd, cwd=buildDirPath)
169 |
--------------------------------------------------------------------------------