예제 #1
0
def makeMpkgPlist(path):

    vers = getFullVersion()
    major, minor = map(int, getVersion().split('.', 2))

    pl = Plist(
        CFBundleGetInfoString="Python %s" % (vers, ),
        CFBundleIdentifier='org.python.Python',
        CFBundleName='Python',
        CFBundleShortVersionString=vers,
        IFMajorVersion=major,
        IFMinorVersion=minor,
        IFPkgFlagComponentDirectory="Contents/Packages",
        IFPkgFlagPackageList=[
            dict(IFPkgFlagPackageLocation='%s-%s.pkg' %
                 (item['name'], getVersion()),
                 IFPkgFlagPackageSelection='selected')
            for item in pkg_recipes()
        ],
        IFPkgFormatVersion=0.10000000149011612,
        IFPkgFlagBackgroundScaling="proportional",
        IFPkgFlagBackgroundAlignment="left",
        IFPkgFlagAuthorizationAction="RootAuthorization",
    )

    writePlist(pl, path)
예제 #2
0
 def _writePlistInfo(self):
     """
     Writes the Info.plist file in the Contests directory.
     """
     pl = Plist(
         CFBundleExecutable=self.executable,
         CFBundleGetInfoString='%s-1.0.0' % self.name,
         CFBundleIconFile=basename(self.icns),
         CFBundleIdentifier='com.%s' % self.name,
         CFBundlePackageType='APPL',
         CFBundleVersion='1.0.0',
         CFBundleShortVersionString='1.0.0',
     )
     writePlist(pl, join(self.contents_dir, 'Info.plist'))
예제 #3
0
def buildInstaller():

    # Zap all compiled files
    for dirpath, _, filenames in os.walk(os.path.join(WORKDIR, '_root')):
        for fn in filenames:
            if fn.endswith('.pyc') or fn.endswith('.pyo'):
                os.unlink(os.path.join(dirpath, fn))

    outdir = os.path.join(WORKDIR, 'installer')
    if os.path.exists(outdir):
        shutil.rmtree(outdir)
    os.mkdir(outdir)

    pkgroot = os.path.join(outdir, 'Python.mpkg', 'Contents')
    pkgcontents = os.path.join(pkgroot, 'Packages')
    os.makedirs(pkgcontents)
    for recipe in pkg_recipes():
        packageFromRecipe(pkgcontents, recipe)

    rsrcDir = os.path.join(pkgroot, 'Resources')

    fn = os.path.join(pkgroot, 'PkgInfo')
    fp = open(fn, 'w')
    fp.write('pmkrpkg1')
    fp.close()

    os.mkdir(rsrcDir)

    makeMpkgPlist(os.path.join(pkgroot, 'Info.plist'))
    pl = Plist(
        IFPkgDescriptionTitle="Python",
        IFPkgDescriptionVersion=getVersion(),
    )

    writePlist(pl, os.path.join(pkgroot, 'Resources', 'Description.plist'))
    for fn in os.listdir('resources'):
        if fn == '.svn': continue
        if fn.endswith('.jpg'):
            shutil.copy(os.path.join('resources', fn),
                        os.path.join(rsrcDir, fn))
        else:
            patchFile(os.path.join('resources', fn), os.path.join(rsrcDir, fn))

    shutil.copy("../../LICENSE", os.path.join(rsrcDir, 'License.txt'))
