|
45 | 45 | 12. zip up documentation/build/html and get ready to upload/delete it. |
46 | 46 | Rename to music21.v.7.1.0-docs.zip (skip for Alpha/Beta) |
47 | 47 |
|
48 | | -12b. If any new file extensions have been added, be sure to add them to MANIFEST.in |
| 48 | +13. Run "hatch build" -- requires hatch to be installed "brew install hatch" |
49 | 49 |
|
50 | | -13. And finally this file. (from the command line; not as python -m...; cwd must |
51 | | - be music21[base]/dist/ ) |
52 | | - There are major problems in SetupTools -- v8 (or even a 7.3.1) needs to |
53 | | - fix them -- creating a dir music21.egg-info in the main dir with a |
54 | | - requires.txt file created as root. |
| 50 | +14. Run this file -- it builds the no-corpus version of music21. |
| 51 | + DO NOT RUN THIS ON A PC -- the Mac .tar.gz might have an incorrect permission if you do. |
55 | 52 |
|
56 | | -14. COMMIT to GitHub at this point w/ commit comment of the new version, |
| 53 | +15. COMMIT to GitHub at this point w/ commit comment of the new version, |
57 | 54 | then don't change anything until the next step is done. |
58 | 55 | (.gitignore will avoid uploading the large files created here...) |
59 | 56 |
|
60 | | -15. Tag the commit: git tag -a vX.Y.Z -m "music21 vX.Y.Z" |
| 57 | +16. Tag the commit: git tag -a vX.Y.Z -m "music21 vX.Y.Z" |
61 | 58 | Don't forget the "v" in the release tag. |
62 | 59 | Sanity check that the correct commit was tagged: git log |
63 | 60 |
|
64 | | -16. Push tags: git push upstream --tags |
| 61 | +17. Push tags: git push upstream --tags |
65 | 62 |
|
66 | | -17. Create a new release on GitHub and upload the TWO files created here and docs. |
| 63 | +18. Create a new release on GitHub and upload the TWO files created here and docs. |
67 | 64 | Drag in this order: .tar.gz, documentation, no-corpus.tar.gz |
68 | 65 |
|
69 | 66 | Finish this before doing the next step, even though it looks like it could be done in parallel. |
70 | 67 |
|
71 | | -18. Upload the new file to PyPI with "twine upload music21-7.3.5a2.tar.gz" [*] |
| 68 | +19. Upload the new file to PyPI with "twine upload music21-7.3.5a2.tar.gz" [*] |
72 | 69 |
|
73 | 70 | [*] Requires twine to be installed |
74 | 71 |
|
|
82 | 79 | username:your_username |
83 | 80 | password:your_password |
84 | 81 |
|
85 | | -19. Delete the two .tar.gz files in dist... |
| 82 | +20. Delete the two .tar.gz files in dist... |
86 | 83 |
|
87 | | -20. For starting a new major release create a GitHub branch for the old one. |
| 84 | +21. For starting a new major release create a GitHub branch for the old one. |
88 | 85 |
|
89 | | -21. Immediately increment the number in _version.py and run tests on it here |
| 86 | +22. Immediately increment the number in _version.py and run tests on it here |
90 | 87 | to prepare for next release. |
91 | 88 |
|
92 | | -22. Announce on the blog, to the list, and twitter. |
93 | | -
|
94 | | -DO NOT RUN THIS ON A PC -- the Mac .tar.gz has an incorrect permission if you do. |
| 89 | +23. Announce on the blog, to the list, and twitter. |
95 | 90 | ''' |
96 | | -import hashlib |
97 | 91 | import os |
98 | | -import sys |
99 | 92 | import shutil |
100 | 93 | import tarfile |
101 | 94 |
|
102 | | -from music21 import base |
103 | | -from music21 import common |
104 | | - |
105 | | -from music21 import environment |
106 | | -environLocal = environment.Environment('..dist.dist') |
107 | | - |
108 | | -PY = sys.executable |
109 | | -environLocal.warn(f'using python executable at {PY}') |
110 | | - |
111 | | -class Distributor: |
112 | | - def __init__(self): |
113 | | - # self.fpEgg = None |
114 | | - # self.fpWin = None |
115 | | - self.fpTar = None |
116 | | - |
117 | | - self.buildNoCorpus = True |
118 | | - # self.fpEggNoCorpus = None |
119 | | - self.fpTarNoCorpus = None |
120 | | - |
121 | | - self.version = base.VERSION_STR |
122 | | - |
123 | | - self._initPaths() |
124 | | - |
125 | | - def _initPaths(self): |
126 | | - |
127 | | - # must be in the dist dir |
128 | | - directory = os.getcwd() |
129 | | - parentDir = os.path.dirname(directory) |
130 | | - parentContents = sorted(os.listdir(parentDir)) |
131 | | - # make sure we are in the proper directory |
132 | | - if (not directory.endswith('dist') |
133 | | - or 'music21' not in parentContents): |
134 | | - raise Exception(f'not in the music21{os.sep}dist directory: {directory}') |
135 | | - |
136 | | - self.fpDistDir = directory |
137 | | - self.fpPackageDir = parentDir # dir with setup.py |
138 | | - self.fpBuildDir = os.path.join(self.fpPackageDir, 'build') |
139 | | - # self.fpEggInfo = os.path.join(self.fpPackageDir, 'music21.egg-info') |
140 | | - |
141 | | - sys.path.insert(0, parentDir) # to get setup in as a possibility. |
142 | | - |
143 | | - for fp in [self.fpDistDir, self.fpPackageDir, self.fpBuildDir]: |
144 | | - environLocal.warn(fp) |
145 | | - |
146 | | - |
147 | | - def updatePaths(self): |
148 | | - ''' |
149 | | - Process output of build scripts. Get most recently produced distributions. |
150 | | - ''' |
151 | | - contents = sorted(os.listdir(self.fpDistDir)) |
152 | | - for fn in contents: |
153 | | - fp = os.path.join(self.fpDistDir, fn) |
154 | | - # if self.version in fn and fn.endswith('.egg'): |
155 | | - # self.fpEgg = fp |
156 | | - # if self.version in fn and fn.endswith('.exe'): |
157 | | - # fpNew = fp.replace('.macosx-10.8-intel.exe', '.win32.exe') |
158 | | - # fpNew = fpNew.replace('.macosx-10.8-x86_64.exe', '.win32.exe') |
159 | | - # fpNew = fpNew.replace('.macosx-10.9-intel.exe', '.win32.exe') |
160 | | - # fpNew = fpNew.replace('.macosx-10.9-x86_64.exe', '.win32.exe') |
161 | | - # fpNew = fpNew.replace('.macosx-10.10-intel.exe', '.win32.exe') |
162 | | - # fpNew = fpNew.replace('.macosx-10.10-x86_64.exe', '.win32.exe') |
163 | | - # fpNew = fpNew.replace('.macosx-10.11-intel.exe', '.win32.exe') |
164 | | - # fpNew = fpNew.replace('.macosx-10.11-x86_64.exe', '.win32.exe') |
165 | | - # fpNew = fpNew.replace('.macosx-10.12-intel.exe', '.win32.exe') |
166 | | - # fpNew = fpNew.replace('.macosx-10.12-x86_64.exe', '.win32.exe') |
167 | | - # if fpNew != fp: |
168 | | - # os.rename(fp, fpNew) |
169 | | - # self.fpWin = fpNew |
170 | | - |
171 | | - print(fn) |
172 | | - if self.version in fn and fn.endswith('.tar.gz'): |
173 | | - self.fpTar = fp |
174 | | - else: |
175 | | - environLocal.warn(fn + ' does not end with .tar.gz') |
176 | | - |
177 | | - environLocal.warn('giving path for tar.gz') |
178 | | - for fn in [self.fpTar]: |
179 | | - if fn is None: |
180 | | - environLocal.warn('missing fn path') |
181 | | - else: |
182 | | - environLocal.warn(fn) |
183 | | - |
184 | | - def removeCorpus(self, fp): |
185 | | - ''' |
186 | | - Remove the corpus from a compressed file (.tar.gz) and |
187 | | - create a new music21-noCorpus version. |
188 | | -
|
189 | | - Return the completed file path of the newly created edition. |
190 | | -
|
191 | | - NOTE: this function works only with Posix systems. |
192 | | - ''' |
193 | | - TAR = 'TAR' |
194 | | - # EGG = 'EGG' |
195 | | - if fp and fp.endswith('.tar.gz'): |
196 | | - mode = TAR |
197 | | - modeExt = '.tar.gz' |
198 | | - else: |
199 | | - raise Exception('incorrect source file path') |
200 | | - |
201 | | - fpDir, fn = os.path.split(fp) |
202 | | - |
203 | | - # this has .tar.gz extension; this is the final completed package |
204 | | - fnDst = fn.replace('music21', 'music21-noCorpus') |
205 | | - fpDst = os.path.join(fpDir, fnDst) |
206 | | - # remove file extensions |
207 | | - fnDstDir = fnDst.replace(modeExt, '') |
208 | | - fpDstDir = os.path.join(fpDir, fnDstDir) |
209 | | - |
210 | | - # get the name of the dir after decompression |
211 | | - fpSrcDir = os.path.join(fpDir, fn.replace(modeExt, '')) |
212 | | - |
213 | | - # remove old dirs if it exists |
214 | | - if os.path.exists(fpDst): |
215 | | - shutil.rmtree(fpDst) |
216 | | - |
217 | | - if os.path.exists(fpDstDir): |
218 | | - shutil.rmtree(fpDstDir) |
219 | | - |
220 | | - if mode == TAR: |
221 | | - tf = tarfile.open(fp, 'r:gz') |
222 | | - # the path here is the dir into which to expand, |
223 | | - # not the name of that dir |
224 | | - tf.extractall(path=fpDir) |
225 | | - os.system(f'mv {fpSrcDir} {fpDstDir}') |
226 | | - tf.close() # done after extraction |
227 | | - |
228 | | - # elif mode == EGG: |
229 | | - # os.system(f'mkdir {fpDstDir}') |
230 | | - # # need to create dst dir to unzip into |
231 | | - # tf = zipfile.ZipFile(fp, 'r') |
232 | | - # tf.extractall(path=fpDstDir) |
233 | | - |
234 | | - |
235 | | - # remove files, updates manifest |
236 | | - for fn in common.getCorpusContentDirs(): |
237 | | - fp = os.path.join(fpDstDir, 'music21', 'corpus', fn) |
238 | | - shutil.rmtree(fp) |
239 | | - |
240 | | - fp = os.path.join(fpDstDir, 'music21', 'corpus', '_metadataCache') |
| 95 | +from music21._version import __version__ as version |
| 96 | +from music21.common.pathTools import getRootFilePath, getCorpusContentDirs |
| 97 | + |
| 98 | +def removeCorpus(): |
| 99 | + ''' |
| 100 | + Remove the corpus from a compressed file (.tar.gz) and |
| 101 | + create a new music21-noCorpus version. |
| 102 | +
|
| 103 | + Return the completed file path of the newly created edition. |
| 104 | +
|
| 105 | + NOTE: this function works only with Posix systems. |
| 106 | + ''' |
| 107 | + fp = getRootFilePath() / 'dist' / ('music21-' + version + '.tar.gz') |
| 108 | + fpDir, fn = os.path.split(str(fp)) |
| 109 | + |
| 110 | + # this has .tar.gz extension; this is the final completed package |
| 111 | + fnDst = fn.replace('music21', 'music21-noCorpus') |
| 112 | + fpDst = os.path.join(fpDir, fnDst) |
| 113 | + # remove file extensions |
| 114 | + fnDstDir = fnDst.replace('.tar.gz', '') |
| 115 | + fpDstDir = os.path.join(fpDir, fnDstDir) |
| 116 | + |
| 117 | + file = tarfile.open(fp) |
| 118 | + file.extractall(fpDir) |
| 119 | + file.close() |
| 120 | + |
| 121 | + os.rename(fpDstDir.replace('-noCorpus', ''), fpDstDir) |
| 122 | + |
| 123 | + # remove files, updates manifest |
| 124 | + for fn in getCorpusContentDirs(): |
| 125 | + fp = os.path.join(fpDstDir, 'music21', 'corpus', fn) |
241 | 126 | shutil.rmtree(fp) |
242 | 127 |
|
243 | | - # adjust the sources Txt file |
244 | | - # if mode == TAR: |
245 | | - sourcesTxt = os.path.join(fpDstDir, 'music21.egg-info', 'SOURCES.txt') |
246 | | - # else: |
247 | | - # raise Exception('invalid mode') |
248 | | - |
249 | | - # elif mode == EGG: |
250 | | - # sourcesTxt = os.path.join(fpDstDir, 'EGG-INFO', 'SOURCES.txt') |
251 | | - |
252 | | - # files will look like 'music21/corpus/haydn' in SOURCES.txt |
253 | | - post = [] |
254 | | - f = open(sourcesTxt, 'r') |
255 | | - corpusContentDirs = common.getCorpusContentDirs() |
256 | | - for line in f: |
257 | | - match = False |
258 | | - if 'corpus' in line: |
259 | | - for fn in corpusContentDirs: |
260 | | - # these are relative paths |
261 | | - fp = os.path.join('music21', 'corpus', fn) |
262 | | - if line.startswith(fp): |
263 | | - match = True |
264 | | - break |
265 | | - if not match: |
266 | | - post.append(line) |
267 | | - f.close() |
268 | | - f = open(sourcesTxt, 'w') |
269 | | - f.writelines(post) |
270 | | - f.close() |
271 | | - |
272 | | - if mode == TAR: |
273 | | - # compress dst dir to dst file path name |
274 | | - # need the -C flag to set relative dir |
275 | | - # just name of dir |
276 | | - cmd = f'tar -C {fpDir} -czf {fpDst} {fnDstDir}/' |
277 | | - os.system(cmd) |
278 | | - |
279 | | - # remove directory that was compressed |
280 | | - if os.path.exists(fpDstDir): |
281 | | - shutil.rmtree(fpDstDir) |
282 | | - |
283 | | - return fpDst # full path with extension |
284 | | - |
285 | | - |
286 | | - |
287 | | - def build(self): |
288 | | - ''' |
289 | | - Build all distributions. Update and rename file paths if necessary; |
290 | | - remove extract build products. |
291 | | - ''' |
292 | | - # call setup.py |
293 | | - # import setup # -- for some reason does not work unless called from command line |
294 | | - for buildType in ['sdist --formats=gztar', 'bdist_wheel']: |
295 | | - environLocal.warn(f'making {buildType}') |
296 | | - |
297 | | - savePath = os.getcwd() |
298 | | - os.chdir(self.fpPackageDir) |
299 | | - os.system(f'{PY} setup.py {buildType}') |
300 | | - os.chdir(savePath) |
301 | | - |
302 | | - self.updatePaths() |
303 | | - |
304 | | - environLocal.warn(f'removing {self.fpBuildDir} (except on windows...there do it yourself)') |
305 | | - try: |
306 | | - shutil.rmtree(self.fpBuildDir) |
307 | | - except FileNotFoundError: |
308 | | - environLocal.warn( |
309 | | - 'Directory was already cleaned up' |
310 | | - ) |
311 | | - |
312 | | - if self.buildNoCorpus is True: |
313 | | - # create no corpus versions |
314 | | - self.fpTarNoCorpus = self.removeCorpus(fp=self.fpTar) |
315 | | - # self.fpEggNoCorpus = self.removeCorpus(fp=self.fpEgg) |
316 | | - |
317 | | - |
318 | | - def md5ForFile(self, path, hexReturn=True): |
319 | | - if hexReturn: |
320 | | - return hashlib.md5(open(path, 'rb').read()).hexdigest() |
321 | | - else: |
322 | | - return hashlib.md5(open(path, 'rb').read()).digest() |
| 128 | + fp = os.path.join(fpDstDir, 'music21', 'corpus', '_metadataCache') |
| 129 | + shutil.rmtree(fp) |
| 130 | + |
| 131 | + # compress dst dir to dst file path name |
| 132 | + # need the -C flag to set relative dir |
| 133 | + # just name of dir |
| 134 | + cmd = f'tar -C {fpDir} -czf {fpDst} {fnDstDir}/' |
| 135 | + os.system(cmd) |
| 136 | + |
| 137 | + # # remove directory that was compressed |
| 138 | + if os.path.exists(fpDstDir): |
| 139 | + shutil.rmtree(fpDstDir) |
| 140 | + |
| 141 | + return fpDst # full path with extension |
323 | 142 |
|
324 | 143 |
|
325 | 144 | # ------------------------------------------------------------------------------ |
326 | 145 | if __name__ == '__main__': |
327 | | - d = Distributor() |
328 | | - d.buildNoCorpus = True |
329 | | - d.build() |
330 | | - d.updatePaths() |
331 | | - # d.getMD5Path() |
332 | | - # d.uploadPyPi() |
| 146 | + removeCorpus() |
0 commit comments