Skip to content

Commit

Permalink
Merge pull request #1429 from cuthbertLab/hatch
Browse files Browse the repository at this point in the history
use hatch for building
  • Loading branch information
mscuthbert committed Sep 19, 2022
2 parents 300845d + 065e70d commit a4a640d
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 253 deletions.
302 changes: 58 additions & 244 deletions dist/dist.py
Expand Up @@ -45,30 +45,27 @@
12. zip up documentation/build/html and get ready to upload/delete it.
Rename to music21.v.7.1.0-docs.zip (skip for Alpha/Beta)
12b. If any new file extensions have been added, be sure to add them to MANIFEST.in
13. Run "hatch build" -- requires hatch to be installed "brew install hatch"
13. And finally this file. (from the command line; not as python -m...; cwd must
be music21[base]/dist/ )
There are major problems in SetupTools -- v8 (or even a 7.3.1) needs to
fix them -- creating a dir music21.egg-info in the main dir with a
requires.txt file created as root.
14. Run this file -- it builds the no-corpus version of music21.
DO NOT RUN THIS ON A PC -- the Mac .tar.gz might have an incorrect permission if you do.
14. COMMIT to GitHub at this point w/ commit comment of the new version,
15. COMMIT to GitHub at this point w/ commit comment of the new version,
then don't change anything until the next step is done.
(.gitignore will avoid uploading the large files created here...)
15. Tag the commit: git tag -a vX.Y.Z -m "music21 vX.Y.Z"
16. Tag the commit: git tag -a vX.Y.Z -m "music21 vX.Y.Z"
Don't forget the "v" in the release tag.
Sanity check that the correct commit was tagged: git log
16. Push tags: git push upstream --tags
17. Push tags: git push upstream --tags
17. Create a new release on GitHub and upload the TWO files created here and docs.
18. Create a new release on GitHub and upload the TWO files created here and docs.
Drag in this order: .tar.gz, documentation, no-corpus.tar.gz
Finish this before doing the next step, even though it looks like it could be done in parallel.
18. Upload the new file to PyPI with "twine upload music21-7.3.5a2.tar.gz" [*]
19. Upload the new file to PyPI with "twine upload music21-7.3.5a2.tar.gz" [*]
[*] Requires twine to be installed
Expand All @@ -82,251 +79,68 @@
username:your_username
password:your_password
19. Delete the two .tar.gz files in dist...
20. Delete the two .tar.gz files in dist...
20. For starting a new major release create a GitHub branch for the old one.
21. For starting a new major release create a GitHub branch for the old one.
21. Immediately increment the number in _version.py and run tests on it here
22. Immediately increment the number in _version.py and run tests on it here
to prepare for next release.
22. Announce on the blog, to the list, and twitter.
DO NOT RUN THIS ON A PC -- the Mac .tar.gz has an incorrect permission if you do.
23. Announce on the blog, to the list, and twitter.
'''
import hashlib
import os
import sys
import shutil
import tarfile

from music21 import base
from music21 import common

from music21 import environment
environLocal = environment.Environment('..dist.dist')

PY = sys.executable
environLocal.warn(f'using python executable at {PY}')

class Distributor:
def __init__(self):
# self.fpEgg = None
# self.fpWin = None
self.fpTar = None

self.buildNoCorpus = True
# self.fpEggNoCorpus = None
self.fpTarNoCorpus = None

self.version = base.VERSION_STR

self._initPaths()

def _initPaths(self):

# must be in the dist dir
directory = os.getcwd()
parentDir = os.path.dirname(directory)
parentContents = sorted(os.listdir(parentDir))
# make sure we are in the proper directory
if (not directory.endswith('dist')
or 'music21' not in parentContents):
raise Exception(f'not in the music21{os.sep}dist directory: {directory}')

self.fpDistDir = directory
self.fpPackageDir = parentDir # dir with setup.py
self.fpBuildDir = os.path.join(self.fpPackageDir, 'build')
# self.fpEggInfo = os.path.join(self.fpPackageDir, 'music21.egg-info')

sys.path.insert(0, parentDir) # to get setup in as a possibility.

for fp in [self.fpDistDir, self.fpPackageDir, self.fpBuildDir]:
environLocal.warn(fp)


def updatePaths(self):
'''
Process output of build scripts. Get most recently produced distributions.
'''
contents = sorted(os.listdir(self.fpDistDir))
for fn in contents:
fp = os.path.join(self.fpDistDir, fn)
# if self.version in fn and fn.endswith('.egg'):
# self.fpEgg = fp
# if self.version in fn and fn.endswith('.exe'):
# fpNew = fp.replace('.macosx-10.8-intel.exe', '.win32.exe')
# fpNew = fpNew.replace('.macosx-10.8-x86_64.exe', '.win32.exe')
# fpNew = fpNew.replace('.macosx-10.9-intel.exe', '.win32.exe')
# fpNew = fpNew.replace('.macosx-10.9-x86_64.exe', '.win32.exe')
# fpNew = fpNew.replace('.macosx-10.10-intel.exe', '.win32.exe')
# fpNew = fpNew.replace('.macosx-10.10-x86_64.exe', '.win32.exe')
# fpNew = fpNew.replace('.macosx-10.11-intel.exe', '.win32.exe')
# fpNew = fpNew.replace('.macosx-10.11-x86_64.exe', '.win32.exe')
# fpNew = fpNew.replace('.macosx-10.12-intel.exe', '.win32.exe')
# fpNew = fpNew.replace('.macosx-10.12-x86_64.exe', '.win32.exe')
# if fpNew != fp:
# os.rename(fp, fpNew)
# self.fpWin = fpNew

print(fn)
if self.version in fn and fn.endswith('.tar.gz'):
self.fpTar = fp
else:
environLocal.warn(fn + ' does not end with .tar.gz')

environLocal.warn('giving path for tar.gz')
for fn in [self.fpTar]:
if fn is None:
environLocal.warn('missing fn path')
else:
environLocal.warn(fn)

def removeCorpus(self, fp):
'''
Remove the corpus from a compressed file (.tar.gz) and
create a new music21-noCorpus version.
Return the completed file path of the newly created edition.
NOTE: this function works only with Posix systems.
'''
TAR = 'TAR'
# EGG = 'EGG'
if fp and fp.endswith('.tar.gz'):
mode = TAR
modeExt = '.tar.gz'
else:
raise Exception('incorrect source file path')

fpDir, fn = os.path.split(fp)

# this has .tar.gz extension; this is the final completed package
fnDst = fn.replace('music21', 'music21-noCorpus')
fpDst = os.path.join(fpDir, fnDst)
# remove file extensions
fnDstDir = fnDst.replace(modeExt, '')
fpDstDir = os.path.join(fpDir, fnDstDir)

# get the name of the dir after decompression
fpSrcDir = os.path.join(fpDir, fn.replace(modeExt, ''))

# remove old dirs if it exists
if os.path.exists(fpDst):
shutil.rmtree(fpDst)

if os.path.exists(fpDstDir):
shutil.rmtree(fpDstDir)

if mode == TAR:
tf = tarfile.open(fp, 'r:gz')
# the path here is the dir into which to expand,
# not the name of that dir
tf.extractall(path=fpDir)
os.system(f'mv {fpSrcDir} {fpDstDir}')
tf.close() # done after extraction

# elif mode == EGG:
# os.system(f'mkdir {fpDstDir}')
# # need to create dst dir to unzip into
# tf = zipfile.ZipFile(fp, 'r')
# tf.extractall(path=fpDstDir)


# remove files, updates manifest
for fn in common.getCorpusContentDirs():
fp = os.path.join(fpDstDir, 'music21', 'corpus', fn)
shutil.rmtree(fp)

fp = os.path.join(fpDstDir, 'music21', 'corpus', '_metadataCache')
from music21._version import __version__ as version
from music21.common.pathTools import getRootFilePath, getCorpusContentDirs

def removeCorpus():
'''
Remove the corpus from a compressed file (.tar.gz) and
create a new music21-noCorpus version.
Return the completed file path of the newly created edition.
NOTE: this function works only with Posix systems.
'''
fp = getRootFilePath() / 'dist' / ('music21-' + version + '.tar.gz')
fpDir, fn = os.path.split(str(fp))

# this has .tar.gz extension; this is the final completed package
fnDst = fn.replace('music21', 'music21-noCorpus')
fpDst = os.path.join(fpDir, fnDst)
# remove file extensions
fnDstDir = fnDst.replace('.tar.gz', '')
fpDstDir = os.path.join(fpDir, fnDstDir)

file = tarfile.open(fp)
file.extractall(fpDir)
file.close()

os.rename(fpDstDir.replace('-noCorpus', ''), fpDstDir)

# remove files, updates manifest
for fn in getCorpusContentDirs():
fp = os.path.join(fpDstDir, 'music21', 'corpus', fn)
shutil.rmtree(fp)

# adjust the sources Txt file
# if mode == TAR:
sourcesTxt = os.path.join(fpDstDir, 'music21.egg-info', 'SOURCES.txt')
# else:
# raise Exception('invalid mode')

# elif mode == EGG:
# sourcesTxt = os.path.join(fpDstDir, 'EGG-INFO', 'SOURCES.txt')

# files will look like 'music21/corpus/haydn' in SOURCES.txt
post = []
f = open(sourcesTxt, 'r')
corpusContentDirs = common.getCorpusContentDirs()
for line in f:
match = False
if 'corpus' in line:
for fn in corpusContentDirs:
# these are relative paths
fp = os.path.join('music21', 'corpus', fn)
if line.startswith(fp):
match = True
break
if not match:
post.append(line)
f.close()
f = open(sourcesTxt, 'w')
f.writelines(post)
f.close()

if mode == TAR:
# compress dst dir to dst file path name
# need the -C flag to set relative dir
# just name of dir
cmd = f'tar -C {fpDir} -czf {fpDst} {fnDstDir}/'
os.system(cmd)

# remove directory that was compressed
if os.path.exists(fpDstDir):
shutil.rmtree(fpDstDir)

return fpDst # full path with extension



def build(self):
'''
Build all distributions. Update and rename file paths if necessary;
remove extract build products.
'''
# call setup.py
# import setup # -- for some reason does not work unless called from command line
for buildType in ['sdist --formats=gztar', 'bdist_wheel']:
environLocal.warn(f'making {buildType}')

savePath = os.getcwd()
os.chdir(self.fpPackageDir)
os.system(f'{PY} setup.py {buildType}')
os.chdir(savePath)

self.updatePaths()

environLocal.warn(f'removing {self.fpBuildDir} (except on windows...there do it yourself)')
try:
shutil.rmtree(self.fpBuildDir)
except FileNotFoundError:
environLocal.warn(
'Directory was already cleaned up'
)

if self.buildNoCorpus is True:
# create no corpus versions
self.fpTarNoCorpus = self.removeCorpus(fp=self.fpTar)
# self.fpEggNoCorpus = self.removeCorpus(fp=self.fpEgg)


def md5ForFile(self, path, hexReturn=True):
if hexReturn:
return hashlib.md5(open(path, 'rb').read()).hexdigest()
else:
return hashlib.md5(open(path, 'rb').read()).digest()
fp = os.path.join(fpDstDir, 'music21', 'corpus', '_metadataCache')
shutil.rmtree(fp)

# compress dst dir to dst file path name
# need the -C flag to set relative dir
# just name of dir
cmd = f'tar -C {fpDir} -czf {fpDst} {fnDstDir}/'
os.system(cmd)

# # remove directory that was compressed
if os.path.exists(fpDstDir):
shutil.rmtree(fpDstDir)

return fpDst # full path with extension


# ------------------------------------------------------------------------------
if __name__ == '__main__':
d = Distributor()
d.buildNoCorpus = True
d.build()
d.updatePaths()
# d.getMD5Path()
# d.uploadPyPi()
removeCorpus()
27 changes: 19 additions & 8 deletions music21/_version.py
Expand Up @@ -41,14 +41,25 @@
Changing this number invalidates old pickles -- do it if the old pickles create a problem.
'''

__version_info__ = (8, 0, 0, 'rc1') # can be 3-tuple or 4+-tuple: (7, 0, 5, 'a2')
def get_version_tuple(vv):
v = vv.split('.')
last_v = v[-1]
v[-1] = ''
beta = ''
in_patch = True
for ch in last_v:
if in_patch and ch.isdigit():
v[-1] += ch
else:
in_patch = False
beta += ch
if beta:
v.append(beta)
return tuple(v)

v = '.'.join(str(x) for x in __version_info__[0:3])
if len(__version_info__) > 3 and __version_info__[3]: # type: ignore
v += __version_info__[3] # type: ignore
if len(__version_info__) > 4:
v += '.' + '.'.join(__version_info__[4:])

__version__ = v
__version__ = '8.0.0rc2'

del v
__version_info__ = get_version_tuple(__version__)

del get_version_tuple
2 changes: 1 addition & 1 deletion music21/base.py
Expand Up @@ -28,7 +28,7 @@
<class 'music21.base.Music21Object'>
>>> music21.VERSION_STR
'8.0.0rc1'
'8.0.0rc2'
Alternatively, after doing a complete import, these classes are available
under the module "base":
Expand Down

0 comments on commit a4a640d

Please sign in to comment.