예제 #4
0
class BundleBuilder(Defaults):
    """BundleBuilder is a barebones class for assembling bundles. It
    knows nothing about executables or icons, it only copies files
    and creates the PkgInfo and Info.plist files.
    """

    # (Note that Defaults.__init__ (deep)copies these values to
    # instance variables. Mutable defaults are therefore safe.)

    # Name of the bundle, with or without extension.
    name = None

    # The property list ("plist")
    plist = Plist(CFBundleDevelopmentRegion="English",
                  CFBundleInfoDictionaryVersion="6.0")

    # The type of the bundle.
    type = "BNDL"
    # The creator code of the bundle.
    creator = None

    # the CFBundleIdentifier (this is used for the preferences file name)
    bundle_id = None

    # List of files that have to be copied to <bundle>/Contents/Resources.
    resources = []

    # List of (src, dest) tuples; dest should be a path relative to the bundle
    # (eg. "Contents/Resources/MyStuff/SomeFile.ext).
    files = []

    # List of shared libraries (dylibs, Frameworks) to bundle with the app
    # will be placed in Contents/Frameworks
    libs = []

    # Directory where the bundle will be assembled.
    builddir = "build"

    # Make symlinks instead copying files. This is handy during debugging, but
    # makes the bundle non-distributable.
    symlink = 0

    # Verbosity level.
    verbosity = 1

    # Destination root directory
    destroot = ""

    def setup(self):
        # XXX rethink self.name munging, this is brittle.
        self.name, ext = os.path.splitext(self.name)
        if not ext:
            ext = ".bundle"
        bundleextension = ext
        # misc (derived) attributes
        self.bundlepath = pathjoin(self.builddir, self.name + bundleextension)

        plist = self.plist
        plist.CFBundleName = self.name
        plist.CFBundlePackageType = self.type
        if self.creator is None:
            if hasattr(plist, "CFBundleSignature"):
                self.creator = plist.CFBundleSignature
            else:
                self.creator = "????"
        plist.CFBundleSignature = self.creator
        if self.bundle_id:
            plist.CFBundleIdentifier = self.bundle_id
        elif not hasattr(plist, "CFBundleIdentifier"):
            plist.CFBundleIdentifier = self.name

    def build(self):
        """Build the bundle."""
        builddir = self.builddir
        if builddir and not os.path.exists(builddir):
            os.mkdir(builddir)
        self.message("Building %s" % repr(self.bundlepath), 1)
        if os.path.exists(self.bundlepath):
            shutil.rmtree(self.bundlepath)
        if os.path.exists(self.bundlepath + '~'):
            shutil.rmtree(self.bundlepath + '~')
        bp = self.bundlepath

        # Create the app bundle in a temporary location and then
        # rename the completed bundle. This way the Finder will
        # never see an incomplete bundle (where it might pick up
        # and cache the wrong meta data)
        self.bundlepath = bp + '~'
        try:
            os.mkdir(self.bundlepath)
            self.preProcess()
            self._copyFiles()
            self._addMetaFiles()
            self.postProcess()
            os.rename(self.bundlepath, bp)
        finally:
            self.bundlepath = bp
        self.message("Done.", 1)

    def preProcess(self):
        """Hook for subclasses."""
        pass

    def postProcess(self):
        """Hook for subclasses."""
        pass

    def _addMetaFiles(self):
        contents = pathjoin(self.bundlepath, "Contents")
        makedirs(contents)
        #
        # Write Contents/PkgInfo
        assert len(self.type) == len(self.creator) == 4, \
                "type and creator must be 4-byte strings."
        pkginfo = pathjoin(contents, "PkgInfo")
        f = open(pkginfo, "wb")
        f.write(self.type + self.creator)
        f.close()
        #
        # Write Contents/Info.plist
        infoplist = pathjoin(contents, "Info.plist")
        self.plist.write(infoplist)

    def _copyFiles(self):
        files = self.files[:]
        for path in self.resources:
            files.append(
                (path, pathjoin("Contents", "Resources",
                                os.path.basename(path))))
        for path in self.libs:
            files.append((path,
                          pathjoin("Contents", "Frameworks",
                                   os.path.basename(path))))
        if self.symlink:
            self.message("Making symbolic links", 1)
            msg = "Making symlink from"
        else:
            self.message("Copying files", 1)
            msg = "Copying"
        files.sort()
        for src, dst in files:
            if os.path.isdir(src):
                self.message("%s %s/ to %s/" % (msg, src, dst), 2)
            else:
                self.message("%s %s to %s" % (msg, src, dst), 2)
            dst = pathjoin(self.bundlepath, dst)
            if self.symlink:
                symlink(src, dst, mkdirs=1)
            else:
                copy(src, dst, mkdirs=1)

    def message(self, msg, level=0):
        if level <= self.verbosity:
            indent = ""
            if level > 1:
                indent = (level - 1) * "  "
            sys.stderr.write(indent + msg + "\n")

    def report(self):
        # XXX something decent
        pass
예제 #5
0
from distutils.core import setup
import py2app
from plistlib import Plist
import os

name = 'ASDictionary'
version = '0.11.0'

os.system('''
sdp -fa %s.sdef;
Rez %sScripting.r -o %s.rsrc -useDF
''' % ((name, ) * 3))

setup(app=[name + ".py"],
      data_files=["MainMenu.nib"],
      options=dict(py2app=dict(plist=Plist(
          NSAppleScriptEnabled=True,
          CFBundleVersion=version,
          CFBundleShortVersionString=version,
          NSHumanReadableCopyright="(C) 2005-2008 HAS",
          CFBundleIdentifier="net.sourceforge.appscript.asdictionary",
          CFBundleDocumentTypes=[
              dict(
                  CFBundleTypeExtensions=["*"],
                  CFBundleTypeName="public.item",
                  CFBundleTypeRole="Viewer",
              ),
          ]),
                               resources=[name + '.icns', name + '.rsrc'],
                               iconfile=name + '.icns')))
예제 #6
0
--

To build, cd to this directory and run:

	python setup.py py2app

"""

from distutils.core import setup, Extension
import py2app
from plistlib import Plist

version = '0.4.0'

setup(app=["ASTranslate.py"],
      data_files=["MainMenu.nib", "ASTranslateDocument.nib"],
      options=dict(py2app=dict(plist=Plist(
          NSAppleScriptEnabled=True,
          CFBundleIdentifier="net.sourceforge.appscript.astranslate",
          CFBundleVersion=version,
          CFBundleShortVersionString=version,
          NSHumanReadableCopyright="(C) 2007-2008 HAS",
          CFBundleDocumentTypes=[
              dict(CFBundleTypeExtensions=[],
                   CFBundleTypeName="Text File",
                   CFBundleTypeRole="Editor",
                   NSDocumentClass="ASTranslateDocument")
          ]),
                               resources=['ASTranslate.icns'],
                               iconfile='ASTranslate.icns')))
예제 #7
0
fullVersStr = __version__
shortVersStr = fullVersStr

inclModules = (
    #    "FileDialog",
)
# packages to include recursively
inclPackages = (
    #    "RO",
)

plist = Plist(
    CFBundleName=appName,
    CFBundleShortVersionString=shortVersStr,
    CFBundleGetInfoString="%s %s" % (appName, fullVersStr),
    CFBundleExecutable=appName,
    LSMinimumSystemVersion="10.6.0",
    LSArchitecturePriority=("i386", )  # force 32-bit mode;
    # this is needed for Tcl/TK 8.5.11 to run on MacOS X 10.9;
    # I'm stuck with 8.5.11 due to a crashing bug in Tcl/Tk 8.5.12 - 8.5.15.1
)

setup(
    app=[mainProg],
    setup_requires=["py2app"],
    options=dict(py2app=dict(
        plist=plist,
        # iconfile = iconFile,
        # includes = inclModules,
        # packages = inclPackages,
    )),
)
예제 #8
0
import os

from bundlebuilder import buildapp
from plistlib import Plist, Dict

plist = Plist(
        CFBundleDocumentTypes = [
            Dict(
                CFBundleTypeExtensions = [ "py", "pyw" ],
                CFBundleTypeName = "Python File",
                CFBundleTypeRole = "Editor",
                NSDocumentClass = "PyDEPythonDocument",
            ),
        ],
    )

buildapp(
        name = "PyDE",
        mainprogram = "main.py",
        resources = [
            os.path.join("Resources", x)
                for x in os.listdir("Resources")
                if x != 'CVS' ] + [ 'pythonfile.py', 'PyDETextView.py', 'PyFontify.py'],
        nibname = "MainMenu.nib",
        plist = plist,
    )
예제 #9
0
class BundleBuilder(Defaults):
    """BundleBuilder is a barebones class for assembling bundles. It
    knows nothing about executables or icons, it only copies files
    and creates the PkgInfo and Info.plist files.
    """
    name = None
    plist = Plist(CFBundleDevelopmentRegion='English', CFBundleInfoDictionaryVersion='6.0')
    type = 'BNDL'
    creator = None
    bundle_id = None
    resources = []
    files = []
    libs = []
    builddir = 'build'
    symlink = 0
    verbosity = 1
    destroot = ''

    def setup(self):
        self.name, ext = os.path.splitext(self.name)
        if not ext:
            ext = '.bundle'
        bundleextension = ext
        self.bundlepath = pathjoin(self.builddir, self.name + bundleextension)
        plist = self.plist
        plist.CFBundleName = self.name
        plist.CFBundlePackageType = self.type
        if self.creator is None:
            if hasattr(plist, 'CFBundleSignature'):
                self.creator = plist.CFBundleSignature
            else:
                self.creator = '????'
        plist.CFBundleSignature = self.creator
        if self.bundle_id:
            plist.CFBundleIdentifier = self.bundle_id
        elif not hasattr(plist, 'CFBundleIdentifier'):
            plist.CFBundleIdentifier = self.name
        return

    def build(self):
        """Build the bundle."""
        builddir = self.builddir
        if builddir and not os.path.exists(builddir):
            os.mkdir(builddir)
        self.message('Building %s' % repr(self.bundlepath), 1)
        if os.path.exists(self.bundlepath):
            shutil.rmtree(self.bundlepath)
        if os.path.exists(self.bundlepath + '~'):
            shutil.rmtree(self.bundlepath + '~')
        bp = self.bundlepath
        self.bundlepath = bp + '~'
        try:
            os.mkdir(self.bundlepath)
            self.preProcess()
            self._copyFiles()
            self._addMetaFiles()
            self.postProcess()
            os.rename(self.bundlepath, bp)
        finally:
            self.bundlepath = bp

        self.message('Done.', 1)

    def preProcess(self):
        """Hook for subclasses."""
        pass

    def postProcess(self):
        """Hook for subclasses."""
        pass

    def _addMetaFiles(self):
        contents = pathjoin(self.bundlepath, 'Contents')
        makedirs(contents)
        raise len(self.type) == len(self.creator) == 4 or AssertionError('type and creator must be 4-byte strings.')
        pkginfo = pathjoin(contents, 'PkgInfo')
        f = open(pkginfo, 'wb')
        f.write(self.type + self.creator)
        f.close()
        infoplist = pathjoin(contents, 'Info.plist')
        self.plist.write(infoplist)

    def _copyFiles(self):
        files = self.files[:]
        for path in self.resources:
            files.append((path, pathjoin('Contents', 'Resources', os.path.basename(path))))

        for path in self.libs:
            files.append((path, pathjoin('Contents', 'Frameworks', os.path.basename(path))))

        if self.symlink:
            self.message('Making symbolic links', 1)
            msg = 'Making symlink from'
        else:
            self.message('Copying files', 1)
            msg = 'Copying'
        files.sort()
        for src, dst in files:
            if os.path.isdir(src):
                self.message('%s %s/ to %s/' % (msg, src, dst), 2)
            else:
                self.message('%s %s to %s' % (msg, src, dst), 2)
            dst = pathjoin(self.bundlepath, dst)
            if self.symlink:
                symlink(src, dst, mkdirs=1)
            else:
                copy(src, dst, mkdirs=1)

    def message(self, msg, level = 0):
        if level <= self.verbosity:
            indent = ''
            if level > 1:
                indent = (level - 1) * '  '
            sys.stderr.write(indent + msg + '\n')

    def report(self):
        pass
예제 #10
0
from bundlebuilder import buildapp
from plistlib import Plist, Dict

plist = Plist(CFBundleDocumentTypes=[
    Dict(
        CFBundleTypeExtensions=["xml", "xml.gz", "*"],
        CFBundleTypeName="XML File",
        CFBundleTypeRole="Editor",
        NSDocumentClass="ImageDocument",
    ),
    Dict(
        CFBundleTypeExtensions=["dwg"],
        CFBundleTypeName="DWG File",
        CFBundleTypeRole="Viewer",
        NSDocumentClass="ImageDocument",
    ),
])

buildapp(
    mainprogram="PythonCad.py",
    resources=[
        "PythonCAD/Interface/Cocoa/MainMenu.nib",
        "PythonCAD/Interface/Cocoa/ImageDocument.nib", "PythonCAD", "prefs.py"
    ],
    nibname="MainMenu",
    plist=plist,
)
예제 #11
0
shortVersStr = fullVersStr.split(None, 1)[0]

inclModules = ("FileDialog", )
# packages to include recursively
inclPackages = (
    "TUI",
    "RO",
    "matplotlib",  # py2app already does this, but it doesn't hurt to insist
)

plist = Plist(
    CFBundleName=appName,
    CFBundleShortVersionString=shortVersStr,
    CFBundleGetInfoString="%s %s" % (appName, fullVersStr),
    CFBundleExecutable=appName,
    LSMinimumSystemVersion="10.6.0",
    #    LSArchitecturePriority      = ("i386",) # force 32-bit mode;
    # this is needed for Tcl/TK 8.5.11 to run on MacOS X 10.9;
    # I'm stuck with 8.5.11 due to a crashing bug in Tcl/Tk 8.5.12 - 8.5.15.1
    # 8.5.16 has a nasty regression in http that prevents downloading images
    # 8.5.17 is a possibility; I'm trying a release candidate as I write this
)

setup(
    app=[mainProg],
    setup_requires=["py2app"],
    options=dict(py2app=dict(
        plist=plist,
        iconfile=iconFile,
        includes=inclModules,
        packages=inclPackages,
    )),
예제 #12
0
def write(dct, path):
    p = Plist()
    p.update(dct)
    p.write(path)
예제 #13
0
from setuptools import setup
from plistlib import Plist

setup(
    name='BasicApp',
    app=['main.py'],
    options = dict(py2app=dict(
        plist = Plist(
            CFBundleName               = "SimpleApp",
            CFBundleShortVersionString = "1.0",
            CFBudleGetInfoString       = "SimpleApp 1.0",
        ),
        iconfile = "main.icns",
        resources = "data3/source.c",
    )),
    data_files = [
        ( 'sub1', [ 'data1/file1.txt', 'data1/file2.txt', 'data1/file3.sh' ]),
        'data2'
    ]
)
예제 #14
0
		Extension('astranslate',
			sources=['astranslate.c'],
			extra_compile_args=['-DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_4'],
			extra_link_args=['-framework', 'Carbon'],
		),
	],

	options=dict(
	
		py2app=dict(
			plist=Plist(
				CFBundleIdentifier="net.sourceforge.appscript.astranslate",
				CFBundleVersion=version,
				CFBundleShortVersionString=version,
				NSHumanReadableCopyright="",
				CFBundleDocumentTypes = [
					dict(
						CFBundleTypeExtensions=[],
						CFBundleTypeName="Text File",
						CFBundleTypeRole="Editor",
						NSDocumentClass="ASTranslateDocument"
					)
				]
			),
			resources=['ASTranslate.icns'],
			iconfile='ASTranslate.icns'
		)
	)
)

예제 #15
0
sdpPath = 'sdp' # Tiger
RezPath = '/Developer/Tools/Rez'

#######

os.system('''
%r -fa %s.sdef;
%r %sScripting.r -o %s.rsrc -useDF
''' % (sdpPath, name, RezPath, name, name))

setup(
	name= name,
	version=version,
	app=[name + '.py'],
	options={
		'py2app': {
			'plist': Plist(
				LSUIElement=int(hide), 
				NSAppleScriptEnabled=True,
				#CFBundleIdentifier=url,
				CFBundleVersion=version, 
				CFBundleShortVersionString=version,
				CFBundleIconFile=name + '.icns'
			),
			'resources': [name + '.rsrc', name + '.icns']
		}
	}
)


예제 #16
0
def packageFromRecipe(targetDir, recipe):
    curdir = os.getcwd()
    try:
        # The major version (such as 2.5) is included in the package name
        # because having two version of python installed at the same time is
        # common.
        pkgname = '%s-%s' % (recipe['name'], getVersion())
        srcdir = recipe.get('source')
        pkgroot = recipe.get('topdir', srcdir)
        postflight = recipe.get('postflight')
        readme = textwrap.dedent(recipe['readme'])
        isRequired = recipe.get('required', True)

        print "- building package %s" % (pkgname, )

        # Substitute some variables
        textvars = dict(
            VER=getVersion(),
            FULLVER=getFullVersion(),
        )
        readme = readme % textvars

        if pkgroot is not None:
            pkgroot = pkgroot % textvars
        else:
            pkgroot = '/'

        if srcdir is not None:
            srcdir = os.path.join(WORKDIR, '_root', srcdir[1:])
            srcdir = srcdir % textvars

        if postflight is not None:
            postflight = os.path.abspath(postflight)

        packageContents = os.path.join(targetDir, pkgname + '.pkg', 'Contents')
        os.makedirs(packageContents)

        if srcdir is not None:
            os.chdir(srcdir)
            runCommand(
                "pax -wf %s . 2>&1" %
                (shellQuote(os.path.join(packageContents, 'Archive.pax')), ))
            runCommand(
                "gzip -9 %s 2>&1" %
                (shellQuote(os.path.join(packageContents, 'Archive.pax')), ))
            runCommand(
                "mkbom . %s 2>&1" %
                (shellQuote(os.path.join(packageContents, 'Archive.bom')), ))

        fn = os.path.join(packageContents, 'PkgInfo')
        fp = open(fn, 'w')
        fp.write('pmkrpkg1')
        fp.close()

        rsrcDir = os.path.join(packageContents, "Resources")
        os.mkdir(rsrcDir)
        fp = open(os.path.join(rsrcDir, 'ReadMe.txt'), 'w')
        fp.write(readme)
        fp.close()

        if postflight is not None:
            patchScript(postflight, os.path.join(rsrcDir, 'postflight'))

        vers = getFullVersion()
        major, minor = map(int, getVersion().split('.', 2))
        pl = Plist(
            CFBundleGetInfoString="Python.%s %s" % (
                pkgname,
                vers,
            ),
            CFBundleIdentifier='org.python.Python.%s' % (pkgname, ),
            CFBundleName='Python.%s' % (pkgname, ),
            CFBundleShortVersionString=vers,
            IFMajorVersion=major,
            IFMinorVersion=minor,
            IFPkgFormatVersion=0.10000000149011612,
            IFPkgFlagAllowBackRev=False,
            IFPkgFlagAuthorizationAction="RootAuthorization",
            IFPkgFlagDefaultLocation=pkgroot,
            IFPkgFlagFollowLinks=True,
            IFPkgFlagInstallFat=True,
            IFPkgFlagIsRequired=isRequired,
            IFPkgFlagOverwritePermissions=False,
            IFPkgFlagRelocatable=False,
            IFPkgFlagRestartAction="NoRestart",
            IFPkgFlagRootVolumeOnly=True,
            IFPkgFlagUpdateInstalledLangauges=False,
        )
        writePlist(pl, os.path.join(packageContents, 'Info.plist'))

        pl = Plist(
            IFPkgDescriptionDescription=readme,
            IFPkgDescriptionTitle=recipe.get('long_name',
                                             "Python.%s" % (pkgname, )),
            IFPkgDescriptionVersion=vers,
        )
        writePlist(
            pl, os.path.join(packageContents, 'Resources',
                             'Description.plist'))

    finally:
        os.chdir(curdir)
예제 #17
0
s = "%s %sScripting.r -o %s.rsrc -useDF;" % (RezPath, name, name)
print s
os.system(s)

#######

setup(name=name,
      version=version,
      app=[name + '.py'],
      options={
          'py2app': {
              'plist':
              Plist(LSUIElement=int(hide),
                    NSAppleScriptEnabled=True,
                    CFBundleIdentifier=bundle,
                    CFBundleName=name,
                    CFBundleDisplayName=name,
                    CFBundleVersion=version,
                    CFBundleShortVersionString=version,
                    CFBundleSignature=creator,
                    CFBundlePackageType="APPL",
                    CFBundleIconFile=name + '.icns',
                    NSHumanReadableCopyright=shortCopyright,
                    CFBundleGetInfoString=longCopyright),
              'iconfile':
              './+icons/appicon.icns',
              'resources': [name + '.rsrc', './+icons/appicon.icns']
          }
      })
예제 #18
0
from distutils.core import setup
import py2app
from plistlib import Plist

setup(
    app=['ASDictionary.py'],
    options={
        'py2app': {
            'argv_emulation':
            True,
            'plist':
            Plist(CFBundleVersion='0.6.2', CFBundleShortVersionString='0.6.2'),
            'resources': ['ASDictionary.icns'],
            'iconfile':
            'ASDictionary.icns',
        }
    },
)

# kludge to copy dialogs.rsrc into application bundle as py2app doesn't do it

import EasyDialogs
from shutil import copy
from os.path import split, join

rsrc = join(split(EasyDialogs.__file__)[0], 'dialogs.rsrc')
rdst = join(split(__file__)[0], 'dist/ASDictionary.app/Contents/Resources/')
copy(rsrc, rdst)